Mapage
  b..  `q*$$$$$$#$$$$$$$$$$$$$$$$$$$P'""""`q$$$$$P'""`q$$$$$$$$$$$$$$$$#,$$$$$$$$$
$c$cb' `$$$$$$$u*$$$$$$$$$$$$P'""'  ,'"   `"qP ^     `q$$$$$$$$$$$$Ei*)8$$$$$$$$
$$C'`qe `$$$$*"4l'$*%RP'"'         db.  4              `q$$$$$$$$$$$$"@$$$$$$$$$
$$L.,d3$k`$$F    *\   .,,.     '~# `qb.     .zNdouesx= .  "`q$$$$$$$$$$$$$$$$$$$
$$$o.`"'""`qNb.      d$$$$$b..      ,qb. :d$""*$$6k%     `.     "$$$$$*`$$$$$$$$
$$$$$.     ,dp'"'    q$$pq$$N$P'"`,d$$3b.`R"eu.`@$@ .      `*@c.  ^*F  .$$$$$$$$
$$$$$$K' ,d$$",P' `. `6' `q@$P   d6$$$$$$bq$$$P f" r,db.    \@$*do    J$$$$*3$$$
$$b$$$k  q4$u-%'     .     `'   d$$$$$$$$o@$$$'-":,d$$$$b    )@$$B\  ...'Ld$$$$$
$$$$$d-  `$RE$6.     ,.   ,db. ,$$$$$$$$$$$$$P .,d$$$$$$$.    "#$$$ .$#d9$$$$$$$
$$$$$$'   `qJ2B$$  ,$P   ,$$$$$o$$$$Pq$$$$$$$' 4`q$$$$$$$b       "$$$$$$$$$$Pq$$
*$P**$o.  ,dCb. ,d6P'`q$P'        `q$$$$$%$$$$$$$$$$$$$$N     q$$$$$$b'    `3$b `$$$$$$
$I$$$$*= `"'  ,   .,,d$$b..,d$$$P"d$$$$$$$$$$$*"#"      q$$$$$$b"Lu  $$$> $$$$$$
).>*$' .     d$  '"`q$$$$$x$$$$P,dNq$6$B$$$$$ d$ee  -    $$$$$P'$$$  q$$$,d$$$$$
C$P'   $.    q$.     q*$$$ ^#*"u$$$bqN$B9$$$$+$$B$$/L  e  q$$$$ $$$  `R$$$$$$$$$
$$'    `b.    q$.     qN$$r   3$$$$$`$$$$b)*RN$%d$$B6$*u  `$$$$,d$P"  q$$$$$$$$$
$$l..   `=..   qbb    `33B$   $$$$$$b$$$$$*N$$$$$#P=BB$Bc  $$$$$$ $   `$$$$$$$$$
$$$$*"'  `qNL   `$b.   qI@$F  $$$$$$$$$$$$$$$$$@P' `d$$$6 .L^=R$u$$    q$EKJ$$$$
$$$$c.     qRr   `qb   `3I#J  t$$$$$$$$$$$$$$kP'  .d$$$$P dN(/b'`q$L   `*%m$CW2$
$$$$$F     `$e:..,dP    ,$*%7uz$$$$$$$$$$$9R*L'  .d$$$$P' 8B$$$b  q$r   $$$$$$$$
$$$$P`       *W3b"'   ,d$$ `2d$$$$$$$$$$$N)@B3b.d$$$$E%'  *$$$$N. `*\   q$$$$$$e
$$$$'.,.      `"' ,'~' q$$ .@$$$$$$$$Pq$$$$$$$$$$$$$$$'  ,$$$t$$b  '     `"""`qe
**$$ .?.q=r.            qb^'?3$$$$$$$bd$$$$$$$$$$$$$$$NbuB$$$$$$$   .,db..  .,d$
$$b. ,$>`qP'<            '~?$ `q#$$$$$$$$$$$$$$$$$$$$$$$$$$$I$$$P  ,ued$$$$$$$$$
$$$$,JP'  ` :      J*$$b    "   `9BE$$$$$$$$$$$$$$$$$$$$$$$$$$$P'  de(~$$$$$$$$$
$$$$k3R     $    =$$$P\$$u \Wc   $7P%$$$$P$$$$$$$$$$$*$$$$$$$$$$b. q$$$$$$$$$$$$
$$$$P'~     $     .$ o$$$$$d$$  ,d' ,d$$$bq$$$$$$$$$$$$$$$$$$$$$$$b.q'`q$$$$$c^*
$$$$X..     B     C.$$$$$$$$$$$kucb,d$$$$$`$$$$$$$$$$$$$9$$$9$$$4$$$$. `$R$$$$$o
$$$$NF-     Fb    :R$$$$Pq$$$$$$$@$e$$$$$$ $$$$$$$$$$B$P' ,d$$$N $#$$b  qu$$$$$$
$$$$$l$:    `qb.   "$$$$bd$$$$$$$$$$$$$$$$,$$$$$$$$$B%' ,d$$$$$E:$ #$$  `$$$$$$$
$$$*$$F       `'    4$$$$$$$$$$#$$$@$$$$$Pd$$$$$$#b.  .,d$$$$$$$$$$eu$   $$$$$$$
$$*P'dL           $F R"*$$$$$d$o?$$$$$$#$'$$$$$$$$eu$$$$$$$$$$E'q$$*fP   4$$$e^*
$$P' 9    =.      9$  $ "$$$$$$$$$$ `q$$# q$$$$$$$$$$$$$Pq6$$$F. q$CP'   d$$$$$.
$P   $r  '4$r.     *$e$L  "$$$$$$$L.  q$? `q$P'hb$$$$$$$bd$$$$$b  `'     '"$$$$$
P    *.   `q$o      X$$$    $$$$$$$c. `$N  #P'   `qRNQ$$$$$$$$$? ,'  ., ,   qR$$
     `$.   `qP       $x      ^$$$$$$b.d$P    ,d' ,d$$$$$$*$$$$"P b.,dP ,$b.,d$$$
b..   `R.   $%f>$e.   *F~ f9$$$$$$$$$$bP   ,'  ,d$$$$$$$R` @$%'  2$$P  d$$$$$$$$
eeeedr.`"  ,"   -$$b.   zozbM?`-\$$$$$$$b   ,d$$$$$$$$$$$`  `'   <*"  d$$J$$$$$$
$$$$$Nk.   W.    :$$$b   $$$b#x$@$$$$$$$$b.d$$$$$$$$$$$$$$r       ' ,d$$$$$2$$$$
$$)$$$$E/  qN.   "$$$$b $$Z'^"$$$$$$$$4$$$$$$$$$$$$$$$$$$$N        `!@$$$$$$$$$$
E$$$R$$$b  `q$b@@$$$$$$ 9$Ndo.. `"*`q$$$$$$$$$$$$$$$$$$$F!      ,   2$$$"$$$$$$$
$$Pq$$$$$N  `$$$$6$$*$P  "$$F$$Neeu.`q$$$$$$$$P'3$*#*$$$r      d'  ,$$$$$K$$$$$$
$$bd$$$$$$    q$$ppP*P'          .,$ `q$$$$$$P'  -    "      ,d$. ,dP'"    "`q$$
$$$$$$E$" ,$$. `"d$b' ,,..   ,ued$$b.  `"q*$P'""R#.  ..    .,d$N?WdP' Philip `$$
$$$$$$P ,z$$$$$euz$$$$$N@$$$$$$$$NPM$b..      .,$$$b. qb*$$$$$$$b$$$ Kaulfuss $$
$$$$$$$d$$$$$$$$$$$$$$$$$$$$$$$$$$'4$$$$$b.,d$$$$$$$b.`qb#$$$$$"'q$$.        ,$$
   ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄         ▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄ 
  ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
  ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░▌       ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀▀▀ 
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░▌       ▐░▌▐░▌          ▐░▌          
  ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌       ▐░▌▐░▌       ▐░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌          ▐░█▄▄▄▄▄▄▄▄▄ 
  ▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░▌          ▐░░░░░░░░░░░▌
   ▀▀▀▀▀▀▀▀▀█░▌▐░▌       ▐░▌▐░▌       ▐░▌▐░█▀▀▀▀█░█▀▀ ▐░▌          ▐░█▀▀▀▀▀▀▀▀▀ 
            ▐░▌▐░▌       ▐░▌▐░▌       ▐░▌▐░▌     ▐░▌  ▐░▌          ▐░▌          
   ▄▄▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌      ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄ 
  ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
   ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀         ▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀ 
   ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄   ▄▄▄▄▄▄▄▄▄▄▄ 
  ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
  ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ 
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░▌          
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░█▄▄▄▄▄▄▄▄▄ 
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░░░░░░░░░░░▌
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░█▀▀▀▀▀▀▀▀▀ 
  ▐░▌          ▐░▌       ▐░▌▐░▌       ▐░▌▐░▌          
  ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ 
  ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
   ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀   ▀▀▀▀▀▀▀▀▀▀▀ 
   ____  _  _  ___  ____  ____    ___   ___  ___   ___             __    _  _    __    ____  __      __    ____     ___    __    __    __   
  (  _ \( \( )/ __)( ___)(  _ \  (__ \ / _ \(__ \ (__ )   ___     /__\  ( \( )  /__\  ( ___)(  )    (  )  ( ___)   / __)  /__\  (  )  (  )  
   )(_) ))  ( \__ \ )__)  )___/   / _/( (_) )/ _/  (_ \  (___)   /(__)\  )  (  /(__)\  )__)  )(__    )(__  )__)   ( (_-. /(__)\  )(__  )(__ 
  (____/(_)\_)(___/(____)(__)    (____)\___/(____)(___/         (__)(__)(_)\_)(__)(__)(____)(____)  (____)(____)   \___/(__)(__)(____)(____)
  
  

functiontoggleDivs(){vardiv1=document.getElementById("menu-mobile");vardiv2=document.getElementById("mapid");varmaDiv=document.getElementById("menuicon");if(div1.style.display==="none"){div1.style.display="block";div2.style.display="none";}else{div1.style.display="none";div2.style.display="block";}}functiontoggleDivs2(){vardiv3=document.getElementById("menu-mobile");vardiv4=document.getElementById("content");varmaDiv2=document.getElementById("menuicon");if(div3.style.display==="none"){div3.style.display="none";div4.style.display="block";}else{div3.style.display="block";div4.style.display="none";}}<!DOCTYPEhtml><html><head><title>CartedeCambrai</title><metacharset="utf-8"/><metaname="viewport"content="width=device-width,initial-scale=1.0"><scriptsrc="action.js"></script><linkrel="stylesheet"href="/Cartographie/leaflet.css"/></head><body><divid="footer"><divid="footer-text"><h1>Cartographie</h1><h2>desressourcesdeCambrai</h2></div><divid="menuicon"onclick="toggleDivs()"><a>MENU</a></div><sectionid="menu-mobile"><h1style="margin-top:25px;text-align:center;font-size:32px;">Menu</h1><ahref="/Cartographie/index.html">Annuaireformat</a><ahref="https://atlas-ata.fr/"target="_blank">CartographiedeATA</a><ahref="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing"target="_blank">Proposerunlieu</a><divid="close"onclick="toggleDivs2()">Fermerlemenu</div></section><sectionid="menu-ordi"><ahref="/Cartographie/index.html">Cartedesressources</a><ahref="https://atlas-ata.fr/"target="_blank">CartographiedeATA</a><ahref="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing"target="_blank">Proposerunlieu</a></section></div><divid="contenting"><divclass="grid"><divclass="grid-item"><h3>LieuxdeCulture</h3><divid="cat"><h4>MuséedesbeauxartsdeCambrai</h4><p>15Ruedel'Épée</p><p>59400Cambrai</p><p>0327822790</p></div><divid="cat"><h4>LeLabo</h4><p>2RueLouisRenard,59400Cambrai</p><p>0374510000</p><p><ahref="https://www.lelabocambrai.fr/"target="_blank">lelabocambrai.fr</a></p></div><divid="cat"><h4>ThéâtredeCambrai</h4><p>1RueduTemple</p><p>0327729500</p><p><ahref="http://www.scenes-mitoyennes.fr/"target="_blank">scenes-mitoyennes.fr</a></p></div><divid="cat"><h4>CentreRégionaldelaPhotographie</h4><p>PlacedesNations</p><p>59282Douchy-les-Mines</p><p>0327435650</p><p><ahref="https://crp.photo/"target="_blank">crp.photo</a></p></div><divid="cat"><h4>AbbayedeVaucelles</h4><p>HammeaudeVaucelles,59258LesRues-des-Vignes</p><p>0359731498</p><p><ahref="https://abbayedevaucelles.fr/"target="_blank">abbayedevaucelles.fr</a></p></div><divid="cat"><h4>Archéo’site—LesRues-des-Vignes</h4><p>>82RueHaute</p><p>59258LesRues-des-Vignes</p><p>0970211746</p><p><ahref="https://www.archeosite-ruesdesvignes.fr/"target="_blank">archeosite-ruesdesvignes.fr</a></p></div><divid="cat"><h4>MuséeMatisse—LeCateau-Cambresis</h4><p>Palais,RueFénelon</p><p>59360LeCateau-Cambrésis</p><p>0359733800</p><p><ahref="https://museematisse.fr/"target="_blank">museematisse.fr</a></p></div><divid="cat"><h4>Médiathèquedel’Escaut</h4><p>2RuedelaPaix</p><p>59267Proville</p><p>0327707487</p><p><ahref="https://www.mediathequedelescaut.fr/"target="_blank">mediathequedelescaut.fr</a></p></div></div><divclass="grid-item"><h3>RessourcesArtistes</h3><divid="cat"><h4>LaMalterie</h4><p>42RueKuhlmann</p><p>59800Lille</p><p>0320151321</p><p><ahref="http://www.lamalterie.com/"target="_blank">lamalterie.com</a></p></div><divid="cat"><h4>LaChambred'Eau</h4><p>61ruedumoulin</p><p>59550LeFavril</p><p>0327770926</p><p><ahref="http://www.lachambredeau.fr/"target="_blank">lachambredeau.fr</a></p></div><divid="cat"><h4>L'HDuSiège</h4><p>15ruedel'HôpitalduSiège</p><p>59300Valenciennes</p><p>0327770926</p><p><ahref="http://www.hdusiege.org/"target="_blank">hdusiege.org</a></p></div><divid="cat"><h4>SMACServiceMobiled'AnimationsCulturelles</h4><p>AvenuedesPotiers</p><p>59500Douai</p><p>0777075009</p><p><ahref="http://smacasso.com/"target="_blank">smacasso.com</a></p></div><divid="cat"><h4>MicroAtelierdeProville(Fablab)</h4><p>2RuedelaPaix</p><p>59267Proville</p><p>0321707487</p><p><ahref="https://mediathequedelescaut.fr"target="_blank">mediathequedelescaut.fr</a></p></div></div><divclass="grid-item"><h3>Collègesetlycées</h3><divid="cat"><h4>CollègeetlycéeFénelon</h4><p>PlaceFrançoisdeFénelon</p><p>59400Cambrai</p><p>0327727777</p><p><ahref="http://lyc-fenelon.etab.ac-lille.fr/"target="_blank">lyc-fenelon.etab.ac-lille.fr</a></p></div><divid="cat"><h4>CollègeetlycéePaulDuez</h4><p>1BoulebardPaulBezin</p><p>59400Cambrai</p><p>0327730730</p><p><ahref="http://www.duez-bettignies.org/"target="_blank">duez-bettignies.org</a></p></div><divid="cat"><h4>CollègeJulesFerry</h4><p>4RueMgrGuerry</p><p>59400Cambrai</p><p>0327837615</p><p><ahref="https://jules-ferry-cambrai.enthdf.fr/"target="_blank">jules-ferry-cambrai.enthdf.fr</a></p></div><divid="cat"><h4>CollègeLamartine</h4><p>330RueGauthier</p><p>59400Cambrai</p><p>0327813317</p><p><ahref="https://lamartine-cambrai.enthdf.fr/"target="_blank">lamartine-cambrai.enthdf.fr</a></p></div><divid="cat"><h4>LycéeprofessionnelLouisedeBrettignies</h4><p>3BoulevardPaulBezin</p><p>59400Cambrai</p><p>0327730718</p></div><divid="cat"><h4>LycéeprofessionnelLouisBlériot</h4><p>RueGauthier</p><p>59400Cambrai</p><p>0327722900</p></div></div><divclass="grid-item"><h3>Matériaux</h3><divid="cat"><h4>Poterieduvieux</h4><p>905AvenuedesNationsUnies</p><p>59270Bailleul</p><p>0328499262</p><p>https://poterieduvieuxbac.com</p></div><divid="cat"><h4>Bricodépôt</h4><p>1909AvenuedeParis</p><p>59400Cambrai</p><p>0327700950</p></div><divid="cat"><h4>LeroyMerlin</h4><p>RN30AvenueJeanJaurès</p><p>59400Cambrai</p><p>0327215600</p></div><divid="cat"><h4>GammVert</h4><p>54BoulevardJeanBart</p><p>59400Cambrai</p><p>0327783511</p></div><divid="cat"><h4>Bricomarché</h4><p>1AvenuedeParis</p><p>59400Cambrai</p><p>0327783939</p></div><divid="cat"><h4>GedimatBracq</h4><p>Rueduchampdetir</p><p>59400Cambrai</p><p>0327829600</p></div><divid="cat"><h4>Point.P</h4><p>140BoulevardFaidherbe</p><p>59400Cambrai</p><p>0327720404</p></div><divid="cat"><h4>4Murs</h4><p>ChemindeMarcoing</p><p>59400Cambrai</p><p>0327811008</p></div><divid="cat"><h4>Chantemur</h4><p>AvenuedeParis</p><p>59400Cambrai</p><p>0327749817</p></div><divid="cat"><h4>ElectroDépôt</h4><p>197AvenuedeValenciennes</p><p>59400Cambrai</p><p>0327707240</p></div></div><divclass="grid-item"><h3>Librairies;papeteries</h3><divid="cat"><h4>LesFuretsduNord</h4><p>22MailSaint-Martin</p><p>59400Cambrai</p><p>0327813377</p></div><divid="cat"><h4>Majuscule</h4><p>14RueHenrideLubac</p><p>59400Cambrai</p><p>0327812554</p><p><ahref="https://www.majuscule-cambrai.com/SiteFront/"target="_blank">majuscule-cambrai.com</a></p></div><divid="cat"><h4>Maisondelapresse</h4><p>1RueduGénéraldeGaulle</p><p>59400Cambrai</p><p>0327812707</p></div><divid="cat"><h4>BureauVallée</h4><p>AveuedeParis</p><p>59400Cambrai</p><p>0327700009</p></div></div><divclass="grid-item"><h3>Centredeloisirs</h3><divid="cat"><h4>Centred’animationÉclipse</h4><p>47AvenuedeDunkerque</p><p>59400Cambrai</p><p>0327822790</p></div><divid="cat"><h4>MissionlocaleduCambrésis</h4><p>24BoulebardFaidherbe</p><p>59400Cambrai</p><p>0327784848</p></div><divid="cat"><h4>ServiceEnfanceJeunessedeCambrai</h4><p>47AvenuedeDunkerque</p><p>0327812022</p><p><ahref="https://www.sejc.fr"target="_blank">sejc.fr</a></p></div><divid="cat"><h4>R’Génération(Centresocial)</h4><p>RueRaymondGernez</p><p>59400Cambrai</p><p>0327703813</p></div><divid="cat"><h4>EspacedeviesocialeLeTipi</h4><p>14rueLafayette</p><p>59400Cambrai</p><p>0327812022</p><p><ahref="https://www.sejc.fr"target="_blank">sejc.fr</a></p></div></div><divclass="grid-item"><h3>ÉcolesetFacultés</h3><divid="cat"><h4>ÉsacCambrai</h4><p>130AlléeSaint-Roch</p><p>59400Cambrai</p><p>0327838142</p><p><ahref="http://www.esac-cambrai.net/"target="_blank">esac-cambrai.net</a></p></div><divid="cat"><h4>UPHF</h4><p>6RuedeRambouillet</p><p>59400Cambrai</p><p>0327723300</p><p><ahref="http://www.centre-universitaire-cambrai.fr/"target="_blank">centre-universitaire-cambrai.fr</a></p></div></div><divclass="grid-item"><h3>SantéetSocial</h3><divid="cat"><h4>RésidenceCrous</h4><p>50AAlléeSaint-Roch</p><p>59400Cambrai</p></div><divid="cat"><h4>CAF</h4><p>2RangSaint-Jean</p><p>59400Cambrai</p></div><divid="cat"><h4>Planningfamilial</h4><p>6RueduMaréchaldeLattredeTassigny</p><p>59400Cambrai</p><p>0327707059</p><p><ahref="http://planningfamilial59.org/"target="_blank">planningfamilial59.org</a></p></div><divid="cat"><h4>Centrehospitalier</h4><p>516AvenuedeParis</p><p>59400Cambrai</p><p>0327737373</p><p><ahref="http://www.ch-cambrai.fr/"target="_blank">ch-cambrai.fr</a></p></div></div><divclass="grid-item"><h3>Emploi</h3><divid="cat"><h4>Pôleemploi</h4><p>16RueduColonelFrancisNicol</p><p>59400Cambrai</p><p>0972723949</p><p><ahref="https://www.pole-emploi.fr/annuaire/"target="_blank">pole-emploi.fr/annuaire</a></p></div><divid="cat"><h4>CambresisEmploi</h4><p>14RueNeuve</p><p>59400Cambrai</p><p>0327700129</p><p><ahref="http://www.cambresisemploi.fr/"target="_blank">www.cambresisemploi.fr</a></p></div><divid="cat"><h4>CCIGrandHainaut</h4><p>3AvenueduSénateurGirard</p><p>59300Valenciennes</p><p>0327513513</p><p><ahref="https://hautsdefrance.cci.fr/cci-grand-hainaut/"target="_blank">hautsdefrance.cci.fr/cci-grand-hainaut/</a></p></div></div><divclass="grid-item"><h3>Résidence/Lieud'expo</h3><divid="cat"><h4>Moduloateliers</h4><p>48rueGambetta</p><p>59540Béthencourt</p><p>0643858642</p><p><ahref="http://www.moduloatelier.com/"target="_blank">moduloatelier.com</a></p></div><divid="cat"><h4>Frûctose</h4><p>RueduMagasinGénéral</p><p>59378Dunkerque</p><p>0328645389</p><p><ahref="https://www.fructosefructose.fr/"target="_blank">fructosefructose.fr</a></p></div><divid="cat"><h4>LaBrasserie</h4><p>5RueBasse</p><p>62111Foncquevillers</p><p>0687915782</p><p><ahref="https://artbrasserie.com/"target="_blank">artbrasserie.com</a></p></div><divid="cat"><h4>L'ŒilduChas</h4><p>1ruedesPetitsViéziers</p><p>62000Arras</p><p><ahref="https://www.facebook.com/loeilduchas"target="_blank">facebook.com/loeilduchas</a></p></div></div><divclass="grid-item"><h3>Autres</h3><divid="cat"><h4>Emmaüs</h4><p>952Routenationale</p><p>59400Fontaine-Notre-Dame</p><p>0327781210</p></div><divid="cat"><h4>Officedutourisme</h4><p>48RueHenrideLubac</p><p>59400Cambrai</p><p>0327783615</p><p><ahref="http://www.tourisme-cambresis.fr/"target="_blank"&g<!DOCTYPEhtml><html><head><title>CartedeCambrai</title><metacharset="utf-8"/><metaname="viewport"content="width=device-width,initial-scale=1.0"><linkrel="stylesheet"href="/Cartographie/leaflet.css"/><scriptsrc="leaflet-src.js"></script><scriptsrc="leaflet-src.js.map"></script><scriptsrc="action.js"></script><divid="mapid"></div></head><body><script>/*---------------Testpourajouteruneiconeperso---------------*/varcultureIcon=L.icon({iconUrl:'images/marker-culture.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varloisirsIcon=L.icon({iconUrl:'images/marker-loisirs.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varecoleIcon=L.icon({iconUrl:'images/marker-ecole.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varetudesIcon=L.icon({iconUrl:'images/marker-etudes.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varaideIcon=L.icon({iconUrl:'images/marker-aide.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varmateriauxIcon=L.icon({iconUrl:'images/marker-materiaux.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varpapierIcon=L.icon({iconUrl:'images/marker-papier.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varprintIcon=L.icon({iconUrl:'images/marker-print.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varautreIcon=L.icon({iconUrl:'images/autre-marker.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varemploiIcon=L.icon({iconUrl:'images/marker-emploi.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varresidenceIcon=L.icon({iconUrl:'images/marker-residence.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});varresidenceIcon=L.icon({iconUrl:'images/marker-residence.svg',iconSize:[38,95],//sizeoftheiconiconAnchor:[20,68],//pointoftheiconwhichwillcorrespondtomarker'slocationpopupAnchor:[-3,-76]//pointfromwhichthepopupshouldopenrelativetotheiconAnchor});/*---------------Générerlamapauxbonnescoordonées---------------*/varmymap=L.map('mapid').setView([50.1699,3.2361],13);L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{maxZoom:19,attribution:'©OpenStreetMap'}).addTo(mymap);/*---------------Markers---------------*/varmodulo=L.marker([50.1355,3.4295],{icon:cultureIcon}).bindPopup("<h2>Moduloateliers</h2><p>48rueGambetta<br>59378Dunkerque<br>0328645389<br>http://www.moduloatelier.com/</p>");varfructose=L.marker([51.0386,2.3678],{icon:cultureIcon}).bindPopup("<h2>Frûctose</h2><p>RueduMagasinGénéral<br>59540Béthencourt<br>0643858642<br>https://www.fructosefructose.fr/</p>");varbrasserie=L.marker([50.1471,2.6309],{icon:cultureIcon}).bindPopup("<h2>Frûctose</h2><p>5RueBasse<br>62111Foncquevillers<br>0687915782<br>https://artbrasserie.com/</p>");varchas=L.marker([50.2909,2.7744],{icon:cultureIcon}).bindPopup("<h2>L'ŒilduChas</h2><p>1ruedesPetitsViéziers<br>62000Arras<br>0687915782<br>https://www.facebook.com/loeilduchas</p>");varressourcesart=L.layerGroup([modulo,fructose,brasserie,chas]);varmalterie=L.marker([50.6201,3.0540],{icon:residenceIcon}).bindPopup("<h2>LaMalterie</h2><p>42RueKuhlmann<br>59800Lille<br>0320151321<br>http://www.lamalterie.com/</p>");varchambre=L.marker([50.0961,3.7319],{icon:residenceIcon}).bindPopup("<h2>LaChambred'Eau</h2><p>61ruedumoulin<br>59550LeFavril<br>0327770926<br>http://www.lachambredeau.fr/</p>");varsiege=L.marker([50.3523,3.5207],{icon:residenceIcon}).bindPopup("<h2>L'HDuSiège</h2><p>15ruedel'HôpitalduSiège<br>59300Valenciennes<br>http://www.hdusiege.org/</p>");varsmac=L.marker([50.3738,3.0787],{icon:residenceIcon}).bindPopup("<h2>ServiceMobiled'AnimationsCulturelles</h2><p>AvenuedesPotiers<br>59500Douai<br>0777075009<br>http://smacasso.com/</p>");varmicroatelier=L.marker([50.1631,3.2067],{icon:residenceIcon}).bindPopup("<h2>MicroAtelierdeProville</h2><p>2RuedelaPaix<br>59267Proville<br>0321707487<br>https://mediathequedelescaut.fr</p>");varresidence=L.layerGroup([malterie,chambre,siege,smac,microatelier]);varlabo=L.marker([50.1725,3.2312],{icon:cultureIcon}).bindPopup("<h2>LeLabo</h2><p>2RueLouisRenard<br>59400Cambrai<br>0374510000<br>https://www.lelabocambrai.fr/</p>");vartheatre=L.marker([50.1753,3.2290],{icon:cultureIcon}).bindPopup("<h2>ThéâtredeCambrai</h2><p>1RueduTemple<br>59400Cambrai<br>0327729500<br>http://www.scenes-mitoyennes.fr/</p>");varmusée=L.marker([50.1733,3.2299],{icon:cultureIcon}).bindPopup("<h2>MuséedesBeaux-artsdeCambrai</h2><p>15Ruedel'Épée<br>59400Cambrai<br>0327822790</p>");varcrp=L.marker([50.3006,3.3859],{icon:cultureIcon}).bindPopup("<h2>CentreRégionaldePhotographie</h2><p>PlacedesNations<br>59282Douchy-les-Mines<br>0327435650<br>http://www.crp.photo/</p>");varabbaye=L.marker([50.0767,3.2220],{icon:cultureIcon}).bindPopup("<h2>AbbayedeVaucelles</h2><p>HammeaudeVaucelles<br>59258LesRues-des-Vignes<br>0359731498<br>https://abbayedevaucelles.fr/</p>");vararcheo=L.marker([50.0940,3.2360],{icon:cultureIcon}).bindPopup("<h2>Archéo'site</h2><p>882RueHaute<br>9258LesRues-des-Vignes<br>0970211746<br>https://www.archeosite-ruesdesvignes.fr/</p>");varmatisse=L.marker([50.1062,3.5412],{icon:cultureIcon}).bindPopup("<h2>MuséeMatisse</h2><p>Palais,RueFénelon<br>59360LeCateau-Cambrésis<br>0359733800<br>https://museematisse.fr/</p>");varescaut=L.marker([50.1631,3.2067],{icon:cultureIcon}).bindPopup("<h2>Médiathèquedel’Escaut</h2><p>2RuedelaPaix<br>59267Proville<br>0327707487<br>https://www.mediathequedelescaut.fr/</p>");varinstitutions=L.layerGroup([musée,theatre,labo,crp,archeo,abbaye,matisse,escaut]);vareclipse=L.marker([50.1819,3.2353],{icon:loisirsIcon}).bindPopup("<h2>Centred’animationÉclipse</h2><p>47AvenuedeDunkerque<br>59400Cambrai<br>0327837465</p>");varmission=L.marker([50.1771,3.2384],{icon:loisirsIcon}).bindPopup("<h2>MissionlocaleduCambrésis</h2><p>24BoulevardFaidherbe<br>59400Cambrai<br>0327784848</p>");varsejc=L.marker([50.1819,3.2353],{icon:loisirsIcon}).bindPopup("<h2>ServiceEnfanceJeunessedeCambrai</h2><p>47AvenuedeDunkerque<br>59400Cambrai<br>0327812022<br>www.sejc.fr</p>");vargeneration=L.marker([50.1641,3.2424],{icon:loisirsIcon}).bindPopup("<h2>R’Génération(Centresocial)</h2><p>RueRaymondGernez<br>59400Cambrai<br>0327703813</p>");vartipi=L.marker([50.1704,3.2616],{icon:loisirsIcon}).bindPopup("<h2>EspacedeviesocialeLeTipi</h2><p>14rueLafayetteàCambrai<br>59400Cambrai<br>0327708692<br>www.sejc.fr</p>");varloisirs=L.layerGroup([eclipse,mission,sejc,generation]);varfenelon=L.marker([50.1759,3.2291],{icon:ecoleIcon}).bindPopup("<h2>CollègeetlycéeFénelon</h2><p>PlaceFrançoisdeFénelon<br>59400Cambrai<br>0327727777<br>http://lyc-fenelon.etab.ac-lille.fr/</p>");varduez=L.marker([50.1736,3.2424],{icon:ecoleIcon}).bindPopup("<h2>CollègeetlycéePaulDuez</h2><p>1BoulevardPaulBezin<br>59400Cambrai<br>0327730730</p>");varferry=L.marker([50.1742,3.2256],{icon:ecoleIcon}).bindPopup("<h2>CollègeJulesFerry</h2><p>4RueMgrGuerry<br>59400Cambrai<br>0327837615<br>https://jules-ferry-cambrai.enthdf.fr/</p>");varlamartine=L.marker([50.1589,3.2641],{icon:ecoleIcon}).bindPopup("<h2>CollègeLamartine</h2><p>330RueGauthier<br>59400Cambrai<br>0327813317</p>");varbrettignies=L.marker([50.1735,3.2423],{icon:ecoleIcon}).bindPopup("<h2>LycéeprofessionnelLouisedeBrettignies</h2><p>3BoulevardPaulBezin<br>59400Cambrai<br>0327730718</p>");varbleriot=L.marker([50.2284,3.3193],{icon:ecoleIcon}).bindPopup("<h2>LycéeprofessionnelLouisBlériot</h2><p>RueGauthier<br>59400Cambrai<br>0327722900</p>");varecole=L.layerGroup([fenelon,duez,ferry,lamartine,brettignies,bleriot]);varesac=L.marker([50.1886,3.2434],{icon:etudesIcon}).bindPopup("<h2>ÉcoleSupérieurd'ArtsdeCambrai</h2><p>130AlléeSaint-Roch<br>59400Cambrai<br>0327838142<br>http://www.esac-cambrai.net/</p>");varupf=L.marker([50.1895,3.2458],{icon:etudesIcon}).bindPopup("<h2>CentreUniversitairedeCambrai-UPHF</h2><p>6RuedeRambouillet<br>59400Cambrai<br>0327723300<br>http://www.centre-universitaire-cambrai.fr/</p>");varsup=L.layerGroup([esac,upf]);varcrous=L.marker([50.1822,3.2422],{icon:aideIcon}).bindPopup("<h2>RésidenceCROUS</h2><p>50AAlléeSaint-Roch<br>59400Cambrai</p>");varcaf=L.marker([50.1751,3.2386],{icon:aideIcon}).bindPopup("<h2>CAF</h2><p>2RangSaint-Jean<br>59400Cambrai</p>");varch=L.marker([50.1658,3.2268],{icon:aideIcon}).bindPopup("<h2>Centrehospitalier</h2><p>516AvenuedeParis<br>59400Cambrai<br>0327737373<br>http://www.ch-cambrai.fr/</p>");varplanning=L.marker([50.1751,3.2356],{icon:aideIcon}).bindPopup("<h2>Planningfamilial</h2><p>6RueduMaréchaldeLattredeTassigny<br>59400Cambrai<br>0327707059<br>http://planningfamilial59.org/</p>");varaide=L.layerGroup([crous,caf,ch,planning]);varpoterie=L.marker([50.7276,2.7371],{icon:materiauxIcon}).bindPopup("<h2>Poterieduvieuxbac</h2><p>905avenuedesNationsUnies<br>59270BAILLEUL<br>0328499262><br>https://poterieduvieuxbac.com</p>");varbrico=L.marker([50.1541,3.2228],{icon:materiauxIcon}).bindPopup("<h2>Bricodépôt</h2><p>1909AvenuedeParis<br>59400Cambrai<br>0327700950</p>");varleroy=L.marker([50.3543,3.4866],{icon:materiauxIcon}).bindPopup("<h2>LeroyMerlin</h2><p>30AvenueJeanJaurès<br>59174LaSentinelle<br>0327215600</p>");vargamm=L.marker([50.1800,3.2259],{icon:materiauxIcon}).bindPopup("<h2>GammVert</h2><p>54BoulevardJeanBart<br>59400Cambrai<br>0327783511</p>");varbricomarche=L.marker([50.1701,3.2316],{icon:materiauxIcon}).bindPopup("<h2>Bricomarché</h2><p>1AvenuedeParis<br>59400Cambrai<br>0327783939</p>");vargedimat=L.marker([50.1736,3.2157],{icon:materiauxIcon}).bindPopup("<h2>GedimatBracq</h2><p>Rueduchampdetir<br>59400Cambrai<br>0327829600</p>");varpointp=L.marker([50.1847,3.2300],{icon:materiauxIcon}).bindPopup("<h2>Point.P</h2><p>140BoulevardFaidherbe<br>59400Cambrai<br>0327720404</p>");varmurs=L.marker([50.1500,3.2194],{icon:materiauxIcon}).bindPopup("<h2>4Murs</h2><p>ChemindeMarcoing<br>59400Cambrai<br>0327811008</p>");varchantemur=L.marker([50.1501,3.2196],{icon:materiauxIcon}).bindPopup("<h2>Chantemur</h2><p>AvenuedeParis,ZISudRN44<br>59400Cambrai<br>0327749817</p>");vardepot=L.marker([50.1840,3.2506],{icon:materiauxIcon}).bindPopup("<h2>ElectroDépôt</h2><p>197AvenuedeValenciennes<br>59400Cambrai<br>0327707240</p>");varmateriaux=L.layerGroup([brico,leroy,gamm,bricomarche,gedimat,pointp,murs,chantemur,depot,poterie]);varfuret=L.marker([50.1749,3.2321],{icon:papierIcon}).bindPopup("<h2>LesFuretsduNord</h2><p>22MailSaint-Martin<br>59400Cambrai<br>0327813377</p>");varmajuscule=L.marker([50.1738,3.2320],{icon:papierIcon}).bindPopup("<h2>Majuscule</h2><p>14RueHenrideLubac<br>59400Cambrai<br>0327812554<br>https://www.majuscule-cambrai.com/SiteFront/</p>");varpresse=L.marker([50.1758,3.2356],{icon:papierIcon}).bindPopup("<h2>Maisondelapresse</h2><p>1RueduGénéraldeGaulle<br>59400Cambrai<br>0327812707</p>");varbureau=L.marker([50.1966,3.1926],{icon:papierIcon}).bindPopup("<h2>BureauVallée</h2><p>AvenuedeParis<br>59400Cambrai<br>0327700009</p>");varpapier=L.layerGroup([furet,majuscule,presse,bureau]);vardanquigny=L.marker([50.1478,3.22506],{icon:printIcon}).bindPopup("<h2>ImprimerieDanquigny</h2><p>AvenueGeorgesNuttin<br>59400Cambrai<br>0327831133</p>");varjacobin=L.marker([50.1757,3.2317],{icon:printIcon}).bindPopup("<h2>JacobinCopieetBarakom</h2><p>14RueTavelle<br>59400Cambrai<br>0981200514</p>");varexpression=L.marker([50.1716,3.2318],{icon:printIcon}).bindPopup("<h2>ExpressionImpression</h2><p>AvenuedelaVictoire<br>59400Cambrai<br>0327796894</p>");varimprimerie=L.layerGroup([danquigny,jacobin,expression]);varpoleemploi=L.marker([50.1757,3.2433],{icon:emploiIcon}).bindPopup("<h2>Pôleemploi</h2><p>16RueduColonelFrancisNicol<br>59400Cambrai<br>0972723949<br>https://www.pole-emploi.fr/annuaire/</p>");varcambresis=L.marker([50.1750,3.2348],{icon:emploiIcon}).bindPopup("<h2>CambresisEmploi</h2><p>14RueNeuve<br>59400Cambrai<br>0327700129<br>http://www.cambresisemploi.fr/</p>");varcci=L.marker([50.3617,3.5171],{icon:emploiIcon}).bindPopup("<h2>CCIGrandHainaut</h2><p>3AvenueduSénateurGirard<br>59300Valenciennes<br>0327513513<br>https://hautsdefrance.cci.fr/cci-grand-hainaut/</p>");varemploi=L.layerGroup([poleemploi,cambresis,cci]);varemmaus=L.marker([50.1687,3.1649],{icon:autreIcon}).bindPopup("<h2>Emmaüs</h2><p>952Rtenationale<br>59400Fontaine-Notre-Dame<br>0327781210</p>");vartourisme=L.marker([50.1732,3.2323],{icon:autreIcon}).bindPopup("<h2>Officedutourisme</h2><p>48RueHenrideLubac<br>59400Cambrai<br>0327783615<br>http://www.tourisme-cambresis.fr/</p>");varautre=L.layerGroup([emmaus,tourisme]);varoverlayMaps={};varlayerControl=L.control.layers(overlayMaps).addTo(mymap);layerControl.addOverlay(institutions,"CentreCulturels");layerControl.addOverlay(residence,"Résidence/Lieud'exposition");layerControl.addOverlay(ressourcesart,"RessourcesArtistes");layerControl.addOverlay(loisirs,"CentredeLoisirs");layerControl.addOverlay(ecole,"CollègesetLycées");layerControl.addOverlay(sup,"ÉtudesSupérieures");layerControl.addOverlay(aide,"SantéetSocial");layerControl.addOverlay(materiaux,"BricolageetMatériaux");layerControl.addOverlay(papier,"LibrairiesetPapiers");layerControl.addOverlay(imprimerie,"Imprimeries");layerControl.addOverlay(autre,"Autres");layerControl.addOverlay(emploi,"Emplois");</script><divid="footer"><divid="footer-text"><h1>Cartographie</h1><h2>desressourcesdeCambrai</h2></div><divid="menuicon"onclick="toggleDivs()"><a>MENU</a></div><sectionid="menu-mobile"href="#"><h1style="margin-top:25px;text-align:center;font-size:32px;">Menu</h1><ahref="/Cartographie/annuaire.html">AnnuaireTextuel</a><ahref="https://atlas-ata.fr/"target="_blank">CartographiedeATA</a><ahref="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing"target="_blank">Proposerunlieu</a><divid="close"onclick="toggleDivs()">Fermerlemenu</div></section><sectionid="menu-ordi"><ahref="/Cartographie/annuaire.html">AnnuaireTextuel</a><ahref="https://atlas-ata.fr/"target="_blank">CartographiedeATA</a><ahref="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing"target="_blank">Proposerunlieu</a></section></div></body></html>/* CSS PERSO */ @font-face { font-family: FBold; src: url("fonts/RaisonnePro-Bold.ttf") } @font-face { font-family: Regular; src: url("fonts/RaisonnePro-Book.ttf") } @font-face { font-family: FLight; src: url("fonts/RaisonnePro-Light.ttf") } @font-face { font-family: DemiBold; src: url("fonts/RaisonnePro-DemiBold.ttf") } #menu-mobile { display:none; } #menu-ordi { display:block; } #menuicon { display:none; } #mapid { display:block; height: 80vh; border: 1.5px black dashed; margin: 15px; } a:visited { color:inherit; } #menu-ordi a { font-family:Regular; font-size:0.8em; text-align: center; position:absolute; right:0px; padding:15px 5px 5px 5px; margin: 25px 15px 0 0; width:75px; height:45px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #menu-ordi a:nth-child(1) { right: 100px; } #menu-ordi a:nth-child(2) { right: 200px; } #contenting { display:block; overflow: scroll; height: 75.7vh; width:calc(100vw -8px); border: 1.5px black dashed; background-color: #ffffff; margin: 15px; padding: 15px; } .grid { display:block; overflow: scroll; display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 15px; width: 100%; background-color: #ffffff; } .grid-item { grid-template-rows: repeat(auto-fit, 3, 1fr); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); padding:15px; background-color:whitesmoke; align-items: center; justify-content: center; font-size: 2em; } .texte { text-decoration: underline; margin-top: 13px; justify-content: center; position:absolute; text-align: center; } body { overflow: hidden; background-color: #EDF0D5; margin:0; } #contenting h4 { font-family: Regular; font-size: 0.6em; margin-bottom:5px; margin-top:10px; } #contenting h3 { background-color: #edf0d5; border: 2px solid black; padding:5px; margin-top:0; margin-bottom: 15px; font-family: FBold; font-size: 0.8em; } #cat { padding-bottom:15px; border-bottom: 1px dotted black; } #contenting p { font-family: FLight; font-size: 0.4em; } #contenting a { color:black; font-family: monospace; font-size: 1.2em; margin:0; } #contenting a:visited { color:black; font-family: monospace; font-size: 1.2em; margin:0; } h1 { padding-top:20px; text-transform:uppercase; font-family: FBold; font-size:2em; line-height: 20px; margin:0; } h2 { font-family: Regular; font-size:1.2em; margin:0; } p { margin:0; font-family: FLight; } #footer { z-index:-1; position:fixed; width:100vw; bottom:0; margin:0; padding:0; height: 17.5vh; background-color:#EDF0D5; } #footer-text { position: absolute; margin:10px 0 0 15px; padding: 10px; width:50vw; height:8vh; } #annuaire { font-family:Regular; font-size:0.8em; display: flex; justify-content: center; position:absolute; right:15px; margin: 25px 0 0 0; width:85px; height:60px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #atlas{ font-family:Regular; font-size:0.8em; display: flex; justify-content: center; position:absolute; right:110px; margin: 25px 0 0 0; width:85px; height:60px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #add{ font-family:Regular; font-size:0.8em; display: flex; justify-content: center; position:absolute; right:205px; margin: 25px 0 0 0; width:85px; height:60px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } /* required styles */ .leaflet-pane, .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow, .leaflet-tile-container, .leaflet-pane > svg, .leaflet-pane > canvas, .leaflet-zoom-box, .leaflet-image-layer, .leaflet-layer { position: absolute; left: 0; top: 0; } .leaflet-container { overflow: hidden; } .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow { -webkit-user-select: none; -moz-user-select: none; user-select: none; -webkit-user-drag: none; } /* Prevents IE11 from highlighting tiles in blue */ .leaflet-tile::selection { background: transparent; } /* Safari renders non-retina tile on retina better with this, but Chrome is worse */ .leaflet-safari .leaflet-tile { image-rendering: -webkit-optimize-contrast; } /* hack that prevents hw layers "stretching" when loading new tiles */ .leaflet-safari .leaflet-tile-container { width: 1600px; height: 1600px; -webkit-transform-origin: 0 0; } .leaflet-marker-icon, .leaflet-marker-shadow { display: block; } /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ .leaflet-container .leaflet-overlay-pane svg { max-width: none !important; max-height: none !important; } .leaflet-container .leaflet-marker-pane img, .leaflet-container .leaflet-shadow-pane img, .leaflet-container .leaflet-tile-pane img, .leaflet-container img.leaflet-image-layer, .leaflet-container .leaflet-tile { max-width: none !important; max-height: none !important; width: auto; padding: 0; } .leaflet-container.leaflet-touch-zoom { -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; } .leaflet-container.leaflet-touch-drag { -ms-touch-action: pinch-zoom; /* Fallback for FF which doesn't support pinch-zoom */ touch-action: none; touch-action: pinch-zoom; } .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { -ms-touch-action: none; touch-action: none; } .leaflet-container { -webkit-tap-highlight-color: transparent; } .leaflet-container a { -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); } .leaflet-tile { filter: inherit; visibility: hidden; } .leaflet-tile-loaded { visibility: inherit; } .leaflet-zoom-box { width: 0; height: 0; -moz-box-sizing: border-box; box-sizing: border-box; z-index: 800; } /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ .leaflet-overlay-pane svg { -moz-user-select: none; } .leaflet-pane { z-index: 400; } .leaflet-tile-pane { z-index: 200; } .leaflet-overlay-pane { z-index: 400; } .leaflet-shadow-pane { z-index: 500; } .leaflet-marker-pane { z-index: 600; } .leaflet-tooltip-pane { z-index: 650; } .leaflet-popup-pane { z-index: 700; } .leaflet-map-pane canvas { z-index: 100; } .leaflet-map-pane svg { z-index: 200; } .leaflet-vml-shape { width: 1px; height: 1px; } .lvml { behavior: url(#default#VML); display: inline-block; position: absolute; } /* control positioning */ .leaflet-control { position: relative; z-index: 800; pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: auto; } .leaflet-top, .leaflet-bottom { position: absolute; z-index: 1000; pointer-events: none; } .leaflet-top { top: 0; } .leaflet-right { right: 0; } .leaflet-bottom { bottom: 0; } .leaflet-left { left: 0; } .leaflet-control { float: left; clear: both; } .leaflet-right .leaflet-control { float: right; } .leaflet-top .leaflet-control { margin-top: 10px; } .leaflet-bottom .leaflet-control { margin-bottom: 10px; } .leaflet-left .leaflet-control { margin-left: 10px; } .leaflet-right .leaflet-control { margin-right: 10px; } /* zoom and fade animations */ .leaflet-fade-anim .leaflet-popup { opacity: 0; -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; transition: opacity 0.2s linear; } .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { opacity: 1; } .leaflet-zoom-animated { -webkit-transform-origin: 0 0; -ms-transform-origin: 0 0; transform-origin: 0 0; } svg.leaflet-zoom-animated { will-change: transform; } .leaflet-zoom-anim .leaflet-zoom-animated { -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); transition: transform 0.25s cubic-bezier(0,0,0.25,1); } .leaflet-zoom-anim .leaflet-tile, .leaflet-pan-anim .leaflet-tile { -webkit-transition: none; -moz-transition: none; transition: none; } .leaflet-zoom-anim .leaflet-zoom-hide { visibility: hidden; } /* cursors */ .leaflet-interactive { cursor: pointer; } .leaflet-grab { cursor: -webkit-grab; cursor: -moz-grab; cursor: grab; } .leaflet-crosshair, .leaflet-crosshair .leaflet-interactive { cursor: crosshair; } .leaflet-popup-pane, .leaflet-control { cursor: auto; } .leaflet-dragging .leaflet-grab, .leaflet-dragging .leaflet-grab .leaflet-interactive, .leaflet-dragging .leaflet-marker-draggable { cursor: move; cursor: -webkit-grabbing; cursor: -moz-grabbing; cursor: grabbing; } /* marker ; overlays interactivity */ .leaflet-marker-icon, .leaflet-marker-shadow, .leaflet-image-layer, .leaflet-pane > svg path, .leaflet-tile-container { pointer-events: none; } .leaflet-marker-icon.leaflet-interactive, .leaflet-image-layer.leaflet-interactive, .leaflet-pane > svg path.leaflet-interactive, svg.leaflet-image-layer.leaflet-interactive path { pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: auto; } /* visual tweaks */ .leaflet-container { background: #ddd; outline-offset: 1px; } .leaflet-container a { color: #0078A8; } .leaflet-zoom-box { border: 2px dotted #38f; background: rgba(255,255,255,0.5); } /* general typography */ .leaflet-container { font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; font-size: 12px; font-size: 0.75rem; line-height: 1.5; } /* general toolbar styles */ .leaflet-bar { } .leaflet-bar a { background-color: #fff; width: 26px; height: 26px; line-height: 26px; display: block; text-align: center; text-decoration: none; color: black; } .leaflet-bar a, .leaflet-control-layers-toggle { background-position: 50% 50%; background-repeat: no-repeat; display: block; } .leaflet-bar a:hover, .leaflet-bar a:focus { background-color: #f4f4f4; } .leaflet-bar a:first-child { border-bottom: none; } .leaflet-bar a:last-child { } .leaflet-bar a.leaflet-disabled { cursor: default; background-color: #f4f4f4; color: #bbb; } .leaflet-touch .leaflet-bar a { width: 30px; height: 30px; line-height: 30px; } .leaflet-touch .leaflet-bar a:first-child { } .leaflet-touch .leaflet-bar a:last-child { } /* zoom control */ .leaflet-control-zoom-in, .leaflet-control-zoom-out { font: bold 18px 'Lucida Console', Monaco, monospace; text-indent: 1px; } .leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { font-size: 22px; border:0.75px solid; } /* layers control */ .leaflet-control-layers { box-shadow: 0 1px 5px rgba(0,0,0,0.4); background: #fff; border-radius: 5px; } .leaflet-control-layers-toggle { background-image: url(images/layers.png); width: 36px; height: 36px; } .leaflet-retina .leaflet-control-layers-toggle { background-image: url(images/layers-2x.png); background-size: 26px 26px; } .leaflet-touch .leaflet-control-layers-toggle { width: 44px; height: 44px; } .leaflet-control-layers .leaflet-control-layers-list, .leaflet-control-layers-expanded .leaflet-control-layers-toggle { display: none; } .leaflet-control-layers-expanded .leaflet-control-layers-list { display: block; position: relative; } .leaflet-control-layers-expanded { padding: 6px 10px 6px 6px; color: #333; background: #fff; } .leaflet-control-layers-scrollbar { overflow-y: scroll; overflow-x: hidden; padding-right: 5px; } .leaflet-control-layers-selector { margin-top: 2px; position: relative; top: 1px; } .leaflet-control-layers label { display: block; font-size: 13px; font-size: 1.08333em; } .leaflet-control-layers-separator { height: 0; border-top: 1px solid #ddd; margin: 5px -10px 5px -6px; } /* Default icon URLs */ .leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ background-image: url(images/marker-icon.png); } /* attribution and scale controls */ .leaflet-container .leaflet-control-attribution { background: #fff; background: rgba(255, 255, 255, 0.8); margin: 0; } .leaflet-control-attribution, .leaflet-control-scale-line { padding: 0 5px; color: #333; line-height: 1.4; } .leaflet-control-attribution a { text-decoration: none; } .leaflet-control-attribution a:hover, .leaflet-control-attribution a:focus { text-decoration: underline; } .leaflet-attribution-flag { display: inline !important; vertical-align: baseline !important; width: 1em; height: 0.6669em; } .leaflet-left .leaflet-control-scale { margin-left: 5px; } .leaflet-bottom .leaflet-control-scale { margin-bottom: 5px; } .leaflet-control-scale-line { border-top: none; line-height: 1.1; padding: 2px 5px 1px; white-space: nowrap; -moz-box-sizing: border-box; box-sizing: border-box; background: rgba(255, 255, 255, 0.8); text-shadow: 1px 1px #fff; } .leaflet-control-scale-line:not(:first-child) { border-top: 2px solid #777; border-bottom: none; margin-top: -2px; } .leaflet-control-scale-line:not(:first-child):not(:last-child) { border-bottom: 2px solid #777; } .leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-bar { } .leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-bar { border: 1px solid black; background-clip: padding-box; } /* popup */ .leaflet-popup { position: absolute; text-align: center; margin-bottom: 20px; } .leaflet-popup-content-wrapper { color:yellow; padding: 1px; text-align: left; border-radius: 12px; } .leaflet-popup-content { margin: 13px 24px 13px 20px; line-height: 1.3; font-size: 13px; font-size: 1.08333em; min-height: 1px; } .leaflet-popup-content p { margin: 17px 0; margin: 1.3em 0; } .leaflet-popup-tip-container { width: 40px; height: 20px; position: absolute; left: 50%; margin-top: -1px; margin-left: -20px; overflow: hidden; pointer-events: none; } .leaflet-popup-tip { width: 17px; height: 17px; padding: 1px; margin: -10px auto 0; pointer-events: auto; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } .leaflet-popup-content-wrapper, .leaflet-popup-tip { background: white; color: #333; box-shadow: 0 3px 14px rgba(0,0,0,0.4); } .leaflet-container a.leaflet-popup-close-button { position: absolute; top: 0; right: 0; border: none; text-align: center; width: 24px; height: 24px; font: 16px/24px Tahoma, Verdana, sans-serif; color: #757575; text-decoration: none; background: transparent; } .leaflet-container a.leaflet-popup-close-button:hover, .leaflet-container a.leaflet-popup-close-button:focus { color: #585858; } .leaflet-popup-scrolled { overflow: auto; } .leaflet-oldie .leaflet-popup-content-wrapper { -ms-zoom: 1; } .leaflet-oldie .leaflet-popup-tip { width: 24px; margin: 0 auto; -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); } .leaflet-oldie .leaflet-control-zoom, .leaflet-oldie .leaflet-control-layers, .leaflet-oldie .leaflet-popup-content-wrapper, .leaflet-oldie .leaflet-popup-tip { border: 1px solid #999; } /* div icon */ .leaflet-div-icon { background: #fff; } /* Tooltip */ /* Base styles for the element that has a tooltip */ .leaflet-tooltip { position: absolute; padding: 6px; background-color: #fff; border: 1px solid #fff; border-radius: 3px; color: #222; white-space: nowrap; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; pointer-events: none; box-shadow: 0 1px 3px rgba(0,0,0,0.4); } .leaflet-tooltip.leaflet-interactive { cursor: pointer; pointer-events: auto; } .leaflet-tooltip-top:before, .leaflet-tooltip-bottom:before, .leaflet-tooltip-left:before, .leaflet-tooltip-right:before { position: absolute; pointer-events: none; border: 6px solid transparent; background: transparent; content: ""; } /* Directions */ .leaflet-tooltip-bottom { margin-top: 6px; } .leaflet-tooltip-top { margin-top: -6px; } .leaflet-tooltip-bottom:before, .leaflet-tooltip-top:before { left: 50%; margin-left: -6px; } .leaflet-tooltip-top:before { bottom: 0; margin-bottom: -12px; border-top-color: #fff; } .leaflet-tooltip-bottom:before { top: 0; margin-top: -12px; margin-left: -6px; border-bottom-color: #fff; } .leaflet-tooltip-left { margin-left: -6px; } .leaflet-tooltip-right { margin-left: 6px; } .leaflet-tooltip-left:before, .leaflet-tooltip-right:before { top: 50%; margin-top: -6px; } .leaflet-tooltip-left:before { right: 0; margin-right: -12px; border-left-color: #fff; } .leaflet-tooltip-right:before { left: 0; margin-left: -12px; border-right-color: #fff; } /* Printing */ @media print { /* Prevent printers from removing background-images of controls. */ .leaflet-control { -webkit-print-color-adjust: exact; print-color-adjust: exact; } } @media only screen and (max-width: 600px) { body{ } h1 { font-size:1.2em; line-height: 15px; } h2 { font-size:0.8em; } #menuicon { font-family:Regular; display:block; text-align: center; background-color: lightblue; position: absolute; margin: 15px 15px 25px 0; padding-top: 25px; right:0; bottom:0; height:45px; width:125px; border: 1.5px dashed black; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #annuaire { font-family:Regular; font-size:0.8em; display: block; text-align: center; justify-content: center; position:absolute; right:0; margin:10px 20px 0 0; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #atlas{ font-family:Regular; font-size:0.8em; display:block; justify-content: center; position:absolute; right:0; margin:45px 20px 0 0 ; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #add{ font-family:Regular; font-size:0.8em; display: block; position:absolute; right:0px; margin: 80px 20px 0 0; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #menu-mobile { z-index:10; position:fixed; top:0; display:none; width: 100vw; height:calc(100vh - 17.5vh); background-color: lightgrey; } #menu-ordi { display:none; } #menu-mobile a { text-decoration: none; font-family: Regular; font-size: 18px; display:block; position:relative; padding: 10px 10px 10px 25px; margin:25px 25px 0 25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #contenting { } #close { text-decoration: none; font-family: Regular; color:whitesmoke; text-align:center; background-color: black; font-size: 18px; display:block; position:relative; padding: 10px 10px 10px 25px; margin:25px 25px 0 25px; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #mapid { display:block; } .texte { text-decoration: underline; margin-top: 4px; text-align: center; text-justify: center; } }document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/1.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button2").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/2.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button3").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/3.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button4").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/4.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button5").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/5.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button2").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/6.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button7").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/7.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button8").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/8.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); }); document.addEventListener("DOMContentLoaded", function() { // Écouteur d'événement pour le clic sur la div document.getElementById("button9").addEventListener("click", function() { // Changer la source de la vidéo var videoSource = document.getElementById("videoSource"); videoSource.src = "vidéo/9.mp4"; // Charger la nouvelle vidéo var videoPlayer = document.getElementById("myVideo"); videoPlayer.load(); }); });<!DOCTYPE html> <html lang="fr"> <head> <meta charset="utf-8" /> <title>Dirty Video Mixer</title> <script src="../Dirty Video Mixer/action.js"></script> <link href="../Dirty Video Mixer/style.css" rel="stylesheet" type="text/css"> </head> <body> <div id="gauche"> <h1>DIRTY VIDEO MIXER</h1> <div id="gauche-gauche"> <div id="box"> <p><mark>Le Dirty Video Mixer est un appareil électronique utilisé en vidéo-art pour mélanger des signaux vidéo en temps réel, créant ainsi des images et des effets visuels uniques. Le terme "dirty" se réfère à l'utilisation de signaux vidéo analogiques, qui peuvent être altérés et modifiés pour créer des effets de distorsion, de couleur et de mouvement. Les artistes utilisent souvent le Dirty Video Mixer pour créer des performances en direct ou des installations vidéo. Il peut être considéré comme une alternative low-tech à l'utilisation de logiciels de montage vidéo par sa fléxibilité d'usage en temps réel.</mark></p> </div> <img src="T1.png" id="dvm-picture" style="width:calc(100% - 2px);"> <div id="box" style="margin-top:-6px"> <p><mark><mark class="mark2">Pour fabriquer le Dirty Video Mixer, vous aurez besoin des éléments suivant.</mark><br><br> <mark > - De fil électrique<br> - De deux interrupteurs<br> - Trois RCA femelles<br> - Un potentiomètre 1K<br> - Un fer à souder pour électronique<br> - Une pince pour les fils électriques</p> </div> <div id="box" style="margin-top:-6px"> <p><mark> Vous pouvez les acheter sur des sites spécialisés, tels que https://www.gotronic.fr/ ou https://www.conrad.fr/. <br><br>Néanmoins, vous avez également la possibilité de les récupérer sur du vieux matériel électronique. <br><br><mark class="mark2">Pour les connecteurs RCA femelles :</mark></br> Vous pouvez les trouver sur les lecteurs de cassettes, les systèmes stéréo et les amplificateurs, les téléviseurs à tube cathodique et le vieux matériel audiovisuel. <br><br><mark class="mark2">Pour les interrupteurs :</mark></br> Ils se trouvent sur de nombreux appareils électroniques obsolètes, du matériel informatique, des appareils ménagers ou encore des jouets électroniques. <br><br><mark class="mark2">Pour le potentiomètre de 1k :</mark></br> Vous pouvez le trouver sur des ordinateurs ou des périphériques, des radios ou du matériel audio, ou encore dans des fablabs. Vérifiez bien la valeur du potentiomètre avant de le récupérer. <br><br><mark class="mark2">Pour le fil :</mark></br> Vous en trouverez sur la plupart des vieux appareils électroniques.</mark> </p> </div> </div> <div id="gauche-droite"> <img src="canvas1.png" id="dvm-picture"> <div id="box" style="margin-top:-7px"> <p><mark>On peut retracer l'origine de ce dispositif jusque dans les installations de Nam June Paik.Entre 1969 et 1971, en collaboration avec le technicien et spécialiste de la télévision Shuya Abe, Paik a construit un synthétiseur vidéo qui lui a permis de monter simultanément sept sources différentes, en temps réel. Sept caméras sont calibrées pour recevoir sept couleurs, chacune ne percevant/photographiant qu'une seule couleur. L'équipement est complété par un bouton de mélange et une petite horloge qui inverse les couleurs, de l'ultraviolet à l'infrarouge.</mark></p> </div> <img src="T2.jpg" id="dvm-picture" style="width:calc(100% - 2px);"> <div id="box" style="margin-top:-7px"> <p><mark>Pour la construction de ce dernier, vous pouvez vous fier à ce schéma ci-dessous. Pour les branchements, je vous redirige vers des vidéos qui sauront mieux les expliquer visuellement : <br><br> <mark class="mark2">https://youtu.be/vMbYGq-RUOo</mark> <br>(en anglais)<br> <mark class="mark2">https://youtu.be/iSRWvQf3u2c </mark><br>(en anglais) <br><br> Ces deux tutoriels vous apprendront à créer le circuit. Pour la boîte, laissez libre cours à votre imagination. Pour ma part, j'utilise un récipient en plastique que je perfore pour faire passer tous mes composants. Je place le circuit à l'intérieur de la boîte et mes différents éléments en ressortent, ce qui protège un peu le circuit. Je vous joins également un fichier PDF en bas de la page si vous souhaitez reproduire ma boîte. <br><br> <mark class="mark2">Un petit conseil pour la soudure </mark><br> Chauffez votre fer à souder, utilisez des petites barres de métal pour la soudure, chauffez votre câble (préalablement dénudé) et l'endroit où vous souhaitez le souder. Ensuite, placez la pointe du fer sur le morceau de métal jusqu'à ce qu'une boule liquide se forme, puis déposez-la à la jonction des deux connectiques. Si vous trouvez que votre soudure est fragile, vous pouvez toujours la refaire chauffer pour la re-tenter.</mark></p> </div> </div> <!-- <div class="block-youtube"> <h2>Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/PYpUOzEz4I4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div> <div class="block-youtube"> <h2 >Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/ujOkuVwgVA4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div> <div class="block-youtube"> <h2 >Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/PYpUOzEz4I4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div>--> </div> <div id="right"> <div id="video"> <video autoplay muted loop control id="myVideo"> <source id="videoSource" src="" type="video/mp4"> </video> </div> <div id="droite"> <div id="inside-block"> <p class="settings" id="button" style="margin-top:13px;">V1DEO</p> <p class="settings" id="button2" style=" margin-top:13px;">VID2O</p> <p class="settings" id="button3"style=" margin-top:13px;">VID3O</p> <p class="settings" id="button4"style=" margin-top:25px;">VI4EO</p> <p class="settings" id="button5"style=" margin-top:25px;">VIDE5</p> <p class="settings" id="button6"style=" margin-top:25px;">6IDEO</p> <p class="settings" id="button7"style=" margin-top:25px;">V7DEO</p> <p class="settings" id="button8"style=" margin-top:25px; ">VID8O</p> <p class="settings" id="button9"style=" margin-top:25px;">VIDE9</p> <p style=" color:white; text-align:center; font-style:italic;">Cliquez sur les boutons pour lancer une vidéo.</p> <script src="action.js"></script> </div> </div> <div id="colophon"> <p style="padding:25px 10px 5px 10px; text-decoration:underline; text-underline-offset:3px; color:white;"><a href="DVM.pdf" style="color:white" target="_blank">- Pour télécharger le modèle de la boite du DVM -</a></p> </div> </div> </body> </html><!DOCTYPE html> <html lang="fr"> <head> <meta charset="utf-8" /> <title>Dirty Video Mixer</title> <script src="../Dirty Video Mixer/action.js"></script> <link href="../Dirty Video Mixer/style.css" rel="stylesheet" type="text/css"> </head> <body> <div id="gauche"> <h1>DIRTY VIDEO MIXER</h1> <div id="gauche-gauche"> <div id="box"> <p><mark>Le Dirty Video Mixer est un appareil électronique utilisé en vidéo-art pour mélanger des signaux vidéo en temps réel, créant ainsi des images et des effets visuels uniques. Le terme "dirty" se réfère à l'utilisation de signaux vidéo analogiques, qui peuvent être altérés et modifiés pour créer des effets de distorsion, de couleur et de mouvement. Les artistes utilisent souvent le Dirty Video Mixer pour créer des performances en direct ou des installations vidéo. Il peut être considéré comme une alternative low-tech à l'utilisation de logiciels de montage vidéo par sa fléxibilité d'usage en temps réel.</mark></p> </div> <img src="T1.png" id="dvm-picture" style="width:calc(100% - 2px);"> <div id="box" style="margin-top:-6px"> <p><mark><mark class="mark2">Pour fabriquer le Dirty Video Mixer, vous aurez besoin des éléments suivant.</mark><br><br> <mark > - De fil électrique<br> - De deux interrupteurs<br> - Trois RCA femelles<br> - Un potentiomètre 1K<br> - Un fer à souder pour électronique<br> - Une pince pour les fils électriques</p> </div> <div id="box" style="margin-top:-6px"> <p><mark> Vous pouvez les acheter sur des sites spécialisés, tels que https://www.gotronic.fr/ ou https://www.conrad.fr/. <br><br>Néanmoins, vous avez également la possibilité de les récupérer sur du vieux matériel électronique. <br><br><mark class="mark2">Pour les connecteurs RCA femelles :</mark></br> Vous pouvez les trouver sur les lecteurs de cassettes, les systèmes stéréo et les amplificateurs, les téléviseurs à tube cathodique et le vieux matériel audiovisuel. <br><br><mark class="mark2">Pour les interrupteurs :</mark></br> Ils se trouvent sur de nombreux appareils électroniques obsolètes, du matériel informatique, des appareils ménagers ou encore des jouets électroniques. <br><br><mark class="mark2">Pour le potentiomètre de 1k :</mark></br> Vous pouvez le trouver sur des ordinateurs ou des périphériques, des radios ou du matériel audio, ou encore dans des fablabs. Vérifiez bien la valeur du potentiomètre avant de le récupérer. <br><br><mark class="mark2">Pour le fil :</mark></br> Vous en trouverez sur la plupart des vieux appareils électroniques.</mark> </p> </div> </div> <div id="gauche-droite"> <img src="canvas1.png" id="dvm-picture"> <div id="box" style="margin-top:-7px"> <p><mark>On peut retracer l'origine de ce dispositif jusque dans les installations de Nam June Paik.Entre 1969 et 1971, en collaboration avec le technicien et spécialiste de la télévision Shuya Abe, Paik a construit un synthétiseur vidéo qui lui a permis de monter simultanément sept sources différentes, en temps réel. Sept caméras sont calibrées pour recevoir sept couleurs, chacune ne percevant/photographiant qu'une seule couleur. L'équipement est complété par un bouton de mélange et une petite horloge qui inverse les couleurs, de l'ultraviolet à l'infrarouge.</mark></p> </div> <img src="T2.jpg" id="dvm-picture" style="width:calc(100% - 2px);"> <div id="box" style="margin-top:-7px"> <p><mark>Pour la construction de ce dernier, vous pouvez vous fier à ce schéma ci-dessous. Pour les branchements, je vous redirige vers des vidéos qui sauront mieux les expliquer visuellement : <br><br> <mark class="mark2">https://youtu.be/vMbYGq-RUOo</mark> <br>(en anglais)<br> <mark class="mark2">https://youtu.be/iSRWvQf3u2c </mark><br>(en anglais) <br><br> Ces deux tutoriels vous apprendront à créer le circuit. Pour la boîte, laissez libre cours à votre imagination. Pour ma part, j'utilise un récipient en plastique que je perfore pour faire passer tous mes composants. Je place le circuit à l'intérieur de la boîte et mes différents éléments en ressortent, ce qui protège un peu le circuit. Je vous joins également un fichier PDF en bas de la page si vous souhaitez reproduire ma boîte. <br><br> <mark class="mark2">Un petit conseil pour la soudure </mark><br> Chauffez votre fer à souder, utilisez des petites barres de métal pour la soudure, chauffez votre câble (préalablement dénudé) et l'endroit où vous souhaitez le souder. Ensuite, placez la pointe du fer sur le morceau de métal jusqu'à ce qu'une boule liquide se forme, puis déposez-la à la jonction des deux connectiques. Si vous trouvez que votre soudure est fragile, vous pouvez toujours la refaire chauffer pour la re-tenter.</mark></p> </div> </div> <!-- <div class="block-youtube"> <h2>Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/PYpUOzEz4I4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div> <div class="block-youtube"> <h2 >Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/ujOkuVwgVA4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div> <div class="block-youtube"> <h2 >Exemple de DVM</h2> <iframe src="https://www.youtube-nocookie.com/embed/PYpUOzEz4I4" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </div>--> </div> <div id="right"> <div id="video"> <video autoplay muted loop control id="myVideo"> <source id="videoSource" src="" type="video/mp4"> </video> </div> <div id="droite"> <div id="inside-block"> <p class="settings" id="button" style="margin-top:13px;">V1DEO</p> <p class="settings" id="button2" style=" margin-top:13px;">VID2O</p> <p class="settings" id="button3"style=" margin-top:13px;">VID3O</p> <p class="settings" id="button4"style=" margin-top:25px;">VI4EO</p> <p class="settings" id="button5"style=" margin-top:25px;">VIDE5</p> <p class="settings" id="button6"style=" margin-top:25px;">6IDEO</p> <p class="settings" id="button7"style=" margin-top:25px;">V7DEO</p> <p class="settings" id="button8"style=" margin-top:25px; ">VID8O</p> <p class="settings" id="button9"style=" margin-top:25px;">VIDE9</p> <p style=" color:white; text-align:center; font-style:italic;">Cliquez sur les boutons pour lancer une vidéo.</p> <script src="action.js"></script> /* Importation des polices d'écriture */ @font-face { font-family: 'Arkes'; src: url(fonts/arkessolidregular.ttf); } body { margin:0; background-color: red; } .block-youtube { height:100%; width:calc(100% - 4px); margin:0; padding:0; margin-right:0; } #box { width:calc(100% - 2px); position:relative; border-bottom:2px solid white; background-color: lightgrey; border-radius:50px; margin:0; border:2px solid red; margin-top:-2px; } #box2 { width:50%; position:absolute; left:25%; } #dvm { position:absolute; margin:0; } marquee { color:white; } #gauche-gauche { position:absolute; width:50%; left:0px; } #gauche-droite { position:absolute; width:50%; left:50%; } #dvm-picture { height:auto; width:calc(100% - 4px); margin-left:0px; background-color: white; border-radius:50px; border:2px solid red; margin-top:-2px; } #myVideo { position:absolute; margin:0; padding:0; z-index:-10; right: 0; height:100%; width:100%; object-fit:fill; border-radius:50px; border:2px solid yellow; } #video { position:fixed; right:0; top:0; width:50%; height:50%; } .youtube { position:relative; display:grid; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); gap:25px; padding:25px 0 25px 0; } iframe { width:calc(100% + 2px); background-color: rgb(255, 255, 255); border:2px solid red; border-radius:0 0 50px 50px; margin-top:-2px; margin-bottom:0px; } #inside-block { height:calc(100% - 50px); width:calc(100% - 50px); margin:25px; } #colophon { overflow:hidden; text-align:center; position:fixed; width:calc(50% - 2px); height:calc(10% - 0px); background-color: rgb(0, 0, 0); bottom:0; right:0; border:2px solid yellow; border-radius:50px; } #droite { margin:5px 0 0 0; top:calc(50% - 4px); right:0; position:fixed; width:50%; height:calc(40% - 6px); background-color: rgb(0, 0, 0); border:2px solid yellow; border-radius:50px; } ::-webkit-scrollbar { height:0px; width: 0px; background: transparent; /* make scrollbar transparent */ } #gauche { border-radius:50px; background-color: rgb(0, 0, 0); position:fixed; left:0; top:0; margin-bottom:0; width:calc(50% - 5px); height:calc(100% - 4px); overflow:scroll; overflow-x: hidden; border: 2px solid yellow; } .mark2 { background-color: black; color:white; } .settings { display:inline-block; position:relative; width:30%; height:30px; text-align:center; padding:10px 5px 0px 5px; background-color: lightgrey; border-radius:50px; color:black; border:1.5px solid red; box-shadow: 2px 1px 37px -14px rgba(242,255,7,0.75); -webkit-box-shadow: 2px 1px 37px -14px rgba(242,255,7,0.75); -moz-box-shadow: 2px 1px 37px -14px rgba(242,255,7,0.75); } h1 { z-index:10; margin:0; width:calc(100% - 4px); text-align: center; background-color: rgb(0, 0, 0); padding:20px 0 20px 0; border:2px solid red; border-radius:50px; font-family:sans-serif; color:rgb(255, 255, 255); margin-top:-2px; } h2 { margin:2px 0 0 0 ; width:calc(100% + 2px); padding:10px 0 10px 0; font-family:sans-serif; font-size:1.2em; text-align: center; background-color: lightgrey; color:rgb(0, 0, 0); border-radius:50px 50px 0 0; border:2px solid red; } ul { margin-left:25px; font-family:sans-serif; font-size:1.1em; color:rgb(0, 0, 0); padding:25px 15px 25px 25px; margin:0; orphans: 3; widows: 3; line-height:1.2em; } p { font-family:sans-serif; font-size:1.1em; color:rgb(0, 0, 0); padding:25px 15px 25px 25px; margin:0; orphans: 3; widows: 3; line-height:1.2em; } .texte-box { background-color: black; border-radius:50px; border:2px solid red; } ::selection { background-color:rgb(0, 255, 0); color:black; padding:0 10px 0 10px; } @media only screen and (max-width: 600px) { p { font-family:sans-serif; } } </div> </div> <div id="colophon"> <p style="padding:25px 10px 5px 10px; text-decoration:underline; text-underline-offset:3px; color:white;"><a href="DVM.pdf" style="color:white" target="_blank">- Pour télécharger le modèle de la boite du DVM -</a></p> </div> </div> </body> </html>let menuToggle = document.querySelector('.menu-toggle'); let menu = document.querySelector('.menu'); menuToggle.addEventListener('click', function() { menu.querySelector('ul').classList.toggle('open'); }); var fixed = document.getElementById('fixed'); fixed.addEventListener('touchmove', function(e) { e.preventDefault(); }, false); document.querySelectorAll('section').forEach(function(section) { section.addEventListener('click', function() { document.querySelectorAll('section').forEach(function(s) { s.classList.remove('active'); }); this.classList.add('active'); }); }); document.querySelector("#menu-icon").addEventListener("click", function(){ document.querySelector("#menu-page").style.display = "block"; }); function openContent(ref) { var a = document.getElementById(ref); console.log(a); a.style.visibility = "visible"; } function closeContent(ref) { var a = document.getElementById(ref); console.log(a); a.style.visibility = "hidden"; } function yo() { window.location.href ="#accueil"; }<!DOCTYPE html> <html> <!-- --> <head> <meta charset="UTF-8"> <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"> <link id="css" rel="stylesheet" href="/Dynamo/style.css"> <script src="action.js"></script> </head> <body onload="yo()"> <!-- Page d'accueil --> <section id="accueil"> <object data="img/dynamo.svg" type="image/svg+xml"></object> <p><h3>Restitution du workshop ÉNERGIE d’Hyper.local</h3></p> <p>L’unité de recherche <u><a href="http://www.esac-cambrai.net/wordpress/hyper-local/" target="_blank">Hyper.local</a></u> réunit les écoles supérieures d’art de Cambrai (Esac), de Valenciennes (ESAD) et de Dunkerque-Tourcoing (esä). Cette unité regroupe des activités de recherche et des activités pédagogiques qui s'articulent autour des questions relatives à l'art, au design et à la communication dans une société contemporaine où les formes de conception, de création, d'échange et de savoir sont redéfinies par les changements technologiques, sociaux, économiques et écologiques.</P> <p>En lien avec <u><a href="https://www.fracgrandlarge-hdf.fr/commissaires-de-la-triennale-art-industrie-2/" target="_blank">la triennale art & industrie</a></u> (10 juin 2023 – 7 janvier 2024) portée par le FRAC Grand large et le LAAC à Dunkerque, Hyper.local s’est emparé de la question de l’énergie en proposant aux étudiant·es des trois écoles de se retrouver à l’esä de Dunkerque autour de cette thématique autour de cette thématique. En ont découlé trois workshops : Les potentiel des riens par Guilhem Roubichou, Glanneur de cellules par Chloé Desmoineaux et Act for Energy de Cédric Carles. Ces trois ateliers ont ensuite été restitué sous forme d'exposition au sein de l'Ésac. </p> </section> <!-- Workshops --> <section id="potentiel-des-riens"> <div id="texte-workshop"> <br> <h1>Workshop 1 ✨</h1> <h3><b>Les potentiels des riens</b> par <a href="https://cargocollective.com/guilhemroubichou" target="_blank" style="color:black; text-decoration:underline"><i>Guilhem Roubichou</i></a></h3> <p>En 2018, avec son œuvre <i>Energy</i>, Guilhem Roubichou détournait un panneau qui indiquait une usine de piles électriques ayant fait faillite dans la zone industrielle d'Anderlecht en Belgique. Pour ce workshop, l’artiste a proposé aux étudiant.es de travailler sur "Les potentiels des riens". Les participant·es sont parti.es de l’une des définitions de l'énergie, à savoir : "la capacité à effectuer des transformations" pour engager une réflexion puis une production à partir d'objets et/ou de matières glanés sur le territoire de Dunkerque qui ont ensuite été modifiés, transformés ou déplacés. Les étudiant-es ont ainsi pu explorer et exploiter les potentiels de ces éléments afin qu’ils puissent les inscrire dans une démarche artistique personnelle que ce soit sous forme d’installations, de sérigraphies, de vidéos, de performances ou encore de dessins numériques.</p> <br> </div> <div class="grid-potentiels-des-riens"> <div class="col-potentiels-des-riens"> <img src="img/r1.jpg"> <p>Installation d'Axel Fontenil et de Baptiste Coppée</p> </div> <div class="col-potentiels-des-riens"> <img src="img/r2.jpg"> <p>Détails d'une' cartographie des enseignes de Dunkerque</p> </div> <div class="col-potentiels-des-riens"> <img src="img/r5.jpg"> <p>Sérigraphie de Léna Monot et Marion Quillien</p> </div> <div class="col-potentiels-des-riens"> <img src="img/r4.jpg"> <p>Impression laser de Melvil Duplant</p> </div> </div> </section> <!-- Glanneur de Cellule--> <section id="glanneur-de-cellules"> <div id="texte-workshop"> <br> <h1>Workshop 2 🕹</h1> <h3><b>Ramasse Miette, Récupérateur de mémoire et glaneur de cellules</b> par <a href="https://chloedesmoineaux.surf/" target="_blank" style="color:black; text-decoration:underline"><i>Chloé Desmoineaux</i></a></h3> <p>Cet atelier est parti d’un constat : les innovations technologiques de l’industrie du vidéo sont extrêmement énergivores (les jeux sont hébergés sur des serveurs distants, suscitent des achats compulsifs et donc de l’obsolescence programmée et sont en constante recherche de l’amélioration de la performance basée sur la rapidité de calculs et un graphisme ultra réaliste). La proposition était d’explorer et de réaliser des jeux qui généreraient le moins de données possibles, en prenant justement le contre-pied des conséquences énergétiques de l’innovation et en s'intéressant davantage aux outils indépendants créés dans les marges, qui puisent leur créativité sur l’exploration, l’<i>open-sourcing</i> et le réemploi de technologies préexistantes. Des outils et des jeux qui ne demandent pas des ordinateurs derniers cris ou un disque dur dédié pour pouvoir être utilisés. La contrainte du petit format devenait un élément à part entière du concept du logiciel. Les participant.es ont également pu travailler sur le recyclage de manettes et le réemploi d’outils déjà à disposition, en s’attardant sur leurs détournements possibles et sur leurs utilisations les plus basiques. Les travaux présentés sont un appel à la création humble et raisonnée mais non moins dénuée d’inventivité et de poésie.</p> <br> </div> <div class="grid-jeux"> <div class="grid-item-jeux"><a href="jeux/Une dégustation sans faim.html" target="_blank"><img src="img/7.png" style="width: 100%; height:auto"></a> <p><i>Une dégustation sans faim</i><br>Artiste Inconnu·e</p></div> <div class="grid-item-jeux"><a href="jeux/The Assistant.html" target="_blank"><img src="img/8.png" style="width: 100%; height:auto"></a> <p><i>The Assistant</i><br>Solène Poizot</p></div> <div class="grid-item-jeux"><a href="jeux/Tech.Luca.01.html" target="_blank"><img src="img/9.png" style="width: 100%; height:auto"></a> <p><i>Tech.Luca.01</i><br>Artiste Inconnu·e</p></div> <div class="grid-item-jeux"><a href="jeux/Routine.html" target="_blank"><img src="img/10.png" style="width: 100%; height:auto"></a> <p><i>Rountine</i><br>Artiste Inconnu·e</p></div> <div class="grid-item-jeux"><a href="jeux/La Grenouille et la flaque d'eau.html" target="_blank"><img src="img/11.png" style="width: 100%; height:auto"></a> <p><i>La Grenouille et la flaque d'eau</i><br>Artiste Inconnu·e</p></div> <div class="grid-item-jeux"><a href="jeux/La Boucle de Marc.html" target="_blank"><img src="img/12.png" style="width: 100%; height:auto"></a> <p><i>La Boucle de Marc</i><br>Anaël Le Gall</p></div> <div class="grid-item-jeux"><a href="jeux/Good Night.html" target="_blank"><img src="img/13.png" style="width: 100%; height:auto"></a> <p><i>Good Night</i><br>Yun-Hsaun Ku</p></div> <div class="grid-item-jeux"><a href="jeux/Galerababos.htm" target="_blank"><img src="img/14.png" style="width: 100%; height:auto"></a> <p><i>Galerababos</i><br>Jérémy Breton</p></div> <div class="grid-item-jeux"><a href="jeux/Find The Exit.html" target="_blank"><img src="img/15.png" style="width: 100%; height:auto"></a> <p><i>Find the Exit</i><br>Élisa Yuste</p></div> <div class="grid-item-jeux"><a href="jeux/Digital Desilusion.html" target="_blank"><img src="img/16.png" style="width: 100%; height:auto"></a> <p><i>Digital Desilusion</i><br>Margaux Deroite / Louis Cauwelier</p></div> <div class="grid-item-jeux"><a href="jeux/empty.html" target="_blank"><img src="img/17.png" style="width: 100%; height:auto"></a> <p><i>...</i><br>Antony Calliau</p></div> <div class="grid-item-jeux"><a href="jeux/Arpente ta rue.html" target="_blank"><img src="img/18.png" style="width: 100%; height:auto"></a> <p><i>Arpente ta rue</i><br>Sterenn</p></div> <div class="grid-item-jeux"><a href="jeux/À La Ferme de Bibi.html" target="_blank"><img src="img/19.png" style="width: 100%; height:auto"></a> <p><i>À la ferme de Bibi</i><br>Artiste Inconnu·e</p></div> <div class="grid-item-jeux"><a href="jeux/Be kind, Delete.html" target="_blank"><img src="img/20.png" style="width: 100%; height:auto;"></a> <p><i>Be Kind, Delete</i><br>Clément Dengremont</p></div> </div> </section> <!-- Act For Energy --> <section id="act-for-energy"> <div id="texte-workshop"> <br> <h1>Workshop 3 🌩</h1> <h3><b>Act For Energy - Expérimenter pour lutter contre la précarité énergétique</b> par <a href="https://www.atelier21.org/act4energy/" target="_blank" style="color:black; text-decoration:underline"><i>Cédric Carles</i></a></h3> <p>Cet atelier invitait à réfléchir et à expérimenter pour trouver des solutions à un problème d’une grande actualité : la précarité énergétique des étudiant·e·s. Durant les trois jours du workshop, les étudiant·e·s en art comme en design ont travaillé à partir de leur propres expériences vécues pour trouver des réponses simples et efficaces pour isoler et garder la chaleur en s’appuyant notamment sur le <i>low tech, le DIY</i> et les alternatives énergétiques au système dominant (pétrole et nucléaire). Ce workshop s’inscrit dans le projet <i>open source</i> itinérant Act4Energy.</p> <br> </div> <div class="grid-act-for-energy"> <div class="col-act-for-energy"> <img src="img/a1.jpg"> </div> <div class="col-act-for-energy"> <img src="img/a2.jpg"> </div> <div class="col-act-for-energy"> <img src="img/a3.jpg"> </div> <div class="col-act-for-energy"> <img src="img/a4.jpg"> </div> </div> </section> <!-- Crédits --> <section id="crédits"> <div id="texte-workshop" style="margin-bottom:25px"> <br> <h1>Exposition à l'Ésac</h1> <p> Les productions réalisées dans le cadre du worskhop “Énergie” ont pris la forme d’une exposition à l’Ésac du 7 décembre 2022 au 21 janvier 2023. Il s'agissait d'une restitution à chaud, l'occasion de faire profiter à toute l’école des projets des étudiant·e·s de 4<sup>e</sup> & 5<sup>e</sup> années. Cette exposition est augmentée d’un site web qui permet l’archivage des productions.</p> <br> </div> <div id="texte-crédits"> <h1>Crédits / Remerciements </h1> <h4>Mise en place de l'exposition / Conception Graphique / Développement Web</h4> <p> <u><a href="http://baptistecoppee.fr/" target="_blank">Baptiste Coppée</a></u> & <u><a href="http://anael.bzh/" target="_blank">Anaël Le Gall</a></u> <br><i>au sein du service civique de médiation de l'Ésac</i></p> <h4>Intervenant·e·s Workshop</h4> <p>Guilhem Roubichou<br>Chloé Desmoineaux<br>Cédric Carles</p> <h4>Textes</h4> <p>Caroline Tron-Carroz<br>Mickaël Tkindt-Naumann</p> </div> </section> <!-- Menu Ordi --> <div id="footer"> <div class="grid-container"> <div class="grid-item" onclick="openContent('accueil')"><a href="#accueil">Accueil</a></div> <div class="grid-item" onclick="closeContent('accueil')"><a href="#potentiel-des-riens">Les potentiels des riens</a></div> <div class="grid-item" onclick="closeContent('accueil')"><a href="#glanneur-de-cellules">Glaneur de cellules</a></div> <div class="grid-item" onclick="closeContent('accueil')"><a href="#act-for-energy">Act For Energy</a></div> <div class="grid-item" onclick="closeContent('accueil')"><a href="#crédits">Exposition à l'Ésac</a></div> </div> </div> <!-- Menu Mobile --> <section id="Menu"> <a href="#accueil"> <h2>Présentation <br>du projet</h2> </a> <a href="#potentiel-des-riens"> <h2>Les potentiels <br> des riens</h2> </a> <a href="#glanneur-de-cellules"> <h2>Glanneur <br> de cellules</h2> </a> <a href="#act-for-energy"> <h2>Act For <br> Energy</h2> </a> <a href="#crédits"><h2>Exposition <br>à l'Ésac</h2> </a> </section> <!-- Footer Mobile --> <a href="#Menu"><div id="menu-icon">+</div></a> </body>body { margin: 0; background-color: #EDEDED; font-family: sans-serif; } /* -------------- Style de texte -------------- */ p { color: #1D1D1B; font-family: sans-serif; } a { text-decoration:none; } a:hover { color: black; text-decoration: underline; } a:visited { color: black; text-decoration-line: none; } h2 { display:none; } h3 { font-family: sans-serif; font-size: 1.5rem; font-weight: 500; } h4 { font-family: sans-serif; font-size: 1.5rem; font-weight: 500; margin-bottom: 5px; } /* -------------- Sections -------------- */ #texte-workshop { margin: 0 3% 0 3%; border-bottom: 1px solid black; } #accueil { width: 80%; position:relative; top:calc(100px + 2vw); left:5%; right:5%; } #act-for-energy { } #glanneur-de-cellules { width: 100%; height:calc(100% - 80px); position:relative; margin-bottom: 150px; } #potentiels-des-riens { } .grid-potentiels-des-riens { display: flex; flex-wrap: wrap; margin-left: 3%; margin-right: 3%; margin-top:35px; margin-bottom: 50px; font-style: italic; } .col-potentiels-des-riens { flex-basis: 50%; box-sizing: border-box; padding: 0 1% 0 1%; margin-bottom:20px; text-align: center; font-size:0.8em; } .grid-act-for-energy { display: flex; flex-wrap: wrap; margin-left: 3%; margin-right: 3%; margin-top:35px; margin-bottom: 50px; font-style: italic; } .col-act-for-energy { flex-basis: 50%; box-sizing: border-box; padding: 0 1% 0 1%; margin-bottom:20px; text-align: center; font-size:0.8em; } #crédits { position: relative; width: 100%; height:100%; } #texte-crédits { position:relative; margin: 0 3% 0 3%; } /* -------------- Menu -------------- */ #menu-text { display:none; } #menu-page { visibility: hidden; display: none; font-family: sans-serif; } #menu-icon { display:none; } #menu { display:none; } #footer { width:100%; bottom:0px; position:fixed; color:#EDEDED; background-color:#1D1D1B; } object { max-width: 800px; width: 70vw; position:relative; left: 0px; } img { width: 100%; height: auto; transition: 0.5s ease; filter: grayscale(100%); } img:hover { width: 100%; height: auto; filter:grayscale(0%); mix-blend-mode: normal; } .grid-item a { color:white; font-size:0.8em; } .grid-item a:visited { color:white; } .grid-item-jeux { background-color:#EDEDED; transition: 0.5s ease; filter: grayscale(100%); } .grid-item-jeux { filter:grayscale(0%); mix-blend-mode: normal; } .grid-jeux { display: grid; grid-template-columns: repeat(4, 1fr); grid-column-gap: 5%; grid-row-gap: 2%; margin: 3% 3% 0 3%; justify-content: center; } .grid-container { display: grid; grid-template-columns:1fr 1fr 1fr 1fr 1fr; grid-template-rows: 50px; } .grid-item { font-size: calc(0.75em + 1vw); font-family: sans-serif; margin-top: calc(15px - 0.5vw); text-align: center; } #burger { display: none; } section { display: none; /* masquer toutes les sections par défaut */ } section:target { display: block; /* afficher la section ciblée */ } @media (max-width: 768px) { body { font-family: sans-serif; } a { text-decoration:none; } a:hover { color: inherit; text-decoration: none; } a:visited { color: inherit; text-decoration-line: none; } #menu-icon { display: block; position:fixed; bottom:25px; right:25px; border-radius:80%;; width:80px; height:80px; background-color:#FFFF00; font-size:4em; font-weight:lighter; text-align:center; } #menu-page { display:block; visibility: hidden; position:fixed; top:0px; left:0px; visibility: hidden; width: 100%; height:calc(100% - 80px); background-color: rgb(0, 0, 0); } #burger { display: block; } h2 { display:block; margin-top: 30px; font-size: 1.5rem; font-weight: 300; background-color: rgb(255, 255, 255); padding: 20px; margin-left: auto; margin-right: auto; width: 60%; text-align: center; border-radius: 60%; outline-style: solid; } h2:hover { background-color: yellow; } #Menu { position: relative; width: 100%; height:calc(100% - 80px); background-color:#EDEDED; text-align: center; text-decoration: none; } #accueil { top:calc(80px + 2vw); } #exposition { top: 75px; width: 80% } #workshops { left: 10%; right: 10%; } .grid-jeux { grid-row-gap: 0.75%; margin-bottom: 200px; } .grid-jeux { grid-template-columns: repeat(2, 1fr); } .MT{ font-size: 5rem; } #footer { display: none; } }const colors = ["yellow", "blue", "red"]; const randomColor = colors[Math.floor(Math.random() * colors.length)]; document.documentElement.style.setProperty('--random-color', randomColor);// Fonction pour générer un nombre aléatoire entre min et max function randomBetween(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } // Récupération de l'élément body var body = document.querySelector("body"); // Définition de la taille de la zone d'affichage var zoneWidth = 171; // en mm var zoneHeight = 157; // en mm // Conversion de la taille en pixels var pixelPerMm = 3.779528; // 1 mm = 3.779528 pixels var zoneWidthPx = zoneWidth * pixelPerMm; var zoneHeightPx = zoneHeight * pixelPerMm; // Boucle pour placer les formes SVG de manière aléatoire var svgCount = randomBetween(10, 15); for (var i = 0; i < svgCount; i++) { // Création de l'élément SVG var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", "30"); svg.setAttribute("height", "30"); // Chargement de l'image SVG var svgImage = document.createElementNS("http://www.w3.org/2000/svg", "image"); svgImage.setAttribute("xlink:href", "img/croix.svg"); svgImage.setAttribute("width", "30"); svgImage.setAttribute("height", "30"); svgImage.style.fill = "#ff00bf"; // Changement de la couleur svg.appendChild(svgImage); // Placement aléatoire de l'élément SVG var x = randomBetween(0, zoneWidthPx - 100); var y = randomBetween(0, zoneHeightPx - 100); svg.style.left = x + "px"; svg.style.top = y + "px"; // Ajout de l'élément SVG à la page body.appendChild(svg); }function afficherDateEtHeure() { const date = new Date(); const heure = date.getHours(); const minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); const secondes = (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); const jour = date.getDate(); const mois = date.getMonth() + 1; const annee = date.getFullYear(); document.getElementById('heure').textContent = heure + ':' + minutes + ':' + secondes; document.getElementById('date').textContent = jour + '/' + mois + '/' + annee; } afficherDateEtHeure();// Imposition for booklet(s) // // This script re-arrange the pages of your document in order to make an imposed sheet layouts for printing. // Two pages per sheet, double-sided class Booklet extends Paged .Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.pagedbooklet; this.sourceSize; this.pageStart; this.pageEnd; } onAtPage(node, item, list) {} onDeclaration(declaration, dItem, dList, rule) { if (declaration.property == "--paged-layout") { if (declaration.value.value.includes("booklet")) { this.pagedbooklet = true; let valuesBooklet = declaration.value.value.split(' '); let index = valuesBooklet.indexOf("booklet"); /* Set first page of the imposition */ if(valuesBooklet[index + 1]){ this.pageStart = parseInt(valuesBooklet[index + 1]); }else{ this.pageStart = 1; } /* Set ladt page of the imposition */ if(valuesBooklet[index + 2]){ this.pageEnd = parseInt(valuesBooklet[index + 2]); } } } } afterRendered(pages) { /* Verify this.pageEnd */ if(!this.pageEnd){ let allPagesBefore = document.querySelectorAll(".pagedjs_page").length; this.pageEnd = allPagesBefore; } /* Verify this.pageStart */ if(this.pageStart == 0){ this.pageStart = 1; }else if(this.pageStart % 2 == 0){ this.pageStart = this.pageStart - 1; } /* Launch when printing */ window.addEventListener("beforeprint", (evenement) => { let containerPages = document.querySelector(".pagedjs_pages"); /* Delete pages we don't want*/ pages.forEach(page => { let id = parseInt(page.id.replace('page-', '')); if(id < this.pageStart || id > this.pageEnd){ let pageSelect = document.querySelector('#'+ page.id); pageSelect.remove(); } }); /* Reset page counter */ let reset = parseInt(this.pageStart) - 1; containerPages.style.counterReset = "page " + reset; let format = document.querySelector(".pagedjs_page"); /* Width of page without bleed, extract the first number of calc() function */ let width = getCSSCustomProp("--pagedjs-width", format); let numbers = width .match(/[0-9]+/g) .map(function (n) { return + (n); }); width = parseInt(numbers[0]); /* Height of page with bleed, addition of all the numbers of calc() function*/ let height = getCSSCustomProp("--pagedjs-height", format); numbers = height .match(/[0-9]+/g) .map(function (n) { return + (n); }); const reducer = (previousValue, currentValue) => previousValue + currentValue; height = numbers.reduce(reducer); /* Bleed of the page */ let bleed = getCSSCustomProp("--pagedjs-bleed-top", format); let bleedNum = parseInt(bleed); /* Spread and half-spread*/ let spread = width * 2 + bleedNum * 2; let spreadHalf = width + bleedNum; // Add CSS to have pages in spread // // - change size of the page when printing (actually, sheet size) // - flex properties // - delete bleeds inside spread */ var newSize = `@media print{ @page{ size: ${spread}mm ${height}mm; } .pagedjs_pages { width: auto; } } @media screen{ .pagedjs_pages{ max-width: calc(var(--pagedjs-width) * 2); } } .pagedjs_pages { display: flex !important; flex-wrap: wrap; transform: none !important; height: 100% !important; min-height: 100%; max-height: 100%; overflow: visible; } .pagedjs_page { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; } .pagedjs_sheet { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; } body{ --pagedjs-bleed-right-left: 0mm; } .pagedjs_left_page{ z-index: 20; width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width))!important; } .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop { border-color: transparent; } .pagedjs_right_page, .pagedjs_right_page .pagedjs_sheet{ width: calc(var(--pagedjs-bleed-right-right) + var(--pagedjs-pagebox-width))!important; } .pagedjs_right_page .pagedjs_sheet{ grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] 1fr [bleed-right] var(--pagedjs-bleed-right-right); } .pagedjs_right_page .pagedjs_bleed-left{ display: none; } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1){ width: 0!important; } .pagedjs_first_page { margin-left: 0; } body{ margin: 0 } .pagedjs_page:nth-of-type(even){ break-after: always; } .pagedjs_page, .pagedjs_sheet{ width: ${spreadHalf - 0.1}mm!important; } `; // Add style for the arrangement of the pages if (this.pagedbooklet == true) { let style = document.createElement("style"); style.textContent = newSize; document .head .appendChild(style); var number_of_pages = document.getElementsByClassName("pagedjs_page").length; var pages_array = []; // If the page count isn't a multiple of 4, we need to pad the array with blank // pages so we have the correct number of pages for a booklet. // // ex. [1, 2, 3, 4, 5, 6, 7, 8, 9, blank, blank, blank] let modulo = number_of_pages % 4; let additional_pages = 0; if (modulo != 0) { additional_pages = 4 - modulo; } for (i = 0; i < additional_pages; i++) { let added_page = document.createElement("div"); added_page .classList .add("pagedjs_page", "added"); added_page.id = `page-${this.pageEnd + i + 1}`; document .querySelector(".pagedjs_pages") .appendChild(added_page); } // Push each page in the array for (var i = number_of_pages + additional_pages; i >= 1; i--) { pages_array.push(i); } // Split the array in half // // ex. [1, 2, 3, 4, 5, 6], [7, 8, 9, blank, blank, blank] var split_start = pages_array.length / 2; var split_end = pages_array.length; var first_array = pages_array.slice(0, split_start); var second_array = pages_array.slice(split_start, split_end); // Reverse the second half of the array. This is the beginning of the back half // of the booklet (from the center fold, back to the outside last page) // // ex. [blank, blank, blank, 9, 8, 7] var second_array_reversed = second_array.reverse(); // Zip the two arrays together in groups of 2 These will end up being each '2-up // side' of the final document So, the sub-array at index zero will be the first // side of physical page one and index 1 will be the back side. However, they // won't yet be in the proper order. // // ex. [[1, blank], [2, blank], [3, blank], [4, 9], [5, 8], [6, 7]] var page_groups = []; for (var i = 0; i < first_array.length; i++) { page_groups[i] = [ first_array[i], second_array_reversed[i] ]; } // We need to reverse every other sub-array starting with the first side. This // is the final step of aligning our booklet pages in the order with which the // booklet gets printed and bound. // // ex. [[blank, 1], [2, blank], [blank, 3], [4, 9], [8, 5], [6, 7]] final_groups // = page_groups.each_with_index { |group, index| group.reverse! if (index % // 2).zero? } var final_groups = []; for (var i = 0; i < page_groups.length; i++) { var group = page_groups[i]; if (i % 2 != 0) { final_groups[i] = page_groups[i].reverse(); } else { final_groups[i] = page_groups[i]; } } console.log("Final Imposition Order: " + final_groups); var allPages = document.querySelectorAll(".pagedjs_page"); var final_flat = final_groups.flat(); final_flat.forEach((folio, i) => { folio = folio + reset; document .querySelector(`#page-${folio}`) .style .order = i; }); } }); // before print } } Paged .registerHandlers(Booklet); /** * Pass in an element and its CSS Custom Property that you want the value of. * Optionally, you can determine what datatype you get back. * * @param {String} propKey * @param {HTMLELement} element=document.documentElement * @param {String} castAs='string' * @returns {*} */ const getCSSCustomProp = ( propKey, element = document.documentElement, castAs = "string" ) => { let response = getComputedStyle(element).getPropertyValue(propKey); // Tidy up the string if there's something to work with if (response.length) { response = response .replace(/\'|"/g, "") .trim(); } // Convert the response into a whatever type we wanted switch (castAs) { case "number": case "int": return parseInt(response, 10); case "float": return parseFloat(response, 10); case "boolean": case "bool": return response === "true" || response === "1"; } // Return the string response by default return response; };<!--------------------------------------------------------- -----------------------------------------------------------> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>IW4X Print</title> <script src="paged.polyfill.js"></script> <script src="imposition.js"></script> <script src="randomize.js"></script> <script href="pagedjs/paged.esm.js"></script> <link href="print.css" rel="stylesheet" type="text/css"> <script src="couleurs.js"></script> </head> <body> <!---------------- COUVERTURE -----------------> <section class="page" id="cover" style="margin-left:5mm;"> <div class="text-container"></div> <div class="title-grid" style="margin-right:0mm; padding-top:5mm">Expérimentations sur la relation entre code créatif et Web2Print</div> <div class="title-grid" style="margin-right:10mm; padding-top:5mm">HTML / CSS / Javascript</div> <div class="title-grid" style="margin-right:20mm; padding-top:5mm">Détourner le jeux-vidéo pour en faire une édition</div> <h1>IW4X</h1> <div class="grid-map"> <div class="map-title" style="margin-left:10px"><h5>1</h5><p>mp_rust</p></div> <div class="map-title" style="margin-left:10px"><h5>2</h5><p>mp_rundown</p></div> <div class="map-title" style="margin-left:10px"><h5>3</h5><p>mp_quarry</p></div> </div> <div class="grid-map" style="margin-top:12mm;"> <div class="map-title" style="margin-left:10px"><h5>4</h5><p>mp_nightshift</p></div> <div class="map-title" style="margin-left:10px"><h5>5</h5><p>mp_invasion</p></div> <div class="map-title" style="margin-left:10px"><h5>6</h5><p>mp_highrise</p></div> </div> <div class="grid-map" style="margin-top:24mm;"> <div class="map-title" style="margin-left:10px"><h5>7</h5><p>mp_favela</p></div> <div class="map-title" style="margin-left:10px"><h5>8</h5><p>mp_estate</p></div> <div class="map-title" style="margin-left:10px"><h5>9</h5><p>mp_derail</p></div> <div class="map-title" style="margin-left:10px"><h5>10</h5><p>mp_checkpoint</p></div> </div> </div> <div class="grid-cover" style="bottom:0; top:unset;"> <div id="test"><img src="img/cover/4.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">1</h5></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div id="test"><img src="img/cover/5.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">2</h5></div> <div id="test"><img src="img/cover/6.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">3</h5></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div id="test"><img src="img/cover/7.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">4</h5></div> <div id="test"><img src="img/cover/8.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">5</h5></div> <div id="test"><img src="img/cover/9.jpg" class="cover-image" alt=""><h5 style="padding-top:2px">6</h5></div> <div class="cover-image" style="background-color: white;"></div> <div id="test"><img src="img/cover/10.jpg" class="cover-image" alt=""> <h5 style="padding-top:2px">7</h5></div> <div id="test"><img src="img/cover/11.jpg" class="cover-image" alt=""> <h5 style="padding-top:2px">8</h5></div> <div id="test"><img src="img/cover/12.jpg" class="cover-image" alt=""> <h5 style="padding-top:2px">9</h5></div> <div id="test"><img src="img/cover/13.jpg" class="cover-image" alt=""> <h5 style="padding-top:2px">10</h5></div> </div> </section> <!---------------- PAGE 1 (blank) -----------------> <section class="page" id="2"> <p style="color:white">PAGE TRANSPARENTE</p> </section> <!---------------- <div class="grille"> <p>iw4x est une modification pour le jeu de tir à la première personne populaire, Call of Duty: Modern Warfare 2 (MW2), qui transforme le jeu en un outil libre et ouvert. Cette transformation permet de sortir des sentiers battus du FPS traditionnel et de repenser le gameplay en fonction des préférences des joueurs. Avec IW4x, les joueurs peuvent bénéficier de fonctionnalités supplémentaires telles que des cartes personnalisées, des serveurs dédiés et une prise en charge des joueurs supplémentaires, qui ne sont pas disponibles dans la version originale du jeu. Cela permet de proposer une expérience de jeu plus personnalisée et enrichie que ce que permet la version originale du jeu. En transformant un jeu commercial propriétaire en un outil libre, IW4x permet aux joueurs de dépasser les limites imposées par les choix des développeurs et de penser différemment le gameplay. Cela permet également à la communauté de développeurs de travailler ensemble pour améliorer le jeu et d'encourager l'innovation dans l'industrie des jeux vidéo. De plus, la communauté de joueurs IW4x est très active et fournit un soutien technique, des mises à jour régulières et des correctifs pour s'assurer que le jeu reste amusant et accessible pour tous. Cette communauté peut également proposer des idées innovantes pour étendre les fonctionnalités du jeu et proposer des expériences de jeu uniques.</p> </div> -----------------> <!---------------- PAGE 2 (gradient) -----------------> <section class="page" id="3"> <script src="croix.js"></script> <div class="grid-cover" style="bottom:0; top:unset; border-top:none; z-index:10;"> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div class="cover-image" style="background-color: white;"></div> <div class="cover-image" style="background-color: white;"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div id="test"><p style="font-family:Almendra; font-size:2em; margin:3mm 0 0 0; color:black">IW4X </p><p style="font-family:AlmendraB; font-size:1em; margin:3mm 0 0 0;color:black"> Édition Générative<br>Anaël Le Gall</p></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div class="cover-image" style="background-color: white;"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> <div id="test" style="background: var(--random-color);background: linear-gradient(90deg, var(--random-color) 30%, rgba(255, 255, 255, 0) 100%);"></div> </div> </section> <!---------------- Page 3 (blank) -----------------> <section class="page" id="4"> <pre> DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE This program is free software. It comes without any warranty, to the extent permitted by applicable law. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License. http://www.wtfpl.net/ for more details. </pre> </section> <!---------------- PAGE 3 (sommaire) -----------------> <section class="page" id="sommaire"> <h2 style="position:absolute; top:8mm;-webkit-text-stroke: 2px var(--random-color); color:black;font-size:92pt;width:200mm; text-align:center">Sommaire</h2> <div class="map-title2" style="margin: 40mm 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_arctic.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px;margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">1</h6><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Introduction</p><h4>6</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_blue_tiger.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px;margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">2</h6><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Web2Print</p><h4>7</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_desert.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px; margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">3</h6><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Besher.exe</p><h4>8-9</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_digital.png); width:100%; height:30px; filter:grayscale(100%);"><h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px;margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">4</h6><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Visuels</p><h4>10-23</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_orange_fal.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px;margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">5</h6><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Fingerprint</p><h4>24</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_red_tiger.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> <div class="map-title2" style="height:50px;margin: 0 50px 25px 20px;"><h6 style="background-color:lightgrey; z-index:-10; color:black; padding-top:13px">6</h6 style="height:50px"><p style="font-size:18pt; font-family:Texte2; padding-top:12px">Colophon</p><h4>12-13</h4></div> <div class="map-title2" style="margin: 0 20px 25px 50px; background-image: url(img/camos/Weapon_camo_menu_red_urban.png); width:100%; height:30px; filter:grayscale(100%);"> <h4 style="width:8mm; background-color: rgba(255, 255, 255, 0)"></h4></div> </section> <!---------------- PAGE 4 (introduction) -----------------> <section class="page" id="6"> <h2 style="margin: 5mm 0 0 5mm">Introduction</h2> <p style="margin: 5mm 0 0 5mm">IW4X est une version modifiée du jeu Call of Duty: Modern Warfare 2, intégrant des outils de modding, la possibilité de créer des serveurs dédiés, ainsi qu'une quantité importante de contenu. Ce projet est mené par le groupe de développeurs indépendants Xlabs, qui ont redistribué une version open-source de plusieurs jeux de la licence. Grâce à cette initiative, ils ont permis à la communauté de profiter d'une expérience de jeu augmentée avec la possibilité de développer des mods alternatifs, offrant ainsi à chacun la possibilité de personnaliser son expérience de jeu. Dans cette édition, j'ai voulu démontrer les possibilités offertes par l'ouverture d'un logiciel à la modification, et explorer les mondes du jeu avec un nouveau regard, impossible dans une version officielle. Tout le contenu de l'édition (à l'exception des typographies) est issu de fichiers récupérés dans le jeu, qu'il s'agisse de sprites, de textures ou de modèles. C'est en partie grâce à ce jeu que mon intérêt pour l'image est né, en découvrant les communautés qui gravitent autour de ce jeu et les contenus associés. Il m'a donc paru intéressant, pour boucler la boucle, d'utiliser toutes ces ressources pour nourrir une édition pour mon diplôme de fin d'études.</p> </section> <!---------------- PAGE 5 (web2print) -----------------> <section class="page" id="7"> <h2 style="position:absolute; top:5mm;left:unset; right:5mm; margin-bottom:10mm">Web2Print</h2> <p style="width:170mm;margin-top:15mm; position:absolute; padding-left:25m; right:5mm">Cette édition est l'occasion d'expérimenter les possibilités offertes par le modèle de mise en page par le code de développement web2print. Au lieu d'utiliser un logiciel dédié, l'intégralité de la mise en page est développée en langage HTML/CSS, généralement utilisé pour la création et la mise en forme de contenu web. Il est également possible d'implémenter du langage Javascript, un langage de programmation qui permet d'ajouter de l'interactivité. Ainsi, cette édition se veut générative : chaque nouvelle itération du programme donne une nouvelle version de l'édition (organisation de la couverture, grille d'images au dos, intégration des données de l'utilisateur), ce qui la rend beaucoup plus dynamique qu'une édition standard qui n'est qu'un objet figé créé par ses concepteurs. Ce projet est rendu possible grâce au travail collaboratif de nombreuses personnes. Cette édition repose sur un script de Quentin Juhel et Julien Taquet qui permet l'imposition en livret de contenu Web2Print. La plupart de mes connaissances en développement proviennent de l'utilisation de Paged.js, une bibliothèque Javascript qui facilite l'utilisation du code web pour la mise en page imprimée. Cette bibliothèque est le fruit du travail d'Adam Hyde, Julie Blanc, Fred Chasen et Julien Taquet.</p> </section> <!---------------- PAGE 6 (DUO) -----------------> <section class="page-2" id="8"> <div class="mw2-grid" style="right:unset; left:0mm;"> <img src="img/grid2/1.jpg"> <img src="img/grid2/2.jpg"> <img src="img/grid2/3.jpg"> <img src="img/grid2/4.jpg"> <img src="img/grid2/5.jpg"> <img src="img/grid2/6.jpg"> <img src="img/grid2/7.jpg"> <img src="img/grid2/8.jpg"> <img src="img/grid2/9.jpg"> </div> <p class="bottom" style="bottom:25mm; width:187mm; left:2mm">Si les Beschers avaient exploré les espaces numériques... </p> </section> <!---------------- PAGE 7 (DUO) -----------------> <section class="page-2" id="9"> <div class="mw2-grid"> <img src="img/grid2/10.jpg"> <img src="img/grid2/11.jpg"> <img src="img/grid2/12.jpg"> <img src="img/grid2/13.jpg"> <img src="img/grid2/14.jpg"> <img src="img/grid2/15.jpg"> <img src="img/grid2/16.jpg"> <img src="img/grid2/17.jpg"> <img src="img/grid2/18.jpg"> </div> <p class="bottom2" style="bottom:5mm; width:187mm; right:2mm">...ils en auraient photographié des pixels.</p> </section> <!---------------- PAGE 8 (fullpage) -----------------> <section class="page-2" id="10"> <img src="img/FULLPAGE/1.jpg" class="fullpage2"> <p class="bottom">mp_checkpoint | x=121 y=72.6 z=10.1</p> </section> <!---------------- PAGE 9 (fullpage) -----------------> <section class="page-2" id="11"> <img src="img/FULLPAGE/2.jpg" class="fullpage"> <p class="bottom2">mp_checkpoint | x=212.6 y=-40 z=-7</p> </section> <!---------------- PAGE 10 (fullpage) -----------------> <section class="page-2" id="12"> <img src="img/FULLPAGE/3.jpg" class="fullpage2"> <p class="bottom">mp_estate | x=45.1 y=-12.6 z=16.4</p> </section> <!---------------- PAGE 11 (fullpage) -----------------> <section class="page-2" id="13"> <img src="img/FULLPAGE/6.jpg" class="fullpage"> <p class="bottom2">mp_storm | x=86.6 y=14.2 z=18.1</p> </section> <!---------------- PAGE 12 (fullpage) -----------------> <section class="page-2" id="14"> <img src="img/FULLPAGE/4.jpg" class="fullpage2"> <p class="bottom">mp_storm | x=76.8 y=2.7 z=78.0</p> </section> <!---------------- PAGE 13 (fullpage) -----------------> <section class="page-2" id="15"> <img src="img/FULLPAGE/5.jpg" class="fullpage"> <p class="bottom2">mp_rust | x=12?3 y=-7.2 z=144.5</p> </section> <!---------------- PAGE 14 (fullpage) -----------------> <section class="page-2" id="16"> <img src="img/FULLPAGE/7.jpg" class="fullpage2"> <p class="bottom">mp_estate | x=12.6 y=0.7 z=-51</p> </section> <!---------------- PAGE 15 (fullpage) -----------------> <section class="page-2" id="17"> <img src="img/FULLPAGE/8.jpg" class="fullpage"> <p class="bottom2">mp_checkpoint | x=234.1 y=-7.0 z=44.3</p> </section> <!---------------- PAGE 16 (fullpage) -----------------> <section class="page-2" id="18"> <img src="img/FULLPAGE/9.jpg" class="fullpage2"> <p class="bottom">mp_afghan | x=-213.4 y=-14.6 z=80.4</p> </section> <!---------------- PAGE 17 (fullpage) -----------------> <section class="page-2" id="19"> <img src="img/FULLPAGE/10.jpg" class="fullpage"> <p class="bottom2">mp_favela | x=12.3 y=-5.7 z=307.8</p> </section> <!---------------- PAGE 18 (fullpage) -----------------> <section class="page-2" id="20"> <img src="img/FULLPAGE/11.jpg" class="fullpage2"> <p class="bottom">mp_backlot | x=218 y=-32.3 z=12.6</p> </section> <!---------------- PAGE 19 (fullpage) -----------------> <section class="page-2" id="21"> <img src="img/FULLPAGE/12.jpg" class="fullpage"> <p class="bottom2">mp_salvage | x=155.6 y=12.4 z=-31.1</p> </section> <section class="page-2" id="22"> <img src="img/full2.jpg" class="fullpage2"> <p class="bottom">mp_afghan | x=12.5 y=230.6 z=-12.3 (modified)</p> </section> <section class="page-2" id="23"> <img src="img/full.jpg" class="fullpage"> <p class="bottom2">mp_checkpoint | x=32 y=241.4 z=8.8 (modified)</p> </section> <!---------------- PAGE 21 (fingerprint) -----------------> <section class="page" id="fingerprintpage"> <h2>Votre empreinte numérique</h2> <p style="margin-top:0;">Cette page permet d'illustrer la notion d'empreinte numérique dans l'utilisation d'un navigateur web. Grâce à la possibilité de lire les éditions en Web2Prints directement dans le navigateur, il est possible d'implémenter des fonctionnalités dans le code qui permettent de récupérer des informations sur la machine de l'utilisateur. Cette empreinte, appelée également "fingerprint", est un ensemble de données qui identifient de manière unique un navigateur web spécifique. Le programme peut identifier des éléments tels que la résolution de l'écran, les plugins utilisés, les polices de caractères installées ou encore la version du système d'exploitation. En combinant ces informations, il est possible de créer une empreinte digitale unique pour chaque navigateur web, qui peut être utilisée pour suivre l'utilisateur en ligne et le reconnaître à travers différentes sessions de navigation.</p> <p style="margin-bottom:25px; border-bottom: 1px solid black; padding-bottom: 10px;">Voici quelques exemples de données scannées par le programme, sans aucun contrôle de votre part.</p> <h2>User agent: </h2><p id="userAgent" class="datauser"></p> <h2>Langue: </h2><p id="language" class="datauser"></p> <h2>Plateforme: </h2><p id="platform" class="datauser"></p> <h2>Version de l'application: </h2><p id="appVersion" class="datauser"></p> <h2>Paramètre des cookies: </h2><p id="cookieEnabled" class="datauser"></p> <h2>Date et heure de création</h2> <p class="datauser">Générée le : <span id="date" ></span> - <span id="heure" class="datauser" style="border:none;"></span></p> <script> const userAgent = window.navigator.userAgent; const language = window.navigator.language; const platform = window.navigator.platform; const appVersion = window.navigator.appVersion; const cookieEnabled = window.navigator.cookieEnabled; document.getElementById("userAgent").innerHTML = userAgent; document.getElementById("language").innerHTML = language; document.getElementById("platform").innerHTML = platform; document.getElementById("appVersion").innerHTML = appVersion; document.getElementById("cookieEnabled").innerHTML = cookieEnabled; </script> <img src="/IW4X Edition/img/test.svg" style="position:absolute; bottom:0; right:0; z-index:-10;height:40px; width:auto;"> </section> <!---------------- PAGE 24 (blank) -----------------> <section class="page" id="25"> <pre style="text-align:right; left:unset; right:5mm; bottom:5mm"> Réalisé par Anaël Le Gall en Web2Print. Script pour l'imposition par Quentin Juhel. Typographies Textes courants en Linux Libertine Titres en Titra IW4X par Xlabs (https://xlabs.dev/) Pour télécharger le jeu, se référer au tutoriel suivant (https://xlabs.dev/support_iw4x_client) </pre> </section> <!---------------- PAGE 23 (gradient) -----------------> <section class="page" id="26"> <div class="grid2"> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> <div class="cell2"></div> </div> </section> <section class="page" id="27"> <p style="color:white">PAGE TRANSPARENTE</p> </section> <!---------------- PAGE 24 -----------------> <section class="page-2" id="28"> <div class="grid"></div> <script src="random.js"></script> <script src="heure.js"></script> </section> </body> </html>/* Importation des polices d'écriture */ @font-face { font-family: 'Arkes'; src: url(fonts/arkessolidregular.ttf); } @font-face { font-family: 'Kupol'; src: url(fonts/KUPOLE-Regular.ttf); } @font-face { font-family: 'Texte2'; src: url(fonts/cmunti.ttf); } @font-face { font-family: 'Texte'; src: url(fonts/cmunrm.ttf); } @font-face { font-family: 'AlmendraB'; src: url(fonts/Titra-Int-Bold.otf); } @font-face { font-family: 'Almendra'; src: url(fonts/Titra-Ext-Light.otf); } @font-face { font-family: 'Tribal'; src: url(fonts/TribaliumNeue-Poster.otf); } :root { --random-color: #000; } body{ --paged-layout : booklet; /* */ font-family: sans-serif; print-color-adjust: exact; /* exact = impression des couleurs de fonds / economy = impression peut consomatrice */ -webkit-print-color-adjust: exact; /* */ } @media print { @page{ size: 200mm 287mm; margin:0mm; bleed: 15mm; marks: crop; } @page:nth(1) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-right{ content: none; background-color:white; border:0px solid white; } } @page:nth(2) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-left{ content: none; background-color:white; border:0px solid white; } } @page:nth(3) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-right{ content: none; background-color:white; border:0px solid white; } } @page:nth(4) { font-family:monospace; margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-right{ content: none; background-color:white; } } @page:nth(5) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; } @page:nth(6) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(7) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-center{ } } @page:nth(8) { margin-bottom:0mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(10) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-center{ } } @page:nth(11) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(12) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-center{ } } @page:nth(13) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(14) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(15) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(16) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(17) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(18) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(19) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(20) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(21) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(22) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ } } @page:nth(23) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ } } @page:nth(26) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ content:none; background-color:white; border:0px solid white; } } @page:nth(27) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-right{ content:none; background-color:white; border:0px solid white; } } @page:nth(28) { margin-bottom:5mm; margin-left:0mm; margin-right:0mm; @bottom-left{ content:none; background-color:white; border:0px solid white; } } /* S'applique aux pages de gauche */ @page{ @bottom-center { font-family:monospace; } } @page:left{ margin-bottom:20mm; margin-right:15mm; @bottom-left{ content: counter(page); position:absolute; font-family:monospace; bottom:5mm; left:5mm; height:25px; width:25px; border-radius:180px; background-color: rgb(220, 220, 220); border:1px solid black; color:black; text-align:center; } } /* S'applique aux pages de droite */ @page:right{ margin-bottom:20mm; margin-left:25mm; @bottom-right{ content: counter(page); position:absolute; font-family:monospace; bottom:5mm; right:5mm; height:25px; width:25px; border-radius:180px; background-color: rgb(220, 220, 220); border:1px solid black; color:black; text-align:center; } } } p { font-family: monospace; font-size:1em; line-height:13pt; text-align:justify; text-justify:inter-word; } h1 { -webkit-text-stroke: 2px; -webkit-text-stroke-color: var(--random-color); font-size:160pt; font-family:'AlmendraB'; top:-5mm; left:5mm; margin:0; z-index:10; } h2 { font-family: 'AlmendraB'; text-transform: uppercase; font-weight: 700; margin:0; font-size:13pt; } h3 { margin:0 0 5mm 0; padding-left:3mm; font-family:monospace; font-size:1em; font-weight: 400; background-color:black; color:white; } h5 { font-size:1.2em; padding-top:1mm; color:white; background-color:black; height:8mm; width:8mm; font-weight: 400; text-align:center; border-radius:180px ; margin:0; } h6 { font-size:1.2em; padding-top:1mm; color:white; background-color:black; height:50px; width:50px; font-weight: 400; text-align:center; border-radius:180px ; margin:0; } .bottom { position:absolute; bottom:5mm; left:5mm; width:175mm; text-align:center; font-family:monospace; padding:5px 0 5px 0; border: 1px solid black; border-radius:180px; } .bottom2 { position:absolute; bottom:5mm; right:5mm; width:175mm; text-align:center; font-family:monospace; padding:5px 0 5px 0; border: 1px solid black; border-radius:180px; } #test { position:relative; height:26.2mm; width:43.7mm; } #test-2{ height:auto; } #test-2 h5 { background-color:white; color:black; border:1px solid black; height:5mm; width:5mm; font-size:0.8em; padding-top:0.2mm; position:absolute; z-index:100; bottom:5mm; right:5mm; } #fingerprintpage { margin:5mm 5mm 0 5mm; } #userAgent { font-family: monospace; } .datauser { margin:5px 0 25px 0; font-size: 1em; font-family: monospace; font-weight:lighter; padding: 10px; border: 1px solid black; background-color: white; border-radius: 5px; color:black; } #test h5 { background-color:white; color:black; border:1px solid black; height:5mm; width:5mm; font-size:0.8em; padding-top:0.2mm; position:absolute; z-index:100; bottom:2mm; right:2mm; } .grid-map { margin-left:5mm; width: 171mm; position:absolute; top: 120mm; display:flex; } .grid-map p { margin:6px 0 0 2mm; font-family:'Texte2'; font-style:italic; } .map-title { border-radius:180px; border:1px solid black; padding-right:3mm; position:relative; display:flex; } .map-title2 { width:195mm; border-radius:180px; border:1px solid black; padding-right:3mm; position:relative; display:flex; } .map { border-radius:180px; border:1px solid black; margin-left:3mm; padding-right:3mm; position:relative; display:flex; } .mw2-grid { position:absolute; top:0; right:0; display:grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); gap:3mm; margin:3mm; } .mw2-grid img { height:80mm; width:auto; } .mw2-infos { top:calc(200mm + 10px); position:absolute; display:grid; grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(3, 1fr); gap: 10px; margin: 10px; height:40mm; width:170mm; } .mw2{ display:flex; border:1px solid black; width:65mm; height:87mm; } .mw2 img { height:100%; width:auto; } .titre { font-size: 1.5rem; margin: 10px; } .text-container { position: relative; } .text { position: absolute; top: 0; left: 0; font-size: 2em; font-weight: bold; color: #fff; } section.page#cover { height:100%; width:100%; margin:0; padding:0; } section.page#gradient { height:100%; width:100%; margin:0; padding:0; } p::first-line { border-top:none; } pre { position:absolute; bottom:15mm; left:5mm; font-family: monospace; font-size: 0.8em; } .page { height:265mm; width:175mm; break-after: page; } .page-2 { margin-right:0mm; height:260mm; width:175mm; break-after: page; } .grid { display: grid; grid-template-columns: repeat(7, 1fr); grid-template-rows: repeat(5, 1fr); gap: 10px; margin: 20px; height:120mm; width:190mm; } .grid2 { display: grid; grid-template-columns: repeat(7, 1fr); grid-template-rows: repeat(5, 1fr); gap: 10px; margin: 20px; height:120mm; width:190mm; } .cell2 { height:25mm; width: 25mm; padding:calc(10px + 2mm); display: flex; flex-direction: column; text-align: left; background: var(--random-color); background: linear-gradient(180deg, var(--random-color) 20%, rgba(255,255,255,0) 100%); } .cell { height:25mm; width: 25mm; padding: 10px; display: flex; flex-direction: column; text-align: left; } .cell img { border: 1px solid black; padding:2mm; filter:grayscale(100); max-width: 100%; max-height: 100%; object-fit: contain; } .cell span { text-align: center; font-size: 0.6em; margin-top: 2mm; font-family:monospace; } .code { background-color: rgb(157, 157, 157); border: 1px solid black; } .code pre { padding:3mm; color: white; } img { width:132.5mm; height:auto; } .fullpage { position:absolute; margin:5mm; top:-1mm; right:0; height:260mm; width:175mm; } .fullpage2 { position:absolute; margin:3mm; top:1mm; left:2mm; height:260mm; width:175mm; } #lower-texte { margin:0 10px 0 10px; } .grid-cover { border-top: 1px solid black; padding-top:5mm; margin: 5mm 5mm 5mm 5mm; width:166mm; position:absolute; top:0mm; left:0; display:grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(3, auto); grid-gap: 5mm; } .grid-cover img{ border: 1px solid black; } .cover-image { height:26.2mm; width:43.7mm; filter:saturate(100); filter:grayscale(100); } .title-grid { position: absolute; display: flex; top: 0mm; right: -1mm; padding-right:3mm; z-index: 25; height: 256mm; writing-mode: vertical-lr; border-left: 1px solid black; padding-left: 2mm; } .title-grid p { position:absolute; right:0; color:green; border:none; } svg { color:#00bfff; position: absolute; } .numbers { position:absolute; bottom:-15mm; right:-8mm; border: 1px solid black; height:20mm; width:74mm; text-align:left; padding:3mm; font-size:0.5em; } .numbers p { margin:0; } .numbers span { margin:0; } .date { position: absolute; top:260mm; right: 0; text-align: left; font-size: 10pt; margin:0; padding:0; } #sommaire p { margin:5px 0 0 3mm; height:12pt; } h4 { position:absolute; right:0; font-size:1.2em; padding-top:3.5mm; color:rgb(255, 255, 255); background-color:rgb(0, 0, 0); height:48.5px; width:30mm; font-weight: 400; text-align:center; border-radius:180px ; margin:0; }const imageDir = "img/grid"; const poolSize = 191; const container = document.querySelector(".grid"); const imageNames = Array.from({length: poolSize}, (v, i) => `cardicon${i+1}.png`); for (let i = 0; i < 63; i++) { const img = new Image(); img.src = `${imageDir}/${imageNames[Math.floor(Math.random() * poolSize)]}`; const cell = document.createElement("div"); cell.classList.add("cell"); cell.appendChild(img); const span = document.createElement("span"); span.innerText = img.src.split("/").pop(); cell.appendChild(span); container.appendChild(cell); }const texts = ["Texte 1", "Texte 2", "Texte 3", "Texte 4", "Texte 5"]; document.addEventListener("DOMContentLoaded", function() { const container = document.getElementById("text-container"); texts.forEach(function(text) { const element = document.createElement("div"); element.classList.add("text"); element.innerText = text; container.appendChild(element); // Définir une position aléatoire pour chaque élément element.style.top = `${getRandomInt(container.offsetHeight - element.offsetHeight)}px`; element.style.left = `${getRandomInt(container.offsetWidth - element.offsetWidth)}px`; }); }); // Fonction pour obtenir un nombre entier aléatoire function getRandomInt(max) { return Math.floor(Math.random() * Math.floor(max)); }function toggleDivs() { var div1 = document.getElementById("menu-mobile"); var div2 = document.getElementById("mapid"); var maDiv = document.getElementById("menuicon"); if (div1.style.display === "none") { div1.style.display = "block"; div2.style.display = "none"; } else { div1.style.display = "none"; div2.style.display = "block"; } } function toggleDivs2() { var div3 = document.getElementById("menu-mobile"); var div4 = document.getElementById("content"); var maDiv2 = document.getElementById("menuicon"); if (div3.style.display === "none") { div3.style.display = "none"; div4.style.display = "block"; } else { div3.style.display = "block"; div4.style.display = "none"; } }<!DOCTYPE html> <html> <head> <title>Libre</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css" /> <script src="leaflet/leaflet-src.js"></script> <script src="leaflet/leaflet-src.js.map"></script> <script src="action.js"></script> <div id="mapid"></div> </head> <body> <script> /* --------------- Test pour ajouter une icone perso --------------- */ var cultureIcon = L.icon({ iconUrl: 'images/marker-culture.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var loisirsIcon = L.icon({ iconUrl: 'images/marker-loisirs.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var ecoleIcon = L.icon({ iconUrl: 'images/marker-ecole.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var etudesIcon = L.icon({ iconUrl: 'images/marker-etudes.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var aideIcon = L.icon({ iconUrl: 'images/marker-aide.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var materiauxIcon = L.icon({ iconUrl: 'images/marker-materiaux.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var papierIcon = L.icon({ iconUrl: 'images/marker-papier.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var printIcon = L.icon({ iconUrl: 'images/marker-print.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); var autreIcon = L.icon({ iconUrl: 'images/autre-marker.svg', iconSize: [38, 95], // size of the icon iconAnchor: [20, 68], // point of the icon which will correspond to marker's location popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor }); /* --------------- Générer la map aux bonnes coordonées --------------- */ var mymap = L.map('mapid').setView([46.6414, 2.5524], 5); L.tileLayer('https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(mymap); /* --------------- Markers --------------- */ var modulo = L.marker([50.1355, 3.4295], {icon: cultureIcon}).bindPopup("<h2> Modulo ateliers </h2> <p> 48 rue Gambetta <br> 59378 Dunkerque <br> 0328645389 <br> http://www.moduloatelier.com/ </p>"); var fructose = L.marker([51.0386, 2.3678], {icon: cultureIcon}).bindPopup("<h2> Frûctose </h2> <p> Rue du Magasin Général <br> 59540 Béthencourt <br> 0643858642 <br> https://www.fructosefructose.fr/ </p>"); var brasserie = L.marker([50.1471, 2.6309], {icon: cultureIcon}).bindPopup("<h2> Frûctose </h2> <p> 5 Rue Basse <br> 62111 Foncquevillers <br> 0687915782 <br> https://artbrasserie.com/ </p>"); var chas = L.marker([50.2909, 2.7744], {icon: cultureIcon}).bindPopup("<h2> L'Œil du Chas </h2> <p> 1 rue des Petits Viéziers <br> 62000 Arras <br> 0687915782 <br> https://www.facebook.com/loeilduchas </p>"); var ressourcesart = L.layerGroup([modulo, fructose, brasserie, chas]); var malterie = L.marker([50.6201, 3.0540], {icon: cultureIcon}).bindPopup("<h2> La Malterie </h2> <p> 42 Rue Kuhlmann <br> 59800 Lille <br> 0320151321 <br> http://www.lamalterie.com/ </p>"); var chambre = L.marker([50.0961, 3.7319], {icon: cultureIcon}).bindPopup("<h2> La Chambre d'Eau </h2> <p> 61 rue du moulin <br> 59550 Le Favril <br> 0327770926 <br> http://www.lachambredeau.fr/ </p>"); var siege = L.marker([50.3523, 3.5207], {icon: cultureIcon}).bindPopup("<h2> L'H Du Siège </h2> <p> 15 rue de l'Hôpital du Siège <br> 59300 Valenciennes <br> http://www.hdusiege.org/ </p>"); var smac = L.marker([50.3738, 3.0787], {icon: cultureIcon}).bindPopup("<h2> Service Mobile d'Animations Culturelles </h2> <p> Avenue des Potiers <br> 59500 Douai <br> 0777075009 <br> http://smacasso.com/ </p>"); var microatelier = L.marker([50.1631, 3.2067], {icon: cultureIcon}).bindPopup("<h2> Micro Atelier de Proville </h2> <p> 2 Rue de la Paix <br> 59267 Proville <br> 0321707487 <br> https://mediathequedelescaut.fr </p>"); var residence = L.layerGroup([malterie, chambre, siege, smac, microatelier]); var labo = L.marker([50.1725, 3.2312], {icon: cultureIcon}).bindPopup("<h2> Le Labo </h2><p> 2 Rue Louis Renard <br> 59400 Cambrai <br> 0374510000 <br> https://www.lelabocambrai.fr/</p>"); var theatre = L.marker([50.1753, 3.2290], {icon: cultureIcon}).bindPopup("<h2> Théâtre de Cambrai </h2><p> 1 Rue du Temple <br> 59400 Cambrai <br> 0327729500 <br> http://www.scenes-mitoyennes.fr/</p>"); var musée = L.marker([50.1733, 3.2299], {icon: cultureIcon}).bindPopup("<h2> Musée des Beaux-arts de Cambrai </h2><p> 15 Rue de l'Épée <br> 59400 Cambrai <br> 0327822790 </p>"); var crp = L.marker([50.3006, 3.3859], {icon: cultureIcon}).bindPopup("<h2> Centre Régional de Photographie </h2><p> Place des Nations <br> 59282 Douchy-les-Mines <br> 0327435650 <br>http://www.crp.photo/</p> "); var abbaye = L.marker([50.0767, 3.2220], {icon: cultureIcon}).bindPopup("<h2> Abbaye de Vaucelles </h2><p> Hammeau de Vaucelles <br> 59258 Les Rues-des-Vignes <br> 0359731498 <br> https://abbayedevaucelles.fr/ </p>"); var archeo = L.marker([50.0940, 3.2360], {icon: cultureIcon}).bindPopup("<h2> Archéo'site </h2><p> 882 Rue Haute <br> 9258 Les Rues-des-Vignes <br> 0970211746 <br> https://www.archeosite-ruesdesvignes.fr/ </p>"); var matisse = L.marker([50.1062, 3.5412], {icon: cultureIcon}).bindPopup("<h2> Musée Matisse </h2><p> Palais, Rue Fénelon <br> 59360 Le Cateau-Cambrésis <br> 0359733800 <br> https://museematisse.fr/ </p>"); var escaut = L.marker([50.1631, 3.2067], {icon: cultureIcon}).bindPopup("<h2> Médiathèque de l’Escaut </h2><p> 2 Rue de la Paix <br> 59267 Proville <br> 0327707487 <br> https://www.mediathequedelescaut.fr/ </p>"); var institutions = L.layerGroup([musée, theatre, labo, crp, archeo, abbaye, matisse, escaut]); var eclipse = L.marker([50.1819, 3.2353], {icon: loisirsIcon}).bindPopup("<h2> Centre d’animation Éclipse </h2><p>47 Avenue de Dunkerque<br> 59400 Cambrai <br> 0327837465 </p>"); var mission = L.marker([50.1771, 3.2384], {icon: loisirsIcon}).bindPopup("<h2> Mission locale du Cambrésis </h2><p> 24 Boulevard Faidherbe <br> 59400 Cambrai <br> 0327784848 </p>"); var sejc = L.marker([50.1819, 3.2353], {icon: loisirsIcon}).bindPopup("<h2> Service Enfance Jeunesse de Cambrai </h2><p>47 Avenue de Dunkerque<br> 59400 Cambrai <br> 0327812022 <br>www.sejc.fr</p>"); var generation = L.marker([50.1641, 3.2424], {icon: loisirsIcon}).bindPopup("<h2> R’Génération (Centre social) </h2><p> Rue Raymond Gernez <br> 59400 Cambrai <br> 0327703813 </p>"); var tipi = L.marker([50.1704, 3.2616], {icon: loisirsIcon}).bindPopup("<h2> Espace de vie sociale Le Tipi </h2><p> 14 rue Lafayette à Cambrai <br> 59400 Cambrai <br> 0327708692 <br>www.sejc.fr </p>"); var loisirs = L.layerGroup([eclipse, mission, sejc, generation]); var fenelon = L.marker([50.1759, 3.2291], {icon: ecoleIcon}).bindPopup("<h2> Collège et lycée Fénelon </h2><p> Place François de Fénelon <br> 59400 Cambrai <br> 0327727777 <br> http://lyc-fenelon.etab.ac-lille.fr/ </p>"); var duez = L.marker([50.1736, 3.2424], {icon: ecoleIcon}).bindPopup("<h2> Collège et lycée Paul Duez </h2><p> 1 Boulevard Paul Bezin <br> 59400 Cambrai <br> 0327730730 </p>"); var ferry = L.marker([50.1742, 3.2256], {icon: ecoleIcon}).bindPopup("<h2> Collège Jules Ferry </h2><p> 4 Rue Mgr Guerry<br> 59400 Cambrai <br> 0327837615 <br> https://jules-ferry-cambrai.enthdf.fr/</p>"); var lamartine = L.marker([50.1589, 3.2641], {icon: ecoleIcon}).bindPopup("<h2> Collège Lamartine </h2><p> 330 Rue Gauthier <br> 59400 Cambrai <br> 0327813317 </p>"); var brettignies = L.marker([50.1735, 3.2423], {icon: ecoleIcon}).bindPopup("<h2> Lycée professionnel Louise de Brettignies </h2><p> 3 Boulevard Paul Bezin <br> 59400 Cambrai <br> 0327730718 </p>"); var bleriot = L.marker([50.2284, 3.3193], {icon: ecoleIcon}).bindPopup("<h2> Lycée professionnel Louis Blériot </h2><p> Rue Gauthier <br> 59400 Cambrai <br> 0327722900 </p>"); var ecole = L.layerGroup([fenelon, duez, ferry, lamartine, brettignies, bleriot]); var esac = L.marker([50.1886, 3.2434], {icon: etudesIcon}).bindPopup("<h2> École Supérieur d'Arts de Cambrai </h2><p> 130 Allée Saint-Roch <br> 59400 Cambrai <br> 0327838142 <br> http://www.esac-cambrai.net/ </p>"); var upf = L.marker([50.1895, 3.2458], {icon: etudesIcon}).bindPopup("<h2> Centre Universitaire de Cambrai - UPHF </h2><p> 6 Rue de Rambouillet <br> 59400 Cambrai <br> 0327723300 <br> http://www.centre-universitaire-cambrai.fr/ </p>"); var sup = L.layerGroup([esac, upf]); var crous = L.marker([50.1822, 3.2422], {icon: aideIcon}).bindPopup("<h2> Résidence CROUS </h2><p> 50A Allée Saint-Roch <br> 59400 Cambrai</p>"); var caf = L.marker([50.1751, 3.2386], {icon: aideIcon}).bindPopup("<h2> CAF </h2><p> 2 Rang Saint-Jean <br> 59400 Cambrai</p>"); var ch = L.marker([50.1658, 3.2268], {icon: aideIcon}).bindPopup("<h2> Centre hospitalier </h2><p> 516 Avenue de Paris <br> 59400 Cambrai <br> 0327737373 <br> http://www.ch-cambrai.fr/ </p>"); var planning = L.marker([50.1751, 3.2356], {icon: aideIcon}).bindPopup("<h2> Planning familial </h2><p> 6 Rue du Maréchal de Lattre de Tassigny <br> 59400 Cambrai <br> 0327707059 <br> http://planningfamilial59.org/ </p>"); var aide = L.layerGroup([crous, caf, ch, planning]); var poterie = L.marker([50.1541, 3.2228], {icon: materiauxIcon}).bindPopup("<h2> Poterie du vieux bac </h2> <p> 905 avenue des Nations Unies <br> 59270 BAILLEUL <br> 0328499262> <br> https://poterieduvieuxbac.com </p>"); var brico = L.marker([50.1541, 3.2228], {icon: materiauxIcon}).bindPopup("<h2> Brico dépôt </h2><p> 1909 Avenue de Paris <br> 59400 Cambrai <br> 0327700950 </p>"); var leroy = L.marker([50.3543, 3.4866], {icon: materiauxIcon}).bindPopup("<h2> Leroy Merlin </h2><p> 30 Avenue Jean Jaurès <br> 59174 La Sentinelle <br> 0327215600 </p>"); var gamm = L.marker([50.1800, 3.2259], {icon: materiauxIcon}).bindPopup("<h2> Gamm Vert </h2><p> 54 Boulevard Jean Bart <br> 59400 Cambrai <br> 0327783511 </p>"); var bricomarche = L.marker([50.1701, 3.2316], {icon: materiauxIcon}).bindPopup("<h2> Bricomarché </h2><p> 1 Avenue de Paris <br> 59400 Cambrai <br> 0327783939 </p>"); var gedimat = L.marker([50.1736, 3.2157], {icon: materiauxIcon}).bindPopup("<h2> Gedimat Bracq </h2><p> Rue du champ de tir <br> 59400 Cambrai <br> 0327829600 </p>"); var pointp = L.marker([50.1847, 3.2300], {icon: materiauxIcon}).bindPopup("<h2> Point.P </h2><p> 140 Boulevard Faidherbe <br> 59400 Cambrai <br> 0327720404 </p>"); var murs = L.marker([50.1500, 3.2194], {icon: materiauxIcon}).bindPopup("<h2> 4Murs </h2><p> Chemin de Marcoing <br> 59400 Cambrai <br> 0327811008 </p>"); var chantemur = L.marker([50.1501, 3.2196], {icon: materiauxIcon}).bindPopup("<h2> Chantemur </h2><p> Avenue de Paris, ZI Sud RN44 <br> 59400 Cambrai <br> 0327749817 </p>"); var depot = L.marker([50.1840, 3.2506], {icon: materiauxIcon}).bindPopup("<h2> Electro Dépôt </h2><p> 197 Avenue de Valenciennes <br> 59400 Cambrai <br> 0327707240 </p>"); var materiaux = L.layerGroup([brico, leroy, gamm, bricomarche, gedimat, pointp, murs, chantemur, depot, poterie]); var furet = L.marker([50.1749, 3.2321], {icon: papierIcon}).bindPopup("<h2> Les Furets du Nord </h2><p> 22 Mail Saint-Martin <br> 59400 Cambrai <br> 0327813377 </p>"); var majuscule = L.marker([50.1738, 3.2320], {icon: papierIcon}).bindPopup("<h2> Majuscule </h2><p> 14 Rue Henri de Lubac <br> 59400 Cambrai <br> 0327812554 <br> https://www.majuscule-cambrai.com/SiteFront/ </p>"); var presse = L.marker([50.1758, 3.2356], {icon: papierIcon}).bindPopup("<h2> Maison de la presse </h2><p> 1 Rue du Général de Gaulle <br> 59400 Cambrai <br> 0327812707 </p>"); var bureau = L.marker([50.1966, 3.1926], {icon: papierIcon}).bindPopup("<h2> Bureau Vallée </h2><p> Avenue de Paris <br> 59400 Cambrai <br> 0327700009 </p>"); var papier = L.layerGroup([furet, majuscule, presse, bureau]); var danquigny = L.marker([50.1478, 3.22506], {icon: printIcon}).bindPopup("<h2> Imprimerie Danquigny </h2><p> Avenue Georges Nuttin <br> 59400 Cambrai <br> 0327831133 </p>"); var jacobin = L.marker([50.1757, 3.2317], {icon: printIcon}).bindPopup("<h2> Jacobin Copie et Barakom </h2><p> 14 Rue Tavelle <br> 59400 Cambrai <br> 0981200514 </p>"); var expression = L.marker([50.1716, 3.2318], {icon: printIcon}).bindPopup("<h2> Expression Impression </h2><p> Avenue de la Victoire <br> 59400 Cambrai <br> 0327796894 </p>"); var imprimerie = L.layerGroup([danquigny, jacobin, expression]); var poleemploi = L.marker([50.1757, 3.2433], {icon: printIcon}).bindPopup("<h2> Pôle emploi </h2><p> 16 Rue du Colonel Francis Nicol <br> 59400 Cambrai <br> 0972723949 <br> https://www.pole-emploi.fr/annuaire/</p>"); var cambresis = L.marker([50.1750, 3.2348], {icon: printIcon}).bindPopup("<h2> Cambresis Emploi </h2><p> 14 Rue Neuve <br> 59400 Cambrai <br> 0327700129 <br> http://www.cambresisemploi.fr/ </p>"); var cci = L.marker([50.3617, 3.5171], {icon: printIcon}).bindPopup("<h2> CCI Grand Hainaut </h2><p> 3 Avenue du Sénateur Girard <br> 59300 Valenciennes <br> 0327513513 <br> https://hautsdefrance.cci.fr/cci-grand-hainaut/ </p>"); var emploi = L.layerGroup([poleemploi, cambresis, cci]); var emmaus = L.marker([50.1687, 3.1649], {icon: autreIcon}).bindPopup("<h2> Emmaüs </h2><p> 952 Rte nationale <br> 59400 Fontaine-Notre-Dame <br> 0327781210 </p>"); var tourisme = L.marker([50.1732, 3.2323], {icon: autreIcon}).bindPopup("<h2> Office du tourisme </h2><p> 48 Rue Henri de Lubac <br> 59400 Cambrai <br> 0327783615 <br> http://www.tourisme-cambresis.fr/ </p>"); var autre = L.layerGroup([emmaus, tourisme]); var overlayMaps = {}; var layerControl = L.control.layers(overlayMaps).addTo(mymap); layerControl.addOverlay(institutions, "Centre Culturels"); layerControl.addOverlay(residence, "Résidence / Lieu d'exposition"); layerControl.addOverlay(ressourcesart, "Ressources Artistes"); layerControl.addOverlay(loisirs, "Centre de Loisirs"); layerControl.addOverlay(ecole, "Collèges et Lycées"); layerControl.addOverlay(sup, "Études Supérieures"); layerControl.addOverlay(aide, "Santé et Social"); layerControl.addOverlay(materiaux, "Bricolage et Matériaux"); layerControl.addOverlay(papier, "Librairies et Papiers"); layerControl.addOverlay(imprimerie, "Imprimeries"); layerControl.addOverlay(autre, "Autres"); layerControl.addOverlay(emploi, "Emplois"); </script> <div id="texte-carte"> <h2>Cartographie pour le designer libriste</h2> <p>Cette carte regroupe des ressources pour le designer ou le graphiste libriste comme des imprimerie riso, des ateliers de sérigraphie, des fablabs...</p> <p>Elle est collaborative, si vous voulez ajouter une adresse ou un point, vous pouvez l'inscrire dans ce <a href="https://annuel2.framapad.org/p/cartographie-collaborative-du-libre-9ztl?lang=fr" target="_blank">framapad</a>.</p> <p> Cette carte est créée via la librairie Leaflet, les données topographiques sont issus d'OpenStreetMap, le thème est Toner du studio de cartographie Stamen.</p> <h3>Liens Externes</h3> <div id="box-lien"> <a href="https://random.com">Cartographie Tiers-Lieux</a> </div> <div id="box-lien"> <a href="https://random.com">Cartographie de l'ATA</a> </div> </div> <header> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="cartographie.html">[Cartographie]</a></li> <li style="margin-right: 25px;"><a href="logiciels.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a <!DOCTYPE html> <html> <head> <title>GraphikLinux</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css" /> <script src="/Linux OS/leaflet/leaflet-src.js"></script> <script src="/Linux OS/leaflet/leaflet-src.js.map"></script> <script src="/Linux OS/action.js"></script> <script src="/Linux OS/p5js/p5.asciiart.js"></script> <script src="/Linux OS/p5js/p5.js"></script> <script src="/Linux OS/p5js/sketch.js"></script> </head> <body style="overflow:hidden"> <div id="big"> <img src="images/Fichier 2.svg" class="title"> </div> <script> // Symmetry corresponding to the number of reflections. Change the number for different number of reflections let symmetry = 6; let angle = 360 / symmetry; let saveButton, clearButton, mouseButton, keyboardButton; let slider; function setup() { createCanvas(windowWidth, windowHeight - 125); angleMode(DEGREES); background(211 , 211 , 211); // Creating the clear screen button clearButton = createButton('Reset'); clearButton.mousePressed(clearScreen); // Setting up the slider for the thickness of the brush brushSizeSlider = createButton('Taille de la ligne'); sizeSlider = createSlider(1, 8, 4, 0.1); } // Clear Screen function function clearScreen() { background(211); } function draw() { translate(width / 2, height / 2); if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { let mx = mouseX - width / 2; let my = mouseY - height / 2; let pmx = pmouseX - width / 2; let pmy = pmouseY - height / 2; if (mouseIsPressed) { for (let i = 0; i < symmetry; i++) { rotate(angle); let sw = sizeSlider.value(); strokeWeight(sw); line(mx, my, pmx, pmy); push(); scale(1, -1); line(mx, my, pmx, pmy); pop(); } } } } </script> <header style=" user-select: none;"> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="logiciels.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a href="informations.html">[Informations]</a></li> </ul> </nav> </header> <!-- <div id="menuicon" onclick="toggleDivs()"><a>MENU</a></div> <section id="menu-mobile" href="#"> <h1 style="margin-top:25px; text-align: center; font-size:32px;">Menu</h1> <a href="/annuaire.html">Annuaire format</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> <div id="close" onclick="toggleDivs()">Fermer le menu</div> </section> <section id="menu-ordi"> <a href="/annuaire.html">Annuaire Textuel</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> </section> </div> --> </body> </html>href="informations.html">[Informations]</a></li> </ul> </nav> </header> </body><!DOCTYPE html> <html> <head> <title>GraphikLinux</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css" /> <script src="leaflet/leaflet-src.js"></script> <script src="leaflet/leaflet-src.js.map"></script> <script src="action.js"></script> </head> <body> <header style="border-bottom:1px solid white;"> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="logiciels.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a href="informations.html">[Informations]</a></li> </ul> </nav> </header> <div id="informations"> Ce site web a été créé pour le DNSEP d'Anaël Le Gall portant sur la culture libriste et l'open-source appliqué au métier de designer graphique. <br> <br>Il se base sur des règles d'éco-conception permettant une indépendance vis-à-vis des Gafam, une durabilité dans le temps et des besoins énergétique et de connexion minimaux. <br><br>Les typographies utilisées sont la DINISH de (insérer auteur) et les polices présentes sur votre système d'exploitation. <br><br>Le site est disponible en téléchargement si vous désirez expérimenter autour. </div> </body> </html>/* CSS PERSO */ @font-face { font-family: ZRegular; src: url("fonts/Zara-Regular.otf") } @font-face { font-family: ZItalic; src: url("fonts/Zara-Oblique.otf") } @font-face { font-family: DRegular; src: url("fonts/DinishExpanded-Regular.ttf") } @font-face { font-family: DItalic; src: url("fonts/DinishExpanded-Italic.ttf") } @font-face { font-family: DBold; src: url("fonts/DinishExpanded-Bold.ttf") } body { cursor: crosshair; background-color:black; margin:0; padding:0; } .bandeau { margin-top:90px; display:flex; top:90px; width: auto; height: 50px; background-color: white; overflow: hidden; font-family: DBold; border-bottom: 1px solid black; } #bandeau2 { display:flex; margin-top:0px; width:350px; position:absolute; right:0; height:50px; background-color:lightgrey; border-bottom: 1px solid black; border-left:1px solid black; } marquee { width: 100%; height: 100%; font-size: 40px; text-transform: uppercase; font-weight: bold; color: #000; white-space: nowrap; } header a { font-size:calc(0.6vw + 5px) } #link { display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px; } #link a { margin-right:25px; padding:5px; text-decoration:underline; } #informations { margin:125px 25px 25px 25px; width:30vw; font-family: DRegular; font-size: 1em; line-height:1.2em; color:white; } #linux { margin:125px 25px 25px 25px; width:90vw; font-family: DRegular; font-size: 1em; line-height:1.2em; color:white; } #box-linux { border:1px dashed white; } #texte-carte { position:absolute; right:5vw; top:105px; width:30vw; margin:0 1vw 0 1vw; } #texte-carte a { color:rgb(0, 255, 0);; text-decoration:underline; } h2 { color:white; } #texte-carte h2 { font-family: DBold; } #content { display:block; overflow: scroll; height:calc(100vh - 65px); width:100vw; background-color: black; margin: 90px 0px 15px 0px; } .grid { display:block; overflow: scroll; display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; width:calc(100vw - 30); margin: 50px 15px 0 15px; } .grid-item { grid-template-rows: repeat(auto-fit, 3, 1fr); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); padding:15px; background-color:black; align-items: center; border-left:1px dashed rgba(211, 211, 211, 0.5); border-right:1px dashed rgba(211, 211, 211, 0.5); justify-content: center; font-size: 2em; } #table { width:100vw; height:40px; position:fixed; top:90px; background-color: rgb(0, 0, 0); border-bottom: 1px solid rgb(0, 255, 0); display:flex; box-shadow: 0px -10px 25px 15px rgba(0, 255, 0, 0.6) } #table a { color:white; } #texte-menu { text-align: center; font-family:monospace; font-size: 12px; width:15vw; height: 27px; padding-left:10px; padding-right:10px; padding-top:14px; border-right:1px solid rgb(0, 255, 0);; } #texte-menu a { text-align: center; font-family:monospace; color:white; } .grid3 { display:grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 1vw; width:calc(100vw - 30px); margin: 10px 15px 0 15px; } .grid-item3 { padding:15px; background-color:rgb(0, 0, 0); align-items: center; justify-content: center; font-size: 2em; height:auto; width: auto; } .grid2 { overflow: scroll; display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 15px; width:calc(100vw - 30px); margin: 50px 15px 0 15px; } .grid-item2 { grid-template-rows: repeat(auto-fit, 1, 3fr); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); padding:15px; background-color:rgb(0, 0, 0); align-items: center; justify-content: center; font-size: 2em; height:auto; } #cat { border-radius:15px; background-color: rgb(255, 255, 255); padding-bottom:15px; margin-bottom: 25px; padding:15px; border:1px solid white; } a:hover { color:rgb(0, 255, 255) } a:active { color:rgb(0, 255, 255) } #cat a { color:black; text-decoration:underline; } #box-lien p { color:white; } #cat:hover { border:1px solid rgba(0, 255, 0); box-shadow: 0px 0px 25px 10px rgba(0, 255, 0, 0.6) } #content h4 { font-family: DBOLD; font-size: 0.6em; margin:0; } h3 { font-family: DBold; color:white; } #content h3 { text-transform: uppercase; margin-bottom:25px; margin-top:10px; padding-left:10px; padding-bottom: 5px; font-family: DRegular; font-size: 0.8em; border-bottom: 1px solid rgba(255, 255, 255, 0.476); } #content p { font-family: DItalic; font-size: 0.5em; line-height:1.3em; color:black; } p { color:white; font-family: DRegular; font-size: 1em; line-height:1.2em; } a { text-decoration: none; font-family: monospace; font-size:1.1em; margin:0; padding:0; } a:active { color:red; } #content a { font-family: monospace; font-size:12px; margin:0; padding:0; } #content a:visited { margin:0; } #bloc { width:100px; height:75px; background-color: lightgrey; border: 1px solid black; } #bloc:hover { position:relative; width:100px; height:75px; background-color: rgb(0, 255, 0);; border: 1px dashed black; } #defaultCanvas0 { margin-top: 90px; overflow:hidden; } #big { display: block; margin-left: auto; margin-right: auto; width: 25%; } .title { position:absolute; margin-top:28vh; width:25%; text-align: center; pointer-events:none; } img { } #titre { padding:25px; background-color: black; position:fixed; width:50vh; height:50vh; border-radius:360px; border:2px solid black; } #titre h1{ color:white; user-select: none; font-family: ZItalic; text-align:center; font-size:3em; margin:85px 0 0 0; } #titre p { font-size:1vmax; hyphens:none; user-select:none; margin-top:10px; text-align:center; } #mapid { display:block; position: absolute; height:calc(100vh - 125px); width:60vw; border: 1px dashed rgb(0, 255, 0); background-color:black; margin: 105px 15px 15px 15px; } header h1{ font-family: Zitalic; text-transform: lowercase; text-align: center; margin-top:15px; color:white; } nav { display: flex; justify-content: center; } ul { list-style: none; margin: 0; padding: 0; } li { margin: 0 10px; } header { position: fixed; top: 0; left: 0; margin:0; padding:0 0 15px 0; width: 100%; background-color: rgb(0, 0, 0); border-bottom:1px solid rgb(0, 255, 0);; z-index: 1; display: flex; flex-direction: column; align-items: center; } header a{ color:rgb(0, 255, 0);; } /* required styles */ .leaflet-pane, .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow, .leaflet-tile-container, .leaflet-pane > svg, .leaflet-pane > canvas, .leaflet-zoom-box, .leaflet-image-layer, .leaflet-layer { position: absolute; left: 0; top: 0; } .leaflet-container { overflow: hidden; } .leaflet-tile, .leaflet-marker-icon, .leaflet-marker-shadow { -webkit-user-select: none; -moz-user-select: none; user-select: none; -webkit-user-drag: none; } /* Prevents IE11 from highlighting tiles in blue */ .leaflet-tile::selection { background: transparent; } /* Safari renders non-retina tile on retina better with this, but Chrome is worse */ .leaflet-safari .leaflet-tile { image-rendering: -webkit-optimize-contrast; } /* hack that prevents hw layers "stretching" when loading new tiles */ .leaflet-safari .leaflet-tile-container { width: 1600px; height: 1600px; -webkit-transform-origin: 0 0; } .leaflet-marker-icon, .leaflet-marker-shadow { display: block; } /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ .leaflet-container .leaflet-overlay-pane svg { max-width: none !important; max-height: none !important; } .leaflet-container .leaflet-marker-pane img, .leaflet-container .leaflet-shadow-pane img, .leaflet-container .leaflet-tile-pane img, .leaflet-container img.leaflet-image-layer, .leaflet-container .leaflet-tile { max-width: none !important; max-height: none !important; width: auto; padding: 0; } .leaflet-container.leaflet-touch-zoom { -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; } .leaflet-container.leaflet-touch-drag { -ms-touch-action: pinch-zoom; /* Fallback for FF which doesn't support pinch-zoom */ touch-action: none; touch-action: pinch-zoom; } .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { -ms-touch-action: none; touch-action: none; } .leaflet-container { -webkit-tap-highlight-color: transparent; } .leaflet-container a { -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); } .leaflet-tile { filter: inherit; visibility: hidden; } .leaflet-tile-loaded { visibility: inherit; } .leaflet-zoom-box { width: 0; height: 0; -moz-box-sizing: border-box; box-sizing: border-box; z-index: 800; } /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ .leaflet-overlay-pane svg { -moz-user-select: none; } .leaflet-pane { z-index: 400; } .leaflet-tile-pane { z-index: 200; } .leaflet-overlay-pane { z-index: 400; } .leaflet-shadow-pane { z-index: 500; } .leaflet-marker-pane { z-index: 600; } .leaflet-tooltip-pane { z-index: 650; } .leaflet-popup-pane { z-index: 700; } .leaflet-map-pane canvas { z-index: 100; } .leaflet-map-pane svg { z-index: 200; } .leaflet-vml-shape { width: 1px; height: 1px; } .lvml { behavior: url(#default#VML); display: inline-block; position: absolute; } /* control positioning */ .leaflet-control { position: relative; z-index: 800; pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: auto; } .leaflet-top, .leaflet-bottom { position: absolute; z-index: 1000; pointer-events: none; } .leaflet-top { top: 0; } .leaflet-right { right: 0; } .leaflet-bottom { bottom: 0; } .leaflet-left { left: 0; } .leaflet-control { float: left; clear: both; } .leaflet-right .leaflet-control { float: right; } .leaflet-top .leaflet-control { margin-top: 10px; } .leaflet-bottom .leaflet-control { margin-bottom: 10px; } .leaflet-left .leaflet-control { margin-left: 10px; } .leaflet-right .leaflet-control { margin-right: 10px; } /* zoom and fade animations */ .leaflet-fade-anim .leaflet-popup { opacity: 0; -webkit-transition: opacity 0.2s linear; -moz-transition: opacity 0.2s linear; transition: opacity 0.2s linear; } .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { opacity: 1; } .leaflet-zoom-animated { -webkit-transform-origin: 0 0; -ms-transform-origin: 0 0; transform-origin: 0 0; } svg.leaflet-zoom-animated { will-change: transform; } .leaflet-zoom-anim .leaflet-zoom-animated { -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); transition: transform 0.25s cubic-bezier(0,0,0.25,1); } .leaflet-zoom-anim .leaflet-tile, .leaflet-pan-anim .leaflet-tile { -webkit-transition: none; -moz-transition: none; transition: none; } .leaflet-zoom-anim .leaflet-zoom-hide { visibility: hidden; } /* cursors */ .leaflet-interactive { cursor: pointer; } .leaflet-grab { cursor: -webkit-grab; cursor: -moz-grab; cursor: grab; } .leaflet-crosshair, .leaflet-crosshair .leaflet-interactive { cursor: crosshair; } .leaflet-popup-pane, .leaflet-control { cursor: auto; } .leaflet-dragging .leaflet-grab, .leaflet-dragging .leaflet-grab .leaflet-interactive, .leaflet-dragging .leaflet-marker-draggable { cursor: move; cursor: -webkit-grabbing; cursor: -moz-grabbing; cursor: grabbing; } /* marker & overlays interactivity */ .leaflet-marker-icon, .leaflet-marker-shadow, .leaflet-image-layer, .leaflet-pane > svg path, .leaflet-tile-container { pointer-events: none; } .leaflet-marker-icon.leaflet-interactive, .leaflet-image-layer.leaflet-interactive, .leaflet-pane > svg path.leaflet-interactive, svg.leaflet-image-layer.leaflet-interactive path { pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: auto; } /* visual tweaks */ .leaflet-container { background: #ddd; outline-offset: 1px; } .leaflet-container a { color: #0078A8; } .leaflet-zoom-box { border: 2px dotted #38f; background: rgba(255,255,255,0.5); } /* general typography */ .leaflet-container { font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; font-size: 12px; font-size: 0.75rem; line-height: 1.5; } /* general toolbar styles */ .leaflet-bar { } .leaflet-bar a { background-color: #fff; width: 26px; height: 26px; line-height: 26px; display: block; text-align: center; text-decoration: none; color: black; } .leaflet-bar a, .leaflet-control-layers-toggle { background-position: 50% 50%; background-repeat: no-repeat; display: block; } .leaflet-bar a:hover, .leaflet-bar a:focus { background-color: #f4f4f4; } .leaflet-bar a:first-child { border-bottom: none; } .leaflet-bar a:last-child { } .leaflet-bar a.leaflet-disabled { cursor: default; background-color: #f4f4f4; color: #bbb; } .leaflet-touch .leaflet-bar a { width: 30px; height: 30px; line-height: 30px; } .leaflet-touch .leaflet-bar a:first-child { } .leaflet-touch .leaflet-bar a:last-child { } /* zoom control */ .leaflet-control-zoom-in, .leaflet-control-zoom-out { font: bold 18px 'Lucida Console', Monaco, monospace; text-indent: 1px; } .leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { font-size: 22px; border:0.75px solid; } /* layers control */ .leaflet-control-layers { box-shadow: 0 1px 5px rgba(0,0,0,0.4); background: #fff; border-radius: 5px; } .leaflet-control-layers-toggle { background-image: url(images/layers.png); width: 36px; height: 36px; } .leaflet-retina .leaflet-control-layers-toggle { background-image: url(images/layers-2x.png); background-size: 26px 26px; } .leaflet-touch .leaflet-control-layers-toggle { width: 44px; height: 44px; } .leaflet-control-layers .leaflet-control-layers-list, .leaflet-control-layers-expanded .leaflet-control-layers-toggle { display: none; } .leaflet-control-layers-expanded .leaflet-control-layers-list { display: block; position: relative; } .leaflet-control-layers-expanded { padding: 6px 10px 6px 6px; color: #333; background: #fff; } .leaflet-control-layers-scrollbar { overflow-y: scroll; overflow-x: hidden; padding-right: 5px; } .leaflet-control-layers-selector { margin-top: 2px; position: relative; top: 1px; } .leaflet-control-layers label { display: block; font-size: 13px; font-size: 1.08333em; } .leaflet-control-layers-separator { height: 0; border-top: 1px solid #ddd; margin: 5px -10px 5px -6px; } /* Default icon URLs */ .leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ background-image: url(images/marker-icon.png); } /* attribution and scale controls */ .leaflet-container .leaflet-control-attribution { background: #fff; background: rgba(255, 255, 255, 0.8); margin: 0; } .leaflet-control-attribution, .leaflet-control-scale-line { padding: 0 5px; color: #333; line-height: 1.4; } .leaflet-control-attribution a { text-decoration: none; } .leaflet-control-attribution a:hover, .leaflet-control-attribution a:focus { text-decoration: underline; } .leaflet-attribution-flag { display: inline !important; vertical-align: baseline !important; width: 1em; height: 0.6669em; } .leaflet-left .leaflet-control-scale { margin-left: 5px; } .leaflet-bottom .leaflet-control-scale { margin-bottom: 5px; } .leaflet-control-scale-line { border-top: none; line-height: 1.1; padding: 2px 5px 1px; white-space: nowrap; -moz-box-sizing: border-box; box-sizing: border-box; background: rgba(255, 255, 255, 0.8); text-shadow: 1px 1px #fff; } .leaflet-control-scale-line:not(:first-child) { border-top: 2px solid #777; border-bottom: none; margin-top: -2px; } .leaflet-control-scale-line:not(:first-child):not(:last-child) { border-bottom: 2px solid #777; } .leaflet-touch .leaflet-control-attribution, .leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-bar { } .leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-bar { border: 1px solid black; background-clip: padding-box; } /* popup */ .leaflet-popup { position: absolute; text-align: center; margin-bottom: 20px; } .leaflet-popup-content-wrapper { color:rgb(0, 255, 0);; padding: 1px; text-align: left; border-radius: 12px; } .leaflet-popup-content { margin: 13px 24px 13px 20px; line-height: 1.3; font-size: 13px; font-size: 1.08333em; min-height: 1px; } .leaflet-popup-content p { margin: 17px 0; margin: 1.3em 0; } .leaflet-popup-tip-container { width: 40px; height: 20px; position: absolute; left: 50%; margin-top: -1px; margin-left: -20px; overflow: hidden; pointer-events: none; } .leaflet-popup-tip { width: 17px; height: 17px; padding: 1px; margin: -10px auto 0; pointer-events: auto; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); } .leaflet-popup-content-wrapper, .leaflet-popup-tip { background: white; color: #333; box-shadow: 0 3px 14px rgba(0,0,0,0.4); } .leaflet-container a.leaflet-popup-close-button { position: absolute; top: 0; right: 0; border: none; text-align: center; width: 24px; height: 24px; font: 16px/24px Tahoma, Verdana, sans-serif; color: #757575; text-decoration: none; background: transparent; } .leaflet-container a.leaflet-popup-close-button:hover, .leaflet-container a.leaflet-popup-close-button:focus { color: #585858; } .leaflet-popup-scrolled { overflow: auto; } .leaflet-oldie .leaflet-popup-content-wrapper { -ms-zoom: 1; } .leaflet-oldie .leaflet-popup-tip { width: 24px; margin: 0 auto; -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); } .leaflet-oldie .leaflet-control-zoom, .leaflet-oldie .leaflet-control-layers, .leaflet-oldie .leaflet-popup-content-wrapper, .leaflet-oldie .leaflet-popup-tip { border: 1px solid #999; } /* div icon */ .leaflet-div-icon { background: #fff; } /* Tooltip */ /* Base styles for the element that has a tooltip */ .leaflet-tooltip { position: absolute; padding: 6px; background-color: #fff; border: 1px solid #fff; border-radius: 3px; color: #222; white-space: nowrap; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; pointer-events: none; box-shadow: 0 1px 3px rgba(0,0,0,0.4); } .leaflet-tooltip.leaflet-interactive { cursor: pointer; pointer-events: auto; } .leaflet-tooltip-top:before, .leaflet-tooltip-bottom:before, .leaflet-tooltip-left:before, .leaflet-tooltip-right:before { position: absolute; pointer-events: none; border: 6px solid transparent; background: transparent; content: ""; } /* Directions */ .leaflet-tooltip-bottom { margin-top: 6px; } .leaflet-tooltip-top { margin-top: -6px; } .leaflet-tooltip-bottom:before, .leaflet-tooltip-top:before { left: 50%; margin-left: -6px; } .leaflet-tooltip-top:before { bottom: 0; margin-bottom: -12px; border-top-color: #fff; } .leaflet-tooltip-bottom:before { top: 0; margin-top: -12px; margin-left: -6px; border-bottom-color: #fff; } .leaflet-tooltip-left { margin-left: -6px; } .leaflet-tooltip-right { margin-left: 6px; } .leaflet-tooltip-left:before, .leaflet-tooltip-right:before { top: 50%; margin-top: -6px; } .leaflet-tooltip-left:before { right: 0; margin-right: -12px; border-left-color: #fff; } .leaflet-tooltip-right:before { left: 0; margin-left: -12px; border-right-color: #fff; } /* Printing */ @media print { /* Prevent printers from removing background-images of controls. */ .leaflet-control { -webkit-print-color-adjust: exact; print-color-adjust: exact; } } @media only screen and (max-width: 600px) { body{ } h1 { font-size:1.2em; line-height: 15px; } h2 { font-size:0.8em; } #menuicon { font-family:Regular; display:block; text-align: center; background-color: lightblue; position: absolute; margin: 15px 15px 25px 0; padding-top: 25px; right:0; bottom:0; height:45px; width:125px; border: 1.5px dashed black; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #annuaire { font-family:Regular; font-size:0.8em; display: block; text-align: center; justify-content: center; position:absolute; right:0; margin:10px 20px 0 0; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #atlas{ font-family:Regular; font-size:0.8em; display:block; justify-content: center; position:absolute; right:0; margin:45px 20px 0 0 ; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #add{ font-family:Regular; font-size:0.8em; display: block; position:absolute; right:0px; margin: 80px 20px 0 0; width:calc(100% - 60vw); height:25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #menu-mobile { z-index:10; position:fixed; top:0; display:none; width: 100vw; height:calc(100vh - 17.5vh); background-color: lightgrey; } #menu-ordi { display:none; } #menu-mobile a { text-decoration: none; font-family: Regular; font-size: 18px; display:block; position:relative; padding: 10px 10px 10px 25px; margin:25px 25px 0 25px; background-color: lightblue; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #contenting { } #close { text-decoration: none; font-family: Regular; color:whitesmoke; text-align:center; background-color: black; font-size: 18px; display:block; position:relative; padding: 10px 10px 10px 25px; margin:25px 25px 0 25px; border: 1px black solid; filter: drop-shadow(2px 2px 5px rgba(0, 0, 0, 0.534)); } #mapid { display:block; } .texte { text-decoration: underline; margin-top: 4px; text-align: center; text-justify: center; } .grid2 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }<!DOCTYPE html> <html> <head> <title>GraphikLinux</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css"> <script src="leaflet/leaflet-src.js"></script> <script src="leaflet/leaflet-src.js.map"></script> <script src="action.js"></script> </head> <body> <header> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a href="informations.html">[Informations]</a></li> </ul> </nav> </header> <div id="linux"> Le but de cette distribution de Linux est de proposé un système exploitation orienté vers la création graphique libre. Elle se base sur Unbuntu, une distribution de Linux relativement accessible pour des personnes qui n'ont pas l'habitude de cet OS. Il est livré avec une série de logiciels pré-installés pour couvrir tous les besoins d'un designer graphique, allant de la création numérique, à la gestion typographique en passant par des outils de code créatif.<br><br> Cela se présente sous la forme d'une image disque (un fichier .iso) qu'il faut envoyer sur une clef USB afin de l'installer sur votre machine. Il est conseillé de l'installer sur un disque dur à part. Néanmoins si vous avez assez d'espace sur votre disque, il est possible de l'installer en "dual boot", ce qui signifie que vous aurez le choix du système d'exploitation à utiliser au démarage de votre machine. <br><br>Pour plus d'information sur l'installation d'Ubuntu, je vous redirige vers ce tutoriel : <br> Le lien pour télécharger UnbuntuGraphik : <br><br> <h4>Tutoriel Linux</h4> <p>- Télécharger l'ISO de UnbuntuGraphik<br> - Munissez vous d'une clé USB vierge ou supprimer toutes les données présentes dessus<br> - Télécharer <a href="https://etcher.balena.io/" style="font-family: DRegular; color:white; text-decoration:underline; font-size:1em;">Etcher</a>, qui vous permettra de flasher l'ISO sur votre clé USB<br> - Ouvrir Etcher, Sélectionner le fichier .iso dans "Flash From File", votre clé USB dans Select Target et Appuyer sur "Flash!" <br> - Brancher votre clé USB sur l'ordinateur où vous voulez installer Linux et lancer votre ordinateur<br> - Au démarrage, lorsque que le logo de votre machine apparaît, appuyer sur la touche pour ouvrir le Bios (F11, Del ou autre indiquer sur l'écran)<br> - Dans les options de démarrage (Boot Menu), mettez votre clé USB en premier et relancer votre ordinateur<br> - Si tout se passe bien, vous devriez avoir le programme d'installation d'Unbuntu qui se lance</p> </div> <div id="content" style="margin:0 0 0 0"> <div class="grid3"> <div class="grid-item3"> <div id="cat"> <h4>Télécharger UnbuntuGraphik</h4> <p>Pour télécharger l'image disque nécessaire à l'installation de l'OS (10go)</p> <div id="link"> <a>unbuntu-graphik-beta.iso</a> </div> </div> </div> </div> </div> </div> </div> <!-- <div id="menuicon" onclick="toggleDivs()"><a>MENU</a></div> <section id="menu-mobile" href="#"> <h1 style="margin-top:25px; text-align: center; font-size:32px;">Menu</h1> <a href="/annuaire.html">Annuaire format</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> <div id="close" onclick="toggleDivs()">Fermer le menu</div> </section> <section id="menu-ordi"> <a href="/annuaire.html">Annuaire Textuel</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> </section> </div> --> </body> </html><!DOCTYPE html> <html> <head> <title>GraphikLinux</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css" /> <script src="leaflet/leaflet-src.js"></script> <script src="leaflet/leaflet-src.js.map"></script> <script src="action.js"></script> </head> <body> <header> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="logiciels.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a href="informations.html">[Informations]</a></li> </ul> </nav> </header> <div id="table"> <div id="texte-menu"><a href="#miseenpage">[Mise en Page]</a></div> <div id="texte-menu"><a href="#dessinvectoriel">[Dessin Vectoriel]</a></div> <div id="texte-menu"><a href="#manipulationphoto">[Manipulation Photo]</a></div> <div id="texte-menu"><a href="#typographie">[Typographie]</a></div> <div id="texte-menu"><a href="#uiux">[UI/UX]</a></div> <div id="texte-menu"><a href="#codecréatif">[Code Créatif]</a></div> <div id="texte-menu"><a href="#autre">[AUTRE]</a></div> </div> <div id="content" style="height:calc(100vh - 105px);"> <div class="grid2"> <div class="grid-item2" id="dessinvectoriel"> <h3>Dessin Vectoriel</h3> <div id="cat"> <h4>Inkscape</h4> <p>Inkscape est un logiciel libre et gratuit de dessin vectoriel. Il est utilisé pour créer des images vectorielles, des illustrations, des graphiques, des logos et des dessins animés. Le logiciel prend en charge les formats de fichiers SVG, PDF, EPS, AI et bien d'autres encore. Il propose une variété d'outils de dessin, de formes, de courbes, de texte et de couleurs pour vous permettre de créer des dessins précis et professionnels. </p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://inkscape.org/release/1.2.2/windows/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://inkscape.org/release/1.2.2/mac-os-x/" style="margin-right:25px;">MacOs</a> <a href="https://inkscape.org/release/1.2.2/gnulinux/" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Krita</h4> <p>Krita est un logiciel de dessin et de peinture numérique libre et gratuit, offrant une large gamme d'outils de dessin et de peinture personnalisables, des calques, des masques de calque, des sélections et des outils de transformation. Il est spécialement conçu pour les artistes et dispose de fonctionnalités telles que la stabilisation des traits, les assistants de dessin et la référence de couleur.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://krita.org/fr/telechargement/krita-desktop/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://krita.org/fr/telechargement/krita-desktop/" style="margin-right:25px;">MacOs</a> <a href="https://krita.org/fr/telechargement/krita-desktop/" style="margin-right:25px;">Linux</a> </div> </div> </div> </section> <div class="grid-item2" id="miseenpage"> <h3>Mise en page</h3> <div id="cat"> <h4>Scribus</h4> <p>Scribus est un logiciel de mise en page professionnelle open source et gratuit, disponible pour Windows, Mac et Linux. Il permet de créer des documents tels que des magazines, des brochures, des livres, des dépliants, des affiches, etc. avec un haut niveau de personnalisation. Scribus propose des fonctionnalités avancées telles que la gestion de couleurs, la transparence, les effets de texte, l'ajout d'images, de tableaux, de graphiques, de formes et bien plus encore. Il est très apprécié pour sa facilité d'utilisation, sa qualité d'impression professionnelle et sa capacité à gérer des documents à plusieurs pages.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://sourceforge.net/projects/scribus/files/scribus/1.4.8/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://sourceforge.net/projects/scribus/files/scribus/1.4.8/" style="margin-right:25px;">MacOs</a> <a href="https://wiki.scribus.net/canvas/Debian" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Paged.js</h4> <p>Paged.js est un moteur de pagination open source qui permet de créer des documents paginés pour le web en utilisant les technologies web standards telles que HTML, CSS et JavaScript. Il offre une alternative à la pagination traditionnelle basée sur les logiciels de traitement de texte, en offrant une flexibilité de mise en page et une personnalisation totale.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/" style="margin-right:25px;">MacOs</a> <a href="https://gitlab.coko.foundation/pagedjs/pagedjs/" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>LibreOffice</h4> <p>LibreOffice est un logiciel de mise en page complet et gratuit qui peut être utilisé pour créer une grande variété de documents professionnels. Avec ses fonctionnalités de mise en page avancées et sa compatibilité avec d'autres formats de fichiers, LibreOffice est une solution efficace pour les entreprises, les organisations et les particuliers qui cherchent à créer des documents de qualité.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://www.libreoffice.org/download/download-libreoffice/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://www.libreoffice.org/download/download-libreoffice/" style="margin-right:25px;">MacOs</a> <a href="https://www.libreoffice.org/download/download-libreoffice/" style="margin-right:25px;">Linux</a> </div> </div> </div> <div class="grid-item2" id="manipulationphoto"> <h3>Manipulation Photo</h3> <div id="cat"> <h4>GIMP</h4> <p>C'est un éditeur d'images open source disponible sur plusieurs plateformes, y compris Windows, Mac OS X et Linux. Il dispose d'une gamme complète d'outils de retouche d'image, de dessin et de peinture. Il prend en charge de nombreux formats de fichiers d'image, y compris les fichiers PSD de Photoshop.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://www.gimp.org/downloads/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://www.gimp.org/downloads/" style="margin-right:25px;">MacOs</a> <a href="https://www.gimp.org/downloads/" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Darktable </h4> <p>C'est un logiciel open source de développement de fichiers RAW pour la photographie numérique, offrant des fonctionnalités de retouche et de gestion de la bibliothèque d'images. Il prend en charge une grande variété de formats de fichiers d'image et offre des fonctionnalités de traitement par lot pour automatiser le processus de développement de fichiers RAW.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://www.darktable.org/install/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://www.darktable.org/install/" style="margin-right:25px;">MacOs</a> <a href="https://www.darktable.org/install/" style="margin-right:25px;">Linux</a> </div> </div> </div> <div class="grid-item2" id="codecréatif"> <h3>Code Créatif</h3> <div id="cat"> <h4>Processings</h4> <p>Processing est un environnement de programmation open source et multiplateforme conçu pour créer des projets graphiques, artistiques et interactifs. Il est particulièrement populaire pour les projets impliquant la création d'animations, de visualisations de données, de jeux et de médias interactifs.<br> Processing est basé sur le langage de programmation Java et utilise une syntaxe simplifiée pour faciliter l'apprentissage et l'utilisation. Il offre également une bibliothèque de graphiques 2D et 3D prête à l'emploi, ainsi qu'une grande communauté d'utilisateurs qui partagent des projets, des ressources et des tutoriels.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://processing.org/download" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://processing.org/download" style="margin-right:25px;">MacOs</a> <a href="https://processing.org/download" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Pure Data</h4> <p>Processing est un environnement de programmation open source et multiplateforme conçu pour créer des projets graphiques, artistiques et interactifs. Il est particulièrement populaire pour les projets impliquant la création d'animations, de visualisations de données, de jeux et de médias interactifs.<br> Processing est basé sur le langage de programmation Java et utilise une syntaxe simplifiée pour faciliter l'apprentissage et l'utilisation. Il offre également une bibliothèque de graphiques 2D et 3D prête à l'emploi, ainsi qu'une grande communauté d'utilisateurs qui partagent des projets, des ressources et des tutoriels.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://puredata.info/downloads" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://puredata.info/downloads" style="margin-right:25px;">MacOs</a> <a href="https://puredata.info/downloads" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>p5.js</h4> <p>p5.js est une bibliothèque open source de programmation créative basée sur le langage JavaScript et conçue pour faciliter la création d'œuvres d'art numériques, de visualisations de données, d'animations et d'interfaces interactives pour le web. p5.js est une bibliothèque de traitement (processing) qui utilise une approche basée sur le dessin en 2D et 3D pour créer des projets créatifs et interactifs pour le web.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://p5js.org/download/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://p5js.org/download/" style="margin-right:25px;">MacOs</a> <a href="https://p5js.org/download/" style="margin-right:25px;">Linux</a> </div> </div> </div> <div class="grid-item2" id="typographie"> <h3>Typographie</h3> <div id="cat"> <h4>FontBase</h4> <p>FontBase est un gestionnaire de polices open source qui prend en charge les systèmes d'exploitation Windows, macOS et Linux. Il permet de gérer et d'organiser des collections de polices, de prévisualiser des polices avant de les installer, de rechercher des polices par nom ou par style, et d'activer ou de désactiver des polices pour une utilisation dans des applications.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://fontba.se/downloads/windows" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://fontba.se/downloads/mac" style="margin-right:25px;">MacOs</a> <a href="https://fontba.se/downloads/linux" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Fontmatrix</h4> <p>C'est un outil de gestion de polices de caractères libre et gratuit pour Linux. Il permet de visualiser, d'installer et de gérer des collections de polices de caractères, de créer des ensembles de polices et d'effectuer des opérations de recherche avancée.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://github.com/fontmatrix/fontmatrix" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://github.com/fontmatrix/fontmatrix" style="margin-right:25px;">MacOs</a> <a href="https://github.com/fontmatrix/fontmatrix" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>FontForge</h4> <p>FontForge est un éditeur de polices de caractères libre et gratuit pour Linux. Il permet de créer, d'éditer et de modifier des polices de caractères à partir de zéro ou de fichiers existants. FontForge prend en charge de nombreux formats de fichiers de polices, y compris TrueType, OpenType et PostScript.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://fontforge.org/en-US/downloads/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://fontforge.org/en-US/downloads/" style="margin-right:25px;">MacOs</a> <a href="https://fontforge.org/en-US/downloads/" style="margin-right:25px;">Linux</a> </div> </div> </div> <div class="grid-item2" id="uiux"> <h3>UI/UX</h3> <div id="cat"> <h4>Figma</h4> <p>C'est un logiciel de conception graphique open source qui permet de créer des designs d'interfaces utilisateur pour les applications web et mobiles. Il dispose d'outils de dessin vectoriel et de fonctionnalités de collaboration en temps réel pour permettre à plusieurs utilisateurs de travailler simultanément sur un même projet.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://www.figma.com/downloads/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://www.figma.com/downloads/" style="margin-right:25px;">MacOs</a> <a href="https://www.figma.com/downloads/" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Pencil Project</h4> <p>C'est un outil open source de prototypage d'interface utilisateur pour les applications web et mobiles. Il permet de créer des maquettes d'interface utilisateur interactives, de dessiner des diagrammes de flux, de créer des storyboards et de collaborer avec d'autres utilisateurs en temps réel.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://pencil.evolus.vn/Downloads.html" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://pencil.evolus.vn/Downloads.html" style="margin-right:25px;">MacOs</a> <a href="https://pencil.evolus.vn/Downloads.html" style="margin-right:25px;">Linux</a> </div> </div> </div> <div class="grid-item2" id="autre"> <h3>Autre</h3> <div id="cat"> <h4>Blender</h4> <p>Blender est un logiciel de modélisation, d'animation et de rendu 3D libre et gratuit. Il est utilisé pour la création d'images, de vidéos, de jeux vidéo, d'animations et d'effets visuels. Blender offre une large gamme d'outils pour la modélisation 3D, la sculpture numérique, la texture, l'éclairage et l'animation, ainsi que des fonctionnalités avancées telles que la simulation physique, la composition et le montage vidéo. Il est également extensible grâce à un système de scripts et de plug-ins.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://www.blender.org/download/" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://www.blender.org/download/" style="margin-right:25px;">MacOs</a> <a href="https://www.blender.org/download/" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>VSCodium</h4> <p>VSCodium est un éditeur de code open source et gratuit, qui est une version sans les composants propriétaires de l'éditeur de code populaire Visual Studio Code (VS Code) de Microsoft. Il offre une interface utilisateur conviviale, des fonctionnalités avancées d'édition de code, de débogage et de gestion de projet.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://vscodium.com/#install" style="margin-right:25px; margin-left:25px">Windows</a> <a href="https://vscodium.com/#install" style="margin-right:25px;">MacOs</a> <a href="https://vscodium.com/#install" style="margin-right:25px;">Linux</a> </div> </div> <div id="cat"> <h4>Framapad</h4> <p>Framapad est un éditeur de texte collaboratif en ligne open source qui permet à plusieurs utilisateurs de travailler sur un même document en temps réel. Il est basé sur la technologie de l'éditeur de texte en ligne Etherpad, mais est hébergé et géré par l'association française Framasoft.</p> <div id="link" style="display:flex; flex-flow: row wrap; border-top:1px dotted; padding-top:5px;"> <p style="margin:-2px 0 0 0; font-size:0.4em; font-family:DRegular;">(Téléchargement)</p> <a href="https://framapad.org/abc/fr/" style="margin-right:25px; margin-left:25px">(En Ligne)</a> </div> </div> </div> <!-- <div id="menuicon" onclick="toggleDivs()"><a>MENU</a></div> <section id="menu-mobile" href="#"> <h1 style="margin-top:25px; text-align: center; font-size:32px;">Menu</h1> <a href="/annuaire.html">Annuaire format</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> <div id="close" onclick="toggleDivs()">Fermer le menu</div> </section> <section id="menu-ordi"> <a href="/annuaire.html">Annuaire Textuel</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> </section> </div> --> </body> </html><!DOCTYPE html> <html> <head> <title>GraphikLinux</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="leaflet.css" /> <script src="leaflet/leaflet-src.js"></script> <script src="leaflet/leaflet-src.js.map"></script> <script src="action.js"></script> </head> <body> <header> <h1 style="justify-content:center; text-align: center; margin:10px 0 10px 0">Open Graphisme</h1> <nav> <ul style="display: flex; list-style: none; margin: 0; padding: 0;"> <li style="margin-right: 25px;"><a href="index.html">[Accueil]</a></li> <li style="margin-right: 25px;"><a href="logiciels.html">[Logiciels]</a></li> <li style="margin-right: 25px;"><a href="ressources.html">[Ressources Graphiques]</a></li> <li style="margin-right: 25px;"><a href="linux.html">[Distribution Linux]</a></li> <li><a href="informations.html">[Informations]</a></li> </ul> </nav> </header> <div id="table"> <div id="texte-menu" style="width:25vw;"><a href="#typographie">[Typothèques]</a></div> <div id="texte-menu" style="width:25vw;"><a href="#images" style="">[Images]</a></div> <div id="texte-menu" style="width:25vw;"><a href="#vecteurs">[Vecteurs]</a></div> <div id="texte-menu" style="width:25vw;"><a href="#couleurs">[Couleurs]</a></div> </div> <div id="content" style="height:calc(100vh - 105px);"> <div class="grid"> <div class="grid-item"> <h3>Typothèques</h3> <div id="cat"> <h4>Fonderie.Download</h4> <p>Une fonderie sous license WTFPL anonyme gérée par des français</p> <a href="https://fonderie.download/" target="_blank">→&nbsp;https://fonderie.download/</a> </div> <div id="cat"> <h4>Velvetyne</h4> <p>Une fonderie libre française active depuis 2010 initié par Frank Adebiaye</p> <a href="https://velvetyne.fr" target="_blank">→&nbsp;https://velvetyne.fr/</a> </div> <div id="cat"> <h4>OSP Foundry</h4> <p>La branche fonderie du projet d'Open Source Publishing</p> <a href="http://osp.kitchen/foundry/" target="_blank">→&nbsp;http://osp.kitchen/foundry/</a> </div> <div id="cat"> <h4>The League of Moveable Type</h4> <p>Probablement la première typothèque libre, et ceux depuis 2009 dans l'idée d'augmenter le nombre de typographies utilisable sur le web </p> <a href="https://www.theleagueofmoveabletype.com/" target="_blank">→&nbsp;https://www.theleagueofmoveabletype.com/</a> </div> <div id="cat"> <h4>Tunera</h4> <p>Fondé en 2020 par Ariel Martín Pérez et rejoint par la suite par Anton Moglia</p> <a href="https://www.tunera.xyz/" target="_blank">→&nbsp;https://www.theleagueofmoveabletype.com/</a> </div> <div id="cat"> <h4>Omnibus Type</h4> <p>Une collection de typographies, beaucoup de polices variables</p> <a href="https://www.omnibus-type.com/" target="_blank">→&nbsp;https://www.omnibus-type.com/</a> </div> <div id="cat"> <h4>DeathOfTypography</h4> <p>Une plateforme regroupant le travail de plusieurs typographes</p> <a href="https://deathoftypography.com/typefaces/" target="_blank">→&nbsp;https://deathoftypography.com/typefaces/</a> </div> <div id="cat"> <h4>Badass Libre Fonts</h4> <p>Une collection de typographies libres déssinée par des femmes, actif depuis 2018</p> <a href="https://www.design-research.be/by-womxn/" target="_blank">→&nbsp;https://www.design-research.be/by-womxn/</a> </div> <div id="cat"> <h4>Berzulis</h4> <p>Une fonderie expérimental créer par le Studio Cryo sous Open Font License avec une spécialité dans les alphabets et la mythologie Lithuanienne</p> <a href="https://berzulis.com/" target="_blank">→&nbsp;https://berzulis.com/</a> </div> <div id="cat"> <h4>Luuse</h4> <p>Une typothèque fonctionnant sous Free Font Library, un outil développé par Luuse eux-mêmes.</p> <a href="https://typotheque.luuse.fun/" target="_blank">→&nbsp;https://typotheque.luuse.fun/</a> </div> <div id="cat"> <h4>Fond de Riz</h4> <p>Une typothèque évolutive sous la direction de Justine Gagnaire, Marie Deloffre et Cédric Rossignol-Brunet</p> <a href="http://fonderiz.fr/" target="_blank">→&nbsp;"http://fonderiz.fr/</a> </div> <div id="cat"> <h4>Typothèque du 75</h4> <p>La typothèque de l'école Belge du 75 développé avec Free Font Library</p> <a href="http://typotheque.le75.be/" target="_blank">→&nbsp;http://typotheque.le75.be/</a> </div> <div id="cat"> <h4>Bye Bye Binary</h4> <p>Cette typothèque présente des fontes inclusif·ves, non-binaires, post-binaires en construction. Ces fontes utilisent læ Queer Unicode Initiative (QUNI) pour encoder leurs glyphes inclusif·ves et rendre leur utilisation compatible.</p> <a href="https://typotheque.genderfluid.space/" target="_blank">→&nbsp;https://typotheque.genderfluid.space/</a> </div> </div> <div class="grid-item"> <h3>Images</h3> <div id="cat"> <h4>OpenClipArt</h4> <p>Un projet actif depuis 2004 permettant de regrouper et partager des images/vecteurs/illustrations complétement libre d'utilisation.</p> <a href="https://openclipart.org/" target="_blank">→&nbsp;https://openclipart.org/</a> </div> <div id="cat"> <h4>Wikipedia Commons</h4> <p>La collection d'image libre de droit de Wikipédia</p> <a href="https://commons.wikimedia.org/wiki/Main_Page" target="_blank">→&nbsp;https://commons.wikimedia.org/</a> </div> <div id="cat"> <h4>Pixabay</h4> <p>Un catalogue de plus de 2.8Md d'image stock gratuites</p> <a href="https://pixabay.com/" target="_blank">→&nbsp;https://pixabay.com/</a> </div> <div id="cat"> <h4>Unsplash</h4> <p>Une plateforme de partage d'images de haute résolution grauite. De très bonnes photographies.</p> <a href="https://unsplash.com/" target="_blank">→&nbsp;https://unsplash.com/</a> </div> <div id="cat"> <h4>Pexels</h4> <p>Collection d'images et de vidéos libres de droits.</p> <a href="https://www.pexels.com/" target="_blank">→&nbsp;https://www.pexels.com/</a> </div> <div id="cat"> <h4>Burst</h4> <p>Des images stocks pour des sites-web et du contenu commercial</p> <a href="https://burst.shopify.com/" target="_blank">→&nbsp;https://burst.shopify.com/</a> </div> <div id="cat"> <h4> Stock.io</h4> <p>Aucun copyrights pour ces stocks photos</p> <a href="https://stocksnap.io/" target="_blank">→&nbsp;https://stocksnap.io/</a> </div> <div id="cat"> <h4>Toutes les images sous license Créative Commons du réseaux Flickr</h4> <p>Velvetyne est un super truc</p> <a href="https://www.flickr.com/creativecommons/" target="_blank">→&nbsp;https://www.flickr.com/creativecommons/</a> </div> </div> <div class="grid-item"> <h3>Vectors</h3> <div id="cat"> <h4>Font Awesome</h4> <p>Plus de 1700 icons gratuites, possibilité d'avoir un abonnement premium</p> <a href="https://fontawesome.com/icons" target="_blank">→&nbsp;https://fontawesome.com/icons</a> </div> <div id="cat"> <h4>Feather Icons</h4> <p>Une collection d'icons Open-Source</p> <a href="https://feathericons.com/" target="_blank">→&nbsp;https://feathericons.com/</a> </div> <div id="cat"> <h4>Ionic</h4> <p>Plusieurs familles d'icons en Open-Source</p> <a href="https://ionic.io/ionicons/" target="_blank">→&nbsp;https://ionic.io/ionicons/</a> </div> <div id="cat"> <h4>Simple Icons</h4> <p>2500 SVG totalement gratuit</p> <a href="https://simpleicons.org/" target="_blank">→&nbsp;https://simpleicons.org/</a> </div> <div id="cat"> <h4>The Noun Project</h4> <p>Un très large choix d'icons en plusieurs formats. Une grande partie gratuite.</p> <a href="https://thenounproject.com/" target="_blank">→&nbsp;https://thenounproject.com/</a> </div> <div id="cat"> <h4>SVG Backgrounds</h4> <p>Un site web permettant de générer des fonds en SVG pour vos sites-web</p> <a href="https://www.svgbackgrounds.com/" target="_blank">→&nbsp;https://www.svgbackgrounds.com/</a> </div> </div> <div class="grid-item"> <h3>Colors</h3> <div id="cat"> <h4>Open Color</h4> <p>Un système de couleur pensé pour l'UI design complétement en Open-Source</p> <a href="https://yeun.github.io/open-color/" target="_blank">→&nbsp;https://yeun.github.io/open-color/</a> </div> <div id="cat"> <h4>Flat UI Colors</h4> <p>Une collection de palettes de couleurs pensée pour le flat design</p> <a href="https://flatuicolors.com/" target="_blank">→&nbsp;https://flatuicolors.com/</a> </div> <div id="cat"> <h4>Coolors</h4> <p>Un super générateur de palettes de couleurs. Beaucoup d'options disponibles</p> <a href="https://coolors.co/" target="_blank">→&nbsp;https://coolors.co/</a> </div> <div id="cat"> <h4>ColorHunt</h4> <p>Une collection de palettes de couleurs</p> <a href="https://colorhunt.co/" target="_blank">→&nbsp;https://colorhunt.co/</a> </div> </div> </div> <!-- <div id="menuicon" onclick="toggleDivs()"><a>MENU</a></div> <section id="menu-mobile" href="#"> <h1 style="margin-top:25px; text-align: center; font-size:32px;">Menu</h1> <a href="/annuaire.html">Annuaire format</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> <div id="close" onclick="toggleDivs()">Fermer le menu</div> </section> <section id="menu-ordi"> <a href="/annuaire.html">Annuaire Textuel</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> </section> </div> --> </body> </html><!DOCTYPE html> <html> <head> <title>Carte de Cambrai</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="action.js"></script> <link rel="stylesheet" href="leaflet.css" /> </head> <body> <div id="footer"> <div id="footer-text"> <h1>Cartographie</h1> <h2>des ressources de Cambrai</h2> </div> <div id="menuicon" onclick="toggleDivs()"><a>MENU</a></div> <section id="menu-mobile"> <h1 style="margin-top:25px; text-align: center; font-size:32px;">Menu</h1> <a href="/annuaire.html">Annuaire format</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> <div id="close" onclick="toggleDivs2()">Fermer le menu</div> </section> <section id="menu-ordi"> <a href="/annuaire.html">Annuaire Textuel</a> <a href="https://atlas-ata.fr/" target="_blank">Cartographie de ATA</a> <a href="https://docs.google.com/document/d/1ox2-WUEOpu7dM-vypXTfgx_KhlcOKvBR9Ks5bpToENU/edit?usp=sharing" target="_blank">Proposer un lieu</a> </section> </div> <div id="contenting"> <div class="grid"> <div class="grid-item"> <h3>Lieux de Culture</h3> <div id="cat"> <h4>Musée des beaux arts de Cambrai</h4> <p>15 Rue de l'Épée</p> <p>59400 Cambrai</p> <p>0327822790</p> </div> <div id="cat"> <h4>Le Labo</h4> <p>2 Rue Louis Renard, 59400 Cambrai</p> <p>0374510000</p> <p><a href="https://www.lelabocambrai.fr/" target="_blank">lelabocambrai.fr</a></p> </div> <div id="cat"> <h4>Théâtre de Cambrai</h4> <p>1 Rue du Temple</p> <p>0327729500</p> <p><a href="http://www.scenes-mitoyennes.fr/" target="_blank">scenes-mitoyennes.fr</a></p> </div> <div id="cat"> <h4>Centre Régional de la Photographie</h4> <p>Place des Nations</p> <p>59282 Douchy-les-Mines</p> <p>0327435650</p> <p><a href="https://crp.photo/" target="_blank">crp.photo</a></p> </div> <div id="cat"> <h4>Abbaye de Vaucelles</h4> <p>Hammeau de Vaucelles, 59258 Les Rues-des-Vignes</p> <p>0359731498</p> <p><a href="https://abbayedevaucelles.fr/" target="_blank">abbayedevaucelles.fr</a></p> </div> <div id="cat"> <h4>Archéo’site — Les Rues-des-Vignes</h4> <p>>82 Rue Haute</p> <p>59258 Les Rues-des-Vignes</p> <p>0970211746</p> <p><a href="https://www.archeosite-ruesdesvignes.fr/" target="_blank">archeosite-ruesdesvignes.fr</a></p> </div> <div id="cat"> <h4>Musée Matisse — Le Cateau-Cambresis</h4> <p>Palais, Rue Fénelon</p> <p>59360 Le Cateau-Cambrésis</p> <p>0359733800</p> <p><a href="https://museematisse.fr/" target="_blank">museematisse.fr</a></p> </div> <div id="cat"> <h4>Médiathèque de l’Escaut</h4> <p>2 Rue de la Paix</p> <p>59267 Proville</p> <p>0327707487</p> <p><a href="https://www.mediathequedelescaut.fr/" target="_blank">mediathequedelescaut.fr</a></p> </div> </div> <div class="grid-item"> <h3>Ressources Artistes</h3> <div id="cat"> <h4>La Malterie</h4> <p>42 Rue Kuhlmann</p> <p>59800 Lille</p> <p>0320151321</p> <p><a href="http://www.lamalterie.com/" target="_blank">lamalterie.com</a></p> </div> <div id="cat"> <h4>La Chambre d'Eau</h4> <p>61 rue du moulin</p> <p>59550 Le Favril</p> <p>0327770926</p> <p><a href="http://www.lachambredeau.fr/" target="_blank">lachambredeau.fr</a></p> </div> <div id="cat"> <h4>L'H Du Siège</h4> <p>15 rue de l'Hôpital du Siège</p> <p>59300 Valenciennes</p> <p>0327770926</p> <p><a href="http://www.hdusiege.org/" target="_blank">hdusiege.org</a></p> </div> <div id="cat"> <h4>SMAC Service Mobile d'Animations Culturelles</h4> <p>Avenue des Potiers</p> <p>59500 Douai</p> <p>0777075009</p> <p><a href="http://smacasso.com/" target="_blank">smacasso.com</a></p> </div> <div id="cat"> <h4>Micro Atelier de Proville (Fablab)</h4> <p>2 Rue de la Paix</p> <p>59267 Proville</p> <p>0321707487</p> <p><a href="https://mediathequedelescaut.fr" target="_blank">mediathequedelescaut.fr</a></p> </div> </div> <div class="grid-item"> <h3>Collèges et lycées</h3> <div id="cat"> <h4>Collège et lycée Fénelon</h4> <p>Place François de Fénelon</p> <p>59400 Cambrai</p> <p>0327727777</p> <p><a href="http://lyc-fenelon.etab.ac-lille.fr/" target="_blank">lyc-fenelon.etab.ac-lille.fr</a></p> </div> <div id="cat"> <h4>Collège et lycée Paul Duez</h4> <p>1 Boulebard Paul Bezin</p> <p>59400 Cambrai</p> <p>0327730730</p> <p><a href="http://www.duez-bettignies.org/" target="_blank">duez-bettignies.org</a></p> </div> <div id="cat"> <h4>Collège Jules Ferry</h4> <p>4 Rue Mgr Guerry</p> <p>59400 Cambrai</p> <p>0327837615</p> <p><a href="https://jules-ferry-cambrai.enthdf.fr/" target="_blank">jules-ferry-cambrai.enthdf.fr</a></p> </div> <div id="cat"> <h4>Collège Lamartine</h4> <p>330 Rue Gauthier</p> <p>59400 Cambrai</p> <p>0327813317</p> <p><a href="https://lamartine-cambrai.enthdf.fr/" target="_blank">lamartine-cambrai.enthdf.fr</a></p> </div> <div id="cat"> <h4>Lycée professionnel Louise de Brettignies</h4> <p>3 Boulevard Paul Bezin</p> <p>59400 Cambrai</p> <p>0327730718</p> </div> <div id="cat"> <h4>Lycée professionnel Louis Blériot</h4> <p>Rue Gauthier</p> <p>59400 Cambrai</p> <p>0327722900</p> </div> </div> <div class="grid-item"> <h3>Matériaux</h3> <div id="cat"> <h4>Poterie du vieux </h4> <p>24 Boulebard Faidherbe</p> <p>59400 Cambrai</p> <p>0327784848</p> </div> <div id="cat"> <h4>Brico dépôt</h4> <p>1909 Avenue de Paris</p> <p> 59400 Cambrai</p> <p>0327700950</p> </div> <div id="cat"> <h4>Leroy Merlin</h4> <p>RN 30 Avenue Jean Jaurès</p> <p>59400 Cambrai</p> <p>0327215600</p> </div> <div id="cat"> <h4>Gamm Vert</h4> <p>54 Boulevard Jean Bart</p> <p>59400 Cambrai</p> <p>0327783511</p> </div> <div id="cat"> <h4>Bricomarché</h4> <p>1 Avenue de Paris</p> <p>59400 Cambrai</p> <p>0327783939</p> </div> <div id="cat"> <h4>Gedimat Bracq</h4> <p>Rue du champ de tir</p> <p>59400 Cambrai</p> <p>0327829600</p> </div> <div id="cat"> <h4>Point.P</h4> <p>140 Boulevard Faidherbe</p> <p>59400 Cambrai</p> <p>0327720404</p> </div> <div id="cat"> <h4>4Murs</h4> <p>Chemin de Marcoing</p> <p>59400 Cambrai</p> <p>0327811008</p> </div> <div id="cat"> <h4>Chantemur</h4> <p>Avenue de Paris</p> <p>59400 Cambrai</p> <p>0327749817</p> </div> <div id="cat"> <h4>Electro Dépôt</h4> <p>197 Avenue de Valenciennes</p> <p>59400 Cambrai</p> <p>0327707240</p> </div> </div> <div class="grid-item"> <h3>Librairies & papeteries</h3> <div id="cat"> <h4>Les Furets du Nord</h4> <p>22 Mail Saint-Martin</p> <p>59400 Cambrai</p> <p>0327813377</p> </div> <div id="cat"> <h4>Majuscule</h4> <p>14 Rue Henri de Lubac</p> <p>59400 Cambrai</p> <p>0327812554</p> <p><a href="https://www.majuscule-cambrai.com/SiteFront/" target="_blank">majuscule-cambrai.com</a></p> </div> <div id="cat"> <h4>Maison de la presse</h4> <p>1 Rue du Général de Gaulle</p> <p>59400 Cambrai</p> <p>0327812707</p> </div> <div id="cat"> <h4>Bureau Vallée</h4> <p>Aveue de Paris</p> <p>59400 Cambrai</p> <p>0327700009</p> </div> </div> <div class="grid-item"> <h3>Centre de loisirs</h3> <div id="cat"> <h4>Centre d’animation Éclipse</h4> <p>47 Avenue de Dunkerque</p> <p>59400 Cambrai</p> <p>0327822790</p> </div> <div id="cat"> <h4>Mission locale du Cambrésis</h4> <p>24 Boulebard Faidherbe</p> <p>59400 Cambrai</p> <p>0327784848</p> </div> <div id="cat"> <h4>Service Enfance Jeunesse de Cambrai</h4> <p>47 Avenue de Dunkerque</p> <p>0327812022</p> <p><a href="https://www.sejc.fr" target="_blank">sejc.fr</a></p> </div> <div id="cat"> <h4>R’Génération (Centre social)</h4> <p>Rue Raymond Gernez</p> <p>59400 Cambrai</p> <p>0327703813</p> </div> <div id="cat"> <h4>Espace de vie sociale Le Tipi</h4> <p>14 rue Lafayette</p> <p> 59400 Cambrai</p> <p>0327812022</p> <p><a href="https://www.sejc.fr" target="_blank">sejc.fr</a></p> </div> </div> <div class="grid-item"> <h3>Écoles et Facultés</h3> <div id="cat"> <h4>Ésac Cambrai</h4> <p>130 Allée Saint-Roch</p> <p>59400 Cambrai</p> <p>0327838142</p> <p><a href="http://www.esac-cambrai.net/" target="_blank">esac-cambrai.net</a></p> </div> <div id="cat"> <h4>UPHF</h4> <p>6 Rue de Rambouillet</p> <p>59400 Cambrai</p> <p>0327723300</p> <p><a href="http://www.centre-universitaire-cambrai.fr/" target="_blank">centre-universitaire-cambrai.fr</a></p> </div> </div> <div class="grid-item"> <h3>Santé et Social</h3> <div id="cat"> <h4>Résidence Crous</h4> <p>50A Allée Saint-Roch</p> <p>59400 Cambrai</p> </div> <div id="cat"> <h4>CAF</h4> <p>2 Rang Saint-Jean</p> <p>59400 Cambrai</p> </div> <div id="cat"> <h4>Planning familial</h4> <p>6 Rue du Maréchal de Lattre de Tassigny</p> <p>59400 Cambrai</p> <p>0327707059</p> <p><a href="http://planningfamilial59.org/" target="_blank">planningfamilial59.org</a></p> </div> <div id="cat"> <h4>Centre hospitalier</h4> <p>516 Avenue de Paris</p> <p>59400 Cambrai</p> <p>0327737373</p> <p><a href="http://www.ch-cambrai.fr/" target="_blank">ch-cambrai.fr</a></p> </div> </div> <div class="grid-item"> <h3>Emploi</h3> <div id="cat"> <h4>Pôle emploi</h4> <p>16 Rue du Colonel Francis Nicol</p> <p>59400 Cambrai</p> <p>0972723949</p> <p><a href="https://www.pole-emploi.fr/annuaire/" target="_blank">pole-emploi.fr/annuaire</a></p> </div> <div id="cat"> <h4>Cambresis Emploi</h4> <p>14 Rue Neuve</p> <p>59400 Cambrai</p> <p>0327700129</p> <p><a href="http://www.cambresisemploi.fr/" target="_blank">www.cambresisemploi.fr</a></p> </div> <div id="cat"> <h4>CCI Grand Hainaut</h4> <p>3 Avenue du Sénateur Girard</p> <p>59300 Valenciennes</p> <p>0327513513</p> <p><a href="https://hautsdefrance.cci.fr/cci-grand-hainaut/" target="_blank">hautsdefrance.cci.fr/cci-grand-hainaut/</a></p> </div> </div> <div class="grid-item"> <h3>Résidence / Lieu d'expo</h3> <div id="cat"> <h4>Modulo ateliers</h4> <p>48 rue Gambetta</p> <p>59540 Béthencourt</p> <p>0643858642</p> <p><a href="http://www.moduloatelier.com/" target="_blank">moduloatelier.com</a></p> </div> <div id="cat"> <h4>Frûctose</h4> <p>Rue du Magasin Général</p> <p>59378 Dunkerque</p> <p>0328645389</p> <p><a href="https://www.fructosefructose.fr/" target="_blank">fructosefructose.fr</a></p> </div> <div id="cat"> <h4>La Brasserie</h4> <p>5 Rue Basse</p> <p>62111 Foncquevillers</p> <p>0687915782</p> <p><a href="https://artbrasserie.com/" target="_blank">artbrasserie.com</a></p> </div> <div id="cat"> <h4>L'Œil du Chas</h4> <p>1 rue des Petits Viéziers</p> <p>62000 Arras</p> <p><a href="https://www.facebook.com/loeilduchas" target="_blank">facebook.com/loeilduchas</a></p> </div> </div> <div class="grid-item"> <h3>Autres</h3> <div id="cat"> <h4>Emmaüs</h4> <p>952 Route nationale</p> <p>59400 Fontaine-Notre-Dame</p> <p>0327781210</p> </div> <div id="cat"> <h4>Office du tourisme</h4> <p>48 Rue Henri de Lubac</p> <p>59400 Cambrai</p> <p>0327783615</p> <p><a href="http://www.tourisme-cambresis.fr/" target="_blank">tourisme-cambresis.fr</a></p> </div> </div> </div> </body> </html><!DOCTYPE html PUBLIC> <html lang="en"> <head> <link href="data:image/x-icon;base64,AAABAAEAEBAQAAAAAAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAsC8qAP+EAACzh1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACAAAAAAAAACAAAAAAAAEiAAAAADAAAiAAAAAAMzAiAAAAAAAAMzAAAAAAAAAiMzMAAAAAAAADAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA" rel="icon" type="image/x-icon" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta content="width=device-width, initial-scale=1" name="viewport"> <title>Mémoire</title> <script type="module" src="/Memoire/pagedjs/script.js"></script> <link href="/Memoire/pagedjs/css/reset.css" rel="stylesheet" type="text/css"> <link href="/Memoire/pagedjs/css/interface/header.css" rel="stylesheet" type="text/css"> <link id="style-screen" href="/Memoire/src/css/style-screen.css" rel="stylesheet" type="text/css"> </head> <body id="screen-page"> </body> </html><!DOCTYPE html PUBLIC> <html lang="fr"> <head> <link href="data:image/x-icon;base64,AAABAAEAEBAQAAAAAAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAsC8qAP+EAACzh1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAACAAAAAAAAACAAAAAAAAEiAAAAADAAAiAAAAAAMzAiAAAAAAAAMzAAAAAAAAAiMzMAAAAAAAADAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA" rel="icon" type="image/x-icon" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta content="width=device-width, initial-scale=1" name="viewport"> <title>Mémoire</title> <script type="module" src="/Memoire/pagedjs/script.js"></script> <link href="/Memoire/pagedjs/css/reset.css" rel="stylesheet" type="text/css"> <link href="/Memoire/pagedjs/css/pagedjs.css" rel="stylesheet" type="text/css"> </head> <body id="print-page"> </body> </html><!-- your CONTENT here --> <!-- COUVERTURE --> <section id="cover"> <pre style="font-size:11px; line-height:16px; margin-top:35%; margin-left:0; text-shadow: none; color:black;"> ██╗ ██╗███████╗██████╗ ███████╗ ██╗ █████╗ ██║ ██║██╔════╝██╔══██╗██╔════╝ ██║ ██╔══██╗ ██║ ██║█████╗ ██████╔╝███████╗ ██║ ███████║ ╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║ ██║ ██╔══██║ ╚████╔╝ ███████╗██║ ██║███████║ ███████╗██║ ██║ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚══════╝╚═╝ ╚═╝ ███████╗ ██████╗ ██████╗ ██████╗ ██╗███████╗████████╗███████╗ ██╔════╝██╔═══██╗██╔══██╗██╔══██╗██║██╔════╝╚══██╔══╝██╔════╝ ███████╗██║ ██║██████╔╝██████╔╝██║█████╗ ██║ █████╗ ╚════██║██║ ██║██╔══██╗██╔══██╗██║██╔══╝ ██║ ██╔══╝ ███████║╚██████╔╝██████╔╝██║ ██║██║███████╗ ██║ ███████╗ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚══════╝ ╚═╝ ╚══════╝ ███╗ ██╗██╗ ██╗███╗ ███╗███████╗██████╗ ██╗ ██████╗ ██╗ ██╗███████╗ ████╗ ██║██║ ██║████╗ ████║██╔════╝██╔══██╗██║██╔═══██╗██║ ██║██╔════╝ ██╔██╗ ██║██║ ██║██╔████╔██║█████╗ ██████╔╝██║██║ ██║██║ ██║█████╗ ██║╚██╗██║██║ ██║██║╚██╔╝██║██╔══╝ ██╔══██╗██║██║▄▄ ██║██║ ██║██╔══╝ ██║ ╚████║╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║██║╚██████╔╝╚██████╔╝███████╗ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝ </pre> <h1>Vers la sobriété numérique</h1> <h2 id="author" style="font-family:Pixel;font-size:14px; text-align:center;">Mémoire de DNSEP&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Anaël LE GALL&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;2022/2023</h2> <br><br> </section> <!-- PREMIÈRE PAGE --> <section id="première-page"> <h1>Vers la sobriété numérique</h1> <h2>par Anaël Le Gall</h2> </section> <div id="first-texte"> <p>Mémoire de DNSEP<br> École supérieure d’art et de communication de Cambrai<br> Année 2022-2023<br><br> Mémoire suivi par Keyvane Alinaghi</p> <p style="font-family:Pixel; font-size:0.5em;">Les opinions exprimées dans ce mémoire de DNSEP n’engagent que leur auteur et en aucun cas l’École supérieure d’art et de communication de Cambrai.</p> </div> <div class="pagebreak"></div> <!-- SOMMAIRE PRINT --> <section id="Sommaire"> <div class="container"> <div class="col-1"> <h3>Introduction - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -</h3><br> <p>Mon rapport au numérique <br> La place croissante du numérique dans nos vies <br> Enjeux environnementaux du numérique</p><br><br><br> <h3>Un espace web capitalisé - - - - - - - - - - - - - - - - - - - - - - - - - - - -</h3><br> <p>Chronologie du Web<br> Capitalisation de l’attention<br> Le tracking, une pratique polluante<br> L’impact de la décentralisation<br> Format des médias numériques</p><br><br><br> <h3>Vers un design Low-Tech - - - - - - - - - - - - - - - - - - - - - - - - - - - - - </h3><br> <p>Un monde aux ressources limitées<br> Définition des low-techs<br> Slow-Web<br> Webdesign Low-tech / Sobriété Numérique</p><br><br><br> <h3>L’open source comme modèle écologique - - - - - - - - - - - - - - - - - - </h3><br> <p>Définition de l’open source<br> Do-It-Yourself et contre-pouvoir<br> L’open-source comme moyen d’émancipation<br> Monopole du logiciel créatif<br> Graphismes et Open-Source</p><br><br><br> <h3>Conclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - </h3><br><br><br> <h3>Bibliographie - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - </h3> </div> <div class="col-2"> <p style="margin-bottom:144px;"> 03-06 </p> <p style="margin-bottom:180px;"> 07-14</p> <p style="margin-bottom:162px;"> 15-22</p> <p style="margin-bottom:180px;"> 23-34</p> <p style="margin-bottom:54px;"> 35-42</p> <p> 43-45 </p> </div> </div> </section> <!-- SOMMAIRE SCREEN --> <section id="Sommaire-Screen"> <div class="grid-screen"> <div class="grid-sommaire"> <a href="#Introduction"><h3>Introduction</h3></a> <p>Mon rapport au numérique / La place croissante du numérique dans nos vies / Enjeux environnementaux du numérique</p> <a href="#un-espace-web-capitalisé"><h3>Un espace web capitalisé</h3></a> <p>Chronologie du Web / Capitalisation de l’attention / Le tracking, une pratique polluante / L’impact de la décentralisation / Format des médias numériques</p> <a href="#Vers-un-design-low-tech"><h3>Vers un design Low-Tech</h3></a> <p>Un monde aux ressources limitées / Définition des low-techs / Slow-Web / Webdesign Low-tech / Sobriété Numérique</p> <a href="#Open-source-comme-modèle-écologique"><h3>L’open source comme modèle écologique</h3></a> <p>Définition de l’open source / Do-It-Yourself et contre-pouvoir / L’open-source comme moyen d’émancipation / Monopole du logiciel créatif / Graphismes et Open-Source</p> <a href="#Conclusion"><h3>Conclusion</h3><br></a> <a href="#Bibliographie"><h3>Bibliographie</h3></a> </div> <div class="grid-colophon"> <h3>Mémoire de DNSEP</h3><br> <p>École supérieure d’art et de communication de Cambrai<br> Année 2022-2023<br> Mémoire suivi par <a href="http://faceboobs.org/web/" target="_blank">Keyvane Alinaghi</a></p> <br> <p>Un grand merci à lui qui m’a aidé et supporté tout au long de ce mémoire. Merci à Caroline Tron-Carroz et Stéphanie Mahieu pour avoir déniché les (très) nombreuses coquilles et fautes d’orthographes. Merci également à Gauthier Roussilhe et Roel Roscam Abbing pour les documents et informations qu’ils m’ont fournit. Enfin, merci à Line Celo pour ses conseils avisés sur la mise en page de ce mémoire.</p> <br><br> <h2>Brizeux </h2> <p>Designé par Véfa Lucas et Roman Seban, Développé par Dreams Office <br>(Libre d’utilisation)</p> <h2>Px Sans Nouveau</h2> <p>Designé par Elvis Mehmedović <br>(Libre d’utilisation)</p> </div> </div> </div> </section> <section id="Introduction" class="chapter" data-chapter="1" style="break-before:avoid"> <div class="pagebreak"></div> <h1 style="margin-top:0; border-top:none;">Introduction</h1> <h5><pre style="font-size:14px; line-height:17px"> ██╗███╗ ██╗████████╗██████╗ ██████╗ ██║████╗ ██║╚══██╔══╝██╔══██╗██╔═══██╗ ██║██╔██╗ ██║ ██║ ██████╔╝██║ ██║█████╗ ██║██║╚██╗██║ ██║ ██╔══██╗██║ ██║╚════╝ ██║██║ ╚████║ ██║ ██║ ██║╚██████╔╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ██████╗ ██╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗ ██╔══██╗██║ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║ ██║ ██║██║ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║ ██║ ██║██║ ██║██║ ██║ ██║██║ ██║██║╚██╗██║ ██████╔╝╚██████╔╝╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝</pre></h5> <pre style="font-size:12px; line-height:16px; color:black; text-shadow:none; margin-top: 125px" > H|| __________H||___________ [|.......................| ||.........## --.#.......| ||......... # # ......| @@@@ ||......... * ......| @@@@@@@ ||........ -^........| , - @@@@ ||.....##\ .......| | ‘_ @@@ ||....##### /###.....| | __\@ \@ ||....########\ \((#.....| _\\ (/ ) @\_/)____ ||..####, ))/ ##.......| |(__/ / /|% #/ ||..##### ‘####.....| \___/ ----/_|-*/ ||..#####\____/#####.....| ,: ‘( ||...######..######......| |: \ ||.....»»»» «»»» ... | |: ) [|_______________________| |: | H||_______H|| |_____,_| H||________\| | / ( H|| H|| | /\ ) H|| H|| ( \| / _H||_______H||__ | /’=. H|________________| ‘=>/ \ / \ /|/ ,___/| </pre> <div class="Texte-chapitre"> <pre> #===============================# = = = - Mon rapport au = = numérique = = = = - La place croissante du = = numérique dans nos vies = = = = - Enjeux environnementaux = = du numérique = = = #===============================# </pre> </div> <div class="pagebreak"></div> <h2>Mon rapport au numérique</h2> <p>Issu de la génération qui a toujours connu internet, j’ai pu suivre son évolution depuis mon enfance. Bloqué au fin fond de ma campagne bretonne, je découvrais la possibilité d’accéder à des informations issues de partout dans le monde et de communiquer sans barrière géographique. C’était l’époque des plateformes d’échange de fichiers eMule, de LimeWire<sup>1</sup> et des débuts de YouTube avant l’expansion du web participatif et de son système de monétisation de la donnée. Internet apparaissait ainsi comme un espace de liberté et d’échange sans frontières.</p> <p> C’est au même endroit que j’ai fait mes premiers pas dans le monde du graphisme. Via le jeu vidéo en ligne (et internet), univers pour lequel j’ai commencé par faire des logos et des fonds d’écrans pour les personnes avec qui je jouais ou parlais, comme pour affirmer un symbole d’appartenance à une communauté ou à une équipe. J’investiguais également les premiers blogs Tumblr et comptes Soundcloud dans lesquels nous partagions musiques, visuels et photos. Mon premier rapport à l’image (étant) a été numérique avant qu’il ne s’étende aux médias imprimés et autres supports liés au design graphique.</p> <br><h2>La place croissante du numérique dans nos vies</h2> <p>Le numérique est inextricable de ma pratique. La majorité des outils de création que j’utilise sont digitaux. C’est également mon moyen de communication privilégié (que ce soit ma boîte mail ou mes réseaux sociaux), un espace de publication, une source d’informations et un espace de stockage.</p> <p>Ne se limitant pas à l’image, ni aux contenus culturels, le numérique est devenu omniprésent et s’est largement globalisé dans mon quotidien et celui des autres. Les outils du numérique bouleversent ainsi nos habitudes de consommation, nos relations sociales et nos moyens de communication. Les grands acteurs de ce milieu comme Google ou Amazon sont devenus en quelques années les piliers de l’économie mondiale en proposant des applications dites gratuites à l’utilisateur. Des plateformes de partage de photos, vidéos, des espaces mails ou de communication sont mises à disposition contre l’utilisation et la revente implicite de nos données personnelles.</p> <p>Tout se digitalise ou se lie au numérique. Les objets de notre quotidien deviennent “connectés”, des frigos, aux casques de vélo en passant par les montres. Les médias traditionnels et les formes de communication qui en découlent ont muté vers des équivalents numériques. En témoigne mon expérience d’étudiant en école d’art, dans laquelle une grande majorité des ateliers (photo, vidéo, graphisme, illustration, son) se déroule derrière un ordinateur.</p> <p>Le numérique est devenu presque invasif, addictif, ouvrir son téléphone un geste compulsif. Malgré une constante évolution technique et les nouvelles possibilités offertes par ses services, Internet n’a plus la même saveur. Les contenus proposés se sont aseptisés, la publicité y est de plus en plus présente et mute constamment (des bannières publicitaires sur les anciens sites web, aujourd’hui ce sont des vidéos qui se lancent automatiquement avec des contenus sponsorisés par des marques qui, parfois se mêlent au réel et créent un flou entre une proposition artistique et un produit à vendre). Si, au cours de mon adolescence, je voyais Internet comme un espace de liberté et d’échanges raisonnés, il m’apparaît aujourd’hui comme un vaste espace où je me perds entre une infinité de contenus éphémères à l’affût d’une petite dose de dopamine.</p> <div class="footnote"> 1 - Logiciel de Peer-to-Peer. Des systèmes d’échanges où l’ordinateur de chacun sert de serveur pour envoyer des fichiers </div> <div class="pagebreak"></div> <br><h2>Enjeux environnementaux du numérique</h2> <p>À une époque où les problèmes environnementaux sont au cœur des débats, mettant bien souvent en cause nos comportements et notre consommation, il semble intéressant de penser l’impact de notre production et de nos échanges immodérés de données digitales.</p> <p>Existe-t-il des solutions numériques ou des attitudes à adopter en réponse aux problématiques environnementales actuelles ? Les métiers du design peuvent-ils proposer des solutions numériques durables, plus saines tout en restant dans un modèle de performance technologique ?</p> <p>Pour tenter d’y répondre, il est intéressant de commencer par faire un état des lieux de notre environnement numérique, des différents acteurs qu’il comporte, afin de pouvoir en déduire les problématiques et de présenter les leviers d’action à notre disposition.</p </section> <div class="pagebreak"></div> <section id="un-espace-web-capitalisé" class="chapter" data-chapter="2"> <div id="appel"> <h1>Un espace web capitalisé</h1> <h5><pre style="font-size:12px; line-height:16px"> ██╗ ██╗███╗ ██╗ ███████╗███████╗██████╗ █████╗ ██████╗███████╗ ██║ ██║████╗ ██║ ██╔════╝██╔════╝██╔══██╗██╔══██╗██╔════╝██╔════╝ ██║ ██║██╔██╗ ██║ █████╗ ███████╗██████╔╝███████║██║ █████╗ ██║ ██║██║╚██╗██║ ██╔══╝ ╚════██║██╔═══╝ ██╔══██║██║ ██╔══╝ ╚██████╔╝██║ ╚████║ ███████╗███████║██║ ██║ ██║╚██████╗███████╗ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ ██╗ ██╗███████╗██████╗ ██║ ██║██╔════╝██╔══██╗ ██║ █╗ ██║█████╗ ██████╔╝ ██║███╗██║██╔══╝ ██╔══██╗ ╚███╔███╔╝███████╗██████╔╝ ╚══╝╚══╝ ╚══════╝╚═════╝ ██████╗ █████╗ ██████╗ ██╗████████╗ █████╗ ██╗ ██╗███████╗███████╗ ██╔════╝██╔══██╗██╔══██╗██║╚══██╔══╝██╔══██╗██║ ██║██╔════╝██╔════╝ ██║ ███████║██████╔╝██║ ██║ ███████║██║ ██║███████╗█████╗ ██║ ██╔══██║██╔═══╝ ██║ ██║ ██╔══██║██║ ██║╚════██║██╔══╝ ╚██████╗██║ ██║██║ ██║ ██║ ██║ ██║███████╗██║███████║███████╗ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝╚══════╝╚══════╝</pre> </h5> <pre style="text-shadow:none; color:black"> __, ,__ // \\ / L/| |\J | | / \ | ,/^| ,~-_,--`, |^\ / /\| / \, ||\\~, / //\\ / ,\,./’;. `, || \\ ~, / // \\ | (~Q’Q~’; ; ,// \\ ~. ,/ // \\ (, \ ^_, / //’ \\ ~-. / //’ \`,.__\_`--’ \,/,’L `\\ \. ,/ // `~---/ // \. `\\ \, / ,/’ | |\, \. `:, \ | ;; !/ `-_ ,`-_ \_, \`, :, | || ( ,: )/\. `. / || | | |! / `-- `--’/ \,/ / !| :, ,; ,;’ ; /\ < / /’ ‘:, | | || / ;/ ) \,-’ /\ || | | || / ./; /_ , _{=_.’ | __ || :, | || __ ; /_/ |--:==:--»\ |/ \ || | | || / \| ( / \ / | \ || | | |! / | ,] | | / \ \ |! | ,; ,;’ __ | \L, | \ | \ | ,;; | | || / \ | \ | / | | __|! | | ||/ \| \ \ | | |/ ,;; | | || \ \| | !; ; | :: <\ («\| /\( ,:’ / : \\ \ ` \.: i\, || / \ \\ | | `, | `-_ ;! / \ || | ,/ |` |_, `-_ ‘.\ / \|! / / \ | `-_ `-__\\ / :; / /_ _) ! `-_____\\|-, / / ,--~ \. \ \|-,\ ,-_/ / ; \ \ \\ _--, | | \_ |: (---, / :,; `,_) /-’ (--’ ‘ \,] ‘ by Valkyrie</pre> </div> <div class="Texte-chapitre"> <pre> #===============================# = = = - Chronologie du Web = = = = - Capitalisation de = = l’attention = = = = - Le tracking, = = une pratique polluante = = = = - L’impact de la = = décentralisation = = = = - Format des médias = = numériques = = = = - Centralisation autour = = de quelques acteurs = = = #===============================#</pre> </div> <div class="pagebreak"></div> <h2>Chronologie du Web</h2> <p>Dans la brève histoire de l’internet, le web<sup>2</sup> s’est construit en trois temps. Tout d’abord, le web 1.0, apparu au début des années 1990 et allant jusqu’à la moitié des années 2000, ne permet qu’une lecture de contenus et la création de pages statiques. Il est utilisé pour éditer et publier des informations et le lecteur n’a que très peu de moyens d’interagir avec. Ensuite, avec le développement du web 2.0, l’utilisateur est devenu l’acteur principal du réseau. Il échange sur de nouveaux espaces participatifs (IRC)<sup>3</sup>, des forums (Usenet)<sup>4</sup> et plus tard des réseaux sociaux. Les utilisateurs créent ensemble, partagent et s’emparent de la toile. Aujourd’hui, nous semblons nous projeter vers le web 3.0, un internet sémantique, décentralisé, organisé par modules et régi par la blockchain. L’idée de cette suite est de structurer les données des internautes et de les faire interagir pour les traiter de manière plus efficace.</p> <br><h2>Capitalisation de l’attention</h2> <p>La majorité des services participatifs qui font le web se rémunèrent grâce aux mécanismes de l’économie de l’attention. L’objectif est de capter et de fidéliser leurs utilisateurs et ainsi d’augmenter leur temps passé sur les plateformes. Les notifications envoyées par les applications de réseaux sociaux ou de streaming se multiplient pour cultiver l’addiction à ses services<sup>5</sup>. Leurs algorithmes privilégient la régularité de publication des internautes auteurs pour offrir un meilleur référencement, une meilleure visibilité ou des récompenses virtuelles. De plus, la lecture sans fin (scroll infini) des publications est devenue une norme, tout comme les playlists audiovisuelles automatisées, pour nous maintenir dans ce flot continuel de contenus. De manière opaque, ces différents services analysent nos comportements afin d’afficher du contenu en fonction de nos goûts, mais également pour nous proposer une publicité ciblée, personnalisée, susceptible de nous intéresser, de nous maintenir captivés.</p> <p>Les conséquences écologiques de ce comportement de consommation numérique sont importantes. Nous consommons de manière frénétique des médias mixtes (photos, vidéos en haute définition)<sup>6</sup> plus lourds que du simple texte, ce qui augmente la consommation d’énergie globale liée au web. Cette consommation est également dû à un accès facilité à internet, un réseau plus rapide et quasiment accessible en illimité (démocratisation de la fibre, utilisation via les téléphones, prix des forfaits en baisse et augmentation des offres internet, même si certaines zones sont encore exclues). Cette activité croissante amène à un effet rebond. L’effet rebond est un paradoxe qui stipule que lorsqu’une énergie ou une matière première devient plus efficiente, sa consommation augmente au lieu de diminuer. Ce phénomène a été observé pendant la révolution industrielle sous le nom de Paradoxe de Jevons. La technologie a permis de rendre beaucoup plus efficace l’utilisation du charbon en diminuant de deux tiers sa consommation pour une unité de fer produite, mais au lieu d’une diminution globale de la consommation de charbon, son utilisation a été multiplié par dix. L’impact environnemental du numérique représente 5% à 10% de la consommation mondiale d’électricité, ce chiffre augmentant chaque année. Il est donc urgent de définir nos besoins réels en termes d’usages et de trouver des solutions moins exigeantes en ressources, qui sont aujourd’hui majoritairement issues de matériaux non renouvelables.</p> <div class="footnote"> 2 - Le Web est le terme communément employé pour parler du World Wide Web, ou WWW, traduit en français par la toile d’araignée mondiale. Il fait référence au système hypertexte fonctionnant sur le réseau informatique mondial Internet.<br> 3 - Internet Relay Chat (ou IRC) est un protocole de communication textuel sur Internet. Il sert à la communication instantanée sous la forme de discussions en groupe par l’intermédiaire de canaux.<br> 4 - Usenet est un système en réseau de forums, inventé en 1979. C’est un ensemble de protocoles servant à générer, stocker et récupérer des « articles » (proche des email) et permet l’échange de ces articles<br> 5 - CITTON Yves, L’économie de l’attention / Nouvel horizon du capitalisme ?, Paris : Ed. La Découverte, 2014.<br> 6 - Rapport du Thinktank «The Shift Projects» sur les usages du numérique, notamment de la place majoritaire de la vidéo dans la transition de données. <br> </div> <div class="pagebreak"></div> <br><h2>Le tracking, une pratique polluante</h2> <p>Un autre facteur lié à l’économie de l’attention qui alourdit la note carbonne du numérique est l’utilisation des cookies. Pour faire simple, les cookies sont des petits documents textes qui sont générés par notre activité sur des sites web et qui sont stockés sur notre machine. Par exemple, si nous nous connectons à un site marchand que nous avons déjà consulté, il se peut que les éléments que nous avions mis dans notre panier apparaissent de nouveau. Ces informations sont lues par le site sur le cookie stocké sur notre ordinateur. Mais ces mêmes cookies, s’ils peuvent être d’ordre fonctionnel, sont aussi la base de la publicité ciblée. Ils stockent nos informations personnelles et nos habitudes de navigation pour être vendues à des services publicitaires. Ce fonctionnement opaque, que la plupart des utilisateurs ne conçoivent même pas, a des répercussions écologiques énormes en plus des problèmes de confidentialité et d’éthique dont il relève. Même s’il ne s’agit que de petits fichiers textes, leur nombre est astronomique.</p> <p>Le projet Carbolytics de Joana<sup>7</sup> Molls, nous permet d’avoir une visualisation de ce monde invisible. En additionnant tous les cookies présents sur le million de pages le plus visité d’Internet (qui représentent tout de même 1,295,345,405,057 visites), elle obtient le nombre astronomique de 197,359,398,267,217 cookies activés, pour une moyenne de 150 cookies déclenchés par visite. En prenant en compte ces chiffres, et en rappelant que cela ne représente que des visites sur des sites internet et non via des applications, l’utilisation mondiale de cookies est émettrice de près de 11558 tonnes de Co2 par mois. Néanmoins, ce chiffre ne doit servir qu’à émettre un ordre de grandeur. Le nombre de facteurs (matériel utilisé, constante évolution des pages internet, différence d’utilisation entre chaque utilisateur…) étant très large, il est quasiment impossible de calculer précisément ce chiffre.</p> <br><h2>L’impact de la décentralisation</h2> <p>L’externalisation de nos données informatiques dans le cloud est l’un des autres enjeux majeurs de cette réflexion. Les espaces de stockage de l’information sont des serveurs centralisés. Les principales dépenses énergétiques de ce système résident dans l’alimentation de milliers ou de millions de machines ainsi que leur refroidissement. Les serveurs sont aujourd’hui majoritairement rassemblés dans des datacenters, des infrastructures uniquement dédiées à l’hébergement de données. </p> <p>Pour l’industrie de la data (Amazon avec AWS, Microsoft avec Azure…), la notion d’optimisation est clé dans leur modèle économique étant donné que ce facteur se répercute directement sur leur rentabilité. Des plans de délocalisation des serveurs vers des régions froides du globe sont une voie pour optimiser les coûts de refroidissement. Sont également développés des systèmes de migration des données vers des serveurs différents suivant le cycle du soleil afin d’optimiser le chemin parcouru par les informations en fonction des heures de haute fréquentation. </p> <p>Néanmoins, on remarque que ce système n’est que peu durable car ces dispositifs restent très gourmands en énergie. Véritable problème environnemental, ces datas centers représentaient en 2017, plus de 20% des dépenses en électricité du secteur de la technologie de l’information<sup>8</sup> (en précisant que 50% des datacenters dit “hyperscale”<sup>9</sup> sont détenus par les GAFAMs).</p> <p>Pour les utilisateurs du réseau, il est difficile de concevoir cette pollution numérique puisque la donnée est abstraite, volatile et internet complexe et non tangible. Nous avons tous des espaces de stockage dans le cloud<sup>10</sup> auxquels nous ne faisions pas forcément attention, des mails qui s’entassent dans notre boîte de réception, des Google Drive laissés à l’abandon. Mais mis bout à bout, cela représente des quantités d’informations énormes agrégées en permanence sur des serveurs énergivores. Quand la poubelle est pleine, on la vide, et ça devrait être pareil sur l’espace numérique.</p> <br><h2>Format des médias numériques</h2> <p>Au-delà de ces questions d’acheminements et de stockage de données, il est également question de repenser nos médiums d’expression. Aujourd’hui, la vidéo représente environ 60% des données transitant<sup>11</sup> sur le web. Certes les systèmes de compression vidéo évoluent sans arrêt, mais est-ce le format à privilégier sur la toile ?</p> <p>Dans le web participatif, tous les internautes sont créateurs de contenus. Il peut donc être de la responsabilité du designer et de l’artiste de choisir ses supports de création, de donner l’exemple d’un usage éthique et responsable des objets numériques même si cela reste compliqué dans un système où les différents services incitent à la production et la consommation. </p> <p>Les choix de design d’application proposés par les services mainstream en ligne amène intrinsèquement à une radicalisation des formes d’expression. Dans un monde où l’information n’a jamais été aussi abondante et le temps de concentration aussi rare, les contenus tendent à se raccourcir et à se densifier, l’expression écrite à disparaître. Cela est vérifiable dans les contenus vidéo proposés par les plateformes de VOD ou d’hébergement. Le format de série a pris le dessus face aux films, et ce en abondance, amenant à de nouvelles formes de consommation (binge watching)<sup>12</sup>, En effet, une saison sort maintenant en intégralité en une seule et même fois contrairement à l’habituel rendez-vous hebdomadaire que représentait les séries télé. </p> <p>Les plateformes vidéos poussent de plus en plus à créer un contenu extrêmement court, en témoigne l’émergence de Tiktok ou la mise en avant des Shorts de YouTube par l’algorithme (des formats d’une moyenne de 30 secondes, qui s’enchaînent de manière intensive d’après un choix de l’algorithme de recommandation). Cette logique s’applique également aux espaces de valorisation et de promotion des artistes designers. On remarque que les possibilités de publication sur les différentes plateformes de promotion se sont restreintes avec le temps.</p> <p>L'exemple de la bascule de Myspace, dont les pages étaient personnalisables avec les langages web HTML / CSS, à Facebook qui propose une mise en page figée où seul du texte et des images peuvent être postés est emblématique. Pour Instagram, c’est le format de publication qui est restreint avec la contrainte de publication d’une image uniquement carrée. Enfin TikTok où l’image fixe (parfois travaillée d’Instagram) laisse place à de courtes vidéos brutes.</p> <div class="footnote"> 7 - Analysis, Exposure and Addition: The Aesthetic and Ecological Logics of Joana Moll’s Carbolytics par Matthew Fuller - https://carbolytics.org/fuller.html<br> 8 - Rapport de Greenpeace sur le numérique - https://urlz.fr/4EEh<br> 9 - Nom donné aux datacenters de plus de 5000 serveurs et 3000m².<br> 10 - Espace de stockage décentralisé sur un serveur externe. Contrairement à un stockage local directement une machine.<br> 11 - Selon le résumé pour décideurs écrit par The Shift Project. «Climat : l’insoutenable usage de la vidéo» - https://urlz.fr/jelt<br> 12 - La pratique de regarder plusieurs épisode d’un série à une cadence frénétique, popularisée à l’air du DVD et du streaming. </div> <div class="pagebreak"></div> <br><h2>Centralisation autour de quelques acteurs</h2> <p>Ces plateformes semblent devenues incontournables dans la promotion du travail de l’artiste, du designer tant elles concentrent d’utilisateurs. Les sites web ou blogs personnels ne sont plus les plateformes qui attirent l’attention. En faisant le choix de services centralisés, assujettis à l’économie de l’attention, à la fabrication de contenus éphémères, les artistes / designers doivent publier en permanence pour pouvoir se rendre visible, suivre les tendances et satisfaire leur communauté. Dans ce magma d’informations, où les auteurs doivent toujours contribuer plus que les autres, constamment créer, publier, comment le designer graphique peut s’émanciper de cet écosystème nocif ? Comment ralentir sa production pour réengager un travail rare, plus réfléchi, diminuant ainsi l’impact de la pollution numérique ? </p> <div class="pagebreak"></div> </section> <section id="Vers-un-design-low-tech" class="chapter" data-chapter="3"> <div class="pagebreak"></div> <h1>Vers un design Low-tech</h1> <h5><pre style="font-size:14px; line-height:17px"> ██╗ ██╗███████╗██████╗ ███████╗ ██╗ ██╗███╗ ██╗ ██║ ██║██╔════╝██╔══██╗██╔════╝ ██║ ██║████╗ ██║ ██║ ██║█████╗ ██████╔╝███████╗ ██║ ██║██╔██╗ ██║ ╚██╗ ██╔╝██╔══╝ ██╔══██╗╚════██║ ██║ ██║██║╚██╗██║ ╚████╔╝ ███████╗██║ ██║███████║ ╚██████╔╝██║ ╚████║ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═══╝ ██████╗ ███████╗███████╗██╗ ██████╗ ███╗ ██╗ ██╔══██╗██╔════╝██╔════╝██║██╔════╝ ████╗ ██║ ██║ ██║█████╗ ███████╗██║██║ ███╗██╔██╗ ██║ ██║ ██║██╔══╝ ╚════██║██║██║ ██║██║╚██╗██║ ██████╔╝███████╗███████║██║╚██████╔╝██║ ╚████║ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ██╗ ██████╗ ██╗ ██╗ ████████╗███████╗ ██████╗██╗ ██╗ ██║ ██╔═══██╗██║ ██║ ╚══██╔══╝██╔════╝██╔════╝██║ ██║ ██║ ██║ ██║██║ █╗ ██║█████╗██║ █████╗ ██║ ███████║ ██║ ██║ ██║██║███╗██║╚════╝██║ ██╔══╝ ██║ ██╔══██║ ███████╗╚██████╔╝╚███╔███╔╝ ██║ ███████╗╚██████╗██║ ██║ ╚══════╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝</pre></h5> <pre style="font-size:12px; line-height:16px; color:black; text-shadow:none; margin-top: 50px" > ‘ . ‘ . . . : . . ‘. ______ .’ ‘ _.-»` `»-._ ‘ .’ ‘. `’--. / \ .--’` / \ ; ; - -- | | -- - | _. | ; /__`A ,_ ; .-’ \ |= |;._.}{__ / ‘-. _.-»»-|.’ # ‘. ` `.-»{}<._ / 1938 \ \ x `» ----/ \_.-’|--X---- -=_ | | |- X. =_ - __ |_________|_.-’|_X-X## jgs `’-._|_|;:;_.-’` ‘::. `»- .:;. .:. ::. ‘::. </pre> <div class="Texte-chapitre"> <pre> #===============================# = = = - Un monde aux ressources = = limitées = = = = - Définition des low-techs = = = = - Slow-Web = = = = - Format des médias = = numériques = = - Webdesign Low-tech / = = Sobriété Numérique = = = #===============================#</pre></div> <div class="pagebreak"></div> <h2>Un monde aux ressources limitées</h2> <p>La pérennité et la disponibilité de nos ressources sont plus que jamais centrales dans nos sociétés. Nous sommes confrontés à un problème de taille, nos ressources se font de plus en plus rares, et notre utilisation démesurée de celles-ci amène inévitablement à un dérèglement de notre planète et de l’écosystème qui s’y trouve. L’utopie capitaliste d’un monde à la croissance perpétuelle se heurte à un problème de taille : cette idéologie n’est pas compatible avec un environnement aux ressources limitées. Si dans notre société capitalisée, le designer produisait au service du profit, son rôle doit maintenant évoluer vers un médiateur au service du consommateur. L’idée étant de redonner une puissance d’action à l’utilisateur.<sup>13</sup></p> <p>Plusieurs facteurs ont accéléré ce processus d’appauvrissement, une forte croissance démographique, une mondialisation des échanges, une transition des modèles de vie sur un modèle consumériste, et un accès croissant à une technologie énergivore. </p> <p>Les solutions pour résoudre ce problème semblent prendre deux directions bien distinctes. Pour certains la solution vient de l’avancée technologique, permettant ainsi d’amener le modèle capitaliste vers une forme de développement durable. Soutenu par la promesse d’utilisations d’énergies renouvelables et moins polluantes. Mais comme dit précédemment, cette théorie sera possiblement soumise à un effet rebond sur la consommation d’énergie. L’autre solution prend la direction inverse et invite plutôt à se pencher sur les technologies du passé, parfois oubliées.</p> <div class="footnote"> 13 - LATOUR Bruno, « Le philosophe doit travailler à redonner des puissances d’agir », Le Monde - https://urlz.fr/k11w </div> <div class="pagebreak"></div> <br><h2>Définition des low-techs</h2> <p>Ce type de technologies sont appelées “low-tech”. Comme son nom l’indique, ce terme s’oppose aux hautes technologies (le high-tech) et se définit comme des technologies, simples voire primitives, souvent issues de principes et de techniques anciennes. Elles ont parfois l’avantage d’être plus efficientes en consommation de ressources, que ce soit à l’utilisation ou à la fabrication, moins opaques pour le consommateur et plus modulables. Ce qui les inscrit parfaitement dans une vision durable. La haute technologie met en avant le progrès comme argument de vente, et propose de nouvelles solutions à des problèmes que l’on sait résoudre depuis des années. Par exemple, si une trottinette électrique est un objet de haute-technologie, le vélo est l’un de ses équivalents low-tech. Certes, il est moins performant que la trottinette, mais il ne demande aucune ressource énergétique autre que la force du corps, il est simple à construire et à réparer, plus écologique dans sa fabrication et dans son fonctionnement, et a déjà fait preuve de son efficacité.</p> <p>Des solutions low-tech pour le design gagnent en popularité, notamment pour ce qui est des médias imprimés avec un retour aux techniques dites classiques (comme la sérigraphie). D’autres initiatives issues de ce courant proposent des techniques pour faire ses encres d’impression ou son papier soi-même. Des pratiques DIY (Do It Yourself ou Fait à la Main) qui peuvent redonner de l’élan aux métiers du graphisme puisqu’ils responsabilisent l’artiste designer, et questionnent ses productions, de la conception à l’impression.</p> <p>Cette philosophie low-tech peut également s’articuler avec le slow movement, mouvement tendant à ralentir les différents aspects du quotidien.</p> <p style="font-family:BrizeuxItalique">“Le Slow Movement se veut une révolution culturelle contre l’idée que plus vite mieux c’est. La philosophie du lent n’est pas d’avancer à pas d’escargot. Mais de faire les choses à la bonne vitesse. Savourez les heures et les minutes plutôt que de les compter. C’est la qualité au-dessus de la quantité, et ce, appliqué à des domaines aussi larges que le travail, la cuisine ou les transports.»<sup>14</sup></p> <p>Dans un domaine comme le numérique où les données n’ont jamais transité aussi vite, ne laissant plus le temps à l’utilisateur de les analyser et de les déchiffrer, remettre la lenteur au centre des processus de création et des consultations pourrait stabiliser l’impact néfaste du numérique sur l’écologie et ainsi repenser nos usages.</p> <p>Appliquons cette idée à notre sujet. Est-ce que nous regarderions nos stories instagram de la même façon si nous n’en avions qu’une par jour ? </p> <div class="footnote"> 14 - Carl Honoré dans son livre « In Praise of Slow»<br> </div> <div class="pagebreak"></div> <br><h2>Slow-Web </h2> <p>Plusieurs personnes ont eu ce raisonnement, et ont proposé des règles pour faire valoir un web plus sain. C’est le cas Tariq Krim, et de son initiative Slow-Web<sup>15</sup>, qui décrit quatre règles pour un développement d’un web plus éthique :</p> <p><i>Le droit à la transparence</i><br>Qui stipule que les produits et les services du web ne doivent pas cacher leur utilisation du contenu et des données personnelles des utilisateurs.</p> <p><i>Supprimer le design manipulatif (ou dark patterns)</i><br>Ne plus utiliser de technique de design pour pousser l’utilisateur à faire des choix qu’il ne désire pas faire initialement sur le service.</p> <p><i>Le droit à la confidentialité</i><br>Garantir une confidentialité à l’utilisateur tout en gardant les bénéfices du produit.</p> <p><i>Le droit de partir</i><br>Donner à l’utilisateur le droit de quitter un service et d’effacer toutes ses données avec le fournisseur sans complications.</p> <p>Ces quatre idées permettent de créer un cadre d’utilisation sain pour l’utilisateur, le rendant moins manipulable et victime d’un service opaque. Il existe de nombreuses solutions logicielles adressées au designer qui empruntent à la culture du libre et de l’open source des moyens qui respectent les communautés d’utilisateurs et qui restreignent l’accumulation de données à outrance.</p> <p>Néanmoins, hors de ces philosophies militantes et des couches logiciels qui les accompagnent, il reste le problème du hardware, énergivore et obsolescent. Pour cela, nous allons nous pencher sur le travail de plusieurs designers et ingénieurs, qui ont étudié le design low-tech dans le cadre du numérique.</p> <div class="footnote"> 15 - https://www.slowweb.io/<br> </div> <div class="pagebreak"></div> <h2>Webdesign Low-tech / Sobriété Numérique</h2> <p>Prenons l’exemple du site du Low-tech Magazine<sup>16</sup> tenu par Kris de Decker, qui développe depuis quelques années avec Marie Otsuka, un site web totalement autonome (qui ne nécessite aucun service tiers pour fonctionner), hébergé dans les locaux de l’entreprise et alimenté par énergie solaire. Leur stratégie de conception leur a permis à la fois de résoudre un problème d’énergie et un problème d’autonomie.</p> <p>Le premier facteur à prendre en compte est que leur serveur est alimenté par l’énergie solaire et ne permet donc pas une mise en ligne en permanence. Même si c’est relativement rare, notamment grâce au climat barcelonais qui fournit énormément de temps d’ensoleillement, on accepte le fait que durant plusieurs jours de temps couvert, le site ne soit plus disponible car les batteries seront déchargées. Ainsi le site répond à deux problématiques écologiques : la réduction de la consommation électrique d’un serveur et la réduction de la consultation de celui-ci, habituant le visiteur à une lecture contrainte par la météo, mais acceptable. </p> <p>Graphiquement, l’équipe a essayé de mettre en image l’impermanence énergétique de leur site web avec plusieurs outils analytiques. Pour montrer le taux de charge de la batterie, un fond de couleur en arrière plan, diminue en parallèle la capacité électrique restante. De plus, plusieurs statistiques sont présentes sur le site, notamment le poids de chacune des pages, qui permet de se rendre compte de l’utilisation d’énergie par le site web et des prévisions météorologiques indiquant la potentielle disponibilité du site dans les prochains jours.</p> <p>L’autre choix fondamental pour le développement de ce système est celui de s’appuyer sur un site statique. La majorité des sites web utilisent des langages de programmation qui génèrent le site en temps réel en allant interroger plusieurs bases de données et en récupérant les métadonnées de l’utilisateur (langue d’affichage, données géographiques, type d’appareil, …). Cela signifie qu’à chaque visite du site, une page web est générée en fonction de ces informations. On parle alors de site dynamique. A contrario, un site statique fonctionne en lisant un fichier unique sur un serveur, ce qui demande beaucoup moins d’énergie à l’ouverture. Le site du Low-tech Magazine est uniquement développé en HTML, CSS et Javascript, sans modules supplémentaires. Ce sont parmi les langages de développement web les moins gourmands en ressources et ils ne sont pas dépendants d’autres serveurs.</p> <p>L’auteur du site a fait également le choix de se passer de cookies, de tracking et de publicité<sup>17</sup> qui sont des poids logiciels supplémentaires impactant la vitesse de chargement de la page web et qui ne sont pas fondamentalement nécessaires au fonctionnement du site web.</p> <div class="footnote"> 16 - https://solar.lowtechmagazine.com/<br> 17 - Selon une étude, la publicité représente jusqu’à 40% du poids d’une page web. https://urlz.fr/jLhp </div> <div class="pagebreak"></div> <p>Pour ce qui est de l’utilisation d’images, qui représente souvent le poids le plus important d’une page web, l’auteur de Low-tech a souhaité les conserver, car importantes en termes de transmission d’informations. Néanmoins, elles sont soumises à un traitement que l’on nomme le dithering.<sup>18</sup> Le but est de rendre l’image moins lourde en modifiant sa résolution et son nombre de couleurs, ce qui leur donne un certain aspect tramé. Couplé à un traitement colorimétrique directement intégré dans le code du site, cela permet d’obtenir des images parfois dix fois plus légères que les originales. Il n’est pas utile d’utiliser des images avec une résolution de plus de 72 dpi, ni de résolutions plus hautes que celles d’affichage (la différence de qualité ne se ressentira que si l’on zoom sur l’image). En complément, la gestion de l’affichage des images est contrôlée par un algorithme (Lazy Loading) qui permet de charger celles-ci au fur et à mesure de la lecture du site.</p> <p>En ce qui concerne le média vidéo, le site ne propose pas ce type de contenu car trop gourmand en bande passante, même avec des systèmes de compressions récents.</p> <p>Pour minimiser au maximum l’utilisation d’images, le logo du site web est typographique. Le seul élément graphique étant ce glyphe de flèche (←)<sup>19</sup> qui est un caractère déjà présent dans les typographies du système d’exploitation. La typographie pour le web est l’élément graphique le plus malléable, le plus impactant et le plus intéressant à exploiter par le designer graphique. Popularisée dans les sphères de designers amateurs par Dafont.com et Google Fonts, la typographie reste un poids non négligeable du site web. Pour de nombreux sites utilisant ces typothèques, il est nécessaire de faire une requête supplémentaire sur un serveur externe pour récupérer le fichier. Pour faire l’économie des ces requêtes, des attributs liés au langage CSS<sup>20</sup> peuvent définir des polices par défaut qui au lieu de charger un fichier typographique, vont utiliser une police sur votre appareil (par exemple, l’attribut sans-sérif utilisera une Helvetica sur MacOS et une Arial sur Windows). Certains sites web, dits “frugaux” utilisent cette fonctionnalité par défaut, et sollicitent les typographies systèmes de votre ordinateur.</p> <p>Néanmoins, si l’usage d’une typographie singulière est justifiée, il est possible de réduire le poids d’un fichier typographique en supprimant certains glyphes<sup>21</sup> inutiles. L’usage de la police d’écriture sur le site web ne demandant souvent pas de toutes les utiliser, il est possible de supprimer les caractères non-utilisés du fichier de la police, allégeant ainsi son poids au chargement de la page.</p> <p>La force de développer avec les langages basiques du web (CSS et HTML), réside dans leur forte adaptabilité. Les interfaces d’accès au web sont extrêmement nombreuses, contrairement à un livre qui ne se lit que via son format de création. Une solution web se doit d’être adaptable, vu la pluralité des interfaces, allant de la montre connectée, au smartphone, en passant par l’ordinateur. C’est le principe du design responsif, le fait qu’en modifiant le format de la page, les éléments la composant se réordonnent.</p> <div class="footnote"> 19 - “←” Symbole Unicode (U+2190)<br> 20 - Le langage web qui définit la mise en forme et les choix graphiques du site. La balise CSS en question : font-family: sans-serif, serif, cursiv, system-ui;<br> 21 - Une glyphe est une représentation graphique d’un signe typographique, autrement dit un caractère, une lettre, un accent, une ligature... </div> <div class="pagebreak"></div> <p>Il y a également un autre avantage de compatibilité. Beaucoup de librairies<sup>22</sup>, de langages, ou de fonctionnalités plus contemporaines ne sont pas compatibles avec tous les navigateurs ou moteurs de recherche. De ce fait, construire un site avant d’intégrer les langages, permet de s’assurer d’avoir un service fonctionnel sur n’importe quel support pendant encore un bon moment. C’est aussi un moyen de se détacher des CMS<sup>23</sup>, qui sont souvent plus lourds, et moins performants que des sites créés soi-même.</p> <p>Il existe d’autres solutions plus simples pour écoconcevoir un site web, qui ne sont pas forcément utilisées par le site du low-tech magazine. </p> <p>L’utilisation des couleurs a un rôle important dans l’énergie consommée par un site web<sup>24</sup>. En effet le mode sombre<sup>25</sup> proposé par de nombreux sites, consomme beaucoup moins d’énergie à afficher qu’un mode clair (sur certaines technologies d’écran uniquement), ce qui en plus d’allonger la durée d’utilisation de votre appareil entre deux charges, permet de prolonger la durée de vie de votre batterie. Néanmoins, on remarque une difficulté de lecture chez certaines personnes mal voyantes. En témoignent les nombreux retours négatifs sur la nouvelle application SNCF Connect adoptant de base le thème sombre. Soulignons le point négatif de la couleur bleue, en plus de son impact assez néfaste pour le métabolisme (durée d’endormissement, fatigue oculaire), elle est la couleur qui consomme le plus d’énergie, contrairement au vert et au rouge qui sont moins gourmandes. </p> <p>Dans la continuité des usages éthiques du web, il est parfois plus simple d’exporter une page web que de la charger à chaque visite. Une version PDF conservée sur le disque dur demande moins de ressources que de recharger une page régulièrement.</p> <p>L’important dans la sobriété est de penser nos contenus et de peser ses usages. Dans nos applications, est-il réellement nécessaire d’avoir une carte interactive pour qu’on nous localise, ou une adresse au format texte suffit-elle ? La sobriété sera le meilleur argument dans la conception d’un site web écologiquement plus propre et plus performant. </p> <br><br> <h2>Pour aller plus loin</h2> <p>Le blog sur le web frugal de Sarah Garcin. <br><i>http://site.sarahgarcin.com/web-frugal/</i></p> <p>How to build a low-tech website par Marie Otsuka. <br><i>https://github.com/lowtechmag/solar/wiki/Solar-Web-Design</i></p> <p>Le guide d’écoconception de services numérique par l’association designers éthiques. <br><i>https://eco-conception.designersethiques.org/guide/fr/</i></p><br> <div class="footnote"> 22 - Une librairie est un ensemble de fonctions et de classes déjà codées dans un langage spécifique. Ce qui permet au développeur d’aller y piocher des fonctionnalités en fonction de ses besoin sans devoir les coder.<br> 23 - Content Managing System. En français Système de gestion de contenu. Famille de logiciels qui permettent de concevoir, gérer et mettre à jour des sites Web ou des application mobile de manière dynamique. Utilisable par plusieurs utilisateurs.<br> 24 - Schéma de la consommation énergétique de chaque couleur sur un écran OLED en fonction de son intensité : https://urlz.fr/j6gF<br> 25 - Le mode sombre est une option logicielle qui rend l’interface utilisateur plus sombre. Il change les arrière-plans clairs en une couleur sombre et modifie le texte de noir à blanc. Ce contraste à majorité sombre tend à limiter la fatigue oculaire lors de le longues sessions d’utilisation. </div> <div class="pagebreak"></div> </section> <div class="pagebreak"></div> <section id="Open-source-comme-modèle-écologique" class="chapter" data-chapter="4"> <h1>L'Open Source comme modèle écologique</h1> <h5><pre style="font-size:10px; line-height:13px"> ██████╗ ██████╗ ███████╗███╗ ██╗ ██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ╚██████╔╝██║ ███████╗██║ ╚████║ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ███████╗ ██████╗ ██╗ ██╗██████╗ ██████╗███████╗ ██╔════╝██╔═══██╗██║ ██║██╔══██╗██╔════╝██╔════╝ ███████╗██║ ██║██║ ██║██████╔╝██║ █████╗ ╚════██║██║ ██║██║ ██║██╔══██╗██║ ██╔══╝ ███████║╚██████╔╝╚██████╔╝██║ ██║╚██████╗███████╗ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ ██████╗ ██████╗ ███╗ ███╗███╗ ███╗███████╗ ██╔════╝██╔═══██╗████╗ ████║████╗ ████║██╔════╝ ██║ ██║ ██║██╔████╔██║██╔████╔██║█████╗ ██║ ██║ ██║██║╚██╔╝██║██║╚██╔╝██║██╔══╝ ╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚═╝ ██║███████╗ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ███╗ ███╗ ██████╗ ██████╗ ███████╗██╗ ███████╗ ████╗ ████║██╔═══██╗██╔══██╗██╔════╝██║ ██╔════╝ ██╔████╔██║██║ ██║██║ ██║█████╗ ██║ █████╗ ██║╚██╔╝██║██║ ██║██║ ██║██╔══╝ ██║ ██╔══╝ ██║ ╚═╝ ██║╚██████╔╝██████╔╝███████╗███████╗███████╗ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚══════╝ ███████╗ ██████╗ ██████╗ ██╗ ██████╗ ██████╗ ██╗ ██████╗ ██╗ ██╗███████╗ ██╔════╝██╔════╝██╔═══██╗██║ ██╔═══██╗██╔════╝ ██║██╔═══██╗██║ ██║██╔════╝ █████╗ ██║ ██║ ██║██║ ██║ ██║██║ ███╗██║██║ ██║██║ ██║█████╗ ██╔══╝ ██║ ██║ ██║██║ ██║ ██║██║ ██║██║██║▄▄ ██║██║ ██║██╔══╝ ███████╗╚██████╗╚██████╔╝███████╗╚██████╔╝╚██████╔╝██║╚██████╔╝╚██████╔╝███████╗ ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝</pre></h5> <pre style="font-size:8px; line-height:11px; color:black; text-shadow:none; margin-top: 20px"> /\ || || || || ~-----~ || /===-- ---~~~ || ;’ /==~- -- - ---~~~ || (/ (‘ /=---- ~~_ --( ‘ || ‘ / ;’ /=---- \__~ ‘ ~==_=~ ‘(‘ ~-~~ ~~~~ ~~~--\~’ \\ (c_\_ .i. /~-- ~~~-- -~ ( ‘ `\ (}| / / : \ / ~~------~ ~~\ ( \ ‘ ||/ \ |===| /~/ ~~~ \ \( ``~\ ~~\ )~.~_ >._.< _~-~ |`_ ~~-~ )\ ‘-~ { / ) \___/ ( \ |` ` _ ~~ ‘ \ -~\ -<__/ - - L~ -; \\ \ _ _/ `` ~~=\ { : }\ ,\ || _ :( \ ~~=\__ \ _/ \_ / ) } _// ( `|’ `` , ~\--~=\ \ / / _/ / ‘ ( ‘ \` } ~ ~~ -~=\ _~_ / \ / \ )^ ( // :_ / ‘ | , _~-’ ‘~~__-_ / - |/ \ ( \ ,_--_ _/ \_’---’, -~ . \ )/ /\ / /\ ,~, \__ _} \_ «~_ , { ( _ )’} ~ - \_ ~\ (-:-) «\ ~ /’’ ‘’ )~ \~_ ~\ )-> \ :| _, « (\ _/)’’} | \~_ ~ /~( | :) / } <`` >;,,/ )= \~__ {{{ ‘ \ =( , , ; {o_o }_/ |v ‘~__ _ )-v| « : ,» {/»\_) {_/’ \~__ ~\_ \\_} ‘ { /~\ ,/! ‘_/ ‘~__ _-~ \_’ : ‘ ,» ~ (‘’` /,’~___~ | / ,» \ ~’ ‘/, ) (-) ‘~____~»; ,» , } /,’) / \ / ,~-» ‘~’ ( ‘’/ / ( ‘ / / ‘~’ ~ ~ ,, /) , (/( \) ( -) /~’ ( ~~ )` ~} ‘ \)’ _/ / ~’ { |) /`,--.( }’ ‘ ( / /~’ (` ~ ( c|~~| `} ) ‘/:\ ,’ ~ )/``) )) ‘|), (/ | \) -sjm (` (-~(( `~`’ ) ‘ (/ ‘ `~’ )’`’) ‘ </pre> <div class="Texte-chapitre"> <pre> #===============================# = = = - Définition de = = l’open source = = = = - Do-It-Yourself et = = contre-pouvoir = = = = - L’open-source comme = = moyen d’émancipation = = = = - Monopole du logiciel = = créatif = = = = - Graphismes et Open-Source = = = #===============================#</pre></div> <div class="pagebreak"></div> <h2>Définition de l’open source</h2> <p>Les technologies Low-tech sont souvent associées à un mouvement issu de la culture numérique, l’open source. C’est une série de principes, s’appliquant via une licence, qui garantit l’ouverture du code source du logiciel. Cela permet de l’étudier, de le modifier et de le redistribuer. Même si il est très populaire pour le numérique, ce système peut s’appliquer à tout autres objets ou outils. </p> <p>Cette organisation de pensée a plusieurs avantages. Dans un premier temps, elle permet l’innovation avec la possibilité d’ajouter des améliorations créées par des contributeurs externes, amenant ainsi le développement d’une communauté autour du produit. Mais également du point de vue de la sécurité, le code source étant disponible aux yeux de tous, cela facilite la découverte de failles ou de bugs.</p> <p>Le mouvement open source essaie de redonner les outils et les connaissances pour permettre à chacun de créer des solutions adaptées à leurs questions. C’est un concept présent dans le design d’ameublement et l’architecture depuis plusieurs années connu sous le nom de self-design. On peut citer l’ouvrage Autoprogettazione<sup>26</sup> d’Enzo Mari, composé de différents plans pour fabriquer ses propres meubles, à l’aide de matériaux et d’outils accessibles. </p> <p>Cette mentalité s’est très bien développée sur internet, qui depuis ses débuts, a été une place de partage de savoirs : création de répertoires, de forums de partage, de tutoriels<sup>27</sup>. Les initiatives dans ce sens sont nombreuses. </p> <p>Par exemple, le site web iFixit<sup>28</sup>, qui fait valoir la réparabilité des systèmes, de nos dispositifs du quotidien. Cela va des outils ménagers, à l’automobile en passant par les appareils numériques en promouvant l’entraide et le partage de connaissances au sein de la communauté. Ces ressources, libres, ouvertes, encouragent une culture du savoir faire, de la débrouille: le DIY.<sup>29</sup></p> <br><h2>Do-It-Yourself et contre-pouvoir</h2> <p>Issu de la culture Punk des années 1970, le Do-It-Yourself est une révolution culturelle entrepris par cette scène musicale pour démystifier la production culturelle en soulignant la capacité de chacun à en devenir un acteur.<sup>30</sup> Cela s’est traduit par une indépendantisation vis-à-vis de l’industrie musicale dominante au profit d’une production faite maison avec ses propres moyens. Cette époque a vu l’émergence de médiums de communication intimement liés à ces styles musicaux, de part leur simplicité de production et de distribution, comme les fanzines ou les cassettes. En plus d’une révolution économique et culturelle, ce mouvement peut se voir comme un véritable programme pédagogique, un excellent système éducatif d’appoint pour faire apprendre aux gens à se former eux-mêmes”.<sup>31</sup></p> <div class="footnote"> 26 - MARI Enzo, Autoprogettazione, Ed. Corraini, 1974.<br> 27 - Explications techniques, souvent sous forme vidéo, sur quasiment tous les sujets possibles, permettant une nouvelle forme de diffusion du savoir.<br> 28 - Manifeste de la réparation par iFixit https://fr.ifixit.com/Manifesto<br> 29 - BOSQUÉ Camille , Open design. Fabrication numérique et mouvement maker, Paris : B42, 2022.<br> 30 - HEIN Fabien, DIY as a Countercultural Dynamic? The Example of the Punk Rock Scene, Contre Culture n°1, p.105-126, 2012.<br> 31 - REYNOLDS Simon, Rip it up and start again. Postpunk 1978-1984, Paris : Ed. Allia, 2005. </div> <div class="pagebreak"></div> <p>Cette idée est totalement transposable au monde du numérique, avec l’idée d’indépendance vis-à-vis de l’industrie numérique dominante. On observe une croissante popularité des initiatives commes les fab-labs ou les makerspaces, qui sont des lieux regroupant outils, individus, et connaissances pour la production. Le tout mis au profit de l’utilisateur. Si la tendance est au raccourcissement de la durée de vie de nos produits numériques, parfois artificiellement, les dispositifs participatifs et DIY comme les fab-labs semblent nécessaires pour contrer ce processus d’obsolescence privilégiée par certaines entreprises.</p> <p>Prenons l’exemple d’Apple. Cette entreprise verrouille au maximum ses machines, que ce soit dans le système d’exploitation très peu permissif hors du cadre définis (Apple Store) ou dans le matériel avec des composants à la comptabilité vers d’autres dispositifs quasi nulle. Cela lui permet de contrôler le marché de la réparation en facturant à des prix beaucoup plus élevés que pour des opérations et des pièces similaires chez d’autres constructeurs. </p> <br><h2>L’open-source comme moyen d’émancipation</h2> <p>L’open source, comme moteur du savoir-faire, du partage, de l’autonomie se veut en opposition avec ce système économique dit disruptif. Dans les innovations technologiques issues de solutions propriétaires, chaque nouveau produit vient souvent écraser et remplacer les produits précédents, menaçant ainsi la stabilité de notre environnement écologique. L’open source permet à des logiciels et des dispositifs de perdurer dans le temps. Chaque algorithme et composant d’un logiciel est augmentable et modifiable à souhait, chaque pièce usée dont on peut connaître la mécanique est remplaçable et confectionnable librement. </p> <p>Le modèle de l’open source est également souhaitable pour se détacher de la poignée d’acteurs qui régissent aujourd’hui les services numériques. En effet, la majorité des services du web sont reliés de près ou de loin aux géants du numérique et à des solutions propriétaires. Que ce soit dans la location de serveurs (c’est le cas de la branche AWS d’Amazon qui est aujourd’hui la principale source de revenue de l’entreprise, à hauteur de 63% du bénéfice réalisé en 2020<sup>32</sup>), dans l’utilisation de Cookies (Google Adsense par exemple, qui permet d’intégrer de la publicité sur un site web) ou d’API<sup>33</sup>. Le problème étant que cela crée une dépendance vis-à-vis de ces entreprises, qui gardent un fonctionnement opaque sur la nature et l’utilisation des données qu’elles traitent.</p> <div class="footnote"> 32 - Article de Vincent Matalon sur les activités d’AWS. Publié sur FranceTVInfo - https://urlz.fr/jkoV<br> 33 - Les API sont des solutions logiciels externes intégrées dans un site web. </div> <div class="pagebreak"></div> <br><h2>Monopole du logiciel créatif</h2> <p>C’est également observable dans le domaine de la création où la majorité de la production graphique se concentre autour de quelques acteurs. <i>“Il est frappant de constater que la diversité logicielle est plus grande dans le domaine de la comptabilité que dans le design graphique !”.</i><sup>34</sup></p> <p>Il est aisé de constater la place dominante d’Adobe dans l’écosystème de la production graphique. Possédant de nombreuses “solutions” pour différents aspects de la création (photoshop pour le traitement d’image, illustrator pour le vectoriel et indesign pour la mise en page). </p> <p>Cette suite de logiciel s’est très vite imposée comme un indispensable dans le design, utilisée dans la majorité des entreprises et enseignée dans nos écoles d’art et de design. L’illusion étant de faire croire que ces logiciels sont pleinement au service du créatif, et qu’ils épargnent le temps long et pénible de l’apprentissage.</p> <p>Lev Manovich, un auteur travaillant sur les nouveaux médias et les cultures digitales, propose une analyse de ces logiciels sous l’angle de “la logique de sélection”. Il constate que le travail créatif dans ces outils de création ne se fait que par des logiques de sélection d’actions à partir de menus prédéfinis. Il y a une idée d’automatisation des fonctions créatives qui se dégage de ces logiciels. Une production graphique industrialisée autour d’un outil de production contrôlé par Adobe</p> <p>Il est intéressant de comparer ce modèle propriétaire avec celui de Blender, logiciel open source de modélisation 3D. Photoshop malgré ces nombreuses mises à jour, n’a que très peu bougé au cours de ces dernières années. A l’inverse, par l’ouverture du logiciel à la communauté et en acceptant des ajouts et des plugins<sup>35</sup> extérieurs, Blender ne cesse de se perfectionner et se présente comme un des meilleurs logiciels de 3D actuel. Plus complet et mieux documenté que la concurrence, avec l’avantage certain d’être gratuit et transparent. L’ouverture des logiciels semblent aujourd’hui être un enjeu clef pour les services de l’écosystème créatif. Il est également intéressant de souligner le travail de la Processing Foundation qui œuvre depuis des années dans le développement de logiciels open source pour les arts graphiques. Ils sont notamment à l’origine de Processing, un logiciel de code graphique développé depuis 2001, et de p5.js une librairie Javascript pour le code créatif avec un accent mis sur l’accessibilité.</p> <div class="footnote"> 34 - Une phrase de Frank Adebiaye, un des fondateurs de la fonderie open-source Velvetyne. Disponible à cette adresse - https://velvetyne.fr/<br> 35 - Un plugin est un outil qui permet d’ajouter des fonctions supplémentaires à un logiciel principal. On le qualifiera aussi de module d’extension ou add-on. Il est dépendant de son logiciel hôte et ne fonctionne pas seul. </div> <div class="pagebreak"></div> <br><h2>Graphismes et Open-Source</h2> <p>Les possibles et les méthodes de productions liées à l’open source séduisent de plus en plus les créateurs. C’est le cas de l’Open Source Publishing<sup>>36</sup>. Un groupe de graphistes n’utilisant que de l’open source dans leur pratique et basant leur travail collaboratif autour du système Git. Il s’agit d’un environnement de travail permettant de conserver chaque version des fichiers sources (versioning). Ces documents numériques peuvent être dupliqués et partagés (fork) pour être modifiés sans pour autant altérer les documents précédents. Chacune de ses modifications pouvant être à leur tour échangées (push & pull). Appliqué au monde de la création graphique, cela signifie que chaque étape de création, chaque esquisse, chaque fichier est documenté est mis en libre accès, avec la possibilité pour chacun de travailler dessus et de le redistribuer à son tour. </p> <p>Le principal outil développé par le collectif est VisualCulture<sup>37</sup>, une API sur leur site web permettant de structurer leur travail autour de cette notion de git. Chaque tâche du processus de création est indexée, en précisant les auteurs, les dates et les remarques, mettant ainsi en avant la notion de transparence et de collaboration au sein d’un projet. Ils sont également à l’origine du projet Html2Print, un utilitaire permettant de faire de la mise en page directement avec du code CSS.</p> <p>Même si cette façon de travailler est initialement liée au monde de la programmation, on peut observer des fonctionnements similaires dans le monde de la création. L’idée de fork, reprendre un fichier existant pour le modifier et de le redistribuer dans sa nouvelle version, est transposable avec la création graphique. </p> <p>En effet, beaucoup des typographies les plus populaires sont en réalité des fork d’autres typographies. Prenons l’exemple de l’Helvetica, il s’agit en réalité d’un redessin de la Akzidenz Grotesk, avec l’idée pour son créateur de la rendre plus contemporaine. L’avantage des artefacts culturels comme les typographies par rapport aux logiciels, c’est qu’elles peuvent aisément coexister. Si utiliser deux versions de Linux en même temps n’a aucun sens, le designer peut autant utiliser une Helvetica qu’une Akzidenz Grotesk.</p> <p>C’est dans cette idée que depuis plusieurs années, le monde de la typographie se rapproche de plus en plus de l’ open source. C’est observable avec l’apparition de plusieurs typothèques basées sur le modèle open source comme chez Open Source Publishing avec leur branche foundry ou avec l’exemple français de Velvetyne. Ces espaces de publications permettent de partager des polices libres de droit, tout en permettant à chaque utilisateur de la modifier, en ajoutant des graisses ou des glyphes. Cela amène à des familles de caractères complètes développées de manière collaborative sans la contrainte de la propriété intellectuelle. C’est notamment possible grâce au système OFL (SIL Open Font License), une licence de free software et d’open source qui permet de distribuer des polices de caractères Unicode<sup>38</sup>.</p> <p>Cette logique s’applique pour d’autres matières du designer graphique comme la photographie, le dessin vectoriel, ou encore le code créatif. </p> <!-- insérer le tableau --> <div class="footnote"> 36 - Site web - http://osp.kitchen/<br> 37 - Lien du projet - http://osp.kitchen/tools/visualculture/<br> 38 - Standard industriel permettant de coder, représenter et traiter de façon cohérente des textes exprimés dans la plupart des écritures du monde. </div> <div class="pagebreak"></div> <p>Pour vous aider, voici un tableau répertoriant plusieurs solutions open-sources ou libre de droit.</p> <div class="pagebreak"></div> </section> <section id="Conclusion" class="chapter" data-chapter="6"> <h2>Conclusion</h2> <p>L’information, la donnée logicielle est intangible, volatile et duplicable à souhait avec quasiment aucune ressource. Tous les logiciels finissent par être redistribués, crackés ou modifiés, et aujourd’hui, toutes les barrières censées prévenir du piratage semblent plus desservir le produit et le consommateur qu’autre chose. La donnée est par essence complètement fluide, malléable, duplicable à l’infini, la verrouiller n’a pas de sens, elle finira forcément par circuler dans l’espace numérique. </p> <p><i>“Il suffit de prendre une poignée de sable dans la main pour comprendre que le désert n’appartient à personne”<sup>39</sup></i></p> <p>Après ces quelques pages de texte, nous pouvons donc émettre quelques pistes de réflexion pour uvn développement éthique du web. Dans cet univers en constante expansion, il est bon de se détacher de la poignée d’acteurs qui concentre aujourd’hui la majorité des publics. Cela préservera l’utilisateur des conséquences perverses de l’économie de l’attention. Repenser les usages du numérique semble être une nécessité pour ne pas tomber dans des dérives imposées par ces géants du secteur. Cela passe par un développement raisonné et qui s’appuie sur la sobriété afin de garantir une durabilité de ces systèmes que ce soit d’un point de vue technique ou environnemental. Une des forces majeures sur laquelle se baser pour y parvenir est le modèle open-source, qui permet de redonner à l’utilisateur une pleine maîtrise de ces outils. Cela devant s’accompagner de connaissances et de relais d’informations pour mieux les appréhender. La but à terme étant de redonner aux usagers leur pleine autonomie sur cet espace qui aujourd’hui profite surtout aux grandes entreprises du secteur. </p> <div class="footnote"> 39 - Un homme, quelque part en Tunisie, il y a quelques années. </div> </section> <div class="pagebreak"></div> <div class="pagebreak"></div> <section id="Bibliographie" class="chapter" data-chapter="5"> <h1>Bibliographie</h1> <h5><pre style="font-size:10px; line-height:13px"> ██████╗ ██╗██████╗ ██╗ ██╗ ██████╗ ██╔══██╗██║██╔══██╗██║ ██║██╔═══██╗ ██████╔╝██║██████╔╝██║ ██║██║ ██║█████╗ ██╔══██╗██║██╔══██╗██║ ██║██║ ██║╚════╝ ██████╔╝██║██████╔╝███████╗██║╚██████╔╝ ╚═════╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═════╝ ██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗██╗███████╗ ██╔════╝ ██╔══██╗██╔══██╗██╔══██╗██║ ██║██║██╔════╝ ██║ ███╗██████╔╝███████║██████╔╝███████║██║█████╗ ██║ ██║██╔══██╗██╔══██║██╔═══╝ ██╔══██║██║██╔══╝ ╚██████╔╝██║ ██║██║ ██║██║ ██║ ██║██║███████╗ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝</pre> <pre style="font-size:8px; line-height:11px; color:black; text-shadow:none; margin-top:200px; margin-left: 150px"> _________________________________________________________ ||-------------------------------------------------------|| ||.--. .-._ .----. || |||==|____| |H|___ .---.___|»»»»|_____.--.___ || ||| |====| | |xxx|_ |+++|=-=|_ _|-=+=-|==|---||| |||==| | | | | \ | | |_\/_|Black| | ^ ||| ||| | | | | |\ \ .--. | |=-=|_/\_|-=+=-| | ^ ||| ||| | | | | |_\ \_( oo )| | | |Magus| | ^ ||| |||==|====| |H|xxx| \ \ |’’| |+++|=-=|»»»»|-=+=-|==|---||| ||`--^----’-^-^---’ `-’ «» ‘---^---^----^-----^--^---^|| ||-------------------------------------------------------|| ||-------------------------------------------------------|| || ___ .-.__.-----. .---.|| || |===| .---. __ .---| |XX|<(*)>|_|^^^||| || , /(| |_|III|__|’’|__|:x:|=| | |=| Q ||| || _a’{ / (|===|+| |++| |==| | | |Illum| | R ||| || ‘/\\/ _(|===|-| | |’’| |:x:|=| |inati| | Y ||| ||_____ -\{___(| |-| | | | | | | | | | Z ||| || _(____)|===|+|[I]|DK|’’|==|:x:|=|XX|<(*)>|=|^^^||| || `---^-^---^--^--’--^---^-^--^-----^-^---^|| ||-------------------------------------------------------|| ||_______________________________________________________|| Qryz </pre> <div class="pagebreak"></div> <h2>Articles et Ouvrages</h2> <p>BOSQUÉ Camille, <i>Open design. Fabrication numérique et mouvement maker</i>, Paris : B42, 2022.</p> <p>CHICK Anne et MICKLETHWAITE Paul, <i>Design for Sustainable Change : How Design and Designers Can Drive the Sustainability Agenda</i>, Londres : Ed. AVA publishing, 2011.</p> <p>CITTON Yves, <i>L’économie de l’attention / Nouvel horizon du capitalisme ?</i>, Paris : Ed. La Découverte, 2014.</p> <p>HEIN Fabien, <i>DIY as a Countercultural Dynamic? The Example of the Punk Rock Scene</i>, Contre Culture n°1, p.105-126, 2012.</p> <p>MARI Enzo, <i>Autoprogettazione</i>, Ed. Corraini, 1974.</p> <p>PAPANEK Victor,<i>Design for the Real World: Human Ecology and Social Change</i>, Londres : Ed. Thames & Hudson, 1972.</p> <p>STEWART Brand, <i>Whole Earth Catalog</i>, Autoplublié, 1962.</p> <br><h2>Articles en ligne</h2> <p>BRIGNULL Harry, « Deceptive Design » <i>https://urlz.fr/ic5G</i> (consulté en mars 2022).</p> <p>GREENWOOD Tome, « The Dark side of green web design », mis en ligne en 2022, <i>https://urlz.fr/ic6g</i> (consulté en février 2022).</p> <p>GROSSMAN Juliette, KAPLAN Daniel et PANSU Denis, « Pistes d’innovation numérique tous risques », mis en ligne en 2021, <i>https://urlz.fr/ic4O</i> (consulté en avril 2022).</p> <p>HABITUS, « No-one Starts From Scratch: Type Design and the Logic of the Fork », i like tight pants.net, mis en ligne en novembre 2013, <i>https://urlz.fr/j47o</i> (consulté en juin 2022).</p> <p>HEFTI Andreas et HEINKE Steve, « L’économie de l’information surabondante et de l’attention rare », Œconomia, n° 5-1, 2015 (p.37-76), <i>https://urlz.fr/ic6S</i> (consulté en mars 2022).</p> <p>HEIN Fabien, « Le DIY comme dynamique contre-culturelle ? L’exemple de la scène punk rock », Contre-cultures n°1, 2012 (p.105-126), <i>https://urlz.fr/jfAM</i> (consulté en septembre 2022).</p> <p>JUBERT Roxane, « La communication visuelle et graphique à l’aune des défis environnementaux : des priorités à redéfinir », Sciences du Design, n° 10, 2019/2 (p.68-75), <i>https://urlz.fr/ic7B</i> (consulté en décembre 2021).</p> <p>LENOX Jack, « Delivering WordPress in 7KB », Blog de Jack Lenox, mis en ligne en 2018, <i>https://urlz.fr/ic3W</i> (consulté en janvier 2022).</p> <p>MASURE Anthony, « Adobe : le créatif au pouvoir », Blog d’Anthony Masure, mis en ligne en juin 2011, <i>https://urlz.fr/j47e</i> (consulté en juin 2022).</p> <p>MASURE Anthony, « Visual Culture. Open Source Publishing, Git et le design graphique », Blog d’Anthony Masure, mis en ligne en novembre 2014 <i>https://urlz.fr/j47i</i> (consulté en juin 2022).</p> <p>Medialab Sciencespo, « Redéfinir son identité publique numérique », mis en ligne en 2020, <i>https://urlz.fr/ic7H</i> (consulté en février 2022).</p> <p>Mightybytes, « How to optimize images for faster load times and sustainability », mis en ligne en 2022, <i>https://urlz.fr/ic69</i> (consulté en avril 2022).</p> <p>RENZULI Damian, « Minify CSS », mis en ligne en 2019, <i>https://urlz.fr/ic78</i> (consulté en janvier 2022).</p> <p>ROSCAM ABBING Roel, « How to build a low-tech website : Software & Hardware », mis en ligne en 2018, <i>https://urlz.fr/ic57</i> (consulté en décembre 2021).</p> <p>ROUSSILHE Gauthier, « Situer Le Numérique », édité par design commun, mis en ligne en 2021, <i>https://urlz.fr/ic5u</i> (consulté en février 2022).</p> <p>ROUSSILHE Gauthier, « Explication sur l’empreinte carbone du streaming et du transfert de données », mis en ligne en 2022, <i>https://urlz.fr/ic4W</i> (consulté en avril 2022).</p> <p>ROUSSILHE Gauthier, « Eco-conception, le brouillard à venir », mis en ligne en 2021, <i>https://urlz.fr/ic50</i> (consulté en avril 2022).</p> <p>Small Technology Foundation, « web0 manifesto », <i>https://urlz.fr/ic41</i> (consulté en février 2022).</p> <p>STOPPER Joshua, « The performance cost of custom web fonts, and how to solve it », mis en ligne en 2019, <i>https://urlz.fr/ic6n</i> (consulté en mars 2022).</p> <p>Web.dev, « Fast load time - Techniques for improving site performance », <i>https://urlz.fr/ic65(consulté</i> en mars 2022)</p> <br><h2>Podcasts</h2> <p>« Souveraineté numérique, la douche froide ? - KRIM Tariq et BENHAMOU Bernard » Thinkerview, 2020, <i>https://urlz.fr/dvc4</i> (consulté en décembre 2021)</p> <p>« Le mensonge de la croissance verte - BIHOUIX Philippe », Thinkerview, 2021, <i>https://urlz.fr/ic3E</i> (consulté en décembre 2021)</p> <p>« Web : et 1, et 2 et 3.0 - MARTIN Nicolas », La Méthode Scientifique, France Culture, 2022, <i>https://urlz.fr/ic3d</i> (consulté en février 2022)</p> <br><h2>Exposition</h2> <p>Common Knowledge - 26th Biennial of Design, Ljubljana, 2020 <i>https://bio.si/en/</i></p> </section> <section id="colophon" class="chapter" data-chapter="6"> <div class="pagebreak"></div> <h1></h1> <h2>Typographies utilisées</h2> <h3>Brizeux </h3> <p>Designé par Véfa Lucas et Roman Seban, Développé par Dreams Office <br>(Libre d’utilisation)</p> <h3>Px Sans Nouveau</h3> <p>Designé par Elvis Mehmedović <br>(Libre d’utilisation)</p> <br><h2>Papiers</h2> <p><b>Couverture</b><br> Clairefontaine A3 - Kraft 120gr</p> <p><b>Intérieur</b><br> Papier de récupération</p><br> <h2>Remerciements</h2> <p>Un grand merci à Keyvane Alinaghi qui m’a aidé et supporté tout au long de ce mémoire. Merci à Caroline Tron-Carroz et Stéphanie Mahieu pour avoir déniché les (très) nombreuses coquilles et fautes d’orthographes. Merci également à Gauthier Roussilhe et Roel Roscam Abbing pour les documents et informations qu’ils m’ont fournit. Enfin, merci à Line Celo pour ses conseils avisés sur la mise en page de ce mémoire.</p> </div> <div class="pagebreak"></div> <div id="4Couverture"> </div>var printButton = document.getElementById("print-button"); var stylesheet = document.getElementById("stylesheet"); var originalStylesheet = "main.css"; var printStylesheet = "print.css"; printButton.addEventListener("click", function() { // Changer le lien vers le fichier CSS stylesheet.href = printStylesheet; // Ouvrir la fenêtre d'impression window.print(); }); window.addEventListener("afterprint", function() { // Rétablir la feuille de style d'origine stylesheet.href = originalStylesheet; });@font-face { font-family: 'Texte'; src: url(Quarantype-Oblique.otf); } @font-face { font-family: 'Texte2'; src: url(Quarantype-Regular.otf); } @font-face { font-family: 'Titre'; src: url(RoubaixIndustrielle-Regular08-13pt.otf); } #print-button { position:absolute; right:0; top:0; } body { margin: 0; padding:0; background-color: #c92f2f; color: #fff; font-family: Monospace; font-size: 13px; line-height: 24px; } .block { display:inline-flex; margin:0; padding:0; inline-size: 0; width:calc(51% / 3); background-color: red;; } #controls { z-index:1000; position:fixed; left:0; bottom:0; height:67px; width:50%; background-color: lightskyblue; border-top:1px solid black; box-shadow: -2px 6px 14px 8px rgba(0,0,0,0.52); } #controls p { margin-top:8px; top:25Px; text-align: center; color:blue; } #infos { box-shadow: 10px 2px 14px 8px rgba(0,0,0,0.52); z-index:1000; position:fixed; right:0; width:50%; height:100%; background-color: lightskyblue; border-left:1px solid black; } #tools { display:inline; height:67px; position:fixed; width:calc(100% - 60px); border-bottom:1px solid black; } p { font-family: 'Courier New', Courier, monospace; margin-top:2px; margin-bottom:15px; } h1 { font-size:5em; font-family:'Texte2'; } #titre { margin-top:15px; margin-right:190px; margin-left:190px; width:100%; height:auto; } button a { font-size:9pt; font-style:normal; color:black; text-decoration: none; } button { position:absolute; } #title { position:absolute; top:0; left:0; } svg { fill:blue; } h2 { margin-bottom:0px; } #presentation { visibility: visible; position:absolute; top:68px; background-color: lightskyblue; width:calc(100% - 50px); padding-left:25px; padding-right:50px; overflow:scroll; overflow-x:hidden; height:calc(100% - 68px); } #presentation p{ margin-top:5px; padding-top:5px; color:blue; margin-bottom:35px; } #presentation h2{ color:blue; padding-bottom:2px; border-bottom:1px solid blue; } a{ margin-top:25px; color:blue; text-decoration:underline; font-size:1.2em; font-weight:bold; padding-bottom:2px; } #tuto { visibility:hidden; position:absolute; top:68px; background-color: lightskyblue; width:calc(100% - 50px); padding-left:25px; padding-right:50px; overflow:scroll; overflow-x:hidden; height:calc(100% - 68px); } #tuto p{ margin-top:5px; padding-top:5px; color:blue; margin-bottom:35px; } #tuto h2{ color:blue; padding-bottom:2px; border-bottom:1px solid blue; } #about { visibility: hidden; position:absolute; background-color: lightskyblue;; top:68px; width:calc(100% - 50px); padding-left:25px; padding-right:50px; overflow:scroll; overflow-x:hidden; height:calc(100% - 68px); } #about p{ margin-top:5px; padding-top:5px; color:blue; margin-bottom:35px; } #about h2{ color:blue; padding-bottom:2px; border-bottom:1px solid blue; } ::selection { background-color: lightgreen; color:green; } h3 { text-align:center; width:calc(50% / 3 - 80px); font-size:12pt; font-family:Monospace; font-weight:bold; color:black; display:inline-block; margin:13px 1px 10px 10px; padding:8px 15px 20px 15px; height:10px; background-color: blue; border-radius: 25Px; border:1px solid black; box-shadow: -8px 7px 19px -13px rgba(0,0,0,0.52); }function openContent(ref) { var a = document.getElementById(ref); console.log(a); a.style.visibility = "visible"; } function closeContent(ref) { var a = document.getElementById(ref); console.log(a); a.style.visibility = "hidden"; }body { print-color-adjust: exact; } @page{ size: 148mm 210mm; margin:10mm 3mm 5mm 3mm; } #cover { display:block; visibility: visible; } p { color:blue; font-family: monospace; margin:2px 5mm 5mm 5mm; } #tools { display:none; } canvas { display:none; page-break-inside: avoid; } #controls { display:none; } #print-button { display:none; } #référence { display:none; } #chapitre1 { display:block; visibility: visible; } h2 { margin:0px 5mm 3mm 5mm; font-family:monospace; border-bottom:1px solid black; } #presentation { display:block; visibility: visible; } #about{ display:block; visibility: visible; } #tuto{ display:block; visibility: visible; }<!DOCTYPE html> <html lang="en"> <head> <title>Sedia Chair</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <link id="stylesheet" rel="stylesheet" type="text/css" href="main.css"> <script src="main.js"></script> </head> <body> <div id="title"> <img src="titre.svg" id="titre" style="break-after: always;"> </div> <div id="controls"> <p>Utilisez la molette pour zoomer/dézoomer<br>Maintenez le clic de la souris en bougeant pour faire pivoter la vue</p> </div> <div id="infos"> <div id="tools"> <a id="#presentation" onclick="openContent('presentation');closeContent('about');closeContent('tuto')"><h3 style="background-color: lightgrey; color:blue; margin-left:25px;">Présentation</h3></a> <a id="#tuto" onclick="closeContent('about');closeContent('presentation');openContent('tuto')"><h3 style="background-color: lightgrey; color:blue;">Outils</h3></a> <a id="#about" onclick="closeContent('presentation');closeContent('tuto');openContent('about')" ><h3 style="background-color: lightgrey; color:blue;">About</h3></a> </div> <div id="presentation"> <img src="bg.png" id="cover" style="display:none"> <h1 style="display:none" id="chapitre1">Présentation</h1> <h2>La Chaise Sédia</h2> <p>Initialement conçu en 1974 par le designer radical italien Enzo Mari, elle fait parti d’une série nommé “autoprogettazione”, un catalogue présenté durant une exposition de Milan comprenant une série 19 meubles à fabriquer soi-même. Il décrit cette chaise comme la forme la plus simple représentant la fonction de s’assoir en se délaissant de toutes formes inutiles. Mon idée avec ce projet est de l’augmenté par le design graphique pour en faire un objet auto-reproductible, à l’instar de l’imprimante 3D RepRap qui peux s’imprimer en partie avec une autre imprimante. Il est également question de rassembler toutes les informations nécessaires et les ressources lié au travail d’Enzo Mari pour faciliter la création de ses meubles.</p> <h2>Autoprogettazione</h2> <p><i>Autoprogettazione</i> est une éditions hybride entre catalogue et manifeste présentant une série de mobilier à réaliser soi-même avec des matériaux de base : bois, clous, scie et marteau. Il s’inscrit dans le mouvement de self-design, et reviendras plusieurs foi comme une référence importante pour des mouvements plus contemporain comme les mouvements low-tech ou le slow-design. <h2>Radical Design</h2> <p>Ce projet s’inscrit dans le Design radical, un mouvement artistique et architectural qui émerge à la fin des années 1960 en Italie en réaction au Good Design et contestant la société de consommation. Autoprogettazione se pose en marge des productions de son époque où l’heure est à l’insouciance et la consommation de masse. Il vient remettre de l’artisanal et de la singularité face à la montée en puissance de la production industrielle standardisée. Ces idées prennent racines dans l'Antidesign florentin et milanais, mais est néanmoins plus théorique, politisé et expérimental que ce dernier, la visée première étant de changer la perception du courant moderniste à travers des projets utopistes. On voit alors émerger à l’époque des groupes de design comme Superstudio, Archizoom, UFO ou encore Gruppo Strum.</p> <div id="référence"> <h2>Références</h2> <a href="https://www.opendesk.cc/" style="margin-top:50px;"><br>OpenDesk</a> <p style="margin-top:-5px;margin-bottom:15px; font-style:italic;">Une plateforme pour acheter des meubles éco-conçu</p> <a href="https://www.cucula.org/en/">Cucula</a> <p style="margin-top:-5px;margin-bottom:15px; font-style:italic;">Une association qui crée des meubles pour les réfugiés à partir des plans d'Enzo Mari</p> <a href="https://ateliers.esad-pyrenees.fr/web/pages/culturenum/ethique/enzo-mari-autoprogettazione.pdf">Autoprogettazione PDF</a> <p style="margin-top:-5px;margin-bottom:15px; font-style:italic;">Une version numérisée du catalogue original</p> <a href="https://jo.github.io/enzo-mari/">Plan adaptable</a> <p style="margin-top:-5px;margin-bottom:15px; font-style:italic;">Un programme permettant de vous fournir un plan de la table <i>Tavolo Rettangolare</i> dans les dimensions que vous souhaitez.</p> </div> </div> <div id="tuto" style="page-break-before: always;"> <h2>Instruction de montage</h2> <p>Pour réaliser cette chaise vous aurez besoins au préalable de quelques outils. Un marteau, des clous (adapté à l’épaisseur de vos planches de bois) et optionnellement de colle à bois, d’un rapporteur et de serre-joints. Vous aurez également besoin de planches de bois (prévoyez une épaisseur d’au moins 3cm pour garantir la solidité de votre chaise). Vous pouvez soit les faire couper dans la majorité des magasins de bricolage, ou chez vous avec une scie circulaire ou une scie sauteuse. <br><br>Voici les dimensions à découper pour vos planches :<br><br> <img src="sedia5.svg" style="width:50%; height:auto; page-break-after: always; "> <h2>Plans de montage</h2> <p>Je vous conseille très fortement de regarder cette vidéo d'Enzo Mari qui montre comment monter cette chaise étape par étape (en anglais) : <br><a href="https://vimeo.com/39624485">Building instructions by Enzo Mari</a> <br><br>Voici également un plan pour bien comprendre les différentes étapes de montage.</p> <img src="sedia2.svg" style="margin-top:-5px; page-break-after: always;"> <br><a href="SediaPlan.pdf" target="_blank" style="margin-top:25px;margin-bottom:25Px">Imprimer les plans de montage</a><br><br> </div> <div id="about"> <h2>À propos</h2> <p>Développé en HTML/CSS/JS dans le cadre de mon DNSEP<br> <br>Modèle 3D en photogrammetry et importation avec <a href="https://threejs.org/"style="font-size:1em;">Three.JS</a>. <br>Titre en <a href="https://velvetyne.fr/fonts/pilowlava/"style="font-size:1em;">Pilowlava</a> par Anton Moglia et Jérémy Landes. <br>Merci à <a href="https://danielparnitzke.de/project/workshop-enzo-mari-sedia-1" style="font-size:1em;">Daniel Parnitzke</a> d'avoir pris le temps de me renseigner et pour ses précieuses informations.</p> </div> <div id="htmlformat"></div> </div> </div> <!-- Import maps polyfill --> <!-- Remove this when import maps will be widely supported --> <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "https://unpkg.com/three/build/three.module.js", "three/addons/": "https://unpkg.com/three/examples/jsm/" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'; let camera, scene, renderer; init(); render(); function init() { const container = document.createElement( 'div' ); document.body.appendChild( container ); camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.25, 30 ); camera.position.set( 5, 6, 7 ); const aspectRatio = window.innerWidth / 2 / window.innerHeight; camera.aspect = aspectRatio; camera.updateProjectionMatrix(); scene = new THREE.Scene(); new RGBELoader() .setPath( 'textures/' ) .load( 'sky2.hdr', function ( texture ) { texture.mapping = THREE.EquirectangularReflectionMapping; scene.background = texture; scene.environment = texture; render(); // model const loader = new GLTFLoader().setPath( 'models/' ); loader.load( 'test2.gltf', function ( gltf ) { scene.add( gltf.scene ); render(); } ); } ); renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize(window.innerWidth / 2, window.innerHeight); renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 0.7; container.appendChild( renderer.domElement ); const controls = new OrbitControls( camera, renderer.domElement ); controls.addEventListener( 'change', render ); // use if there is no animation loop controls.minDistance = 2; controls.maxDistance = 10; controls.target.set( 0, 1, - 0.2 ); controls.update(); // window.addEventListener( 'resize', onWindowResize ); } function onWindowResize() { const newWidth = window.innerWidth / 2; const newHeight = window.innerHeight; camera.aspect = newWidth / newHeight; camera.updateProjectionMatrix(); renderer.setSize(newWidth, newHeight); } // function render() { renderer.render( scene, camera ); } </script> </body> </html>@page{ margin:0; size: A1; } @media print { @page{ margin:0; size: 594mm 841mm; } } @font-face { font-family:'Linux' ; src: url(font/cmunti.ttf); } body { print-color-adjust: exact; margin:0; } /* --------------- Haut à gauche --------------- */ #top-left { position:absolute; top:0; left:0; height:420mm; width:297mm; background-color: lightgreen; } #top-left h1 { text-align:center; font-size:120pt; color:black; font-family:'Linux'; } #top-left p { text-align:center; font-size:88pt; color:white; font-family:sans-serif; } /* --------------- Haut à droite --------------- */ #top-right { position:absolute; top:0; right:0; height:420mm; width:297mm; background-color: lightcoral; } #top-right h1 { text-align:center; font-size:120pt; color:black; font-family:sans-serif; } #top-right p { text-align:center; font-size:88pt; color:white; font-family:sans-serif; } /* --------------- Bas à droite --------------- */ #bottom-right { position:absolute; bottom:1mm; right:0; height:420mm; width:297mm; background-color: lightyellow; } #bottom-right h1 { text-align:center; font-size:120pt; color:black; font-family:sans-serif; } #bottom-right p { text-align:center; font-size:88pt; color:white; font-family:sans-serif; } /* --------------- Bas à gauche --------------- */ #bottom-left { position:absolute; bottom:1mm; left:0; height:420mm; width:297mm; background-color: lightblue; } #bottom-left h1 { text-align:center; font-size:120pt; color:black; font-family:sans-serif; } #bottom-left p { text-align:center; font-size:88pt; color:white; font-family:sans-serif; }<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>demo pagedjs</title> <link href="affiche.css" rel="stylesheet" type="text/css"> <script src="paged.polyfill.js"></script> <script src="action.js"></script> </head> <body> <div id="top-left"> <h1>Titre 1</h1> <p>Playlist</p> </div> <div id="top-right"> <h1>Titre 1</h1> <p>Playlist</p> </div> <div id="bottom-left"> <h1>Titre 1</h1> <p>Playlist</p> </div> <div id="bottom-right"> <h1>Titre 1</h1> <p>Playlist</p> </div> </html>@page{ margin:0; size: A4 landscape; } @font-face { font-family:'Linux' ; src: url(font/cmunti.ttf); } #cd1 { position:absolute; top:60mm; left:10mm; height:13cm; width:13cm; background-image:url(../Template/image/9.png); border-radius:90mm; border:2px solid black; } #cd2 { position:absolute; top:60mm; left:160mm; height:13cm; width:13cm; background-image:url(../WorkshopFMRLucile/Template/image/space3.png); border-radius:90mm; border:2px solid black; } p { font-size:14pt; font-family: monospace; text-align: center; color:white; } #défonce { z-index:10; height:40mm; width:40mm; border-radius:40mm; border:2px solid black; background-color: rgb(255, 255, 255); position:absolute; top:45mm; left:45mm; } h1 { text-align: center; } h2 { text-align: center; font-family:monospace; } body { print-color-adjust: exact; margin:0; } #liens { position:absolute; top:85px; width:100%; } a { padding-top:100px; margin-left:25px; font-family: sans-serif; color:black; } #screen { position:fixed; top:0; left:0; height:75px; width:100%; background-color: lightgrey; } #screen h1 { text-align: center; font-family:sans-serif; }<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>demo pagedjs</title> <link href="cd.css" rel="stylesheet" type="text/css"> <script src="paged.polyfill.js"></script> <script src="action.js"></script> </head> <body> <div id="screen"> <h1>RadioFMR Workshop</h1> </div> <div id="liens"> <a href="https://mensuel.framapad.org/p/workshopradiofmr-a1ex?lang=fr" target="_blank">Framapad</a> <a href="https://constraint.systems/" target="_blank">ContraintSystem</a> <a href="https://ditherit.com/" target="_blank">Dithering it </a> <a href="https://synth.alicericci.eu/synths.php" target="_blank">Synthétiseur </a> <a href="http://anael.bzh/Linux%20OS/ressources.html" target="_blank">Typographies</a> <a href="https://cssgradient.io/" target="_blank">Dégradé CSS</a> <a href="https://fontsee.com/" target="_blank">Voir les fonts en WOFF</a> </div> <div id="cd1"> <div id="défonce"></div> </div> <div id="cd2"> <div id="défonce"></div> </div> </body> </html>@page{ margin:0; size: 420mm 297mm; } @font-face { font-family:'Linux' ; src: url(font/cmunti.ttf); } @font-face { font-family: 'ApfelGrotezkBrukt'; src: url('font/ApfelGrotezk-Brukt.woff2') format('woff2'), url('font/ApfelGrotezk-Brukt.woff') format('woff'); font-weight: normal; font-style: normal; } @font-face { font-family: 'Mess'; src: url('font/Mess.otf'); } @font-face { font-family: 'ApfelGrotezkFett'; src: url('font/ApfelGrotezk-Fett.woff2') format('woff2'), url('font/ApfelGrotezk-Fett.woff') format('woff'); font-weight: normal; font-style: normal; } @font-face { font-family: 'ApfelGrotezkRegular'; src: url('font/ApfelGrotezk-Regular.woff2') format('woff2'), url('font/ApfelGrotezk-Regular.woff') format('woff'); font-weight: normal; font-style: normal; } @font-face { font-family: 'Gambarino'; src: url('font/Gambarino-Regular.woff2') format('woff2'), url('font/Gambarino-Regular.woff') format('woff'); font-weight: normal; font-style: normal; } #truecd { position:absolute; top:60mm; left:280mm; height:12cm; width:12cm; background-image:url(image/9.png); border-radius:90mm; border:2px solid black; } #cercle { z-index:10; position:absolute; background-image: url(image9.png); min-width: 100%; min-height: 100%; background-repeat: no-repeat; } #picture { position:absolute; bottom:5mm; right:5mm; } h5 { font-family:'Mess'; color:white; font-size:250pt; position:absolute; margin:0; top:0mm; left:20mm; -webkit-text-fill-color: transparent; background: linear-gradient(90deg, rgba(255,238,44,1) 0%, rgba(226,0,35,1) 100%); background-clip: text; text-stroke: 0.25px rgb(0, 0, 0); } #défonce { z-index:10; height:40mm; width:40mm; border-radius:40mm; border:2px solid black; background-color: rgb(255, 255, 255); position:absolute; top:40mm; left:40mm; } h1 { margin:5mm 0 0 5mm; /* Haut / Gauche / Bas / haut */ text-align: center; font-family:'ApfelGrotezkBrukt'; font-size:48pt; color:#E20023; background: white; border-radius:90px; width:120mm; background-color: #000000; border:1px solid rgb(255, 255, 255); } h2 { text-align: center; font-family:monospace; font-family:'Gambarino'; margin:0 0 4mm 20mm; font-size:14pt; background-color: #FFEE2C; width:90mm; border-radius:90px; border:1px solid black; } pre { display:inline-flex; font-size:12pt; padding:1mm 5mm 1mm 5mm; background-color: white; border-radius:90px; border:1px solid black; margin:-4mm 0 4mm 6mm; width:25mm; font-family:sans-serif; } h4 { margin-top:3mm; text-align: center; font-family:'ApfelGrotezkBrukt'; font-size:32pt; } #cd1 { position:absolute; top:60mm; left:10mm; width: 130mm; height:130mm; border:2px solid black; background-image:url(image/canvas.png) } #cd2 { position:absolute; width: 130mm; height:130mm; top:60mm; left:140mm; border-top:2px solid black; border-right:2px solid black; border-bottom:2px solid black; background-image: url(image/9.png); } #copymark { text-align:center; position:absolute; padding-top:1mm; bottom:4mm; right:5mm; margin:0; font-family:'ApfelGrotezkRegular'; font-size:10pt; color:rgb(255, 255, 255); border-radius:90px; width:120mm; height:6mm; background-color: #000000; border:1px solid rgb(255, 255, 255); } #bleed1 { z-index:-5; position:absolute; width: 130mm; height:10mm; top:40mm; left:140mm; background-color: transparent; border-style: solid; border-width: 10mm; border-color: transparent transparent lightgrey transparent; } #bleed2 { z-index:-5; position:absolute; width: 130mm; height:10mm; top:190mm; left:140mm; background-color: transparent; border-style: solid; border-width: 10mm; border-color: lightgrey transparent transparent; } body { print-color-adjust: exact; margin:0; } #liens { position:absolute; top:85px; width:100%; } a { padding-top:100px; margin-left:25px; font-family: sans-serif; color:black; } #screen { position:fixed; top:0; left:0; height:75px; width:100%; background-color: lightgrey; } #screen h1 { text-align: center; font-family:sans-serif; }<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Workshop FMR</title> <link href="pochette.css" rel="stylesheet" type="text/css"> <script src="paged.polyfill.js"></script> <script src="action.js"></script> </head> <body> <div id="screen"> <h4>RadioFMR Workshop</h4> </div> <div id="liens"> <a href="https://mensuel.framapad.org/p/workshopradiofmr-a1ex?lang=fr" target="_blank">Framapad</a> <a href="https://constraint.systems/" target="_blank">ContraintSystem</a> <a href="https://ditherit.com/" target="_blank">Dithering it </a> <a href="https://synth.alicericci.eu/synths.php" target="_blank">Synthétiseur </a> <a href="http://anael.bzh/Linux%20OS/ressources.html" target="_blank">Typographies</a> <a href="https://cssgradient.io/" target="_blank">Dégradé CSS</a> </div> <div class="template"> <div id="cd2" contenteditable="true"> <h5>A</h5> <h2 style="position:absolute; bottom:5mm; left:5mm; margin:0; background-color: black; color:white; border:1px solid white; width:50mm;">Radio FMR</h2> </div> <div id="cd1" contenteditable="true"> <pre style="margin:4mm 5mm 3mm 5mm; width:30mm; padding-left:7mm;background-color:black; color:white; border:1px solid white ;">Tracklist</pre> <h2 style="margin-left:5mm;">Jwles - Cup N Some Ice</h2> <h2 style="margin-left:35mm">H JeuneCrack - Présidentiel Flow</h2> <h2 style="margin-left:5mm;">Gipsy kings - Volare</h2> <h2 style="margin-left:35mm">Tyler The Creator - NEW MAGIC WAND</h2> <h2 style="margin-left:5mm;">Ricchi e Poveri - Sarà perché ti amo</h2> <h2 style="margin-left:35mm;">Karavana - Que Putada</h2> <h2 style="margin-left:5mm;">Them Changes- Thundercat</h2> <h2 style="margin-left:35mm">Cloudbusting- Kate Bush</h2> <pre> Emma</pre> <pre> Lucile</pre> <pre> Anaël</pre> <pre>Baptiste</pre> <p id="copymark">Workshop @ Radio FMR</p> </div> <div id="bleed1"></div> <div id="bleed2"></div> <div id="truecd"> <div id="défonce"></di> </div> </div> </body> </html>const fs = require('fs'); const path = require('path'); // définir les chemins de fichiers à lire const htmlFilePath = path.join(__dirname, 'index.html'); const cssFilePath = path.join(__dirname, 'style.css'); const jsFilePath = path.join(__dirname, 'action.js'); // lire le contenu des fichiers const htmlContent = fs.readFileSync(htmlFilePath, 'utf-8'); const cssContent = fs.readFileSync(cssFilePath, 'utf-8'); const jsContent = fs.readFileSync(jsFilePath, 'utf-8'); // écrire le contenu dans un fichier test.html fs.writeFileSync( path.join(__dirname, 'test.html'), `<html> <head> <style>${cssContent}</style> <script>${jsContent}</script> </head> <body> ${htmlContent} </body> </html>` ); console.log('Contenu écrit dans le fichier test.html');<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>DNSEP 2023</title> <script href="action.js"></script> <link href="style.css" rel="stylesheet" type="text/css"> </head> <body> <div id="title"> <h1>OpenDNSEP</h1> <p style="text-align: center; width:90%; margin:0 5% 0 5%;">Index de mon projet de DNSEP - Anaël Le Gall - 2022/2023</p> </div> <div id="liens"> <div class="box"> <a href="/Linux OS/index.html" target="_blank">GraphikLinux →</a> <br> <p>Un système d'exploitations basé sur Ubuntu orienté pour création numérique.</p></div> <div class="box"> <a href="/Dirty Video Mixer/dirty-video-mixer.html">Dirty Video Mixer →</a> <br> <p>Un mixeur vidéo analogique DIY créé à partir du modèle de Karl Klamp, permettant de faire du VJing ou d'autres expérimentations vidéos.</p></div> <div class="box"> <a href="/Sedia/sedia.html">Chaise Sedia →</a> <br> <p>Une augmentation par le graphisme de la chaise Sédia du designer Enzo Mari.</p></div> <div class="box"> <a href="Memoire/index.html" target="_blank">Mémoire Web2Print →</a> <br> <p>Mémoire de second cycle portant sur la création web durable et de l'économie de moyens numériques.</p></div> <div class="box"> <a href="/IW4X Edition/IW4XPrint.html" target="_blank">IW4X Edition →</a> <br> <p>Edition générative à partir du code source du jeu IW4X. L'édition est imprimable directement depuis votre navigateur (optimisé pour Firefox). </p></div> <div class="box"> <a href="WorkshopFMR/Template/pochette.html">Template Workshop FMR →</a> <br> <p>Un template Web2Print pour la fabrication de pochettes de CD</p></div> <h2 style="text-align: center; margin-top:40px"><i>Dans le cadre de mon service civique en médiation culturelle.</i></h2> <br> <div class="box"> <a href="/Dynamo/index.html" target="_blank">Site-Web Dynamo →</a> <br> <p>Réalisation d'une exposition et d'un site-web éco-conçu pour la restitution des workshops "Énergie".</p></div> <div class="box"> <a href="/Cartographie/index.html" target="_blank">Cartographie des ressources de Cambrai →</a> <br> <p>Cartographies participatives des ressources pour les étudiants dans la région du Cambrésis.</p></div> <div class="box"> <a href="">Archives →</a> <p>Archivage des travaux réalisés dans le cadre de notre service civique par Baptiste Coppée.</p></div> </div> </body> </html>/* Importation des polices d'écriture */ @font-face { font-family: 'Arkes'; src: url(fonts/arkessolidregular.ttf); } body{ background-color: black; color:white; margin:0; } h1 { padding-top: 25px; margin:0 ; font-family: sans-serif; } h2 { } h3 { font-family: sans-serif; } p { margin: 10px 0 5px 0; font-family: sans-serif; } ::selection { background-color:rgb(0, 255, 0); color:black; padding:0 10px 0 10px; } a { margin-bottom: 10px; font-size:1.5em; color: rgb(0, 255, 0); font-family: monospace; } a:visited { margin-bottom: 15px; color: rgb(0, 255, 0); font-family: monospace; } #liens { width:90%; margin:0 5% 0 5%; } .box { border-bottom: 1px solid white; padding: 10px; margin-bottom:5px; } #title { margin:0 0 25px 0; text-align: center; border-bottom:1px dashed rgb(0, 255, 0); padding-bottom:20px; box-shadow: 0px -10px 25px 15px rgba(0, 255, 0, 0.6); } @media only screen and (max-width: 600px) { #liens { width:90%; margin:0 5% 0 5%; } }{"version":3,"file":"leaflet-src.esm.js","sources":["../src/core/Util.js","../src/core/Class.js","../src/core/Events.js","../src/geometry/Point.js","../src/geometry/Bounds.js","../src/geo/LatLngBounds.js","../src/geo/LatLng.js","../src/geo/crs/CRS.js","../src/geo/crs/CRS.Earth.js","../src/geo/projection/Projection.SphericalMercator.js","../src/geometry/Transformation.js","../src/geo/crs/CRS.EPSG3857.js","../src/layer/vector/SVG.Util.js","../src/core/Browser.js","../src/dom/DomEvent.Pointer.js","../src/dom/DomEvent.DoubleTap.js","../src/dom/DomUtil.js","../src/dom/DomEvent.js","../src/dom/PosAnimation.js","../src/map/Map.js","../src/control/Control.js","../src/control/Control.Layers.js","../src/control/Control.Zoom.js","../src/control/Control.Scale.js","../src/control/Control.Attribution.js","../src/control/index.js","../src/core/Handler.js","../src/core/index.js","../src/dom/Draggable.js","../src/geometry/LineUtil.js","../src/geometry/PolyUtil.js","../src/geo/projection/Projection.LonLat.js","../src/geo/projection/Projection.Mercator.js","../src/geo/projection/index.js","../src/geo/crs/CRS.EPSG3395.js","../src/geo/crs/CRS.EPSG4326.js","../src/geo/crs/CRS.Simple.js","../src/geo/crs/index.js","../src/layer/Layer.js","../src/layer/LayerGroup.js","../src/layer/FeatureGroup.js","../src/layer/marker/Icon.js","../src/layer/marker/Icon.Default.js","../src/layer/marker/Marker.Drag.js","../src/layer/marker/Marker.js","../src/layer/vector/Path.js","../src/layer/vector/CircleMarker.js","../src/layer/vector/Circle.js","../src/layer/vector/Polyline.js","../src/layer/vector/Polygon.js","../src/layer/GeoJSON.js","../src/layer/ImageOverlay.js","../src/layer/VideoOverlay.js","../src/layer/SVGOverlay.js","../src/layer/DivOverlay.js","../src/layer/Popup.js","../src/layer/Tooltip.js","../src/layer/marker/DivIcon.js","../src/layer/marker/index.js","../src/layer/tile/GridLayer.js","../src/layer/tile/TileLayer.js","../src/layer/tile/TileLayer.WMS.js","../src/layer/tile/index.js","../src/layer/vector/Renderer.js","../src/layer/vector/Canvas.js","../src/layer/vector/SVG.VML.js","../src/layer/vector/SVG.js","../src/layer/vector/Renderer.getRenderer.js","../src/layer/vector/Rectangle.js","../src/layer/vector/index.js","../src/layer/index.js","../src/map/handler/Map.BoxZoom.js","../src/map/handler/Map.DoubleClickZoom.js","../src/map/handler/Map.Drag.js","../src/map/handler/Map.Keyboard.js","../src/map/handler/Map.ScrollWheelZoom.js","../src/map/handler/Map.TapHold.js","../src/map/handler/Map.TouchZoom.js","../src/map/index.js"],"sourcesContent":["/*\r\n * @namespace Util\r\n *\r\n * Various utility functions, used by Leaflet internally.\r\n */\r\n\r\n// @function extend(dest: Object, src?: Object): Object\r\n// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.\r\nexport function extend(dest) {\r\n\tvar i, j, len, src;\r\n\r\n\tfor (j = 1, len = arguments.length; j < len; j++) {\r\n\t\tsrc = arguments[j];\r\n\t\tfor (i in src) {\r\n\t\t\tdest[i] = src[i];\r\n\t\t}\r\n\t}\r\n\treturn dest;\r\n}\r\n\r\n// @function create(proto: Object, properties?: Object): Object\r\n// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)\r\nexport var create = Object.create || (function () {\r\n\tfunction F() {}\r\n\treturn function (proto) {\r\n\t\tF.prototype = proto;\r\n\t\treturn new F();\r\n\t};\r\n})();\r\n\r\n// @function bind(fn: Function, …): Function\r\n// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).\r\n// Has a `L.bind()` shortcut.\r\nexport function bind(fn, obj) {\r\n\tvar slice = Array.prototype.slice;\r\n\r\n\tif (fn.bind) {\r\n\t\treturn fn.bind.apply(fn, slice.call(arguments, 1));\r\n\t}\r\n\r\n\tvar args = slice.call(arguments, 2);\r\n\r\n\treturn function () {\r\n\t\treturn fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);\r\n\t};\r\n}\r\n\r\n// @property lastId: Number\r\n// Last unique ID used by [`stamp()`](#util-stamp)\r\nexport var lastId = 0;\r\n\r\n// @function stamp(obj: Object): Number\r\n// Returns the unique ID of an object, assigning it one if it doesn't have it.\r\nexport function stamp(obj) {\r\n\tif (!('_leaflet_id' in obj)) {\r\n\t\tobj['_leaflet_id'] = ++lastId;\r\n\t}\r\n\treturn obj._leaflet_id;\r\n}\r\n\r\n// @function throttle(fn: Function, time: Number, context: Object): Function\r\n// Returns a function which executes function `fn` with the given scope `context`\r\n// (so that the `this` keyword refers to `context` inside `fn`'s code). The function\r\n// `fn` will be called no more than one time per given amount of `time`. The arguments\r\n// received by the bound function will be any arguments passed when binding the\r\n// function, followed by any arguments passed when invoking the bound function.\r\n// Has an `L.throttle` shortcut.\r\nexport function throttle(fn, time, context) {\r\n\tvar lock, args, wrapperFn, later;\r\n\r\n\tlater = function () {\r\n\t\t// reset lock and call if queued\r\n\t\tlock = false;\r\n\t\tif (args) {\r\n\t\t\twrapperFn.apply(context, args);\r\n\t\t\targs = false;\r\n\t\t}\r\n\t};\r\n\r\n\twrapperFn = function () {\r\n\t\tif (lock) {\r\n\t\t\t// called too soon, queue to call later\r\n\t\t\targs = arguments;\r\n\r\n\t\t} else {\r\n\t\t\t// call and lock until later\r\n\t\t\tfn.apply(context, arguments);\r\n\t\t\tsetTimeout(later, time);\r\n\t\t\tlock = true;\r\n\t\t}\r\n\t};\r\n\r\n\treturn wrapperFn;\r\n}\r\n\r\n// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number\r\n// Returns the number `num` modulo `range` in such a way so it lies within\r\n// `range[0]` and `range[1]`. The returned value will be always smaller than\r\n// `range[1]` unless `includeMax` is set to `true`.\r\nexport function wrapNum(x, range, includeMax) {\r\n\tvar max = range[1],\r\n\t min = range[0],\r\n\t d = max - min;\r\n\treturn x === max && includeMax ? x : ((x - min) % d + d) % d + min;\r\n}\r\n\r\n// @function falseFn(): Function\r\n// Returns a function which always returns `false`.\r\nexport function falseFn() { return false; }\r\n\r\n// @function formatNum(num: Number, precision?: Number|false): Number\r\n// Returns the number `num` rounded with specified `precision`.\r\n// The default `precision` value is 6 decimal places.\r\n// `false` can be passed to skip any processing (can be useful to avoid round-off errors).\r\nexport function formatNum(num, precision) {\r\n\tif (precision === false) { return num; }\r\n\tvar pow = Math.pow(10, precision === undefined ? 6 : precision);\r\n\treturn Math.round(num * pow) / pow;\r\n}\r\n\r\n// @function trim(str: String): String\r\n// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)\r\nexport function trim(str) {\r\n\treturn str.trim ? str.trim() : str.replace(/^\\s+|\\s+$/g, '');\r\n}\r\n\r\n// @function splitWords(str: String): String[]\r\n// Trims and splits the string on whitespace and returns the array of parts.\r\nexport function splitWords(str) {\r\n\treturn trim(str).split(/\\s+/);\r\n}\r\n\r\n// @function setOptions(obj: Object, options: Object): Object\r\n// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.\r\nexport function setOptions(obj, options) {\r\n\tif (!Object.prototype.hasOwnProperty.call(obj, 'options')) {\r\n\t\tobj.options = obj.options ? create(obj.options) : {};\r\n\t}\r\n\tfor (var i in options) {\r\n\t\tobj.options[i] = options[i];\r\n\t}\r\n\treturn obj.options;\r\n}\r\n\r\n// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String\r\n// Converts an object into a parameter URL string, e.g. `{a: \"foo\", b: \"bar\"}`\r\n// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will\r\n// be appended at the end. If `uppercase` is `true`, the parameter names will\r\n// be uppercased (e.g. `'?A=foo&B=bar'`)\r\nexport function getParamString(obj, existingUrl, uppercase) {\r\n\tvar params = [];\r\n\tfor (var i in obj) {\r\n\t\tparams.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));\r\n\t}\r\n\treturn ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');\r\n}\r\n\r\nvar templateRe = /\\{ *([\\w_ -]+) *\\}/g;\r\n\r\n// @function template(str: String, data: Object): String\r\n// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`\r\n// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string\r\n// `('Hello foo, bar')`. You can also specify functions instead of strings for\r\n// data values — they will be evaluated passing `data` as an argument.\r\nexport function template(str, data) {\r\n\treturn str.replace(templateRe, function (str, key) {\r\n\t\tvar value = data[key];\r\n\r\n\t\tif (value === undefined) {\r\n\t\t\tthrow new Error('No value provided for variable ' + str);\r\n\r\n\t\t} else if (typeof value === 'function') {\r\n\t\t\tvalue = value(data);\r\n\t\t}\r\n\t\treturn value;\r\n\t});\r\n}\r\n\r\n// @function isArray(obj): Boolean\r\n// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)\r\nexport var isArray = Array.isArray || function (obj) {\r\n\treturn (Object.prototype.toString.call(obj) === '[object Array]');\r\n};\r\n\r\n// @function indexOf(array: Array, el: Object): Number\r\n// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)\r\nexport function indexOf(array, el) {\r\n\tfor (var i = 0; i < array.length; i++) {\r\n\t\tif (array[i] === el) { return i; }\r\n\t}\r\n\treturn -1;\r\n}\r\n\r\n// @property emptyImageUrl: String\r\n// Data URI string containing a base64-encoded empty GIF image.\r\n// Used as a hack to free memory from unused images on WebKit-powered\r\n// mobile devices (by setting image `src` to this string).\r\nexport var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';\r\n\r\n// inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/\r\n\r\nfunction getPrefixed(name) {\r\n\treturn window['webkit' + name] || window['moz' + name] || window['ms' + name];\r\n}\r\n\r\nvar lastTime = 0;\r\n\r\n// fallback for IE 7-8\r\nfunction timeoutDefer(fn) {\r\n\tvar time = +new Date(),\r\n\t timeToCall = Math.max(0, 16 - (time - lastTime));\r\n\r\n\tlastTime = time + timeToCall;\r\n\treturn window.setTimeout(fn, timeToCall);\r\n}\r\n\r\nexport var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;\r\nexport var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||\r\n\t\tgetPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };\r\n\r\n// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number\r\n// Schedules `fn` to be executed when the browser repaints. `fn` is bound to\r\n// `context` if given. When `immediate` is set, `fn` is called immediately if\r\n// the browser doesn't have native support for\r\n// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),\r\n// otherwise it's delayed. Returns a request ID that can be used to cancel the request.\r\nexport function requestAnimFrame(fn, context, immediate) {\r\n\tif (immediate && requestFn === timeoutDefer) {\r\n\t\tfn.call(context);\r\n\t} else {\r\n\t\treturn requestFn.call(window, bind(fn, context));\r\n\t}\r\n}\r\n\r\n// @function cancelAnimFrame(id: Number): undefined\r\n// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).\r\nexport function cancelAnimFrame(id) {\r\n\tif (id) {\r\n\t\tcancelFn.call(window, id);\r\n\t}\r\n}\r\n","import * as Util from './Util';\r\n\r\n// @class Class\r\n// @aka L.Class\r\n\r\n// @section\r\n// @uninheritable\r\n\r\n// Thanks to John Resig and Dean Edwards for inspiration!\r\n\r\nexport function Class() {}\r\n\r\nClass.extend = function (props) {\r\n\r\n\t// @function extend(props: Object): Function\r\n\t// [Extends the current class](#class-inheritance) given the properties to be included.\r\n\t// Returns a Javascript function that is a class constructor (to be called with `new`).\r\n\tvar NewClass = function () {\r\n\r\n\t\tUtil.setOptions(this);\r\n\r\n\t\t// call the constructor\r\n\t\tif (this.initialize) {\r\n\t\t\tthis.initialize.apply(this, arguments);\r\n\t\t}\r\n\r\n\t\t// call all constructor hooks\r\n\t\tthis.callInitHooks();\r\n\t};\r\n\r\n\tvar parentProto = NewClass.__super__ = this.prototype;\r\n\r\n\tvar proto = Util.create(parentProto);\r\n\tproto.constructor = NewClass;\r\n\r\n\tNewClass.prototype = proto;\r\n\r\n\t// inherit parent's statics\r\n\tfor (var i in this) {\r\n\t\tif (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') {\r\n\t\t\tNewClass[i] = this[i];\r\n\t\t}\r\n\t}\r\n\r\n\t// mix static properties into the class\r\n\tif (props.statics) {\r\n\t\tUtil.extend(NewClass, props.statics);\r\n\t}\r\n\r\n\t// mix includes into the prototype\r\n\tif (props.includes) {\r\n\t\tcheckDeprecatedMixinEvents(props.includes);\r\n\t\tUtil.extend.apply(null, [proto].concat(props.includes));\r\n\t}\r\n\r\n\t// mix given properties into the prototype\r\n\tUtil.extend(proto, props);\r\n\tdelete proto.statics;\r\n\tdelete proto.includes;\r\n\r\n\t// merge options\r\n\tif (proto.options) {\r\n\t\tproto.options = parentProto.options ? Util.create(parentProto.options) : {};\r\n\t\tUtil.extend(proto.options, props.options);\r\n\t}\r\n\r\n\tproto._initHooks = [];\r\n\r\n\t// add method for calling all hooks\r\n\tproto.callInitHooks = function () {\r\n\r\n\t\tif (this._initHooksCalled) { return; }\r\n\r\n\t\tif (parentProto.callInitHooks) {\r\n\t\t\tparentProto.callInitHooks.call(this);\r\n\t\t}\r\n\r\n\t\tthis._initHooksCalled = true;\r\n\r\n\t\tfor (var i = 0, len = proto._initHooks.length; i < len; i++) {\r\n\t\t\tproto._initHooks[i].call(this);\r\n\t\t}\r\n\t};\r\n\r\n\treturn NewClass;\r\n};\r\n\r\n\r\n// @function include(properties: Object): this\r\n// [Includes a mixin](#class-includes) into the current class.\r\nClass.include = function (props) {\r\n\tvar parentOptions = this.prototype.options;\r\n\tUtil.extend(this.prototype, props);\r\n\tif (props.options) {\r\n\t\tthis.prototype.options = parentOptions;\r\n\t\tthis.mergeOptions(props.options);\r\n\t}\r\n\treturn this;\r\n};\r\n\r\n// @function mergeOptions(options: Object): this\r\n// [Merges `options`](#class-options) into the defaults of the class.\r\nClass.mergeOptions = function (options) {\r\n\tUtil.extend(this.prototype.options, options);\r\n\treturn this;\r\n};\r\n\r\n// @function addInitHook(fn: Function): this\r\n// Adds a [constructor hook](#class-constructor-hooks) to the class.\r\nClass.addInitHook = function (fn) { // (Function) || (String, args...)\r\n\tvar args = Array.prototype.slice.call(arguments, 1);\r\n\r\n\tvar init = typeof fn === 'function' ? fn : function () {\r\n\t\tthis[fn].apply(this, args);\r\n\t};\r\n\r\n\tthis.prototype._initHooks = this.prototype._initHooks || [];\r\n\tthis.prototype._initHooks.push(init);\r\n\treturn this;\r\n};\r\n\r\nfunction checkDeprecatedMixinEvents(includes) {\r\n\t/* global L: true */\r\n\tif (typeof L === 'undefined' || !L || !L.Mixin) { return; }\r\n\r\n\tincludes = Util.isArray(includes) ? includes : [includes];\r\n\r\n\tfor (var i = 0; i < includes.length; i++) {\r\n\t\tif (includes[i] === L.Mixin.Events) {\r\n\t\t\tconsole.warn('Deprecated include of L.Mixin.Events: ' +\r\n\t\t\t\t'this property will be removed in future releases, ' +\r\n\t\t\t\t'please inherit from L.Evented instead.', new Error().stack);\r\n\t\t}\r\n\t}\r\n}\r\n","import {Class} from './Class';\r\nimport * as Util from './Util';\r\n\r\n/*\r\n * @class Evented\r\n * @aka L.Evented\r\n * @inherits Class\r\n *\r\n * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * map.on('click', function(e) {\r\n * \talert(e.latlng);\r\n * } );\r\n * ```\r\n *\r\n * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:\r\n *\r\n * ```js\r\n * function onClick(e) { ... }\r\n *\r\n * map.on('click', onClick);\r\n * map.off('click', onClick);\r\n * ```\r\n */\r\n\r\nexport var Events = {\r\n\t/* @method on(type: String, fn: Function, context?: Object): this\r\n\t * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).\r\n\t *\r\n\t * @alternative\r\n\t * @method on(eventMap: Object): this\r\n\t * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\t */\r\n\ton: function (types, fn, context) {\r\n\r\n\t\t// types can be a map of types/handlers\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\t// we don't process space-separated events here for performance;\r\n\t\t\t\t// it's a hot path since Layer uses the on(obj) syntax\r\n\t\t\t\tthis._on(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// types can be a string of space-separated words\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t/* @method off(type: String, fn?: Function, context?: Object): this\r\n\t * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.\r\n\t *\r\n\t * @alternative\r\n\t * @method off(eventMap: Object): this\r\n\t * Removes a set of type/listener pairs.\r\n\t *\r\n\t * @alternative\r\n\t * @method off: this\r\n\t * Removes all listeners to all events on the object. This includes implicitly attached events.\r\n\t */\r\n\toff: function (types, fn, context) {\r\n\r\n\t\tif (!arguments.length) {\r\n\t\t\t// clear all listeners if called without arguments\r\n\t\t\tdelete this._events;\r\n\r\n\t\t} else if (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis._off(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tvar removeAll = arguments.length === 1;\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tif (removeAll) {\r\n\t\t\t\t\tthis._off(types[i]);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._off(types[i], fn, context);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// attach listener (without syntactic sugar now)\r\n\t_on: function (type, fn, context, _once) {\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tconsole.warn('wrong listener type: ' + typeof fn);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// check if fn already there\r\n\t\tif (this._listens(type, fn, context) !== false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\t// Less memory footprint.\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tvar newListener = {fn: fn, ctx: context};\r\n\t\tif (_once) {\r\n\t\t\tnewListener.once = true;\r\n\t\t}\r\n\r\n\t\tthis._events = this._events || {};\r\n\t\tthis._events[type] = this._events[type] || [];\r\n\t\tthis._events[type].push(newListener);\r\n\t},\r\n\r\n\t_off: function (type, fn, context) {\r\n\t\tvar listeners,\r\n\t\t i,\r\n\t\t len;\r\n\r\n\t\tif (!this._events) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlisteners = this._events[type];\r\n\t\tif (!listeners) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (arguments.length === 1) { // remove all\r\n\t\t\tif (this._firingCount) {\r\n\t\t\t\t// Set all removed listeners to noop\r\n\t\t\t\t// so they are not called if remove happens in fire\r\n\t\t\t\tfor (i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\t\tlisteners[i].fn = Util.falseFn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// clear all listeners for a type if function isn't specified\r\n\t\t\tdelete this._events[type];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tconsole.warn('wrong listener type: ' + typeof fn);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// find fn and remove it\r\n\t\tvar index = this._listens(type, fn, context);\r\n\t\tif (index !== false) {\r\n\t\t\tvar listener = listeners[index];\r\n\t\t\tif (this._firingCount) {\r\n\t\t\t\t// set the removed listener to noop so that's not called if remove happens in fire\r\n\t\t\t\tlistener.fn = Util.falseFn;\r\n\r\n\t\t\t\t/* copy array in case events are being fired */\r\n\t\t\t\tthis._events[type] = listeners = listeners.slice();\r\n\t\t\t}\r\n\t\t\tlisteners.splice(index, 1);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method fire(type: String, data?: Object, propagate?: Boolean): this\r\n\t// Fires an event of the specified type. You can optionally provide a data\r\n\t// object — the first argument of the listener function will contain its\r\n\t// properties. The event can optionally be propagated to event parents.\r\n\tfire: function (type, data, propagate) {\r\n\t\tif (!this.listens(type, propagate)) { return this; }\r\n\r\n\t\tvar event = Util.extend({}, data, {\r\n\t\t\ttype: type,\r\n\t\t\ttarget: this,\r\n\t\t\tsourceTarget: data && data.sourceTarget || this\r\n\t\t});\r\n\r\n\t\tif (this._events) {\r\n\t\t\tvar listeners = this._events[type];\r\n\t\t\tif (listeners) {\r\n\t\t\t\tthis._firingCount = (this._firingCount + 1) || 1;\r\n\t\t\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\t\tvar l = listeners[i];\r\n\t\t\t\t\t// off overwrites l.fn, so we need to copy fn to a var\r\n\t\t\t\t\tvar fn = l.fn;\r\n\t\t\t\t\tif (l.once) {\r\n\t\t\t\t\t\tthis.off(type, fn, l.ctx);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfn.call(l.ctx || this, event);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._firingCount--;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// propagate the event to parents (set with addEventParent)\r\n\t\t\tthis._propagateEvent(event);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method listens(type: String, propagate?: Boolean): Boolean\r\n\t// @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean\r\n\t// Returns `true` if a particular event type has any listeners attached to it.\r\n\t// The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.\r\n\tlistens: function (type, fn, context, propagate) {\r\n\t\tif (typeof type !== 'string') {\r\n\t\t\tconsole.warn('\"string\" type argument expected');\r\n\t\t}\r\n\r\n\t\t// we don't overwrite the input `fn` value, because we need to use it for propagation\r\n\t\tvar _fn = fn;\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tpropagate = !!fn;\r\n\t\t\t_fn = undefined;\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tvar listeners = this._events && this._events[type];\r\n\t\tif (listeners && listeners.length) {\r\n\t\t\tif (this._listens(type, _fn, context) !== false) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// also check parents for listeners if event propagates\r\n\t\t\tfor (var id in this._eventParents) {\r\n\t\t\t\tif (this._eventParents[id].listens(type, fn, context, propagate)) { return true; }\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t},\r\n\r\n\t// returns the index (number) or false\r\n\t_listens: function (type, fn, context) {\r\n\t\tif (!this._events) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tvar listeners = this._events[type] || [];\r\n\t\tif (!fn) {\r\n\t\t\treturn !!listeners.length;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\t// Less memory footprint.\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\tif (listeners[i].fn === fn && listeners[i].ctx === context) {\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\t// @method once(…): this\r\n\t// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.\r\n\tonce: function (types, fn, context) {\r\n\r\n\t\t// types can be a map of types/handlers\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\t// we don't process space-separated events here for performance;\r\n\t\t\t\t// it's a hot path since Layer uses the on(obj) syntax\r\n\t\t\t\tthis._on(type, types[type], fn, true);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// types can be a string of space-separated words\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(types[i], fn, context, true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addEventParent(obj: Evented): this\r\n\t// Adds an event parent - an `Evented` that will receive propagated events\r\n\taddEventParent: function (obj) {\r\n\t\tthis._eventParents = this._eventParents || {};\r\n\t\tthis._eventParents[Util.stamp(obj)] = obj;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeEventParent(obj: Evented): this\r\n\t// Removes an event parent, so it will stop receiving propagated events\r\n\tremoveEventParent: function (obj) {\r\n\t\tif (this._eventParents) {\r\n\t\t\tdelete this._eventParents[Util.stamp(obj)];\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_propagateEvent: function (e) {\r\n\t\tfor (var id in this._eventParents) {\r\n\t\t\tthis._eventParents[id].fire(e.type, Util.extend({\r\n\t\t\t\tlayer: e.target,\r\n\t\t\t\tpropagatedFrom: e.target\r\n\t\t\t}, e), true);\r\n\t\t}\r\n\t}\r\n};\r\n\r\n// aliases; we should ditch those eventually\r\n\r\n// @method addEventListener(…): this\r\n// Alias to [`on(…)`](#evented-on)\r\nEvents.addEventListener = Events.on;\r\n\r\n// @method removeEventListener(…): this\r\n// Alias to [`off(…)`](#evented-off)\r\n\r\n// @method clearAllEventListeners(…): this\r\n// Alias to [`off()`](#evented-off)\r\nEvents.removeEventListener = Events.clearAllEventListeners = Events.off;\r\n\r\n// @method addOneTimeEventListener(…): this\r\n// Alias to [`once(…)`](#evented-once)\r\nEvents.addOneTimeEventListener = Events.once;\r\n\r\n// @method fireEvent(…): this\r\n// Alias to [`fire(…)`](#evented-fire)\r\nEvents.fireEvent = Events.fire;\r\n\r\n// @method hasEventListeners(…): Boolean\r\n// Alias to [`listens(…)`](#evented-listens)\r\nEvents.hasEventListeners = Events.listens;\r\n\r\nexport var Evented = Class.extend(Events);\r\n","import {isArray, formatNum} from '../core/Util';\r\n\r\n/*\r\n * @class Point\r\n * @aka L.Point\r\n *\r\n * Represents a point with `x` and `y` coordinates in pixels.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var point = L.point(200, 300);\r\n * ```\r\n *\r\n * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:\r\n *\r\n * ```js\r\n * map.panBy([200, 300]);\r\n * map.panBy(L.point(200, 300));\r\n * ```\r\n *\r\n * Note that `Point` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function Point(x, y, round) {\r\n\t// @property x: Number; The `x` coordinate of the point\r\n\tthis.x = (round ? Math.round(x) : x);\r\n\t// @property y: Number; The `y` coordinate of the point\r\n\tthis.y = (round ? Math.round(y) : y);\r\n}\r\n\r\nvar trunc = Math.trunc || function (v) {\r\n\treturn v > 0 ? Math.floor(v) : Math.ceil(v);\r\n};\r\n\r\nPoint.prototype = {\r\n\r\n\t// @method clone(): Point\r\n\t// Returns a copy of the current point.\r\n\tclone: function () {\r\n\t\treturn new Point(this.x, this.y);\r\n\t},\r\n\r\n\t// @method add(otherPoint: Point): Point\r\n\t// Returns the result of addition of the current and the given points.\r\n\tadd: function (point) {\r\n\t\t// non-destructive, returns a new point\r\n\t\treturn this.clone()._add(toPoint(point));\r\n\t},\r\n\r\n\t_add: function (point) {\r\n\t\t// destructive, used directly for performance in situations where it's safe to modify existing point\r\n\t\tthis.x += point.x;\r\n\t\tthis.y += point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method subtract(otherPoint: Point): Point\r\n\t// Returns the result of subtraction of the given point from the current.\r\n\tsubtract: function (point) {\r\n\t\treturn this.clone()._subtract(toPoint(point));\r\n\t},\r\n\r\n\t_subtract: function (point) {\r\n\t\tthis.x -= point.x;\r\n\t\tthis.y -= point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method divideBy(num: Number): Point\r\n\t// Returns the result of division of the current point by the given number.\r\n\tdivideBy: function (num) {\r\n\t\treturn this.clone()._divideBy(num);\r\n\t},\r\n\r\n\t_divideBy: function (num) {\r\n\t\tthis.x /= num;\r\n\t\tthis.y /= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method multiplyBy(num: Number): Point\r\n\t// Returns the result of multiplication of the current point by the given number.\r\n\tmultiplyBy: function (num) {\r\n\t\treturn this.clone()._multiplyBy(num);\r\n\t},\r\n\r\n\t_multiplyBy: function (num) {\r\n\t\tthis.x *= num;\r\n\t\tthis.y *= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method scaleBy(scale: Point): Point\r\n\t// Multiply each coordinate of the current point by each coordinate of\r\n\t// `scale`. In linear algebra terms, multiply the point by the\r\n\t// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)\r\n\t// defined by `scale`.\r\n\tscaleBy: function (point) {\r\n\t\treturn new Point(this.x * point.x, this.y * point.y);\r\n\t},\r\n\r\n\t// @method unscaleBy(scale: Point): Point\r\n\t// Inverse of `scaleBy`. Divide each coordinate of the current point by\r\n\t// each coordinate of `scale`.\r\n\tunscaleBy: function (point) {\r\n\t\treturn new Point(this.x / point.x, this.y / point.y);\r\n\t},\r\n\r\n\t// @method round(): Point\r\n\t// Returns a copy of the current point with rounded coordinates.\r\n\tround: function () {\r\n\t\treturn this.clone()._round();\r\n\t},\r\n\r\n\t_round: function () {\r\n\t\tthis.x = Math.round(this.x);\r\n\t\tthis.y = Math.round(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method floor(): Point\r\n\t// Returns a copy of the current point with floored coordinates (rounded down).\r\n\tfloor: function () {\r\n\t\treturn this.clone()._floor();\r\n\t},\r\n\r\n\t_floor: function () {\r\n\t\tthis.x = Math.floor(this.x);\r\n\t\tthis.y = Math.floor(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method ceil(): Point\r\n\t// Returns a copy of the current point with ceiled coordinates (rounded up).\r\n\tceil: function () {\r\n\t\treturn this.clone()._ceil();\r\n\t},\r\n\r\n\t_ceil: function () {\r\n\t\tthis.x = Math.ceil(this.x);\r\n\t\tthis.y = Math.ceil(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method trunc(): Point\r\n\t// Returns a copy of the current point with truncated coordinates (rounded towards zero).\r\n\ttrunc: function () {\r\n\t\treturn this.clone()._trunc();\r\n\t},\r\n\r\n\t_trunc: function () {\r\n\t\tthis.x = trunc(this.x);\r\n\t\tthis.y = trunc(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method distanceTo(otherPoint: Point): Number\r\n\t// Returns the cartesian distance between the current and the given points.\r\n\tdistanceTo: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\tvar x = point.x - this.x,\r\n\t\t y = point.y - this.y;\r\n\r\n\t\treturn Math.sqrt(x * x + y * y);\r\n\t},\r\n\r\n\t// @method equals(otherPoint: Point): Boolean\r\n\t// Returns `true` if the given point has the same coordinates.\r\n\tequals: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\treturn point.x === this.x &&\r\n\t\t point.y === this.y;\r\n\t},\r\n\r\n\t// @method contains(otherPoint: Point): Boolean\r\n\t// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).\r\n\tcontains: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\treturn Math.abs(point.x) <= Math.abs(this.x) &&\r\n\t\t Math.abs(point.y) <= Math.abs(this.y);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point for debugging purposes.\r\n\ttoString: function () {\r\n\t\treturn 'Point(' +\r\n\t\t formatNum(this.x) + ', ' +\r\n\t\t formatNum(this.y) + ')';\r\n\t}\r\n};\r\n\r\n// @factory L.point(x: Number, y: Number, round?: Boolean)\r\n// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Number[])\r\n// Expects an array of the form `[x, y]` instead.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Object)\r\n// Expects a plain object of the form `{x: Number, y: Number}` instead.\r\nexport function toPoint(x, y, round) {\r\n\tif (x instanceof Point) {\r\n\t\treturn x;\r\n\t}\r\n\tif (isArray(x)) {\r\n\t\treturn new Point(x[0], x[1]);\r\n\t}\r\n\tif (x === undefined || x === null) {\r\n\t\treturn x;\r\n\t}\r\n\tif (typeof x === 'object' && 'x' in x && 'y' in x) {\r\n\t\treturn new Point(x.x, x.y);\r\n\t}\r\n\treturn new Point(x, y, round);\r\n}\r\n","import {Point, toPoint} from './Point';\r\n\r\n/*\r\n * @class Bounds\r\n * @aka L.Bounds\r\n *\r\n * Represents a rectangular area in pixel coordinates.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var p1 = L.point(10, 10),\r\n * p2 = L.point(40, 60),\r\n * bounds = L.bounds(p1, p2);\r\n * ```\r\n *\r\n * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:\r\n *\r\n * ```js\r\n * otherBounds.intersects([[10, 10], [40, 60]]);\r\n * ```\r\n *\r\n * Note that `Bounds` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function Bounds(a, b) {\r\n\tif (!a) { return; }\r\n\r\n\tvar points = b ? [a, b] : a;\r\n\r\n\tfor (var i = 0, len = points.length; i < len; i++) {\r\n\t\tthis.extend(points[i]);\r\n\t}\r\n}\r\n\r\nBounds.prototype = {\r\n\t// @method extend(point: Point): this\r\n\t// Extends the bounds to contain the given point.\r\n\r\n\t// @alternative\r\n\t// @method extend(otherBounds: Bounds): this\r\n\t// Extend the bounds to contain the given bounds\r\n\textend: function (obj) {\r\n\t\tvar min2, max2;\r\n\t\tif (!obj) { return this; }\r\n\r\n\t\tif (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) {\r\n\t\t\tmin2 = max2 = toPoint(obj);\r\n\t\t} else {\r\n\t\t\tobj = toBounds(obj);\r\n\t\t\tmin2 = obj.min;\r\n\t\t\tmax2 = obj.max;\r\n\r\n\t\t\tif (!min2 || !max2) { return this; }\r\n\t\t}\r\n\r\n\t\t// @property min: Point\r\n\t\t// The top left corner of the rectangle.\r\n\t\t// @property max: Point\r\n\t\t// The bottom right corner of the rectangle.\r\n\t\tif (!this.min && !this.max) {\r\n\t\t\tthis.min = min2.clone();\r\n\t\t\tthis.max = max2.clone();\r\n\t\t} else {\r\n\t\t\tthis.min.x = Math.min(min2.x, this.min.x);\r\n\t\t\tthis.max.x = Math.max(max2.x, this.max.x);\r\n\t\t\tthis.min.y = Math.min(min2.y, this.min.y);\r\n\t\t\tthis.max.y = Math.max(max2.y, this.max.y);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getCenter(round?: Boolean): Point\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function (round) {\r\n\t\treturn toPoint(\r\n\t\t (this.min.x + this.max.x) / 2,\r\n\t\t (this.min.y + this.max.y) / 2, round);\r\n\t},\r\n\r\n\t// @method getBottomLeft(): Point\r\n\t// Returns the bottom-left point of the bounds.\r\n\tgetBottomLeft: function () {\r\n\t\treturn toPoint(this.min.x, this.max.y);\r\n\t},\r\n\r\n\t// @method getTopRight(): Point\r\n\t// Returns the top-right point of the bounds.\r\n\tgetTopRight: function () { // -> Point\r\n\t\treturn toPoint(this.max.x, this.min.y);\r\n\t},\r\n\r\n\t// @method getTopLeft(): Point\r\n\t// Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).\r\n\tgetTopLeft: function () {\r\n\t\treturn this.min; // left, top\r\n\t},\r\n\r\n\t// @method getBottomRight(): Point\r\n\t// Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).\r\n\tgetBottomRight: function () {\r\n\t\treturn this.max; // right, bottom\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the size of the given bounds\r\n\tgetSize: function () {\r\n\t\treturn this.max.subtract(this.min);\r\n\t},\r\n\r\n\t// @method contains(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\t// @alternative\r\n\t// @method contains(point: Point): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) {\r\n\t\tvar min, max;\r\n\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof Point) {\r\n\t\t\tobj = toPoint(obj);\r\n\t\t} else {\r\n\t\t\tobj = toBounds(obj);\r\n\t\t}\r\n\r\n\t\tif (obj instanceof Bounds) {\r\n\t\t\tmin = obj.min;\r\n\t\t\tmax = obj.max;\r\n\t\t} else {\r\n\t\t\tmin = max = obj;\r\n\t\t}\r\n\r\n\t\treturn (min.x >= this.min.x) &&\r\n\t\t (max.x <= this.max.x) &&\r\n\t\t (min.y >= this.min.y) &&\r\n\t\t (max.y <= this.max.y);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds\r\n\t// intersect if they have at least one point in common.\r\n\tintersects: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t max = this.max,\r\n\t\t min2 = bounds.min,\r\n\t\t max2 = bounds.max,\r\n\t\t xIntersects = (max2.x >= min.x) && (min2.x <= max.x),\r\n\t\t yIntersects = (max2.y >= min.y) && (min2.y <= max.y);\r\n\r\n\t\treturn xIntersects && yIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds\r\n\t// overlap if their intersection is an area.\r\n\toverlaps: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t max = this.max,\r\n\t\t min2 = bounds.min,\r\n\t\t max2 = bounds.max,\r\n\t\t xOverlaps = (max2.x > min.x) && (min2.x < max.x),\r\n\t\t yOverlaps = (max2.y > min.y) && (min2.y < max.y);\r\n\r\n\t\treturn xOverlaps && yOverlaps;\r\n\t},\r\n\r\n\t// @method isValid(): Boolean\r\n\t// Returns `true` if the bounds are properly initialized.\r\n\tisValid: function () {\r\n\t\treturn !!(this.min && this.max);\r\n\t},\r\n\r\n\r\n\t// @method pad(bufferRatio: Number): Bounds\r\n\t// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.\r\n\t// For example, a ratio of 0.5 extends the bounds by 50% in each direction.\r\n\t// Negative values will retract the bounds.\r\n\tpad: function (bufferRatio) {\r\n\t\tvar min = this.min,\r\n\t\tmax = this.max,\r\n\t\theightBuffer = Math.abs(min.x - max.x) * bufferRatio,\r\n\t\twidthBuffer = Math.abs(min.y - max.y) * bufferRatio;\r\n\r\n\r\n\t\treturn toBounds(\r\n\t\t\ttoPoint(min.x - heightBuffer, min.y - widthBuffer),\r\n\t\t\ttoPoint(max.x + heightBuffer, max.y + widthBuffer));\r\n\t},\r\n\r\n\r\n\t// @method equals(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle is equivalent to the given bounds.\r\n\tequals: function (bounds) {\r\n\t\tif (!bounds) { return false; }\r\n\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\treturn this.min.equals(bounds.getTopLeft()) &&\r\n\t\t\tthis.max.equals(bounds.getBottomRight());\r\n\t},\r\n};\r\n\r\n\r\n// @factory L.bounds(corner1: Point, corner2: Point)\r\n// Creates a Bounds object from two corners coordinate pairs.\r\n// @alternative\r\n// @factory L.bounds(points: Point[])\r\n// Creates a Bounds object from the given array of points.\r\nexport function toBounds(a, b) {\r\n\tif (!a || a instanceof Bounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new Bounds(a, b);\r\n}\r\n","import {LatLng, toLatLng} from './LatLng';\r\n\r\n/*\r\n * @class LatLngBounds\r\n * @aka L.LatLngBounds\r\n *\r\n * Represents a rectangular geographical area on a map.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var corner1 = L.latLng(40.712, -74.227),\r\n * corner2 = L.latLng(40.774, -74.125),\r\n * bounds = L.latLngBounds(corner1, corner2);\r\n * ```\r\n *\r\n * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:\r\n *\r\n * ```js\r\n * map.fitBounds([\r\n * \t[40.712, -74.227],\r\n * \t[40.774, -74.125]\r\n * ]);\r\n * ```\r\n *\r\n * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.\r\n *\r\n * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])\r\n\tif (!corner1) { return; }\r\n\r\n\tvar latlngs = corner2 ? [corner1, corner2] : corner1;\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\tthis.extend(latlngs[i]);\r\n\t}\r\n}\r\n\r\nLatLngBounds.prototype = {\r\n\r\n\t// @method extend(latlng: LatLng): this\r\n\t// Extend the bounds to contain the given point\r\n\r\n\t// @alternative\r\n\t// @method extend(otherBounds: LatLngBounds): this\r\n\t// Extend the bounds to contain the given bounds\r\n\textend: function (obj) {\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2, ne2;\r\n\r\n\t\tif (obj instanceof LatLng) {\r\n\t\t\tsw2 = obj;\r\n\t\t\tne2 = obj;\r\n\r\n\t\t} else if (obj instanceof LatLngBounds) {\r\n\t\t\tsw2 = obj._southWest;\r\n\t\t\tne2 = obj._northEast;\r\n\r\n\t\t\tif (!sw2 || !ne2) { return this; }\r\n\r\n\t\t} else {\r\n\t\t\treturn obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;\r\n\t\t}\r\n\r\n\t\tif (!sw && !ne) {\r\n\t\t\tthis._southWest = new LatLng(sw2.lat, sw2.lng);\r\n\t\t\tthis._northEast = new LatLng(ne2.lat, ne2.lng);\r\n\t\t} else {\r\n\t\t\tsw.lat = Math.min(sw2.lat, sw.lat);\r\n\t\t\tsw.lng = Math.min(sw2.lng, sw.lng);\r\n\t\t\tne.lat = Math.max(ne2.lat, ne.lat);\r\n\t\t\tne.lng = Math.max(ne2.lng, ne.lng);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method pad(bufferRatio: Number): LatLngBounds\r\n\t// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.\r\n\t// For example, a ratio of 0.5 extends the bounds by 50% in each direction.\r\n\t// Negative values will retract the bounds.\r\n\tpad: function (bufferRatio) {\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,\r\n\t\t widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;\r\n\r\n\t\treturn new LatLngBounds(\r\n\t\t new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),\r\n\t\t new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));\r\n\t},\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function () {\r\n\t\treturn new LatLng(\r\n\t\t (this._southWest.lat + this._northEast.lat) / 2,\r\n\t\t (this._southWest.lng + this._northEast.lng) / 2);\r\n\t},\r\n\r\n\t// @method getSouthWest(): LatLng\r\n\t// Returns the south-west point of the bounds.\r\n\tgetSouthWest: function () {\r\n\t\treturn this._southWest;\r\n\t},\r\n\r\n\t// @method getNorthEast(): LatLng\r\n\t// Returns the north-east point of the bounds.\r\n\tgetNorthEast: function () {\r\n\t\treturn this._northEast;\r\n\t},\r\n\r\n\t// @method getNorthWest(): LatLng\r\n\t// Returns the north-west point of the bounds.\r\n\tgetNorthWest: function () {\r\n\t\treturn new LatLng(this.getNorth(), this.getWest());\r\n\t},\r\n\r\n\t// @method getSouthEast(): LatLng\r\n\t// Returns the south-east point of the bounds.\r\n\tgetSouthEast: function () {\r\n\t\treturn new LatLng(this.getSouth(), this.getEast());\r\n\t},\r\n\r\n\t// @method getWest(): Number\r\n\t// Returns the west longitude of the bounds\r\n\tgetWest: function () {\r\n\t\treturn this._southWest.lng;\r\n\t},\r\n\r\n\t// @method getSouth(): Number\r\n\t// Returns the south latitude of the bounds\r\n\tgetSouth: function () {\r\n\t\treturn this._southWest.lat;\r\n\t},\r\n\r\n\t// @method getEast(): Number\r\n\t// Returns the east longitude of the bounds\r\n\tgetEast: function () {\r\n\t\treturn this._northEast.lng;\r\n\t},\r\n\r\n\t// @method getNorth(): Number\r\n\t// Returns the north latitude of the bounds\r\n\tgetNorth: function () {\r\n\t\treturn this._northEast.lat;\r\n\t},\r\n\r\n\t// @method contains(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\r\n\t// @alternative\r\n\t// @method contains (latlng: LatLng): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {\r\n\t\t\tobj = toLatLng(obj);\r\n\t\t} else {\r\n\t\t\tobj = toLatLngBounds(obj);\r\n\t\t}\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2, ne2;\r\n\r\n\t\tif (obj instanceof LatLngBounds) {\r\n\t\t\tsw2 = obj.getSouthWest();\r\n\t\t\tne2 = obj.getNorthEast();\r\n\t\t} else {\r\n\t\t\tsw2 = ne2 = obj;\r\n\t\t}\r\n\r\n\t\treturn (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&\r\n\t\t (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.\r\n\tintersects: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2 = bounds.getSouthWest(),\r\n\t\t ne2 = bounds.getNorthEast(),\r\n\r\n\t\t latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),\r\n\t\t lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);\r\n\r\n\t\treturn latIntersects && lngIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.\r\n\toverlaps: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2 = bounds.getSouthWest(),\r\n\t\t ne2 = bounds.getNorthEast(),\r\n\r\n\t\t latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),\r\n\t\t lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);\r\n\r\n\t\treturn latOverlaps && lngOverlaps;\r\n\t},\r\n\r\n\t// @method toBBoxString(): String\r\n\t// Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.\r\n\ttoBBoxString: function () {\r\n\t\treturn [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');\r\n\t},\r\n\r\n\t// @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean\r\n\t// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.\r\n\tequals: function (bounds, maxMargin) {\r\n\t\tif (!bounds) { return false; }\r\n\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\treturn this._southWest.equals(bounds.getSouthWest(), maxMargin) &&\r\n\t\t this._northEast.equals(bounds.getNorthEast(), maxMargin);\r\n\t},\r\n\r\n\t// @method isValid(): Boolean\r\n\t// Returns `true` if the bounds are properly initialized.\r\n\tisValid: function () {\r\n\t\treturn !!(this._southWest && this._northEast);\r\n\t}\r\n};\r\n\r\n// TODO International date line?\r\n\r\n// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)\r\n// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.\r\n\r\n// @alternative\r\n// @factory L.latLngBounds(latlngs: LatLng[])\r\n// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).\r\nexport function toLatLngBounds(a, b) {\r\n\tif (a instanceof LatLngBounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new LatLngBounds(a, b);\r\n}\r\n","import * as Util from '../core/Util';\r\nimport {Earth} from './crs/CRS.Earth';\r\nimport {toLatLngBounds} from './LatLngBounds';\r\n\r\n/* @class LatLng\r\n * @aka L.LatLng\r\n *\r\n * Represents a geographical point with a certain latitude and longitude.\r\n *\r\n * @example\r\n *\r\n * ```\r\n * var latlng = L.latLng(50.5, 30.5);\r\n * ```\r\n *\r\n * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:\r\n *\r\n * ```\r\n * map.panTo([50, 30]);\r\n * map.panTo({lon: 30, lat: 50});\r\n * map.panTo({lat: 50, lng: 30});\r\n * map.panTo(L.latLng(50, 30));\r\n * ```\r\n *\r\n * Note that `LatLng` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function LatLng(lat, lng, alt) {\r\n\tif (isNaN(lat) || isNaN(lng)) {\r\n\t\tthrow new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\r\n\t}\r\n\r\n\t// @property lat: Number\r\n\t// Latitude in degrees\r\n\tthis.lat = +lat;\r\n\r\n\t// @property lng: Number\r\n\t// Longitude in degrees\r\n\tthis.lng = +lng;\r\n\r\n\t// @property alt: Number\r\n\t// Altitude in meters (optional)\r\n\tif (alt !== undefined) {\r\n\t\tthis.alt = +alt;\r\n\t}\r\n}\r\n\r\nLatLng.prototype = {\r\n\t// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean\r\n\t// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.\r\n\tequals: function (obj, maxMargin) {\r\n\t\tif (!obj) { return false; }\r\n\r\n\t\tobj = toLatLng(obj);\r\n\r\n\t\tvar margin = Math.max(\r\n\t\t Math.abs(this.lat - obj.lat),\r\n\t\t Math.abs(this.lng - obj.lng));\r\n\r\n\t\treturn margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point (for debugging purposes).\r\n\ttoString: function (precision) {\r\n\t\treturn 'LatLng(' +\r\n\t\t Util.formatNum(this.lat, precision) + ', ' +\r\n\t\t Util.formatNum(this.lng, precision) + ')';\r\n\t},\r\n\r\n\t// @method distanceTo(otherLatLng: LatLng): Number\r\n\t// Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).\r\n\tdistanceTo: function (other) {\r\n\t\treturn Earth.distance(this, toLatLng(other));\r\n\t},\r\n\r\n\t// @method wrap(): LatLng\r\n\t// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.\r\n\twrap: function () {\r\n\t\treturn Earth.wrapLatLng(this);\r\n\t},\r\n\r\n\t// @method toBounds(sizeInMeters: Number): LatLngBounds\r\n\t// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.\r\n\ttoBounds: function (sizeInMeters) {\r\n\t\tvar latAccuracy = 180 * sizeInMeters / 40075017,\r\n\t\t lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);\r\n\r\n\t\treturn toLatLngBounds(\r\n\t\t [this.lat - latAccuracy, this.lng - lngAccuracy],\r\n\t\t [this.lat + latAccuracy, this.lng + lngAccuracy]);\r\n\t},\r\n\r\n\tclone: function () {\r\n\t\treturn new LatLng(this.lat, this.lng, this.alt);\r\n\t}\r\n};\r\n\r\n\r\n\r\n// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng\r\n// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Array): LatLng\r\n// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Object): LatLng\r\n// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.\r\n\r\nexport function toLatLng(a, b, c) {\r\n\tif (a instanceof LatLng) {\r\n\t\treturn a;\r\n\t}\r\n\tif (Util.isArray(a) && typeof a[0] !== 'object') {\r\n\t\tif (a.length === 3) {\r\n\t\t\treturn new LatLng(a[0], a[1], a[2]);\r\n\t\t}\r\n\t\tif (a.length === 2) {\r\n\t\t\treturn new LatLng(a[0], a[1]);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\tif (a === undefined || a === null) {\r\n\t\treturn a;\r\n\t}\r\n\tif (typeof a === 'object' && 'lat' in a) {\r\n\t\treturn new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);\r\n\t}\r\n\tif (b === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\treturn new LatLng(a, b, c);\r\n}\r\n","\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {LatLng} from '../LatLng';\r\nimport {LatLngBounds} from '../LatLngBounds';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.Base\r\n * Object that defines coordinate reference systems for projecting\r\n * geographical points into pixel (screen) coordinates and back (and to\r\n * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See\r\n * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system).\r\n *\r\n * Leaflet defines the most usual CRSs by default. If you want to use a\r\n * CRS not defined by default, take a look at the\r\n * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.\r\n *\r\n * Note that the CRS instances do not inherit from Leaflet's `Class` object,\r\n * and can't be instantiated. Also, new classes can't inherit from them,\r\n * and methods can't be added to them with the `include` function.\r\n */\r\n\r\nexport var CRS = {\r\n\t// @method latLngToPoint(latlng: LatLng, zoom: Number): Point\r\n\t// Projects geographical coordinates into pixel coordinates for a given zoom.\r\n\tlatLngToPoint: function (latlng, zoom) {\r\n\t\tvar projectedPoint = this.projection.project(latlng),\r\n\t\t scale = this.scale(zoom);\r\n\r\n\t\treturn this.transformation._transform(projectedPoint, scale);\r\n\t},\r\n\r\n\t// @method pointToLatLng(point: Point, zoom: Number): LatLng\r\n\t// The inverse of `latLngToPoint`. Projects pixel coordinates on a given\r\n\t// zoom into geographical coordinates.\r\n\tpointToLatLng: function (point, zoom) {\r\n\t\tvar scale = this.scale(zoom),\r\n\t\t untransformedPoint = this.transformation.untransform(point, scale);\r\n\r\n\t\treturn this.projection.unproject(untransformedPoint);\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng): Point\r\n\t// Projects geographical coordinates into coordinates in units accepted for\r\n\t// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).\r\n\tproject: function (latlng) {\r\n\t\treturn this.projection.project(latlng);\r\n\t},\r\n\r\n\t// @method unproject(point: Point): LatLng\r\n\t// Given a projected coordinate returns the corresponding LatLng.\r\n\t// The inverse of `project`.\r\n\tunproject: function (point) {\r\n\t\treturn this.projection.unproject(point);\r\n\t},\r\n\r\n\t// @method scale(zoom: Number): Number\r\n\t// Returns the scale used when transforming projected coordinates into\r\n\t// pixel coordinates for a particular zoom. For example, it returns\r\n\t// `256 * 2^zoom` for Mercator-based CRS.\r\n\tscale: function (zoom) {\r\n\t\treturn 256 * Math.pow(2, zoom);\r\n\t},\r\n\r\n\t// @method zoom(scale: Number): Number\r\n\t// Inverse of `scale()`, returns the zoom level corresponding to a scale\r\n\t// factor of `scale`.\r\n\tzoom: function (scale) {\r\n\t\treturn Math.log(scale / 256) / Math.LN2;\r\n\t},\r\n\r\n\t// @method getProjectedBounds(zoom: Number): Bounds\r\n\t// Returns the projection's bounds scaled and transformed for the provided `zoom`.\r\n\tgetProjectedBounds: function (zoom) {\r\n\t\tif (this.infinite) { return null; }\r\n\r\n\t\tvar b = this.projection.bounds,\r\n\t\t s = this.scale(zoom),\r\n\t\t min = this.transformation.transform(b.min, s),\r\n\t\t max = this.transformation.transform(b.max, s);\r\n\r\n\t\treturn new Bounds(min, max);\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates.\r\n\r\n\t// @property code: String\r\n\t// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)\r\n\t//\r\n\t// @property wrapLng: Number[]\r\n\t// An array of two numbers defining whether the longitude (horizontal) coordinate\r\n\t// axis wraps around a given range and how. Defaults to `[-180, 180]` in most\r\n\t// geographical CRSs. If `undefined`, the longitude axis does not wrap around.\r\n\t//\r\n\t// @property wrapLat: Number[]\r\n\t// Like `wrapLng`, but for the latitude (vertical) axis.\r\n\r\n\t// wrapLng: [min, max],\r\n\t// wrapLat: [min, max],\r\n\r\n\t// @property infinite: Boolean\r\n\t// If true, the coordinate space will be unbounded (infinite in both axes)\r\n\tinfinite: false,\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where lat and lng has been wrapped according to the\r\n\t// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.\r\n\twrapLatLng: function (latlng) {\r\n\t\tvar lng = this.wrapLng ? Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,\r\n\t\t lat = this.wrapLat ? Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,\r\n\t\t alt = latlng.alt;\r\n\r\n\t\treturn new LatLng(lat, lng, alt);\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring\r\n\t// that its center is within the CRS's bounds.\r\n\t// Only accepts actual `L.LatLngBounds` instances, not arrays.\r\n\twrapLatLngBounds: function (bounds) {\r\n\t\tvar center = bounds.getCenter(),\r\n\t\t newCenter = this.wrapLatLng(center),\r\n\t\t latShift = center.lat - newCenter.lat,\r\n\t\t lngShift = center.lng - newCenter.lng;\r\n\r\n\t\tif (latShift === 0 && lngShift === 0) {\r\n\t\t\treturn bounds;\r\n\t\t}\r\n\r\n\t\tvar sw = bounds.getSouthWest(),\r\n\t\t ne = bounds.getNorthEast(),\r\n\t\t newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),\r\n\t\t newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);\r\n\r\n\t\treturn new LatLngBounds(newSw, newNe);\r\n\t}\r\n};\r\n","import {CRS} from './CRS';\nimport * as Util from '../../core/Util';\n\n/*\n * @namespace CRS\n * @crs L.CRS.Earth\n *\n * Serves as the base for CRS that are global such that they cover the earth.\n * Can only be used as the base for other CRS and cannot be used directly,\n * since it does not have a `code`, `projection` or `transformation`. `distance()` returns\n * meters.\n */\n\nexport var Earth = Util.extend({}, CRS, {\n\twrapLng: [-180, 180],\n\n\t// Mean Earth Radius, as recommended for use by\n\t// the International Union of Geodesy and Geophysics,\n\t// see https://rosettacode.org/wiki/Haversine_formula\n\tR: 6371000,\n\n\t// distance between two geographical points using spherical law of cosines approximation\n\tdistance: function (latlng1, latlng2) {\n\t\tvar rad = Math.PI / 180,\n\t\t lat1 = latlng1.lat * rad,\n\t\t lat2 = latlng2.lat * rad,\n\t\t sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),\n\t\t sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),\n\t\t a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,\n\t\t c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\t\treturn this.R * c;\n\t}\n});\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @projection L.Projection.SphericalMercator\r\n *\r\n * Spherical Mercator projection — the most common projection for online maps,\r\n * used by almost all free and commercial tile providers. Assumes that Earth is\r\n * a sphere. Used by the `EPSG:3857` CRS.\r\n */\r\n\r\nvar earthRadius = 6378137;\r\n\r\nexport var SphericalMercator = {\r\n\r\n\tR: earthRadius,\r\n\tMAX_LATITUDE: 85.0511287798,\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t max = this.MAX_LATITUDE,\r\n\t\t lat = Math.max(Math.min(max, latlng.lat), -max),\r\n\t\t sin = Math.sin(lat * d);\r\n\r\n\t\treturn new Point(\r\n\t\t\tthis.R * latlng.lng * d,\r\n\t\t\tthis.R * Math.log((1 + sin) / (1 - sin)) / 2);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI;\r\n\r\n\t\treturn new LatLng(\r\n\t\t\t(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,\r\n\t\t\tpoint.x * d / this.R);\r\n\t},\r\n\r\n\tbounds: (function () {\r\n\t\tvar d = earthRadius * Math.PI;\r\n\t\treturn new Bounds([-d, -d], [d, d]);\r\n\t})()\r\n};\r\n","import {Point} from './Point';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class Transformation\r\n * @aka L.Transformation\r\n *\r\n * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`\r\n * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing\r\n * the reverse. Used by Leaflet in its projections code.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var transformation = L.transformation(2, 5, -1, 10),\r\n * \tp = L.point(1, 2),\r\n * \tp2 = transformation.transform(p), // L.point(7, 8)\r\n * \tp3 = transformation.untransform(p2); // L.point(1, 2)\r\n * ```\r\n */\r\n\r\n\r\n// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)\r\n// Creates a `Transformation` object with the given coefficients.\r\nexport function Transformation(a, b, c, d) {\r\n\tif (Util.isArray(a)) {\r\n\t\t// use array properties\r\n\t\tthis._a = a[0];\r\n\t\tthis._b = a[1];\r\n\t\tthis._c = a[2];\r\n\t\tthis._d = a[3];\r\n\t\treturn;\r\n\t}\r\n\tthis._a = a;\r\n\tthis._b = b;\r\n\tthis._c = c;\r\n\tthis._d = d;\r\n}\r\n\r\nTransformation.prototype = {\r\n\t// @method transform(point: Point, scale?: Number): Point\r\n\t// Returns a transformed point, optionally multiplied by the given scale.\r\n\t// Only accepts actual `L.Point` instances, not arrays.\r\n\ttransform: function (point, scale) { // (Point, Number) -> Point\r\n\t\treturn this._transform(point.clone(), scale);\r\n\t},\r\n\r\n\t// destructive transform (faster)\r\n\t_transform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\tpoint.x = scale * (this._a * point.x + this._b);\r\n\t\tpoint.y = scale * (this._c * point.y + this._d);\r\n\t\treturn point;\r\n\t},\r\n\r\n\t// @method untransform(point: Point, scale?: Number): Point\r\n\t// Returns the reverse transformation of the given point, optionally divided\r\n\t// by the given scale. Only accepts actual `L.Point` instances, not arrays.\r\n\tuntransform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\treturn new Point(\r\n\t\t (point.x / scale - this._b) / this._a,\r\n\t\t (point.y / scale - this._d) / this._c);\r\n\t}\r\n};\r\n\r\n// factory L.transformation(a: Number, b: Number, c: Number, d: Number)\r\n\r\n// @factory L.transformation(a: Number, b: Number, c: Number, d: Number)\r\n// Instantiates a Transformation object with the given coefficients.\r\n\r\n// @alternative\r\n// @factory L.transformation(coefficients: Array): Transformation\r\n// Expects an coefficients array of the form\r\n// `[a: Number, b: Number, c: Number, d: Number]`.\r\n\r\nexport function toTransformation(a, b, c, d) {\r\n\treturn new Transformation(a, b, c, d);\r\n}\r\n","import {Earth} from './CRS.Earth';\r\nimport {SphericalMercator} from '../projection/Projection.SphericalMercator';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3857\r\n *\r\n * The most common CRS for online maps, used by almost all free and commercial\r\n * tile providers. Uses Spherical Mercator projection. Set in by default in\r\n * Map's `crs` option.\r\n */\r\n\r\nexport var EPSG3857 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:3857',\r\n\tprojection: SphericalMercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * SphericalMercator.R);\r\n\t\treturn toTransformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n\r\nexport var EPSG900913 = Util.extend({}, EPSG3857, {\r\n\tcode: 'EPSG:900913'\r\n});\r\n","import Browser from '../../core/Browser';\n\n// @namespace SVG; @section\n// There are several static functions which can be called without instantiating L.SVG:\n\n// @function create(name: String): SVGElement\n// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),\n// corresponding to the class name passed. For example, using 'line' will return\n// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).\nexport function svgCreate(name) {\n\treturn document.createElementNS('http://www.w3.org/2000/svg', name);\n}\n\n// @function pointsToPath(rings: Point[], closed: Boolean): String\n// Generates a SVG path string for multiple rings, with each ring turning\n// into \"M..L..L..\" instructions\nexport function pointsToPath(rings, closed) {\n\tvar str = '',\n\ti, j, len, len2, points, p;\n\n\tfor (i = 0, len = rings.length; i < len; i++) {\n\t\tpoints = rings[i];\n\n\t\tfor (j = 0, len2 = points.length; j < len2; j++) {\n\t\t\tp = points[j];\n\t\t\tstr += (j ? 'L' : 'M') + p.x + ' ' + p.y;\n\t\t}\n\n\t\t// closes the ring for polygons; \"x\" is VML syntax\n\t\tstr += closed ? (Browser.svg ? 'z' : 'x') : '';\n\t}\n\n\t// SVG complains about empty path strings\n\treturn str || 'M0 0';\n}\n\n\n\n\n","import * as Util from './Util';\r\nimport {svgCreate} from '../layer/vector/SVG.Util';\r\n\r\n/*\r\n * @namespace Browser\r\n * @aka L.Browser\r\n *\r\n * A namespace with static properties for browser/feature detection used by Leaflet internally.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * if (L.Browser.ielt9) {\r\n * alert('Upgrade your browser, dude!');\r\n * }\r\n * ```\r\n */\r\n\r\nvar style = document.documentElement.style;\r\n\r\n// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).\r\nvar ie = 'ActiveXObject' in window;\r\n\r\n// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.\r\nvar ielt9 = ie && !document.addEventListener;\r\n\r\n// @property edge: Boolean; `true` for the Edge web browser.\r\nvar edge = 'msLaunchUri' in navigator && !('documentMode' in document);\r\n\r\n// @property webkit: Boolean;\r\n// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).\r\nvar webkit = userAgentContains('webkit');\r\n\r\n// @property android: Boolean\r\n// **Deprecated.** `true` for any browser running on an Android platform.\r\nvar android = userAgentContains('android');\r\n\r\n// @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3.\r\nvar android23 = userAgentContains('android 2') || userAgentContains('android 3');\r\n\r\n/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */\r\nvar webkitVer = parseInt(/WebKit\\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit\r\n// @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome)\r\nvar androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);\r\n\r\n// @property opera: Boolean; `true` for the Opera browser\r\nvar opera = !!window.opera;\r\n\r\n// @property chrome: Boolean; `true` for the Chrome browser.\r\nvar chrome = !edge && userAgentContains('chrome');\r\n\r\n// @property gecko: Boolean; `true` for gecko-based browsers like Firefox.\r\nvar gecko = userAgentContains('gecko') && !webkit && !opera && !ie;\r\n\r\n// @property safari: Boolean; `true` for the Safari browser.\r\nvar safari = !chrome && userAgentContains('safari');\r\n\r\nvar phantom = userAgentContains('phantom');\r\n\r\n// @property opera12: Boolean\r\n// `true` for the Opera browser supporting CSS transforms (version 12 or later).\r\nvar opera12 = 'OTransition' in style;\r\n\r\n// @property win: Boolean; `true` when the browser is running in a Windows platform\r\nvar win = navigator.platform.indexOf('Win') === 0;\r\n\r\n// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.\r\nvar ie3d = ie && ('transition' in style);\r\n\r\n// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.\r\nvar webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;\r\n\r\n// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.\r\nvar gecko3d = 'MozPerspective' in style;\r\n\r\n// @property any3d: Boolean\r\n// `true` for all browsers supporting CSS transforms.\r\nvar any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;\r\n\r\n// @property mobile: Boolean; `true` for all browsers running in a mobile device.\r\nvar mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');\r\n\r\n// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.\r\nvar mobileWebkit = mobile && webkit;\r\n\r\n// @property mobileWebkit3d: Boolean\r\n// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.\r\nvar mobileWebkit3d = mobile && webkit3d;\r\n\r\n// @property msPointer: Boolean\r\n// `true` for browsers implementing the Microsoft touch events model (notably IE10).\r\nvar msPointer = !window.PointerEvent && window.MSPointerEvent;\r\n\r\n// @property pointer: Boolean\r\n// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).\r\nvar pointer = !!(window.PointerEvent || msPointer);\r\n\r\n// @property touchNative: Boolean\r\n// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).\r\n// **This does not necessarily mean** that the browser is running in a computer with\r\n// a touchscreen, it only means that the browser is capable of understanding\r\n// touch events.\r\nvar touchNative = 'ontouchstart' in window || !!window.TouchEvent;\r\n\r\n// @property touch: Boolean\r\n// `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events.\r\n// Note: pointer events will be preferred (if available), and processed for all `touch*` listeners.\r\nvar touch = !window.L_NO_TOUCH && (touchNative || pointer);\r\n\r\n// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.\r\nvar mobileOpera = mobile && opera;\r\n\r\n// @property mobileGecko: Boolean\r\n// `true` for gecko-based browsers running in a mobile device.\r\nvar mobileGecko = mobile && gecko;\r\n\r\n// @property retina: Boolean\r\n// `true` for browsers on a high-resolution \"retina\" screen or on any screen when browser's display zoom is more than 100%.\r\nvar retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;\r\n\r\n// @property passiveEvents: Boolean\r\n// `true` for browsers that support passive events.\r\nvar passiveEvents = (function () {\r\n\tvar supportsPassiveOption = false;\r\n\ttry {\r\n\t\tvar opts = Object.defineProperty({}, 'passive', {\r\n\t\t\tget: function () { // eslint-disable-line getter-return\r\n\t\t\t\tsupportsPassiveOption = true;\r\n\t\t\t}\r\n\t\t});\r\n\t\twindow.addEventListener('testPassiveEventSupport', Util.falseFn, opts);\r\n\t\twindow.removeEventListener('testPassiveEventSupport', Util.falseFn, opts);\r\n\t} catch (e) {\r\n\t\t// Errors can safely be ignored since this is only a browser support test.\r\n\t}\r\n\treturn supportsPassiveOption;\r\n}());\r\n\r\n// @property canvas: Boolean\r\n// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\r\nvar canvas = (function () {\r\n\treturn !!document.createElement('canvas').getContext;\r\n}());\r\n\r\n// @property svg: Boolean\r\n// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).\r\nvar svg = !!(document.createElementNS && svgCreate('svg').createSVGRect);\r\n\r\nvar inlineSvg = !!svg && (function () {\r\n\tvar div = document.createElement('div');\r\n\tdiv.innerHTML = '<svg/>';\r\n\treturn (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';\r\n})();\r\n\r\n// @property vml: Boolean\r\n// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).\r\nvar vml = !svg && (function () {\r\n\ttry {\r\n\t\tvar div = document.createElement('div');\r\n\t\tdiv.innerHTML = '<v:shape adj=\"1\"/>';\r\n\r\n\t\tvar shape = div.firstChild;\r\n\t\tshape.style.behavior = 'url(#default#VML)';\r\n\r\n\t\treturn shape && (typeof shape.adj === 'object');\r\n\r\n\t} catch (e) {\r\n\t\treturn false;\r\n\t}\r\n}());\r\n\r\n\r\n// @property mac: Boolean; `true` when the browser is running in a Mac platform\r\nvar mac = navigator.platform.indexOf('Mac') === 0;\r\n\r\n// @property mac: Boolean; `true` when the browser is running in a Linux platform\r\nvar linux = navigator.platform.indexOf('Linux') === 0;\r\n\r\nfunction userAgentContains(str) {\r\n\treturn navigator.userAgent.toLowerCase().indexOf(str) >= 0;\r\n}\r\n\r\n\r\nexport default {\r\n\tie: ie,\r\n\tielt9: ielt9,\r\n\tedge: edge,\r\n\twebkit: webkit,\r\n\tandroid: android,\r\n\tandroid23: android23,\r\n\tandroidStock: androidStock,\r\n\topera: opera,\r\n\tchrome: chrome,\r\n\tgecko: gecko,\r\n\tsafari: safari,\r\n\tphantom: phantom,\r\n\topera12: opera12,\r\n\twin: win,\r\n\tie3d: ie3d,\r\n\twebkit3d: webkit3d,\r\n\tgecko3d: gecko3d,\r\n\tany3d: any3d,\r\n\tmobile: mobile,\r\n\tmobileWebkit: mobileWebkit,\r\n\tmobileWebkit3d: mobileWebkit3d,\r\n\tmsPointer: msPointer,\r\n\tpointer: pointer,\r\n\ttouch: touch,\r\n\ttouchNative: touchNative,\r\n\tmobileOpera: mobileOpera,\r\n\tmobileGecko: mobileGecko,\r\n\tretina: retina,\r\n\tpassiveEvents: passiveEvents,\r\n\tcanvas: canvas,\r\n\tsvg: svg,\r\n\tvml: vml,\r\n\tinlineSvg: inlineSvg,\r\n\tmac: mac,\r\n\tlinux: linux\r\n};\r\n","import * as DomEvent from './DomEvent';\nimport Browser from '../core/Browser';\nimport {falseFn} from '../core/Util';\n\n/*\n * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.\n */\n\nvar POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown';\nvar POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove';\nvar POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup';\nvar POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel';\nvar pEvent = {\n\ttouchstart : POINTER_DOWN,\n\ttouchmove : POINTER_MOVE,\n\ttouchend : POINTER_UP,\n\ttouchcancel : POINTER_CANCEL\n};\nvar handle = {\n\ttouchstart : _onPointerStart,\n\ttouchmove : _handlePointer,\n\ttouchend : _handlePointer,\n\ttouchcancel : _handlePointer\n};\nvar _pointers = {};\nvar _pointerDocListener = false;\n\n// Provides a touch events wrapper for (ms)pointer events.\n// ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890\n\nexport function addPointerListener(obj, type, handler) {\n\tif (type === 'touchstart') {\n\t\t_addPointerDocListener();\n\t}\n\tif (!handle[type]) {\n\t\tconsole.warn('wrong event specified:', type);\n\t\treturn falseFn;\n\t}\n\thandler = handle[type].bind(this, handler);\n\tobj.addEventListener(pEvent[type], handler, false);\n\treturn handler;\n}\n\nexport function removePointerListener(obj, type, handler) {\n\tif (!pEvent[type]) {\n\t\tconsole.warn('wrong event specified:', type);\n\t\treturn;\n\t}\n\tobj.removeEventListener(pEvent[type], handler, false);\n}\n\nfunction _globalPointerDown(e) {\n\t_pointers[e.pointerId] = e;\n}\n\nfunction _globalPointerMove(e) {\n\tif (_pointers[e.pointerId]) {\n\t\t_pointers[e.pointerId] = e;\n\t}\n}\n\nfunction _globalPointerUp(e) {\n\tdelete _pointers[e.pointerId];\n}\n\nfunction _addPointerDocListener() {\n\t// need to keep track of what pointers and how many are active to provide e.touches emulation\n\tif (!_pointerDocListener) {\n\t\t// we listen document as any drags that end by moving the touch off the screen get fired there\n\t\tdocument.addEventListener(POINTER_DOWN, _globalPointerDown, true);\n\t\tdocument.addEventListener(POINTER_MOVE, _globalPointerMove, true);\n\t\tdocument.addEventListener(POINTER_UP, _globalPointerUp, true);\n\t\tdocument.addEventListener(POINTER_CANCEL, _globalPointerUp, true);\n\n\t\t_pointerDocListener = true;\n\t}\n}\n\nfunction _handlePointer(handler, e) {\n\tif (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; }\n\n\te.touches = [];\n\tfor (var i in _pointers) {\n\t\te.touches.push(_pointers[i]);\n\t}\n\te.changedTouches = [e];\n\n\thandler(e);\n}\n\nfunction _onPointerStart(handler, e) {\n\t// IE10 specific: MsTouch needs preventDefault. See #2000\n\tif (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {\n\t\tDomEvent.preventDefault(e);\n\t}\n\t_handlePointer(handler, e);\n}\n","import * as DomEvent from './DomEvent';\r\n\r\n/*\r\n * Extends the event handling code with double tap support for mobile browsers.\r\n *\r\n * Note: currently most browsers fire native dblclick, with only a few exceptions\r\n * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)\r\n */\r\n\r\nfunction makeDblclick(event) {\r\n\t// in modern browsers `type` cannot be just overridden:\r\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only\r\n\tvar newEvent = {},\r\n\t prop, i;\r\n\tfor (i in event) {\r\n\t\tprop = event[i];\r\n\t\tnewEvent[i] = prop && prop.bind ? prop.bind(event) : prop;\r\n\t}\r\n\tevent = newEvent;\r\n\tnewEvent.type = 'dblclick';\r\n\tnewEvent.detail = 2;\r\n\tnewEvent.isTrusted = false;\r\n\tnewEvent._simulated = true; // for debug purposes\r\n\treturn newEvent;\r\n}\r\n\r\nvar delay = 200;\r\nexport function addDoubleTapListener(obj, handler) {\r\n\t// Most browsers handle double tap natively\r\n\tobj.addEventListener('dblclick', handler);\r\n\r\n\t// On some platforms the browser doesn't fire native dblclicks for touch events.\r\n\t// It seems that in all such cases `detail` property of `click` event is always `1`.\r\n\t// So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.\r\n\tvar last = 0,\r\n\t detail;\r\n\tfunction simDblclick(e) {\r\n\t\tif (e.detail !== 1) {\r\n\t\t\tdetail = e.detail; // keep in sync to avoid false dblclick in some cases\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.pointerType === 'mouse' ||\r\n\t\t\t(e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// When clicking on an <input>, the browser generates a click on its\r\n\t\t// <label> (and vice versa) triggering two clicks in quick succession.\r\n\t\t// This ignores clicks on elements which are a label with a 'for'\r\n\t\t// attribute (or children of such a label), but not children of\r\n\t\t// a <input>.\r\n\t\tvar path = DomEvent.getPropagationPath(e);\r\n\t\tif (path.some(function (el) {\r\n\t\t\treturn el instanceof HTMLLabelElement && el.attributes.for;\r\n\t\t}) &&\r\n\t\t\t!path.some(function (el) {\r\n\t\t\t\treturn (\r\n\t\t\t\t\tel instanceof HTMLInputElement ||\r\n\t\t\t\t\tel instanceof HTMLSelectElement\r\n\t\t\t\t);\r\n\t\t\t})\r\n\t\t) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar now = Date.now();\r\n\t\tif (now - last <= delay) {\r\n\t\t\tdetail++;\r\n\t\t\tif (detail === 2) {\r\n\t\t\t\thandler(makeDblclick(e));\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdetail = 1;\r\n\t\t}\r\n\t\tlast = now;\r\n\t}\r\n\r\n\tobj.addEventListener('click', simDblclick);\r\n\r\n\treturn {\r\n\t\tdblclick: handler,\r\n\t\tsimDblclick: simDblclick\r\n\t};\r\n}\r\n\r\nexport function removeDoubleTapListener(obj, handlers) {\r\n\tobj.removeEventListener('dblclick', handlers.dblclick);\r\n\tobj.removeEventListener('click', handlers.simDblclick);\r\n}\r\n","import * as DomEvent from './DomEvent';\r\nimport * as Util from '../core/Util';\r\nimport {Point} from '../geometry/Point';\r\nimport Browser from '../core/Browser';\r\n\r\n/*\r\n * @namespace DomUtil\r\n *\r\n * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)\r\n * tree, used by Leaflet internally.\r\n *\r\n * Most functions expecting or returning a `HTMLElement` also work for\r\n * SVG elements. The only difference is that classes refer to CSS classes\r\n * in HTML and SVG classes in SVG.\r\n */\r\n\r\n\r\n// @property TRANSFORM: String\r\n// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).\r\nexport var TRANSFORM = testProp(\r\n\t['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);\r\n\r\n// webkitTransition comes first because some browser versions that drop vendor prefix don't do\r\n// the same for the transitionend event, in particular the Android 4.1 stock browser\r\n\r\n// @property TRANSITION: String\r\n// Vendor-prefixed transition style name.\r\nexport var TRANSITION = testProp(\r\n\t['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);\r\n\r\n// @property TRANSITION_END: String\r\n// Vendor-prefixed transitionend event name.\r\nexport var TRANSITION_END =\r\n\tTRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';\r\n\r\n\r\n// @function get(id: String|HTMLElement): HTMLElement\r\n// Returns an element given its DOM id, or returns the element itself\r\n// if it was passed directly.\r\nexport function get(id) {\r\n\treturn typeof id === 'string' ? document.getElementById(id) : id;\r\n}\r\n\r\n// @function getStyle(el: HTMLElement, styleAttrib: String): String\r\n// Returns the value for a certain style attribute on an element,\r\n// including computed values or values set through CSS.\r\nexport function getStyle(el, style) {\r\n\tvar value = el.style[style] || (el.currentStyle && el.currentStyle[style]);\r\n\r\n\tif ((!value || value === 'auto') && document.defaultView) {\r\n\t\tvar css = document.defaultView.getComputedStyle(el, null);\r\n\t\tvalue = css ? css[style] : null;\r\n\t}\r\n\treturn value === 'auto' ? null : value;\r\n}\r\n\r\n// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement\r\n// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.\r\nexport function create(tagName, className, container) {\r\n\tvar el = document.createElement(tagName);\r\n\tel.className = className || '';\r\n\r\n\tif (container) {\r\n\t\tcontainer.appendChild(el);\r\n\t}\r\n\treturn el;\r\n}\r\n\r\n// @function remove(el: HTMLElement)\r\n// Removes `el` from its parent element\r\nexport function remove(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent) {\r\n\t\tparent.removeChild(el);\r\n\t}\r\n}\r\n\r\n// @function empty(el: HTMLElement)\r\n// Removes all of `el`'s children elements from `el`\r\nexport function empty(el) {\r\n\twhile (el.firstChild) {\r\n\t\tel.removeChild(el.firstChild);\r\n\t}\r\n}\r\n\r\n// @function toFront(el: HTMLElement)\r\n// Makes `el` the last child of its parent, so it renders in front of the other children.\r\nexport function toFront(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent && parent.lastChild !== el) {\r\n\t\tparent.appendChild(el);\r\n\t}\r\n}\r\n\r\n// @function toBack(el: HTMLElement)\r\n// Makes `el` the first child of its parent, so it renders behind the other children.\r\nexport function toBack(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent && parent.firstChild !== el) {\r\n\t\tparent.insertBefore(el, parent.firstChild);\r\n\t}\r\n}\r\n\r\n// @function hasClass(el: HTMLElement, name: String): Boolean\r\n// Returns `true` if the element's class attribute contains `name`.\r\nexport function hasClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\treturn el.classList.contains(name);\r\n\t}\r\n\tvar className = getClass(el);\r\n\treturn className.length > 0 && new RegExp('(^|\\\\s)' + name + '(\\\\s|$)').test(className);\r\n}\r\n\r\n// @function addClass(el: HTMLElement, name: String)\r\n// Adds `name` to the element's class attribute.\r\nexport function addClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\tvar classes = Util.splitWords(name);\r\n\t\tfor (var i = 0, len = classes.length; i < len; i++) {\r\n\t\t\tel.classList.add(classes[i]);\r\n\t\t}\r\n\t} else if (!hasClass(el, name)) {\r\n\t\tvar className = getClass(el);\r\n\t\tsetClass(el, (className ? className + ' ' : '') + name);\r\n\t}\r\n}\r\n\r\n// @function removeClass(el: HTMLElement, name: String)\r\n// Removes `name` from the element's class attribute.\r\nexport function removeClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\tel.classList.remove(name);\r\n\t} else {\r\n\t\tsetClass(el, Util.trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));\r\n\t}\r\n}\r\n\r\n// @function setClass(el: HTMLElement, name: String)\r\n// Sets the element's class.\r\nexport function setClass(el, name) {\r\n\tif (el.className.baseVal === undefined) {\r\n\t\tel.className = name;\r\n\t} else {\r\n\t\t// in case of SVG element\r\n\t\tel.className.baseVal = name;\r\n\t}\r\n}\r\n\r\n// @function getClass(el: HTMLElement): String\r\n// Returns the element's class.\r\nexport function getClass(el) {\r\n\t// Check if the element is an SVGElementInstance and use the correspondingElement instead\r\n\t// (Required for linked SVG elements in IE11.)\r\n\tif (el.correspondingElement) {\r\n\t\tel = el.correspondingElement;\r\n\t}\r\n\treturn el.className.baseVal === undefined ? el.className : el.className.baseVal;\r\n}\r\n\r\n// @function setOpacity(el: HTMLElement, opacity: Number)\r\n// Set the opacity of an element (including old IE support).\r\n// `opacity` must be a number from `0` to `1`.\r\nexport function setOpacity(el, value) {\r\n\tif ('opacity' in el.style) {\r\n\t\tel.style.opacity = value;\r\n\t} else if ('filter' in el.style) {\r\n\t\t_setOpacityIE(el, value);\r\n\t}\r\n}\r\n\r\nfunction _setOpacityIE(el, value) {\r\n\tvar filter = false,\r\n\t filterName = 'DXImageTransform.Microsoft.Alpha';\r\n\r\n\t// filters collection throws an error if we try to retrieve a filter that doesn't exist\r\n\ttry {\r\n\t\tfilter = el.filters.item(filterName);\r\n\t} catch (e) {\r\n\t\t// don't set opacity to 1 if we haven't already set an opacity,\r\n\t\t// it isn't needed and breaks transparent pngs.\r\n\t\tif (value === 1) { return; }\r\n\t}\r\n\r\n\tvalue = Math.round(value * 100);\r\n\r\n\tif (filter) {\r\n\t\tfilter.Enabled = (value !== 100);\r\n\t\tfilter.Opacity = value;\r\n\t} else {\r\n\t\tel.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';\r\n\t}\r\n}\r\n\r\n// @function testProp(props: String[]): String|false\r\n// Goes through the array of style names and returns the first name\r\n// that is a valid style name for an element. If no such name is found,\r\n// it returns false. Useful for vendor-prefixed styles like `transform`.\r\nexport function testProp(props) {\r\n\tvar style = document.documentElement.style;\r\n\r\n\tfor (var i = 0; i < props.length; i++) {\r\n\t\tif (props[i] in style) {\r\n\t\t\treturn props[i];\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n\r\n// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)\r\n// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels\r\n// and optionally scaled by `scale`. Does not have an effect if the\r\n// browser doesn't support 3D CSS transforms.\r\nexport function setTransform(el, offset, scale) {\r\n\tvar pos = offset || new Point(0, 0);\r\n\r\n\tel.style[TRANSFORM] =\r\n\t\t(Browser.ie3d ?\r\n\t\t\t'translate(' + pos.x + 'px,' + pos.y + 'px)' :\r\n\t\t\t'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +\r\n\t\t(scale ? ' scale(' + scale + ')' : '');\r\n}\r\n\r\n// @function setPosition(el: HTMLElement, position: Point)\r\n// Sets the position of `el` to coordinates specified by `position`,\r\n// using CSS translate or top/left positioning depending on the browser\r\n// (used by Leaflet internally to position its layers).\r\nexport function setPosition(el, point) {\r\n\r\n\t/*eslint-disable */\r\n\tel._leaflet_pos = point;\r\n\t/* eslint-enable */\r\n\r\n\tif (Browser.any3d) {\r\n\t\tsetTransform(el, point);\r\n\t} else {\r\n\t\tel.style.left = point.x + 'px';\r\n\t\tel.style.top = point.y + 'px';\r\n\t}\r\n}\r\n\r\n// @function getPosition(el: HTMLElement): Point\r\n// Returns the coordinates of an element previously positioned with setPosition.\r\nexport function getPosition(el) {\r\n\t// this method is only used for elements previously positioned using setPosition,\r\n\t// so it's safe to cache the position for performance\r\n\r\n\treturn el._leaflet_pos || new Point(0, 0);\r\n}\r\n\r\n// @function disableTextSelection()\r\n// Prevents the user from generating `selectstart` DOM events, usually generated\r\n// when the user drags the mouse through a page with text. Used internally\r\n// by Leaflet to override the behaviour of any click-and-drag interaction on\r\n// the map. Affects drag interactions on the whole document.\r\n\r\n// @function enableTextSelection()\r\n// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).\r\nexport var disableTextSelection;\r\nexport var enableTextSelection;\r\nvar _userSelect;\r\nif ('onselectstart' in document) {\r\n\tdisableTextSelection = function () {\r\n\t\tDomEvent.on(window, 'selectstart', DomEvent.preventDefault);\r\n\t};\r\n\tenableTextSelection = function () {\r\n\t\tDomEvent.off(window, 'selectstart', DomEvent.preventDefault);\r\n\t};\r\n} else {\r\n\tvar userSelectProperty = testProp(\r\n\t\t['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);\r\n\r\n\tdisableTextSelection = function () {\r\n\t\tif (userSelectProperty) {\r\n\t\t\tvar style = document.documentElement.style;\r\n\t\t\t_userSelect = style[userSelectProperty];\r\n\t\t\tstyle[userSelectProperty] = 'none';\r\n\t\t}\r\n\t};\r\n\tenableTextSelection = function () {\r\n\t\tif (userSelectProperty) {\r\n\t\t\tdocument.documentElement.style[userSelectProperty] = _userSelect;\r\n\t\t\t_userSelect = undefined;\r\n\t\t}\r\n\t};\r\n}\r\n\r\n// @function disableImageDrag()\r\n// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but\r\n// for `dragstart` DOM events, usually generated when the user drags an image.\r\nexport function disableImageDrag() {\r\n\tDomEvent.on(window, 'dragstart', DomEvent.preventDefault);\r\n}\r\n\r\n// @function enableImageDrag()\r\n// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).\r\nexport function enableImageDrag() {\r\n\tDomEvent.off(window, 'dragstart', DomEvent.preventDefault);\r\n}\r\n\r\nvar _outlineElement, _outlineStyle;\r\n// @function preventOutline(el: HTMLElement)\r\n// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)\r\n// of the element `el` invisible. Used internally by Leaflet to prevent\r\n// focusable elements from displaying an outline when the user performs a\r\n// drag interaction on them.\r\nexport function preventOutline(element) {\r\n\twhile (element.tabIndex === -1) {\r\n\t\telement = element.parentNode;\r\n\t}\r\n\tif (!element.style) { return; }\r\n\trestoreOutline();\r\n\t_outlineElement = element;\r\n\t_outlineStyle = element.style.outline;\r\n\telement.style.outline = 'none';\r\n\tDomEvent.on(window, 'keydown', restoreOutline);\r\n}\r\n\r\n// @function restoreOutline()\r\n// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().\r\nexport function restoreOutline() {\r\n\tif (!_outlineElement) { return; }\r\n\t_outlineElement.style.outline = _outlineStyle;\r\n\t_outlineElement = undefined;\r\n\t_outlineStyle = undefined;\r\n\tDomEvent.off(window, 'keydown', restoreOutline);\r\n}\r\n\r\n// @function getSizedParentNode(el: HTMLElement): HTMLElement\r\n// Finds the closest parent node which size (width and height) is not null.\r\nexport function getSizedParentNode(element) {\r\n\tdo {\r\n\t\telement = element.parentNode;\r\n\t} while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);\r\n\treturn element;\r\n}\r\n\r\n// @function getScale(el: HTMLElement): Object\r\n// Computes the CSS scale currently applied on the element.\r\n// Returns an object with `x` and `y` members as horizontal and vertical scales respectively,\r\n// and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).\r\nexport function getScale(element) {\r\n\tvar rect = element.getBoundingClientRect(); // Read-only in old browsers.\r\n\r\n\treturn {\r\n\t\tx: rect.width / element.offsetWidth || 1,\r\n\t\ty: rect.height / element.offsetHeight || 1,\r\n\t\tboundingClientRect: rect\r\n\t};\r\n}\r\n","import {Point} from '../geometry/Point';\r\nimport * as Util from '../core/Util';\r\nimport Browser from '../core/Browser';\r\nimport {addPointerListener, removePointerListener} from './DomEvent.Pointer';\r\nimport {addDoubleTapListener, removeDoubleTapListener} from './DomEvent.DoubleTap';\r\nimport {getScale} from './DomUtil';\r\n\r\n/*\r\n * @namespace DomEvent\r\n * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.\r\n */\r\n\r\n// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.\r\n\r\n// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n// Adds a listener function (`fn`) to a particular DOM event type of the\r\n// element `el`. You can optionally specify the context of the listener\r\n// (object the `this` keyword will point to). You can also pass several\r\n// space-separated types (e.g. `'click dblclick'`).\r\n\r\n// @alternative\r\n// @function on(el: HTMLElement, eventMap: Object, context?: Object): this\r\n// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\nexport function on(obj, types, fn, context) {\r\n\r\n\tif (types && typeof types === 'object') {\r\n\t\tfor (var type in types) {\r\n\t\t\taddOne(obj, type, types[type], fn);\r\n\t\t}\r\n\t} else {\r\n\t\ttypes = Util.splitWords(types);\r\n\r\n\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\taddOne(obj, types[i], fn, context);\r\n\t\t}\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\nvar eventsKey = '_leaflet_events';\r\n\r\n// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n// Removes a previously added listener function.\r\n// Note that if you passed a custom context to on, you must pass the same\r\n// context to `off` in order to remove the listener.\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement, eventMap: Object, context?: Object): this\r\n// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement, types: String): this\r\n// Removes all previously added listeners of given types.\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement): this\r\n// Removes all previously added listeners from given HTMLElement\r\nexport function off(obj, types, fn, context) {\r\n\r\n\tif (arguments.length === 1) {\r\n\t\tbatchRemove(obj);\r\n\t\tdelete obj[eventsKey];\r\n\r\n\t} else if (types && typeof types === 'object') {\r\n\t\tfor (var type in types) {\r\n\t\t\tremoveOne(obj, type, types[type], fn);\r\n\t\t}\r\n\r\n\t} else {\r\n\t\ttypes = Util.splitWords(types);\r\n\r\n\t\tif (arguments.length === 2) {\r\n\t\t\tbatchRemove(obj, function (type) {\r\n\t\t\t\treturn Util.indexOf(types, type) !== -1;\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tremoveOne(obj, types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\nfunction batchRemove(obj, filterFn) {\r\n\tfor (var id in obj[eventsKey]) {\r\n\t\tvar type = id.split(/\\d/)[0];\r\n\t\tif (!filterFn || filterFn(type)) {\r\n\t\t\tremoveOne(obj, type, null, null, id);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nvar mouseSubst = {\r\n\tmouseenter: 'mouseover',\r\n\tmouseleave: 'mouseout',\r\n\twheel: !('onwheel' in window) && 'mousewheel'\r\n};\r\n\r\nfunction addOne(obj, type, fn, context) {\r\n\tvar id = type + Util.stamp(fn) + (context ? '_' + Util.stamp(context) : '');\r\n\r\n\tif (obj[eventsKey] && obj[eventsKey][id]) { return this; }\r\n\r\n\tvar handler = function (e) {\r\n\t\treturn fn.call(context || obj, e || window.event);\r\n\t};\r\n\r\n\tvar originalHandler = handler;\r\n\r\n\tif (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\t// Needs DomEvent.Pointer.js\r\n\t\thandler = addPointerListener(obj, type, handler);\r\n\r\n\t} else if (Browser.touch && (type === 'dblclick')) {\r\n\t\thandler = addDoubleTapListener(obj, handler);\r\n\r\n\t} else if ('addEventListener' in obj) {\r\n\r\n\t\tif (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') {\r\n\t\t\tobj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false);\r\n\r\n\t\t} else if (type === 'mouseenter' || type === 'mouseleave') {\r\n\t\t\thandler = function (e) {\r\n\t\t\t\te = e || window.event;\r\n\t\t\t\tif (isExternalTarget(obj, e)) {\r\n\t\t\t\t\toriginalHandler(e);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\tobj.addEventListener(mouseSubst[type], handler, false);\r\n\r\n\t\t} else {\r\n\t\t\tobj.addEventListener(type, originalHandler, false);\r\n\t\t}\r\n\r\n\t} else {\r\n\t\tobj.attachEvent('on' + type, handler);\r\n\t}\r\n\r\n\tobj[eventsKey] = obj[eventsKey] || {};\r\n\tobj[eventsKey][id] = handler;\r\n}\r\n\r\nfunction removeOne(obj, type, fn, context, id) {\r\n\tid = id || type + Util.stamp(fn) + (context ? '_' + Util.stamp(context) : '');\r\n\tvar handler = obj[eventsKey] && obj[eventsKey][id];\r\n\r\n\tif (!handler) { return this; }\r\n\r\n\tif (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\tremovePointerListener(obj, type, handler);\r\n\r\n\t} else if (Browser.touch && (type === 'dblclick')) {\r\n\t\tremoveDoubleTapListener(obj, handler);\r\n\r\n\t} else if ('removeEventListener' in obj) {\r\n\r\n\t\tobj.removeEventListener(mouseSubst[type] || type, handler, false);\r\n\r\n\t} else {\r\n\t\tobj.detachEvent('on' + type, handler);\r\n\t}\r\n\r\n\tobj[eventsKey][id] = null;\r\n}\r\n\r\n// @function stopPropagation(ev: DOMEvent): this\r\n// Stop the given event from propagation to parent elements. Used inside the listener functions:\r\n// ```js\r\n// L.DomEvent.on(div, 'click', function (ev) {\r\n// \tL.DomEvent.stopPropagation(ev);\r\n// });\r\n// ```\r\nexport function stopPropagation(e) {\r\n\r\n\tif (e.stopPropagation) {\r\n\t\te.stopPropagation();\r\n\t} else if (e.originalEvent) { // In case of Leaflet event.\r\n\t\te.originalEvent._stopped = true;\r\n\t} else {\r\n\t\te.cancelBubble = true;\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\n// @function disableScrollPropagation(el: HTMLElement): this\r\n// Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants).\r\nexport function disableScrollPropagation(el) {\r\n\taddOne(el, 'wheel', stopPropagation);\r\n\treturn this;\r\n}\r\n\r\n// @function disableClickPropagation(el: HTMLElement): this\r\n// Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`,\r\n// `'mousedown'` and `'touchstart'` events (plus browser variants).\r\nexport function disableClickPropagation(el) {\r\n\ton(el, 'mousedown touchstart dblclick contextmenu', stopPropagation);\r\n\tel['_leaflet_disable_click'] = true;\r\n\treturn this;\r\n}\r\n\r\n// @function preventDefault(ev: DOMEvent): this\r\n// Prevents the default action of the DOM Event `ev` from happening (such as\r\n// following a link in the href of the a element, or doing a POST request\r\n// with page reload when a `<form>` is submitted).\r\n// Use it inside listener functions.\r\nexport function preventDefault(e) {\r\n\tif (e.preventDefault) {\r\n\t\te.preventDefault();\r\n\t} else {\r\n\t\te.returnValue = false;\r\n\t}\r\n\treturn this;\r\n}\r\n\r\n// @function stop(ev: DOMEvent): this\r\n// Does `stopPropagation` and `preventDefault` at the same time.\r\nexport function stop(e) {\r\n\tpreventDefault(e);\r\n\tstopPropagation(e);\r\n\treturn this;\r\n}\r\n\r\n// @function getPropagationPath(ev: DOMEvent): Array\r\n// Compatibility polyfill for [`Event.composedPath()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath).\r\n// Returns an array containing the `HTMLElement`s that the given DOM event\r\n// should propagate to (if not stopped).\r\nexport function getPropagationPath(ev) {\r\n\tif (ev.composedPath) {\r\n\t\treturn ev.composedPath();\r\n\t}\r\n\r\n\tvar path = [];\r\n\tvar el = ev.target;\r\n\r\n\twhile (el) {\r\n\t\tpath.push(el);\r\n\t\tel = el.parentNode;\r\n\t}\r\n\treturn path;\r\n}\r\n\r\n\r\n// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point\r\n// Gets normalized mouse position from a DOM event relative to the\r\n// `container` (border excluded) or to the whole page if not specified.\r\nexport function getMousePosition(e, container) {\r\n\tif (!container) {\r\n\t\treturn new Point(e.clientX, e.clientY);\r\n\t}\r\n\r\n\tvar scale = getScale(container),\r\n\t offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y)\r\n\r\n\treturn new Point(\r\n\t\t// offset.left/top values are in page scale (like clientX/Y),\r\n\t\t// whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).\r\n\t\t(e.clientX - offset.left) / scale.x - container.clientLeft,\r\n\t\t(e.clientY - offset.top) / scale.y - container.clientTop\r\n\t);\r\n}\r\n\r\n\r\n// except , Safari and\r\n// We need double the scroll pixels (see #7403 and #4538) for all Browsers\r\n// except OSX (Mac) -> 3x, Chrome running on Linux 1x\r\n\r\nvar wheelPxFactor =\r\n\t(Browser.linux && Browser.chrome) ? window.devicePixelRatio :\r\n\tBrowser.mac ? window.devicePixelRatio * 3 :\r\n\twindow.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1;\r\n// @function getWheelDelta(ev: DOMEvent): Number\r\n// Gets normalized wheel delta from a wheel DOM event, in vertical\r\n// pixels scrolled (negative if scrolling down).\r\n// Events from pointing devices without precise scrolling are mapped to\r\n// a best guess of 60 pixels.\r\nexport function getWheelDelta(e) {\r\n\treturn (Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta\r\n\t (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels\r\n\t (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines\r\n\t (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages\r\n\t (e.deltaX || e.deltaZ) ? 0 :\t// Skip horizontal/depth wheel events\r\n\t e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels\r\n\t (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines\r\n\t e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages\r\n\t 0;\r\n}\r\n\r\n// check if element really left/entered the event target (for mouseenter/mouseleave)\r\nexport function isExternalTarget(el, e) {\r\n\r\n\tvar related = e.relatedTarget;\r\n\r\n\tif (!related) { return true; }\r\n\r\n\ttry {\r\n\t\twhile (related && (related !== el)) {\r\n\t\t\trelated = related.parentNode;\r\n\t\t}\r\n\t} catch (err) {\r\n\t\treturn false;\r\n\t}\r\n\treturn (related !== el);\r\n}\r\n\r\n// @function addListener(…): this\r\n// Alias to [`L.DomEvent.on`](#domevent-on)\r\nexport {on as addListener};\r\n\r\n// @function removeListener(…): this\r\n// Alias to [`L.DomEvent.off`](#domevent-off)\r\nexport {off as removeListener};\r\n","import * as Util from '../core/Util';\nimport {Evented} from '../core/Events';\nimport * as DomUtil from '../dom/DomUtil';\n\n\n/*\n * @class PosAnimation\n * @aka L.PosAnimation\n * @inherits Evented\n * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.\n *\n * @example\n * ```js\n * var myPositionMarker = L.marker([48.864716, 2.294694]).addTo(map);\n *\n * myPositionMarker.on(\"click\", function() {\n * \tvar pos = map.latLngToLayerPoint(myPositionMarker.getLatLng());\n * \tpos.y -= 25;\n * \tvar fx = new L.PosAnimation();\n *\n * \tfx.once('end',function() {\n * \t\tpos.y += 25;\n * \t\tfx.run(myPositionMarker._icon, pos, 0.8);\n * \t});\n *\n * \tfx.run(myPositionMarker._icon, pos, 0.3);\n * });\n *\n * ```\n *\n * @constructor L.PosAnimation()\n * Creates a `PosAnimation` object.\n *\n */\n\nexport var PosAnimation = Evented.extend({\n\n\t// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)\n\t// Run an animation of a given element to a new position, optionally setting\n\t// duration in seconds (`0.25` by default) and easing linearity factor (3rd\n\t// argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1),\n\t// `0.5` by default).\n\trun: function (el, newPos, duration, easeLinearity) {\n\t\tthis.stop();\n\n\t\tthis._el = el;\n\t\tthis._inProgress = true;\n\t\tthis._duration = duration || 0.25;\n\t\tthis._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);\n\n\t\tthis._startPos = DomUtil.getPosition(el);\n\t\tthis._offset = newPos.subtract(this._startPos);\n\t\tthis._startTime = +new Date();\n\n\t\t// @event start: Event\n\t\t// Fired when the animation starts\n\t\tthis.fire('start');\n\n\t\tthis._animate();\n\t},\n\n\t// @method stop()\n\t// Stops the animation (if currently running).\n\tstop: function () {\n\t\tif (!this._inProgress) { return; }\n\n\t\tthis._step(true);\n\t\tthis._complete();\n\t},\n\n\t_animate: function () {\n\t\t// animation loop\n\t\tthis._animId = Util.requestAnimFrame(this._animate, this);\n\t\tthis._step();\n\t},\n\n\t_step: function (round) {\n\t\tvar elapsed = (+new Date()) - this._startTime,\n\t\t duration = this._duration * 1000;\n\n\t\tif (elapsed < duration) {\n\t\t\tthis._runFrame(this._easeOut(elapsed / duration), round);\n\t\t} else {\n\t\t\tthis._runFrame(1);\n\t\t\tthis._complete();\n\t\t}\n\t},\n\n\t_runFrame: function (progress, round) {\n\t\tvar pos = this._startPos.add(this._offset.multiplyBy(progress));\n\t\tif (round) {\n\t\t\tpos._round();\n\t\t}\n\t\tDomUtil.setPosition(this._el, pos);\n\n\t\t// @event step: Event\n\t\t// Fired continuously during the animation.\n\t\tthis.fire('step');\n\t},\n\n\t_complete: function () {\n\t\tUtil.cancelAnimFrame(this._animId);\n\n\t\tthis._inProgress = false;\n\t\t// @event end: Event\n\t\t// Fired when the animation ends.\n\t\tthis.fire('end');\n\t},\n\n\t_easeOut: function (t) {\n\t\treturn 1 - Math.pow(1 - t, this._easeOutPower);\n\t}\n});\n","import * as Util from '../core/Util';\r\nimport {Evented} from '../core/Events';\r\nimport {EPSG3857} from '../geo/crs/CRS.EPSG3857';\r\nimport {Point, toPoint} from '../geometry/Point';\r\nimport {Bounds, toBounds} from '../geometry/Bounds';\r\nimport {LatLng, toLatLng} from '../geo/LatLng';\r\nimport {LatLngBounds, toLatLngBounds} from '../geo/LatLngBounds';\r\nimport Browser from '../core/Browser';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport {PosAnimation} from '../dom/PosAnimation';\r\n\r\n/*\r\n * @class Map\r\n * @aka L.Map\r\n * @inherits Evented\r\n *\r\n * The central class of the API — it is used to create a map on a page and manipulate it.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * // initialize the map on the \"map\" div with a given center and zoom\r\n * var map = L.map('map', {\r\n * \tcenter: [51.505, -0.09],\r\n * \tzoom: 13\r\n * });\r\n * ```\r\n *\r\n */\r\n\r\nexport var Map = Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section Map State Options\r\n\t\t// @option crs: CRS = L.CRS.EPSG3857\r\n\t\t// The [Coordinate Reference System](#crs) to use. Don't change this if you're not\r\n\t\t// sure what it means.\r\n\t\tcrs: EPSG3857,\r\n\r\n\t\t// @option center: LatLng = undefined\r\n\t\t// Initial geographic center of the map\r\n\t\tcenter: undefined,\r\n\r\n\t\t// @option zoom: Number = undefined\r\n\t\t// Initial map zoom level\r\n\t\tzoom: undefined,\r\n\r\n\t\t// @option minZoom: Number = *\r\n\t\t// Minimum zoom level of the map.\r\n\t\t// If not specified and at least one `GridLayer` or `TileLayer` is in the map,\r\n\t\t// the lowest of their `minZoom` options will be used instead.\r\n\t\tminZoom: undefined,\r\n\r\n\t\t// @option maxZoom: Number = *\r\n\t\t// Maximum zoom level of the map.\r\n\t\t// If not specified and at least one `GridLayer` or `TileLayer` is in the map,\r\n\t\t// the highest of their `maxZoom` options will be used instead.\r\n\t\tmaxZoom: undefined,\r\n\r\n\t\t// @option layers: Layer[] = []\r\n\t\t// Array of layers that will be added to the map initially\r\n\t\tlayers: [],\r\n\r\n\t\t// @option maxBounds: LatLngBounds = null\r\n\t\t// When this option is set, the map restricts the view to the given\r\n\t\t// geographical bounds, bouncing the user back if the user tries to pan\r\n\t\t// outside the view. To set the restriction dynamically, use\r\n\t\t// [`setMaxBounds`](#map-setmaxbounds) method.\r\n\t\tmaxBounds: undefined,\r\n\r\n\t\t// @option renderer: Renderer = *\r\n\t\t// The default method for drawing vector layers on the map. `L.SVG`\r\n\t\t// or `L.Canvas` by default depending on browser support.\r\n\t\trenderer: undefined,\r\n\r\n\r\n\t\t// @section Animation Options\r\n\t\t// @option zoomAnimation: Boolean = true\r\n\t\t// Whether the map zoom animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tzoomAnimation: true,\r\n\r\n\t\t// @option zoomAnimationThreshold: Number = 4\r\n\t\t// Won't animate zoom if the zoom difference exceeds this value.\r\n\t\tzoomAnimationThreshold: 4,\r\n\r\n\t\t// @option fadeAnimation: Boolean = true\r\n\t\t// Whether the tile fade animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tfadeAnimation: true,\r\n\r\n\t\t// @option markerZoomAnimation: Boolean = true\r\n\t\t// Whether markers animate their zoom with the zoom animation, if disabled\r\n\t\t// they will disappear for the length of the animation. By default it's\r\n\t\t// enabled in all browsers that support CSS3 Transitions except Android.\r\n\t\tmarkerZoomAnimation: true,\r\n\r\n\t\t// @option transform3DLimit: Number = 2^23\r\n\t\t// Defines the maximum size of a CSS translation transform. The default\r\n\t\t// value should not be changed unless a web browser positions layers in\r\n\t\t// the wrong place after doing a large `panBy`.\r\n\t\ttransform3DLimit: 8388608, // Precision limit of a 32-bit float\r\n\r\n\t\t// @section Interaction Options\r\n\t\t// @option zoomSnap: Number = 1\r\n\t\t// Forces the map's zoom level to always be a multiple of this, particularly\r\n\t\t// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.\r\n\t\t// By default, the zoom level snaps to the nearest integer; lower values\r\n\t\t// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`\r\n\t\t// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.\r\n\t\tzoomSnap: 1,\r\n\r\n\t\t// @option zoomDelta: Number = 1\r\n\t\t// Controls how much the map's zoom level will change after a\r\n\t\t// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`\r\n\t\t// or `-` on the keyboard, or using the [zoom controls](#control-zoom).\r\n\t\t// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.\r\n\t\tzoomDelta: 1,\r\n\r\n\t\t// @option trackResize: Boolean = true\r\n\t\t// Whether the map automatically handles browser window resize to update itself.\r\n\t\ttrackResize: true\r\n\t},\r\n\r\n\tinitialize: function (id, options) { // (HTMLElement or String, Object)\r\n\t\toptions = Util.setOptions(this, options);\r\n\r\n\t\t// Make sure to assign internal flags at the beginning,\r\n\t\t// to avoid inconsistent state in some edge cases.\r\n\t\tthis._handlers = [];\r\n\t\tthis._layers = {};\r\n\t\tthis._zoomBoundLayers = {};\r\n\t\tthis._sizeChanged = true;\r\n\r\n\t\tthis._initContainer(id);\r\n\t\tthis._initLayout();\r\n\r\n\t\t// hack for https://github.com/Leaflet/Leaflet/issues/1980\r\n\t\tthis._onResize = Util.bind(this._onResize, this);\r\n\r\n\t\tthis._initEvents();\r\n\r\n\t\tif (options.maxBounds) {\r\n\t\t\tthis.setMaxBounds(options.maxBounds);\r\n\t\t}\r\n\r\n\t\tif (options.zoom !== undefined) {\r\n\t\t\tthis._zoom = this._limitZoom(options.zoom);\r\n\t\t}\r\n\r\n\t\tif (options.center && options.zoom !== undefined) {\r\n\t\t\tthis.setView(toLatLng(options.center), options.zoom, {reset: true});\r\n\t\t}\r\n\r\n\t\tthis.callInitHooks();\r\n\r\n\t\t// don't animate on browsers without hardware-accelerated transitions or old Android/Opera\r\n\t\tthis._zoomAnimated = DomUtil.TRANSITION && Browser.any3d && !Browser.mobileOpera &&\r\n\t\t\t\tthis.options.zoomAnimation;\r\n\r\n\t\t// zoom transitions run with the same duration for all layers, so if one of transitionend events\r\n\t\t// happens after starting zoom animation (propagating to the map pane), we know that it ended globally\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tthis._createAnimProxy();\r\n\t\t\tDomEvent.on(this._proxy, DomUtil.TRANSITION_END, this._catchTransitionEnd, this);\r\n\t\t}\r\n\r\n\t\tthis._addLayers(this.options.layers);\r\n\t},\r\n\r\n\r\n\t// @section Methods for modifying map state\r\n\r\n\t// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) with the given\r\n\t// animation options.\r\n\tsetView: function (center, zoom, options) {\r\n\r\n\t\tzoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);\r\n\t\tcenter = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);\r\n\t\toptions = options || {};\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tif (this._loaded && !options.reset && options !== true) {\r\n\r\n\t\t\tif (options.animate !== undefined) {\r\n\t\t\t\toptions.zoom = Util.extend({animate: options.animate}, options.zoom);\r\n\t\t\t\toptions.pan = Util.extend({animate: options.animate, duration: options.duration}, options.pan);\r\n\t\t\t}\r\n\r\n\t\t\t// try animating pan or zoom\r\n\t\t\tvar moved = (this._zoom !== zoom) ?\r\n\t\t\t\tthis._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :\r\n\t\t\t\tthis._tryAnimatedPan(center, options.pan);\r\n\r\n\t\t\tif (moved) {\r\n\t\t\t\t// prevent resize handler call, the view will refresh after animation anyway\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\treturn this;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// animation didn't start, just reset the map view\r\n\t\tthis._resetView(center, zoom, options.pan && options.pan.noMoveStart);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setZoom(zoom: Number, options?: Zoom/pan options): this\r\n\t// Sets the zoom of the map.\r\n\tsetZoom: function (zoom, options) {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthis._zoom = zoom;\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn this.setView(this.getCenter(), zoom, {zoom: options});\r\n\t},\r\n\r\n\t// @method zoomIn(delta?: Number, options?: Zoom options): this\r\n\t// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomIn: function (delta, options) {\r\n\t\tdelta = delta || (Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom + delta, options);\r\n\t},\r\n\r\n\t// @method zoomOut(delta?: Number, options?: Zoom options): this\r\n\t// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomOut: function (delta, options) {\r\n\t\tdelta = delta || (Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom - delta, options);\r\n\t},\r\n\r\n\t// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified geographical point on the map\r\n\t// stationary (e.g. used internally for scroll zoom and double-click zoom).\r\n\t// @alternative\r\n\t// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.\r\n\tsetZoomAround: function (latlng, zoom, options) {\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t viewHalf = this.getSize().divideBy(2),\r\n\t\t containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),\r\n\r\n\t\t centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),\r\n\t\t newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));\r\n\r\n\t\treturn this.setView(newCenter, zoom, {zoom: options});\r\n\t},\r\n\r\n\t_getBoundsCenterZoom: function (bounds, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tbounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);\r\n\r\n\t\tvar paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),\r\n\t\t paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),\r\n\r\n\t\t zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));\r\n\r\n\t\tzoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;\r\n\r\n\t\tif (zoom === Infinity) {\r\n\t\t\treturn {\r\n\t\t\t\tcenter: bounds.getCenter(),\r\n\t\t\t\tzoom: zoom\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tvar paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),\r\n\r\n\t\t swPoint = this.project(bounds.getSouthWest(), zoom),\r\n\t\t nePoint = this.project(bounds.getNorthEast(), zoom),\r\n\t\t center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);\r\n\r\n\t\treturn {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom\r\n\t\t};\r\n\t},\r\n\r\n\t// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets a map view that contains the given geographical bounds with the\r\n\t// maximum zoom level possible.\r\n\tfitBounds: function (bounds, options) {\r\n\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthrow new Error('Bounds are not valid.');\r\n\t\t}\r\n\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.setView(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method fitWorld(options?: fitBounds options): this\r\n\t// Sets a map view that mostly contains the whole world with the maximum\r\n\t// zoom level possible.\r\n\tfitWorld: function (options) {\r\n\t\treturn this.fitBounds([[-90, -180], [90, 180]], options);\r\n\t},\r\n\r\n\t// @method panTo(latlng: LatLng, options?: Pan options): this\r\n\t// Pans the map to a given center.\r\n\tpanTo: function (center, options) { // (LatLng)\r\n\t\treturn this.setView(center, this._zoom, {pan: options});\r\n\t},\r\n\r\n\t// @method panBy(offset: Point, options?: Pan options): this\r\n\t// Pans the map by a given number of pixels (animated).\r\n\tpanBy: function (offset, options) {\r\n\t\toffset = toPoint(offset).round();\r\n\t\toptions = options || {};\r\n\r\n\t\tif (!offset.x && !offset.y) {\r\n\t\t\treturn this.fire('moveend');\r\n\t\t}\r\n\t\t// If we pan too far, Chrome gets issues with tiles\r\n\t\t// and makes them disappear or appear in the wrong place (slightly offset) #2602\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) {\r\n\t\t\tthis._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tif (!this._panAnim) {\r\n\t\t\tthis._panAnim = new PosAnimation();\r\n\r\n\t\t\tthis._panAnim.on({\r\n\t\t\t\t'step': this._onPanTransitionStep,\r\n\t\t\t\t'end': this._onPanTransitionEnd\r\n\t\t\t}, this);\r\n\t\t}\r\n\r\n\t\t// don't fire movestart if animating inertia\r\n\t\tif (!options.noMoveStart) {\r\n\t\t\tthis.fire('movestart');\r\n\t\t}\r\n\r\n\t\t// animate pan unless animate: false specified\r\n\t\tif (options.animate !== false) {\r\n\t\t\tDomUtil.addClass(this._mapPane, 'leaflet-pan-anim');\r\n\r\n\t\t\tvar newPos = this._getMapPanePos().subtract(offset).round();\r\n\t\t\tthis._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);\r\n\t\t} else {\r\n\t\t\tthis._rawPanBy(offset);\r\n\t\t\tthis.fire('move').fire('moveend');\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) performing a smooth\r\n\t// pan-zoom animation.\r\n\tflyTo: function (targetCenter, targetZoom, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tif (options.animate === false || !Browser.any3d) {\r\n\t\t\treturn this.setView(targetCenter, targetZoom, options);\r\n\t\t}\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tvar from = this.project(this.getCenter()),\r\n\t\t to = this.project(targetCenter),\r\n\t\t size = this.getSize(),\r\n\t\t startZoom = this._zoom;\r\n\r\n\t\ttargetCenter = toLatLng(targetCenter);\r\n\t\ttargetZoom = targetZoom === undefined ? startZoom : targetZoom;\r\n\r\n\t\tvar w0 = Math.max(size.x, size.y),\r\n\t\t w1 = w0 * this.getZoomScale(startZoom, targetZoom),\r\n\t\t u1 = (to.distanceTo(from)) || 1,\r\n\t\t rho = 1.42,\r\n\t\t rho2 = rho * rho;\r\n\r\n\t\tfunction r(i) {\r\n\t\t\tvar s1 = i ? -1 : 1,\r\n\t\t\t s2 = i ? w1 : w0,\r\n\t\t\t t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,\r\n\t\t\t b1 = 2 * s2 * rho2 * u1,\r\n\t\t\t b = t1 / b1,\r\n\t\t\t sq = Math.sqrt(b * b + 1) - b;\r\n\r\n\t\t\t // workaround for floating point precision bug when sq = 0, log = -Infinite,\r\n\t\t\t // thus triggering an infinite loop in flyTo\r\n\t\t\t var log = sq < 0.000000001 ? -18 : Math.log(sq);\r\n\r\n\t\t\treturn log;\r\n\t\t}\r\n\r\n\t\tfunction sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\r\n\t\tfunction cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\r\n\t\tfunction tanh(n) { return sinh(n) / cosh(n); }\r\n\r\n\t\tvar r0 = r(0);\r\n\r\n\t\tfunction w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }\r\n\t\tfunction u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }\r\n\r\n\t\tfunction easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }\r\n\r\n\t\tvar start = Date.now(),\r\n\t\t S = (r(1) - r0) / rho,\r\n\t\t duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;\r\n\r\n\t\tfunction frame() {\r\n\t\t\tvar t = (Date.now() - start) / duration,\r\n\t\t\t s = easeOut(t) * S;\r\n\r\n\t\t\tif (t <= 1) {\r\n\t\t\t\tthis._flyToFrame = Util.requestAnimFrame(frame, this);\r\n\r\n\t\t\t\tthis._move(\r\n\t\t\t\t\tthis.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),\r\n\t\t\t\t\tthis.getScaleZoom(w0 / w(s), startZoom),\r\n\t\t\t\t\t{flyTo: true});\r\n\r\n\t\t\t} else {\r\n\t\t\t\tthis\r\n\t\t\t\t\t._move(targetCenter, targetZoom)\r\n\t\t\t\t\t._moveEnd(true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._moveStart(true, options.noMoveStart);\r\n\r\n\t\tframe.call(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),\r\n\t// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).\r\n\tflyToBounds: function (bounds, options) {\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.flyTo(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method setMaxBounds(bounds: LatLngBounds): this\r\n\t// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).\r\n\tsetMaxBounds: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (this.listens('moveend', this._panInsideMaxBounds)) {\r\n\t\t\tthis.off('moveend', this._panInsideMaxBounds);\r\n\t\t}\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthis.options.maxBounds = null;\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tthis.options.maxBounds = bounds;\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\tthis._panInsideMaxBounds();\r\n\t\t}\r\n\r\n\t\treturn this.on('moveend', this._panInsideMaxBounds);\r\n\t},\r\n\r\n\t// @method setMinZoom(zoom: Number): this\r\n\t// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).\r\n\tsetMinZoom: function (zoom) {\r\n\t\tvar oldZoom = this.options.minZoom;\r\n\t\tthis.options.minZoom = zoom;\r\n\r\n\t\tif (this._loaded && oldZoom !== zoom) {\r\n\t\t\tthis.fire('zoomlevelschange');\r\n\r\n\t\t\tif (this.getZoom() < this.options.minZoom) {\r\n\t\t\t\treturn this.setZoom(zoom);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setMaxZoom(zoom: Number): this\r\n\t// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).\r\n\tsetMaxZoom: function (zoom) {\r\n\t\tvar oldZoom = this.options.maxZoom;\r\n\t\tthis.options.maxZoom = zoom;\r\n\r\n\t\tif (this._loaded && oldZoom !== zoom) {\r\n\t\t\tthis.fire('zoomlevelschange');\r\n\r\n\t\t\tif (this.getZoom() > this.options.maxZoom) {\r\n\t\t\t\treturn this.setZoom(zoom);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this\r\n\t// Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.\r\n\tpanInsideBounds: function (bounds, options) {\r\n\t\tthis._enforcingBounds = true;\r\n\t\tvar center = this.getCenter(),\r\n\t\t newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));\r\n\r\n\t\tif (!center.equals(newCenter)) {\r\n\t\t\tthis.panTo(newCenter, options);\r\n\t\t}\r\n\r\n\t\tthis._enforcingBounds = false;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method panInside(latlng: LatLng, options?: padding options): this\r\n\t// Pans the map the minimum amount to make the `latlng` visible. Use\r\n\t// padding options to fit the display to more restricted bounds.\r\n\t// If `latlng` is already within the (optionally padded) display bounds,\r\n\t// the map will not be panned.\r\n\tpanInside: function (latlng, options) {\r\n\t\toptions = options || {};\r\n\r\n\t\tvar paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),\r\n\t\t paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),\r\n\t\t pixelCenter = this.project(this.getCenter()),\r\n\t\t pixelPoint = this.project(latlng),\r\n\t\t pixelBounds = this.getPixelBounds(),\r\n\t\t paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),\r\n\t\t paddedSize = paddedBounds.getSize();\r\n\r\n\t\tif (!paddedBounds.contains(pixelPoint)) {\r\n\t\t\tthis._enforcingBounds = true;\r\n\t\t\tvar centerOffset = pixelPoint.subtract(paddedBounds.getCenter());\r\n\t\t\tvar offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);\r\n\t\t\tpixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;\r\n\t\t\tpixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;\r\n\t\t\tthis.panTo(this.unproject(pixelCenter), options);\r\n\t\t\tthis._enforcingBounds = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method invalidateSize(options: Zoom/pan options): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default. If `options.pan` is `false`, panning will not occur.\r\n\t// If `options.debounceMoveend` is `true`, it will delay `moveend` event so\r\n\t// that it doesn't happen often even if the method is called many\r\n\t// times in a row.\r\n\r\n\t// @alternative\r\n\t// @method invalidateSize(animate: Boolean): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default.\r\n\tinvalidateSize: function (options) {\r\n\t\tif (!this._loaded) { return this; }\r\n\r\n\t\toptions = Util.extend({\r\n\t\t\tanimate: false,\r\n\t\t\tpan: true\r\n\t\t}, options === true ? {animate: true} : options);\r\n\r\n\t\tvar oldSize = this.getSize();\r\n\t\tthis._sizeChanged = true;\r\n\t\tthis._lastCenter = null;\r\n\r\n\t\tvar newSize = this.getSize(),\r\n\t\t oldCenter = oldSize.divideBy(2).round(),\r\n\t\t newCenter = newSize.divideBy(2).round(),\r\n\t\t offset = oldCenter.subtract(newCenter);\r\n\r\n\t\tif (!offset.x && !offset.y) { return this; }\r\n\r\n\t\tif (options.animate && options.pan) {\r\n\t\t\tthis.panBy(offset);\r\n\r\n\t\t} else {\r\n\t\t\tif (options.pan) {\r\n\t\t\t\tthis._rawPanBy(offset);\r\n\t\t\t}\r\n\r\n\t\t\tthis.fire('move');\r\n\r\n\t\t\tif (options.debounceMoveend) {\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\tthis._sizeTimer = setTimeout(Util.bind(this.fire, this, 'moveend'), 200);\r\n\t\t\t} else {\r\n\t\t\t\tthis.fire('moveend');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @section Map state change events\r\n\t\t// @event resize: ResizeEvent\r\n\t\t// Fired when the map is resized.\r\n\t\treturn this.fire('resize', {\r\n\t\t\toldSize: oldSize,\r\n\t\t\tnewSize: newSize\r\n\t\t});\r\n\t},\r\n\r\n\t// @section Methods for modifying map state\r\n\t// @method stop(): this\r\n\t// Stops the currently running `panTo` or `flyTo` animation, if any.\r\n\tstop: function () {\r\n\t\tthis.setZoom(this._limitZoom(this._zoom));\r\n\t\tif (!this.options.zoomSnap) {\r\n\t\t\tthis.fire('viewreset');\r\n\t\t}\r\n\t\treturn this._stop();\r\n\t},\r\n\r\n\t// @section Geolocation methods\r\n\t// @method locate(options?: Locate options): this\r\n\t// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)\r\n\t// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,\r\n\t// and optionally sets the map view to the user's location with respect to\r\n\t// detection accuracy (or to the world view if geolocation failed).\r\n\t// Note that, if your page doesn't use HTTPS, this method will fail in\r\n\t// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))\r\n\t// See `Locate options` for more details.\r\n\tlocate: function (options) {\r\n\r\n\t\toptions = this._locateOptions = Util.extend({\r\n\t\t\ttimeout: 10000,\r\n\t\t\twatch: false\r\n\t\t\t// setView: false\r\n\t\t\t// maxZoom: <Number>\r\n\t\t\t// maximumAge: 0\r\n\t\t\t// enableHighAccuracy: false\r\n\t\t}, options);\r\n\r\n\t\tif (!('geolocation' in navigator)) {\r\n\t\t\tthis._handleGeolocationError({\r\n\t\t\t\tcode: 0,\r\n\t\t\t\tmessage: 'Geolocation not supported.'\r\n\t\t\t});\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar onResponse = Util.bind(this._handleGeolocationResponse, this),\r\n\t\t onError = Util.bind(this._handleGeolocationError, this);\r\n\r\n\t\tif (options.watch) {\r\n\t\t\tthis._locationWatchId =\r\n\t\t\t navigator.geolocation.watchPosition(onResponse, onError, options);\r\n\t\t} else {\r\n\t\t\tnavigator.geolocation.getCurrentPosition(onResponse, onError, options);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method stopLocate(): this\r\n\t// Stops watching location previously initiated by `map.locate({watch: true})`\r\n\t// and aborts resetting the map view if map.locate was called with\r\n\t// `{setView: true}`.\r\n\tstopLocate: function () {\r\n\t\tif (navigator.geolocation && navigator.geolocation.clearWatch) {\r\n\t\t\tnavigator.geolocation.clearWatch(this._locationWatchId);\r\n\t\t}\r\n\t\tif (this._locateOptions) {\r\n\t\t\tthis._locateOptions.setView = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_handleGeolocationError: function (error) {\r\n\t\tif (!this._container._leaflet_id) { return; }\r\n\r\n\t\tvar c = error.code,\r\n\t\t message = error.message ||\r\n\t\t (c === 1 ? 'permission denied' :\r\n\t\t (c === 2 ? 'position unavailable' : 'timeout'));\r\n\r\n\t\tif (this._locateOptions.setView && !this._loaded) {\r\n\t\t\tthis.fitWorld();\r\n\t\t}\r\n\r\n\t\t// @section Location events\r\n\t\t// @event locationerror: ErrorEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method) failed.\r\n\t\tthis.fire('locationerror', {\r\n\t\t\tcode: c,\r\n\t\t\tmessage: 'Geolocation error: ' + message + '.'\r\n\t\t});\r\n\t},\r\n\r\n\t_handleGeolocationResponse: function (pos) {\r\n\t\tif (!this._container._leaflet_id) { return; }\r\n\r\n\t\tvar lat = pos.coords.latitude,\r\n\t\t lng = pos.coords.longitude,\r\n\t\t latlng = new LatLng(lat, lng),\r\n\t\t bounds = latlng.toBounds(pos.coords.accuracy * 2),\r\n\t\t options = this._locateOptions;\r\n\r\n\t\tif (options.setView) {\r\n\t\t\tvar zoom = this.getBoundsZoom(bounds);\r\n\t\t\tthis.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);\r\n\t\t}\r\n\r\n\t\tvar data = {\r\n\t\t\tlatlng: latlng,\r\n\t\t\tbounds: bounds,\r\n\t\t\ttimestamp: pos.timestamp\r\n\t\t};\r\n\r\n\t\tfor (var i in pos.coords) {\r\n\t\t\tif (typeof pos.coords[i] === 'number') {\r\n\t\t\t\tdata[i] = pos.coords[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @event locationfound: LocationEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method)\r\n\t\t// went successfully.\r\n\t\tthis.fire('locationfound', data);\r\n\t},\r\n\r\n\t// TODO Appropriate docs section?\r\n\t// @section Other Methods\r\n\t// @method addHandler(name: String, HandlerClass: Function): this\r\n\t// Adds a new `Handler` to the map, given its name and constructor function.\r\n\taddHandler: function (name, HandlerClass) {\r\n\t\tif (!HandlerClass) { return this; }\r\n\r\n\t\tvar handler = this[name] = new HandlerClass(this);\r\n\r\n\t\tthis._handlers.push(handler);\r\n\r\n\t\tif (this.options[name]) {\r\n\t\t\thandler.enable();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove(): this\r\n\t// Destroys the map and clears all related event listeners.\r\n\tremove: function () {\r\n\r\n\t\tthis._initEvents(true);\r\n\t\tif (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }\r\n\r\n\t\tif (this._containerId !== this._container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is being reused by another instance');\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\t// throws error in IE6-8\r\n\t\t\tdelete this._container._leaflet_id;\r\n\t\t\tdelete this._containerId;\r\n\t\t} catch (e) {\r\n\t\t\t/*eslint-disable */\r\n\t\t\tthis._container._leaflet_id = undefined;\r\n\t\t\t/* eslint-enable */\r\n\t\t\tthis._containerId = undefined;\r\n\t\t}\r\n\r\n\t\tif (this._locationWatchId !== undefined) {\r\n\t\t\tthis.stopLocate();\r\n\t\t}\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tDomUtil.remove(this._mapPane);\r\n\r\n\t\tif (this._clearControlPos) {\r\n\t\t\tthis._clearControlPos();\r\n\t\t}\r\n\t\tif (this._resizeRequest) {\r\n\t\t\tUtil.cancelAnimFrame(this._resizeRequest);\r\n\t\t\tthis._resizeRequest = null;\r\n\t\t}\r\n\r\n\t\tthis._clearHandlers();\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\t// @section Map state change events\r\n\t\t\t// @event unload: Event\r\n\t\t\t// Fired when the map is destroyed with [remove](#map-remove) method.\r\n\t\t\tthis.fire('unload');\r\n\t\t}\r\n\r\n\t\tvar i;\r\n\t\tfor (i in this._layers) {\r\n\t\t\tthis._layers[i].remove();\r\n\t\t}\r\n\t\tfor (i in this._panes) {\r\n\t\t\tDomUtil.remove(this._panes[i]);\r\n\t\t}\r\n\r\n\t\tthis._layers = [];\r\n\t\tthis._panes = [];\r\n\t\tdelete this._mapPane;\r\n\t\tdelete this._renderer;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\t// @method createPane(name: String, container?: HTMLElement): HTMLElement\r\n\t// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,\r\n\t// then returns it. The pane is created as a child of `container`, or\r\n\t// as a child of the main map pane if not set.\r\n\tcreatePane: function (name, container) {\r\n\t\tvar className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),\r\n\t\t pane = DomUtil.create('div', className, container || this._mapPane);\r\n\r\n\t\tif (name) {\r\n\t\t\tthis._panes[name] = pane;\r\n\t\t}\r\n\t\treturn pane;\r\n\t},\r\n\r\n\t// @section Methods for Getting Map State\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the geographical center of the map view\r\n\tgetCenter: function () {\r\n\t\tthis._checkIfLoaded();\r\n\r\n\t\tif (this._lastCenter && !this._moved()) {\r\n\t\t\treturn this._lastCenter.clone();\r\n\t\t}\r\n\t\treturn this.layerPointToLatLng(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// @method getZoom(): Number\r\n\t// Returns the current zoom level of the map view\r\n\tgetZoom: function () {\r\n\t\treturn this._zoom;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the geographical bounds visible in the current map view\r\n\tgetBounds: function () {\r\n\t\tvar bounds = this.getPixelBounds(),\r\n\t\t sw = this.unproject(bounds.getBottomLeft()),\r\n\t\t ne = this.unproject(bounds.getTopRight());\r\n\r\n\t\treturn new LatLngBounds(sw, ne);\r\n\t},\r\n\r\n\t// @method getMinZoom(): Number\r\n\t// Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.\r\n\tgetMinZoom: function () {\r\n\t\treturn this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;\r\n\t},\r\n\r\n\t// @method getMaxZoom(): Number\r\n\t// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).\r\n\tgetMaxZoom: function () {\r\n\t\treturn this.options.maxZoom === undefined ?\r\n\t\t\t(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :\r\n\t\t\tthis.options.maxZoom;\r\n\t},\r\n\r\n\t// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number\r\n\t// Returns the maximum zoom level on which the given bounds fit to the map\r\n\t// view in its entirety. If `inside` (optional) is set to `true`, the method\r\n\t// instead returns the minimum zoom level on which the map view fits into\r\n\t// the given bounds in its entirety.\r\n\tgetBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\t\tpadding = toPoint(padding || [0, 0]);\r\n\r\n\t\tvar zoom = this.getZoom() || 0,\r\n\t\t min = this.getMinZoom(),\r\n\t\t max = this.getMaxZoom(),\r\n\t\t nw = bounds.getNorthWest(),\r\n\t\t se = bounds.getSouthEast(),\r\n\t\t size = this.getSize().subtract(padding),\r\n\t\t boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),\r\n\t\t snap = Browser.any3d ? this.options.zoomSnap : 1,\r\n\t\t scalex = size.x / boundsSize.x,\r\n\t\t scaley = size.y / boundsSize.y,\r\n\t\t scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);\r\n\r\n\t\tzoom = this.getScaleZoom(scale, zoom);\r\n\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level\r\n\t\t\tzoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;\r\n\t\t}\r\n\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the current size of the map container (in pixels).\r\n\tgetSize: function () {\r\n\t\tif (!this._size || this._sizeChanged) {\r\n\t\t\tthis._size = new Point(\r\n\t\t\t\tthis._container.clientWidth || 0,\r\n\t\t\t\tthis._container.clientHeight || 0);\r\n\r\n\t\t\tthis._sizeChanged = false;\r\n\t\t}\r\n\t\treturn this._size.clone();\r\n\t},\r\n\r\n\t// @method getPixelBounds(): Bounds\r\n\t// Returns the bounds of the current map view in projected pixel\r\n\t// coordinates (sometimes useful in layer and overlay implementations).\r\n\tgetPixelBounds: function (center, zoom) {\r\n\t\tvar topLeftPoint = this._getTopLeftPoint(center, zoom);\r\n\t\treturn new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));\r\n\t},\r\n\r\n\t// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to\r\n\t// the map pane? \"left point of the map layer\" can be confusing, specially\r\n\t// since there can be negative offsets.\r\n\t// @method getPixelOrigin(): Point\r\n\t// Returns the projected pixel coordinates of the top left point of\r\n\t// the map layer (useful in custom layer and overlay implementations).\r\n\tgetPixelOrigin: function () {\r\n\t\tthis._checkIfLoaded();\r\n\t\treturn this._pixelOrigin;\r\n\t},\r\n\r\n\t// @method getPixelWorldBounds(zoom?: Number): Bounds\r\n\t// Returns the world's bounds in pixel coordinates for zoom level `zoom`.\r\n\t// If `zoom` is omitted, the map's current zoom level is used.\r\n\tgetPixelWorldBounds: function (zoom) {\r\n\t\treturn this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method getPane(pane: String|HTMLElement): HTMLElement\r\n\t// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).\r\n\tgetPane: function (pane) {\r\n\t\treturn typeof pane === 'string' ? this._panes[pane] : pane;\r\n\t},\r\n\r\n\t// @method getPanes(): Object\r\n\t// Returns a plain object containing the names of all [panes](#map-pane) as keys and\r\n\t// the panes as values.\r\n\tgetPanes: function () {\r\n\t\treturn this._panes;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTML element that contains the map.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\r\n\t// @section Conversion Methods\r\n\r\n\t// @method getZoomScale(toZoom: Number, fromZoom: Number): Number\r\n\t// Returns the scale factor to be applied to a map transition from zoom level\r\n\t// `fromZoom` to `toZoom`. Used internally to help with zoom animations.\r\n\tgetZoomScale: function (toZoom, fromZoom) {\r\n\t\t// TODO replace with universal implementation after refactoring projections\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\treturn crs.scale(toZoom) / crs.scale(fromZoom);\r\n\t},\r\n\r\n\t// @method getScaleZoom(scale: Number, fromZoom: Number): Number\r\n\t// Returns the zoom level that the map would end up at, if it is at `fromZoom`\r\n\t// level and everything is scaled by a factor of `scale`. Inverse of\r\n\t// [`getZoomScale`](#map-getZoomScale).\r\n\tgetScaleZoom: function (scale, fromZoom) {\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\tvar zoom = crs.zoom(scale * crs.scale(fromZoom));\r\n\t\treturn isNaN(zoom) ? Infinity : zoom;\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng, zoom: Number): Point\r\n\t// Projects a geographical coordinate `LatLng` according to the projection\r\n\t// of the map's CRS, then scales it according to `zoom` and the CRS's\r\n\t// `Transformation`. The result is pixel coordinate relative to\r\n\t// the CRS origin.\r\n\tproject: function (latlng, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.latLngToPoint(toLatLng(latlng), zoom);\r\n\t},\r\n\r\n\t// @method unproject(point: Point, zoom: Number): LatLng\r\n\t// Inverse of [`project`](#map-project).\r\n\tunproject: function (point, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.pointToLatLng(toPoint(point), zoom);\r\n\t},\r\n\r\n\t// @method layerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding geographical coordinate (for the current zoom level).\r\n\tlayerPointToLatLng: function (point) {\r\n\t\tvar projectedPoint = toPoint(point).add(this.getPixelOrigin());\r\n\t\treturn this.unproject(projectedPoint);\r\n\t},\r\n\r\n\t// @method latLngToLayerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the [origin pixel](#map-getpixelorigin).\r\n\tlatLngToLayerPoint: function (latlng) {\r\n\t\tvar projectedPoint = this.project(toLatLng(latlng))._round();\r\n\t\treturn projectedPoint._subtract(this.getPixelOrigin());\r\n\t},\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the\r\n\t// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the\r\n\t// CRS's bounds.\r\n\t// By default this means longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees.\r\n\twrapLatLng: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLng(toLatLng(latlng));\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring that\r\n\t// its center is within the CRS's bounds.\r\n\t// By default this means the center longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees, and the majority of the bounds\r\n\t// overlaps the CRS's bounds.\r\n\twrapLatLngBounds: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates according to\r\n\t// the map's CRS. By default this measures distance in meters.\r\n\tdistance: function (latlng1, latlng2) {\r\n\t\treturn this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));\r\n\t},\r\n\r\n\t// @method containerPointToLayerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the map container, returns the corresponding\r\n\t// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).\r\n\tcontainerPointToLayerPoint: function (point) { // (Point)\r\n\t\treturn toPoint(point).subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method layerPointToContainerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding pixel coordinate relative to the map container.\r\n\tlayerPointToContainerPoint: function (point) { // (Point)\r\n\t\treturn toPoint(point).add(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method containerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the map container, returns\r\n\t// the corresponding geographical coordinate (for the current zoom level).\r\n\tcontainerPointToLatLng: function (point) {\r\n\t\tvar layerPoint = this.containerPointToLayerPoint(toPoint(point));\r\n\t\treturn this.layerPointToLatLng(layerPoint);\r\n\t},\r\n\r\n\t// @method latLngToContainerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the map container.\r\n\tlatLngToContainerPoint: function (latlng) {\r\n\t\treturn this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));\r\n\t},\r\n\r\n\t// @method mouseEventToContainerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to the\r\n\t// map container where the event took place.\r\n\tmouseEventToContainerPoint: function (e) {\r\n\t\treturn DomEvent.getMousePosition(e, this._container);\r\n\t},\r\n\r\n\t// @method mouseEventToLayerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to\r\n\t// the [origin pixel](#map-getpixelorigin) where the event took place.\r\n\tmouseEventToLayerPoint: function (e) {\r\n\t\treturn this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));\r\n\t},\r\n\r\n\t// @method mouseEventToLatLng(ev: MouseEvent): LatLng\r\n\t// Given a MouseEvent object, returns geographical coordinate where the\r\n\t// event took place.\r\n\tmouseEventToLatLng: function (e) { // (MouseEvent)\r\n\t\treturn this.layerPointToLatLng(this.mouseEventToLayerPoint(e));\r\n\t},\r\n\r\n\r\n\t// map initialization methods\r\n\r\n\t_initContainer: function (id) {\r\n\t\tvar container = this._container = DomUtil.get(id);\r\n\r\n\t\tif (!container) {\r\n\t\t\tthrow new Error('Map container not found.');\r\n\t\t} else if (container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is already initialized.');\r\n\t\t}\r\n\r\n\t\tDomEvent.on(container, 'scroll', this._onScroll, this);\r\n\t\tthis._containerId = Util.stamp(container);\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar container = this._container;\r\n\r\n\t\tthis._fadeAnimated = this.options.fadeAnimation && Browser.any3d;\r\n\r\n\t\tDomUtil.addClass(container, 'leaflet-container' +\r\n\t\t\t(Browser.touch ? ' leaflet-touch' : '') +\r\n\t\t\t(Browser.retina ? ' leaflet-retina' : '') +\r\n\t\t\t(Browser.ielt9 ? ' leaflet-oldie' : '') +\r\n\t\t\t(Browser.safari ? ' leaflet-safari' : '') +\r\n\t\t\t(this._fadeAnimated ? ' leaflet-fade-anim' : ''));\r\n\r\n\t\tvar position = DomUtil.getStyle(container, 'position');\r\n\r\n\t\tif (position !== 'absolute' && position !== 'relative' && position !== 'fixed' && position !== 'sticky') {\r\n\t\t\tcontainer.style.position = 'relative';\r\n\t\t}\r\n\r\n\t\tthis._initPanes();\r\n\r\n\t\tif (this._initControlPos) {\r\n\t\t\tthis._initControlPos();\r\n\t\t}\r\n\t},\r\n\r\n\t_initPanes: function () {\r\n\t\tvar panes = this._panes = {};\r\n\t\tthis._paneRenderers = {};\r\n\r\n\t\t// @section\r\n\t\t//\r\n\t\t// Panes are DOM elements used to control the ordering of layers on the map. You\r\n\t\t// can access panes with [`map.getPane`](#map-getpane) or\r\n\t\t// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the\r\n\t\t// [`map.createPane`](#map-createpane) method.\r\n\t\t//\r\n\t\t// Every map has the following default panes that differ only in zIndex.\r\n\t\t//\r\n\t\t// @pane mapPane: HTMLElement = 'auto'\r\n\t\t// Pane that contains all other map panes\r\n\r\n\t\tthis._mapPane = this.createPane('mapPane', this._container);\r\n\t\tDomUtil.setPosition(this._mapPane, new Point(0, 0));\r\n\r\n\t\t// @pane tilePane: HTMLElement = 200\r\n\t\t// Pane for `GridLayer`s and `TileLayer`s\r\n\t\tthis.createPane('tilePane');\r\n\t\t// @pane overlayPane: HTMLElement = 400\r\n\t\t// Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s\r\n\t\tthis.createPane('overlayPane');\r\n\t\t// @pane shadowPane: HTMLElement = 500\r\n\t\t// Pane for overlay shadows (e.g. `Marker` shadows)\r\n\t\tthis.createPane('shadowPane');\r\n\t\t// @pane markerPane: HTMLElement = 600\r\n\t\t// Pane for `Icon`s of `Marker`s\r\n\t\tthis.createPane('markerPane');\r\n\t\t// @pane tooltipPane: HTMLElement = 650\r\n\t\t// Pane for `Tooltip`s.\r\n\t\tthis.createPane('tooltipPane');\r\n\t\t// @pane popupPane: HTMLElement = 700\r\n\t\t// Pane for `Popup`s.\r\n\t\tthis.createPane('popupPane');\r\n\r\n\t\tif (!this.options.markerZoomAnimation) {\r\n\t\t\tDomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');\r\n\t\t\tDomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');\r\n\t\t}\r\n\t},\r\n\r\n\r\n\t// private methods that modify map state\r\n\r\n\t// @section Map state change events\r\n\t_resetView: function (center, zoom, noMoveStart) {\r\n\t\tDomUtil.setPosition(this._mapPane, new Point(0, 0));\r\n\r\n\t\tvar loading = !this._loaded;\r\n\t\tthis._loaded = true;\r\n\t\tzoom = this._limitZoom(zoom);\r\n\r\n\t\tthis.fire('viewprereset');\r\n\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\t\tthis\r\n\t\t\t._moveStart(zoomChanged, noMoveStart)\r\n\t\t\t._move(center, zoom)\r\n\t\t\t._moveEnd(zoomChanged);\r\n\r\n\t\t// @event viewreset: Event\r\n\t\t// Fired when the map needs to redraw its content (this usually happens\r\n\t\t// on map zoom or load). Very useful for creating custom overlays.\r\n\t\tthis.fire('viewreset');\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the map is initialized (when its center and zoom are set\r\n\t\t// for the first time).\r\n\t\tif (loading) {\r\n\t\t\tthis.fire('load');\r\n\t\t}\r\n\t},\r\n\r\n\t_moveStart: function (zoomChanged, noMoveStart) {\r\n\t\t// @event zoomstart: Event\r\n\t\t// Fired when the map zoom is about to change (e.g. before zoom animation).\r\n\t\t// @event movestart: Event\r\n\t\t// Fired when the view of the map starts changing (e.g. user starts dragging the map).\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomstart');\r\n\t\t}\r\n\t\tif (!noMoveStart) {\r\n\t\t\tthis.fire('movestart');\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_move: function (center, zoom, data, supressEvent) {\r\n\t\tif (zoom === undefined) {\r\n\t\t\tzoom = this._zoom;\r\n\t\t}\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\r\n\t\tthis._zoom = zoom;\r\n\t\tthis._lastCenter = center;\r\n\t\tthis._pixelOrigin = this._getNewPixelOrigin(center);\r\n\r\n\t\tif (!supressEvent) {\r\n\t\t\t// @event zoom: Event\r\n\t\t\t// Fired repeatedly during any change in zoom level,\r\n\t\t\t// including zoom and fly animations.\r\n\t\t\tif (zoomChanged || (data && data.pinch)) {\t// Always fire 'zoom' if pinching because #3530\r\n\t\t\t\tthis.fire('zoom', data);\r\n\t\t\t}\r\n\r\n\t\t\t// @event move: Event\r\n\t\t\t// Fired repeatedly during any movement of the map,\r\n\t\t\t// including pan and fly animations.\r\n\t\t\tthis.fire('move', data);\r\n\t\t} else if (data && data.pinch) {\t// Always fire 'zoom' if pinching because #3530\r\n\t\t\tthis.fire('zoom', data);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_moveEnd: function (zoomChanged) {\r\n\t\t// @event zoomend: Event\r\n\t\t// Fired when the map zoom changed, after any animations.\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomend');\r\n\t\t}\r\n\r\n\t\t// @event moveend: Event\r\n\t\t// Fired when the center of the map stops changing\r\n\t\t// (e.g. user stopped dragging the map or after non-centered zoom).\r\n\t\treturn this.fire('moveend');\r\n\t},\r\n\r\n\t_stop: function () {\r\n\t\tUtil.cancelAnimFrame(this._flyToFrame);\r\n\t\tif (this._panAnim) {\r\n\t\t\tthis._panAnim.stop();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_rawPanBy: function (offset) {\r\n\t\tDomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));\r\n\t},\r\n\r\n\t_getZoomSpan: function () {\r\n\t\treturn this.getMaxZoom() - this.getMinZoom();\r\n\t},\r\n\r\n\t_panInsideMaxBounds: function () {\r\n\t\tif (!this._enforcingBounds) {\r\n\t\t\tthis.panInsideBounds(this.options.maxBounds);\r\n\t\t}\r\n\t},\r\n\r\n\t_checkIfLoaded: function () {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthrow new Error('Set map center and zoom first.');\r\n\t\t}\r\n\t},\r\n\r\n\t// DOM event handling\r\n\r\n\t// @section Interaction events\r\n\t_initEvents: function (remove) {\r\n\t\tthis._targets = {};\r\n\t\tthis._targets[Util.stamp(this._container)] = this;\r\n\r\n\t\tvar onOff = remove ? DomEvent.off : DomEvent.on;\r\n\r\n\t\t// @event click: MouseEvent\r\n\t\t// Fired when the user clicks (or taps) the map.\r\n\t\t// @event dblclick: MouseEvent\r\n\t\t// Fired when the user double-clicks (or double-taps) the map.\r\n\t\t// @event mousedown: MouseEvent\r\n\t\t// Fired when the user pushes the mouse button on the map.\r\n\t\t// @event mouseup: MouseEvent\r\n\t\t// Fired when the user releases the mouse button on the map.\r\n\t\t// @event mouseover: MouseEvent\r\n\t\t// Fired when the mouse enters the map.\r\n\t\t// @event mouseout: MouseEvent\r\n\t\t// Fired when the mouse leaves the map.\r\n\t\t// @event mousemove: MouseEvent\r\n\t\t// Fired while the mouse moves over the map.\r\n\t\t// @event contextmenu: MouseEvent\r\n\t\t// Fired when the user pushes the right mouse button on the map, prevents\r\n\t\t// default browser context menu from showing if there are listeners on\r\n\t\t// this event. Also fired on mobile when the user holds a single touch\r\n\t\t// for a second (also called long press).\r\n\t\t// @event keypress: KeyboardEvent\r\n\t\t// Fired when the user presses a key from the keyboard that produces a character value while the map is focused.\r\n\t\t// @event keydown: KeyboardEvent\r\n\t\t// Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event,\r\n\t\t// the `keydown` event is fired for keys that produce a character value and for keys\r\n\t\t// that do not produce a character value.\r\n\t\t// @event keyup: KeyboardEvent\r\n\t\t// Fired when the user releases a key from the keyboard while the map is focused.\r\n\t\tonOff(this._container, 'click dblclick mousedown mouseup ' +\r\n\t\t\t'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);\r\n\r\n\t\tif (this.options.trackResize) {\r\n\t\t\tonOff(window, 'resize', this._onResize, this);\r\n\t\t}\r\n\r\n\t\tif (Browser.any3d && this.options.transform3DLimit) {\r\n\t\t\t(remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);\r\n\t\t}\r\n\t},\r\n\r\n\t_onResize: function () {\r\n\t\tUtil.cancelAnimFrame(this._resizeRequest);\r\n\t\tthis._resizeRequest = Util.requestAnimFrame(\r\n\t\t function () { this.invalidateSize({debounceMoveend: true}); }, this);\r\n\t},\r\n\r\n\t_onScroll: function () {\r\n\t\tthis._container.scrollTop = 0;\r\n\t\tthis._container.scrollLeft = 0;\r\n\t},\r\n\r\n\t_onMoveEnd: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\tif (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {\r\n\t\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have\r\n\t\t\t// a pixel offset on very high values, see: https://jsfiddle.net/dg6r5hhb/\r\n\t\t\tthis._resetView(this.getCenter(), this.getZoom());\r\n\t\t}\r\n\t},\r\n\r\n\t_findEventTargets: function (e, type) {\r\n\t\tvar targets = [],\r\n\t\t target,\r\n\t\t isHover = type === 'mouseout' || type === 'mouseover',\r\n\t\t src = e.target || e.srcElement,\r\n\t\t dragging = false;\r\n\r\n\t\twhile (src) {\r\n\t\t\ttarget = this._targets[Util.stamp(src)];\r\n\t\t\tif (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {\r\n\t\t\t\t// Prevent firing click after you just dragged an object.\r\n\t\t\t\tdragging = true;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (target && target.listens(type, true)) {\r\n\t\t\t\tif (isHover && !DomEvent.isExternalTarget(src, e)) { break; }\r\n\t\t\t\ttargets.push(target);\r\n\t\t\t\tif (isHover) { break; }\r\n\t\t\t}\r\n\t\t\tif (src === this._container) { break; }\r\n\t\t\tsrc = src.parentNode;\r\n\t\t}\r\n\t\tif (!targets.length && !dragging && !isHover && this.listens(type, true)) {\r\n\t\t\ttargets = [this];\r\n\t\t}\r\n\t\treturn targets;\r\n\t},\r\n\r\n\t_isClickDisabled: function (el) {\r\n\t\twhile (el && el !== this._container) {\r\n\t\t\tif (el['_leaflet_disable_click']) { return true; }\r\n\t\t\tel = el.parentNode;\r\n\t\t}\r\n\t},\r\n\r\n\t_handleDOMEvent: function (e) {\r\n\t\tvar el = (e.target || e.srcElement);\r\n\t\tif (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar type = e.type;\r\n\r\n\t\tif (type === 'mousedown') {\r\n\t\t\t// prevents outline when clicking on keyboard-focusable element\r\n\t\t\tDomUtil.preventOutline(el);\r\n\t\t}\r\n\r\n\t\tthis._fireDOMEvent(e, type);\r\n\t},\r\n\r\n\t_mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],\r\n\r\n\t_fireDOMEvent: function (e, type, canvasTargets) {\r\n\r\n\t\tif (e.type === 'click') {\r\n\t\t\t// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).\r\n\t\t\t// @event preclick: MouseEvent\r\n\t\t\t// Fired before mouse click on the map (sometimes useful when you\r\n\t\t\t// want something to happen on click before any existing click\r\n\t\t\t// handlers start running).\r\n\t\t\tvar synth = Util.extend({}, e);\r\n\t\t\tsynth.type = 'preclick';\r\n\t\t\tthis._fireDOMEvent(synth, synth.type, canvasTargets);\r\n\t\t}\r\n\r\n\t\t// Find the layer the event is propagating from and its parents.\r\n\t\tvar targets = this._findEventTargets(e, type);\r\n\r\n\t\tif (canvasTargets) {\r\n\t\t\tvar filtered = []; // pick only targets with listeners\r\n\t\t\tfor (var i = 0; i < canvasTargets.length; i++) {\r\n\t\t\t\tif (canvasTargets[i].listens(type, true)) {\r\n\t\t\t\t\tfiltered.push(canvasTargets[i]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\ttargets = filtered.concat(targets);\r\n\t\t}\r\n\r\n\t\tif (!targets.length) { return; }\r\n\r\n\t\tif (type === 'contextmenu') {\r\n\t\t\tDomEvent.preventDefault(e);\r\n\t\t}\r\n\r\n\t\tvar target = targets[0];\r\n\t\tvar data = {\r\n\t\t\toriginalEvent: e\r\n\t\t};\r\n\r\n\t\tif (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {\r\n\t\t\tvar isMarker = target.getLatLng && (!target._radius || target._radius <= 10);\r\n\t\t\tdata.containerPoint = isMarker ?\r\n\t\t\t\tthis.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);\r\n\t\t\tdata.layerPoint = this.containerPointToLayerPoint(data.containerPoint);\r\n\t\t\tdata.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);\r\n\t\t}\r\n\r\n\t\tfor (i = 0; i < targets.length; i++) {\r\n\t\t\ttargets[i].fire(type, data, true);\r\n\t\t\tif (data.originalEvent._stopped ||\r\n\t\t\t\t(targets[i].options.bubblingMouseEvents === false && Util.indexOf(this._mouseEvents, type) !== -1)) { return; }\r\n\t\t}\r\n\t},\r\n\r\n\t_draggableMoved: function (obj) {\r\n\t\tobj = obj.dragging && obj.dragging.enabled() ? obj : this;\r\n\t\treturn (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());\r\n\t},\r\n\r\n\t_clearHandlers: function () {\r\n\t\tfor (var i = 0, len = this._handlers.length; i < len; i++) {\r\n\t\t\tthis._handlers[i].disable();\r\n\t\t}\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method whenReady(fn: Function, context?: Object): this\r\n\t// Runs the given function `fn` when the map gets initialized with\r\n\t// a view (center and zoom) and at least one layer, or immediately\r\n\t// if it's already initialized, optionally passing a function context.\r\n\twhenReady: function (callback, context) {\r\n\t\tif (this._loaded) {\r\n\t\t\tcallback.call(context || this, {target: this});\r\n\t\t} else {\r\n\t\t\tthis.on('load', callback, context);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\r\n\t// private methods for getting map state\r\n\r\n\t_getMapPanePos: function () {\r\n\t\treturn DomUtil.getPosition(this._mapPane) || new Point(0, 0);\r\n\t},\r\n\r\n\t_moved: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\treturn pos && !pos.equals([0, 0]);\r\n\t},\r\n\r\n\t_getTopLeftPoint: function (center, zoom) {\r\n\t\tvar pixelOrigin = center && zoom !== undefined ?\r\n\t\t\tthis._getNewPixelOrigin(center, zoom) :\r\n\t\t\tthis.getPixelOrigin();\r\n\t\treturn pixelOrigin.subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t_getNewPixelOrigin: function (center, zoom) {\r\n\t\tvar viewHalf = this.getSize()._divideBy(2);\r\n\t\treturn this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();\r\n\t},\r\n\r\n\t_latLngToNewLayerPoint: function (latlng, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn this.project(latlng, zoom)._subtract(topLeft);\r\n\t},\r\n\r\n\t_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn toBounds([\r\n\t\t\tthis.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)\r\n\t\t]);\r\n\t},\r\n\r\n\t// layer point of the current center\r\n\t_getCenterLayerPoint: function () {\r\n\t\treturn this.containerPointToLayerPoint(this.getSize()._divideBy(2));\r\n\t},\r\n\r\n\t// offset of the specified place to the current center in pixels\r\n\t_getCenterOffset: function (latlng) {\r\n\t\treturn this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// adjust center for view to get inside bounds\r\n\t_limitCenter: function (center, zoom, bounds) {\r\n\r\n\t\tif (!bounds) { return center; }\r\n\r\n\t\tvar centerPoint = this.project(center, zoom),\r\n\t\t viewHalf = this.getSize().divideBy(2),\r\n\t\t viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),\r\n\t\t offset = this._getBoundsOffset(viewBounds, bounds, zoom);\r\n\r\n\t\t// If offset is less than a pixel, ignore.\r\n\t\t// This prevents unstable projections from getting into\r\n\t\t// an infinite loop of tiny offsets.\r\n\t\tif (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {\r\n\t\t\treturn center;\r\n\t\t}\r\n\r\n\t\treturn this.unproject(centerPoint.add(offset), zoom);\r\n\t},\r\n\r\n\t// adjust offset for view to get inside bounds\r\n\t_limitOffset: function (offset, bounds) {\r\n\t\tif (!bounds) { return offset; }\r\n\r\n\t\tvar viewBounds = this.getPixelBounds(),\r\n\t\t newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));\r\n\r\n\t\treturn offset.add(this._getBoundsOffset(newBounds, bounds));\r\n\t},\r\n\r\n\t// returns offset needed for pxBounds to get inside maxBounds at a specified zoom\r\n\t_getBoundsOffset: function (pxBounds, maxBounds, zoom) {\r\n\t\tvar projectedMaxBounds = toBounds(\r\n\t\t this.project(maxBounds.getNorthEast(), zoom),\r\n\t\t this.project(maxBounds.getSouthWest(), zoom)\r\n\t\t ),\r\n\t\t minOffset = projectedMaxBounds.min.subtract(pxBounds.min),\r\n\t\t maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),\r\n\r\n\t\t dx = this._rebound(minOffset.x, -maxOffset.x),\r\n\t\t dy = this._rebound(minOffset.y, -maxOffset.y);\r\n\r\n\t\treturn new Point(dx, dy);\r\n\t},\r\n\r\n\t_rebound: function (left, right) {\r\n\t\treturn left + right > 0 ?\r\n\t\t\tMath.round(left - right) / 2 :\r\n\t\t\tMath.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));\r\n\t},\r\n\r\n\t_limitZoom: function (zoom) {\r\n\t\tvar min = this.getMinZoom(),\r\n\t\t max = this.getMaxZoom(),\r\n\t\t snap = Browser.any3d ? this.options.zoomSnap : 1;\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / snap) * snap;\r\n\t\t}\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t_onPanTransitionStep: function () {\r\n\t\tthis.fire('move');\r\n\t},\r\n\r\n\t_onPanTransitionEnd: function () {\r\n\t\tDomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');\r\n\t\tthis.fire('moveend');\r\n\t},\r\n\r\n\t_tryAnimatedPan: function (center, options) {\r\n\t\t// difference between the new and current centers in pixels\r\n\t\tvar offset = this._getCenterOffset(center)._trunc();\r\n\r\n\t\t// don't animate too far unless animate: true specified in options\r\n\t\tif ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tthis.panBy(offset, options);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_createAnimProxy: function () {\r\n\r\n\t\tvar proxy = this._proxy = DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');\r\n\t\tthis._panes.mapPane.appendChild(proxy);\r\n\r\n\t\tthis.on('zoomanim', function (e) {\r\n\t\t\tvar prop = DomUtil.TRANSFORM,\r\n\t\t\t transform = this._proxy.style[prop];\r\n\r\n\t\t\tDomUtil.setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));\r\n\r\n\t\t\t// workaround for case when transform is the same and so transitionend event is not fired\r\n\t\t\tif (transform === this._proxy.style[prop] && this._animatingZoom) {\r\n\t\t\t\tthis._onZoomTransitionEnd();\r\n\t\t\t}\r\n\t\t}, this);\r\n\r\n\t\tthis.on('load moveend', this._animMoveEnd, this);\r\n\r\n\t\tthis._on('unload', this._destroyAnimProxy, this);\r\n\t},\r\n\r\n\t_destroyAnimProxy: function () {\r\n\t\tDomUtil.remove(this._proxy);\r\n\t\tthis.off('load moveend', this._animMoveEnd, this);\r\n\t\tdelete this._proxy;\r\n\t},\r\n\r\n\t_animMoveEnd: function () {\r\n\t\tvar c = this.getCenter(),\r\n\t\t z = this.getZoom();\r\n\t\tDomUtil.setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));\r\n\t},\r\n\r\n\t_catchTransitionEnd: function (e) {\r\n\t\tif (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {\r\n\t\t\tthis._onZoomTransitionEnd();\r\n\t\t}\r\n\t},\r\n\r\n\t_nothingToAnimate: function () {\r\n\t\treturn !this._container.getElementsByClassName('leaflet-zoom-animated').length;\r\n\t},\r\n\r\n\t_tryAnimatedZoom: function (center, zoom, options) {\r\n\r\n\t\tif (this._animatingZoom) { return true; }\r\n\r\n\t\toptions = options || {};\r\n\r\n\t\t// don't animate if disabled, not supported or zoom difference is too large\r\n\t\tif (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||\r\n\t\t Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }\r\n\r\n\t\t// offset is the pixel coords of the zoom origin relative to the current center\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);\r\n\r\n\t\t// don't animate if the zoom origin isn't within one screen from the current center, unless forced\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tUtil.requestAnimFrame(function () {\r\n\t\t\tthis\r\n\t\t\t ._moveStart(true, false)\r\n\t\t\t ._animateZoom(center, zoom, true);\r\n\t\t}, this);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_animateZoom: function (center, zoom, startAnim, noUpdate) {\r\n\t\tif (!this._mapPane) { return; }\r\n\r\n\t\tif (startAnim) {\r\n\t\t\tthis._animatingZoom = true;\r\n\r\n\t\t\t// remember what center/zoom to set after animation\r\n\t\t\tthis._animateToCenter = center;\r\n\t\t\tthis._animateToZoom = zoom;\r\n\r\n\t\t\tDomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');\r\n\t\t}\r\n\r\n\t\t// @section Other Events\r\n\t\t// @event zoomanim: ZoomAnimEvent\r\n\t\t// Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom.\r\n\t\tthis.fire('zoomanim', {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom,\r\n\t\t\tnoUpdate: noUpdate\r\n\t\t});\r\n\r\n\t\tif (!this._tempFireZoomEvent) {\r\n\t\t\tthis._tempFireZoomEvent = this._zoom !== this._animateToZoom;\r\n\t\t}\r\n\r\n\t\tthis._move(this._animateToCenter, this._animateToZoom, undefined, true);\r\n\r\n\t\t// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693\r\n\t\tsetTimeout(Util.bind(this._onZoomTransitionEnd, this), 250);\r\n\t},\r\n\r\n\t_onZoomTransitionEnd: function () {\r\n\t\tif (!this._animatingZoom) { return; }\r\n\r\n\t\tif (this._mapPane) {\r\n\t\t\tDomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');\r\n\t\t}\r\n\r\n\t\tthis._animatingZoom = false;\r\n\r\n\t\tthis._move(this._animateToCenter, this._animateToZoom, undefined, true);\r\n\r\n\t\tif (this._tempFireZoomEvent) {\r\n\t\t\tthis.fire('zoom');\r\n\t\t}\r\n\t\tdelete this._tempFireZoomEvent;\r\n\r\n\t\tthis.fire('move');\r\n\r\n\t\tthis._moveEnd(true);\r\n\t}\r\n});\r\n\r\n// @section\r\n\r\n// @factory L.map(id: String, options?: Map options)\r\n// Instantiates a map object given the DOM ID of a `<div>` element\r\n// and optionally an object literal with `Map options`.\r\n//\r\n// @alternative\r\n// @factory L.map(el: HTMLElement, options?: Map options)\r\n// Instantiates a map object given an instance of a `<div>` HTML element\r\n// and optionally an object literal with `Map options`.\r\nexport function createMap(id, options) {\r\n\treturn new Map(id, options);\r\n}\r\n","\r\nimport {Class} from '../core/Class';\r\nimport {Map} from '../map/Map';\r\nimport * as Util from '../core/Util';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class Control\r\n * @aka L.Control\r\n * @inherits Class\r\n *\r\n * L.Control is a base class for implementing map controls. Handles positioning.\r\n * All other controls extend from this class.\r\n */\r\n\r\nexport var Control = Class.extend({\r\n\t// @section\r\n\t// @aka Control Options\r\n\toptions: {\r\n\t\t// @option position: String = 'topright'\r\n\t\t// The position of the control (one of the map corners). Possible values are `'topleft'`,\r\n\t\t// `'topright'`, `'bottomleft'` or `'bottomright'`\r\n\t\tposition: 'topright'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tUtil.setOptions(this, options);\r\n\t},\r\n\r\n\t/* @section\r\n\t * Classes extending L.Control will inherit the following methods:\r\n\t *\r\n\t * @method getPosition: string\r\n\t * Returns the position of the control.\r\n\t */\r\n\tgetPosition: function () {\r\n\t\treturn this.options.position;\r\n\t},\r\n\r\n\t// @method setPosition(position: string): this\r\n\t// Sets the position of the control.\r\n\tsetPosition: function (position) {\r\n\t\tvar map = this._map;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.removeControl(this);\r\n\t\t}\r\n\r\n\t\tthis.options.position = position;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.addControl(this);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTMLElement that contains the control.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method addTo(map: Map): this\r\n\t// Adds the control to the given map.\r\n\taddTo: function (map) {\r\n\t\tthis.remove();\r\n\t\tthis._map = map;\r\n\r\n\t\tvar container = this._container = this.onAdd(map),\r\n\t\t pos = this.getPosition(),\r\n\t\t corner = map._controlCorners[pos];\r\n\r\n\t\tDomUtil.addClass(container, 'leaflet-control');\r\n\r\n\t\tif (pos.indexOf('bottom') !== -1) {\r\n\t\t\tcorner.insertBefore(container, corner.firstChild);\r\n\t\t} else {\r\n\t\t\tcorner.appendChild(container);\r\n\t\t}\r\n\r\n\t\tthis._map.on('unload', this.remove, this);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove: this\r\n\t// Removes the control from the map it is currently active on.\r\n\tremove: function () {\r\n\t\tif (!this._map) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tDomUtil.remove(this._container);\r\n\r\n\t\tif (this.onRemove) {\r\n\t\t\tthis.onRemove(this._map);\r\n\t\t}\r\n\r\n\t\tthis._map.off('unload', this.remove, this);\r\n\t\tthis._map = null;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_refocusOnMap: function (e) {\r\n\t\t// if map exists and event is not a keyboard event\r\n\t\tif (this._map && e && e.screenX > 0 && e.screenY > 0) {\r\n\t\t\tthis._map.getContainer().focus();\r\n\t\t}\r\n\t}\r\n});\r\n\r\nexport var control = function (options) {\r\n\treturn new Control(options);\r\n};\r\n\r\n/* @section Extension methods\r\n * @uninheritable\r\n *\r\n * Every control should extend from `L.Control` and (re-)implement the following methods.\r\n *\r\n * @method onAdd(map: Map): HTMLElement\r\n * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).\r\n *\r\n * @method onRemove(map: Map)\r\n * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).\r\n */\r\n\r\n/* @namespace Map\r\n * @section Methods for Layers and Controls\r\n */\r\nMap.include({\r\n\t// @method addControl(control: Control): this\r\n\t// Adds the given control to the map\r\n\taddControl: function (control) {\r\n\t\tcontrol.addTo(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeControl(control: Control): this\r\n\t// Removes the given control from the map\r\n\tremoveControl: function (control) {\r\n\t\tcontrol.remove();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initControlPos: function () {\r\n\t\tvar corners = this._controlCorners = {},\r\n\t\t l = 'leaflet-',\r\n\t\t container = this._controlContainer =\r\n\t\t DomUtil.create('div', l + 'control-container', this._container);\r\n\r\n\t\tfunction createCorner(vSide, hSide) {\r\n\t\t\tvar className = l + vSide + ' ' + l + hSide;\r\n\r\n\t\t\tcorners[vSide + hSide] = DomUtil.create('div', className, container);\r\n\t\t}\r\n\r\n\t\tcreateCorner('top', 'left');\r\n\t\tcreateCorner('top', 'right');\r\n\t\tcreateCorner('bottom', 'left');\r\n\t\tcreateCorner('bottom', 'right');\r\n\t},\r\n\r\n\t_clearControlPos: function () {\r\n\t\tfor (var i in this._controlCorners) {\r\n\t\t\tDomUtil.remove(this._controlCorners[i]);\r\n\t\t}\r\n\t\tDomUtil.remove(this._controlContainer);\r\n\t\tdelete this._controlCorners;\r\n\t\tdelete this._controlContainer;\r\n\t}\r\n});\r\n","\r\nimport {Control} from './Control';\r\nimport * as Util from '../core/Util';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class Control.Layers\r\n * @aka L.Control.Layers\r\n * @inherits Control\r\n *\r\n * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var baseLayers = {\r\n * \t\"Mapbox\": mapbox,\r\n * \t\"OpenStreetMap\": osm\r\n * };\r\n *\r\n * var overlays = {\r\n * \t\"Marker\": marker,\r\n * \t\"Roads\": roadsLayer\r\n * };\r\n *\r\n * L.control.layers(baseLayers, overlays).addTo(map);\r\n * ```\r\n *\r\n * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:\r\n *\r\n * ```js\r\n * {\r\n * \"<someName1>\": layer1,\r\n * \"<someName2>\": layer2\r\n * }\r\n * ```\r\n *\r\n * The layer names can contain HTML, which allows you to add additional styling to the items:\r\n *\r\n * ```js\r\n * {\"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>\": myLayer}\r\n * ```\r\n */\r\n\r\nexport var Layers = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Layers options\r\n\toptions: {\r\n\t\t// @option collapsed: Boolean = true\r\n\t\t// If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.\r\n\t\tcollapsed: true,\r\n\t\tposition: 'topright',\r\n\r\n\t\t// @option autoZIndex: Boolean = true\r\n\t\t// If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.\r\n\t\tautoZIndex: true,\r\n\r\n\t\t// @option hideSingleBase: Boolean = false\r\n\t\t// If `true`, the base layers in the control will be hidden when there is only one.\r\n\t\thideSingleBase: false,\r\n\r\n\t\t// @option sortLayers: Boolean = false\r\n\t\t// Whether to sort the layers. When `false`, layers will keep the order\r\n\t\t// in which they were added to the control.\r\n\t\tsortLayers: false,\r\n\r\n\t\t// @option sortFunction: Function = *\r\n\t\t// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)\r\n\t\t// that will be used for sorting the layers, when `sortLayers` is `true`.\r\n\t\t// The function receives both the `L.Layer` instances and their names, as in\r\n\t\t// `sortFunction(layerA, layerB, nameA, nameB)`.\r\n\t\t// By default, it sorts layers alphabetically by their name.\r\n\t\tsortFunction: function (layerA, layerB, nameA, nameB) {\r\n\t\t\treturn nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);\r\n\t\t}\r\n\t},\r\n\r\n\tinitialize: function (baseLayers, overlays, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tthis._layers = [];\r\n\t\tthis._lastZIndex = 0;\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tfor (var i in baseLayers) {\r\n\t\t\tthis._addLayer(baseLayers[i], i);\r\n\t\t}\r\n\r\n\t\tfor (i in overlays) {\r\n\t\t\tthis._addLayer(overlays[i], i, true);\r\n\t\t}\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._initLayout();\r\n\t\tthis._update();\r\n\r\n\t\tthis._map = map;\r\n\t\tmap.on('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\taddTo: function (map) {\r\n\t\tControl.prototype.addTo.call(this, map);\r\n\t\t// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.\r\n\t\treturn this._expandIfNotCollapsed();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tthis._map.off('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.off('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addBaseLayer(layer: Layer, name: String): this\r\n\t// Adds a base layer (radio button entry) with the given name to the control.\r\n\taddBaseLayer: function (layer, name) {\r\n\t\tthis._addLayer(layer, name);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method addOverlay(layer: Layer, name: String): this\r\n\t// Adds an overlay (checkbox entry) with the given name to the control.\r\n\taddOverlay: function (layer, name) {\r\n\t\tthis._addLayer(layer, name, true);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Remove the given layer from the control.\r\n\tremoveLayer: function (layer) {\r\n\t\tlayer.off('add remove', this._onLayerChange, this);\r\n\r\n\t\tvar obj = this._getLayer(Util.stamp(layer));\r\n\t\tif (obj) {\r\n\t\t\tthis._layers.splice(this._layers.indexOf(obj), 1);\r\n\t\t}\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method expand(): this\r\n\t// Expand the control container if collapsed.\r\n\texpand: function () {\r\n\t\tDomUtil.addClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\tthis._section.style.height = null;\r\n\t\tvar acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);\r\n\t\tif (acceptableHeight < this._section.clientHeight) {\r\n\t\t\tDomUtil.addClass(this._section, 'leaflet-control-layers-scrollbar');\r\n\t\t\tthis._section.style.height = acceptableHeight + 'px';\r\n\t\t} else {\r\n\t\t\tDomUtil.removeClass(this._section, 'leaflet-control-layers-scrollbar');\r\n\t\t}\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method collapse(): this\r\n\t// Collapse the control container if expanded.\r\n\tcollapse: function () {\r\n\t\tDomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar className = 'leaflet-control-layers',\r\n\t\t container = this._container = DomUtil.create('div', className),\r\n\t\t collapsed = this.options.collapsed;\r\n\r\n\t\t// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released\r\n\t\tcontainer.setAttribute('aria-haspopup', true);\r\n\r\n\t\tDomEvent.disableClickPropagation(container);\r\n\t\tDomEvent.disableScrollPropagation(container);\r\n\r\n\t\tvar section = this._section = DomUtil.create('section', className + '-list');\r\n\r\n\t\tif (collapsed) {\r\n\t\t\tthis._map.on('click', this.collapse, this);\r\n\r\n\t\t\tDomEvent.on(container, {\r\n\t\t\t\tmouseenter: this._expandSafely,\r\n\t\t\t\tmouseleave: this.collapse\r\n\t\t\t}, this);\r\n\t\t}\r\n\r\n\t\tvar link = this._layersLink = DomUtil.create('a', className + '-toggle', container);\r\n\t\tlink.href = '#';\r\n\t\tlink.title = 'Layers';\r\n\t\tlink.setAttribute('role', 'button');\r\n\r\n\t\tDomEvent.on(link, {\r\n\t\t\tkeydown: function (e) {\r\n\t\t\t\tif (e.keyCode === 13) {\r\n\t\t\t\t\tthis._expandSafely();\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t// Certain screen readers intercept the key event and instead send a click event\r\n\t\t\tclick: function (e) {\r\n\t\t\t\tDomEvent.preventDefault(e);\r\n\t\t\t\tthis._expandSafely();\r\n\t\t\t}\r\n\t\t}, this);\r\n\r\n\t\tif (!collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\r\n\t\tthis._baseLayersList = DomUtil.create('div', className + '-base', section);\r\n\t\tthis._separator = DomUtil.create('div', className + '-separator', section);\r\n\t\tthis._overlaysList = DomUtil.create('div', className + '-overlays', section);\r\n\r\n\t\tcontainer.appendChild(section);\r\n\t},\r\n\r\n\t_getLayer: function (id) {\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\r\n\t\t\tif (this._layers[i] && Util.stamp(this._layers[i].layer) === id) {\r\n\t\t\t\treturn this._layers[i];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_addLayer: function (layer, name, overlay) {\r\n\t\tif (this._map) {\r\n\t\t\tlayer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\tthis._layers.push({\r\n\t\t\tlayer: layer,\r\n\t\t\tname: name,\r\n\t\t\toverlay: overlay\r\n\t\t});\r\n\r\n\t\tif (this.options.sortLayers) {\r\n\t\t\tthis._layers.sort(Util.bind(function (a, b) {\r\n\t\t\t\treturn this.options.sortFunction(a.layer, b.layer, a.name, b.name);\r\n\t\t\t}, this));\r\n\t\t}\r\n\r\n\t\tif (this.options.autoZIndex && layer.setZIndex) {\r\n\t\t\tthis._lastZIndex++;\r\n\t\t\tlayer.setZIndex(this._lastZIndex);\r\n\t\t}\r\n\r\n\t\tthis._expandIfNotCollapsed();\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._container) { return this; }\r\n\r\n\t\tDomUtil.empty(this._baseLayersList);\r\n\t\tDomUtil.empty(this._overlaysList);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tvar baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;\r\n\r\n\t\tfor (i = 0; i < this._layers.length; i++) {\r\n\t\t\tobj = this._layers[i];\r\n\t\t\tthis._addItem(obj);\r\n\t\t\toverlaysPresent = overlaysPresent || obj.overlay;\r\n\t\t\tbaseLayersPresent = baseLayersPresent || !obj.overlay;\r\n\t\t\tbaseLayersCount += !obj.overlay ? 1 : 0;\r\n\t\t}\r\n\r\n\t\t// Hide base layers section if there's only one layer.\r\n\t\tif (this.options.hideSingleBase) {\r\n\t\t\tbaseLayersPresent = baseLayersPresent && baseLayersCount > 1;\r\n\t\t\tthis._baseLayersList.style.display = baseLayersPresent ? '' : 'none';\r\n\t\t}\r\n\r\n\t\tthis._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_onLayerChange: function (e) {\r\n\t\tif (!this._handlingClick) {\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\tvar obj = this._getLayer(Util.stamp(e.target));\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Layer events\r\n\t\t// @event baselayerchange: LayersControlEvent\r\n\t\t// Fired when the base layer is changed through the [layers control](#control-layers).\r\n\t\t// @event overlayadd: LayersControlEvent\r\n\t\t// Fired when an overlay is selected through the [layers control](#control-layers).\r\n\t\t// @event overlayremove: LayersControlEvent\r\n\t\t// Fired when an overlay is deselected through the [layers control](#control-layers).\r\n\t\t// @namespace Control.Layers\r\n\t\tvar type = obj.overlay ?\r\n\t\t\t(e.type === 'add' ? 'overlayadd' : 'overlayremove') :\r\n\t\t\t(e.type === 'add' ? 'baselayerchange' : null);\r\n\r\n\t\tif (type) {\r\n\t\t\tthis._map.fire(type, obj);\r\n\t\t}\r\n\t},\r\n\r\n\t// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)\r\n\t_createRadioElement: function (name, checked) {\r\n\r\n\t\tvar radioHtml = '<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\"' +\r\n\t\t\t\tname + '\"' + (checked ? ' checked=\"checked\"' : '') + '/>';\r\n\r\n\t\tvar radioFragment = document.createElement('div');\r\n\t\tradioFragment.innerHTML = radioHtml;\r\n\r\n\t\treturn radioFragment.firstChild;\r\n\t},\r\n\r\n\t_addItem: function (obj) {\r\n\t\tvar label = document.createElement('label'),\r\n\t\t checked = this._map.hasLayer(obj.layer),\r\n\t\t input;\r\n\r\n\t\tif (obj.overlay) {\r\n\t\t\tinput = document.createElement('input');\r\n\t\t\tinput.type = 'checkbox';\r\n\t\t\tinput.className = 'leaflet-control-layers-selector';\r\n\t\t\tinput.defaultChecked = checked;\r\n\t\t} else {\r\n\t\t\tinput = this._createRadioElement('leaflet-base-layers_' + Util.stamp(this), checked);\r\n\t\t}\r\n\r\n\t\tthis._layerControlInputs.push(input);\r\n\t\tinput.layerId = Util.stamp(obj.layer);\r\n\r\n\t\tDomEvent.on(input, 'click', this._onInputClick, this);\r\n\r\n\t\tvar name = document.createElement('span');\r\n\t\tname.innerHTML = ' ' + obj.name;\r\n\r\n\t\t// Helps from preventing layer control flicker when checkboxes are disabled\r\n\t\t// https://github.com/Leaflet/Leaflet/issues/2771\r\n\t\tvar holder = document.createElement('span');\r\n\r\n\t\tlabel.appendChild(holder);\r\n\t\tholder.appendChild(input);\r\n\t\tholder.appendChild(name);\r\n\r\n\t\tvar container = obj.overlay ? this._overlaysList : this._baseLayersList;\r\n\t\tcontainer.appendChild(label);\r\n\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn label;\r\n\t},\r\n\r\n\t_onInputClick: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input, layer;\r\n\t\tvar addedLayers = [],\r\n\t\t removedLayers = [];\r\n\r\n\t\tthis._handlingClick = true;\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\r\n\t\t\tif (input.checked) {\r\n\t\t\t\taddedLayers.push(layer);\r\n\t\t\t} else if (!input.checked) {\r\n\t\t\t\tremovedLayers.push(layer);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Bugfix issue 2318: Should remove all old layers before readding new ones\r\n\t\tfor (i = 0; i < removedLayers.length; i++) {\r\n\t\t\tif (this._map.hasLayer(removedLayers[i])) {\r\n\t\t\t\tthis._map.removeLayer(removedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (i = 0; i < addedLayers.length; i++) {\r\n\t\t\tif (!this._map.hasLayer(addedLayers[i])) {\r\n\t\t\t\tthis._map.addLayer(addedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tthis._refocusOnMap();\r\n\t},\r\n\r\n\t_checkDisabledLayers: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input,\r\n\t\t layer,\r\n\t\t zoom = this._map.getZoom();\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\t\t\tinput.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||\r\n\t\t\t (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_expandIfNotCollapsed: function () {\r\n\t\tif (this._map && !this.options.collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_expandSafely: function () {\r\n\t\tvar section = this._section;\r\n\t\tDomEvent.on(section, 'click', DomEvent.preventDefault);\r\n\t\tthis.expand();\r\n\t\tsetTimeout(function () {\r\n\t\t\tDomEvent.off(section, 'click', DomEvent.preventDefault);\r\n\t\t});\r\n\t}\r\n\r\n});\r\n\r\n\r\n// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)\r\n// Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.\r\nexport var layers = function (baseLayers, overlays, options) {\r\n\treturn new Layers(baseLayers, overlays, options);\r\n};\r\n","\r\nimport {Control} from './Control';\r\nimport {Map} from '../map/Map';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport * as DomEvent from '../dom/DomEvent';\r\n\r\n/*\r\n * @class Control.Zoom\r\n * @aka L.Control.Zoom\r\n * @inherits Control\r\n *\r\n * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.\r\n */\r\n\r\nexport var Zoom = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Zoom options\r\n\toptions: {\r\n\t\tposition: 'topleft',\r\n\r\n\t\t// @option zoomInText: String = '<span aria-hidden=\"true\">+</span>'\r\n\t\t// The text set on the 'zoom in' button.\r\n\t\tzoomInText: '<span aria-hidden=\"true\">+</span>',\r\n\r\n\t\t// @option zoomInTitle: String = 'Zoom in'\r\n\t\t// The title set on the 'zoom in' button.\r\n\t\tzoomInTitle: 'Zoom in',\r\n\r\n\t\t// @option zoomOutText: String = '<span aria-hidden=\"true\">&#x2212;</span>'\r\n\t\t// The text set on the 'zoom out' button.\r\n\t\tzoomOutText: '<span aria-hidden=\"true\">&#x2212;</span>',\r\n\r\n\t\t// @option zoomOutTitle: String = 'Zoom out'\r\n\t\t// The title set on the 'zoom out' button.\r\n\t\tzoomOutTitle: 'Zoom out'\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tvar zoomName = 'leaflet-control-zoom',\r\n\t\t container = DomUtil.create('div', zoomName + ' leaflet-bar'),\r\n\t\t options = this.options;\r\n\r\n\t\tthis._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,\r\n\t\t zoomName + '-in', container, this._zoomIn);\r\n\t\tthis._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,\r\n\t\t zoomName + '-out', container, this._zoomOut);\r\n\r\n\t\tthis._updateDisabled();\r\n\t\tmap.on('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\r\n\t\treturn container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\t},\r\n\r\n\tdisable: function () {\r\n\t\tthis._disabled = true;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\tenable: function () {\r\n\t\tthis._disabled = false;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_zoomIn: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {\r\n\t\t\tthis._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_zoomOut: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom > this._map.getMinZoom()) {\r\n\t\t\tthis._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_createButton: function (html, title, className, container, fn) {\r\n\t\tvar link = DomUtil.create('a', className, container);\r\n\t\tlink.innerHTML = html;\r\n\t\tlink.href = '#';\r\n\t\tlink.title = title;\r\n\r\n\t\t/*\r\n\t\t * Will force screen readers like VoiceOver to read this as \"Zoom in - button\"\r\n\t\t */\r\n\t\tlink.setAttribute('role', 'button');\r\n\t\tlink.setAttribute('aria-label', title);\r\n\r\n\t\tDomEvent.disableClickPropagation(link);\r\n\t\tDomEvent.on(link, 'click', DomEvent.stop);\r\n\t\tDomEvent.on(link, 'click', fn, this);\r\n\t\tDomEvent.on(link, 'click', this._refocusOnMap, this);\r\n\r\n\t\treturn link;\r\n\t},\r\n\r\n\t_updateDisabled: function () {\r\n\t\tvar map = this._map,\r\n\t\t className = 'leaflet-disabled';\r\n\r\n\t\tDomUtil.removeClass(this._zoomInButton, className);\r\n\t\tDomUtil.removeClass(this._zoomOutButton, className);\r\n\t\tthis._zoomInButton.setAttribute('aria-disabled', 'false');\r\n\t\tthis._zoomOutButton.setAttribute('aria-disabled', 'false');\r\n\r\n\t\tif (this._disabled || map._zoom === map.getMinZoom()) {\r\n\t\t\tDomUtil.addClass(this._zoomOutButton, className);\r\n\t\t\tthis._zoomOutButton.setAttribute('aria-disabled', 'true');\r\n\t\t}\r\n\t\tif (this._disabled || map._zoom === map.getMaxZoom()) {\r\n\t\t\tDomUtil.addClass(this._zoomInButton, className);\r\n\t\t\tthis._zoomInButton.setAttribute('aria-disabled', 'true');\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option zoomControl: Boolean = true\r\n// Whether a [zoom control](#control-zoom) is added to the map by default.\r\nMap.mergeOptions({\r\n\tzoomControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.zoomControl) {\r\n\t\t// @section Controls\r\n\t\t// @property zoomControl: Control.Zoom\r\n\t\t// The default zoom control (only available if the\r\n\t\t// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).\r\n\t\tthis.zoomControl = new Zoom();\r\n\t\tthis.addControl(this.zoomControl);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Zoom\r\n// @factory L.control.zoom(options: Control.Zoom options)\r\n// Creates a zoom control\r\nexport var zoom = function (options) {\r\n\treturn new Zoom(options);\r\n};\r\n","\nimport {Control} from './Control';\nimport * as DomUtil from '../dom/DomUtil';\n\n/*\n * @class Control.Scale\n * @aka L.Control.Scale\n * @inherits Control\n *\n * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.\n *\n * @example\n *\n * ```js\n * L.control.scale().addTo(map);\n * ```\n */\n\nexport var Scale = Control.extend({\n\t// @section\n\t// @aka Control.Scale options\n\toptions: {\n\t\tposition: 'bottomleft',\n\n\t\t// @option maxWidth: Number = 100\n\t\t// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).\n\t\tmaxWidth: 100,\n\n\t\t// @option metric: Boolean = True\n\t\t// Whether to show the metric scale line (m/km).\n\t\tmetric: true,\n\n\t\t// @option imperial: Boolean = True\n\t\t// Whether to show the imperial scale line (mi/ft).\n\t\timperial: true\n\n\t\t// @option updateWhenIdle: Boolean = false\n\t\t// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).\n\t},\n\n\tonAdd: function (map) {\n\t\tvar className = 'leaflet-control-scale',\n\t\t container = DomUtil.create('div', className),\n\t\t options = this.options;\n\n\t\tthis._addScales(options, className + '-line', container);\n\n\t\tmap.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t\tmap.whenReady(this._update, this);\n\n\t\treturn container;\n\t},\n\n\tonRemove: function (map) {\n\t\tmap.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t},\n\n\t_addScales: function (options, className, container) {\n\t\tif (options.metric) {\n\t\t\tthis._mScale = DomUtil.create('div', className, container);\n\t\t}\n\t\tif (options.imperial) {\n\t\t\tthis._iScale = DomUtil.create('div', className, container);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tvar map = this._map,\n\t\t y = map.getSize().y / 2;\n\n\t\tvar maxMeters = map.distance(\n\t\t\tmap.containerPointToLatLng([0, y]),\n\t\t\tmap.containerPointToLatLng([this.options.maxWidth, y]));\n\n\t\tthis._updateScales(maxMeters);\n\t},\n\n\t_updateScales: function (maxMeters) {\n\t\tif (this.options.metric && maxMeters) {\n\t\t\tthis._updateMetric(maxMeters);\n\t\t}\n\t\tif (this.options.imperial && maxMeters) {\n\t\t\tthis._updateImperial(maxMeters);\n\t\t}\n\t},\n\n\t_updateMetric: function (maxMeters) {\n\t\tvar meters = this._getRoundNum(maxMeters),\n\t\t label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';\n\n\t\tthis._updateScale(this._mScale, label, meters / maxMeters);\n\t},\n\n\t_updateImperial: function (maxMeters) {\n\t\tvar maxFeet = maxMeters * 3.2808399,\n\t\t maxMiles, miles, feet;\n\n\t\tif (maxFeet > 5280) {\n\t\t\tmaxMiles = maxFeet / 5280;\n\t\t\tmiles = this._getRoundNum(maxMiles);\n\t\t\tthis._updateScale(this._iScale, miles + ' mi', miles / maxMiles);\n\n\t\t} else {\n\t\t\tfeet = this._getRoundNum(maxFeet);\n\t\t\tthis._updateScale(this._iScale, feet + ' ft', feet / maxFeet);\n\t\t}\n\t},\n\n\t_updateScale: function (scale, text, ratio) {\n\t\tscale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';\n\t\tscale.innerHTML = text;\n\t},\n\n\t_getRoundNum: function (num) {\n\t\tvar pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),\n\t\t d = num / pow10;\n\n\t\td = d >= 10 ? 10 :\n\t\t d >= 5 ? 5 :\n\t\t d >= 3 ? 3 :\n\t\t d >= 2 ? 2 : 1;\n\n\t\treturn pow10 * d;\n\t}\n});\n\n\n// @factory L.control.scale(options?: Control.Scale options)\n// Creates an scale control with the given options.\nexport var scale = function (options) {\n\treturn new Scale(options);\n};\n","\r\nimport {Control} from './Control';\r\nimport {Map} from '../map/Map';\r\nimport * as Util from '../core/Util';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport Browser from '../core/Browser';\r\n\r\nvar ukrainianFlag = '<svg aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"8\" viewBox=\"0 0 12 8\" class=\"leaflet-attribution-flag\"><path fill=\"#4C7BE1\" d=\"M0 0h12v4H0z\"/><path fill=\"#FFD500\" d=\"M0 4h12v3H0z\"/><path fill=\"#E0BC00\" d=\"M0 7h12v1H0z\"/></svg>';\r\n\r\n\r\n/*\r\n * @class Control.Attribution\r\n * @aka L.Control.Attribution\r\n * @inherits Control\r\n *\r\n * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.\r\n */\r\n\r\nexport var Attribution = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Attribution options\r\n\toptions: {\r\n\t\tposition: 'bottomright',\r\n\r\n\t\t// @option prefix: String|false = 'Leaflet'\r\n\t\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\t\tprefix: '<a href=\"https://leafletjs.com\" title=\"A JavaScript library for interactive maps\">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._attributions = {};\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tmap.attributionControl = this;\r\n\t\tthis._container = DomUtil.create('div', 'leaflet-control-attribution');\r\n\t\tDomEvent.disableClickPropagation(this._container);\r\n\r\n\t\t// TODO ugly, refactor\r\n\t\tfor (var i in map._layers) {\r\n\t\t\tif (map._layers[i].getAttribution) {\r\n\t\t\t\tthis.addAttribution(map._layers[i].getAttribution());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._update();\r\n\r\n\t\tmap.on('layeradd', this._addAttribution, this);\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('layeradd', this._addAttribution, this);\r\n\t},\r\n\r\n\t_addAttribution: function (ev) {\r\n\t\tif (ev.layer.getAttribution) {\r\n\t\t\tthis.addAttribution(ev.layer.getAttribution());\r\n\t\t\tev.layer.once('remove', function () {\r\n\t\t\t\tthis.removeAttribution(ev.layer.getAttribution());\r\n\t\t\t}, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setPrefix(prefix: String|false): this\r\n\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\tsetPrefix: function (prefix) {\r\n\t\tthis.options.prefix = prefix;\r\n\t\tthis._update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addAttribution(text: String): this\r\n\t// Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).\r\n\taddAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (!this._attributions[text]) {\r\n\t\t\tthis._attributions[text] = 0;\r\n\t\t}\r\n\t\tthis._attributions[text]++;\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeAttribution(text: String): this\r\n\t// Removes an attribution text.\r\n\tremoveAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (this._attributions[text]) {\r\n\t\t\tthis._attributions[text]--;\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar attribs = [];\r\n\r\n\t\tfor (var i in this._attributions) {\r\n\t\t\tif (this._attributions[i]) {\r\n\t\t\t\tattribs.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar prefixAndAttribs = [];\r\n\r\n\t\tif (this.options.prefix) {\r\n\t\t\tprefixAndAttribs.push(this.options.prefix);\r\n\t\t}\r\n\t\tif (attribs.length) {\r\n\t\t\tprefixAndAttribs.push(attribs.join(', '));\r\n\t\t}\r\n\r\n\t\tthis._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden=\"true\">|</span> ');\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option attributionControl: Boolean = true\r\n// Whether a [attribution control](#control-attribution) is added to the map by default.\r\nMap.mergeOptions({\r\n\tattributionControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.attributionControl) {\r\n\t\tnew Attribution().addTo(this);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Attribution\r\n// @factory L.control.attribution(options: Control.Attribution options)\r\n// Creates an attribution control.\r\nexport var attribution = function (options) {\r\n\treturn new Attribution(options);\r\n};\r\n","import {Control, control} from './Control';\nimport {Layers, layers} from './Control.Layers';\nimport {Zoom, zoom} from './Control.Zoom';\nimport {Scale, scale} from './Control.Scale';\nimport {Attribution, attribution} from './Control.Attribution';\n\nControl.Layers = Layers;\nControl.Zoom = Zoom;\nControl.Scale = Scale;\nControl.Attribution = Attribution;\n\ncontrol.layers = layers;\ncontrol.zoom = zoom;\ncontrol.scale = scale;\ncontrol.attribution = attribution;\n\nexport {Control, control};\n","import {Class} from './Class';\n\n/*\n\tL.Handler is a base class for handler classes that are used internally to inject\n\tinteraction features like dragging to classes like Map and Marker.\n*/\n\n// @class Handler\n// @aka L.Handler\n// Abstract class for map interaction handlers\n\nexport var Handler = Class.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t},\n\n\t// @method enable(): this\n\t// Enables the handler\n\tenable: function () {\n\t\tif (this._enabled) { return this; }\n\n\t\tthis._enabled = true;\n\t\tthis.addHooks();\n\t\treturn this;\n\t},\n\n\t// @method disable(): this\n\t// Disables the handler\n\tdisable: function () {\n\t\tif (!this._enabled) { return this; }\n\n\t\tthis._enabled = false;\n\t\tthis.removeHooks();\n\t\treturn this;\n\t},\n\n\t// @method enabled(): Boolean\n\t// Returns `true` if the handler is enabled\n\tenabled: function () {\n\t\treturn !!this._enabled;\n\t}\n\n\t// @section Extension methods\n\t// Classes inheriting from `Handler` must implement the two following methods:\n\t// @method addHooks()\n\t// Called when the handler is enabled, should add event hooks.\n\t// @method removeHooks()\n\t// Called when the handler is disabled, should remove the event hooks added previously.\n});\n\n// @section There is static function which can be called without instantiating L.Handler:\n// @function addTo(map: Map, name: String): this\n// Adds a new Handler to the given map with the given name.\nHandler.addTo = function (map, name) {\n\tmap.addHandler(name, this);\n\treturn this;\n};\n","import Browser from './Browser';\nexport {Browser};\n\nexport {Class} from './Class';\n\nimport {Evented} from './Events';\nimport {Events} from './Events';\nexport {Evented};\nexport var Mixin = {Events: Events};\n\nexport {Handler} from './Handler';\n\nimport * as Util from './Util';\nexport {Util};\nexport {extend, bind, stamp, setOptions} from './Util';\n","import {Evented} from '../core/Events';\r\nimport Browser from '../core/Browser';\r\nimport * as DomEvent from './DomEvent';\r\nimport * as DomUtil from './DomUtil';\r\nimport * as Util from '../core/Util';\r\nimport {Point} from '../geometry/Point';\r\n\r\n/*\r\n * @class Draggable\r\n * @aka L.Draggable\r\n * @inherits Evented\r\n *\r\n * A class for making DOM elements draggable (including touch support).\r\n * Used internally for map and marker dragging. Only works for elements\r\n * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).\r\n *\r\n * @example\r\n * ```js\r\n * var draggable = new L.Draggable(elementToDrag);\r\n * draggable.enable();\r\n * ```\r\n */\r\n\r\nvar START = Browser.touch ? 'touchstart mousedown' : 'mousedown';\r\n\r\nexport var Draggable = Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section\r\n\t\t// @aka Draggable options\r\n\t\t// @option clickTolerance: Number = 3\r\n\t\t// The max number of pixels a user can shift the mouse pointer during a click\r\n\t\t// for it to be considered a valid click (as opposed to a mouse drag).\r\n\t\tclickTolerance: 3\r\n\t},\r\n\r\n\t// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)\r\n\t// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).\r\n\tinitialize: function (element, dragStartTarget, preventOutline, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._element = element;\r\n\t\tthis._dragStartTarget = dragStartTarget || element;\r\n\t\tthis._preventOutline = preventOutline;\r\n\t},\r\n\r\n\t// @method enable()\r\n\t// Enables the dragging ability\r\n\tenable: function () {\r\n\t\tif (this._enabled) { return; }\r\n\r\n\t\tDomEvent.on(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = true;\r\n\t},\r\n\r\n\t// @method disable()\r\n\t// Disables the dragging ability\r\n\tdisable: function () {\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\t// If we're currently dragging this draggable,\r\n\t\t// disabling it counts as first ending the drag.\r\n\t\tif (Draggable._dragging === this) {\r\n\t\t\tthis.finishDrag(true);\r\n\t\t}\r\n\r\n\t\tDomEvent.off(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = false;\r\n\t\tthis._moved = false;\r\n\t},\r\n\r\n\t_onDown: function (e) {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\tthis._moved = false;\r\n\r\n\t\tif (DomUtil.hasClass(this._element, 'leaflet-zoom-anim')) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length !== 1) {\r\n\t\t\t// Finish dragging to avoid conflict with touchZoom\r\n\t\t\tif (Draggable._dragging === this) {\r\n\t\t\t\tthis.finishDrag();\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }\r\n\t\tDraggable._dragging = this; // Prevent dragging multiple objects at once.\r\n\r\n\t\tif (this._preventOutline) {\r\n\t\t\tDomUtil.preventOutline(this._element);\r\n\t\t}\r\n\r\n\t\tDomUtil.disableImageDrag();\r\n\t\tDomUtil.disableTextSelection();\r\n\r\n\t\tif (this._moving) { return; }\r\n\r\n\t\t// @event down: Event\r\n\t\t// Fired when a drag is about to start.\r\n\t\tthis.fire('down');\r\n\r\n\t\tvar first = e.touches ? e.touches[0] : e,\r\n\t\t sizedParent = DomUtil.getSizedParentNode(this._element);\r\n\r\n\t\tthis._startPoint = new Point(first.clientX, first.clientY);\r\n\t\tthis._startPos = DomUtil.getPosition(this._element);\r\n\r\n\t\t// Cache the scale, so that we can continuously compensate for it during drag (_onMove).\r\n\t\tthis._parentScale = DomUtil.getScale(sizedParent);\r\n\r\n\t\tvar mouseevent = e.type === 'mousedown';\r\n\t\tDomEvent.on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this);\r\n\t\tDomEvent.on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this);\r\n\t},\r\n\r\n\t_onMove: function (e) {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length > 1) {\r\n\t\t\tthis._moved = true;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\r\n\t\t offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);\r\n\r\n\t\tif (!offset.x && !offset.y) { return; }\r\n\t\tif (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }\r\n\r\n\t\t// We assume that the parent container's position, border and scale do not change for the duration of the drag.\r\n\t\t// Therefore there is no need to account for the position and border (they are eliminated by the subtraction)\r\n\t\t// and we can use the cached value for the scale.\r\n\t\toffset.x /= this._parentScale.x;\r\n\t\toffset.y /= this._parentScale.y;\r\n\r\n\t\tDomEvent.preventDefault(e);\r\n\r\n\t\tif (!this._moved) {\r\n\t\t\t// @event dragstart: Event\r\n\t\t\t// Fired when a drag starts\r\n\t\t\tthis.fire('dragstart');\r\n\r\n\t\t\tthis._moved = true;\r\n\r\n\t\t\tDomUtil.addClass(document.body, 'leaflet-dragging');\r\n\r\n\t\t\tthis._lastTarget = e.target || e.srcElement;\r\n\t\t\t// IE and Edge do not give the <use> element, so fetch it\r\n\t\t\t// if necessary\r\n\t\t\tif (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {\r\n\t\t\t\tthis._lastTarget = this._lastTarget.correspondingUseElement;\r\n\t\t\t}\r\n\t\t\tDomUtil.addClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t}\r\n\r\n\t\tthis._newPos = this._startPos.add(offset);\r\n\t\tthis._moving = true;\r\n\r\n\t\tthis._lastEvent = e;\r\n\t\tthis._updatePosition();\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tvar e = {originalEvent: this._lastEvent};\r\n\r\n\t\t// @event predrag: Event\r\n\t\t// Fired continuously during dragging *before* each corresponding\r\n\t\t// update of the element's position.\r\n\t\tthis.fire('predrag', e);\r\n\t\tDomUtil.setPosition(this._element, this._newPos);\r\n\r\n\t\t// @event drag: Event\r\n\t\t// Fired continuously during dragging.\r\n\t\tthis.fire('drag', e);\r\n\t},\r\n\r\n\t_onUp: function () {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\t\tthis.finishDrag();\r\n\t},\r\n\r\n\tfinishDrag: function (noInertia) {\r\n\t\tDomUtil.removeClass(document.body, 'leaflet-dragging');\r\n\r\n\t\tif (this._lastTarget) {\r\n\t\t\tDomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t\tthis._lastTarget = null;\r\n\t\t}\r\n\r\n\t\tDomEvent.off(document, 'mousemove touchmove', this._onMove, this);\r\n\t\tDomEvent.off(document, 'mouseup touchend touchcancel', this._onUp, this);\r\n\r\n\t\tDomUtil.enableImageDrag();\r\n\t\tDomUtil.enableTextSelection();\r\n\r\n\t\tif (this._moved && this._moving) {\r\n\r\n\t\t\t// @event dragend: DragEndEvent\r\n\t\t\t// Fired when the drag ends.\r\n\t\t\tthis.fire('dragend', {\r\n\t\t\t\tnoInertia: noInertia,\r\n\t\t\t\tdistance: this._newPos.distanceTo(this._startPos)\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._moving = false;\r\n\t\tDraggable._dragging = false;\r\n\t}\r\n\r\n});\r\n","import {Point, toPoint} from './Point';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLng} from '../geo/LatLng';\r\n\r\n\r\n/*\r\n * @namespace LineUtil\r\n *\r\n * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.\r\n */\r\n\r\n// Simplify polyline with vertex reduction and Douglas-Peucker simplification.\r\n// Improves rendering performance dramatically by lessening the number of points to draw.\r\n\r\n// @function simplify(points: Point[], tolerance: Number): Point[]\r\n// Dramatically reduces the number of points in a polyline while retaining\r\n// its shape and returns a new array of simplified points, using the\r\n// [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm).\r\n// Used for a huge performance boost when processing/displaying Leaflet polylines for\r\n// each zoom level and also reducing visual noise. tolerance affects the amount of\r\n// simplification (lesser value means higher quality but slower and with more points).\r\n// Also released as a separated micro-library [Simplify.js](https://mourner.github.io/simplify-js/).\r\nexport function simplify(points, tolerance) {\r\n\tif (!tolerance || !points.length) {\r\n\t\treturn points.slice();\r\n\t}\r\n\r\n\tvar sqTolerance = tolerance * tolerance;\r\n\r\n\t // stage 1: vertex reduction\r\n\t points = _reducePoints(points, sqTolerance);\r\n\r\n\t // stage 2: Douglas-Peucker simplification\r\n\t points = _simplifyDP(points, sqTolerance);\r\n\r\n\treturn points;\r\n}\r\n\r\n// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number\r\n// Returns the distance between point `p` and segment `p1` to `p2`.\r\nexport function pointToSegmentDistance(p, p1, p2) {\r\n\treturn Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));\r\n}\r\n\r\n// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number\r\n// Returns the closest point from a point `p` on a segment `p1` to `p2`.\r\nexport function closestPointOnSegment(p, p1, p2) {\r\n\treturn _sqClosestPointOnSegment(p, p1, p2);\r\n}\r\n\r\n// Ramer-Douglas-Peucker simplification, see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\r\nfunction _simplifyDP(points, sqTolerance) {\r\n\r\n\tvar len = points.length,\r\n\t ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,\r\n\t markers = new ArrayConstructor(len);\r\n\r\n\t markers[0] = markers[len - 1] = 1;\r\n\r\n\t_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);\r\n\r\n\tvar i,\r\n\t newPoints = [];\r\n\r\n\tfor (i = 0; i < len; i++) {\r\n\t\tif (markers[i]) {\r\n\t\t\tnewPoints.push(points[i]);\r\n\t\t}\r\n\t}\r\n\r\n\treturn newPoints;\r\n}\r\n\r\nfunction _simplifyDPStep(points, markers, sqTolerance, first, last) {\r\n\r\n\tvar maxSqDist = 0,\r\n\tindex, i, sqDist;\r\n\r\n\tfor (i = first + 1; i <= last - 1; i++) {\r\n\t\tsqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);\r\n\r\n\t\tif (sqDist > maxSqDist) {\r\n\t\t\tindex = i;\r\n\t\t\tmaxSqDist = sqDist;\r\n\t\t}\r\n\t}\r\n\r\n\tif (maxSqDist > sqTolerance) {\r\n\t\tmarkers[index] = 1;\r\n\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, first, index);\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, index, last);\r\n\t}\r\n}\r\n\r\n// reduce points that are too close to each other to a single point\r\nfunction _reducePoints(points, sqTolerance) {\r\n\tvar reducedPoints = [points[0]];\r\n\r\n\tfor (var i = 1, prev = 0, len = points.length; i < len; i++) {\r\n\t\tif (_sqDist(points[i], points[prev]) > sqTolerance) {\r\n\t\t\treducedPoints.push(points[i]);\r\n\t\t\tprev = i;\r\n\t\t}\r\n\t}\r\n\tif (prev < len - 1) {\r\n\t\treducedPoints.push(points[len - 1]);\r\n\t}\r\n\treturn reducedPoints;\r\n}\r\n\r\nvar _lastCode;\r\n\r\n// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean\r\n// Clips the segment a to b by rectangular bounds with the\r\n// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)\r\n// (modifying the segment points directly!). Used by Leaflet to only show polyline\r\n// points that are on the screen or near, increasing performance.\r\nexport function clipSegment(a, b, bounds, useLastCode, round) {\r\n\tvar codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),\r\n\t codeB = _getBitCode(b, bounds),\r\n\r\n\t codeOut, p, newCode;\r\n\r\n\t // save 2nd code to avoid calculating it on the next segment\r\n\t _lastCode = codeB;\r\n\r\n\twhile (true) {\r\n\t\t// if a,b is inside the clip window (trivial accept)\r\n\t\tif (!(codeA | codeB)) {\r\n\t\t\treturn [a, b];\r\n\t\t}\r\n\r\n\t\t// if a,b is outside the clip window (trivial reject)\r\n\t\tif (codeA & codeB) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// other cases\r\n\t\tcodeOut = codeA || codeB;\r\n\t\tp = _getEdgeIntersection(a, b, codeOut, bounds, round);\r\n\t\tnewCode = _getBitCode(p, bounds);\r\n\r\n\t\tif (codeOut === codeA) {\r\n\t\t\ta = p;\r\n\t\t\tcodeA = newCode;\r\n\t\t} else {\r\n\t\t\tb = p;\r\n\t\t\tcodeB = newCode;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function _getEdgeIntersection(a, b, code, bounds, round) {\r\n\tvar dx = b.x - a.x,\r\n\t dy = b.y - a.y,\r\n\t min = bounds.min,\r\n\t max = bounds.max,\r\n\t x, y;\r\n\r\n\tif (code & 8) { // top\r\n\t\tx = a.x + dx * (max.y - a.y) / dy;\r\n\t\ty = max.y;\r\n\r\n\t} else if (code & 4) { // bottom\r\n\t\tx = a.x + dx * (min.y - a.y) / dy;\r\n\t\ty = min.y;\r\n\r\n\t} else if (code & 2) { // right\r\n\t\tx = max.x;\r\n\t\ty = a.y + dy * (max.x - a.x) / dx;\r\n\r\n\t} else if (code & 1) { // left\r\n\t\tx = min.x;\r\n\t\ty = a.y + dy * (min.x - a.x) / dx;\r\n\t}\r\n\r\n\treturn new Point(x, y, round);\r\n}\r\n\r\nexport function _getBitCode(p, bounds) {\r\n\tvar code = 0;\r\n\r\n\tif (p.x < bounds.min.x) { // left\r\n\t\tcode |= 1;\r\n\t} else if (p.x > bounds.max.x) { // right\r\n\t\tcode |= 2;\r\n\t}\r\n\r\n\tif (p.y < bounds.min.y) { // bottom\r\n\t\tcode |= 4;\r\n\t} else if (p.y > bounds.max.y) { // top\r\n\t\tcode |= 8;\r\n\t}\r\n\r\n\treturn code;\r\n}\r\n\r\n// square distance (to avoid unnecessary Math.sqrt calls)\r\nfunction _sqDist(p1, p2) {\r\n\tvar dx = p2.x - p1.x,\r\n\t dy = p2.y - p1.y;\r\n\treturn dx * dx + dy * dy;\r\n}\r\n\r\n// return closest point on segment or distance to that point\r\nexport function _sqClosestPointOnSegment(p, p1, p2, sqDist) {\r\n\tvar x = p1.x,\r\n\t y = p1.y,\r\n\t dx = p2.x - x,\r\n\t dy = p2.y - y,\r\n\t dot = dx * dx + dy * dy,\r\n\t t;\r\n\r\n\tif (dot > 0) {\r\n\t\tt = ((p.x - x) * dx + (p.y - y) * dy) / dot;\r\n\r\n\t\tif (t > 1) {\r\n\t\t\tx = p2.x;\r\n\t\t\ty = p2.y;\r\n\t\t} else if (t > 0) {\r\n\t\t\tx += dx * t;\r\n\t\t\ty += dy * t;\r\n\t\t}\r\n\t}\r\n\r\n\tdx = p.x - x;\r\n\tdy = p.y - y;\r\n\r\n\treturn sqDist ? dx * dx + dy * dy : new Point(x, y);\r\n}\r\n\r\n\r\n// @function isFlat(latlngs: LatLng[]): Boolean\r\n// Returns true if `latlngs` is a flat array, false is nested.\r\nexport function isFlat(latlngs) {\r\n\treturn !Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');\r\n}\r\n\r\nexport function _flat(latlngs) {\r\n\tconsole.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');\r\n\treturn isFlat(latlngs);\r\n}\r\n\r\n/* @function polylineCenter(latlngs: LatLng[], crs: CRS): LatLng\r\n * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polyline.\r\n */\r\nexport function polylineCenter(latlngs, crs) {\r\n\tvar i, halfDist, segDist, dist, p1, p2, ratio, center;\r\n\r\n\tif (!latlngs || latlngs.length === 0) {\r\n\t\tthrow new Error('latlngs not passed');\r\n\t}\r\n\r\n\tif (!isFlat(latlngs)) {\r\n\t\tconsole.warn('latlngs are not flat! Only the first ring will be used');\r\n\t\tlatlngs = latlngs[0];\r\n\t}\r\n\r\n\tvar points = [];\r\n\tfor (var j in latlngs) {\r\n\t\tpoints.push(crs.project(toLatLng(latlngs[j])));\r\n\t}\r\n\r\n\tvar len = points.length;\r\n\r\n\tfor (i = 0, halfDist = 0; i < len - 1; i++) {\r\n\t\thalfDist += points[i].distanceTo(points[i + 1]) / 2;\r\n\t}\r\n\r\n\t// The line is so small in the current view that all points are on the same pixel.\r\n\tif (halfDist === 0) {\r\n\t\tcenter = points[0];\r\n\t} else {\r\n\t\tfor (i = 0, dist = 0; i < len - 1; i++) {\r\n\t\t\tp1 = points[i];\r\n\t\t\tp2 = points[i + 1];\r\n\t\t\tsegDist = p1.distanceTo(p2);\r\n\t\t\tdist += segDist;\r\n\r\n\t\t\tif (dist > halfDist) {\r\n\t\t\t\tratio = (dist - halfDist) / segDist;\r\n\t\t\t\tcenter = [\r\n\t\t\t\t\tp2.x - ratio * (p2.x - p1.x),\r\n\t\t\t\t\tp2.y - ratio * (p2.y - p1.y)\r\n\t\t\t\t];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn crs.unproject(toPoint(center));\r\n}\r\n","import * as LineUtil from './LineUtil';\r\nimport {toLatLng} from '../geo/LatLng';\r\nimport {toPoint} from './Point';\r\n/*\r\n * @namespace PolyUtil\r\n * Various utility functions for polygon geometries.\r\n */\r\n\r\n/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]\r\n * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).\r\n * Used by Leaflet to only show polygon points that are on the screen or near, increasing\r\n * performance. Note that polygon points needs different algorithm for clipping\r\n * than polyline, so there's a separate method for it.\r\n */\r\nexport function clipPolygon(points, bounds, round) {\r\n\tvar clippedPoints,\r\n\t edges = [1, 4, 2, 8],\r\n\t i, j, k,\r\n\t a, b,\r\n\t len, edge, p;\r\n\r\n\tfor (i = 0, len = points.length; i < len; i++) {\r\n\t\tpoints[i]._code = LineUtil._getBitCode(points[i], bounds);\r\n\t}\r\n\r\n\t// for each edge (left, bottom, right, top)\r\n\tfor (k = 0; k < 4; k++) {\r\n\t\tedge = edges[k];\r\n\t\tclippedPoints = [];\r\n\r\n\t\tfor (i = 0, len = points.length, j = len - 1; i < len; j = i++) {\r\n\t\t\ta = points[i];\r\n\t\t\tb = points[j];\r\n\r\n\t\t\t// if a is inside the clip window\r\n\t\t\tif (!(a._code & edge)) {\r\n\t\t\t\t// if b is outside the clip window (a->b goes out of screen)\r\n\t\t\t\tif (b._code & edge) {\r\n\t\t\t\t\tp = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\t\tp._code = LineUtil._getBitCode(p, bounds);\r\n\t\t\t\t\tclippedPoints.push(p);\r\n\t\t\t\t}\r\n\t\t\t\tclippedPoints.push(a);\r\n\r\n\t\t\t// else if b is inside the clip window (a->b enters the screen)\r\n\t\t\t} else if (!(b._code & edge)) {\r\n\t\t\t\tp = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\tp._code = LineUtil._getBitCode(p, bounds);\r\n\t\t\t\tclippedPoints.push(p);\r\n\t\t\t}\r\n\t\t}\r\n\t\tpoints = clippedPoints;\r\n\t}\r\n\r\n\treturn points;\r\n}\r\n\r\n/* @function polygonCenter(latlngs: LatLng[] crs: CRS): LatLng\r\n * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon.\r\n */\r\nexport function polygonCenter(latlngs, crs) {\r\n\tvar i, j, p1, p2, f, area, x, y, center;\r\n\r\n\tif (!latlngs || latlngs.length === 0) {\r\n\t\tthrow new Error('latlngs not passed');\r\n\t}\r\n\r\n\tif (!LineUtil.isFlat(latlngs)) {\r\n\t\tconsole.warn('latlngs are not flat! Only the first ring will be used');\r\n\t\tlatlngs = latlngs[0];\r\n\t}\r\n\r\n\tvar points = [];\r\n\tfor (var k in latlngs) {\r\n\t\tpoints.push(crs.project(toLatLng(latlngs[k])));\r\n\t}\r\n\r\n\tvar len = points.length;\r\n\tarea = x = y = 0;\r\n\r\n\t// polygon centroid algorithm;\r\n\tfor (i = 0, j = len - 1; i < len; j = i++) {\r\n\t\tp1 = points[i];\r\n\t\tp2 = points[j];\r\n\r\n\t\tf = p1.y * p2.x - p2.y * p1.x;\r\n\t\tx += (p1.x + p2.x) * f;\r\n\t\ty += (p1.y + p2.y) * f;\r\n\t\tarea += f * 3;\r\n\t}\r\n\r\n\tif (area === 0) {\r\n\t\t// Polygon is so small that all points are on same pixel.\r\n\t\tcenter = points[0];\r\n\t} else {\r\n\t\tcenter = [x / area, y / area];\r\n\t}\r\n\treturn crs.unproject(toPoint(center));\r\n}\r\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @section\r\n * Leaflet comes with a set of already defined Projections out of the box:\r\n *\r\n * @projection L.Projection.LonLat\r\n *\r\n * Equirectangular, or Plate Carree projection — the most simple projection,\r\n * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as\r\n * latitude. Also suitable for flat worlds, e.g. game maps. Used by the\r\n * `EPSG:4326` and `Simple` CRS.\r\n */\r\n\r\nexport var LonLat = {\r\n\tproject: function (latlng) {\r\n\t\treturn new Point(latlng.lng, latlng.lat);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\treturn new LatLng(point.y, point.x);\r\n\t},\r\n\r\n\tbounds: new Bounds([-180, -90], [180, 90])\r\n};\r\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @projection L.Projection.Mercator\r\n *\r\n * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS.\r\n */\r\n\r\nexport var Mercator = {\r\n\tR: 6378137,\r\n\tR_MINOR: 6356752.314245179,\r\n\r\n\tbounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t r = this.R,\r\n\t\t y = latlng.lat * d,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t con = e * Math.sin(y);\r\n\r\n\t\tvar ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\ty = -r * Math.log(Math.max(ts, 1E-10));\r\n\r\n\t\treturn new Point(latlng.lng * d * r, y);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI,\r\n\t\t r = this.R,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t ts = Math.exp(-point.y / r),\r\n\t\t phi = Math.PI / 2 - 2 * Math.atan(ts);\r\n\r\n\t\tfor (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {\r\n\t\t\tcon = e * Math.sin(phi);\r\n\t\t\tcon = Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\t\tdphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;\r\n\t\t\tphi += dphi;\r\n\t\t}\r\n\r\n\t\treturn new LatLng(phi * d, point.x * d / r);\r\n\t}\r\n};\r\n","/*\n * @class Projection\n\n * An object with methods for projecting geographical coordinates of the world onto\n * a flat surface (and back). See [Map projection](https://en.wikipedia.org/wiki/Map_projection).\n\n * @property bounds: Bounds\n * The bounds (specified in CRS units) where the projection is valid\n\n * @method project(latlng: LatLng): Point\n * Projects geographical coordinates into a 2D point.\n * Only accepts actual `L.LatLng` instances, not arrays.\n\n * @method unproject(point: Point): LatLng\n * The inverse of `project`. Projects a 2D point into a geographical location.\n * Only accepts actual `L.Point` instances, not arrays.\n\n * Note that the projection instances do not inherit from Leaflet's `Class` object,\n * and can't be instantiated. Also, new classes can't inherit from them,\n * and methods can't be added to them with the `include` function.\n\n */\n\nexport {LonLat} from './Projection.LonLat';\nexport {Mercator} from './Projection.Mercator';\nexport {SphericalMercator} from './Projection.SphericalMercator';\n","import {Earth} from './CRS.Earth';\r\nimport {Mercator} from '../projection/Projection.Mercator';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3395\r\n *\r\n * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.\r\n */\r\nexport var EPSG3395 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:3395',\r\n\tprojection: Mercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * Mercator.R);\r\n\t\treturn toTransformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n","import {Earth} from './CRS.Earth';\r\nimport {LonLat} from '../projection/Projection.LonLat';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG4326\r\n *\r\n * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.\r\n *\r\n * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),\r\n * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer`\r\n * with this CRS, ensure that there are two 256x256 pixel tiles covering the\r\n * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),\r\n * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.\r\n */\r\n\r\nexport var EPSG4326 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:4326',\r\n\tprojection: LonLat,\r\n\ttransformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)\r\n});\r\n","import {CRS} from './CRS';\nimport {LonLat} from '../projection/Projection.LonLat';\nimport {toTransformation} from '../../geometry/Transformation';\nimport * as Util from '../../core/Util';\n\n/*\n * @namespace CRS\n * @crs L.CRS.Simple\n *\n * A simple CRS that maps longitude and latitude into `x` and `y` directly.\n * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`\n * axis should still be inverted (going from bottom to top). `distance()` returns\n * simple euclidean distance.\n */\n\nexport var Simple = Util.extend({}, CRS, {\n\tprojection: LonLat,\n\ttransformation: toTransformation(1, 0, -1, 0),\n\n\tscale: function (zoom) {\n\t\treturn Math.pow(2, zoom);\n\t},\n\n\tzoom: function (scale) {\n\t\treturn Math.log(scale) / Math.LN2;\n\t},\n\n\tdistance: function (latlng1, latlng2) {\n\t\tvar dx = latlng2.lng - latlng1.lng,\n\t\t dy = latlng2.lat - latlng1.lat;\n\n\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t},\n\n\tinfinite: true\n});\n","import {CRS} from './CRS';\nimport {Earth} from './CRS.Earth';\nimport {EPSG3395} from './CRS.EPSG3395';\nimport {EPSG3857, EPSG900913} from './CRS.EPSG3857';\nimport {EPSG4326} from './CRS.EPSG4326';\nimport {Simple} from './CRS.Simple';\n\nCRS.Earth = Earth;\nCRS.EPSG3395 = EPSG3395;\nCRS.EPSG3857 = EPSG3857;\nCRS.EPSG900913 = EPSG900913;\nCRS.EPSG4326 = EPSG4326;\nCRS.Simple = Simple;\n\nexport {CRS};\n","import {Evented} from '../core/Events';\nimport {Map} from '../map/Map';\nimport * as Util from '../core/Util';\n\n/*\n * @class Layer\n * @inherits Evented\n * @aka L.Layer\n * @aka ILayer\n *\n * A set of methods from the Layer base class that all Leaflet layers use.\n * Inherits all methods, options and events from `L.Evented`.\n *\n * @example\n *\n * ```js\n * var layer = L.marker(latlng).addTo(map);\n * layer.addTo(map);\n * layer.remove();\n * ```\n *\n * @event add: Event\n * Fired after the layer is added to a map\n *\n * @event remove: Event\n * Fired after the layer is removed from a map\n */\n\n\nexport var Layer = Evented.extend({\n\n\t// Classes extending `L.Layer` will inherit the following options:\n\toptions: {\n\t\t// @option pane: String = 'overlayPane'\n\t\t// By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.\n\t\tpane: 'overlayPane',\n\n\t\t// @option attribution: String = null\n\t\t// String to be shown in the attribution control, e.g. \"© OpenStreetMap contributors\". It describes the layer data and is often a legal obligation towards copyright holders and tile providers.\n\t\tattribution: null,\n\n\t\tbubblingMouseEvents: true\n\t},\n\n\t/* @section\n\t * Classes extending `L.Layer` will inherit the following methods:\n\t *\n\t * @method addTo(map: Map|LayerGroup): this\n\t * Adds the layer to the given map or layer group.\n\t */\n\taddTo: function (map) {\n\t\tmap.addLayer(this);\n\t\treturn this;\n\t},\n\n\t// @method remove: this\n\t// Removes the layer from the map it is currently active on.\n\tremove: function () {\n\t\treturn this.removeFrom(this._map || this._mapToAdd);\n\t},\n\n\t// @method removeFrom(map: Map): this\n\t// Removes the layer from the given map\n\t//\n\t// @alternative\n\t// @method removeFrom(group: LayerGroup): this\n\t// Removes the layer from the given `LayerGroup`\n\tremoveFrom: function (obj) {\n\t\tif (obj) {\n\t\t\tobj.removeLayer(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getPane(name? : String): HTMLElement\n\t// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.\n\tgetPane: function (name) {\n\t\treturn this._map.getPane(name ? (this.options[name] || name) : this.options.pane);\n\t},\n\n\taddInteractiveTarget: function (targetEl) {\n\t\tthis._map._targets[Util.stamp(targetEl)] = this;\n\t\treturn this;\n\t},\n\n\tremoveInteractiveTarget: function (targetEl) {\n\t\tdelete this._map._targets[Util.stamp(targetEl)];\n\t\treturn this;\n\t},\n\n\t// @method getAttribution: String\n\t// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).\n\tgetAttribution: function () {\n\t\treturn this.options.attribution;\n\t},\n\n\t_layerAdd: function (e) {\n\t\tvar map = e.target;\n\n\t\t// check in case layer gets added and then removed before the map is ready\n\t\tif (!map.hasLayer(this)) { return; }\n\n\t\tthis._map = map;\n\t\tthis._zoomAnimated = map._zoomAnimated;\n\n\t\tif (this.getEvents) {\n\t\t\tvar events = this.getEvents();\n\t\t\tmap.on(events, this);\n\t\t\tthis.once('remove', function () {\n\t\t\t\tmap.off(events, this);\n\t\t\t}, this);\n\t\t}\n\n\t\tthis.onAdd(map);\n\n\t\tthis.fire('add');\n\t\tmap.fire('layeradd', {layer: this});\n\t}\n});\n\n/* @section Extension methods\n * @uninheritable\n *\n * Every layer should extend from `L.Layer` and (re-)implement the following methods.\n *\n * @method onAdd(map: Map): this\n * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).\n *\n * @method onRemove(map: Map): this\n * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).\n *\n * @method getEvents(): Object\n * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.\n *\n * @method getAttribution(): String\n * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.\n *\n * @method beforeAdd(map: Map): this\n * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.\n */\n\n\n/* @namespace Map\n * @section Layer events\n *\n * @event layeradd: LayerEvent\n * Fired when a new layer is added to the map.\n *\n * @event layerremove: LayerEvent\n * Fired when some layer is removed from the map\n *\n * @section Methods for Layers and Controls\n */\nMap.include({\n\t// @method addLayer(layer: Layer): this\n\t// Adds the given layer to the map\n\taddLayer: function (layer) {\n\t\tif (!layer._layerAdd) {\n\t\t\tthrow new Error('The provided object is not a Layer.');\n\t\t}\n\n\t\tvar id = Util.stamp(layer);\n\t\tif (this._layers[id]) { return this; }\n\t\tthis._layers[id] = layer;\n\n\t\tlayer._mapToAdd = this;\n\n\t\tif (layer.beforeAdd) {\n\t\t\tlayer.beforeAdd(this);\n\t\t}\n\n\t\tthis.whenReady(layer._layerAdd, layer);\n\n\t\treturn this;\n\t},\n\n\t// @method removeLayer(layer: Layer): this\n\t// Removes the given layer from the map.\n\tremoveLayer: function (layer) {\n\t\tvar id = Util.stamp(layer);\n\n\t\tif (!this._layers[id]) { return this; }\n\n\t\tif (this._loaded) {\n\t\t\tlayer.onRemove(this);\n\t\t}\n\n\t\tdelete this._layers[id];\n\n\t\tif (this._loaded) {\n\t\t\tthis.fire('layerremove', {layer: layer});\n\t\t\tlayer.fire('remove');\n\t\t}\n\n\t\tlayer._map = layer._mapToAdd = null;\n\n\t\treturn this;\n\t},\n\n\t// @method hasLayer(layer: Layer): Boolean\n\t// Returns `true` if the given layer is currently added to the map\n\thasLayer: function (layer) {\n\t\treturn Util.stamp(layer) in this._layers;\n\t},\n\n\t/* @method eachLayer(fn: Function, context?: Object): this\n\t * Iterates over the layers of the map, optionally specifying context of the iterator function.\n\t * ```\n\t * map.eachLayer(function(layer){\n\t * layer.bindPopup('Hello');\n\t * });\n\t * ```\n\t */\n\teachLayer: function (method, context) {\n\t\tfor (var i in this._layers) {\n\t\t\tmethod.call(context, this._layers[i]);\n\t\t}\n\t\treturn this;\n\t},\n\n\t_addLayers: function (layers) {\n\t\tlayers = layers ? (Util.isArray(layers) ? layers : [layers]) : [];\n\n\t\tfor (var i = 0, len = layers.length; i < len; i++) {\n\t\t\tthis.addLayer(layers[i]);\n\t\t}\n\t},\n\n\t_addZoomLimit: function (layer) {\n\t\tif (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {\n\t\t\tthis._zoomBoundLayers[Util.stamp(layer)] = layer;\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_removeZoomLimit: function (layer) {\n\t\tvar id = Util.stamp(layer);\n\n\t\tif (this._zoomBoundLayers[id]) {\n\t\t\tdelete this._zoomBoundLayers[id];\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_updateZoomLevels: function () {\n\t\tvar minZoom = Infinity,\n\t\t maxZoom = -Infinity,\n\t\t oldZoomSpan = this._getZoomSpan();\n\n\t\tfor (var i in this._zoomBoundLayers) {\n\t\t\tvar options = this._zoomBoundLayers[i].options;\n\n\t\t\tminZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);\n\t\t\tmaxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);\n\t\t}\n\n\t\tthis._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;\n\t\tthis._layersMinZoom = minZoom === Infinity ? undefined : minZoom;\n\n\t\t// @section Map state change events\n\t\t// @event zoomlevelschange: Event\n\t\t// Fired when the number of zoomlevels on the map is changed due\n\t\t// to adding or removing a layer.\n\t\tif (oldZoomSpan !== this._getZoomSpan()) {\n\t\t\tthis.fire('zoomlevelschange');\n\t\t}\n\n\t\tif (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {\n\t\t\tthis.setZoom(this._layersMaxZoom);\n\t\t}\n\t\tif (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {\n\t\t\tthis.setZoom(this._layersMinZoom);\n\t\t}\n\t}\n});\n","\r\nimport {Layer} from './Layer';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class LayerGroup\r\n * @aka L.LayerGroup\r\n * @inherits Interactive layer\r\n *\r\n * Used to group several layers and handle them as one. If you add it to the map,\r\n * any layers added or removed from the group will be added/removed on the map as\r\n * well. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.layerGroup([marker1, marker2])\r\n * \t.addLayer(polyline)\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nexport var LayerGroup = Layer.extend({\r\n\r\n\tinitialize: function (layers, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tvar i, len;\r\n\r\n\t\tif (layers) {\r\n\t\t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n\t\t\t\tthis.addLayer(layers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addLayer(layer: Layer): this\r\n\t// Adds the given layer to the group.\r\n\taddLayer: function (layer) {\r\n\t\tvar id = this.getLayerId(layer);\r\n\r\n\t\tthis._layers[id] = layer;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.addLayer(layer);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Removes the given layer from the group.\r\n\t// @alternative\r\n\t// @method removeLayer(id: Number): this\r\n\t// Removes the layer with the given internal ID from the group.\r\n\tremoveLayer: function (layer) {\r\n\t\tvar id = layer in this._layers ? layer : this.getLayerId(layer);\r\n\r\n\t\tif (this._map && this._layers[id]) {\r\n\t\t\tthis._map.removeLayer(this._layers[id]);\r\n\t\t}\r\n\r\n\t\tdelete this._layers[id];\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method hasLayer(layer: Layer): Boolean\r\n\t// Returns `true` if the given layer is currently added to the group.\r\n\t// @alternative\r\n\t// @method hasLayer(id: Number): Boolean\r\n\t// Returns `true` if the given internal ID is currently added to the group.\r\n\thasLayer: function (layer) {\r\n\t\tvar layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);\r\n\t\treturn layerId in this._layers;\r\n\t},\r\n\r\n\t// @method clearLayers(): this\r\n\t// Removes all the layers from the group.\r\n\tclearLayers: function () {\r\n\t\treturn this.eachLayer(this.removeLayer, this);\r\n\t},\r\n\r\n\t// @method invoke(methodName: String, …): this\r\n\t// Calls `methodName` on every layer contained in this group, passing any\r\n\t// additional parameters. Has no effect if the layers contained do not\r\n\t// implement `methodName`.\r\n\tinvoke: function (methodName) {\r\n\t\tvar args = Array.prototype.slice.call(arguments, 1),\r\n\t\t i, layer;\r\n\r\n\t\tfor (i in this._layers) {\r\n\t\t\tlayer = this._layers[i];\r\n\r\n\t\t\tif (layer[methodName]) {\r\n\t\t\t\tlayer[methodName].apply(layer, args);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis.eachLayer(map.addLayer, map);\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tthis.eachLayer(map.removeLayer, map);\r\n\t},\r\n\r\n\t// @method eachLayer(fn: Function, context?: Object): this\r\n\t// Iterates over the layers of the group, optionally specifying context of the iterator function.\r\n\t// ```js\r\n\t// group.eachLayer(function (layer) {\r\n\t// \tlayer.bindPopup('Hello');\r\n\t// });\r\n\t// ```\r\n\teachLayer: function (method, context) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmethod.call(context, this._layers[i]);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getLayer(id: Number): Layer\r\n\t// Returns the layer with the given internal ID.\r\n\tgetLayer: function (id) {\r\n\t\treturn this._layers[id];\r\n\t},\r\n\r\n\t// @method getLayers(): Layer[]\r\n\t// Returns an array of all the layers added to the group.\r\n\tgetLayers: function () {\r\n\t\tvar layers = [];\r\n\t\tthis.eachLayer(layers.push, layers);\r\n\t\treturn layers;\r\n\t},\r\n\r\n\t// @method setZIndex(zIndex: Number): this\r\n\t// Calls `setZIndex` on every layer contained in this group, passing the z-index.\r\n\tsetZIndex: function (zIndex) {\r\n\t\treturn this.invoke('setZIndex', zIndex);\r\n\t},\r\n\r\n\t// @method getLayerId(layer: Layer): Number\r\n\t// Returns the internal ID for a layer\r\n\tgetLayerId: function (layer) {\r\n\t\treturn Util.stamp(layer);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.layerGroup(layers?: Layer[], options?: Object)\r\n// Create a layer group, optionally given an initial set of layers and an `options` object.\r\nexport var layerGroup = function (layers, options) {\r\n\treturn new LayerGroup(layers, options);\r\n};\r\n","import {LayerGroup} from './LayerGroup';\r\nimport {LatLngBounds} from '../geo/LatLngBounds';\r\n\r\n/*\r\n * @class FeatureGroup\r\n * @aka L.FeatureGroup\r\n * @inherits LayerGroup\r\n *\r\n * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:\r\n * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))\r\n * * Events are propagated to the `FeatureGroup`, so if the group has an event\r\n * handler, it will handle events from any of the layers. This includes mouse events\r\n * and custom events.\r\n * * Has `layeradd` and `layerremove` events\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.featureGroup([marker1, marker2, polyline])\r\n * \t.bindPopup('Hello world!')\r\n * \t.on('click', function() { alert('Clicked on a member of the group!'); })\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nexport var FeatureGroup = LayerGroup.extend({\r\n\r\n\taddLayer: function (layer) {\r\n\t\tif (this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlayer.addEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.addLayer.call(this, layer);\r\n\r\n\t\t// @event layeradd: LayerEvent\r\n\t\t// Fired when a layer is added to this `FeatureGroup`\r\n\t\treturn this.fire('layeradd', {layer: layer});\r\n\t},\r\n\r\n\tremoveLayer: function (layer) {\r\n\t\tif (!this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tif (layer in this._layers) {\r\n\t\t\tlayer = this._layers[layer];\r\n\t\t}\r\n\r\n\t\tlayer.removeEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.removeLayer.call(this, layer);\r\n\r\n\t\t// @event layerremove: LayerEvent\r\n\t\t// Fired when a layer is removed from this `FeatureGroup`\r\n\t\treturn this.fire('layerremove', {layer: layer});\r\n\t},\r\n\r\n\t// @method setStyle(style: Path options): this\r\n\t// Sets the given path options to each layer of the group that has a `setStyle` method.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.invoke('setStyle', style);\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer group to the top of all other layers\r\n\tbringToFront: function () {\r\n\t\treturn this.invoke('bringToFront');\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer group to the back of all other layers\r\n\tbringToBack: function () {\r\n\t\treturn this.invoke('bringToBack');\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).\r\n\tgetBounds: function () {\r\n\t\tvar bounds = new LatLngBounds();\r\n\r\n\t\tfor (var id in this._layers) {\r\n\t\t\tvar layer = this._layers[id];\r\n\t\t\tbounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());\r\n\t\t}\r\n\t\treturn bounds;\r\n\t}\r\n});\r\n\r\n// @factory L.featureGroup(layers?: Layer[], options?: Object)\r\n// Create a feature group, optionally given an initial set of layers and an `options` object.\r\nexport var featureGroup = function (layers, options) {\r\n\treturn new FeatureGroup(layers, options);\r\n};\r\n","import {Class} from '../../core/Class';\r\nimport {setOptions} from '../../core/Util';\r\nimport {toPoint as point} from '../../geometry/Point';\r\nimport Browser from '../../core/Browser';\r\n\r\n/*\r\n * @class Icon\r\n * @aka L.Icon\r\n *\r\n * Represents an icon to provide when creating a marker.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var myIcon = L.icon({\r\n * iconUrl: 'my-icon.png',\r\n * iconRetinaUrl: 'my-icon@2x.png',\r\n * iconSize: [38, 95],\r\n * iconAnchor: [22, 94],\r\n * popupAnchor: [-3, -76],\r\n * shadowUrl: 'my-icon-shadow.png',\r\n * shadowRetinaUrl: 'my-icon-shadow@2x.png',\r\n * shadowSize: [68, 95],\r\n * shadowAnchor: [22, 94]\r\n * });\r\n *\r\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\r\n * ```\r\n *\r\n * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.\r\n *\r\n */\r\n\r\nexport var Icon = Class.extend({\r\n\r\n\t/* @section\r\n\t * @aka Icon options\r\n\t *\r\n\t * @option iconUrl: String = null\r\n\t * **(required)** The URL to the icon image (absolute or relative to your script path).\r\n\t *\r\n\t * @option iconRetinaUrl: String = null\r\n\t * The URL to a retina sized version of the icon image (absolute or relative to your\r\n\t * script path). Used for Retina screen devices.\r\n\t *\r\n\t * @option iconSize: Point = null\r\n\t * Size of the icon image in pixels.\r\n\t *\r\n\t * @option iconAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the icon (relative to its top left corner). The icon\r\n\t * will be aligned so that this point is at the marker's geographical location. Centered\r\n\t * by default if size is specified, also can be set in CSS with negative margins.\r\n\t *\r\n\t * @option popupAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which popups will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option tooltipAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which tooltips will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option shadowUrl: String = null\r\n\t * The URL to the icon shadow image. If not specified, no shadow image will be created.\r\n\t *\r\n\t * @option shadowRetinaUrl: String = null\r\n\t *\r\n\t * @option shadowSize: Point = null\r\n\t * Size of the shadow image in pixels.\r\n\t *\r\n\t * @option shadowAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the shadow (relative to its top left corner) (the same\r\n\t * as iconAnchor if not specified).\r\n\t *\r\n\t * @option className: String = ''\r\n\t * A custom class name to assign to both icon and shadow images. Empty by default.\r\n\t */\r\n\r\n\toptions: {\r\n\t\tpopupAnchor: [0, 0],\r\n\t\ttooltipAnchor: [0, 0],\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tsetOptions(this, options);\r\n\t},\r\n\r\n\t// @method createIcon(oldIcon?: HTMLElement): HTMLElement\r\n\t// Called internally when the icon has to be shown, returns a `<img>` HTML element\r\n\t// styled according to the options.\r\n\tcreateIcon: function (oldIcon) {\r\n\t\treturn this._createIcon('icon', oldIcon);\r\n\t},\r\n\r\n\t// @method createShadow(oldIcon?: HTMLElement): HTMLElement\r\n\t// As `createIcon`, but for the shadow beneath it.\r\n\tcreateShadow: function (oldIcon) {\r\n\t\treturn this._createIcon('shadow', oldIcon);\r\n\t},\r\n\r\n\t_createIcon: function (name, oldIcon) {\r\n\t\tvar src = this._getIconUrl(name);\r\n\r\n\t\tif (!src) {\r\n\t\t\tif (name === 'icon') {\r\n\t\t\t\tthrow new Error('iconUrl not set in Icon options (see the docs).');\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tvar img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);\r\n\t\tthis._setIconStyles(img, name);\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\timg.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\treturn img;\r\n\t},\r\n\r\n\t_setIconStyles: function (img, name) {\r\n\t\tvar options = this.options;\r\n\t\tvar sizeOption = options[name + 'Size'];\r\n\r\n\t\tif (typeof sizeOption === 'number') {\r\n\t\t\tsizeOption = [sizeOption, sizeOption];\r\n\t\t}\r\n\r\n\t\tvar size = point(sizeOption),\r\n\t\t anchor = point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||\r\n\t\t size && size.divideBy(2, true));\r\n\r\n\t\timg.className = 'leaflet-marker-' + name + ' ' + (options.className || '');\r\n\r\n\t\tif (anchor) {\r\n\t\t\timg.style.marginLeft = (-anchor.x) + 'px';\r\n\t\t\timg.style.marginTop = (-anchor.y) + 'px';\r\n\t\t}\r\n\r\n\t\tif (size) {\r\n\t\t\timg.style.width = size.x + 'px';\r\n\t\t\timg.style.height = size.y + 'px';\r\n\t\t}\r\n\t},\r\n\r\n\t_createImg: function (src, el) {\r\n\t\tel = el || document.createElement('img');\r\n\t\tel.src = src;\r\n\t\treturn el;\r\n\t},\r\n\r\n\t_getIconUrl: function (name) {\r\n\t\treturn Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.icon(options: Icon options)\r\n// Creates an icon instance with the given options.\r\nexport function icon(options) {\r\n\treturn new Icon(options);\r\n}\r\n","import {Icon} from './Icon';\nimport * as DomUtil from '../../dom/DomUtil';\n\n/*\n * @miniclass Icon.Default (Icon)\n * @aka L.Icon.Default\n * @section\n *\n * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when\n * no icon is specified. Points to the blue marker image distributed with Leaflet\n * releases.\n *\n * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`\n * (which is a set of `Icon options`).\n *\n * If you want to _completely_ replace the default icon, override the\n * `L.Marker.prototype.options.icon` with your own icon instead.\n */\n\nexport var IconDefault = Icon.extend({\n\n\toptions: {\n\t\ticonUrl: 'marker-icon.png',\n\t\ticonRetinaUrl: 'marker-icon-2x.png',\n\t\tshadowUrl: 'marker-shadow.png',\n\t\ticonSize: [25, 41],\n\t\ticonAnchor: [12, 41],\n\t\tpopupAnchor: [1, -34],\n\t\ttooltipAnchor: [16, -28],\n\t\tshadowSize: [41, 41]\n\t},\n\n\t_getIconUrl: function (name) {\n\t\tif (typeof IconDefault.imagePath !== 'string') {\t// Deprecated, backwards-compatibility only\n\t\t\tIconDefault.imagePath = this._detectIconPath();\n\t\t}\n\n\t\t// @option imagePath: String\n\t\t// `Icon.Default` will try to auto-detect the location of the\n\t\t// blue icon images. If you are placing these images in a non-standard\n\t\t// way, set this option to point to the right path.\n\t\treturn (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);\n\t},\n\n\t_stripUrl: function (path) {\t// separate function to use in tests\n\t\tvar strip = function (str, re, idx) {\n\t\t\tvar match = re.exec(str);\n\t\t\treturn match && match[idx];\n\t\t};\n\t\tpath = strip(path, /^url\\((['\"])?(.+)\\1\\)$/, 2);\n\t\treturn path && strip(path, /^(.*)marker-icon\\.png$/, 1);\n\t},\n\n\t_detectIconPath: function () {\n\t\tvar el = DomUtil.create('div', 'leaflet-default-icon-path', document.body);\n\t\tvar path = DomUtil.getStyle(el, 'background-image') ||\n\t\t DomUtil.getStyle(el, 'backgroundImage');\t// IE8\n\n\t\tdocument.body.removeChild(el);\n\t\tpath = this._stripUrl(path);\n\t\tif (path) { return path; }\n\t\tvar link = document.querySelector('link[href$=\"leaflet.css\"]');\n\t\tif (!link) { return ''; }\n\t\treturn link.href.substring(0, link.href.length - 'leaflet.css'.length - 1);\n\t}\n});\n","import {Handler} from '../../core/Handler';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {Draggable} from '../../dom/Draggable';\nimport {toBounds} from '../../geometry/Bounds';\nimport {toPoint} from '../../geometry/Point';\nimport {requestAnimFrame, cancelAnimFrame} from '../../core/Util';\n\n/*\n * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.\n */\n\n\n/* @namespace Marker\n * @section Interaction handlers\n *\n * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:\n *\n * ```js\n * marker.dragging.disable();\n * ```\n *\n * @property dragging: Handler\n * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).\n */\n\nexport var MarkerDrag = Handler.extend({\n\tinitialize: function (marker) {\n\t\tthis._marker = marker;\n\t},\n\n\taddHooks: function () {\n\t\tvar icon = this._marker._icon;\n\n\t\tif (!this._draggable) {\n\t\t\tthis._draggable = new Draggable(icon, icon, true);\n\t\t}\n\n\t\tthis._draggable.on({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).enable();\n\n\t\tDomUtil.addClass(icon, 'leaflet-marker-draggable');\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._draggable.off({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).disable();\n\n\t\tif (this._marker._icon) {\n\t\t\tDomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');\n\t\t}\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\t_adjustPan: function (e) {\n\t\tvar marker = this._marker,\n\t\t map = marker._map,\n\t\t speed = this._marker.options.autoPanSpeed,\n\t\t padding = this._marker.options.autoPanPadding,\n\t\t iconPos = DomUtil.getPosition(marker._icon),\n\t\t bounds = map.getPixelBounds(),\n\t\t origin = map.getPixelOrigin();\n\n\t\tvar panBounds = toBounds(\n\t\t\tbounds.min._subtract(origin).add(padding),\n\t\t\tbounds.max._subtract(origin).subtract(padding)\n\t\t);\n\n\t\tif (!panBounds.contains(iconPos)) {\n\t\t\t// Compute incremental movement\n\t\t\tvar movement = toPoint(\n\t\t\t\t(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -\n\t\t\t\t(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),\n\n\t\t\t\t(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -\n\t\t\t\t(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)\n\t\t\t).multiplyBy(speed);\n\n\t\t\tmap.panBy(movement, {animate: false});\n\n\t\t\tthis._draggable._newPos._add(movement);\n\t\t\tthis._draggable._startPos._add(movement);\n\n\t\t\tDomUtil.setPosition(marker._icon, this._draggable._newPos);\n\t\t\tthis._onDrag(e);\n\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDragStart: function () {\n\t\t// @section Dragging events\n\t\t// @event dragstart: Event\n\t\t// Fired when the user starts dragging the marker.\n\n\t\t// @event movestart: Event\n\t\t// Fired when the marker starts moving (because of dragging).\n\n\t\tthis._oldLatLng = this._marker.getLatLng();\n\n\t\t// When using ES6 imports it could not be set when `Popup` was not imported as well\n\t\tthis._marker.closePopup && this._marker.closePopup();\n\n\t\tthis._marker\n\t\t\t.fire('movestart')\n\t\t\t.fire('dragstart');\n\t},\n\n\t_onPreDrag: function (e) {\n\t\tif (this._marker.options.autoPan) {\n\t\t\tcancelAnimFrame(this._panRequest);\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tvar marker = this._marker,\n\t\t shadow = marker._shadow,\n\t\t iconPos = DomUtil.getPosition(marker._icon),\n\t\t latlng = marker._map.layerPointToLatLng(iconPos);\n\n\t\t// update shadow position\n\t\tif (shadow) {\n\t\t\tDomUtil.setPosition(shadow, iconPos);\n\t\t}\n\n\t\tmarker._latlng = latlng;\n\t\te.latlng = latlng;\n\t\te.oldLatLng = this._oldLatLng;\n\n\t\t// @event drag: Event\n\t\t// Fired repeatedly while the user drags the marker.\n\t\tmarker\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_onDragEnd: function (e) {\n\t\t// @event dragend: DragEndEvent\n\t\t// Fired when the user stops dragging the marker.\n\n\t\t cancelAnimFrame(this._panRequest);\n\n\t\t// @event moveend: Event\n\t\t// Fired when the marker stops moving (because of dragging).\n\t\tdelete this._oldLatLng;\n\t\tthis._marker\n\t\t .fire('moveend')\n\t\t .fire('dragend', e);\n\t}\n});\n","import {Layer} from '../Layer';\r\nimport {IconDefault} from './Icon.Default';\r\nimport * as Util from '../../core/Util';\r\nimport {toLatLng as latLng} from '../../geo/LatLng';\r\nimport {toPoint as point} from '../../geometry/Point';\r\nimport * as DomUtil from '../../dom/DomUtil';\r\nimport * as DomEvent from '../../dom/DomEvent';\r\nimport {MarkerDrag} from './Marker.Drag';\r\n\r\n/*\r\n * @class Marker\r\n * @inherits Interactive layer\r\n * @aka L.Marker\r\n * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.marker([50.5, 30.5]).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var Marker = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka Marker options\r\n\toptions: {\r\n\t\t// @option icon: Icon = *\r\n\t\t// Icon instance to use for rendering the marker.\r\n\t\t// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.\r\n\t\t// If not specified, a common instance of `L.Icon.Default` is used.\r\n\t\ticon: new IconDefault(),\r\n\r\n\t\t// Option inherited from \"Interactive layer\" abstract class\r\n\t\tinteractive: true,\r\n\r\n\t\t// @option keyboard: Boolean = true\r\n\t\t// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.\r\n\t\tkeyboard: true,\r\n\r\n\t\t// @option title: String = ''\r\n\t\t// Text for the browser tooltip that appear on marker hover (no tooltip by default).\r\n\t\t// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).\r\n\t\ttitle: '',\r\n\r\n\t\t// @option alt: String = 'Marker'\r\n\t\t// Text for the `alt` attribute of the icon image.\r\n\t\t// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).\r\n\t\talt: 'Marker',\r\n\r\n\t\t// @option zIndexOffset: Number = 0\r\n\t\t// By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).\r\n\t\tzIndexOffset: 0,\r\n\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the marker.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option riseOnHover: Boolean = false\r\n\t\t// If `true`, the marker will get on top of others when you hover the mouse over it.\r\n\t\triseOnHover: false,\r\n\r\n\t\t// @option riseOffset: Number = 250\r\n\t\t// The z-index offset used for the `riseOnHover` feature.\r\n\t\triseOffset: 250,\r\n\r\n\t\t// @option pane: String = 'markerPane'\r\n\t\t// `Map pane` where the markers icon will be added.\r\n\t\tpane: 'markerPane',\r\n\r\n\t\t// @option shadowPane: String = 'shadowPane'\r\n\t\t// `Map pane` where the markers shadow will be added.\r\n\t\tshadowPane: 'shadowPane',\r\n\r\n\t\t// @option bubblingMouseEvents: Boolean = false\r\n\t\t// When `true`, a mouse event on this marker will trigger the same event on the map\r\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\r\n\t\tbubblingMouseEvents: false,\r\n\r\n\t\t// @option autoPanOnFocus: Boolean = true\r\n\t\t// When `true`, the map will pan whenever the marker is focused (via\r\n\t\t// e.g. pressing `tab` on the keyboard) to ensure the marker is\r\n\t\t// visible within the map's bounds\r\n\t\tautoPanOnFocus: true,\r\n\r\n\t\t// @section Draggable marker options\r\n\t\t// @option draggable: Boolean = false\r\n\t\t// Whether the marker is draggable with mouse/touch or not.\r\n\t\tdraggable: false,\r\n\r\n\t\t// @option autoPan: Boolean = false\r\n\t\t// Whether to pan the map when dragging this marker near its edge or not.\r\n\t\tautoPan: false,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(50, 50)\r\n\t\t// Distance (in pixels to the left/right and to the top/bottom) of the\r\n\t\t// map edge to start panning the map.\r\n\t\tautoPanPadding: [50, 50],\r\n\r\n\t\t// @option autoPanSpeed: Number = 10\r\n\t\t// Number of pixels the map should pan by.\r\n\t\tautoPanSpeed: 10\r\n\t},\r\n\r\n\t/* @section\r\n\t *\r\n\t * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:\r\n\t */\r\n\r\n\tinitialize: function (latlng, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\t\tthis._latlng = latLng(latlng);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.on('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._initIcon();\r\n\t\tthis.update();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (this.dragging && this.dragging.enabled()) {\r\n\t\t\tthis.options.draggable = true;\r\n\t\t\tthis.dragging.removeHooks();\r\n\t\t}\r\n\t\tdelete this.dragging;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.off('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._removeIcon();\r\n\t\tthis._removeShadow();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\treturn {\r\n\t\t\tzoom: this.update,\r\n\t\t\tviewreset: this.update\r\n\t\t};\r\n\t},\r\n\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the current geographical position of the marker.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Changes the marker position to the given point.\r\n\tsetLatLng: function (latlng) {\r\n\t\tvar oldLatLng = this._latlng;\r\n\t\tthis._latlng = latLng(latlng);\r\n\t\tthis.update();\r\n\r\n\t\t// @event move: Event\r\n\t\t// Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.\r\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\r\n\t},\r\n\r\n\t// @method setZIndexOffset(offset: Number): this\r\n\t// Changes the [zIndex offset](#marker-zindexoffset) of the marker.\r\n\tsetZIndexOffset: function (offset) {\r\n\t\tthis.options.zIndexOffset = offset;\r\n\t\treturn this.update();\r\n\t},\r\n\r\n\t// @method getIcon: Icon\r\n\t// Returns the current icon used by the marker\r\n\tgetIcon: function () {\r\n\t\treturn this.options.icon;\r\n\t},\r\n\r\n\t// @method setIcon(icon: Icon): this\r\n\t// Changes the marker icon.\r\n\tsetIcon: function (icon) {\r\n\r\n\t\tthis.options.icon = icon;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._initIcon();\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\tif (this._popup) {\r\n\t\t\tthis.bindPopup(this._popup, this._popup.options);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetElement: function () {\r\n\t\treturn this._icon;\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tif (this._icon && this._map) {\r\n\t\t\tvar pos = this._map.latLngToLayerPoint(this._latlng).round();\r\n\t\t\tthis._setPos(pos);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initIcon: function () {\r\n\t\tvar options = this.options,\r\n\t\t classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\r\n\r\n\t\tvar icon = options.icon.createIcon(this._icon),\r\n\t\t addIcon = false;\r\n\r\n\t\t// if we're not reusing the icon, remove the old one and init new one\r\n\t\tif (icon !== this._icon) {\r\n\t\t\tif (this._icon) {\r\n\t\t\t\tthis._removeIcon();\r\n\t\t\t}\r\n\t\t\taddIcon = true;\r\n\r\n\t\t\tif (options.title) {\r\n\t\t\t\ticon.title = options.title;\r\n\t\t\t}\r\n\r\n\t\t\tif (icon.tagName === 'IMG') {\r\n\t\t\t\ticon.alt = options.alt || '';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tDomUtil.addClass(icon, classToAdd);\r\n\r\n\t\tif (options.keyboard) {\r\n\t\t\ticon.tabIndex = '0';\r\n\t\t\ticon.setAttribute('role', 'button');\r\n\t\t}\r\n\r\n\t\tthis._icon = icon;\r\n\r\n\t\tif (options.riseOnHover) {\r\n\t\t\tthis.on({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.options.autoPanOnFocus) {\r\n\t\t\tDomEvent.on(icon, 'focus', this._panOnFocus, this);\r\n\t\t}\r\n\r\n\t\tvar newShadow = options.icon.createShadow(this._shadow),\r\n\t\t addShadow = false;\r\n\r\n\t\tif (newShadow !== this._shadow) {\r\n\t\t\tthis._removeShadow();\r\n\t\t\taddShadow = true;\r\n\t\t}\r\n\r\n\t\tif (newShadow) {\r\n\t\t\tDomUtil.addClass(newShadow, classToAdd);\r\n\t\t\tnewShadow.alt = '';\r\n\t\t}\r\n\t\tthis._shadow = newShadow;\r\n\r\n\r\n\t\tif (options.opacity < 1) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\r\n\t\tif (addIcon) {\r\n\t\t\tthis.getPane().appendChild(this._icon);\r\n\t\t}\r\n\t\tthis._initInteraction();\r\n\t\tif (newShadow && addShadow) {\r\n\t\t\tthis.getPane(options.shadowPane).appendChild(this._shadow);\r\n\t\t}\r\n\t},\r\n\r\n\t_removeIcon: function () {\r\n\t\tif (this.options.riseOnHover) {\r\n\t\t\tthis.off({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.options.autoPanOnFocus) {\r\n\t\t\tDomEvent.off(this._icon, 'focus', this._panOnFocus, this);\r\n\t\t}\r\n\r\n\t\tDomUtil.remove(this._icon);\r\n\t\tthis.removeInteractiveTarget(this._icon);\r\n\r\n\t\tthis._icon = null;\r\n\t},\r\n\r\n\t_removeShadow: function () {\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.remove(this._shadow);\r\n\t\t}\r\n\t\tthis._shadow = null;\r\n\t},\r\n\r\n\t_setPos: function (pos) {\r\n\r\n\t\tif (this._icon) {\r\n\t\t\tDomUtil.setPosition(this._icon, pos);\r\n\t\t}\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.setPosition(this._shadow, pos);\r\n\t\t}\r\n\r\n\t\tthis._zIndex = pos.y + this.options.zIndexOffset;\r\n\r\n\t\tthis._resetZIndex();\r\n\t},\r\n\r\n\t_updateZIndex: function (offset) {\r\n\t\tif (this._icon) {\r\n\t\t\tthis._icon.style.zIndex = this._zIndex + offset;\r\n\t\t}\r\n\t},\r\n\r\n\t_animateZoom: function (opt) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();\r\n\r\n\t\tthis._setPos(pos);\r\n\t},\r\n\r\n\t_initInteraction: function () {\r\n\r\n\t\tif (!this.options.interactive) { return; }\r\n\r\n\t\tDomUtil.addClass(this._icon, 'leaflet-interactive');\r\n\r\n\t\tthis.addInteractiveTarget(this._icon);\r\n\r\n\t\tif (MarkerDrag) {\r\n\t\t\tvar draggable = this.options.draggable;\r\n\t\t\tif (this.dragging) {\r\n\t\t\t\tdraggable = this.dragging.enabled();\r\n\t\t\t\tthis.dragging.disable();\r\n\t\t\t}\r\n\r\n\t\t\tthis.dragging = new MarkerDrag(this);\r\n\r\n\t\t\tif (draggable) {\r\n\t\t\t\tthis.dragging.enable();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Changes the opacity of the marker.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\t\tif (this._map) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tvar opacity = this.options.opacity;\r\n\r\n\t\tif (this._icon) {\r\n\t\t\tDomUtil.setOpacity(this._icon, opacity);\r\n\t\t}\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.setOpacity(this._shadow, opacity);\r\n\t\t}\r\n\t},\r\n\r\n\t_bringToFront: function () {\r\n\t\tthis._updateZIndex(this.options.riseOffset);\r\n\t},\r\n\r\n\t_resetZIndex: function () {\r\n\t\tthis._updateZIndex(0);\r\n\t},\r\n\r\n\t_panOnFocus: function () {\r\n\t\tvar map = this._map;\r\n\t\tif (!map) { return; }\r\n\r\n\t\tvar iconOpts = this.options.icon.options;\r\n\t\tvar size = iconOpts.iconSize ? point(iconOpts.iconSize) : point(0, 0);\r\n\t\tvar anchor = iconOpts.iconAnchor ? point(iconOpts.iconAnchor) : point(0, 0);\r\n\r\n\t\tmap.panInside(this._latlng, {\r\n\t\t\tpaddingTopLeft: anchor,\r\n\t\t\tpaddingBottomRight: size.subtract(anchor)\r\n\t\t});\r\n\t},\r\n\r\n\t_getPopupAnchor: function () {\r\n\t\treturn this.options.icon.options.popupAnchor;\r\n\t},\r\n\r\n\t_getTooltipAnchor: function () {\r\n\t\treturn this.options.icon.options.tooltipAnchor;\r\n\t}\r\n});\r\n\r\n\r\n// factory L.marker(latlng: LatLng, options? : Marker options)\r\n\r\n// @factory L.marker(latlng: LatLng, options? : Marker options)\r\n// Instantiates a Marker object given a geographical point and optionally an options object.\r\nexport function marker(latlng, options) {\r\n\treturn new Marker(latlng, options);\r\n}\r\n","import {Layer} from '../Layer';\nimport * as Util from '../../core/Util';\n\n/*\n * @class Path\n * @aka L.Path\n * @inherits Interactive layer\n *\n * An abstract class that contains options and constants shared between vector\n * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.\n */\n\nexport var Path = Layer.extend({\n\n\t// @section\n\t// @aka Path options\n\toptions: {\n\t\t// @option stroke: Boolean = true\n\t\t// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.\n\t\tstroke: true,\n\n\t\t// @option color: String = '#3388ff'\n\t\t// Stroke color\n\t\tcolor: '#3388ff',\n\n\t\t// @option weight: Number = 3\n\t\t// Stroke width in pixels\n\t\tweight: 3,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Stroke opacity\n\t\topacity: 1,\n\n\t\t// @option lineCap: String= 'round'\n\t\t// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.\n\t\tlineCap: 'round',\n\n\t\t// @option lineJoin: String = 'round'\n\t\t// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.\n\t\tlineJoin: 'round',\n\n\t\t// @option dashArray: String = null\n\t\t// A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashArray: null,\n\n\t\t// @option dashOffset: String = null\n\t\t// A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashOffset: null,\n\n\t\t// @option fill: Boolean = depends\n\t\t// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.\n\t\tfill: false,\n\n\t\t// @option fillColor: String = *\n\t\t// Fill color. Defaults to the value of the [`color`](#path-color) option\n\t\tfillColor: null,\n\n\t\t// @option fillOpacity: Number = 0.2\n\t\t// Fill opacity.\n\t\tfillOpacity: 0.2,\n\n\t\t// @option fillRule: String = 'evenodd'\n\t\t// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.\n\t\tfillRule: 'evenodd',\n\n\t\t// className: '',\n\n\t\t// Option inherited from \"Interactive layer\" abstract class\n\t\tinteractive: true,\n\n\t\t// @option bubblingMouseEvents: Boolean = true\n\t\t// When `true`, a mouse event on this path will trigger the same event on the map\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\n\t\tbubblingMouseEvents: true\n\t},\n\n\tbeforeAdd: function (map) {\n\t\t// Renderer is set here because we need to call renderer.getEvents\n\t\t// before this.getEvents.\n\t\tthis._renderer = map.getRenderer(this);\n\t},\n\n\tonAdd: function () {\n\t\tthis._renderer._initPath(this);\n\t\tthis._reset();\n\t\tthis._renderer._addPath(this);\n\t},\n\n\tonRemove: function () {\n\t\tthis._renderer._removePath(this);\n\t},\n\n\t// @method redraw(): this\n\t// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._renderer._updatePath(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method setStyle(style: Path options): this\n\t// Changes the appearance of a Path based on the options in the `Path options` object.\n\tsetStyle: function (style) {\n\t\tUtil.setOptions(this, style);\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._updateStyle(this);\n\t\t\tif (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) {\n\t\t\t\tthis._updateBounds();\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToFront(): this\n\t// Brings the layer to the top of all path layers.\n\tbringToFront: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToFront(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack(): this\n\t// Brings the layer to the bottom of all path layers.\n\tbringToBack: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToBack(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetElement: function () {\n\t\treturn this._path;\n\t},\n\n\t_reset: function () {\n\t\t// defined in child classes\n\t\tthis._project();\n\t\tthis._update();\n\t},\n\n\t_clickTolerance: function () {\n\t\t// used when doing hit detection for Canvas layers\n\t\treturn (this.options.stroke ? this.options.weight / 2 : 0) +\n\t\t (this._renderer.options.tolerance || 0);\n\t}\n});\n","import {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport {toLatLng} from '../../geo/LatLng';\nimport {Bounds} from '../../geometry/Bounds';\n\n\n/*\n * @class CircleMarker\n * @aka L.CircleMarker\n * @inherits Path\n *\n * A circle of a fixed size with radius specified in pixels. Extends `Path`.\n */\n\nexport var CircleMarker = Path.extend({\n\n\t// @section\n\t// @aka CircleMarker options\n\toptions: {\n\t\tfill: true,\n\n\t\t// @option radius: Number = 10\n\t\t// Radius of the circle marker, in pixels\n\t\tradius: 10\n\t},\n\n\tinitialize: function (latlng, options) {\n\t\tUtil.setOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis._radius = this.options.radius;\n\t},\n\n\t// @method setLatLng(latLng: LatLng): this\n\t// Sets the position of a circle marker to a new location.\n\tsetLatLng: function (latlng) {\n\t\tvar oldLatLng = this._latlng;\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis.redraw();\n\n\t\t// @event move: Event\n\t\t// Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\n\t},\n\n\t// @method getLatLng(): LatLng\n\t// Returns the current geographical position of the circle marker\n\tgetLatLng: function () {\n\t\treturn this._latlng;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle marker. Units are in pixels.\n\tsetRadius: function (radius) {\n\t\tthis.options.radius = this._radius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of the circle\n\tgetRadius: function () {\n\t\treturn this._radius;\n\t},\n\n\tsetStyle : function (options) {\n\t\tvar radius = options && options.radius || this._radius;\n\t\tPath.prototype.setStyle.call(this, options);\n\t\tthis.setRadius(radius);\n\t\treturn this;\n\t},\n\n\t_project: function () {\n\t\tthis._point = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._updateBounds();\n\t},\n\n\t_updateBounds: function () {\n\t\tvar r = this._radius,\n\t\t r2 = this._radiusY || r,\n\t\t w = this._clickTolerance(),\n\t\t p = [r + w, r2 + w];\n\t\tthis._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));\n\t},\n\n\t_update: function () {\n\t\tif (this._map) {\n\t\t\tthis._updatePath();\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updateCircle(this);\n\t},\n\n\t_empty: function () {\n\t\treturn this._radius && !this._renderer._bounds.intersects(this._pxBounds);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\treturn p.distanceTo(this._point) <= this._radius + this._clickTolerance();\n\t}\n});\n\n\n// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)\n// Instantiates a circle marker object given a geographical point, and an optional options object.\nexport function circleMarker(latlng, options) {\n\treturn new CircleMarker(latlng, options);\n}\n","import {CircleMarker} from './CircleMarker';\nimport {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport {toLatLng} from '../../geo/LatLng';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Earth} from '../../geo/crs/CRS.Earth';\n\n\n/*\n * @class Circle\n * @aka L.Circle\n * @inherits CircleMarker\n *\n * A class for drawing circle overlays on a map. Extends `CircleMarker`.\n *\n * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).\n *\n * @example\n *\n * ```js\n * L.circle([50.5, 30.5], {radius: 200}).addTo(map);\n * ```\n */\n\nexport var Circle = CircleMarker.extend({\n\n\tinitialize: function (latlng, options, legacyOptions) {\n\t\tif (typeof options === 'number') {\n\t\t\t// Backwards compatibility with 0.7.x factory (latlng, radius, options?)\n\t\t\toptions = Util.extend({}, legacyOptions, {radius: options});\n\t\t}\n\t\tUtil.setOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\n\t\tif (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }\n\n\t\t// @section\n\t\t// @aka Circle options\n\t\t// @option radius: Number; Radius of the circle, in meters.\n\t\tthis._mRadius = this.options.radius;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle. Units are in meters.\n\tsetRadius: function (radius) {\n\t\tthis._mRadius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of a circle. Units are in meters.\n\tgetRadius: function () {\n\t\treturn this._mRadius;\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\tvar half = [this._radius, this._radiusY || this._radius];\n\n\t\treturn new LatLngBounds(\n\t\t\tthis._map.layerPointToLatLng(this._point.subtract(half)),\n\t\t\tthis._map.layerPointToLatLng(this._point.add(half)));\n\t},\n\n\tsetStyle: Path.prototype.setStyle,\n\n\t_project: function () {\n\n\t\tvar lng = this._latlng.lng,\n\t\t lat = this._latlng.lat,\n\t\t map = this._map,\n\t\t crs = map.options.crs;\n\n\t\tif (crs.distance === Earth.distance) {\n\t\t\tvar d = Math.PI / 180,\n\t\t\t latR = (this._mRadius / Earth.R) / d,\n\t\t\t top = map.project([lat + latR, lng]),\n\t\t\t bottom = map.project([lat - latR, lng]),\n\t\t\t p = top.add(bottom).divideBy(2),\n\t\t\t lat2 = map.unproject(p).lat,\n\t\t\t lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /\n\t\t\t (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;\n\n\t\t\tif (isNaN(lngR) || lngR === 0) {\n\t\t\t\tlngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425\n\t\t\t}\n\n\t\t\tthis._point = p.subtract(map.getPixelOrigin());\n\t\t\tthis._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;\n\t\t\tthis._radiusY = p.y - top.y;\n\n\t\t} else {\n\t\t\tvar latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));\n\n\t\t\tthis._point = map.latLngToLayerPoint(this._latlng);\n\t\t\tthis._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;\n\t\t}\n\n\t\tthis._updateBounds();\n\t}\n});\n\n// @factory L.circle(latlng: LatLng, options?: Circle options)\n// Instantiates a circle object given a geographical point, and an options object\n// which contains the circle radius.\n// @alternative\n// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)\n// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.\n// Do not use in new applications or plugins.\nexport function circle(latlng, options, legacyOptions) {\n\treturn new Circle(latlng, options, legacyOptions);\n}\n","import {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport * as LineUtil from '../../geometry/LineUtil';\nimport {LatLng, toLatLng} from '../../geo/LatLng';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Bounds} from '../../geometry/Bounds';\nimport {Point} from '../../geometry/Point';\n\n/*\n * @class Polyline\n * @aka L.Polyline\n * @inherits Path\n *\n * A class for drawing polyline overlays on a map. Extends `Path`.\n *\n * @example\n *\n * ```js\n * // create a red polyline from an array of LatLng points\n * var latlngs = [\n * \t[45.51, -122.68],\n * \t[37.77, -122.43],\n * \t[34.04, -118.2]\n * ];\n *\n * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polyline\n * map.fitBounds(polyline.getBounds());\n * ```\n *\n * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:\n *\n * ```js\n * // create a red polyline from an array of arrays of LatLng points\n * var latlngs = [\n * \t[[45.51, -122.68],\n * \t [37.77, -122.43],\n * \t [34.04, -118.2]],\n * \t[[40.78, -73.91],\n * \t [41.83, -87.62],\n * \t [32.76, -96.72]]\n * ];\n * ```\n */\n\n\nexport var Polyline = Path.extend({\n\n\t// @section\n\t// @aka Polyline options\n\toptions: {\n\t\t// @option smoothFactor: Number = 1.0\n\t\t// How much to simplify the polyline on each zoom level. More means\n\t\t// better performance and smoother look, and less means more accurate representation.\n\t\tsmoothFactor: 1.0,\n\n\t\t// @option noClip: Boolean = false\n\t\t// Disable polyline clipping.\n\t\tnoClip: false\n\t},\n\n\tinitialize: function (latlngs, options) {\n\t\tUtil.setOptions(this, options);\n\t\tthis._setLatLngs(latlngs);\n\t},\n\n\t// @method getLatLngs(): LatLng[]\n\t// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.\n\tgetLatLngs: function () {\n\t\treturn this._latlngs;\n\t},\n\n\t// @method setLatLngs(latlngs: LatLng[]): this\n\t// Replaces all the points in the polyline with the given array of geographical points.\n\tsetLatLngs: function (latlngs) {\n\t\tthis._setLatLngs(latlngs);\n\t\treturn this.redraw();\n\t},\n\n\t// @method isEmpty(): Boolean\n\t// Returns `true` if the Polyline has no LatLngs.\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length;\n\t},\n\n\t// @method closestLayerPoint(p: Point): Point\n\t// Returns the point closest to `p` on the Polyline.\n\tclosestLayerPoint: function (p) {\n\t\tvar minDistance = Infinity,\n\t\t minPoint = null,\n\t\t closest = LineUtil._sqClosestPointOnSegment,\n\t\t p1, p2;\n\n\t\tfor (var j = 0, jLen = this._parts.length; j < jLen; j++) {\n\t\t\tvar points = this._parts[j];\n\n\t\t\tfor (var i = 1, len = points.length; i < len; i++) {\n\t\t\t\tp1 = points[i - 1];\n\t\t\t\tp2 = points[i];\n\n\t\t\t\tvar sqDist = closest(p, p1, p2, true);\n\n\t\t\t\tif (sqDist < minDistance) {\n\t\t\t\t\tminDistance = sqDist;\n\t\t\t\t\tminPoint = closest(p, p1, p2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (minPoint) {\n\t\t\tminPoint.distance = Math.sqrt(minDistance);\n\t\t}\n\t\treturn minPoint;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\t\treturn LineUtil.polylineCenter(this._defaultShape(), this._map.options.crs);\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\treturn this._bounds;\n\t},\n\n\t// @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this\n\t// Adds a given point to the polyline. By default, adds to the first ring of\n\t// the polyline in case of a multi-polyline, but can be overridden by passing\n\t// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).\n\taddLatLng: function (latlng, latlngs) {\n\t\tlatlngs = latlngs || this._defaultShape();\n\t\tlatlng = toLatLng(latlng);\n\t\tlatlngs.push(latlng);\n\t\tthis._bounds.extend(latlng);\n\t\treturn this.redraw();\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tthis._bounds = new LatLngBounds();\n\t\tthis._latlngs = this._convertLatLngs(latlngs);\n\t},\n\n\t_defaultShape: function () {\n\t\treturn LineUtil.isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];\n\t},\n\n\t// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = [],\n\t\t flat = LineUtil.isFlat(latlngs);\n\n\t\tfor (var i = 0, len = latlngs.length; i < len; i++) {\n\t\t\tif (flat) {\n\t\t\t\tresult[i] = toLatLng(latlngs[i]);\n\t\t\t\tthis._bounds.extend(result[i]);\n\t\t\t} else {\n\t\t\t\tresult[i] = this._convertLatLngs(latlngs[i]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t},\n\n\t_project: function () {\n\t\tvar pxBounds = new Bounds();\n\t\tthis._rings = [];\n\t\tthis._projectLatlngs(this._latlngs, this._rings, pxBounds);\n\n\t\tif (this._bounds.isValid() && pxBounds.isValid()) {\n\t\t\tthis._rawPxBounds = pxBounds;\n\t\t\tthis._updateBounds();\n\t\t}\n\t},\n\n\t_updateBounds: function () {\n\t\tvar w = this._clickTolerance(),\n\t\t p = new Point(w, w);\n\n\t\tif (!this._rawPxBounds) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._pxBounds = new Bounds([\n\t\t\tthis._rawPxBounds.min.subtract(p),\n\t\t\tthis._rawPxBounds.max.add(p)\n\t\t]);\n\t},\n\n\t// recursively turns latlngs into a set of rings with projected coordinates\n\t_projectLatlngs: function (latlngs, result, projectedBounds) {\n\t\tvar flat = latlngs[0] instanceof LatLng,\n\t\t len = latlngs.length,\n\t\t i, ring;\n\n\t\tif (flat) {\n\t\t\tring = [];\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tring[i] = this._map.latLngToLayerPoint(latlngs[i]);\n\t\t\t\tprojectedBounds.extend(ring[i]);\n\t\t\t}\n\t\t\tresult.push(ring);\n\t\t} else {\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tthis._projectLatlngs(latlngs[i], result, projectedBounds);\n\t\t\t}\n\t\t}\n\t},\n\n\t// clip polyline by renderer bounds so that we have less to render for performance\n\t_clipPoints: function () {\n\t\tvar bounds = this._renderer._bounds;\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tvar parts = this._parts,\n\t\t i, j, k, len, len2, segment, points;\n\n\t\tfor (i = 0, k = 0, len = this._rings.length; i < len; i++) {\n\t\t\tpoints = this._rings[i];\n\n\t\t\tfor (j = 0, len2 = points.length; j < len2 - 1; j++) {\n\t\t\t\tsegment = LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);\n\n\t\t\t\tif (!segment) { continue; }\n\n\t\t\t\tparts[k] = parts[k] || [];\n\t\t\t\tparts[k].push(segment[0]);\n\n\t\t\t\t// if segment goes out of screen, or it's the last one, it's the end of the line part\n\t\t\t\tif ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {\n\t\t\t\t\tparts[k].push(segment[1]);\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// simplify each clipped part of the polyline for performance\n\t_simplifyPoints: function () {\n\t\tvar parts = this._parts,\n\t\t tolerance = this.options.smoothFactor;\n\n\t\tfor (var i = 0, len = parts.length; i < len; i++) {\n\t\t\tparts[i] = LineUtil.simplify(parts[i], tolerance);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tif (!this._map) { return; }\n\n\t\tthis._clipPoints();\n\t\tthis._simplifyPoints();\n\t\tthis._updatePath();\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p, closed) {\n\t\tvar i, j, k, len, len2, part,\n\t\t w = this._clickTolerance();\n\n\t\tif (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }\n\n\t\t// hit detection for polylines\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tif (!closed && (j === 0)) { continue; }\n\n\t\t\t\tif (LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n});\n\n// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)\n// Instantiates a polyline object given an array of geographical points and\n// optionally an options object. You can create a `Polyline` object with\n// multiple separate lines (`MultiPolyline`) by passing an array of arrays\n// of geographic points.\nexport function polyline(latlngs, options) {\n\treturn new Polyline(latlngs, options);\n}\n\n// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.\nPolyline._flat = LineUtil._flat;\n","import {Polyline} from './Polyline';\nimport {LatLng} from '../../geo/LatLng';\nimport * as LineUtil from '../../geometry/LineUtil';\nimport {Point} from '../../geometry/Point';\nimport {Bounds} from '../../geometry/Bounds';\nimport * as PolyUtil from '../../geometry/PolyUtil';\n\n/*\n * @class Polygon\n * @aka L.Polygon\n * @inherits Polyline\n *\n * A class for drawing polygon overlays on a map. Extends `Polyline`.\n *\n * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.\n *\n *\n * @example\n *\n * ```js\n * // create a red polygon from an array of LatLng points\n * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];\n *\n * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polygon\n * map.fitBounds(polygon.getBounds());\n * ```\n *\n * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:\n *\n * ```js\n * var latlngs = [\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ];\n * ```\n *\n * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.\n *\n * ```js\n * var latlngs = [\n * [ // first polygon\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ],\n * [ // second polygon\n * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]\n * ]\n * ];\n * ```\n */\n\nexport var Polygon = Polyline.extend({\n\n\toptions: {\n\t\tfill: true\n\t},\n\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length || !this._latlngs[0].length;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\t\treturn PolyUtil.polygonCenter(this._defaultShape(), this._map.options.crs);\n\t},\n\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = Polyline.prototype._convertLatLngs.call(this, latlngs),\n\t\t len = result.length;\n\n\t\t// remove last point if it equals first one\n\t\tif (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {\n\t\t\tresult.pop();\n\t\t}\n\t\treturn result;\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tPolyline.prototype._setLatLngs.call(this, latlngs);\n\t\tif (LineUtil.isFlat(this._latlngs)) {\n\t\t\tthis._latlngs = [this._latlngs];\n\t\t}\n\t},\n\n\t_defaultShape: function () {\n\t\treturn LineUtil.isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];\n\t},\n\n\t_clipPoints: function () {\n\t\t// polygons need a different clipping algorithm so we redefine that\n\n\t\tvar bounds = this._renderer._bounds,\n\t\t w = this.options.weight,\n\t\t p = new Point(w, w);\n\n\t\t// increase clip padding by stroke width to avoid stroke on clip edges\n\t\tbounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tfor (var i = 0, len = this._rings.length, clipped; i < len; i++) {\n\t\t\tclipped = PolyUtil.clipPolygon(this._rings[i], bounds, true);\n\t\t\tif (clipped.length) {\n\t\t\t\tthis._parts.push(clipped);\n\t\t\t}\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this, true);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\tvar inside = false,\n\t\t part, p1, p2, i, j, k, len, len2;\n\n\t\tif (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }\n\n\t\t// ray casting algorithm for detecting if point is in polygon\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tp1 = part[j];\n\t\t\t\tp2 = part[k];\n\n\t\t\t\tif (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {\n\t\t\t\t\tinside = !inside;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// also check if it's on polygon stroke\n\t\treturn inside || Polyline.prototype._containsPoint.call(this, p, true);\n\t}\n\n});\n\n\n// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)\nexport function polygon(latlngs, options) {\n\treturn new Polygon(latlngs, options);\n}\n","import {LayerGroup} from './LayerGroup';\r\nimport {FeatureGroup} from './FeatureGroup';\r\nimport * as Util from '../core/Util';\r\nimport {Marker} from './marker/Marker';\r\nimport {Circle} from './vector/Circle';\r\nimport {CircleMarker} from './vector/CircleMarker';\r\nimport {Polyline} from './vector/Polyline';\r\nimport {Polygon} from './vector/Polygon';\r\nimport {LatLng} from '../geo/LatLng';\r\nimport * as LineUtil from '../geometry/LineUtil';\r\nimport {toLatLng} from '../geo/LatLng';\r\n\r\n\r\n/*\r\n * @class GeoJSON\r\n * @aka L.GeoJSON\r\n * @inherits FeatureGroup\r\n *\r\n * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse\r\n * GeoJSON data and display it on the map. Extends `FeatureGroup`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.geoJSON(data, {\r\n * \tstyle: function (feature) {\r\n * \t\treturn {color: feature.properties.color};\r\n * \t}\r\n * }).bindPopup(function (layer) {\r\n * \treturn layer.feature.properties.description;\r\n * }).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var GeoJSON = FeatureGroup.extend({\r\n\r\n\t/* @section\r\n\t * @aka GeoJSON options\r\n\t *\r\n\t * @option pointToLayer: Function = *\r\n\t * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally\r\n\t * called when data is added, passing the GeoJSON point feature and its `LatLng`.\r\n\t * The default is to spawn a default `Marker`:\r\n\t * ```js\r\n\t * function(geoJsonPoint, latlng) {\r\n\t * \treturn L.marker(latlng);\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option style: Function = *\r\n\t * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,\r\n\t * called internally when data is added.\r\n\t * The default value is to not override any defaults:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn {}\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option onEachFeature: Function = *\r\n\t * A `Function` that will be called once for each created `Feature`, after it has\r\n\t * been created and styled. Useful for attaching events and popups to features.\r\n\t * The default is to do nothing with the newly created layers:\r\n\t * ```js\r\n\t * function (feature, layer) {}\r\n\t * ```\r\n\t *\r\n\t * @option filter: Function = *\r\n\t * A `Function` that will be used to decide whether to include a feature or not.\r\n\t * The default is to include all features:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn true;\r\n\t * }\r\n\t * ```\r\n\t * Note: dynamically changing the `filter` option will have effect only on newly\r\n\t * added data. It will _not_ re-evaluate already included features.\r\n\t *\r\n\t * @option coordsToLatLng: Function = *\r\n\t * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.\r\n\t * The default is the `coordsToLatLng` static method.\r\n\t *\r\n\t * @option markersInheritOptions: Boolean = false\r\n\t * Whether default Markers for \"Point\" type Features inherit from group options.\r\n\t */\r\n\r\n\tinitialize: function (geojson, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tif (geojson) {\r\n\t\t\tthis.addData(geojson);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addData( <GeoJSON> data ): this\r\n\t// Adds a GeoJSON object to the layer.\r\n\taddData: function (geojson) {\r\n\t\tvar features = Util.isArray(geojson) ? geojson : geojson.features,\r\n\t\t i, len, feature;\r\n\r\n\t\tif (features) {\r\n\t\t\tfor (i = 0, len = features.length; i < len; i++) {\r\n\t\t\t\t// only add this if geometry or geometries are set and not null\r\n\t\t\t\tfeature = features[i];\r\n\t\t\t\tif (feature.geometries || feature.geometry || feature.features || feature.coordinates) {\r\n\t\t\t\t\tthis.addData(feature);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar options = this.options;\r\n\r\n\t\tif (options.filter && !options.filter(geojson)) { return this; }\r\n\r\n\t\tvar layer = geometryToLayer(geojson, options);\r\n\t\tif (!layer) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tlayer.feature = asFeature(geojson);\r\n\r\n\t\tlayer.defaultOptions = layer.options;\r\n\t\tthis.resetStyle(layer);\r\n\r\n\t\tif (options.onEachFeature) {\r\n\t\t\toptions.onEachFeature(geojson, layer);\r\n\t\t}\r\n\r\n\t\treturn this.addLayer(layer);\r\n\t},\r\n\r\n\t// @method resetStyle( <Path> layer? ): this\r\n\t// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.\r\n\t// If `layer` is omitted, the style of all features in the current layer is reset.\r\n\tresetStyle: function (layer) {\r\n\t\tif (layer === undefined) {\r\n\t\t\treturn this.eachLayer(this.resetStyle, this);\r\n\t\t}\r\n\t\t// reset any custom styles\r\n\t\tlayer.options = Util.extend({}, layer.defaultOptions);\r\n\t\tthis._setLayerStyle(layer, this.options.style);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setStyle( <Function> style ): this\r\n\t// Changes styles of GeoJSON vector layers with the given style function.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.eachLayer(function (layer) {\r\n\t\t\tthis._setLayerStyle(layer, style);\r\n\t\t}, this);\r\n\t},\r\n\r\n\t_setLayerStyle: function (layer, style) {\r\n\t\tif (layer.setStyle) {\r\n\t\t\tif (typeof style === 'function') {\r\n\t\t\t\tstyle = style(layer.feature);\r\n\t\t\t}\r\n\t\t\tlayer.setStyle(style);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @section\r\n// There are several static functions which can be called without instantiating L.GeoJSON:\r\n\r\n// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer\r\n// Creates a `Layer` from a given GeoJSON feature. Can use a custom\r\n// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)\r\n// functions if provided as options.\r\nexport function geometryToLayer(geojson, options) {\r\n\r\n\tvar geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,\r\n\t coords = geometry ? geometry.coordinates : null,\r\n\t layers = [],\r\n\t pointToLayer = options && options.pointToLayer,\r\n\t _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,\r\n\t latlng, latlngs, i, len;\r\n\r\n\tif (!coords && !geometry) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tswitch (geometry.type) {\r\n\tcase 'Point':\r\n\t\tlatlng = _coordsToLatLng(coords);\r\n\t\treturn _pointToLayer(pointToLayer, geojson, latlng, options);\r\n\r\n\tcase 'MultiPoint':\r\n\t\tfor (i = 0, len = coords.length; i < len; i++) {\r\n\t\t\tlatlng = _coordsToLatLng(coords[i]);\r\n\t\t\tlayers.push(_pointToLayer(pointToLayer, geojson, latlng, options));\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tcase 'LineString':\r\n\tcase 'MultiLineString':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);\r\n\t\treturn new Polyline(latlngs, options);\r\n\r\n\tcase 'Polygon':\r\n\tcase 'MultiPolygon':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);\r\n\t\treturn new Polygon(latlngs, options);\r\n\r\n\tcase 'GeometryCollection':\r\n\t\tfor (i = 0, len = geometry.geometries.length; i < len; i++) {\r\n\t\t\tvar geoLayer = geometryToLayer({\r\n\t\t\t\tgeometry: geometry.geometries[i],\r\n\t\t\t\ttype: 'Feature',\r\n\t\t\t\tproperties: geojson.properties\r\n\t\t\t}, options);\r\n\r\n\t\t\tif (geoLayer) {\r\n\t\t\t\tlayers.push(geoLayer);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tcase 'FeatureCollection':\r\n\t\tfor (i = 0, len = geometry.features.length; i < len; i++) {\r\n\t\t\tvar featureLayer = geometryToLayer(geometry.features[i], options);\r\n\r\n\t\t\tif (featureLayer) {\r\n\t\t\t\tlayers.push(featureLayer);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tdefault:\r\n\t\tthrow new Error('Invalid GeoJSON object.');\r\n\t}\r\n}\r\n\r\nfunction _pointToLayer(pointToLayerFn, geojson, latlng, options) {\r\n\treturn pointToLayerFn ?\r\n\t\tpointToLayerFn(geojson, latlng) :\r\n\t\tnew Marker(latlng, options && options.markersInheritOptions && options);\r\n}\r\n\r\n// @function coordsToLatLng(coords: Array): LatLng\r\n// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)\r\n// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.\r\nexport function coordsToLatLng(coords) {\r\n\treturn new LatLng(coords[1], coords[0], coords[2]);\r\n}\r\n\r\n// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array\r\n// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.\r\n// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).\r\n// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.\r\nexport function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {\r\n\tvar latlngs = [];\r\n\r\n\tfor (var i = 0, len = coords.length, latlng; i < len; i++) {\r\n\t\tlatlng = levelsDeep ?\r\n\t\t\tcoordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :\r\n\t\t\t(_coordsToLatLng || coordsToLatLng)(coords[i]);\r\n\r\n\t\tlatlngs.push(latlng);\r\n\t}\r\n\r\n\treturn latlngs;\r\n}\r\n\r\n// @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array\r\n// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function.\r\nexport function latLngToCoords(latlng, precision) {\r\n\tlatlng = toLatLng(latlng);\r\n\treturn latlng.alt !== undefined ?\r\n\t\t[Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision), Util.formatNum(latlng.alt, precision)] :\r\n\t\t[Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision)];\r\n}\r\n\r\n// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array\r\n// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)\r\n// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function.\r\nexport function latLngsToCoords(latlngs, levelsDeep, closed, precision) {\r\n\tvar coords = [];\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\t// Check for flat arrays required to ensure unbalanced arrays are correctly converted in recursion\r\n\t\tcoords.push(levelsDeep ?\r\n\t\t\tlatLngsToCoords(latlngs[i], LineUtil.isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) :\r\n\t\t\tlatLngToCoords(latlngs[i], precision));\r\n\t}\r\n\r\n\tif (!levelsDeep && closed) {\r\n\t\tcoords.push(coords[0].slice());\r\n\t}\r\n\r\n\treturn coords;\r\n}\r\n\r\nexport function getFeature(layer, newGeometry) {\r\n\treturn layer.feature ?\r\n\t\tUtil.extend({}, layer.feature, {geometry: newGeometry}) :\r\n\t\tasFeature(newGeometry);\r\n}\r\n\r\n// @function asFeature(geojson: Object): Object\r\n// Normalize GeoJSON geometries/features into GeoJSON features.\r\nexport function asFeature(geojson) {\r\n\tif (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {\r\n\t\treturn geojson;\r\n\t}\r\n\r\n\treturn {\r\n\t\ttype: 'Feature',\r\n\t\tproperties: {},\r\n\t\tgeometry: geojson\r\n\t};\r\n}\r\n\r\nvar PointToGeoJSON = {\r\n\ttoGeoJSON: function (precision) {\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'Point',\r\n\t\t\tcoordinates: latLngToCoords(this.getLatLng(), precision)\r\n\t\t});\r\n\t}\r\n};\r\n\r\n// @namespace Marker\r\n// @section Other methods\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).\r\nMarker.include(PointToGeoJSON);\r\n\r\n// @namespace CircleMarker\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).\r\nCircle.include(PointToGeoJSON);\r\nCircleMarker.include(PointToGeoJSON);\r\n\r\n\r\n// @namespace Polyline\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).\r\nPolyline.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar multi = !LineUtil.isFlat(this._latlngs);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'LineString',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n// @namespace Polygon\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).\r\nPolygon.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar holes = !LineUtil.isFlat(this._latlngs),\r\n\t\t multi = holes && !LineUtil.isFlat(this._latlngs[0]);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);\r\n\r\n\t\tif (!holes) {\r\n\t\t\tcoords = [coords];\r\n\t\t}\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'Polygon',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n\r\n// @namespace LayerGroup\r\nLayerGroup.include({\r\n\ttoMultiPoint: function (precision) {\r\n\t\tvar coords = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tcoords.push(layer.toGeoJSON(precision).geometry.coordinates);\r\n\t\t});\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'MultiPoint',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t},\r\n\r\n\t// @method toGeoJSON(precision?: Number|false): Object\r\n\t// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n\t// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).\r\n\ttoGeoJSON: function (precision) {\r\n\r\n\t\tvar type = this.feature && this.feature.geometry && this.feature.geometry.type;\r\n\r\n\t\tif (type === 'MultiPoint') {\r\n\t\t\treturn this.toMultiPoint(precision);\r\n\t\t}\r\n\r\n\t\tvar isGeometryCollection = type === 'GeometryCollection',\r\n\t\t jsons = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tif (layer.toGeoJSON) {\r\n\t\t\t\tvar json = layer.toGeoJSON(precision);\r\n\t\t\t\tif (isGeometryCollection) {\r\n\t\t\t\t\tjsons.push(json.geometry);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvar feature = asFeature(json);\r\n\t\t\t\t\t// Squash nested feature collections\r\n\t\t\t\t\tif (feature.type === 'FeatureCollection') {\r\n\t\t\t\t\t\tjsons.push.apply(jsons, feature.features);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tjsons.push(feature);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (isGeometryCollection) {\r\n\t\t\treturn getFeature(this, {\r\n\t\t\t\tgeometries: jsons,\r\n\t\t\t\ttype: 'GeometryCollection'\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'FeatureCollection',\r\n\t\t\tfeatures: jsons\r\n\t\t};\r\n\t}\r\n});\r\n\r\n// @namespace GeoJSON\r\n// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)\r\n// Creates a GeoJSON layer. Optionally accepts an object in\r\n// [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map\r\n// (you can alternatively add it later with `addData` method) and an `options` object.\r\nexport function geoJSON(geojson, options) {\r\n\treturn new GeoJSON(geojson, options);\r\n}\r\n\r\n// Backward compatibility.\r\nexport var geoJson = geoJSON;\r\n","import {Layer} from './Layer';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLngBounds} from '../geo/LatLngBounds';\r\nimport {Bounds} from '../geometry/Bounds';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class ImageOverlay\r\n * @aka L.ImageOverlay\r\n * @inherits Interactive layer\r\n *\r\n * Used to load and display a single image over specific bounds of the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\r\n * \timageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\r\n * L.imageOverlay(imageUrl, imageBounds).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var ImageOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka ImageOverlay options\r\n\toptions: {\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the image overlay.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the image.\r\n\t\t// If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false,\r\n\r\n\t\t// @option errorOverlayUrl: String = ''\r\n\t\t// URL to the overlay image to show in place of the overlay that failed to load.\r\n\t\terrorOverlayUrl: '',\r\n\r\n\t\t// @option zIndex: Number = 1\r\n\t\t// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.\r\n\t\tzIndex: 1,\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom class name to assign to the image. Empty by default.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\tinitialize: function (url, bounds, options) { // (String, LatLngBounds, Object)\r\n\t\tthis._url = url;\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tUtil.setOptions(this, options);\r\n\t},\r\n\r\n\tonAdd: function () {\r\n\t\tif (!this._image) {\r\n\t\t\tthis._initImage();\r\n\r\n\t\t\tif (this.options.opacity < 1) {\r\n\t\t\t\tthis._updateOpacity();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.addClass(this._image, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._image);\r\n\t\t}\r\n\r\n\t\tthis.getPane().appendChild(this._image);\r\n\t\tthis._reset();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tDomUtil.remove(this._image);\r\n\t\tif (this.options.interactive) {\r\n\t\t\tthis.removeInteractiveTarget(this._image);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Sets the opacity of the overlay.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetStyle: function (styleOpts) {\r\n\t\tif (styleOpts.opacity) {\r\n\t\t\tthis.setOpacity(styleOpts.opacity);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer to the top of all overlays.\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toFront(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer to the bottom of all overlays.\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toBack(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setUrl(url: String): this\r\n\t// Changes the URL of the image.\r\n\tsetUrl: function (url) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._image.src = url;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setBounds(bounds: LatLngBounds): this\r\n\t// Update the bounds that this ImageOverlay covers\r\n\tsetBounds: function (bounds) {\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._reset();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._reset,\r\n\t\t\tviewreset: this._reset\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method setZIndex(value: Number): this\r\n\t// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.\r\n\tsetZIndex: function (value) {\r\n\t\tthis.options.zIndex = value;\r\n\t\tthis._updateZIndex();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Get the bounds that this ImageOverlay covers\r\n\tgetBounds: function () {\r\n\t\treturn this._bounds;\r\n\t},\r\n\r\n\t// @method getElement(): HTMLElement\r\n\t// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)\r\n\t// used by this overlay.\r\n\tgetElement: function () {\r\n\t\treturn this._image;\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'IMG';\r\n\t\tvar img = this._image = wasElementSupplied ? this._url : DomUtil.create('img');\r\n\r\n\t\tDomUtil.addClass(img, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { DomUtil.addClass(img, 'leaflet-zoom-animated'); }\r\n\t\tif (this.options.className) { DomUtil.addClass(img, this.options.className); }\r\n\r\n\t\timg.onselectstart = Util.falseFn;\r\n\t\timg.onmousemove = Util.falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the ImageOverlay layer has loaded its image\r\n\t\timg.onload = Util.bind(this.fire, this, 'load');\r\n\t\timg.onerror = Util.bind(this._overlayOnError, this, 'error');\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\timg.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\tif (this.options.zIndex) {\r\n\t\t\tthis._updateZIndex();\r\n\t\t}\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tthis._url = img.src;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\timg.src = this._url;\r\n\t\timg.alt = this.options.alt;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar scale = this._map.getZoomScale(e.zoom),\r\n\t\t offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;\r\n\r\n\t\tDomUtil.setTransform(this._image, offset, scale);\r\n\t},\r\n\r\n\t_reset: function () {\r\n\t\tvar image = this._image,\r\n\t\t bounds = new Bounds(\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getNorthWest()),\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getSouthEast())),\r\n\t\t size = bounds.getSize();\r\n\r\n\t\tDomUtil.setPosition(image, bounds.min);\r\n\r\n\t\timage.style.width = size.x + 'px';\r\n\t\timage.style.height = size.y + 'px';\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tDomUtil.setOpacity(this._image, this.options.opacity);\r\n\t},\r\n\r\n\t_updateZIndex: function () {\r\n\t\tif (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {\r\n\t\t\tthis._image.style.zIndex = this.options.zIndex;\r\n\t\t}\r\n\t},\r\n\r\n\t_overlayOnError: function () {\r\n\t\t// @event error: Event\r\n\t\t// Fired when the ImageOverlay layer fails to load its image\r\n\t\tthis.fire('error');\r\n\r\n\t\tvar errorUrl = this.options.errorOverlayUrl;\r\n\t\tif (errorUrl && this._url !== errorUrl) {\r\n\t\t\tthis._url = errorUrl;\r\n\t\t\tthis._image.src = errorUrl;\r\n\t\t}\r\n\t},\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the center of the ImageOverlay.\r\n\tgetCenter: function () {\r\n\t\treturn this._bounds.getCenter();\r\n\t}\r\n});\r\n\r\n// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)\r\n// Instantiates an image overlay object given the URL of the image and the\r\n// geographical bounds it is tied to.\r\nexport var imageOverlay = function (url, bounds, options) {\r\n\treturn new ImageOverlay(url, bounds, options);\r\n};\r\n","import {ImageOverlay} from './ImageOverlay';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class VideoOverlay\r\n * @aka L.VideoOverlay\r\n * @inherits ImageOverlay\r\n *\r\n * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.\r\n *\r\n * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)\r\n * HTML5 element.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',\r\n * \tvideoBounds = [[ 32, -130], [ 13, -100]];\r\n * L.videoOverlay(videoUrl, videoBounds ).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var VideoOverlay = ImageOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka VideoOverlay options\r\n\toptions: {\r\n\t\t// @option autoplay: Boolean = true\r\n\t\t// Whether the video starts playing automatically when loaded.\r\n\t\t// On some browsers autoplay will only work with `muted: true`\r\n\t\tautoplay: true,\r\n\r\n\t\t// @option loop: Boolean = true\r\n\t\t// Whether the video will loop back to the beginning when played.\r\n\t\tloop: true,\r\n\r\n\t\t// @option keepAspectRatio: Boolean = true\r\n\t\t// Whether the video will save aspect ratio after the projection.\r\n\t\t// Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)\r\n\t\tkeepAspectRatio: true,\r\n\r\n\t\t// @option muted: Boolean = false\r\n\t\t// Whether the video starts on mute when loaded.\r\n\t\tmuted: false,\r\n\r\n\t\t// @option playsInline: Boolean = true\r\n\t\t// Mobile browsers will play the video right where it is instead of open it up in fullscreen mode.\r\n\t\tplaysInline: true\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'VIDEO';\r\n\t\tvar vid = this._image = wasElementSupplied ? this._url : DomUtil.create('video');\r\n\r\n\t\tDomUtil.addClass(vid, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { DomUtil.addClass(vid, 'leaflet-zoom-animated'); }\r\n\t\tif (this.options.className) { DomUtil.addClass(vid, this.options.className); }\r\n\r\n\t\tvid.onselectstart = Util.falseFn;\r\n\t\tvid.onmousemove = Util.falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the video has finished loading the first frame\r\n\t\tvid.onloadeddata = Util.bind(this.fire, this, 'load');\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tvar sourceElements = vid.getElementsByTagName('source');\r\n\t\t\tvar sources = [];\r\n\t\t\tfor (var j = 0; j < sourceElements.length; j++) {\r\n\t\t\t\tsources.push(sourceElements[j].src);\r\n\t\t\t}\r\n\r\n\t\t\tthis._url = (sourceElements.length > 0) ? sources : [vid.src];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!Util.isArray(this._url)) { this._url = [this._url]; }\r\n\r\n\t\tif (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) {\r\n\t\t\tvid.style['objectFit'] = 'fill';\r\n\t\t}\r\n\t\tvid.autoplay = !!this.options.autoplay;\r\n\t\tvid.loop = !!this.options.loop;\r\n\t\tvid.muted = !!this.options.muted;\r\n\t\tvid.playsInline = !!this.options.playsInline;\r\n\t\tfor (var i = 0; i < this._url.length; i++) {\r\n\t\t\tvar source = DomUtil.create('source');\r\n\t\t\tsource.src = this._url[i];\r\n\t\t\tvid.appendChild(source);\r\n\t\t}\r\n\t}\r\n\r\n\t// @method getElement(): HTMLVideoElement\r\n\t// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)\r\n\t// used by this overlay.\r\n});\r\n\r\n\r\n// @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)\r\n// Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the\r\n// geographical bounds it is tied to.\r\n\r\nexport function videoOverlay(video, bounds, options) {\r\n\treturn new VideoOverlay(video, bounds, options);\r\n}\r\n","import {ImageOverlay} from './ImageOverlay';\nimport * as DomUtil from '../dom/DomUtil';\nimport * as Util from '../core/Util';\n\n/*\n * @class SVGOverlay\n * @aka L.SVGOverlay\n * @inherits ImageOverlay\n *\n * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`.\n *\n * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element.\n *\n * @example\n *\n * ```js\n * var svgElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n * svgElement.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n * svgElement.setAttribute('viewBox', \"0 0 200 200\");\n * svgElement.innerHTML = '<rect width=\"200\" height=\"200\"/><rect x=\"75\" y=\"23\" width=\"50\" height=\"50\" style=\"fill:red\"/><rect x=\"75\" y=\"123\" width=\"50\" height=\"50\" style=\"fill:#0013ff\"/>';\n * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ];\n * L.svgOverlay(svgElement, svgElementBounds).addTo(map);\n * ```\n */\n\nexport var SVGOverlay = ImageOverlay.extend({\n\t_initImage: function () {\n\t\tvar el = this._image = this._url;\n\n\t\tDomUtil.addClass(el, 'leaflet-image-layer');\n\t\tif (this._zoomAnimated) { DomUtil.addClass(el, 'leaflet-zoom-animated'); }\n\t\tif (this.options.className) { DomUtil.addClass(el, this.options.className); }\n\n\t\tel.onselectstart = Util.falseFn;\n\t\tel.onmousemove = Util.falseFn;\n\t}\n\n\t// @method getElement(): SVGElement\n\t// Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)\n\t// used by this overlay.\n});\n\n\n// @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options)\n// Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to.\n// A viewBox attribute is required on the SVG element to zoom in and out properly.\n\nexport function svgOverlay(el, bounds, options) {\n\treturn new SVGOverlay(el, bounds, options);\n}\n","import {Map} from '../map/Map';\r\nimport {Layer} from './Layer';\r\nimport {FeatureGroup} from './FeatureGroup';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLng, LatLng} from '../geo/LatLng';\r\nimport {toPoint} from '../geometry/Point';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class DivOverlay\r\n * @inherits Interactive layer\r\n * @aka L.DivOverlay\r\n * Base model for L.Popup and L.Tooltip. Inherit from it for custom overlays like plugins.\r\n */\r\n\r\n// @namespace DivOverlay\r\nexport var DivOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka DivOverlay options\r\n\toptions: {\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If true, the popup/tooltip will listen to the mouse events.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option offset: Point = Point(0, 0)\r\n\t\t// The offset of the overlay position.\r\n\t\toffset: [0, 0],\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the overlay.\r\n\t\tclassName: '',\r\n\r\n\t\t// @option pane: String = undefined\r\n\t\t// `Map pane` where the overlay will be added.\r\n\t\tpane: undefined,\r\n\r\n\t\t// @option content: String|HTMLElement|Function = ''\r\n\t\t// Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be\r\n\t\t// passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay.\r\n\t\tcontent: ''\r\n\t},\r\n\r\n\tinitialize: function (options, source) {\r\n\t\tif (options && (options instanceof LatLng || Util.isArray(options))) {\r\n\t\t\tthis._latlng = toLatLng(options);\r\n\t\t\tUtil.setOptions(this, source);\r\n\t\t} else {\r\n\t\t\tUtil.setOptions(this, options);\r\n\t\t\tthis._source = source;\r\n\t\t}\r\n\t\tif (this.options.content) {\r\n\t\t\tthis._content = this.options.content;\r\n\t\t}\r\n\t},\r\n\r\n\t// @method openOn(map: Map): this\r\n\t// Adds the overlay to the map.\r\n\t// Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`.\r\n\topenOn: function (map) {\r\n\t\tmap = arguments.length ? map : this._source._map; // experimental, not the part of public api\r\n\t\tif (!map.hasLayer(this)) {\r\n\t\t\tmap.addLayer(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method close(): this\r\n\t// Closes the overlay.\r\n\t// Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)`\r\n\t// and `layer.closePopup()`/`.closeTooltip()`.\r\n\tclose: function () {\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.removeLayer(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method toggle(layer?: Layer): this\r\n\t// Opens or closes the overlay bound to layer depending on its current state.\r\n\t// Argument may be omitted only for overlay bound to layer.\r\n\t// Alternative to `layer.togglePopup()`/`.toggleTooltip()`.\r\n\ttoggle: function (layer) {\r\n\t\tif (this._map) {\r\n\t\t\tthis.close();\r\n\t\t} else {\r\n\t\t\tif (arguments.length) {\r\n\t\t\t\tthis._source = layer;\r\n\t\t\t} else {\r\n\t\t\t\tlayer = this._source;\r\n\t\t\t}\r\n\t\t\tthis._prepareOpen();\r\n\r\n\t\t\t// open the overlay on the map\r\n\t\t\tthis.openOn(layer._map);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = map._zoomAnimated;\r\n\r\n\t\tif (!this._container) {\r\n\t\t\tthis._initLayout();\r\n\t\t}\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 0);\r\n\t\t}\r\n\r\n\t\tclearTimeout(this._removeTimeout);\r\n\t\tthis.getPane().appendChild(this._container);\r\n\t\tthis.update();\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 1);\r\n\t\t}\r\n\r\n\t\tthis.bringToFront();\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.addClass(this._container, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 0);\r\n\t\t\tthis._removeTimeout = setTimeout(Util.bind(DomUtil.remove, undefined, this._container), 200);\r\n\t\t} else {\r\n\t\t\tDomUtil.remove(this._container);\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-interactive');\r\n\t\t\tthis.removeInteractiveTarget(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\t// @namespace DivOverlay\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the geographical point of the overlay.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Sets the geographical point where the overlay will open.\r\n\tsetLatLng: function (latlng) {\r\n\t\tthis._latlng = toLatLng(latlng);\r\n\t\tif (this._map) {\r\n\t\t\tthis._updatePosition();\r\n\t\t\tthis._adjustPan();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContent: String|HTMLElement\r\n\t// Returns the content of the overlay.\r\n\tgetContent: function () {\r\n\t\treturn this._content;\r\n\t},\r\n\r\n\t// @method setContent(htmlContent: String|HTMLElement|Function): this\r\n\t// Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function.\r\n\t// The function should return a `String` or `HTMLElement` to be used in the overlay.\r\n\tsetContent: function (content) {\r\n\t\tthis._content = content;\r\n\t\tthis.update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getElement: String|HTMLElement\r\n\t// Returns the HTML container of the overlay.\r\n\tgetElement: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method update: null\r\n\t// Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded.\r\n\tupdate: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tthis._container.style.visibility = 'hidden';\r\n\r\n\t\tthis._updateContent();\r\n\t\tthis._updateLayout();\r\n\t\tthis._updatePosition();\r\n\r\n\t\tthis._container.style.visibility = '';\r\n\r\n\t\tthis._adjustPan();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._updatePosition,\r\n\t\t\tviewreset: this._updatePosition\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method isOpen: Boolean\r\n\t// Returns `true` when the overlay is visible on the map.\r\n\tisOpen: function () {\r\n\t\treturn !!this._map && this._map.hasLayer(this);\r\n\t},\r\n\r\n\t// @method bringToFront: this\r\n\t// Brings this overlay in front of other overlays (in the same map pane).\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toFront(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack: this\r\n\t// Brings this overlay to the back of other overlays (in the same map pane).\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toBack(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)\r\n\t_prepareOpen: function (latlng) {\r\n\t\tvar source = this._source;\r\n\t\tif (!source._map) { return false; }\r\n\r\n\t\tif (source instanceof FeatureGroup) {\r\n\t\t\tsource = null;\r\n\t\t\tvar layers = this._source._layers;\r\n\t\t\tfor (var id in layers) {\r\n\t\t\t\tif (layers[id]._map) {\r\n\t\t\t\t\tsource = layers[id];\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!source) { return false; } // Unable to get source layer.\r\n\r\n\t\t\t// set overlay source to this layer\r\n\t\t\tthis._source = source;\r\n\t\t}\r\n\r\n\t\tif (!latlng) {\r\n\t\t\tif (source.getCenter) {\r\n\t\t\t\tlatlng = source.getCenter();\r\n\t\t\t} else if (source.getLatLng) {\r\n\t\t\t\tlatlng = source.getLatLng();\r\n\t\t\t} else if (source.getBounds) {\r\n\t\t\t\tlatlng = source.getBounds().getCenter();\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Unable to get source layer LatLng.');\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.setLatLng(latlng);\r\n\r\n\t\tif (this._map) {\r\n\t\t\t// update the overlay (content, layout, etc...)\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_updateContent: function () {\r\n\t\tif (!this._content) { return; }\r\n\r\n\t\tvar node = this._contentNode;\r\n\t\tvar content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;\r\n\r\n\t\tif (typeof content === 'string') {\r\n\t\t\tnode.innerHTML = content;\r\n\t\t} else {\r\n\t\t\twhile (node.hasChildNodes()) {\r\n\t\t\t\tnode.removeChild(node.firstChild);\r\n\t\t\t}\r\n\t\t\tnode.appendChild(content);\r\n\t\t}\r\n\r\n\t\t// @namespace DivOverlay\r\n\t\t// @section DivOverlay events\r\n\t\t// @event contentupdate: Event\r\n\t\t// Fired when the content of the overlay is updated\r\n\t\tthis.fire('contentupdate');\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng),\r\n\t\t offset = toPoint(this.options.offset),\r\n\t\t anchor = this._getAnchor();\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tDomUtil.setPosition(this._container, pos.add(anchor));\r\n\t\t} else {\r\n\t\t\toffset = offset.add(pos).add(anchor);\r\n\t\t}\r\n\r\n\t\tvar bottom = this._containerBottom = -offset.y,\r\n\t\t left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;\r\n\r\n\t\t// bottom position the overlay in case the height of the overlay changes (images loading etc)\r\n\t\tthis._container.style.bottom = bottom + 'px';\r\n\t\tthis._container.style.left = left + 'px';\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\treturn [0, 0];\r\n\t}\r\n\r\n});\r\n\r\nMap.include({\r\n\t_initOverlay: function (OverlayClass, content, latlng, options) {\r\n\t\tvar overlay = content;\r\n\t\tif (!(overlay instanceof OverlayClass)) {\r\n\t\t\toverlay = new OverlayClass(options).setContent(content);\r\n\t\t}\r\n\t\tif (latlng) {\r\n\t\t\toverlay.setLatLng(latlng);\r\n\t\t}\r\n\t\treturn overlay;\r\n\t}\r\n});\r\n\r\n\r\nLayer.include({\r\n\t_initOverlay: function (OverlayClass, old, content, options) {\r\n\t\tvar overlay = content;\r\n\t\tif (overlay instanceof OverlayClass) {\r\n\t\t\tUtil.setOptions(overlay, options);\r\n\t\t\toverlay._source = this;\r\n\t\t} else {\r\n\t\t\toverlay = (old && !options) ? old : new OverlayClass(options, this);\r\n\t\t\toverlay.setContent(content);\r\n\t\t}\r\n\t\treturn overlay;\r\n\t}\r\n});\r\n","import {DivOverlay} from './DivOverlay';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport {Point, toPoint} from '../geometry/Point';\r\nimport {Map} from '../map/Map';\r\nimport {Layer} from './Layer';\r\nimport {Path} from './vector/Path';\r\nimport {FeatureGroup} from './FeatureGroup';\r\n\r\n/*\r\n * @class Popup\r\n * @inherits DivOverlay\r\n * @aka L.Popup\r\n * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to\r\n * open popups while making sure that only one popup is open at one time\r\n * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.\r\n *\r\n * @example\r\n *\r\n * If you want to just bind a popup to marker click and then open it, it's really easy:\r\n *\r\n * ```js\r\n * marker.bindPopup(popupContent).openPopup();\r\n * ```\r\n * Path overlays like polylines also have a `bindPopup` method.\r\n *\r\n * A popup can be also standalone:\r\n *\r\n * ```js\r\n * var popup = L.popup()\r\n * \t.setLatLng(latlng)\r\n * \t.setContent('<p>Hello world!<br />This is a nice popup.</p>')\r\n * \t.openOn(map);\r\n * ```\r\n * or\r\n * ```js\r\n * var popup = L.popup(latlng, {content: '<p>Hello world!<br />This is a nice popup.</p>')\r\n * \t.openOn(map);\r\n * ```\r\n */\r\n\r\n\r\n// @namespace Popup\r\nexport var Popup = DivOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka Popup options\r\n\toptions: {\r\n\t\t// @option pane: String = 'popupPane'\r\n\t\t// `Map pane` where the popup will be added.\r\n\t\tpane: 'popupPane',\r\n\r\n\t\t// @option offset: Point = Point(0, 7)\r\n\t\t// The offset of the popup position.\r\n\t\toffset: [0, 7],\r\n\r\n\t\t// @option maxWidth: Number = 300\r\n\t\t// Max width of the popup, in pixels.\r\n\t\tmaxWidth: 300,\r\n\r\n\t\t// @option minWidth: Number = 50\r\n\t\t// Min width of the popup, in pixels.\r\n\t\tminWidth: 50,\r\n\r\n\t\t// @option maxHeight: Number = null\r\n\t\t// If set, creates a scrollable container of the given height\r\n\t\t// inside a popup if its content exceeds it.\r\n\t\t// The scrollable container can be styled using the\r\n\t\t// `leaflet-popup-scrolled` CSS class selector.\r\n\t\tmaxHeight: null,\r\n\r\n\t\t// @option autoPan: Boolean = true\r\n\t\t// Set it to `false` if you don't want the map to do panning animation\r\n\t\t// to fit the opened popup.\r\n\t\tautoPan: true,\r\n\r\n\t\t// @option autoPanPaddingTopLeft: Point = null\r\n\t\t// The margin between the popup and the top left corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingTopLeft: null,\r\n\r\n\t\t// @option autoPanPaddingBottomRight: Point = null\r\n\t\t// The margin between the popup and the bottom right corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingBottomRight: null,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(5, 5)\r\n\t\t// Equivalent of setting both top left and bottom right autopan padding to the same value.\r\n\t\tautoPanPadding: [5, 5],\r\n\r\n\t\t// @option keepInView: Boolean = false\r\n\t\t// Set it to `true` if you want to prevent users from panning the popup\r\n\t\t// off of the screen while it is open.\r\n\t\tkeepInView: false,\r\n\r\n\t\t// @option closeButton: Boolean = true\r\n\t\t// Controls the presence of a close button in the popup.\r\n\t\tcloseButton: true,\r\n\r\n\t\t// @option autoClose: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the popup closing when another popup is opened.\r\n\t\tautoClose: true,\r\n\r\n\t\t// @option closeOnEscapeKey: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the ESC key for closing of the popup.\r\n\t\tcloseOnEscapeKey: true,\r\n\r\n\t\t// @option closeOnClick: Boolean = *\r\n\t\t// Set it if you want to override the default behavior of the popup closing when user clicks\r\n\t\t// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method openOn(map: Map): this\r\n\t// Alternative to `map.openPopup(popup)`.\r\n\t// Adds the popup to the map and closes the previous one.\r\n\topenOn: function (map) {\r\n\t\tmap = arguments.length ? map : this._source._map; // experimental, not the part of public api\r\n\r\n\t\tif (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) {\r\n\t\t\tmap.removeLayer(map._popup);\r\n\t\t}\r\n\t\tmap._popup = this;\r\n\r\n\t\treturn DivOverlay.prototype.openOn.call(this, map);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tDivOverlay.prototype.onAdd.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupopen: PopupEvent\r\n\t\t// Fired when a popup is opened in the map\r\n\t\tmap.fire('popupopen', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupopen: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is opened\r\n\t\t\tthis._source.fire('popupopen', {popup: this}, true);\r\n\t\t\t// For non-path layers, we toggle the popup when clicking\r\n\t\t\t// again the layer, so prevent the map to reopen it.\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.on('preclick', DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tDivOverlay.prototype.onRemove.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupclose: PopupEvent\r\n\t\t// Fired when a popup in the map is closed\r\n\t\tmap.fire('popupclose', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupclose: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is closed\r\n\t\t\tthis._source.fire('popupclose', {popup: this}, true);\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.off('preclick', DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\r\n\r\n\t\tif (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {\r\n\t\t\tevents.preclick = this.close;\r\n\t\t}\r\n\r\n\t\tif (this.options.keepInView) {\r\n\t\t\tevents.moveend = this._adjustPan;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar prefix = 'leaflet-popup',\r\n\t\t container = this._container = DomUtil.create('div',\r\n\t\t\tprefix + ' ' + (this.options.className || '') +\r\n\t\t\t' leaflet-zoom-animated');\r\n\r\n\t\tvar wrapper = this._wrapper = DomUtil.create('div', prefix + '-content-wrapper', container);\r\n\t\tthis._contentNode = DomUtil.create('div', prefix + '-content', wrapper);\r\n\r\n\t\tDomEvent.disableClickPropagation(container);\r\n\t\tDomEvent.disableScrollPropagation(this._contentNode);\r\n\t\tDomEvent.on(container, 'contextmenu', DomEvent.stopPropagation);\r\n\r\n\t\tthis._tipContainer = DomUtil.create('div', prefix + '-tip-container', container);\r\n\t\tthis._tip = DomUtil.create('div', prefix + '-tip', this._tipContainer);\r\n\r\n\t\tif (this.options.closeButton) {\r\n\t\t\tvar closeButton = this._closeButton = DomUtil.create('a', prefix + '-close-button', container);\r\n\t\t\tcloseButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399\r\n\t\t\tcloseButton.setAttribute('aria-label', 'Close popup');\r\n\t\t\tcloseButton.href = '#close';\r\n\t\t\tcloseButton.innerHTML = '<span aria-hidden=\"true\">&#215;</span>';\r\n\r\n\t\t\tDomEvent.on(closeButton, 'click', function (ev) {\r\n\t\t\t\tDomEvent.preventDefault(ev);\r\n\t\t\t\tthis.close();\r\n\t\t\t}, this);\r\n\t\t}\r\n\t},\r\n\r\n\t_updateLayout: function () {\r\n\t\tvar container = this._contentNode,\r\n\t\t style = container.style;\r\n\r\n\t\tstyle.width = '';\r\n\t\tstyle.whiteSpace = 'nowrap';\r\n\r\n\t\tvar width = container.offsetWidth;\r\n\t\twidth = Math.min(width, this.options.maxWidth);\r\n\t\twidth = Math.max(width, this.options.minWidth);\r\n\r\n\t\tstyle.width = (width + 1) + 'px';\r\n\t\tstyle.whiteSpace = '';\r\n\r\n\t\tstyle.height = '';\r\n\r\n\t\tvar height = container.offsetHeight,\r\n\t\t maxHeight = this.options.maxHeight,\r\n\t\t scrolledClass = 'leaflet-popup-scrolled';\r\n\r\n\t\tif (maxHeight && height > maxHeight) {\r\n\t\t\tstyle.height = maxHeight + 'px';\r\n\t\t\tDomUtil.addClass(container, scrolledClass);\r\n\t\t} else {\r\n\t\t\tDomUtil.removeClass(container, scrolledClass);\r\n\t\t}\r\n\r\n\t\tthis._containerWidth = this._container.offsetWidth;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),\r\n\t\t anchor = this._getAnchor();\r\n\t\tDomUtil.setPosition(this._container, pos.add(anchor));\r\n\t},\r\n\r\n\t_adjustPan: function () {\r\n\t\tif (!this.options.autoPan) { return; }\r\n\t\tif (this._map._panAnim) { this._map._panAnim.stop(); }\r\n\r\n\t\t// We can endlessly recurse if keepInView is set and the view resets.\r\n\t\t// Let's guard against that by exiting early if we're responding to our own autopan.\r\n\t\tif (this._autopanning) {\r\n\t\t\tthis._autopanning = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar map = this._map,\r\n\t\t marginBottom = parseInt(DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,\r\n\t\t containerHeight = this._container.offsetHeight + marginBottom,\r\n\t\t containerWidth = this._containerWidth,\r\n\t\t layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);\r\n\r\n\t\tlayerPos._add(DomUtil.getPosition(this._container));\r\n\r\n\t\tvar containerPos = map.layerPointToContainerPoint(layerPos),\r\n\t\t padding = toPoint(this.options.autoPanPadding),\r\n\t\t paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),\r\n\t\t paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),\r\n\t\t size = map.getSize(),\r\n\t\t dx = 0,\r\n\t\t dy = 0;\r\n\r\n\t\tif (containerPos.x + containerWidth + paddingBR.x > size.x) { // right\r\n\t\t\tdx = containerPos.x + containerWidth - size.x + paddingBR.x;\r\n\t\t}\r\n\t\tif (containerPos.x - dx - paddingTL.x < 0) { // left\r\n\t\t\tdx = containerPos.x - paddingTL.x;\r\n\t\t}\r\n\t\tif (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom\r\n\t\t\tdy = containerPos.y + containerHeight - size.y + paddingBR.y;\r\n\t\t}\r\n\t\tif (containerPos.y - dy - paddingTL.y < 0) { // top\r\n\t\t\tdy = containerPos.y - paddingTL.y;\r\n\t\t}\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event autopanstart: Event\r\n\t\t// Fired when the map starts autopanning when opening a popup.\r\n\t\tif (dx || dy) {\r\n\t\t\t// Track that we're autopanning, as this function will be re-ran on moveend\r\n\t\t\tif (this.options.keepInView) {\r\n\t\t\t\tthis._autopanning = true;\r\n\t\t\t}\r\n\r\n\t\t\tmap\r\n\t\t\t .fire('autopanstart')\r\n\t\t\t .panBy([dx, dy]);\r\n\t\t}\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\t// Where should we anchor the popup on the source layer?\r\n\t\treturn toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);\r\n\t}\r\n\r\n});\r\n\r\n// @namespace Popup\r\n// @factory L.popup(options?: Popup options, source?: Layer)\r\n// Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.\r\n// @alternative\r\n// @factory L.popup(latlng: LatLng, options?: Popup options)\r\n// Instantiates a `Popup` object given `latlng` where the popup will open and an optional `options` object that describes its appearance and location.\r\nexport var popup = function (options, source) {\r\n\treturn new Popup(options, source);\r\n};\r\n\r\n\r\n/* @namespace Map\r\n * @section Interaction Options\r\n * @option closePopupOnClick: Boolean = true\r\n * Set it to `false` if you don't want popups to close when user clicks the map.\r\n */\r\nMap.mergeOptions({\r\n\tclosePopupOnClick: true\r\n});\r\n\r\n\r\n// @namespace Map\r\n// @section Methods for Layers and Controls\r\nMap.include({\r\n\t// @method openPopup(popup: Popup): this\r\n\t// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).\r\n\t// @alternative\r\n\t// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this\r\n\t// Creates a popup with the specified content and options and opens it in the given point on a map.\r\n\topenPopup: function (popup, latlng, options) {\r\n\t\tthis._initOverlay(Popup, popup, latlng, options)\r\n\t\t .openOn(this);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(popup?: Popup): this\r\n\t// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).\r\n\tclosePopup: function (popup) {\r\n\t\tpopup = arguments.length ? popup : this._popup;\r\n\t\tif (popup) {\r\n\t\t\tpopup.close();\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n/*\r\n * @namespace Layer\r\n * @section Popup methods example\r\n *\r\n * All layers share a set of methods convenient for binding popups to it.\r\n *\r\n * ```js\r\n * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\r\n * layer.openPopup();\r\n * layer.closePopup();\r\n * ```\r\n *\r\n * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.\r\n */\r\n\r\n// @section Popup methods\r\nLayer.include({\r\n\r\n\t// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this\r\n\t// Binds a popup to the layer with the passed `content` and sets up the\r\n\t// necessary event listeners. If a `Function` is passed it will receive\r\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\r\n\tbindPopup: function (content, options) {\r\n\t\tthis._popup = this._initOverlay(Popup, this._popup, content, options);\r\n\t\tif (!this._popupHandlersAdded) {\r\n\t\t\tthis.on({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = true;\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method unbindPopup(): this\r\n\t// Removes the popup previously bound with `bindPopup`.\r\n\tunbindPopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis.off({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = false;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method openPopup(latlng?: LatLng): this\r\n\t// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.\r\n\topenPopup: function (latlng) {\r\n\t\tif (this._popup) {\r\n\t\t\tif (!(this instanceof FeatureGroup)) {\r\n\t\t\t\tthis._popup._source = this;\r\n\t\t\t}\r\n\t\t\tif (this._popup._prepareOpen(latlng || this._latlng)) {\r\n\t\t\t\t// open the popup on the map\r\n\t\t\t\tthis._popup.openOn(this._map);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(): this\r\n\t// Closes the popup bound to this layer if it is open.\r\n\tclosePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.close();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method togglePopup(): this\r\n\t// Opens or closes the popup bound to this layer depending on its current state.\r\n\ttogglePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.toggle(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method isPopupOpen(): boolean\r\n\t// Returns `true` if the popup bound to this layer is currently open.\r\n\tisPopupOpen: function () {\r\n\t\treturn (this._popup ? this._popup.isOpen() : false);\r\n\t},\r\n\r\n\t// @method setPopupContent(content: String|HTMLElement|Popup): this\r\n\t// Sets the content of the popup bound to this layer.\r\n\tsetPopupContent: function (content) {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getPopup(): Popup\r\n\t// Returns the popup bound to this layer.\r\n\tgetPopup: function () {\r\n\t\treturn this._popup;\r\n\t},\r\n\r\n\t_openPopup: function (e) {\r\n\t\tif (!this._popup || !this._map) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// prevent map click\r\n\t\tDomEvent.stop(e);\r\n\r\n\t\tvar target = e.layer || e.target;\r\n\t\tif (this._popup._source === target && !(target instanceof Path)) {\r\n\t\t\t// treat it like a marker and figure out\r\n\t\t\t// if we should toggle it open/closed\r\n\t\t\tif (this._map.hasLayer(this._popup)) {\r\n\t\t\t\tthis.closePopup();\r\n\t\t\t} else {\r\n\t\t\t\tthis.openPopup(e.latlng);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._popup._source = target;\r\n\t\tthis.openPopup(e.latlng);\r\n\t},\r\n\r\n\t_movePopup: function (e) {\r\n\t\tthis._popup.setLatLng(e.latlng);\r\n\t},\r\n\r\n\t_onKeyPress: function (e) {\r\n\t\tif (e.originalEvent.keyCode === 13) {\r\n\t\t\tthis._openPopup(e);\r\n\t\t}\r\n\t}\r\n});\r\n","import {DivOverlay} from './DivOverlay';\nimport {toPoint} from '../geometry/Point';\nimport {Map} from '../map/Map';\nimport {Layer} from './Layer';\nimport * as DomUtil from '../dom/DomUtil';\nimport * as DomEvent from '../dom/DomEvent';\nimport * as Util from '../core/Util';\nimport {FeatureGroup} from './FeatureGroup';\n\n/*\n * @class Tooltip\n * @inherits DivOverlay\n * @aka L.Tooltip\n * Used to display small texts on top of map layers.\n *\n * @example\n * If you want to just bind a tooltip to marker:\n *\n * ```js\n * marker.bindTooltip(\"my tooltip text\").openTooltip();\n * ```\n * Path overlays like polylines also have a `bindTooltip` method.\n *\n * A tooltip can be also standalone:\n *\n * ```js\n * var tooltip = L.tooltip()\n * \t.setLatLng(latlng)\n * \t.setContent('Hello world!<br />This is a nice tooltip.')\n * \t.addTo(map);\n * ```\n * or\n * ```js\n * var tooltip = L.tooltip(latlng, {content: 'Hello world!<br />This is a nice tooltip.'})\n * \t.addTo(map);\n * ```\n *\n *\n * Note about tooltip offset. Leaflet takes two options in consideration\n * for computing tooltip offsetting:\n * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.\n * Add a positive x offset to move the tooltip to the right, and a positive y offset to\n * move it to the bottom. Negatives will move to the left and top.\n * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You\n * should adapt this value if you use a custom icon.\n */\n\n\n// @namespace Tooltip\nexport var Tooltip = DivOverlay.extend({\n\n\t// @section\n\t// @aka Tooltip options\n\toptions: {\n\t\t// @option pane: String = 'tooltipPane'\n\t\t// `Map pane` where the tooltip will be added.\n\t\tpane: 'tooltipPane',\n\n\t\t// @option offset: Point = Point(0, 0)\n\t\t// Optional offset of the tooltip position.\n\t\toffset: [0, 0],\n\n\t\t// @option direction: String = 'auto'\n\t\t// Direction where to open the tooltip. Possible values are: `right`, `left`,\n\t\t// `top`, `bottom`, `center`, `auto`.\n\t\t// `auto` will dynamically switch between `right` and `left` according to the tooltip\n\t\t// position on the map.\n\t\tdirection: 'auto',\n\n\t\t// @option permanent: Boolean = false\n\t\t// Whether to open the tooltip permanently or only on mouseover.\n\t\tpermanent: false,\n\n\t\t// @option sticky: Boolean = false\n\t\t// If true, the tooltip will follow the mouse instead of being fixed at the feature center.\n\t\tsticky: false,\n\n\t\t// @option opacity: Number = 0.9\n\t\t// Tooltip container opacity.\n\t\topacity: 0.9\n\t},\n\n\tonAdd: function (map) {\n\t\tDivOverlay.prototype.onAdd.call(this, map);\n\t\tthis.setOpacity(this.options.opacity);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipopen: TooltipEvent\n\t\t// Fired when a tooltip is opened in the map.\n\t\tmap.fire('tooltipopen', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\tthis.addEventParent(this._source);\n\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipopen: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is opened.\n\t\t\tthis._source.fire('tooltipopen', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tonRemove: function (map) {\n\t\tDivOverlay.prototype.onRemove.call(this, map);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipclose: TooltipEvent\n\t\t// Fired when a tooltip in the map is closed.\n\t\tmap.fire('tooltipclose', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\tthis.removeEventParent(this._source);\n\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipclose: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is closed.\n\t\t\tthis._source.fire('tooltipclose', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\n\n\t\tif (!this.options.permanent) {\n\t\t\tevents.preclick = this.close;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t_initLayout: function () {\n\t\tvar prefix = 'leaflet-tooltip',\n\t\t className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\n\n\t\tthis._contentNode = this._container = DomUtil.create('div', className);\n\n\t\tthis._container.setAttribute('role', 'tooltip');\n\t\tthis._container.setAttribute('id', 'leaflet-tooltip-' + Util.stamp(this));\n\t},\n\n\t_updateLayout: function () {},\n\n\t_adjustPan: function () {},\n\n\t_setPosition: function (pos) {\n\t\tvar subX, subY,\n\t\t map = this._map,\n\t\t container = this._container,\n\t\t centerPoint = map.latLngToContainerPoint(map.getCenter()),\n\t\t tooltipPoint = map.layerPointToContainerPoint(pos),\n\t\t direction = this.options.direction,\n\t\t tooltipWidth = container.offsetWidth,\n\t\t tooltipHeight = container.offsetHeight,\n\t\t offset = toPoint(this.options.offset),\n\t\t anchor = this._getAnchor();\n\n\t\tif (direction === 'top') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = tooltipHeight;\n\t\t} else if (direction === 'bottom') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = 0;\n\t\t} else if (direction === 'center') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (direction === 'right') {\n\t\t\tsubX = 0;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (direction === 'left') {\n\t\t\tsubX = tooltipWidth;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (tooltipPoint.x < centerPoint.x) {\n\t\t\tdirection = 'right';\n\t\t\tsubX = 0;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else {\n\t\t\tdirection = 'left';\n\t\t\tsubX = tooltipWidth + (offset.x + anchor.x) * 2;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t}\n\n\t\tpos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);\n\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-right');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-left');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-top');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-bottom');\n\t\tDomUtil.addClass(container, 'leaflet-tooltip-' + direction);\n\t\tDomUtil.setPosition(container, pos);\n\t},\n\n\t_updatePosition: function () {\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._setPosition(pos);\n\t},\n\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\n\t\tif (this._container) {\n\t\t\tDomUtil.setOpacity(this._container, opacity);\n\t\t}\n\t},\n\n\t_animateZoom: function (e) {\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);\n\t\tthis._setPosition(pos);\n\t},\n\n\t_getAnchor: function () {\n\t\t// Where should we anchor the tooltip on the source layer?\n\t\treturn toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);\n\t}\n\n});\n\n// @namespace Tooltip\n// @factory L.tooltip(options?: Tooltip options, source?: Layer)\n// Instantiates a `Tooltip` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.\n// @alternative\n// @factory L.tooltip(latlng: LatLng, options?: Tooltip options)\n// Instantiates a `Tooltip` object given `latlng` where the tooltip will open and an optional `options` object that describes its appearance and location.\nexport var tooltip = function (options, source) {\n\treturn new Tooltip(options, source);\n};\n\n// @namespace Map\n// @section Methods for Layers and Controls\nMap.include({\n\n\t// @method openTooltip(tooltip: Tooltip): this\n\t// Opens the specified tooltip.\n\t// @alternative\n\t// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this\n\t// Creates a tooltip with the specified content and options and open it.\n\topenTooltip: function (tooltip, latlng, options) {\n\t\tthis._initOverlay(Tooltip, tooltip, latlng, options)\n\t\t .openOn(this);\n\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(tooltip: Tooltip): this\n\t// Closes the tooltip given as parameter.\n\tcloseTooltip: function (tooltip) {\n\t\ttooltip.close();\n\t\treturn this;\n\t}\n\n});\n\n/*\n * @namespace Layer\n * @section Tooltip methods example\n *\n * All layers share a set of methods convenient for binding tooltips to it.\n *\n * ```js\n * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);\n * layer.openTooltip();\n * layer.closeTooltip();\n * ```\n */\n\n// @section Tooltip methods\nLayer.include({\n\n\t// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this\n\t// Binds a tooltip to the layer with the passed `content` and sets up the\n\t// necessary event listeners. If a `Function` is passed it will receive\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\n\tbindTooltip: function (content, options) {\n\n\t\tif (this._tooltip && this.isTooltipOpen()) {\n\t\t\tthis.unbindTooltip();\n\t\t}\n\n\t\tthis._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options);\n\t\tthis._initTooltipInteractions();\n\n\t\tif (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {\n\t\t\tthis.openTooltip();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method unbindTooltip(): this\n\t// Removes the tooltip previously bound with `bindTooltip`.\n\tunbindTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._initTooltipInteractions(true);\n\t\t\tthis.closeTooltip();\n\t\t\tthis._tooltip = null;\n\t\t}\n\t\treturn this;\n\t},\n\n\t_initTooltipInteractions: function (remove) {\n\t\tif (!remove && this._tooltipHandlersAdded) { return; }\n\t\tvar onOff = remove ? 'off' : 'on',\n\t\t events = {\n\t\t\tremove: this.closeTooltip,\n\t\t\tmove: this._moveTooltip\n\t\t };\n\t\tif (!this._tooltip.options.permanent) {\n\t\t\tevents.mouseover = this._openTooltip;\n\t\t\tevents.mouseout = this.closeTooltip;\n\t\t\tevents.click = this._openTooltip;\n\t\t\tif (this._map) {\n\t\t\t\tthis._addFocusListeners();\n\t\t\t} else {\n\t\t\t\tevents.add = this._addFocusListeners;\n\t\t\t}\n\t\t} else {\n\t\t\tevents.add = this._openTooltip;\n\t\t}\n\t\tif (this._tooltip.options.sticky) {\n\t\t\tevents.mousemove = this._moveTooltip;\n\t\t}\n\t\tthis[onOff](events);\n\t\tthis._tooltipHandlersAdded = !remove;\n\t},\n\n\t// @method openTooltip(latlng?: LatLng): this\n\t// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.\n\topenTooltip: function (latlng) {\n\t\tif (this._tooltip) {\n\t\t\tif (!(this instanceof FeatureGroup)) {\n\t\t\t\tthis._tooltip._source = this;\n\t\t\t}\n\t\t\tif (this._tooltip._prepareOpen(latlng)) {\n\t\t\t\t// open the tooltip on the map\n\t\t\t\tthis._tooltip.openOn(this._map);\n\n\t\t\t\tif (this.getElement) {\n\t\t\t\t\tthis._setAriaDescribedByOnLayer(this);\n\t\t\t\t} else if (this.eachLayer) {\n\t\t\t\t\tthis.eachLayer(this._setAriaDescribedByOnLayer, this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(): this\n\t// Closes the tooltip bound to this layer if it is open.\n\tcloseTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\treturn this._tooltip.close();\n\t\t}\n\t},\n\n\t// @method toggleTooltip(): this\n\t// Opens or closes the tooltip bound to this layer depending on its current state.\n\ttoggleTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.toggle(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method isTooltipOpen(): boolean\n\t// Returns `true` if the tooltip bound to this layer is currently open.\n\tisTooltipOpen: function () {\n\t\treturn this._tooltip.isOpen();\n\t},\n\n\t// @method setTooltipContent(content: String|HTMLElement|Tooltip): this\n\t// Sets the content of the tooltip bound to this layer.\n\tsetTooltipContent: function (content) {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.setContent(content);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getTooltip(): Tooltip\n\t// Returns the tooltip bound to this layer.\n\tgetTooltip: function () {\n\t\treturn this._tooltip;\n\t},\n\n\t_addFocusListeners: function () {\n\t\tif (this.getElement) {\n\t\t\tthis._addFocusListenersOnLayer(this);\n\t\t} else if (this.eachLayer) {\n\t\t\tthis.eachLayer(this._addFocusListenersOnLayer, this);\n\t\t}\n\t},\n\n\t_addFocusListenersOnLayer: function (layer) {\n\t\tvar el = layer.getElement();\n\t\tif (el) {\n\t\t\tDomEvent.on(el, 'focus', function () {\n\t\t\t\tthis._tooltip._source = layer;\n\t\t\t\tthis.openTooltip();\n\t\t\t}, this);\n\t\t\tDomEvent.on(el, 'blur', this.closeTooltip, this);\n\t\t}\n\t},\n\n\t_setAriaDescribedByOnLayer: function (layer) {\n\t\tvar el = layer.getElement();\n\t\tif (el) {\n\t\t\tel.setAttribute('aria-describedby', this._tooltip._container.id);\n\t\t}\n\t},\n\n\n\t_openTooltip: function (e) {\n\t\tif (!this._tooltip || !this._map || (this._map.dragging && this._map.dragging.moving())) {\n\t\t\treturn;\n\t\t}\n\t\tthis._tooltip._source = e.layer || e.target;\n\n\t\tthis.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined);\n\t},\n\n\t_moveTooltip: function (e) {\n\t\tvar latlng = e.latlng, containerPoint, layerPoint;\n\t\tif (this._tooltip.options.sticky && e.originalEvent) {\n\t\t\tcontainerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);\n\t\t\tlayerPoint = this._map.containerPointToLayerPoint(containerPoint);\n\t\t\tlatlng = this._map.layerPointToLatLng(layerPoint);\n\t\t}\n\t\tthis._tooltip.setLatLng(latlng);\n\t}\n});\n","import {Icon} from './Icon';\nimport {toPoint as point} from '../../geometry/Point';\nimport {empty} from '../../dom/DomUtil';\n\n/*\n * @class DivIcon\n * @aka L.DivIcon\n * @inherits Icon\n *\n * Represents a lightweight icon for markers that uses a simple `<div>`\n * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.\n *\n * @example\n * ```js\n * var myIcon = L.divIcon({className: 'my-div-icon'});\n * // you can set .my-div-icon styles in CSS\n *\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n * ```\n *\n * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.\n */\n\nexport var DivIcon = Icon.extend({\n\toptions: {\n\t\t// @section\n\t\t// @aka DivIcon options\n\t\ticonSize: [12, 12], // also can be set through CSS\n\n\t\t// iconAnchor: (Point),\n\t\t// popupAnchor: (Point),\n\n\t\t// @option html: String|HTMLElement = ''\n\t\t// Custom HTML code to put inside the div element, empty by default. Alternatively,\n\t\t// an instance of `HTMLElement`.\n\t\thtml: false,\n\n\t\t// @option bgPos: Point = [0, 0]\n\t\t// Optional relative position of the background, in pixels\n\t\tbgPos: null,\n\n\t\tclassName: 'leaflet-div-icon'\n\t},\n\n\tcreateIcon: function (oldIcon) {\n\t\tvar div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),\n\t\t options = this.options;\n\n\t\tif (options.html instanceof Element) {\n\t\t\tempty(div);\n\t\t\tdiv.appendChild(options.html);\n\t\t} else {\n\t\t\tdiv.innerHTML = options.html !== false ? options.html : '';\n\t\t}\n\n\t\tif (options.bgPos) {\n\t\t\tvar bgPos = point(options.bgPos);\n\t\t\tdiv.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';\n\t\t}\n\t\tthis._setIconStyles(div, 'icon');\n\n\t\treturn div;\n\t},\n\n\tcreateShadow: function () {\n\t\treturn null;\n\t}\n});\n\n// @factory L.divIcon(options: DivIcon options)\n// Creates a `DivIcon` instance with the given options.\nexport function divIcon(options) {\n\treturn new DivIcon(options);\n}\n","import {Icon} from './Icon';\nexport {icon} from './Icon';\nimport {IconDefault} from './Icon.Default';\nIcon.Default = IconDefault;\nexport {Icon};\n\nexport {DivIcon, divIcon} from './DivIcon';\nexport {Marker, marker} from './Marker';\n","import {Layer} from '../Layer';\nimport Browser from '../../core/Browser';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {Point} from '../../geometry/Point';\nimport {Bounds} from '../../geometry/Bounds';\nimport {LatLngBounds, toLatLngBounds as latLngBounds} from '../../geo/LatLngBounds';\n\n/*\n * @class GridLayer\n * @inherits Layer\n * @aka L.GridLayer\n *\n * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.\n * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.\n *\n *\n * @section Synchronous usage\n * @example\n *\n * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords){\n * // create a <canvas> element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // get a canvas context and draw something on it using coords.x, coords.y and coords.z\n * var ctx = tile.getContext('2d');\n *\n * // return the tile so it can be rendered on screen\n * return tile;\n * }\n * });\n * ```\n *\n * @section Asynchronous usage\n * @example\n *\n * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords, done){\n * var error;\n *\n * // create a <canvas> element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // draw something asynchronously and pass the tile to the done() callback\n * setTimeout(function() {\n * done(error, tile);\n * }, 1000);\n *\n * return tile;\n * }\n * });\n * ```\n *\n * @section\n */\n\n\nexport var GridLayer = Layer.extend({\n\n\t// @section\n\t// @aka GridLayer options\n\toptions: {\n\t\t// @option tileSize: Number|Point = 256\n\t\t// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.\n\t\ttileSize: 256,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Opacity of the tiles. Can be used in the `createTile()` function.\n\t\topacity: 1,\n\n\t\t// @option updateWhenIdle: Boolean = (depends)\n\t\t// Load new tiles only when panning ends.\n\t\t// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.\n\t\t// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the\n\t\t// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.\n\t\tupdateWhenIdle: Browser.mobile,\n\n\t\t// @option updateWhenZooming: Boolean = true\n\t\t// By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.\n\t\tupdateWhenZooming: true,\n\n\t\t// @option updateInterval: Number = 200\n\t\t// Tiles will not update more than once every `updateInterval` milliseconds when panning.\n\t\tupdateInterval: 200,\n\n\t\t// @option zIndex: Number = 1\n\t\t// The explicit zIndex of the tile layer.\n\t\tzIndex: 1,\n\n\t\t// @option bounds: LatLngBounds = undefined\n\t\t// If set, tiles will only be loaded inside the set `LatLngBounds`.\n\t\tbounds: null,\n\n\t\t// @option minZoom: Number = 0\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\n\t\tminZoom: 0,\n\n\t\t// @option maxZoom: Number = undefined\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\n\t\tmaxZoom: undefined,\n\n\t\t// @option maxNativeZoom: Number = undefined\n\t\t// Maximum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded\n\t\t// from `maxNativeZoom` level and auto-scaled.\n\t\tmaxNativeZoom: undefined,\n\n\t\t// @option minNativeZoom: Number = undefined\n\t\t// Minimum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels lower than `minNativeZoom` will be loaded\n\t\t// from `minNativeZoom` level and auto-scaled.\n\t\tminNativeZoom: undefined,\n\n\t\t// @option noWrap: Boolean = false\n\t\t// Whether the layer is wrapped around the antimeridian. If `true`, the\n\t\t// GridLayer will only be displayed once at low zoom levels. Has no\n\t\t// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used\n\t\t// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting\n\t\t// tiles outside the CRS limits.\n\t\tnoWrap: false,\n\n\t\t// @option pane: String = 'tilePane'\n\t\t// `Map pane` where the grid layer will be added.\n\t\tpane: 'tilePane',\n\n\t\t// @option className: String = ''\n\t\t// A custom class name to assign to the tile layer. Empty by default.\n\t\tclassName: '',\n\n\t\t// @option keepBuffer: Number = 2\n\t\t// When panning the map, keep this many rows and columns of tiles before unloading them.\n\t\tkeepBuffer: 2\n\t},\n\n\tinitialize: function (options) {\n\t\tUtil.setOptions(this, options);\n\t},\n\n\tonAdd: function () {\n\t\tthis._initContainer();\n\n\t\tthis._levels = {};\n\t\tthis._tiles = {};\n\n\t\tthis._resetView(); // implicit _update() call\n\t},\n\n\tbeforeAdd: function (map) {\n\t\tmap._addZoomLimit(this);\n\t},\n\n\tonRemove: function (map) {\n\t\tthis._removeAllTiles();\n\t\tDomUtil.remove(this._container);\n\t\tmap._removeZoomLimit(this);\n\t\tthis._container = null;\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t// @method bringToFront: this\n\t// Brings the tile layer to the top of all tile layers.\n\tbringToFront: function () {\n\t\tif (this._map) {\n\t\t\tDomUtil.toFront(this._container);\n\t\t\tthis._setAutoZIndex(Math.max);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack: this\n\t// Brings the tile layer to the bottom of all tile layers.\n\tbringToBack: function () {\n\t\tif (this._map) {\n\t\t\tDomUtil.toBack(this._container);\n\t\t\tthis._setAutoZIndex(Math.min);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getContainer: HTMLElement\n\t// Returns the HTML element that contains the tiles for this layer.\n\tgetContainer: function () {\n\t\treturn this._container;\n\t},\n\n\t// @method setOpacity(opacity: Number): this\n\t// Changes the [opacity](#gridlayer-opacity) of the grid layer.\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\t\tthis._updateOpacity();\n\t\treturn this;\n\t},\n\n\t// @method setZIndex(zIndex: Number): this\n\t// Changes the [zIndex](#gridlayer-zindex) of the grid layer.\n\tsetZIndex: function (zIndex) {\n\t\tthis.options.zIndex = zIndex;\n\t\tthis._updateZIndex();\n\n\t\treturn this;\n\t},\n\n\t// @method isLoading: Boolean\n\t// Returns `true` if any tile in the grid layer has not finished loading.\n\tisLoading: function () {\n\t\treturn this._loading;\n\t},\n\n\t// @method redraw: this\n\t// Causes the layer to clear all the tiles and request them again.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._removeAllTiles();\n\t\t\tvar tileZoom = this._clampZoom(this._map.getZoom());\n\t\t\tif (tileZoom !== this._tileZoom) {\n\t\t\t\tthis._tileZoom = tileZoom;\n\t\t\t\tthis._updateLevels();\n\t\t\t}\n\t\t\tthis._update();\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewprereset: this._invalidateAll,\n\t\t\tviewreset: this._resetView,\n\t\t\tzoom: this._resetView,\n\t\t\tmoveend: this._onMoveEnd\n\t\t};\n\n\t\tif (!this.options.updateWhenIdle) {\n\t\t\t// update tiles on move, but not more often than once per given interval\n\t\t\tif (!this._onMove) {\n\t\t\t\tthis._onMove = Util.throttle(this._onMoveEnd, this.options.updateInterval, this);\n\t\t\t}\n\n\t\t\tevents.move = this._onMove;\n\t\t}\n\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._animateZoom;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t// @section Extension methods\n\t// Layers extending `GridLayer` shall reimplement the following method.\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\n\t// Called only internally, must be overridden by classes extending `GridLayer`.\n\t// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback\n\t// is specified, it must be called when the tile has finished loading and drawing.\n\tcreateTile: function () {\n\t\treturn document.createElement('div');\n\t},\n\n\t// @section\n\t// @method getTileSize: Point\n\t// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.\n\tgetTileSize: function () {\n\t\tvar s = this.options.tileSize;\n\t\treturn s instanceof Point ? s : new Point(s, s);\n\t},\n\n\t_updateZIndex: function () {\n\t\tif (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {\n\t\t\tthis._container.style.zIndex = this.options.zIndex;\n\t\t}\n\t},\n\n\t_setAutoZIndex: function (compare) {\n\t\t// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)\n\n\t\tvar layers = this.getPane().children,\n\t\t edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min\n\n\t\tfor (var i = 0, len = layers.length, zIndex; i < len; i++) {\n\n\t\t\tzIndex = layers[i].style.zIndex;\n\n\t\t\tif (layers[i] !== this._container && zIndex) {\n\t\t\t\tedgeZIndex = compare(edgeZIndex, +zIndex);\n\t\t\t}\n\t\t}\n\n\t\tif (isFinite(edgeZIndex)) {\n\t\t\tthis.options.zIndex = edgeZIndex + compare(-1, 1);\n\t\t\tthis._updateZIndex();\n\t\t}\n\t},\n\n\t_updateOpacity: function () {\n\t\tif (!this._map) { return; }\n\n\t\t// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles\n\t\tif (Browser.ielt9) { return; }\n\n\t\tDomUtil.setOpacity(this._container, this.options.opacity);\n\n\t\tvar now = +new Date(),\n\t\t nextFrame = false,\n\t\t willPrune = false;\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar tile = this._tiles[key];\n\t\t\tif (!tile.current || !tile.loaded) { continue; }\n\n\t\t\tvar fade = Math.min(1, (now - tile.loaded) / 200);\n\n\t\t\tDomUtil.setOpacity(tile.el, fade);\n\t\t\tif (fade < 1) {\n\t\t\t\tnextFrame = true;\n\t\t\t} else {\n\t\t\t\tif (tile.active) {\n\t\t\t\t\twillPrune = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis._onOpaqueTile(tile);\n\t\t\t\t}\n\t\t\t\ttile.active = true;\n\t\t\t}\n\t\t}\n\n\t\tif (willPrune && !this._noPrune) { this._pruneTiles(); }\n\n\t\tif (nextFrame) {\n\t\t\tUtil.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = Util.requestAnimFrame(this._updateOpacity, this);\n\t\t}\n\t},\n\n\t_onOpaqueTile: Util.falseFn,\n\n\t_initContainer: function () {\n\t\tif (this._container) { return; }\n\n\t\tthis._container = DomUtil.create('div', 'leaflet-layer ' + (this.options.className || ''));\n\t\tthis._updateZIndex();\n\n\t\tif (this.options.opacity < 1) {\n\t\t\tthis._updateOpacity();\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t},\n\n\t_updateLevels: function () {\n\n\t\tvar zoom = this._tileZoom,\n\t\t maxZoom = this.options.maxZoom;\n\n\t\tif (zoom === undefined) { return undefined; }\n\n\t\tfor (var z in this._levels) {\n\t\t\tz = Number(z);\n\t\t\tif (this._levels[z].el.children.length || z === zoom) {\n\t\t\t\tthis._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);\n\t\t\t\tthis._onUpdateLevel(z);\n\t\t\t} else {\n\t\t\t\tDomUtil.remove(this._levels[z].el);\n\t\t\t\tthis._removeTilesAtZoom(z);\n\t\t\t\tthis._onRemoveLevel(z);\n\t\t\t\tdelete this._levels[z];\n\t\t\t}\n\t\t}\n\n\t\tvar level = this._levels[zoom],\n\t\t map = this._map;\n\n\t\tif (!level) {\n\t\t\tlevel = this._levels[zoom] = {};\n\n\t\t\tlevel.el = DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);\n\t\t\tlevel.el.style.zIndex = maxZoom;\n\n\t\t\tlevel.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();\n\t\t\tlevel.zoom = zoom;\n\n\t\t\tthis._setZoomTransform(level, map.getCenter(), map.getZoom());\n\n\t\t\t// force the browser to consider the newly added element for transition\n\t\t\tUtil.falseFn(level.el.offsetWidth);\n\n\t\t\tthis._onCreateLevel(level);\n\t\t}\n\n\t\tthis._level = level;\n\n\t\treturn level;\n\t},\n\n\t_onUpdateLevel: Util.falseFn,\n\n\t_onRemoveLevel: Util.falseFn,\n\n\t_onCreateLevel: Util.falseFn,\n\n\t_pruneTiles: function () {\n\t\tif (!this._map) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar key, tile;\n\n\t\tvar zoom = this._map.getZoom();\n\t\tif (zoom > this.options.maxZoom ||\n\t\t\tzoom < this.options.minZoom) {\n\t\t\tthis._removeAllTiles();\n\t\t\treturn;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\ttile.retain = tile.current;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\tif (tile.current && !tile.active) {\n\t\t\t\tvar coords = tile.coords;\n\t\t\t\tif (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {\n\t\t\t\t\tthis._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\tif (!this._tiles[key].retain) {\n\t\t\t\tthis._removeTile(key);\n\t\t\t}\n\t\t}\n\t},\n\n\t_removeTilesAtZoom: function (zoom) {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (this._tiles[key].coords.z !== zoom) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_removeAllTiles: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_invalidateAll: function () {\n\t\tfor (var z in this._levels) {\n\t\t\tDomUtil.remove(this._levels[z].el);\n\t\t\tthis._onRemoveLevel(Number(z));\n\t\t\tdelete this._levels[z];\n\t\t}\n\t\tthis._removeAllTiles();\n\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t_retainParent: function (x, y, z, minZoom) {\n\t\tvar x2 = Math.floor(x / 2),\n\t\t y2 = Math.floor(y / 2),\n\t\t z2 = z - 1,\n\t\t coords2 = new Point(+x2, +y2);\n\t\tcoords2.z = +z2;\n\n\t\tvar key = this._tileCoordsToKey(coords2),\n\t\t tile = this._tiles[key];\n\n\t\tif (tile && tile.active) {\n\t\t\ttile.retain = true;\n\t\t\treturn true;\n\n\t\t} else if (tile && tile.loaded) {\n\t\t\ttile.retain = true;\n\t\t}\n\n\t\tif (z2 > minZoom) {\n\t\t\treturn this._retainParent(x2, y2, z2, minZoom);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_retainChildren: function (x, y, z, maxZoom) {\n\n\t\tfor (var i = 2 * x; i < 2 * x + 2; i++) {\n\t\t\tfor (var j = 2 * y; j < 2 * y + 2; j++) {\n\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = z + 1;\n\n\t\t\t\tvar key = this._tileCoordsToKey(coords),\n\t\t\t\t tile = this._tiles[key];\n\n\t\t\t\tif (tile && tile.active) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t\tcontinue;\n\n\t\t\t\t} else if (tile && tile.loaded) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t}\n\n\t\t\t\tif (z + 1 < maxZoom) {\n\t\t\t\t\tthis._retainChildren(i, j, z + 1, maxZoom);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetView: function (e) {\n\t\tvar animating = e && (e.pinch || e.flyTo);\n\t\tthis._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);\n\t},\n\n\t_animateZoom: function (e) {\n\t\tthis._setView(e.center, e.zoom, true, e.noUpdate);\n\t},\n\n\t_clampZoom: function (zoom) {\n\t\tvar options = this.options;\n\n\t\tif (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {\n\t\t\treturn options.minNativeZoom;\n\t\t}\n\n\t\tif (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {\n\t\t\treturn options.maxNativeZoom;\n\t\t}\n\n\t\treturn zoom;\n\t},\n\n\t_setView: function (center, zoom, noPrune, noUpdate) {\n\t\tvar tileZoom = Math.round(zoom);\n\t\tif ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||\n\t\t (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {\n\t\t\ttileZoom = undefined;\n\t\t} else {\n\t\t\ttileZoom = this._clampZoom(tileZoom);\n\t\t}\n\n\t\tvar tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);\n\n\t\tif (!noUpdate || tileZoomChanged) {\n\n\t\t\tthis._tileZoom = tileZoom;\n\n\t\t\tif (this._abortLoading) {\n\t\t\t\tthis._abortLoading();\n\t\t\t}\n\n\t\t\tthis._updateLevels();\n\t\t\tthis._resetGrid();\n\n\t\t\tif (tileZoom !== undefined) {\n\t\t\t\tthis._update(center);\n\t\t\t}\n\n\t\t\tif (!noPrune) {\n\t\t\t\tthis._pruneTiles();\n\t\t\t}\n\n\t\t\t// Flag to prevent _updateOpacity from pruning tiles during\n\t\t\t// a zoom anim or a pinch gesture\n\t\t\tthis._noPrune = !!noPrune;\n\t\t}\n\n\t\tthis._setZoomTransforms(center, zoom);\n\t},\n\n\t_setZoomTransforms: function (center, zoom) {\n\t\tfor (var i in this._levels) {\n\t\t\tthis._setZoomTransform(this._levels[i], center, zoom);\n\t\t}\n\t},\n\n\t_setZoomTransform: function (level, center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, level.zoom),\n\t\t translate = level.origin.multiplyBy(scale)\n\t\t .subtract(this._map._getNewPixelOrigin(center, zoom)).round();\n\n\t\tif (Browser.any3d) {\n\t\t\tDomUtil.setTransform(level.el, translate, scale);\n\t\t} else {\n\t\t\tDomUtil.setPosition(level.el, translate);\n\t\t}\n\t},\n\n\t_resetGrid: function () {\n\t\tvar map = this._map,\n\t\t crs = map.options.crs,\n\t\t tileSize = this._tileSize = this.getTileSize(),\n\t\t tileZoom = this._tileZoom;\n\n\t\tvar bounds = this._map.getPixelWorldBounds(this._tileZoom);\n\t\tif (bounds) {\n\t\t\tthis._globalTileRange = this._pxBoundsToTileRange(bounds);\n\t\t}\n\n\t\tthis._wrapX = crs.wrapLng && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),\n\t\t\tMath.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)\n\t\t];\n\t\tthis._wrapY = crs.wrapLat && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),\n\t\t\tMath.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)\n\t\t];\n\t},\n\n\t_onMoveEnd: function () {\n\t\tif (!this._map || this._map._animatingZoom) { return; }\n\n\t\tthis._update();\n\t},\n\n\t_getTiledPixelBounds: function (center) {\n\t\tvar map = this._map,\n\t\t mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),\n\t\t scale = map.getZoomScale(mapZoom, this._tileZoom),\n\t\t pixelCenter = map.project(center, this._tileZoom).floor(),\n\t\t halfSize = map.getSize().divideBy(scale * 2);\n\n\t\treturn new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));\n\t},\n\n\t// Private method to load tiles in the grid's active zoom level according to map bounds\n\t_update: function (center) {\n\t\tvar map = this._map;\n\t\tif (!map) { return; }\n\t\tvar zoom = this._clampZoom(map.getZoom());\n\n\t\tif (center === undefined) { center = map.getCenter(); }\n\t\tif (this._tileZoom === undefined) { return; }\t// if out of minzoom/maxzoom\n\n\t\tvar pixelBounds = this._getTiledPixelBounds(center),\n\t\t tileRange = this._pxBoundsToTileRange(pixelBounds),\n\t\t tileCenter = tileRange.getCenter(),\n\t\t queue = [],\n\t\t margin = this.options.keepBuffer,\n\t\t noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),\n\t\t tileRange.getTopRight().add([margin, -margin]));\n\n\t\t// Sanity check: panic if the tile range contains Infinity somewhere.\n\t\tif (!(isFinite(tileRange.min.x) &&\n\t\t isFinite(tileRange.min.y) &&\n\t\t isFinite(tileRange.max.x) &&\n\t\t isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar c = this._tiles[key].coords;\n\t\t\tif (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {\n\t\t\t\tthis._tiles[key].current = false;\n\t\t\t}\n\t\t}\n\n\t\t// _update just loads more tiles. If the tile zoom level differs too much\n\t\t// from the map's, let _setView reset levels and prune old tiles.\n\t\tif (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }\n\n\t\t// create a queue of coordinates to load tiles from\n\t\tfor (var j = tileRange.min.y; j <= tileRange.max.y; j++) {\n\t\t\tfor (var i = tileRange.min.x; i <= tileRange.max.x; i++) {\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = this._tileZoom;\n\n\t\t\t\tif (!this._isValidTile(coords)) { continue; }\n\n\t\t\t\tvar tile = this._tiles[this._tileCoordsToKey(coords)];\n\t\t\t\tif (tile) {\n\t\t\t\t\ttile.current = true;\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push(coords);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sort tile queue to load tiles in order of their distance to center\n\t\tqueue.sort(function (a, b) {\n\t\t\treturn a.distanceTo(tileCenter) - b.distanceTo(tileCenter);\n\t\t});\n\n\t\tif (queue.length !== 0) {\n\t\t\t// if it's the first batch of tiles to load\n\t\t\tif (!this._loading) {\n\t\t\t\tthis._loading = true;\n\t\t\t\t// @event loading: Event\n\t\t\t\t// Fired when the grid layer starts loading tiles.\n\t\t\t\tthis.fire('loading');\n\t\t\t}\n\n\t\t\t// create DOM fragment to append tiles in one batch\n\t\t\tvar fragment = document.createDocumentFragment();\n\n\t\t\tfor (i = 0; i < queue.length; i++) {\n\t\t\t\tthis._addTile(queue[i], fragment);\n\t\t\t}\n\n\t\t\tthis._level.el.appendChild(fragment);\n\t\t}\n\t},\n\n\t_isValidTile: function (coords) {\n\t\tvar crs = this._map.options.crs;\n\n\t\tif (!crs.infinite) {\n\t\t\t// don't load tile if it's out of bounds and not wrapped\n\t\t\tvar bounds = this._globalTileRange;\n\t\t\tif ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||\n\t\t\t (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }\n\t\t}\n\n\t\tif (!this.options.bounds) { return true; }\n\n\t\t// don't load tile if it doesn't intersect the bounds in options\n\t\tvar tileBounds = this._tileCoordsToBounds(coords);\n\t\treturn latLngBounds(this.options.bounds).overlaps(tileBounds);\n\t},\n\n\t_keyToBounds: function (key) {\n\t\treturn this._tileCoordsToBounds(this._keyToTileCoords(key));\n\t},\n\n\t_tileCoordsToNwSe: function (coords) {\n\t\tvar map = this._map,\n\t\t tileSize = this.getTileSize(),\n\t\t nwPoint = coords.scaleBy(tileSize),\n\t\t sePoint = nwPoint.add(tileSize),\n\t\t nw = map.unproject(nwPoint, coords.z),\n\t\t se = map.unproject(sePoint, coords.z);\n\t\treturn [nw, se];\n\t},\n\n\t// converts tile coordinates to its geographical bounds\n\t_tileCoordsToBounds: function (coords) {\n\t\tvar bp = this._tileCoordsToNwSe(coords),\n\t\t bounds = new LatLngBounds(bp[0], bp[1]);\n\n\t\tif (!this.options.noWrap) {\n\t\t\tbounds = this._map.wrapLatLngBounds(bounds);\n\t\t}\n\t\treturn bounds;\n\t},\n\t// converts tile coordinates to key for the tile cache\n\t_tileCoordsToKey: function (coords) {\n\t\treturn coords.x + ':' + coords.y + ':' + coords.z;\n\t},\n\n\t// converts tile cache key to coordinates\n\t_keyToTileCoords: function (key) {\n\t\tvar k = key.split(':'),\n\t\t coords = new Point(+k[0], +k[1]);\n\t\tcoords.z = +k[2];\n\t\treturn coords;\n\t},\n\n\t_removeTile: function (key) {\n\t\tvar tile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\tDomUtil.remove(tile.el);\n\n\t\tdelete this._tiles[key];\n\n\t\t// @event tileunload: TileEvent\n\t\t// Fired when a tile is removed (e.g. when a tile goes off the screen).\n\t\tthis.fire('tileunload', {\n\t\t\ttile: tile.el,\n\t\t\tcoords: this._keyToTileCoords(key)\n\t\t});\n\t},\n\n\t_initTile: function (tile) {\n\t\tDomUtil.addClass(tile, 'leaflet-tile');\n\n\t\tvar tileSize = this.getTileSize();\n\t\ttile.style.width = tileSize.x + 'px';\n\t\ttile.style.height = tileSize.y + 'px';\n\n\t\ttile.onselectstart = Util.falseFn;\n\t\ttile.onmousemove = Util.falseFn;\n\n\t\t// update opacity on tiles in IE7-8 because of filter inheritance problems\n\t\tif (Browser.ielt9 && this.options.opacity < 1) {\n\t\t\tDomUtil.setOpacity(tile, this.options.opacity);\n\t\t}\n\t},\n\n\t_addTile: function (coords, container) {\n\t\tvar tilePos = this._getTilePos(coords),\n\t\t key = this._tileCoordsToKey(coords);\n\n\t\tvar tile = this.createTile(this._wrapCoords(coords), Util.bind(this._tileReady, this, coords));\n\n\t\tthis._initTile(tile);\n\n\t\t// if createTile is defined with a second argument (\"done\" callback),\n\t\t// we know that tile is async and will be ready later; otherwise\n\t\tif (this.createTile.length < 2) {\n\t\t\t// mark tile as ready, but delay one frame for opacity animation to happen\n\t\t\tUtil.requestAnimFrame(Util.bind(this._tileReady, this, coords, null, tile));\n\t\t}\n\n\t\tDomUtil.setPosition(tile, tilePos);\n\n\t\t// save tile in cache\n\t\tthis._tiles[key] = {\n\t\t\tel: tile,\n\t\t\tcoords: coords,\n\t\t\tcurrent: true\n\t\t};\n\n\t\tcontainer.appendChild(tile);\n\t\t// @event tileloadstart: TileEvent\n\t\t// Fired when a tile is requested and starts loading.\n\t\tthis.fire('tileloadstart', {\n\t\t\ttile: tile,\n\t\t\tcoords: coords\n\t\t});\n\t},\n\n\t_tileReady: function (coords, err, tile) {\n\t\tif (err) {\n\t\t\t// @event tileerror: TileErrorEvent\n\t\t\t// Fired when there is an error loading a tile.\n\t\t\tthis.fire('tileerror', {\n\t\t\t\terror: err,\n\t\t\t\ttile: tile,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tvar key = this._tileCoordsToKey(coords);\n\n\t\ttile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\ttile.loaded = +new Date();\n\t\tif (this._map._fadeAnimated) {\n\t\t\tDomUtil.setOpacity(tile.el, 0);\n\t\t\tUtil.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = Util.requestAnimFrame(this._updateOpacity, this);\n\t\t} else {\n\t\t\ttile.active = true;\n\t\t\tthis._pruneTiles();\n\t\t}\n\n\t\tif (!err) {\n\t\t\tDomUtil.addClass(tile.el, 'leaflet-tile-loaded');\n\n\t\t\t// @event tileload: TileEvent\n\t\t\t// Fired when a tile loads.\n\t\t\tthis.fire('tileload', {\n\t\t\t\ttile: tile.el,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tif (this._noTilesToLoad()) {\n\t\t\tthis._loading = false;\n\t\t\t// @event load: Event\n\t\t\t// Fired when the grid layer loaded all visible tiles.\n\t\t\tthis.fire('load');\n\n\t\t\tif (Browser.ielt9 || !this._map._fadeAnimated) {\n\t\t\t\tUtil.requestAnimFrame(this._pruneTiles, this);\n\t\t\t} else {\n\t\t\t\t// Wait a bit more than 0.2 secs (the duration of the tile fade-in)\n\t\t\t\t// to trigger a pruning.\n\t\t\t\tsetTimeout(Util.bind(this._pruneTiles, this), 250);\n\t\t\t}\n\t\t}\n\t},\n\n\t_getTilePos: function (coords) {\n\t\treturn coords.scaleBy(this.getTileSize()).subtract(this._level.origin);\n\t},\n\n\t_wrapCoords: function (coords) {\n\t\tvar newCoords = new Point(\n\t\t\tthis._wrapX ? Util.wrapNum(coords.x, this._wrapX) : coords.x,\n\t\t\tthis._wrapY ? Util.wrapNum(coords.y, this._wrapY) : coords.y);\n\t\tnewCoords.z = coords.z;\n\t\treturn newCoords;\n\t},\n\n\t_pxBoundsToTileRange: function (bounds) {\n\t\tvar tileSize = this.getTileSize();\n\t\treturn new Bounds(\n\t\t\tbounds.min.unscaleBy(tileSize).floor(),\n\t\t\tbounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));\n\t},\n\n\t_noTilesToLoad: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (!this._tiles[key].loaded) { return false; }\n\t\t}\n\t\treturn true;\n\t}\n});\n\n// @factory L.gridLayer(options?: GridLayer options)\n// Creates a new instance of GridLayer with the supplied options.\nexport function gridLayer(options) {\n\treturn new GridLayer(options);\n}\n","import {GridLayer} from './GridLayer';\r\nimport Browser from '../../core/Browser';\r\nimport * as Util from '../../core/Util';\r\nimport * as DomEvent from '../../dom/DomEvent';\r\nimport * as DomUtil from '../../dom/DomUtil';\r\n\r\n\r\n/*\r\n * @class TileLayer\r\n * @inherits GridLayer\r\n * @aka L.TileLayer\r\n * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors'}).addTo(map);\n * ```\r\n *\r\n * @section URL template\r\n * @example\r\n *\r\n * A string of the following form:\r\n *\r\n * ```\r\n * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\r\n * ```\r\n *\r\n * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add \"&commat;2x\" to the URL to load retina tiles.\r\n *\r\n * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:\r\n *\r\n * ```\r\n * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\r\n * ```\r\n */\r\n\r\n\r\nexport var TileLayer = GridLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer options\r\n\toptions: {\r\n\t\t// @option minZoom: Number = 0\r\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\r\n\t\tminZoom: 0,\r\n\r\n\t\t// @option maxZoom: Number = 18\r\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\r\n\t\tmaxZoom: 18,\r\n\r\n\t\t// @option subdomains: String|String[] = 'abc'\r\n\t\t// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.\r\n\t\tsubdomains: 'abc',\r\n\r\n\t\t// @option errorTileUrl: String = ''\r\n\t\t// URL to the tile image to show in place of the tile that failed to load.\r\n\t\terrorTileUrl: '',\r\n\r\n\t\t// @option zoomOffset: Number = 0\r\n\t\t// The zoom number used in tile URLs will be offset with this value.\r\n\t\tzoomOffset: 0,\r\n\r\n\t\t// @option tms: Boolean = false\r\n\t\t// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).\r\n\t\ttms: false,\r\n\r\n\t\t// @option zoomReverse: Boolean = false\r\n\t\t// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)\r\n\t\tzoomReverse: false,\r\n\r\n\t\t// @option detectRetina: Boolean = false\r\n\t\t// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.\r\n\t\tdetectRetina: false,\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false,\r\n\r\n\t\t// @option referrerPolicy: Boolean|String = false\r\n\t\t// Whether the referrerPolicy attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.\r\n\t\t// This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer\r\n\t\t// (e.g. to validate an API token).\r\n\t\t// Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.\r\n\t\treferrerPolicy: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\toptions = Util.setOptions(this, options);\r\n\r\n\t\t// detecting retina displays, adjusting tileSize and zoom levels\r\n\t\tif (options.detectRetina && Browser.retina && options.maxZoom > 0) {\r\n\r\n\t\t\toptions.tileSize = Math.floor(options.tileSize / 2);\r\n\r\n\t\t\tif (!options.zoomReverse) {\r\n\t\t\t\toptions.zoomOffset++;\r\n\t\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);\r\n\t\t\t} else {\r\n\t\t\t\toptions.zoomOffset--;\r\n\t\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom + 1);\r\n\t\t\t}\r\n\r\n\t\t\toptions.minZoom = Math.max(0, options.minZoom);\r\n\t\t} else if (!options.zoomReverse) {\r\n\t\t\t// make sure maxZoom is gte minZoom\r\n\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom);\r\n\t\t} else {\r\n\t\t\t// make sure minZoom is lte maxZoom\r\n\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom);\r\n\t\t}\r\n\r\n\t\tif (typeof options.subdomains === 'string') {\r\n\t\t\toptions.subdomains = options.subdomains.split('');\r\n\t\t}\r\n\r\n\t\tthis.on('tileunload', this._onTileRemove);\r\n\t},\r\n\r\n\t// @method setUrl(url: String, noRedraw?: Boolean): this\r\n\t// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).\r\n\t// If the URL does not change, the layer will not be redrawn unless\r\n\t// the noRedraw parameter is set to false.\r\n\tsetUrl: function (url, noRedraw) {\r\n\t\tif (this._url === url && noRedraw === undefined) {\r\n\t\t\tnoRedraw = true;\r\n\t\t}\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\r\n\t// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)\r\n\t// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`\r\n\t// callback is called when the tile has been loaded.\r\n\tcreateTile: function (coords, done) {\r\n\t\tvar tile = document.createElement('img');\r\n\r\n\t\tDomEvent.on(tile, 'load', Util.bind(this._tileOnLoad, this, done, tile));\r\n\t\tDomEvent.on(tile, 'error', Util.bind(this._tileOnError, this, done, tile));\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\ttile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\t// for this new option we follow the documented behavior\r\n\t\t// more closely by only setting the property when string\r\n\t\tif (typeof this.options.referrerPolicy === 'string') {\r\n\t\t\ttile.referrerPolicy = this.options.referrerPolicy;\r\n\t\t}\r\n\r\n\t\t// The alt attribute is set to the empty string,\r\n\t\t// allowing screen readers to ignore the decorative image tiles.\r\n\t\t// https://www.w3.org/WAI/tutorials/images/decorative/\r\n\t\t// https://www.w3.org/TR/html-aria/#el-img-empty-alt\r\n\t\ttile.alt = '';\r\n\r\n\t\ttile.src = this.getTileUrl(coords);\r\n\r\n\t\treturn tile;\r\n\t},\r\n\r\n\t// @section Extension methods\r\n\t// @uninheritable\r\n\t// Layers extending `TileLayer` might reimplement the following method.\r\n\t// @method getTileUrl(coords: Object): String\r\n\t// Called only internally, returns the URL for a tile given its coordinates.\r\n\t// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.\r\n\tgetTileUrl: function (coords) {\r\n\t\tvar data = {\r\n\t\t\tr: Browser.retina ? '@2x' : '',\r\n\t\t\ts: this._getSubdomain(coords),\r\n\t\t\tx: coords.x,\r\n\t\t\ty: coords.y,\r\n\t\t\tz: this._getZoomForUrl()\r\n\t\t};\r\n\t\tif (this._map && !this._map.options.crs.infinite) {\r\n\t\t\tvar invertedY = this._globalTileRange.max.y - coords.y;\r\n\t\t\tif (this.options.tms) {\r\n\t\t\t\tdata['y'] = invertedY;\r\n\t\t\t}\r\n\t\t\tdata['-y'] = invertedY;\r\n\t\t}\r\n\r\n\t\treturn Util.template(this._url, Util.extend(data, this.options));\r\n\t},\r\n\r\n\t_tileOnLoad: function (done, tile) {\r\n\t\t// For https://github.com/Leaflet/Leaflet/issues/3332\r\n\t\tif (Browser.ielt9) {\r\n\t\t\tsetTimeout(Util.bind(done, this, null, tile), 0);\r\n\t\t} else {\r\n\t\t\tdone(null, tile);\r\n\t\t}\r\n\t},\r\n\r\n\t_tileOnError: function (done, tile, e) {\r\n\t\tvar errorUrl = this.options.errorTileUrl;\r\n\t\tif (errorUrl && tile.getAttribute('src') !== errorUrl) {\r\n\t\t\ttile.src = errorUrl;\r\n\t\t}\r\n\t\tdone(e, tile);\r\n\t},\r\n\r\n\t_onTileRemove: function (e) {\r\n\t\te.tile.onload = null;\r\n\t},\r\n\r\n\t_getZoomForUrl: function () {\r\n\t\tvar zoom = this._tileZoom,\r\n\t\tmaxZoom = this.options.maxZoom,\r\n\t\tzoomReverse = this.options.zoomReverse,\r\n\t\tzoomOffset = this.options.zoomOffset;\r\n\r\n\t\tif (zoomReverse) {\r\n\t\t\tzoom = maxZoom - zoom;\r\n\t\t}\r\n\r\n\t\treturn zoom + zoomOffset;\r\n\t},\r\n\r\n\t_getSubdomain: function (tilePoint) {\r\n\t\tvar index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;\r\n\t\treturn this.options.subdomains[index];\r\n\t},\r\n\r\n\t// stops loading all tiles in the background layer\r\n\t_abortLoading: function () {\r\n\t\tvar i, tile;\r\n\t\tfor (i in this._tiles) {\r\n\t\t\tif (this._tiles[i].coords.z !== this._tileZoom) {\r\n\t\t\t\ttile = this._tiles[i].el;\r\n\r\n\t\t\t\ttile.onload = Util.falseFn;\r\n\t\t\t\ttile.onerror = Util.falseFn;\r\n\r\n\t\t\t\tif (!tile.complete) {\r\n\t\t\t\t\ttile.src = Util.emptyImageUrl;\r\n\t\t\t\t\tvar coords = this._tiles[i].coords;\r\n\t\t\t\t\tDomUtil.remove(tile);\r\n\t\t\t\t\tdelete this._tiles[i];\r\n\t\t\t\t\t// @event tileabort: TileEvent\r\n\t\t\t\t\t// Fired when a tile was loading but is now not wanted.\r\n\t\t\t\t\tthis.fire('tileabort', {\r\n\t\t\t\t\t\ttile: tile,\r\n\t\t\t\t\t\tcoords: coords\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_removeTile: function (key) {\r\n\t\tvar tile = this._tiles[key];\r\n\t\tif (!tile) { return; }\r\n\r\n\t\t// Cancels any pending http requests associated with the tile\r\n\t\ttile.el.setAttribute('src', Util.emptyImageUrl);\r\n\r\n\t\treturn GridLayer.prototype._removeTile.call(this, key);\r\n\t},\r\n\r\n\t_tileReady: function (coords, err, tile) {\r\n\t\tif (!this._map || (tile && tile.getAttribute('src') === Util.emptyImageUrl)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\treturn GridLayer.prototype._tileReady.call(this, coords, err, tile);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)\r\n// Instantiates a tile layer object given a `URL template` and optionally an options object.\r\n\r\nexport function tileLayer(url, options) {\r\n\treturn new TileLayer(url, options);\r\n}\r\n","import {TileLayer} from './TileLayer';\r\nimport {extend, setOptions, getParamString} from '../../core/Util';\r\nimport Browser from '../../core/Browser';\r\nimport {EPSG4326} from '../../geo/crs/CRS.EPSG4326';\r\nimport {toBounds} from '../../geometry/Bounds';\r\n\r\n/*\r\n * @class TileLayer.WMS\r\n * @inherits TileLayer\r\n * @aka L.TileLayer.WMS\r\n * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var nexrad = L.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\r\n * \tlayers: 'nexrad-n0r-900913',\r\n * \tformat: 'image/png',\r\n * \ttransparent: true,\r\n * \tattribution: \"Weather data © 2012 IEM Nexrad\"\r\n * });\r\n * ```\r\n */\r\n\r\nexport var TileLayerWMS = TileLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer.WMS options\r\n\t// If any custom options not documented here are used, they will be sent to the\r\n\t// WMS server as extra parameters in each request URL. This can be useful for\r\n\t// [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html).\r\n\tdefaultWmsParams: {\r\n\t\tservice: 'WMS',\r\n\t\trequest: 'GetMap',\r\n\r\n\t\t// @option layers: String = ''\r\n\t\t// **(required)** Comma-separated list of WMS layers to show.\r\n\t\tlayers: '',\r\n\r\n\t\t// @option styles: String = ''\r\n\t\t// Comma-separated list of WMS styles.\r\n\t\tstyles: '',\r\n\r\n\t\t// @option format: String = 'image/jpeg'\r\n\t\t// WMS image format (use `'image/png'` for layers with transparency).\r\n\t\tformat: 'image/jpeg',\r\n\r\n\t\t// @option transparent: Boolean = false\r\n\t\t// If `true`, the WMS service will return images with transparency.\r\n\t\ttransparent: false,\r\n\r\n\t\t// @option version: String = '1.1.1'\r\n\t\t// Version of the WMS service to use\r\n\t\tversion: '1.1.1'\r\n\t},\r\n\r\n\toptions: {\r\n\t\t// @option crs: CRS = null\r\n\t\t// Coordinate Reference System to use for the WMS requests, defaults to\r\n\t\t// map CRS. Don't change this if you're not sure what it means.\r\n\t\tcrs: null,\r\n\r\n\t\t// @option uppercase: Boolean = false\r\n\t\t// If `true`, WMS request parameter keys will be uppercase.\r\n\t\tuppercase: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tvar wmsParams = extend({}, this.defaultWmsParams);\r\n\r\n\t\t// all keys that are not TileLayer options go to WMS params\r\n\t\tfor (var i in options) {\r\n\t\t\tif (!(i in this.options)) {\r\n\t\t\t\twmsParams[i] = options[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions = setOptions(this, options);\r\n\r\n\t\tvar realRetina = options.detectRetina && Browser.retina ? 2 : 1;\r\n\t\tvar tileSize = this.getTileSize();\r\n\t\twmsParams.width = tileSize.x * realRetina;\r\n\t\twmsParams.height = tileSize.y * realRetina;\r\n\r\n\t\tthis.wmsParams = wmsParams;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\r\n\t\tthis._crs = this.options.crs || map.options.crs;\r\n\t\tthis._wmsVersion = parseFloat(this.wmsParams.version);\r\n\r\n\t\tvar projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';\r\n\t\tthis.wmsParams[projectionKey] = this._crs.code;\r\n\r\n\t\tTileLayer.prototype.onAdd.call(this, map);\r\n\t},\r\n\r\n\tgetTileUrl: function (coords) {\r\n\r\n\t\tvar tileBounds = this._tileCoordsToNwSe(coords),\r\n\t\t crs = this._crs,\r\n\t\t bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),\r\n\t\t min = bounds.min,\r\n\t\t max = bounds.max,\r\n\t\t bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?\r\n\t\t [min.y, min.x, max.y, max.x] :\r\n\t\t [min.x, min.y, max.x, max.y]).join(','),\r\n\t\t url = TileLayer.prototype.getTileUrl.call(this, coords);\r\n\t\treturn url +\r\n\t\t\tgetParamString(this.wmsParams, url, this.options.uppercase) +\r\n\t\t\t(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;\r\n\t},\r\n\r\n\t// @method setParams(params: Object, noRedraw?: Boolean): this\r\n\t// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).\r\n\tsetParams: function (params, noRedraw) {\r\n\r\n\t\textend(this.wmsParams, params);\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)\r\n// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.\r\nexport function tileLayerWMS(url, options) {\r\n\treturn new TileLayerWMS(url, options);\r\n}\r\n","export {GridLayer, gridLayer} from './GridLayer';\nimport {TileLayer, tileLayer} from './TileLayer';\nimport {TileLayerWMS, tileLayerWMS} from './TileLayer.WMS';\nTileLayer.WMS = TileLayerWMS;\ntileLayer.wms = tileLayerWMS;\nexport {TileLayer, tileLayer};\n","import {Layer} from '../Layer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as Util from '../../core/Util';\nimport Browser from '../../core/Browser';\nimport {Bounds} from '../../geometry/Bounds';\n\n\n\n/*\n * @class Renderer\n * @inherits Layer\n * @aka L.Renderer\n *\n * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the\n * DOM container of the renderer, its bounds, and its zoom animation.\n *\n * A `Renderer` works as an implicit layer group for all `Path`s - the renderer\n * itself can be added or removed to the map. All paths use a renderer, which can\n * be implicit (the map will decide the type of renderer and use it automatically)\n * or explicit (using the [`renderer`](#path-renderer) option of the path).\n *\n * Do not use this class directly, use `SVG` and `Canvas` instead.\n *\n * @event update: Event\n * Fired when the renderer updates its bounds, center and zoom, for example when\n * its map has moved\n */\n\nexport var Renderer = Layer.extend({\n\n\t// @section\n\t// @aka Renderer options\n\toptions: {\n\t\t// @option padding: Number = 0.1\n\t\t// How much to extend the clip area around the map view (relative to its size)\n\t\t// e.g. 0.1 would be 10% of map view in each direction\n\t\tpadding: 0.1\n\t},\n\n\tinitialize: function (options) {\n\t\tUtil.setOptions(this, options);\n\t\tUtil.stamp(this);\n\t\tthis._layers = this._layers || {};\n\t},\n\n\tonAdd: function () {\n\t\tif (!this._container) {\n\t\t\tthis._initContainer(); // defined by renderer implementations\n\n\t\t\tif (this._zoomAnimated) {\n\t\t\t\tDomUtil.addClass(this._container, 'leaflet-zoom-animated');\n\t\t\t}\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t\tthis._update();\n\t\tthis.on('update', this._updatePaths, this);\n\t},\n\n\tonRemove: function () {\n\t\tthis.off('update', this._updatePaths, this);\n\t\tthis._destroyContainer();\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewreset: this._reset,\n\t\t\tzoom: this._onZoom,\n\t\t\tmoveend: this._update,\n\t\t\tzoomend: this._onZoomEnd\n\t\t};\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._onAnimZoom;\n\t\t}\n\t\treturn events;\n\t},\n\n\t_onAnimZoom: function (ev) {\n\t\tthis._updateTransform(ev.center, ev.zoom);\n\t},\n\n\t_onZoom: function () {\n\t\tthis._updateTransform(this._map.getCenter(), this._map.getZoom());\n\t},\n\n\t_updateTransform: function (center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, this._zoom),\n\t\t viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),\n\t\t currentCenterPoint = this._map.project(this._center, zoom),\n\n\t\t topLeftOffset = viewHalf.multiplyBy(-scale).add(currentCenterPoint)\n\t\t\t\t .subtract(this._map._getNewPixelOrigin(center, zoom));\n\n\t\tif (Browser.any3d) {\n\t\t\tDomUtil.setTransform(this._container, topLeftOffset, scale);\n\t\t} else {\n\t\t\tDomUtil.setPosition(this._container, topLeftOffset);\n\t\t}\n\t},\n\n\t_reset: function () {\n\t\tthis._update();\n\t\tthis._updateTransform(this._center, this._zoom);\n\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._reset();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._project();\n\t\t}\n\t},\n\n\t_updatePaths: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._update();\n\t\t}\n\t},\n\n\t_update: function () {\n\t\t// Update pixel bounds of renderer container (for positioning/sizing/clipping later)\n\t\t// Subclasses are responsible of firing the 'update' event.\n\t\tvar p = this.options.padding,\n\t\t size = this._map.getSize(),\n\t\t min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();\n\n\t\tthis._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());\n\n\t\tthis._center = this._map.getCenter();\n\t\tthis._zoom = this._map.getZoom();\n\t}\n});\n","import {Renderer} from './Renderer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport Browser from '../../core/Browser';\nimport * as Util from '../../core/Util';\nimport {Bounds} from '../../geometry/Bounds';\n\n/*\n * @class Canvas\n * @inherits Renderer\n * @aka L.Canvas\n *\n * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](https://caniuse.com/canvas), Canvas is not\n * available in all web browsers, notably IE8, and overlapping geometries might\n * not display properly in some edge cases.\n *\n * @example\n *\n * Use Canvas by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.canvas()\n * });\n * ```\n *\n * Use a Canvas renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.canvas({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nexport var Canvas = Renderer.extend({\n\n\t// @section\n\t// @aka Canvas options\n\toptions: {\n\t\t// @option tolerance: Number = 0\n\t\t// How much to extend the click tolerance around a path/object on the map.\n\t\ttolerance: 0\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = Renderer.prototype.getEvents.call(this);\n\t\tevents.viewprereset = this._onViewPreReset;\n\t\treturn events;\n\t},\n\n\t_onViewPreReset: function () {\n\t\t// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once\n\t\tthis._postponeUpdatePaths = true;\n\t},\n\n\tonAdd: function () {\n\t\tRenderer.prototype.onAdd.call(this);\n\n\t\t// Redraw vectors since canvas is cleared upon removal,\n\t\t// in case of removing the renderer itself from the map.\n\t\tthis._draw();\n\t},\n\n\t_initContainer: function () {\n\t\tvar container = this._container = document.createElement('canvas');\n\n\t\tDomEvent.on(container, 'mousemove', this._onMouseMove, this);\n\t\tDomEvent.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);\n\t\tDomEvent.on(container, 'mouseout', this._handleMouseOut, this);\n\t\tcontainer['_leaflet_disable_events'] = true;\n\n\t\tthis._ctx = container.getContext('2d');\n\t},\n\n\t_destroyContainer: function () {\n\t\tUtil.cancelAnimFrame(this._redrawRequest);\n\t\tdelete this._ctx;\n\t\tDomUtil.remove(this._container);\n\t\tDomEvent.off(this._container);\n\t\tdelete this._container;\n\t},\n\n\t_updatePaths: function () {\n\t\tif (this._postponeUpdatePaths) { return; }\n\n\t\tvar layer;\n\t\tthis._redrawBounds = null;\n\t\tfor (var id in this._layers) {\n\t\t\tlayer = this._layers[id];\n\t\t\tlayer._update();\n\t\t}\n\t\tthis._redraw();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t container = this._container,\n\t\t size = b.getSize(),\n\t\t m = Browser.retina ? 2 : 1;\n\n\t\tDomUtil.setPosition(container, b.min);\n\n\t\t// set canvas size (also clearing it); use double size on retina\n\t\tcontainer.width = m * size.x;\n\t\tcontainer.height = m * size.y;\n\t\tcontainer.style.width = size.x + 'px';\n\t\tcontainer.style.height = size.y + 'px';\n\n\t\tif (Browser.retina) {\n\t\t\tthis._ctx.scale(2, 2);\n\t\t}\n\n\t\t// translate so we use the same path coordinates after canvas element moves\n\t\tthis._ctx.translate(-b.min.x, -b.min.y);\n\n\t\t// Tell paths to redraw themselves\n\t\tthis.fire('update');\n\t},\n\n\t_reset: function () {\n\t\tRenderer.prototype._reset.call(this);\n\n\t\tif (this._postponeUpdatePaths) {\n\t\t\tthis._postponeUpdatePaths = false;\n\t\t\tthis._updatePaths();\n\t\t}\n\t},\n\n\t_initPath: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._layers[Util.stamp(layer)] = layer;\n\n\t\tvar order = layer._order = {\n\t\t\tlayer: layer,\n\t\t\tprev: this._drawLast,\n\t\t\tnext: null\n\t\t};\n\t\tif (this._drawLast) { this._drawLast.next = order; }\n\t\tthis._drawLast = order;\n\t\tthis._drawFirst = this._drawFirst || this._drawLast;\n\t},\n\n\t_addPath: function (layer) {\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\tthis._drawLast = prev;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\tdelete layer._order;\n\n\t\tdelete this._layers[Util.stamp(layer)];\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updatePath: function (layer) {\n\t\t// Redraw the union of the layer's old pixel\n\t\t// bounds and the new pixel bounds.\n\t\tthis._extendRedrawBounds(layer);\n\t\tlayer._project();\n\t\tlayer._update();\n\t\t// The redraw will extend the redraw bounds\n\t\t// with the new pixel bounds.\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateDashArray: function (layer) {\n\t\tif (typeof layer.options.dashArray === 'string') {\n\t\t\tvar parts = layer.options.dashArray.split(/[, ]+/),\n\t\t\t dashArray = [],\n\t\t\t dashValue,\n\t\t\t i;\n\t\t\tfor (i = 0; i < parts.length; i++) {\n\t\t\t\tdashValue = Number(parts[i]);\n\t\t\t\t// Ignore dash array containing invalid lengths\n\t\t\t\tif (isNaN(dashValue)) { return; }\n\t\t\t\tdashArray.push(dashValue);\n\t\t\t}\n\t\t\tlayer.options._dashArray = dashArray;\n\t\t} else {\n\t\t\tlayer.options._dashArray = layer.options.dashArray;\n\t\t}\n\t},\n\n\t_requestRedraw: function (layer) {\n\t\tif (!this._map) { return; }\n\n\t\tthis._extendRedrawBounds(layer);\n\t\tthis._redrawRequest = this._redrawRequest || Util.requestAnimFrame(this._redraw, this);\n\t},\n\n\t_extendRedrawBounds: function (layer) {\n\t\tif (layer._pxBounds) {\n\t\t\tvar padding = (layer.options.weight || 0) + 1;\n\t\t\tthis._redrawBounds = this._redrawBounds || new Bounds();\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));\n\t\t}\n\t},\n\n\t_redraw: function () {\n\t\tthis._redrawRequest = null;\n\n\t\tif (this._redrawBounds) {\n\t\t\tthis._redrawBounds.min._floor();\n\t\t\tthis._redrawBounds.max._ceil();\n\t\t}\n\n\t\tthis._clear(); // clear layers in redraw bounds\n\t\tthis._draw(); // draw layers\n\n\t\tthis._redrawBounds = null;\n\t},\n\n\t_clear: function () {\n\t\tvar bounds = this._redrawBounds;\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t} else {\n\t\t\tthis._ctx.save();\n\t\t\tthis._ctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\t\tthis._ctx.clearRect(0, 0, this._container.width, this._container.height);\n\t\t\tthis._ctx.restore();\n\t\t}\n\t},\n\n\t_draw: function () {\n\t\tvar layer, bounds = this._redrawBounds;\n\t\tthis._ctx.save();\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.beginPath();\n\t\t\tthis._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t\tthis._ctx.clip();\n\t\t}\n\n\t\tthis._drawing = true;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {\n\t\t\t\tlayer._updatePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._drawing = false;\n\n\t\tthis._ctx.restore(); // Restore state before clipping.\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tif (!this._drawing) { return; }\n\n\t\tvar i, j, len2, p,\n\t\t parts = layer._parts,\n\t\t len = parts.length,\n\t\t ctx = this._ctx;\n\n\t\tif (!len) { return; }\n\n\t\tctx.beginPath();\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tfor (j = 0, len2 = parts[i].length; j < len2; j++) {\n\t\t\t\tp = parts[i][j];\n\t\t\t\tctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);\n\t\t\t}\n\t\t\tif (closed) {\n\t\t\t\tctx.closePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\n\t\t// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature\n\t},\n\n\t_updateCircle: function (layer) {\n\n\t\tif (!this._drawing || layer._empty()) { return; }\n\n\t\tvar p = layer._point,\n\t\t ctx = this._ctx,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;\n\n\t\tif (s !== 1) {\n\t\t\tctx.save();\n\t\t\tctx.scale(1, s);\n\t\t}\n\n\t\tctx.beginPath();\n\t\tctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);\n\n\t\tif (s !== 1) {\n\t\t\tctx.restore();\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\t},\n\n\t_fillStroke: function (ctx, layer) {\n\t\tvar options = layer.options;\n\n\t\tif (options.fill) {\n\t\t\tctx.globalAlpha = options.fillOpacity;\n\t\t\tctx.fillStyle = options.fillColor || options.color;\n\t\t\tctx.fill(options.fillRule || 'evenodd');\n\t\t}\n\n\t\tif (options.stroke && options.weight !== 0) {\n\t\t\tif (ctx.setLineDash) {\n\t\t\t\tctx.setLineDash(layer.options && layer.options._dashArray || []);\n\t\t\t}\n\t\t\tctx.globalAlpha = options.opacity;\n\t\t\tctx.lineWidth = options.weight;\n\t\t\tctx.strokeStyle = options.color;\n\t\t\tctx.lineCap = options.lineCap;\n\t\t\tctx.lineJoin = options.lineJoin;\n\t\t\tctx.stroke();\n\t\t}\n\t},\n\n\t// Canvas obviously doesn't have mouse events for individual drawn objects,\n\t// so we emulate that by calculating what's under the mouse on mousemove/click manually\n\n\t_onClick: function (e) {\n\t\tvar point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tif (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {\n\t\t\t\t\tclickedLayer = layer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._fireEvent(clickedLayer ? [clickedLayer] : false, e);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }\n\n\t\tvar point = this._map.mouseEventToLayerPoint(e);\n\t\tthis._handleMouseHover(e, point);\n\t},\n\n\n\t_handleMouseOut: function (e) {\n\t\tvar layer = this._hoveredLayer;\n\t\tif (layer) {\n\t\t\t// if we're leaving the layer, fire mouseout\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-interactive');\n\t\t\tthis._fireEvent([layer], e, 'mouseout');\n\t\t\tthis._hoveredLayer = null;\n\t\t\tthis._mouseHoverThrottled = false;\n\t\t}\n\t},\n\n\t_handleMouseHover: function (e, point) {\n\t\tif (this._mouseHoverThrottled) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar layer, candidateHoveredLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tcandidateHoveredLayer = layer;\n\t\t\t}\n\t\t}\n\n\t\tif (candidateHoveredLayer !== this._hoveredLayer) {\n\t\t\tthis._handleMouseOut(e);\n\n\t\t\tif (candidateHoveredLayer) {\n\t\t\t\tDomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor\n\t\t\t\tthis._fireEvent([candidateHoveredLayer], e, 'mouseover');\n\t\t\t\tthis._hoveredLayer = candidateHoveredLayer;\n\t\t\t}\n\t\t}\n\n\t\tthis._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);\n\n\t\tthis._mouseHoverThrottled = true;\n\t\tsetTimeout(Util.bind(function () {\n\t\t\tthis._mouseHoverThrottled = false;\n\t\t}, this), 32);\n\t},\n\n\t_fireEvent: function (layers, e, type) {\n\t\tthis._map._fireDOMEvent(e, type || e.type, layers);\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tvar order = layer._order;\n\n\t\tif (!order) { return; }\n\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\t// Already last\n\t\t\treturn;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else if (next) {\n\t\t\t// Update first entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\torder.prev = this._drawLast;\n\t\tthis._drawLast.next = order;\n\n\t\torder.next = null;\n\t\tthis._drawLast = order;\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tvar order = layer._order;\n\n\t\tif (!order) { return; }\n\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\t// Already first\n\t\t\treturn;\n\t\t}\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else if (prev) {\n\t\t\t// Update last entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawLast = prev;\n\t\t}\n\n\t\torder.prev = null;\n\n\t\torder.next = this._drawFirst;\n\t\tthis._drawFirst.prev = order;\n\t\tthis._drawFirst = order;\n\n\t\tthis._requestRedraw(layer);\n\t}\n});\n\n// @factory L.canvas(options?: Renderer options)\n// Creates a Canvas renderer with the given options.\nexport function canvas(options) {\n\treturn Browser.canvas ? new Canvas(options) : null;\n}\n","import * as DomUtil from '../../dom/DomUtil';\nimport * as Util from '../../core/Util';\nimport {Renderer} from './Renderer';\n\n/*\n * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!\n */\n\n\nexport var vmlCreate = (function () {\n\ttry {\n\t\tdocument.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');\n\t\treturn function (name) {\n\t\t\treturn document.createElement('<lvml:' + name + ' class=\"lvml\">');\n\t\t};\n\t} catch (e) {\n\t\t// Do not return fn from catch block so `e` can be garbage collected\n\t\t// See https://github.com/Leaflet/Leaflet/pull/7279\n\t}\n\treturn function (name) {\n\t\treturn document.createElement('<' + name + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">');\n\t};\n})();\n\n\n/*\n * @class SVG\n *\n *\n * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility\n * with old versions of Internet Explorer.\n */\n\n// mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences\nexport var vmlMixin = {\n\n\t_initContainer: function () {\n\t\tthis._container = DomUtil.create('div', 'leaflet-vml-container');\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom) { return; }\n\t\tRenderer.prototype._update.call(this);\n\t\tthis.fire('update');\n\t},\n\n\t_initPath: function (layer) {\n\t\tvar container = layer._container = vmlCreate('shape');\n\n\t\tDomUtil.addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));\n\n\t\tcontainer.coordsize = '1 1';\n\n\t\tlayer._path = vmlCreate('path');\n\t\tcontainer.appendChild(layer._path);\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[Util.stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tvar container = layer._container;\n\t\tthis._container.appendChild(container);\n\n\t\tif (layer.options.interactive) {\n\t\t\tlayer.addInteractiveTarget(container);\n\t\t}\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar container = layer._container;\n\t\tDomUtil.remove(container);\n\t\tlayer.removeInteractiveTarget(container);\n\t\tdelete this._layers[Util.stamp(layer)];\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar stroke = layer._stroke,\n\t\t fill = layer._fill,\n\t\t options = layer.options,\n\t\t container = layer._container;\n\n\t\tcontainer.stroked = !!options.stroke;\n\t\tcontainer.filled = !!options.fill;\n\n\t\tif (options.stroke) {\n\t\t\tif (!stroke) {\n\t\t\t\tstroke = layer._stroke = vmlCreate('stroke');\n\t\t\t}\n\t\t\tcontainer.appendChild(stroke);\n\t\t\tstroke.weight = options.weight + 'px';\n\t\t\tstroke.color = options.color;\n\t\t\tstroke.opacity = options.opacity;\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tstroke.dashStyle = Util.isArray(options.dashArray) ?\n\t\t\t\t options.dashArray.join(' ') :\n\t\t\t\t options.dashArray.replace(/( *, *)/g, ' ');\n\t\t\t} else {\n\t\t\t\tstroke.dashStyle = '';\n\t\t\t}\n\t\t\tstroke.endcap = options.lineCap.replace('butt', 'flat');\n\t\t\tstroke.joinstyle = options.lineJoin;\n\n\t\t} else if (stroke) {\n\t\t\tcontainer.removeChild(stroke);\n\t\t\tlayer._stroke = null;\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tif (!fill) {\n\t\t\t\tfill = layer._fill = vmlCreate('fill');\n\t\t\t}\n\t\t\tcontainer.appendChild(fill);\n\t\t\tfill.color = options.fillColor || options.color;\n\t\t\tfill.opacity = options.fillOpacity;\n\n\t\t} else if (fill) {\n\t\t\tcontainer.removeChild(fill);\n\t\t\tlayer._fill = null;\n\t\t}\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point.round(),\n\t\t r = Math.round(layer._radius),\n\t\t r2 = Math.round(layer._radiusY || r);\n\n\t\tthis._setPath(layer, layer._empty() ? 'M0 0' :\n\t\t\t'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.v = path;\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tDomUtil.toFront(layer._container);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tDomUtil.toBack(layer._container);\n\t}\n};\n","import {Renderer} from './Renderer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport Browser from '../../core/Browser';\nimport {stamp} from '../../core/Util';\nimport {svgCreate, pointsToPath} from './SVG.Util';\nexport {pointsToPath};\nimport {vmlMixin, vmlCreate} from './SVG.VML';\n\nexport var create = Browser.vml ? vmlCreate : svgCreate;\n\n/*\n * @class SVG\n * @inherits Renderer\n * @aka L.SVG\n *\n * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](https://caniuse.com/svg), SVG is not\n * available in all web browsers, notably Android 2.x and 3.x.\n *\n * Although SVG is not available on IE7 and IE8, these browsers support\n * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)\n * (a now deprecated technology), and the SVG renderer will fall back to VML in\n * this case.\n *\n * @example\n *\n * Use SVG by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.svg()\n * });\n * ```\n *\n * Use a SVG renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.svg({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nexport var SVG = Renderer.extend({\n\n\t_initContainer: function () {\n\t\tthis._container = create('svg');\n\n\t\t// makes it possible to click through svg root; we'll reset it back in individual paths\n\t\tthis._container.setAttribute('pointer-events', 'none');\n\n\t\tthis._rootGroup = create('g');\n\t\tthis._container.appendChild(this._rootGroup);\n\t},\n\n\t_destroyContainer: function () {\n\t\tDomUtil.remove(this._container);\n\t\tDomEvent.off(this._container);\n\t\tdelete this._container;\n\t\tdelete this._rootGroup;\n\t\tdelete this._svgSize;\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t size = b.getSize(),\n\t\t container = this._container;\n\n\t\t// set size of svg-container if changed\n\t\tif (!this._svgSize || !this._svgSize.equals(size)) {\n\t\t\tthis._svgSize = size;\n\t\t\tcontainer.setAttribute('width', size.x);\n\t\t\tcontainer.setAttribute('height', size.y);\n\t\t}\n\n\t\t// movement: update container viewBox so that we don't have to change coordinates of individual layers\n\t\tDomUtil.setPosition(container, b.min);\n\t\tcontainer.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));\n\n\t\tthis.fire('update');\n\t},\n\n\t// methods below are called by vector layers implementations\n\n\t_initPath: function (layer) {\n\t\tvar path = layer._path = create('path');\n\n\t\t// @namespace Path\n\t\t// @option className: String = null\n\t\t// Custom class name set on an element. Only for SVG renderer.\n\t\tif (layer.options.className) {\n\t\t\tDomUtil.addClass(path, layer.options.className);\n\t\t}\n\n\t\tif (layer.options.interactive) {\n\t\t\tDomUtil.addClass(path, 'leaflet-interactive');\n\t\t}\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tif (!this._rootGroup) { this._initContainer(); }\n\t\tthis._rootGroup.appendChild(layer._path);\n\t\tlayer.addInteractiveTarget(layer._path);\n\t},\n\n\t_removePath: function (layer) {\n\t\tDomUtil.remove(layer._path);\n\t\tlayer.removeInteractiveTarget(layer._path);\n\t\tdelete this._layers[stamp(layer)];\n\t},\n\n\t_updatePath: function (layer) {\n\t\tlayer._project();\n\t\tlayer._update();\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar path = layer._path,\n\t\t options = layer.options;\n\n\t\tif (!path) { return; }\n\n\t\tif (options.stroke) {\n\t\t\tpath.setAttribute('stroke', options.color);\n\t\t\tpath.setAttribute('stroke-opacity', options.opacity);\n\t\t\tpath.setAttribute('stroke-width', options.weight);\n\t\t\tpath.setAttribute('stroke-linecap', options.lineCap);\n\t\t\tpath.setAttribute('stroke-linejoin', options.lineJoin);\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tpath.setAttribute('stroke-dasharray', options.dashArray);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dasharray');\n\t\t\t}\n\n\t\t\tif (options.dashOffset) {\n\t\t\t\tpath.setAttribute('stroke-dashoffset', options.dashOffset);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dashoffset');\n\t\t\t}\n\t\t} else {\n\t\t\tpath.setAttribute('stroke', 'none');\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tpath.setAttribute('fill', options.fillColor || options.color);\n\t\t\tpath.setAttribute('fill-opacity', options.fillOpacity);\n\t\t\tpath.setAttribute('fill-rule', options.fillRule || 'evenodd');\n\t\t} else {\n\t\t\tpath.setAttribute('fill', 'none');\n\t\t}\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tthis._setPath(layer, pointsToPath(layer._parts, closed));\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t r2 = Math.max(Math.round(layer._radiusY), 1) || r,\n\t\t arc = 'a' + r + ',' + r2 + ' 0 1,0 ';\n\n\t\t// drawing a circle with two half-arcs\n\t\tvar d = layer._empty() ? 'M0 0' :\n\t\t\t'M' + (p.x - r) + ',' + p.y +\n\t\t\tarc + (r * 2) + ',0 ' +\n\t\t\tarc + (-r * 2) + ',0 ';\n\n\t\tthis._setPath(layer, d);\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.setAttribute('d', path);\n\t},\n\n\t// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements\n\t_bringToFront: function (layer) {\n\t\tDomUtil.toFront(layer._path);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tDomUtil.toBack(layer._path);\n\t}\n});\n\nif (Browser.vml) {\n\tSVG.include(vmlMixin);\n}\n\n// @namespace SVG\n// @factory L.svg(options?: Renderer options)\n// Creates a SVG renderer with the given options.\nexport function svg(options) {\n\treturn Browser.svg || Browser.vml ? new SVG(options) : null;\n}\n","import {Map} from '../../map/Map';\nimport {canvas} from './Canvas';\nimport {svg} from './SVG';\n\nMap.include({\n\t// @namespace Map; @method getRenderer(layer: Path): Renderer\n\t// Returns the instance of `Renderer` that should be used to render the given\n\t// `Path`. It will ensure that the `renderer` options of the map and paths\n\t// are respected, and that the renderers do exist on the map.\n\tgetRenderer: function (layer) {\n\t\t// @namespace Path; @option renderer: Renderer\n\t\t// Use this specific instance of `Renderer` for this path. Takes\n\t\t// precedence over the map's [default renderer](#map-renderer).\n\t\tvar renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;\n\n\t\tif (!renderer) {\n\t\t\trenderer = this._renderer = this._createRenderer();\n\t\t}\n\n\t\tif (!this.hasLayer(renderer)) {\n\t\t\tthis.addLayer(renderer);\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_getPaneRenderer: function (name) {\n\t\tif (name === 'overlayPane' || name === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar renderer = this._paneRenderers[name];\n\t\tif (renderer === undefined) {\n\t\t\trenderer = this._createRenderer({pane: name});\n\t\t\tthis._paneRenderers[name] = renderer;\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_createRenderer: function (options) {\n\t\t// @namespace Map; @option preferCanvas: Boolean = false\n\t\t// Whether `Path`s should be rendered on a `Canvas` renderer.\n\t\t// By default, all `Path`s are rendered in a `SVG` renderer.\n\t\treturn (this.options.preferCanvas && canvas(options)) || svg(options);\n\t}\n});\n","import {Polygon} from './Polygon';\nimport {toLatLngBounds} from '../../geo/LatLngBounds';\n\n/*\n * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.\n */\n\n/*\n * @class Rectangle\n * @aka L.Rectangle\n * @inherits Polygon\n *\n * A class for drawing rectangle overlays on a map. Extends `Polygon`.\n *\n * @example\n *\n * ```js\n * // define rectangle geographical bounds\n * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n *\n * // create an orange rectangle\n * L.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n *\n * // zoom the map to the rectangle bounds\n * map.fitBounds(bounds);\n * ```\n *\n */\n\n\nexport var Rectangle = Polygon.extend({\n\tinitialize: function (latLngBounds, options) {\n\t\tPolygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);\n\t},\n\n\t// @method setBounds(latLngBounds: LatLngBounds): this\n\t// Redraws the rectangle with the passed bounds.\n\tsetBounds: function (latLngBounds) {\n\t\treturn this.setLatLngs(this._boundsToLatLngs(latLngBounds));\n\t},\n\n\t_boundsToLatLngs: function (latLngBounds) {\n\t\tlatLngBounds = toLatLngBounds(latLngBounds);\n\t\treturn [\n\t\t\tlatLngBounds.getSouthWest(),\n\t\t\tlatLngBounds.getNorthWest(),\n\t\t\tlatLngBounds.getNorthEast(),\n\t\t\tlatLngBounds.getSouthEast()\n\t\t];\n\t}\n});\n\n\n// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)\nexport function rectangle(latLngBounds, options) {\n\treturn new Rectangle(latLngBounds, options);\n}\n","export {Renderer} from './Renderer';\nexport {Canvas, canvas} from './Canvas';\nimport {SVG, create, pointsToPath, svg} from './SVG';\nSVG.create = create;\nSVG.pointsToPath = pointsToPath;\nexport {SVG, svg};\nimport './Renderer.getRenderer';\t// This is a bit of a hack, but needed because circular dependencies\n\nexport {Path} from './Path';\nexport {CircleMarker, circleMarker} from './CircleMarker';\nexport {Circle, circle} from './Circle';\nexport {Polyline, polyline} from './Polyline';\nexport {Polygon, polygon} from './Polygon';\nexport {Rectangle, rectangle} from './Rectangle';\n","export {Layer} from './Layer';\nexport {LayerGroup, layerGroup} from './LayerGroup';\nexport {FeatureGroup, featureGroup} from './FeatureGroup';\nimport {GeoJSON, geoJSON, geoJson, geometryToLayer, coordsToLatLng, coordsToLatLngs, latLngToCoords, latLngsToCoords, getFeature, asFeature} from './GeoJSON';\nGeoJSON.geometryToLayer = geometryToLayer;\nGeoJSON.coordsToLatLng = coordsToLatLng;\nGeoJSON.coordsToLatLngs = coordsToLatLngs;\nGeoJSON.latLngToCoords = latLngToCoords;\nGeoJSON.latLngsToCoords = latLngsToCoords;\nGeoJSON.getFeature = getFeature;\nGeoJSON.asFeature = asFeature;\nexport {GeoJSON, geoJSON, geoJson};\n\nexport {ImageOverlay, imageOverlay} from './ImageOverlay';\nexport {VideoOverlay, videoOverlay} from './VideoOverlay';\nexport {SVGOverlay, svgOverlay} from './SVGOverlay';\n\nexport {DivOverlay} from './DivOverlay';\nexport {Popup, popup} from './Popup';\nexport {Tooltip, tooltip} from './Tooltip';\n\nexport * from './marker/index';\nexport * from './tile/index';\nexport * from './vector/index';\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Bounds} from '../../geometry/Bounds';\n\n/*\n * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map\n * (zoom to a selected bounding box), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option boxZoom: Boolean = true\n\t// Whether the map can be zoomed to a rectangular area specified by\n\t// dragging the mouse while pressing the shift key.\n\tboxZoom: true\n});\n\nexport var BoxZoom = Handler.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t\tthis._container = map._container;\n\t\tthis._pane = map._panes.overlayPane;\n\t\tthis._resetStateTimeout = 0;\n\t\tmap.on('unload', this._destroy, this);\n\t},\n\n\taddHooks: function () {\n\t\tDomEvent.on(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tmoved: function () {\n\t\treturn this._moved;\n\t},\n\n\t_destroy: function () {\n\t\tDomUtil.remove(this._pane);\n\t\tdelete this._pane;\n\t},\n\n\t_resetState: function () {\n\t\tthis._resetStateTimeout = 0;\n\t\tthis._moved = false;\n\t},\n\n\t_clearDeferredResetState: function () {\n\t\tif (this._resetStateTimeout !== 0) {\n\t\t\tclearTimeout(this._resetStateTimeout);\n\t\t\tthis._resetStateTimeout = 0;\n\t\t}\n\t},\n\n\t_onMouseDown: function (e) {\n\t\tif (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }\n\n\t\t// Clear the deferred resetState if it hasn't executed yet, otherwise it\n\t\t// will interrupt the interaction and orphan a box element in the container.\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetState();\n\n\t\tDomUtil.disableTextSelection();\n\t\tDomUtil.disableImageDrag();\n\n\t\tthis._startPoint = this._map.mouseEventToContainerPoint(e);\n\n\t\tDomEvent.on(document, {\n\t\t\tcontextmenu: DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._moved) {\n\t\t\tthis._moved = true;\n\n\t\t\tthis._box = DomUtil.create('div', 'leaflet-zoom-box', this._container);\n\t\t\tDomUtil.addClass(this._container, 'leaflet-crosshair');\n\n\t\t\tthis._map.fire('boxzoomstart');\n\t\t}\n\n\t\tthis._point = this._map.mouseEventToContainerPoint(e);\n\n\t\tvar bounds = new Bounds(this._point, this._startPoint),\n\t\t size = bounds.getSize();\n\n\t\tDomUtil.setPosition(this._box, bounds.min);\n\n\t\tthis._box.style.width = size.x + 'px';\n\t\tthis._box.style.height = size.y + 'px';\n\t},\n\n\t_finish: function () {\n\t\tif (this._moved) {\n\t\t\tDomUtil.remove(this._box);\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-crosshair');\n\t\t}\n\n\t\tDomUtil.enableTextSelection();\n\t\tDomUtil.enableImageDrag();\n\n\t\tDomEvent.off(document, {\n\t\t\tcontextmenu: DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseUp: function (e) {\n\t\tif ((e.which !== 1) && (e.button !== 1)) { return; }\n\n\t\tthis._finish();\n\n\t\tif (!this._moved) { return; }\n\t\t// Postpone to next JS tick so internal click event handling\n\t\t// still see it as \"moved\".\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetStateTimeout = setTimeout(Util.bind(this._resetState, this), 0);\n\n\t\tvar bounds = new LatLngBounds(\n\t\t this._map.containerPointToLatLng(this._startPoint),\n\t\t this._map.containerPointToLatLng(this._point));\n\n\t\tthis._map\n\t\t\t.fitBounds(bounds)\n\t\t\t.fire('boxzoomend', {boxZoomBounds: bounds});\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.keyCode === 27) {\n\t\t\tthis._finish();\n\t\t\tthis._clearDeferredResetState();\n\t\t\tthis._resetState();\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property boxZoom: Handler\n// Box (shift-drag with mouse) zoom handler.\nMap.addInitHook('addHandler', 'boxZoom', BoxZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\n\n/*\n * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\n\nMap.mergeOptions({\n\t// @option doubleClickZoom: Boolean|String = true\n\t// Whether the map can be zoomed in by double clicking on it and\n\t// zoomed out by double clicking while holding shift. If passed\n\t// `'center'`, double-click zoom will zoom to the center of the\n\t// view regardless of where the mouse was.\n\tdoubleClickZoom: true\n});\n\nexport var DoubleClickZoom = Handler.extend({\n\taddHooks: function () {\n\t\tthis._map.on('dblclick', this._onDoubleClick, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._map.off('dblclick', this._onDoubleClick, this);\n\t},\n\n\t_onDoubleClick: function (e) {\n\t\tvar map = this._map,\n\t\t oldZoom = map.getZoom(),\n\t\t delta = map.options.zoomDelta,\n\t\t zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;\n\n\t\tif (map.options.doubleClickZoom === 'center') {\n\t\t\tmap.setZoom(zoom);\n\t\t} else {\n\t\t\tmap.setZoomAround(e.containerPoint, zoom);\n\t\t}\n\t}\n});\n\n// @section Handlers\n//\n// Map properties include interaction handlers that allow you to control\n// interaction behavior in runtime, enabling or disabling certain features such\n// as dragging or touch zoom (see `Handler` methods). For example:\n//\n// ```js\n// map.doubleClickZoom.disable();\n// ```\n//\n// @property doubleClickZoom: Handler\n// Double click zoom handler.\nMap.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport {Draggable} from '../../dom/Draggable';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {toLatLngBounds as latLngBounds} from '../../geo/LatLngBounds';\nimport {toBounds} from '../../geometry/Bounds';\n\n/*\n * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option dragging: Boolean = true\n\t// Whether the map is draggable with mouse/touch or not.\n\tdragging: true,\n\n\t// @section Panning Inertia Options\n\t// @option inertia: Boolean = *\n\t// If enabled, panning of the map will have an inertia effect where\n\t// the map builds momentum while dragging and continues moving in\n\t// the same direction for some time. Feels especially nice on touch\n\t// devices. Enabled by default.\n\tinertia: true,\n\n\t// @option inertiaDeceleration: Number = 3000\n\t// The rate with which the inertial movement slows down, in pixels/second².\n\tinertiaDeceleration: 3400, // px/s^2\n\n\t// @option inertiaMaxSpeed: Number = Infinity\n\t// Max speed of the inertial movement, in pixels/second.\n\tinertiaMaxSpeed: Infinity, // px/s\n\n\t// @option easeLinearity: Number = 0.2\n\teaseLinearity: 0.2,\n\n\t// TODO refactor, move to CRS\n\t// @option worldCopyJump: Boolean = false\n\t// With this option enabled, the map tracks when you pan to another \"copy\"\n\t// of the world and seamlessly jumps to the original one so that all overlays\n\t// like markers and vector layers are still visible.\n\tworldCopyJump: false,\n\n\t// @option maxBoundsViscosity: Number = 0.0\n\t// If `maxBounds` is set, this option will control how solid the bounds\n\t// are when dragging the map around. The default value of `0.0` allows the\n\t// user to drag outside the bounds at normal speed, higher values will\n\t// slow down map dragging outside bounds, and `1.0` makes the bounds fully\n\t// solid, preventing the user from dragging outside the bounds.\n\tmaxBoundsViscosity: 0.0\n});\n\nexport var Drag = Handler.extend({\n\taddHooks: function () {\n\t\tif (!this._draggable) {\n\t\t\tvar map = this._map;\n\n\t\t\tthis._draggable = new Draggable(map._mapPane, map._container);\n\n\t\t\tthis._draggable.on({\n\t\t\t\tdragstart: this._onDragStart,\n\t\t\t\tdrag: this._onDrag,\n\t\t\t\tdragend: this._onDragEnd\n\t\t\t}, this);\n\n\t\t\tthis._draggable.on('predrag', this._onPreDragLimit, this);\n\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\tthis._draggable.on('predrag', this._onPreDragWrap, this);\n\t\t\t\tmap.on('zoomend', this._onZoomEnd, this);\n\n\t\t\t\tmap.whenReady(this._onZoomEnd, this);\n\t\t\t}\n\t\t}\n\t\tDomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');\n\t\tthis._draggable.enable();\n\t\tthis._positions = [];\n\t\tthis._times = [];\n\t},\n\n\tremoveHooks: function () {\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-grab');\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-touch-drag');\n\t\tthis._draggable.disable();\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\tmoving: function () {\n\t\treturn this._draggable && this._draggable._moving;\n\t},\n\n\t_onDragStart: function () {\n\t\tvar map = this._map;\n\n\t\tmap._stop();\n\t\tif (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {\n\t\t\tvar bounds = latLngBounds(this._map.options.maxBounds);\n\n\t\t\tthis._offsetLimit = toBounds(\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)\n\t\t\t\t\t.add(this._map.getSize()));\n\n\t\t\tthis._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));\n\t\t} else {\n\t\t\tthis._offsetLimit = null;\n\t\t}\n\n\t\tmap\n\t\t .fire('movestart')\n\t\t .fire('dragstart');\n\n\t\tif (map.options.inertia) {\n\t\t\tthis._positions = [];\n\t\t\tthis._times = [];\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tif (this._map.options.inertia) {\n\t\t\tvar time = this._lastTime = +new Date(),\n\t\t\t pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;\n\n\t\t\tthis._positions.push(pos);\n\t\t\tthis._times.push(time);\n\n\t\t\tthis._prunePositions(time);\n\t\t}\n\n\t\tthis._map\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_prunePositions: function (time) {\n\t\twhile (this._positions.length > 1 && time - this._times[0] > 50) {\n\t\t\tthis._positions.shift();\n\t\t\tthis._times.shift();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tvar pxCenter = this._map.getSize().divideBy(2),\n\t\t pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);\n\n\t\tthis._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;\n\t\tthis._worldWidth = this._map.getPixelWorldBounds().getSize().x;\n\t},\n\n\t_viscousLimit: function (value, threshold) {\n\t\treturn value - (value - threshold) * this._viscosity;\n\t},\n\n\t_onPreDragLimit: function () {\n\t\tif (!this._viscosity || !this._offsetLimit) { return; }\n\n\t\tvar offset = this._draggable._newPos.subtract(this._draggable._startPos);\n\n\t\tvar limit = this._offsetLimit;\n\t\tif (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }\n\t\tif (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }\n\t\tif (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }\n\t\tif (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }\n\n\t\tthis._draggable._newPos = this._draggable._startPos.add(offset);\n\t},\n\n\t_onPreDragWrap: function () {\n\t\t// TODO refactor to be able to adjust map pane position after zoom\n\t\tvar worldWidth = this._worldWidth,\n\t\t halfWidth = Math.round(worldWidth / 2),\n\t\t dx = this._initialWorldOffset,\n\t\t x = this._draggable._newPos.x,\n\t\t newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,\n\t\t newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,\n\t\t newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;\n\n\t\tthis._draggable._absPos = this._draggable._newPos.clone();\n\t\tthis._draggable._newPos.x = newX;\n\t},\n\n\t_onDragEnd: function (e) {\n\t\tvar map = this._map,\n\t\t options = map.options,\n\n\t\t noInertia = !options.inertia || e.noInertia || this._times.length < 2;\n\n\t\tmap.fire('dragend', e);\n\n\t\tif (noInertia) {\n\t\t\tmap.fire('moveend');\n\n\t\t} else {\n\t\t\tthis._prunePositions(+new Date());\n\n\t\t\tvar direction = this._lastPos.subtract(this._positions[0]),\n\t\t\t duration = (this._lastTime - this._times[0]) / 1000,\n\t\t\t ease = options.easeLinearity,\n\n\t\t\t speedVector = direction.multiplyBy(ease / duration),\n\t\t\t speed = speedVector.distanceTo([0, 0]),\n\n\t\t\t limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),\n\t\t\t limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),\n\n\t\t\t decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),\n\t\t\t offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();\n\n\t\t\tif (!offset.x && !offset.y) {\n\t\t\t\tmap.fire('moveend');\n\n\t\t\t} else {\n\t\t\t\toffset = map._limitOffset(offset, map.options.maxBounds);\n\n\t\t\t\tUtil.requestAnimFrame(function () {\n\t\t\t\t\tmap.panBy(offset, {\n\t\t\t\t\t\tduration: decelerationDuration,\n\t\t\t\t\t\teaseLinearity: ease,\n\t\t\t\t\t\tnoMoveStart: true,\n\t\t\t\t\t\tanimate: true\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property dragging: Handler\n// Map dragging handler (by both mouse and touch).\nMap.addInitHook('addHandler', 'dragging', Drag);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport {on, off, stop} from '../../dom/DomEvent';\nimport {toPoint} from '../../geometry/Point';\n\n\n/*\n * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.\n */\n\n// @namespace Map\n// @section Keyboard Navigation Options\nMap.mergeOptions({\n\t// @option keyboard: Boolean = true\n\t// Makes the map focusable and allows users to navigate the map with keyboard\n\t// arrows and `+`/`-` keys.\n\tkeyboard: true,\n\n\t// @option keyboardPanDelta: Number = 80\n\t// Amount of pixels to pan when pressing an arrow key.\n\tkeyboardPanDelta: 80\n});\n\nexport var Keyboard = Handler.extend({\n\n\tkeyCodes: {\n\t\tleft: [37],\n\t\tright: [39],\n\t\tdown: [40],\n\t\tup: [38],\n\t\tzoomIn: [187, 107, 61, 171],\n\t\tzoomOut: [189, 109, 54, 173]\n\t},\n\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\n\t\tthis._setPanDelta(map.options.keyboardPanDelta);\n\t\tthis._setZoomDelta(map.options.zoomDelta);\n\t},\n\n\taddHooks: function () {\n\t\tvar container = this._map._container;\n\n\t\t// make the container focusable by tabbing\n\t\tif (container.tabIndex <= 0) {\n\t\t\tcontainer.tabIndex = '0';\n\t\t}\n\n\t\ton(container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.on({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._removeHooks();\n\n\t\toff(this._map._container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.off({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\t_onMouseDown: function () {\n\t\tif (this._focused) { return; }\n\n\t\tvar body = document.body,\n\t\t docEl = document.documentElement,\n\t\t top = body.scrollTop || docEl.scrollTop,\n\t\t left = body.scrollLeft || docEl.scrollLeft;\n\n\t\tthis._map._container.focus();\n\n\t\twindow.scrollTo(left, top);\n\t},\n\n\t_onFocus: function () {\n\t\tthis._focused = true;\n\t\tthis._map.fire('focus');\n\t},\n\n\t_onBlur: function () {\n\t\tthis._focused = false;\n\t\tthis._map.fire('blur');\n\t},\n\n\t_setPanDelta: function (panDelta) {\n\t\tvar keys = this._panKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.left.length; i < len; i++) {\n\t\t\tkeys[codes.left[i]] = [-1 * panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.right.length; i < len; i++) {\n\t\t\tkeys[codes.right[i]] = [panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.down.length; i < len; i++) {\n\t\t\tkeys[codes.down[i]] = [0, panDelta];\n\t\t}\n\t\tfor (i = 0, len = codes.up.length; i < len; i++) {\n\t\t\tkeys[codes.up[i]] = [0, -1 * panDelta];\n\t\t}\n\t},\n\n\t_setZoomDelta: function (zoomDelta) {\n\t\tvar keys = this._zoomKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.zoomIn.length; i < len; i++) {\n\t\t\tkeys[codes.zoomIn[i]] = zoomDelta;\n\t\t}\n\t\tfor (i = 0, len = codes.zoomOut.length; i < len; i++) {\n\t\t\tkeys[codes.zoomOut[i]] = -zoomDelta;\n\t\t}\n\t},\n\n\t_addHooks: function () {\n\t\ton(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_removeHooks: function () {\n\t\toff(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.altKey || e.ctrlKey || e.metaKey) { return; }\n\n\t\tvar key = e.keyCode,\n\t\t map = this._map,\n\t\t offset;\n\n\t\tif (key in this._panKeys) {\n\t\t\tif (!map._panAnim || !map._panAnim._inProgress) {\n\t\t\t\toffset = this._panKeys[key];\n\t\t\t\tif (e.shiftKey) {\n\t\t\t\t\toffset = toPoint(offset).multiplyBy(3);\n\t\t\t\t}\n\n\t\t\t\tif (map.options.maxBounds) {\n\t\t\t\t\toffset = map._limitOffset(toPoint(offset), map.options.maxBounds);\n\t\t\t\t}\n\n\t\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\t\tvar newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));\n\t\t\t\t\tmap.panTo(newLatLng);\n\t\t\t\t} else {\n\t\t\t\t\tmap.panBy(offset);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (key in this._zoomKeys) {\n\t\t\tmap.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);\n\n\t\t} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {\n\t\t\tmap.closePopup();\n\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tstop(e);\n\t}\n});\n\n// @section Handlers\n// @section Handlers\n// @property keyboard: Handler\n// Keyboard navigation handler.\nMap.addInitHook('addHandler', 'keyboard', Keyboard);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport * as Util from '../../core/Util';\n\n/*\n * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Mouse wheel options\n\t// @option scrollWheelZoom: Boolean|String = true\n\t// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,\n\t// it will zoom to the center of the view regardless of where the mouse was.\n\tscrollWheelZoom: true,\n\n\t// @option wheelDebounceTime: Number = 40\n\t// Limits the rate at which a wheel can fire (in milliseconds). By default\n\t// user can't zoom via wheel more often than once per 40 ms.\n\twheelDebounceTime: 40,\n\n\t// @option wheelPxPerZoomLevel: Number = 60\n\t// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))\n\t// mean a change of one full zoom level. Smaller values will make wheel-zooming\n\t// faster (and vice versa).\n\twheelPxPerZoomLevel: 60\n});\n\nexport var ScrollWheelZoom = Handler.extend({\n\taddHooks: function () {\n\t\tDomEvent.on(this._map._container, 'wheel', this._onWheelScroll, this);\n\n\t\tthis._delta = 0;\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._map._container, 'wheel', this._onWheelScroll, this);\n\t},\n\n\t_onWheelScroll: function (e) {\n\t\tvar delta = DomEvent.getWheelDelta(e);\n\n\t\tvar debounce = this._map.options.wheelDebounceTime;\n\n\t\tthis._delta += delta;\n\t\tthis._lastMousePos = this._map.mouseEventToContainerPoint(e);\n\n\t\tif (!this._startTime) {\n\t\t\tthis._startTime = +new Date();\n\t\t}\n\n\t\tvar left = Math.max(debounce - (+new Date() - this._startTime), 0);\n\n\t\tclearTimeout(this._timer);\n\t\tthis._timer = setTimeout(Util.bind(this._performZoom, this), left);\n\n\t\tDomEvent.stop(e);\n\t},\n\n\t_performZoom: function () {\n\t\tvar map = this._map,\n\t\t zoom = map.getZoom(),\n\t\t snap = this._map.options.zoomSnap || 0;\n\n\t\tmap._stop(); // stop panning and fly animations if any\n\n\t\t// map the delta with a sigmoid function to -4..4 range leaning on -1..1\n\t\tvar d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),\n\t\t d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,\n\t\t d4 = snap ? Math.ceil(d3 / snap) * snap : d3,\n\t\t delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;\n\n\t\tthis._delta = 0;\n\t\tthis._startTime = null;\n\n\t\tif (!delta) { return; }\n\n\t\tif (map.options.scrollWheelZoom === 'center') {\n\t\t\tmap.setZoom(zoom + delta);\n\t\t} else {\n\t\t\tmap.setZoomAround(this._lastMousePos, zoom + delta);\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property scrollWheelZoom: Handler\n// Scroll wheel zoom handler.\nMap.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport {Point} from '../../geometry/Point';\nimport * as Util from '../../core/Util';\nimport Browser from '../../core/Browser';\n\n/*\n * L.Map.TapHold is used to simulate `contextmenu` event on long hold,\n * which otherwise is not fired by mobile Safari.\n */\n\nvar tapHoldDelay = 600;\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option tapHold: Boolean\n\t// Enables simulation of `contextmenu` event, default is `true` for mobile Safari.\n\ttapHold: Browser.touchNative && Browser.safari && Browser.mobile,\n\n\t// @option tapTolerance: Number = 15\n\t// The max number of pixels a user can shift his finger during touch\n\t// for it to be considered a valid tap.\n\ttapTolerance: 15\n});\n\nexport var TapHold = Handler.extend({\n\taddHooks: function () {\n\t\tDomEvent.on(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\t_onDown: function (e) {\n\t\tclearTimeout(this._holdTimeout);\n\t\tif (e.touches.length !== 1) { return; }\n\n\t\tvar first = e.touches[0];\n\t\tthis._startPos = this._newPos = new Point(first.clientX, first.clientY);\n\n\t\tthis._holdTimeout = setTimeout(Util.bind(function () {\n\t\t\tthis._cancel();\n\t\t\tif (!this._isTapValid()) { return; }\n\n\t\t\t// prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events\n\t\t\tDomEvent.on(document, 'touchend', DomEvent.preventDefault);\n\t\t\tDomEvent.on(document, 'touchend touchcancel', this._cancelClickPrevent);\n\t\t\tthis._simulateEvent('contextmenu', first);\n\t\t}, this), tapHoldDelay);\n\n\t\tDomEvent.on(document, 'touchend touchcancel contextmenu', this._cancel, this);\n\t\tDomEvent.on(document, 'touchmove', this._onMove, this);\n\t},\n\n\t_cancelClickPrevent: function cancelClickPrevent() {\n\t\tDomEvent.off(document, 'touchend', DomEvent.preventDefault);\n\t\tDomEvent.off(document, 'touchend touchcancel', cancelClickPrevent);\n\t},\n\n\t_cancel: function () {\n\t\tclearTimeout(this._holdTimeout);\n\t\tDomEvent.off(document, 'touchend touchcancel contextmenu', this._cancel, this);\n\t\tDomEvent.off(document, 'touchmove', this._onMove, this);\n\t},\n\n\t_onMove: function (e) {\n\t\tvar first = e.touches[0];\n\t\tthis._newPos = new Point(first.clientX, first.clientY);\n\t},\n\n\t_isTapValid: function () {\n\t\treturn this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;\n\t},\n\n\t_simulateEvent: function (type, e) {\n\t\tvar simulatedEvent = new MouseEvent(type, {\n\t\t\tbubbles: true,\n\t\t\tcancelable: true,\n\t\t\tview: window,\n\t\t\t// detail: 1,\n\t\t\tscreenX: e.screenX,\n\t\t\tscreenY: e.screenY,\n\t\t\tclientX: e.clientX,\n\t\t\tclientY: e.clientY,\n\t\t\t// button: 2,\n\t\t\t// buttons: 2\n\t\t});\n\n\t\tsimulatedEvent._simulated = true;\n\n\t\te.target.dispatchEvent(simulatedEvent);\n\t}\n});\n\n// @section Handlers\n// @property tapHold: Handler\n// Long tap handler to simulate `contextmenu` event (useful in mobile Safari).\nMap.addInitHook('addHandler', 'tapHold', TapHold);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport Browser from '../../core/Browser';\n\n/*\n * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option touchZoom: Boolean|String = *\n\t// Whether the map can be zoomed by touch-dragging with two fingers. If\n\t// passed `'center'`, it will zoom to the center of the view regardless of\n\t// where the touch events (fingers) were. Enabled for touch-capable web\n\t// browsers.\n\ttouchZoom: Browser.touch,\n\n\t// @option bounceAtZoomLimits: Boolean = true\n\t// Set it to false if you don't want the map to zoom beyond min/max zoom\n\t// and then bounce back when pinch-zooming.\n\tbounceAtZoomLimits: true\n});\n\nexport var TouchZoom = Handler.extend({\n\taddHooks: function () {\n\t\tDomUtil.addClass(this._map._container, 'leaflet-touch-zoom');\n\t\tDomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');\n\t\tDomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\t_onTouchStart: function (e) {\n\t\tvar map = this._map;\n\t\tif (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }\n\n\t\tvar p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]);\n\n\t\tthis._centerPoint = map.getSize()._divideBy(2);\n\t\tthis._startLatLng = map.containerPointToLatLng(this._centerPoint);\n\t\tif (map.options.touchZoom !== 'center') {\n\t\t\tthis._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));\n\t\t}\n\n\t\tthis._startDist = p1.distanceTo(p2);\n\t\tthis._startZoom = map.getZoom();\n\n\t\tthis._moved = false;\n\t\tthis._zooming = true;\n\n\t\tmap._stop();\n\n\t\tDomEvent.on(document, 'touchmove', this._onTouchMove, this);\n\t\tDomEvent.on(document, 'touchend touchcancel', this._onTouchEnd, this);\n\n\t\tDomEvent.preventDefault(e);\n\t},\n\n\t_onTouchMove: function (e) {\n\t\tif (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }\n\n\t\tvar map = this._map,\n\t\t p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]),\n\t\t scale = p1.distanceTo(p2) / this._startDist;\n\n\t\tthis._zoom = map.getScaleZoom(scale, this._startZoom);\n\n\t\tif (!map.options.bounceAtZoomLimits && (\n\t\t\t(this._zoom < map.getMinZoom() && scale < 1) ||\n\t\t\t(this._zoom > map.getMaxZoom() && scale > 1))) {\n\t\t\tthis._zoom = map._limitZoom(this._zoom);\n\t\t}\n\n\t\tif (map.options.touchZoom === 'center') {\n\t\t\tthis._center = this._startLatLng;\n\t\t\tif (scale === 1) { return; }\n\t\t} else {\n\t\t\t// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng\n\t\t\tvar delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);\n\t\t\tif (scale === 1 && delta.x === 0 && delta.y === 0) { return; }\n\t\t\tthis._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);\n\t\t}\n\n\t\tif (!this._moved) {\n\t\t\tmap._moveStart(true, false);\n\t\t\tthis._moved = true;\n\t\t}\n\n\t\tUtil.cancelAnimFrame(this._animRequest);\n\n\t\tvar moveFn = Util.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}, undefined);\n\t\tthis._animRequest = Util.requestAnimFrame(moveFn, this, true);\n\n\t\tDomEvent.preventDefault(e);\n\t},\n\n\t_onTouchEnd: function () {\n\t\tif (!this._moved || !this._zooming) {\n\t\t\tthis._zooming = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._zooming = false;\n\t\tUtil.cancelAnimFrame(this._animRequest);\n\n\t\tDomEvent.off(document, 'touchmove', this._onTouchMove, this);\n\t\tDomEvent.off(document, 'touchend touchcancel', this._onTouchEnd, this);\n\n\t\t// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.\n\t\tif (this._map.options.zoomAnimation) {\n\t\t\tthis._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);\n\t\t} else {\n\t\t\tthis._map._resetView(this._center, this._map._limitZoom(this._zoom));\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property touchZoom: Handler\n// Touch zoom handler.\nMap.addInitHook('addHandler', 'touchZoom', TouchZoom);\n","import {Map} from './Map';\nimport {BoxZoom} from './handler/Map.BoxZoom';\nMap.BoxZoom = BoxZoom;\nimport {DoubleClickZoom} from './handler/Map.DoubleClickZoom';\nMap.DoubleClickZoom = DoubleClickZoom;\nimport {Drag} from './handler/Map.Drag';\nMap.Drag = Drag;\nimport {Keyboard} from './handler/Map.Keyboard';\nMap.Keyboard = Keyboard;\nimport {ScrollWheelZoom} from './handler/Map.ScrollWheelZoom';\nMap.ScrollWheelZoom = ScrollWheelZoom;\nimport {TapHold} from './handler/Map.TapHold';\nMap.TapHold = TapHold;\nimport {TouchZoom} from './handler/Map.TouchZoom';\nMap.TouchZoom = TouchZoom;\n\nexport {Map, createMap as map} from './Map';\n"],"names":["create","Util.setOptions","Util.create","Util.extend","Util.isArray","Util.splitWords","Util.falseFn","Util.stamp","Util.formatNum","Util.wrapNum","canvas","svg","DomEvent.preventDefault","DomEvent.getPropagationPath","Util.trim","DomEvent.on","DomEvent.off","Util.indexOf","DomUtil.getPosition","Util.requestAnimFrame","DomUtil.setPosition","Util.cancelAnimFrame","Util.bind","DomUtil.TRANSITION","DomUtil.TRANSITION_END","DomUtil.addClass","DomUtil.remove","DomUtil.create","DomEvent.getMousePosition","DomUtil.get","DomUtil.getStyle","DomEvent.isExternalTarget","DomUtil.preventOutline","DomUtil.removeClass","DomUtil.TRANSFORM","DomUtil.setTransform","DomEvent.disableClickPropagation","DomEvent.disableScrollPropagation","DomUtil.empty","DomEvent.stop","DomUtil.hasClass","DomUtil.disableImageDrag","DomUtil.disableTextSelection","DomUtil.getSizedParentNode","DomUtil.getScale","DomUtil.enableImageDrag","DomUtil.enableTextSelection","LineUtil._getBitCod{"version":3,"file":"leaflet-src.js","sources":["../src/core/Util.js","../src/core/Class.js","../src/core/Events.js","../src/geometry/Point.js","../src/geometry/Bounds.js","../src/geo/LatLngBounds.js","../src/geo/LatLng.js","../src/geo/crs/CRS.js","../src/geo/crs/CRS.Earth.js","../src/geo/projection/Projection.SphericalMercator.js","../src/geometry/Transformation.js","../src/geo/crs/CRS.EPSG3857.js","../src/layer/vector/SVG.Util.js","../src/core/Browser.js","../src/dom/DomEvent.Pointer.js","../src/dom/DomEvent.DoubleTap.js","../src/dom/DomUtil.js","../src/dom/DomEvent.js","../src/dom/PosAnimation.js","../src/map/Map.js","../src/control/Control.js","../src/control/Control.Layers.js","../src/control/Control.Zoom.js","../src/control/Control.Scale.js","../src/control/Control.Attribution.js","../src/control/index.js","../src/core/Handler.js","../src/core/index.js","../src/dom/Draggable.js","../src/geometry/LineUtil.js","../src/geometry/PolyUtil.js","../src/geo/projection/Projection.LonLat.js","../src/geo/projection/Projection.Mercator.js","../src/geo/projection/index.js","../src/geo/crs/CRS.EPSG3395.js","../src/geo/crs/CRS.EPSG4326.js","../src/geo/crs/CRS.Simple.js","../src/geo/crs/index.js","../src/layer/Layer.js","../src/layer/LayerGroup.js","../src/layer/FeatureGroup.js","../src/layer/marker/Icon.js","../src/layer/marker/Icon.Default.js","../src/layer/marker/Marker.Drag.js","../src/layer/marker/Marker.js","../src/layer/vector/Path.js","../src/layer/vector/CircleMarker.js","../src/layer/vector/Circle.js","../src/layer/vector/Polyline.js","../src/layer/vector/Polygon.js","../src/layer/GeoJSON.js","../src/layer/ImageOverlay.js","../src/layer/VideoOverlay.js","../src/layer/SVGOverlay.js","../src/layer/DivOverlay.js","../src/layer/Popup.js","../src/layer/Tooltip.js","../src/layer/marker/DivIcon.js","../src/layer/marker/index.js","../src/layer/tile/GridLayer.js","../src/layer/tile/TileLayer.js","../src/layer/tile/TileLayer.WMS.js","../src/layer/tile/index.js","../src/layer/vector/Renderer.js","../src/layer/vector/Canvas.js","../src/layer/vector/SVG.VML.js","../src/layer/vector/SVG.js","../src/layer/vector/Renderer.getRenderer.js","../src/layer/vector/Rectangle.js","../src/layer/vector/index.js","../src/layer/index.js","../src/map/handler/Map.BoxZoom.js","../src/map/handler/Map.DoubleClickZoom.js","../src/map/handler/Map.Drag.js","../src/map/handler/Map.Keyboard.js","../src/map/handler/Map.ScrollWheelZoom.js","../src/map/handler/Map.TapHold.js","../src/map/handler/Map.TouchZoom.js","../src/map/index.js"],"sourcesContent":["/*\r\n * @namespace Util\r\n *\r\n * Various utility functions, used by Leaflet internally.\r\n */\r\n\r\n// @function extend(dest: Object, src?: Object): Object\r\n// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.\r\nexport function extend(dest) {\r\n\tvar i, j, len, src;\r\n\r\n\tfor (j = 1, len = arguments.length; j < len; j++) {\r\n\t\tsrc = arguments[j];\r\n\t\tfor (i in src) {\r\n\t\t\tdest[i] = src[i];\r\n\t\t}\r\n\t}\r\n\treturn dest;\r\n}\r\n\r\n// @function create(proto: Object, properties?: Object): Object\r\n// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)\r\nexport var create = Object.create || (function () {\r\n\tfunction F() {}\r\n\treturn function (proto) {\r\n\t\tF.prototype = proto;\r\n\t\treturn new F();\r\n\t};\r\n})();\r\n\r\n// @function bind(fn: Function, …): Function\r\n// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).\r\n// Has a `L.bind()` shortcut.\r\nexport function bind(fn, obj) {\r\n\tvar slice = Array.prototype.slice;\r\n\r\n\tif (fn.bind) {\r\n\t\treturn fn.bind.apply(fn, slice.call(arguments, 1));\r\n\t}\r\n\r\n\tvar args = slice.call(arguments, 2);\r\n\r\n\treturn function () {\r\n\t\treturn fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);\r\n\t};\r\n}\r\n\r\n// @property lastId: Number\r\n// Last unique ID used by [`stamp()`](#util-stamp)\r\nexport var lastId = 0;\r\n\r\n// @function stamp(obj: Object): Number\r\n// Returns the unique ID of an object, assigning it one if it doesn't have it.\r\nexport function stamp(obj) {\r\n\tif (!('_leaflet_id' in obj)) {\r\n\t\tobj['_leaflet_id'] = ++lastId;\r\n\t}\r\n\treturn obj._leaflet_id;\r\n}\r\n\r\n// @function throttle(fn: Function, time: Number, context: Object): Function\r\n// Returns a function which executes function `fn` with the given scope `context`\r\n// (so that the `this` keyword refers to `context` inside `fn`'s code). The function\r\n// `fn` will be called no more than one time per given amount of `time`. The arguments\r\n// received by the bound function will be any arguments passed when binding the\r\n// function, followed by any arguments passed when invoking the bound function.\r\n// Has an `L.throttle` shortcut.\r\nexport function throttle(fn, time, context) {\r\n\tvar lock, args, wrapperFn, later;\r\n\r\n\tlater = function () {\r\n\t\t// reset lock and call if queued\r\n\t\tlock = false;\r\n\t\tif (args) {\r\n\t\t\twrapperFn.apply(context, args);\r\n\t\t\targs = false;\r\n\t\t}\r\n\t};\r\n\r\n\twrapperFn = function () {\r\n\t\tif (lock) {\r\n\t\t\t// called too soon, queue to call later\r\n\t\t\targs = arguments;\r\n\r\n\t\t} else {\r\n\t\t\t// call and lock until later\r\n\t\t\tfn.apply(context, arguments);\r\n\t\t\tsetTimeout(later, time);\r\n\t\t\tlock = true;\r\n\t\t}\r\n\t};\r\n\r\n\treturn wrapperFn;\r\n}\r\n\r\n// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number\r\n// Returns the number `num` modulo `range` in such a way so it lies within\r\n// `range[0]` and `range[1]`. The returned value will be always smaller than\r\n// `range[1]` unless `includeMax` is set to `true`.\r\nexport function wrapNum(x, range, includeMax) {\r\n\tvar max = range[1],\r\n\t min = range[0],\r\n\t d = max - min;\r\n\treturn x === max && includeMax ? x : ((x - min) % d + d) % d + min;\r\n}\r\n\r\n// @function falseFn(): Function\r\n// Returns a function which always returns `false`.\r\nexport function falseFn() { return false; }\r\n\r\n// @function formatNum(num: Number, precision?: Number|false): Number\r\n// Returns the number `num` rounded with specified `precision`.\r\n// The default `precision` value is 6 decimal places.\r\n// `false` can be passed to skip any processing (can be useful to avoid round-off errors).\r\nexport function formatNum(num, precision) {\r\n\tif (precision === false) { return num; }\r\n\tvar pow = Math.pow(10, precision === undefined ? 6 : precision);\r\n\treturn Math.round(num * pow) / pow;\r\n}\r\n\r\n// @function trim(str: String): String\r\n// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)\r\nexport function trim(str) {\r\n\treturn str.trim ? str.trim() : str.replace(/^\\s+|\\s+$/g, '');\r\n}\r\n\r\n// @function splitWords(str: String): String[]\r\n// Trims and splits the string on whitespace and returns the array of parts.\r\nexport function splitWords(str) {\r\n\treturn trim(str).split(/\\s+/);\r\n}\r\n\r\n// @function setOptions(obj: Object, options: Object): Object\r\n// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.\r\nexport function setOptions(obj, options) {\r\n\tif (!Object.prototype.hasOwnProperty.call(obj, 'options')) {\r\n\t\tobj.options = obj.options ? create(obj.options) : {};\r\n\t}\r\n\tfor (var i in options) {\r\n\t\tobj.options[i] = options[i];\r\n\t}\r\n\treturn obj.options;\r\n}\r\n\r\n// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String\r\n// Converts an object into a parameter URL string, e.g. `{a: \"foo\", b: \"bar\"}`\r\n// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will\r\n// be appended at the end. If `uppercase` is `true`, the parameter names will\r\n// be uppercased (e.g. `'?A=foo&B=bar'`)\r\nexport function getParamString(obj, existingUrl, uppercase) {\r\n\tvar params = [];\r\n\tfor (var i in obj) {\r\n\t\tparams.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));\r\n\t}\r\n\treturn ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');\r\n}\r\n\r\nvar templateRe = /\\{ *([\\w_ -]+) *\\}/g;\r\n\r\n// @function template(str: String, data: Object): String\r\n// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`\r\n// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string\r\n// `('Hello foo, bar')`. You can also specify functions instead of strings for\r\n// data values — they will be evaluated passing `data` as an argument.\r\nexport function template(str, data) {\r\n\treturn str.replace(templateRe, function (str, key) {\r\n\t\tvar value = data[key];\r\n\r\n\t\tif (value === undefined) {\r\n\t\t\tthrow new Error('No value provided for variable ' + str);\r\n\r\n\t\t} else if (typeof value === 'function') {\r\n\t\t\tvalue = value(data);\r\n\t\t}\r\n\t\treturn value;\r\n\t});\r\n}\r\n\r\n// @function isArray(obj): Boolean\r\n// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)\r\nexport var isArray = Array.isArray || function (obj) {\r\n\treturn (Object.prototype.toString.call(obj) === '[object Array]');\r\n};\r\n\r\n// @function indexOf(array: Array, el: Object): Number\r\n// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)\r\nexport function indexOf(array, el) {\r\n\tfor (var i = 0; i < array.length; i++) {\r\n\t\tif (array[i] === el) { return i; }\r\n\t}\r\n\treturn -1;\r\n}\r\n\r\n// @property emptyImageUrl: String\r\n// Data URI string containing a base64-encoded empty GIF image.\r\n// Used as a hack to free memory from unused images on WebKit-powered\r\n// mobile devices (by setting image `src` to this string).\r\nexport var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';\r\n\r\n// inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/\r\n\r\nfunction getPrefixed(name) {\r\n\treturn window['webkit' + name] || window['moz' + name] || window['ms' + name];\r\n}\r\n\r\nvar lastTime = 0;\r\n\r\n// fallback for IE 7-8\r\nfunction timeoutDefer(fn) {\r\n\tvar time = +new Date(),\r\n\t timeToCall = Math.max(0, 16 - (time - lastTime));\r\n\r\n\tlastTime = time + timeToCall;\r\n\treturn window.setTimeout(fn, timeToCall);\r\n}\r\n\r\nexport var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;\r\nexport var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||\r\n\t\tgetPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };\r\n\r\n// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number\r\n// Schedules `fn` to be executed when the browser repaints. `fn` is bound to\r\n// `context` if given. When `immediate` is set, `fn` is called immediately if\r\n// the browser doesn't have native support for\r\n// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),\r\n// otherwise it's delayed. Returns a request ID that can be used to cancel the request.\r\nexport function requestAnimFrame(fn, context, immediate) {\r\n\tif (immediate && requestFn === timeoutDefer) {\r\n\t\tfn.call(context);\r\n\t} else {\r\n\t\treturn requestFn.call(window, bind(fn, context));\r\n\t}\r\n}\r\n\r\n// @function cancelAnimFrame(id: Number): undefined\r\n// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).\r\nexport function cancelAnimFrame(id) {\r\n\tif (id) {\r\n\t\tcancelFn.call(window, id);\r\n\t}\r\n}\r\n","import * as Util from './Util';\r\n\r\n// @class Class\r\n// @aka L.Class\r\n\r\n// @section\r\n// @uninheritable\r\n\r\n// Thanks to John Resig and Dean Edwards for inspiration!\r\n\r\nexport function Class() {}\r\n\r\nClass.extend = function (props) {\r\n\r\n\t// @function extend(props: Object): Function\r\n\t// [Extends the current class](#class-inheritance) given the properties to be included.\r\n\t// Returns a Javascript function that is a class constructor (to be called with `new`).\r\n\tvar NewClass = function () {\r\n\r\n\t\tUtil.setOptions(this);\r\n\r\n\t\t// call the constructor\r\n\t\tif (this.initialize) {\r\n\t\t\tthis.initialize.apply(this, arguments);\r\n\t\t}\r\n\r\n\t\t// call all constructor hooks\r\n\t\tthis.callInitHooks();\r\n\t};\r\n\r\n\tvar parentProto = NewClass.__super__ = this.prototype;\r\n\r\n\tvar proto = Util.create(parentProto);\r\n\tproto.constructor = NewClass;\r\n\r\n\tNewClass.prototype = proto;\r\n\r\n\t// inherit parent's statics\r\n\tfor (var i in this) {\r\n\t\tif (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') {\r\n\t\t\tNewClass[i] = this[i];\r\n\t\t}\r\n\t}\r\n\r\n\t// mix static properties into the class\r\n\tif (props.statics) {\r\n\t\tUtil.extend(NewClass, props.statics);\r\n\t}\r\n\r\n\t// mix includes into the prototype\r\n\tif (props.includes) {\r\n\t\tcheckDeprecatedMixinEvents(props.includes);\r\n\t\tUtil.extend.apply(null, [proto].concat(props.includes));\r\n\t}\r\n\r\n\t// mix given properties into the prototype\r\n\tUtil.extend(proto, props);\r\n\tdelete proto.statics;\r\n\tdelete proto.includes;\r\n\r\n\t// merge options\r\n\tif (proto.options) {\r\n\t\tproto.options = parentProto.options ? Util.create(parentProto.options) : {};\r\n\t\tUtil.extend(proto.options, props.options);\r\n\t}\r\n\r\n\tproto._initHooks = [];\r\n\r\n\t// add method for calling all hooks\r\n\tproto.callInitHooks = function () {\r\n\r\n\t\tif (this._initHooksCalled) { return; }\r\n\r\n\t\tif (parentProto.callInitHooks) {\r\n\t\t\tparentProto.callInitHooks.call(this);\r\n\t\t}\r\n\r\n\t\tthis._initHooksCalled = true;\r\n\r\n\t\tfor (var i = 0, len = proto._initHooks.length; i < len; i++) {\r\n\t\t\tproto._initHooks[i].call(this);\r\n\t\t}\r\n\t};\r\n\r\n\treturn NewClass;\r\n};\r\n\r\n\r\n// @function include(properties: Object): this\r\n// [Includes a mixin](#class-includes) into the current class.\r\nClass.include = function (props) {\r\n\tvar parentOptions = this.prototype.options;\r\n\tUtil.extend(this.prototype, props);\r\n\tif (props.options) {\r\n\t\tthis.prototype.options = parentOptions;\r\n\t\tthis.mergeOptions(props.options);\r\n\t}\r\n\treturn this;\r\n};\r\n\r\n// @function mergeOptions(options: Object): this\r\n// [Merges `options`](#class-options) into the defaults of the class.\r\nClass.mergeOptions = function (options) {\r\n\tUtil.extend(this.prototype.options, options);\r\n\treturn this;\r\n};\r\n\r\n// @function addInitHook(fn: Function): this\r\n// Adds a [constructor hook](#class-constructor-hooks) to the class.\r\nClass.addInitHook = function (fn) { // (Function) || (String, args...)\r\n\tvar args = Array.prototype.slice.call(arguments, 1);\r\n\r\n\tvar init = typeof fn === 'function' ? fn : function () {\r\n\t\tthis[fn].apply(this, args);\r\n\t};\r\n\r\n\tthis.prototype._initHooks = this.prototype._initHooks || [];\r\n\tthis.prototype._initHooks.push(init);\r\n\treturn this;\r\n};\r\n\r\nfunction checkDeprecatedMixinEvents(includes) {\r\n\t/* global L: true */\r\n\tif (typeof L === 'undefined' || !L || !L.Mixin) { return; }\r\n\r\n\tincludes = Util.isArray(includes) ? includes : [includes];\r\n\r\n\tfor (var i = 0; i < includes.length; i++) {\r\n\t\tif (includes[i] === L.Mixin.Events) {\r\n\t\t\tconsole.warn('Deprecated include of L.Mixin.Events: ' +\r\n\t\t\t\t'this property will be removed in future releases, ' +\r\n\t\t\t\t'please inherit from L.Evented instead.', new Error().stack);\r\n\t\t}\r\n\t}\r\n}\r\n","import {Class} from './Class';\r\nimport * as Util from './Util';\r\n\r\n/*\r\n * @class Evented\r\n * @aka L.Evented\r\n * @inherits Class\r\n *\r\n * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * map.on('click', function(e) {\r\n * \talert(e.latlng);\r\n * } );\r\n * ```\r\n *\r\n * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:\r\n *\r\n * ```js\r\n * function onClick(e) { ... }\r\n *\r\n * map.on('click', onClick);\r\n * map.off('click', onClick);\r\n * ```\r\n */\r\n\r\nexport var Events = {\r\n\t/* @method on(type: String, fn: Function, context?: Object): this\r\n\t * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).\r\n\t *\r\n\t * @alternative\r\n\t * @method on(eventMap: Object): this\r\n\t * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\t */\r\n\ton: function (types, fn, context) {\r\n\r\n\t\t// types can be a map of types/handlers\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\t// we don't process space-separated events here for performance;\r\n\t\t\t\t// it's a hot path since Layer uses the on(obj) syntax\r\n\t\t\t\tthis._on(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// types can be a string of space-separated words\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t/* @method off(type: String, fn?: Function, context?: Object): this\r\n\t * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.\r\n\t *\r\n\t * @alternative\r\n\t * @method off(eventMap: Object): this\r\n\t * Removes a set of type/listener pairs.\r\n\t *\r\n\t * @alternative\r\n\t * @method off: this\r\n\t * Removes all listeners to all events on the object. This includes implicitly attached events.\r\n\t */\r\n\toff: function (types, fn, context) {\r\n\r\n\t\tif (!arguments.length) {\r\n\t\t\t// clear all listeners if called without arguments\r\n\t\t\tdelete this._events;\r\n\r\n\t\t} else if (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis._off(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tvar removeAll = arguments.length === 1;\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tif (removeAll) {\r\n\t\t\t\t\tthis._off(types[i]);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis._off(types[i], fn, context);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// attach listener (without syntactic sugar now)\r\n\t_on: function (type, fn, context, _once) {\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tconsole.warn('wrong listener type: ' + typeof fn);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// check if fn already there\r\n\t\tif (this._listens(type, fn, context) !== false) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\t// Less memory footprint.\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tvar newListener = {fn: fn, ctx: context};\r\n\t\tif (_once) {\r\n\t\t\tnewListener.once = true;\r\n\t\t}\r\n\r\n\t\tthis._events = this._events || {};\r\n\t\tthis._events[type] = this._events[type] || [];\r\n\t\tthis._events[type].push(newListener);\r\n\t},\r\n\r\n\t_off: function (type, fn, context) {\r\n\t\tvar listeners,\r\n\t\t i,\r\n\t\t len;\r\n\r\n\t\tif (!this._events) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlisteners = this._events[type];\r\n\t\tif (!listeners) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (arguments.length === 1) { // remove all\r\n\t\t\tif (this._firingCount) {\r\n\t\t\t\t// Set all removed listeners to noop\r\n\t\t\t\t// so they are not called if remove happens in fire\r\n\t\t\t\tfor (i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\t\tlisteners[i].fn = Util.falseFn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// clear all listeners for a type if function isn't specified\r\n\t\t\tdelete this._events[type];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tconsole.warn('wrong listener type: ' + typeof fn);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// find fn and remove it\r\n\t\tvar index = this._listens(type, fn, context);\r\n\t\tif (index !== false) {\r\n\t\t\tvar listener = listeners[index];\r\n\t\t\tif (this._firingCount) {\r\n\t\t\t\t// set the removed listener to noop so that's not called if remove happens in fire\r\n\t\t\t\tlistener.fn = Util.falseFn;\r\n\r\n\t\t\t\t/* copy array in case events are being fired */\r\n\t\t\t\tthis._events[type] = listeners = listeners.slice();\r\n\t\t\t}\r\n\t\t\tlisteners.splice(index, 1);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method fire(type: String, data?: Object, propagate?: Boolean): this\r\n\t// Fires an event of the specified type. You can optionally provide a data\r\n\t// object — the first argument of the listener function will contain its\r\n\t// properties. The event can optionally be propagated to event parents.\r\n\tfire: function (type, data, propagate) {\r\n\t\tif (!this.listens(type, propagate)) { return this; }\r\n\r\n\t\tvar event = Util.extend({}, data, {\r\n\t\t\ttype: type,\r\n\t\t\ttarget: this,\r\n\t\t\tsourceTarget: data && data.sourceTarget || this\r\n\t\t});\r\n\r\n\t\tif (this._events) {\r\n\t\t\tvar listeners = this._events[type];\r\n\t\t\tif (listeners) {\r\n\t\t\t\tthis._firingCount = (this._firingCount + 1) || 1;\r\n\t\t\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\t\tvar l = listeners[i];\r\n\t\t\t\t\t// off overwrites l.fn, so we need to copy fn to a var\r\n\t\t\t\t\tvar fn = l.fn;\r\n\t\t\t\t\tif (l.once) {\r\n\t\t\t\t\t\tthis.off(type, fn, l.ctx);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfn.call(l.ctx || this, event);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._firingCount--;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// propagate the event to parents (set with addEventParent)\r\n\t\t\tthis._propagateEvent(event);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method listens(type: String, propagate?: Boolean): Boolean\r\n\t// @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean\r\n\t// Returns `true` if a particular event type has any listeners attached to it.\r\n\t// The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.\r\n\tlistens: function (type, fn, context, propagate) {\r\n\t\tif (typeof type !== 'string') {\r\n\t\t\tconsole.warn('\"string\" type argument expected');\r\n\t\t}\r\n\r\n\t\t// we don't overwrite the input `fn` value, because we need to use it for propagation\r\n\t\tvar _fn = fn;\r\n\t\tif (typeof fn !== 'function') {\r\n\t\t\tpropagate = !!fn;\r\n\t\t\t_fn = undefined;\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tvar listeners = this._events && this._events[type];\r\n\t\tif (listeners && listeners.length) {\r\n\t\t\tif (this._listens(type, _fn, context) !== false) {\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// also check parents for listeners if event propagates\r\n\t\t\tfor (var id in this._eventParents) {\r\n\t\t\t\tif (this._eventParents[id].listens(type, fn, context, propagate)) { return true; }\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t},\r\n\r\n\t// returns the index (number) or false\r\n\t_listens: function (type, fn, context) {\r\n\t\tif (!this._events) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tvar listeners = this._events[type] || [];\r\n\t\tif (!fn) {\r\n\t\t\treturn !!listeners.length;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\t// Less memory footprint.\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\tif (listeners[i].fn === fn && listeners[i].ctx === context) {\r\n\t\t\t\treturn i;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\r\n\t},\r\n\r\n\t// @method once(…): this\r\n\t// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.\r\n\tonce: function (types, fn, context) {\r\n\r\n\t\t// types can be a map of types/handlers\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\t// we don't process space-separated events here for performance;\r\n\t\t\t\t// it's a hot path since Layer uses the on(obj) syntax\r\n\t\t\t\tthis._on(type, types[type], fn, true);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// types can be a string of space-separated words\r\n\t\t\ttypes = Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(types[i], fn, context, true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addEventParent(obj: Evented): this\r\n\t// Adds an event parent - an `Evented` that will receive propagated events\r\n\taddEventParent: function (obj) {\r\n\t\tthis._eventParents = this._eventParents || {};\r\n\t\tthis._eventParents[Util.stamp(obj)] = obj;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeEventParent(obj: Evented): this\r\n\t// Removes an event parent, so it will stop receiving propagated events\r\n\tremoveEventParent: function (obj) {\r\n\t\tif (this._eventParents) {\r\n\t\t\tdelete this._eventParents[Util.stamp(obj)];\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_propagateEvent: function (e) {\r\n\t\tfor (var id in this._eventParents) {\r\n\t\t\tthis._eventParents[id].fire(e.type, Util.extend({\r\n\t\t\t\tlayer: e.target,\r\n\t\t\t\tpropagatedFrom: e.target\r\n\t\t\t}, e), true);\r\n\t\t}\r\n\t}\r\n};\r\n\r\n// aliases; we should ditch those eventually\r\n\r\n// @method addEventListener(…): this\r\n// Alias to [`on(…)`](#evented-on)\r\nEvents.addEventListener = Events.on;\r\n\r\n// @method removeEventListener(…): this\r\n// Alias to [`off(…)`](#evented-off)\r\n\r\n// @method clearAllEventListeners(…): this\r\n// Alias to [`off()`](#evented-off)\r\nEvents.removeEventListener = Events.clearAllEventListeners = Events.off;\r\n\r\n// @method addOneTimeEventListener(…): this\r\n// Alias to [`once(…)`](#evented-once)\r\nEvents.addOneTimeEventListener = Events.once;\r\n\r\n// @method fireEvent(…): this\r\n// Alias to [`fire(…)`](#evented-fire)\r\nEvents.fireEvent = Events.fire;\r\n\r\n// @method hasEventListeners(…): Boolean\r\n// Alias to [`listens(…)`](#evented-listens)\r\nEvents.hasEventListeners = Events.listens;\r\n\r\nexport var Evented = Class.extend(Events);\r\n","import {isArray, formatNum} from '../core/Util';\r\n\r\n/*\r\n * @class Point\r\n * @aka L.Point\r\n *\r\n * Represents a point with `x` and `y` coordinates in pixels.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var point = L.point(200, 300);\r\n * ```\r\n *\r\n * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:\r\n *\r\n * ```js\r\n * map.panBy([200, 300]);\r\n * map.panBy(L.point(200, 300));\r\n * ```\r\n *\r\n * Note that `Point` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function Point(x, y, round) {\r\n\t// @property x: Number; The `x` coordinate of the point\r\n\tthis.x = (round ? Math.round(x) : x);\r\n\t// @property y: Number; The `y` coordinate of the point\r\n\tthis.y = (round ? Math.round(y) : y);\r\n}\r\n\r\nvar trunc = Math.trunc || function (v) {\r\n\treturn v > 0 ? Math.floor(v) : Math.ceil(v);\r\n};\r\n\r\nPoint.prototype = {\r\n\r\n\t// @method clone(): Point\r\n\t// Returns a copy of the current point.\r\n\tclone: function () {\r\n\t\treturn new Point(this.x, this.y);\r\n\t},\r\n\r\n\t// @method add(otherPoint: Point): Point\r\n\t// Returns the result of addition of the current and the given points.\r\n\tadd: function (point) {\r\n\t\t// non-destructive, returns a new point\r\n\t\treturn this.clone()._add(toPoint(point));\r\n\t},\r\n\r\n\t_add: function (point) {\r\n\t\t// destructive, used directly for performance in situations where it's safe to modify existing point\r\n\t\tthis.x += point.x;\r\n\t\tthis.y += point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method subtract(otherPoint: Point): Point\r\n\t// Returns the result of subtraction of the given point from the current.\r\n\tsubtract: function (point) {\r\n\t\treturn this.clone()._subtract(toPoint(point));\r\n\t},\r\n\r\n\t_subtract: function (point) {\r\n\t\tthis.x -= point.x;\r\n\t\tthis.y -= point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method divideBy(num: Number): Point\r\n\t// Returns the result of division of the current point by the given number.\r\n\tdivideBy: function (num) {\r\n\t\treturn this.clone()._divideBy(num);\r\n\t},\r\n\r\n\t_divideBy: function (num) {\r\n\t\tthis.x /= num;\r\n\t\tthis.y /= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method multiplyBy(num: Number): Point\r\n\t// Returns the result of multiplication of the current point by the given number.\r\n\tmultiplyBy: function (num) {\r\n\t\treturn this.clone()._multiplyBy(num);\r\n\t},\r\n\r\n\t_multiplyBy: function (num) {\r\n\t\tthis.x *= num;\r\n\t\tthis.y *= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method scaleBy(scale: Point): Point\r\n\t// Multiply each coordinate of the current point by each coordinate of\r\n\t// `scale`. In linear algebra terms, multiply the point by the\r\n\t// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)\r\n\t// defined by `scale`.\r\n\tscaleBy: function (point) {\r\n\t\treturn new Point(this.x * point.x, this.y * point.y);\r\n\t},\r\n\r\n\t// @method unscaleBy(scale: Point): Point\r\n\t// Inverse of `scaleBy`. Divide each coordinate of the current point by\r\n\t// each coordinate of `scale`.\r\n\tunscaleBy: function (point) {\r\n\t\treturn new Point(this.x / point.x, this.y / point.y);\r\n\t},\r\n\r\n\t// @method round(): Point\r\n\t// Returns a copy of the current point with rounded coordinates.\r\n\tround: function () {\r\n\t\treturn this.clone()._round();\r\n\t},\r\n\r\n\t_round: function () {\r\n\t\tthis.x = Math.round(this.x);\r\n\t\tthis.y = Math.round(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method floor(): Point\r\n\t// Returns a copy of the current point with floored coordinates (rounded down).\r\n\tfloor: function () {\r\n\t\treturn this.clone()._floor();\r\n\t},\r\n\r\n\t_floor: function () {\r\n\t\tthis.x = Math.floor(this.x);\r\n\t\tthis.y = Math.floor(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method ceil(): Point\r\n\t// Returns a copy of the current point with ceiled coordinates (rounded up).\r\n\tceil: function () {\r\n\t\treturn this.clone()._ceil();\r\n\t},\r\n\r\n\t_ceil: function () {\r\n\t\tthis.x = Math.ceil(this.x);\r\n\t\tthis.y = Math.ceil(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method trunc(): Point\r\n\t// Returns a copy of the current point with truncated coordinates (rounded towards zero).\r\n\ttrunc: function () {\r\n\t\treturn this.clone()._trunc();\r\n\t},\r\n\r\n\t_trunc: function () {\r\n\t\tthis.x = trunc(this.x);\r\n\t\tthis.y = trunc(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method distanceTo(otherPoint: Point): Number\r\n\t// Returns the cartesian distance between the current and the given points.\r\n\tdistanceTo: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\tvar x = point.x - this.x,\r\n\t\t y = point.y - this.y;\r\n\r\n\t\treturn Math.sqrt(x * x + y * y);\r\n\t},\r\n\r\n\t// @method equals(otherPoint: Point): Boolean\r\n\t// Returns `true` if the given point has the same coordinates.\r\n\tequals: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\treturn point.x === this.x &&\r\n\t\t point.y === this.y;\r\n\t},\r\n\r\n\t// @method contains(otherPoint: Point): Boolean\r\n\t// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).\r\n\tcontains: function (point) {\r\n\t\tpoint = toPoint(point);\r\n\r\n\t\treturn Math.abs(point.x) <= Math.abs(this.x) &&\r\n\t\t Math.abs(point.y) <= Math.abs(this.y);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point for debugging purposes.\r\n\ttoString: function () {\r\n\t\treturn 'Point(' +\r\n\t\t formatNum(this.x) + ', ' +\r\n\t\t formatNum(this.y) + ')';\r\n\t}\r\n};\r\n\r\n// @factory L.point(x: Number, y: Number, round?: Boolean)\r\n// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Number[])\r\n// Expects an array of the form `[x, y]` instead.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Object)\r\n// Expects a plain object of the form `{x: Number, y: Number}` instead.\r\nexport function toPoint(x, y, round) {\r\n\tif (x instanceof Point) {\r\n\t\treturn x;\r\n\t}\r\n\tif (isArray(x)) {\r\n\t\treturn new Point(x[0], x[1]);\r\n\t}\r\n\tif (x === undefined || x === null) {\r\n\t\treturn x;\r\n\t}\r\n\tif (typeof x === 'object' && 'x' in x && 'y' in x) {\r\n\t\treturn new Point(x.x, x.y);\r\n\t}\r\n\treturn new Point(x, y, round);\r\n}\r\n","import {Point, toPoint} from './Point';\r\n\r\n/*\r\n * @class Bounds\r\n * @aka L.Bounds\r\n *\r\n * Represents a rectangular area in pixel coordinates.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var p1 = L.point(10, 10),\r\n * p2 = L.point(40, 60),\r\n * bounds = L.bounds(p1, p2);\r\n * ```\r\n *\r\n * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:\r\n *\r\n * ```js\r\n * otherBounds.intersects([[10, 10], [40, 60]]);\r\n * ```\r\n *\r\n * Note that `Bounds` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function Bounds(a, b) {\r\n\tif (!a) { return; }\r\n\r\n\tvar points = b ? [a, b] : a;\r\n\r\n\tfor (var i = 0, len = points.length; i < len; i++) {\r\n\t\tthis.extend(points[i]);\r\n\t}\r\n}\r\n\r\nBounds.prototype = {\r\n\t// @method extend(point: Point): this\r\n\t// Extends the bounds to contain the given point.\r\n\r\n\t// @alternative\r\n\t// @method extend(otherBounds: Bounds): this\r\n\t// Extend the bounds to contain the given bounds\r\n\textend: function (obj) {\r\n\t\tvar min2, max2;\r\n\t\tif (!obj) { return this; }\r\n\r\n\t\tif (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) {\r\n\t\t\tmin2 = max2 = toPoint(obj);\r\n\t\t} else {\r\n\t\t\tobj = toBounds(obj);\r\n\t\t\tmin2 = obj.min;\r\n\t\t\tmax2 = obj.max;\r\n\r\n\t\t\tif (!min2 || !max2) { return this; }\r\n\t\t}\r\n\r\n\t\t// @property min: Point\r\n\t\t// The top left corner of the rectangle.\r\n\t\t// @property max: Point\r\n\t\t// The bottom right corner of the rectangle.\r\n\t\tif (!this.min && !this.max) {\r\n\t\t\tthis.min = min2.clone();\r\n\t\t\tthis.max = max2.clone();\r\n\t\t} else {\r\n\t\t\tthis.min.x = Math.min(min2.x, this.min.x);\r\n\t\t\tthis.max.x = Math.max(max2.x, this.max.x);\r\n\t\t\tthis.min.y = Math.min(min2.y, this.min.y);\r\n\t\t\tthis.max.y = Math.max(max2.y, this.max.y);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getCenter(round?: Boolean): Point\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function (round) {\r\n\t\treturn toPoint(\r\n\t\t (this.min.x + this.max.x) / 2,\r\n\t\t (this.min.y + this.max.y) / 2, round);\r\n\t},\r\n\r\n\t// @method getBottomLeft(): Point\r\n\t// Returns the bottom-left point of the bounds.\r\n\tgetBottomLeft: function () {\r\n\t\treturn toPoint(this.min.x, this.max.y);\r\n\t},\r\n\r\n\t// @method getTopRight(): Point\r\n\t// Returns the top-right point of the bounds.\r\n\tgetTopRight: function () { // -> Point\r\n\t\treturn toPoint(this.max.x, this.min.y);\r\n\t},\r\n\r\n\t// @method getTopLeft(): Point\r\n\t// Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).\r\n\tgetTopLeft: function () {\r\n\t\treturn this.min; // left, top\r\n\t},\r\n\r\n\t// @method getBottomRight(): Point\r\n\t// Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).\r\n\tgetBottomRight: function () {\r\n\t\treturn this.max; // right, bottom\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the size of the given bounds\r\n\tgetSize: function () {\r\n\t\treturn this.max.subtract(this.min);\r\n\t},\r\n\r\n\t// @method contains(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\t// @alternative\r\n\t// @method contains(point: Point): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) {\r\n\t\tvar min, max;\r\n\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof Point) {\r\n\t\t\tobj = toPoint(obj);\r\n\t\t} else {\r\n\t\t\tobj = toBounds(obj);\r\n\t\t}\r\n\r\n\t\tif (obj instanceof Bounds) {\r\n\t\t\tmin = obj.min;\r\n\t\t\tmax = obj.max;\r\n\t\t} else {\r\n\t\t\tmin = max = obj;\r\n\t\t}\r\n\r\n\t\treturn (min.x >= this.min.x) &&\r\n\t\t (max.x <= this.max.x) &&\r\n\t\t (min.y >= this.min.y) &&\r\n\t\t (max.y <= this.max.y);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds\r\n\t// intersect if they have at least one point in common.\r\n\tintersects: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t max = this.max,\r\n\t\t min2 = bounds.min,\r\n\t\t max2 = bounds.max,\r\n\t\t xIntersects = (max2.x >= min.x) && (min2.x <= max.x),\r\n\t\t yIntersects = (max2.y >= min.y) && (min2.y <= max.y);\r\n\r\n\t\treturn xIntersects && yIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds\r\n\t// overlap if their intersection is an area.\r\n\toverlaps: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t max = this.max,\r\n\t\t min2 = bounds.min,\r\n\t\t max2 = bounds.max,\r\n\t\t xOverlaps = (max2.x > min.x) && (min2.x < max.x),\r\n\t\t yOverlaps = (max2.y > min.y) && (min2.y < max.y);\r\n\r\n\t\treturn xOverlaps && yOverlaps;\r\n\t},\r\n\r\n\t// @method isValid(): Boolean\r\n\t// Returns `true` if the bounds are properly initialized.\r\n\tisValid: function () {\r\n\t\treturn !!(this.min && this.max);\r\n\t},\r\n\r\n\r\n\t// @method pad(bufferRatio: Number): Bounds\r\n\t// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.\r\n\t// For example, a ratio of 0.5 extends the bounds by 50% in each direction.\r\n\t// Negative values will retract the bounds.\r\n\tpad: function (bufferRatio) {\r\n\t\tvar min = this.min,\r\n\t\tmax = this.max,\r\n\t\theightBuffer = Math.abs(min.x - max.x) * bufferRatio,\r\n\t\twidthBuffer = Math.abs(min.y - max.y) * bufferRatio;\r\n\r\n\r\n\t\treturn toBounds(\r\n\t\t\ttoPoint(min.x - heightBuffer, min.y - widthBuffer),\r\n\t\t\ttoPoint(max.x + heightBuffer, max.y + widthBuffer));\r\n\t},\r\n\r\n\r\n\t// @method equals(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle is equivalent to the given bounds.\r\n\tequals: function (bounds) {\r\n\t\tif (!bounds) { return false; }\r\n\r\n\t\tbounds = toBounds(bounds);\r\n\r\n\t\treturn this.min.equals(bounds.getTopLeft()) &&\r\n\t\t\tthis.max.equals(bounds.getBottomRight());\r\n\t},\r\n};\r\n\r\n\r\n// @factory L.bounds(corner1: Point, corner2: Point)\r\n// Creates a Bounds object from two corners coordinate pairs.\r\n// @alternative\r\n// @factory L.bounds(points: Point[])\r\n// Creates a Bounds object from the given array of points.\r\nexport function toBounds(a, b) {\r\n\tif (!a || a instanceof Bounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new Bounds(a, b);\r\n}\r\n","import {LatLng, toLatLng} from './LatLng';\r\n\r\n/*\r\n * @class LatLngBounds\r\n * @aka L.LatLngBounds\r\n *\r\n * Represents a rectangular geographical area on a map.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var corner1 = L.latLng(40.712, -74.227),\r\n * corner2 = L.latLng(40.774, -74.125),\r\n * bounds = L.latLngBounds(corner1, corner2);\r\n * ```\r\n *\r\n * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:\r\n *\r\n * ```js\r\n * map.fitBounds([\r\n * \t[40.712, -74.227],\r\n * \t[40.774, -74.125]\r\n * ]);\r\n * ```\r\n *\r\n * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.\r\n *\r\n * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])\r\n\tif (!corner1) { return; }\r\n\r\n\tvar latlngs = corner2 ? [corner1, corner2] : corner1;\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\tthis.extend(latlngs[i]);\r\n\t}\r\n}\r\n\r\nLatLngBounds.prototype = {\r\n\r\n\t// @method extend(latlng: LatLng): this\r\n\t// Extend the bounds to contain the given point\r\n\r\n\t// @alternative\r\n\t// @method extend(otherBounds: LatLngBounds): this\r\n\t// Extend the bounds to contain the given bounds\r\n\textend: function (obj) {\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2, ne2;\r\n\r\n\t\tif (obj instanceof LatLng) {\r\n\t\t\tsw2 = obj;\r\n\t\t\tne2 = obj;\r\n\r\n\t\t} else if (obj instanceof LatLngBounds) {\r\n\t\t\tsw2 = obj._southWest;\r\n\t\t\tne2 = obj._northEast;\r\n\r\n\t\t\tif (!sw2 || !ne2) { return this; }\r\n\r\n\t\t} else {\r\n\t\t\treturn obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;\r\n\t\t}\r\n\r\n\t\tif (!sw && !ne) {\r\n\t\t\tthis._southWest = new LatLng(sw2.lat, sw2.lng);\r\n\t\t\tthis._northEast = new LatLng(ne2.lat, ne2.lng);\r\n\t\t} else {\r\n\t\t\tsw.lat = Math.min(sw2.lat, sw.lat);\r\n\t\t\tsw.lng = Math.min(sw2.lng, sw.lng);\r\n\t\t\tne.lat = Math.max(ne2.lat, ne.lat);\r\n\t\t\tne.lng = Math.max(ne2.lng, ne.lng);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method pad(bufferRatio: Number): LatLngBounds\r\n\t// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.\r\n\t// For example, a ratio of 0.5 extends the bounds by 50% in each direction.\r\n\t// Negative values will retract the bounds.\r\n\tpad: function (bufferRatio) {\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,\r\n\t\t widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;\r\n\r\n\t\treturn new LatLngBounds(\r\n\t\t new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),\r\n\t\t new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));\r\n\t},\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function () {\r\n\t\treturn new LatLng(\r\n\t\t (this._southWest.lat + this._northEast.lat) / 2,\r\n\t\t (this._southWest.lng + this._northEast.lng) / 2);\r\n\t},\r\n\r\n\t// @method getSouthWest(): LatLng\r\n\t// Returns the south-west point of the bounds.\r\n\tgetSouthWest: function () {\r\n\t\treturn this._southWest;\r\n\t},\r\n\r\n\t// @method getNorthEast(): LatLng\r\n\t// Returns the north-east point of the bounds.\r\n\tgetNorthEast: function () {\r\n\t\treturn this._northEast;\r\n\t},\r\n\r\n\t// @method getNorthWest(): LatLng\r\n\t// Returns the north-west point of the bounds.\r\n\tgetNorthWest: function () {\r\n\t\treturn new LatLng(this.getNorth(), this.getWest());\r\n\t},\r\n\r\n\t// @method getSouthEast(): LatLng\r\n\t// Returns the south-east point of the bounds.\r\n\tgetSouthEast: function () {\r\n\t\treturn new LatLng(this.getSouth(), this.getEast());\r\n\t},\r\n\r\n\t// @method getWest(): Number\r\n\t// Returns the west longitude of the bounds\r\n\tgetWest: function () {\r\n\t\treturn this._southWest.lng;\r\n\t},\r\n\r\n\t// @method getSouth(): Number\r\n\t// Returns the south latitude of the bounds\r\n\tgetSouth: function () {\r\n\t\treturn this._southWest.lat;\r\n\t},\r\n\r\n\t// @method getEast(): Number\r\n\t// Returns the east longitude of the bounds\r\n\tgetEast: function () {\r\n\t\treturn this._northEast.lng;\r\n\t},\r\n\r\n\t// @method getNorth(): Number\r\n\t// Returns the north latitude of the bounds\r\n\tgetNorth: function () {\r\n\t\treturn this._northEast.lat;\r\n\t},\r\n\r\n\t// @method contains(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\r\n\t// @alternative\r\n\t// @method contains (latlng: LatLng): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {\r\n\t\t\tobj = toLatLng(obj);\r\n\t\t} else {\r\n\t\t\tobj = toLatLngBounds(obj);\r\n\t\t}\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2, ne2;\r\n\r\n\t\tif (obj instanceof LatLngBounds) {\r\n\t\t\tsw2 = obj.getSouthWest();\r\n\t\t\tne2 = obj.getNorthEast();\r\n\t\t} else {\r\n\t\t\tsw2 = ne2 = obj;\r\n\t\t}\r\n\r\n\t\treturn (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&\r\n\t\t (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.\r\n\tintersects: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2 = bounds.getSouthWest(),\r\n\t\t ne2 = bounds.getNorthEast(),\r\n\r\n\t\t latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),\r\n\t\t lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);\r\n\r\n\t\treturn latIntersects && lngIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.\r\n\toverlaps: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t ne = this._northEast,\r\n\t\t sw2 = bounds.getSouthWest(),\r\n\t\t ne2 = bounds.getNorthEast(),\r\n\r\n\t\t latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),\r\n\t\t lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);\r\n\r\n\t\treturn latOverlaps && lngOverlaps;\r\n\t},\r\n\r\n\t// @method toBBoxString(): String\r\n\t// Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.\r\n\ttoBBoxString: function () {\r\n\t\treturn [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');\r\n\t},\r\n\r\n\t// @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean\r\n\t// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.\r\n\tequals: function (bounds, maxMargin) {\r\n\t\tif (!bounds) { return false; }\r\n\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\treturn this._southWest.equals(bounds.getSouthWest(), maxMargin) &&\r\n\t\t this._northEast.equals(bounds.getNorthEast(), maxMargin);\r\n\t},\r\n\r\n\t// @method isValid(): Boolean\r\n\t// Returns `true` if the bounds are properly initialized.\r\n\tisValid: function () {\r\n\t\treturn !!(this._southWest && this._northEast);\r\n\t}\r\n};\r\n\r\n// TODO International date line?\r\n\r\n// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)\r\n// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.\r\n\r\n// @alternative\r\n// @factory L.latLngBounds(latlngs: LatLng[])\r\n// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).\r\nexport function toLatLngBounds(a, b) {\r\n\tif (a instanceof LatLngBounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new LatLngBounds(a, b);\r\n}\r\n","import * as Util from '../core/Util';\r\nimport {Earth} from './crs/CRS.Earth';\r\nimport {toLatLngBounds} from './LatLngBounds';\r\n\r\n/* @class LatLng\r\n * @aka L.LatLng\r\n *\r\n * Represents a geographical point with a certain latitude and longitude.\r\n *\r\n * @example\r\n *\r\n * ```\r\n * var latlng = L.latLng(50.5, 30.5);\r\n * ```\r\n *\r\n * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:\r\n *\r\n * ```\r\n * map.panTo([50, 30]);\r\n * map.panTo({lon: 30, lat: 50});\r\n * map.panTo({lat: 50, lng: 30});\r\n * map.panTo(L.latLng(50, 30));\r\n * ```\r\n *\r\n * Note that `LatLng` does not inherit from Leaflet's `Class` object,\r\n * which means new classes can't inherit from it, and new methods\r\n * can't be added to it with the `include` function.\r\n */\r\n\r\nexport function LatLng(lat, lng, alt) {\r\n\tif (isNaN(lat) || isNaN(lng)) {\r\n\t\tthrow new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\r\n\t}\r\n\r\n\t// @property lat: Number\r\n\t// Latitude in degrees\r\n\tthis.lat = +lat;\r\n\r\n\t// @property lng: Number\r\n\t// Longitude in degrees\r\n\tthis.lng = +lng;\r\n\r\n\t// @property alt: Number\r\n\t// Altitude in meters (optional)\r\n\tif (alt !== undefined) {\r\n\t\tthis.alt = +alt;\r\n\t}\r\n}\r\n\r\nLatLng.prototype = {\r\n\t// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean\r\n\t// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.\r\n\tequals: function (obj, maxMargin) {\r\n\t\tif (!obj) { return false; }\r\n\r\n\t\tobj = toLatLng(obj);\r\n\r\n\t\tvar margin = Math.max(\r\n\t\t Math.abs(this.lat - obj.lat),\r\n\t\t Math.abs(this.lng - obj.lng));\r\n\r\n\t\treturn margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point (for debugging purposes).\r\n\ttoString: function (precision) {\r\n\t\treturn 'LatLng(' +\r\n\t\t Util.formatNum(this.lat, precision) + ', ' +\r\n\t\t Util.formatNum(this.lng, precision) + ')';\r\n\t},\r\n\r\n\t// @method distanceTo(otherLatLng: LatLng): Number\r\n\t// Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).\r\n\tdistanceTo: function (other) {\r\n\t\treturn Earth.distance(this, toLatLng(other));\r\n\t},\r\n\r\n\t// @method wrap(): LatLng\r\n\t// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.\r\n\twrap: function () {\r\n\t\treturn Earth.wrapLatLng(this);\r\n\t},\r\n\r\n\t// @method toBounds(sizeInMeters: Number): LatLngBounds\r\n\t// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.\r\n\ttoBounds: function (sizeInMeters) {\r\n\t\tvar latAccuracy = 180 * sizeInMeters / 40075017,\r\n\t\t lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);\r\n\r\n\t\treturn toLatLngBounds(\r\n\t\t [this.lat - latAccuracy, this.lng - lngAccuracy],\r\n\t\t [this.lat + latAccuracy, this.lng + lngAccuracy]);\r\n\t},\r\n\r\n\tclone: function () {\r\n\t\treturn new LatLng(this.lat, this.lng, this.alt);\r\n\t}\r\n};\r\n\r\n\r\n\r\n// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng\r\n// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Array): LatLng\r\n// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Object): LatLng\r\n// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.\r\n\r\nexport function toLatLng(a, b, c) {\r\n\tif (a instanceof LatLng) {\r\n\t\treturn a;\r\n\t}\r\n\tif (Util.isArray(a) && typeof a[0] !== 'object') {\r\n\t\tif (a.length === 3) {\r\n\t\t\treturn new LatLng(a[0], a[1], a[2]);\r\n\t\t}\r\n\t\tif (a.length === 2) {\r\n\t\t\treturn new LatLng(a[0], a[1]);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\tif (a === undefined || a === null) {\r\n\t\treturn a;\r\n\t}\r\n\tif (typeof a === 'object' && 'lat' in a) {\r\n\t\treturn new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);\r\n\t}\r\n\tif (b === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\treturn new LatLng(a, b, c);\r\n}\r\n","\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {LatLng} from '../LatLng';\r\nimport {LatLngBounds} from '../LatLngBounds';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.Base\r\n * Object that defines coordinate reference systems for projecting\r\n * geographical points into pixel (screen) coordinates and back (and to\r\n * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See\r\n * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system).\r\n *\r\n * Leaflet defines the most usual CRSs by default. If you want to use a\r\n * CRS not defined by default, take a look at the\r\n * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.\r\n *\r\n * Note that the CRS instances do not inherit from Leaflet's `Class` object,\r\n * and can't be instantiated. Also, new classes can't inherit from them,\r\n * and methods can't be added to them with the `include` function.\r\n */\r\n\r\nexport var CRS = {\r\n\t// @method latLngToPoint(latlng: LatLng, zoom: Number): Point\r\n\t// Projects geographical coordinates into pixel coordinates for a given zoom.\r\n\tlatLngToPoint: function (latlng, zoom) {\r\n\t\tvar projectedPoint = this.projection.project(latlng),\r\n\t\t scale = this.scale(zoom);\r\n\r\n\t\treturn this.transformation._transform(projectedPoint, scale);\r\n\t},\r\n\r\n\t// @method pointToLatLng(point: Point, zoom: Number): LatLng\r\n\t// The inverse of `latLngToPoint`. Projects pixel coordinates on a given\r\n\t// zoom into geographical coordinates.\r\n\tpointToLatLng: function (point, zoom) {\r\n\t\tvar scale = this.scale(zoom),\r\n\t\t untransformedPoint = this.transformation.untransform(point, scale);\r\n\r\n\t\treturn this.projection.unproject(untransformedPoint);\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng): Point\r\n\t// Projects geographical coordinates into coordinates in units accepted for\r\n\t// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).\r\n\tproject: function (latlng) {\r\n\t\treturn this.projection.project(latlng);\r\n\t},\r\n\r\n\t// @method unproject(point: Point): LatLng\r\n\t// Given a projected coordinate returns the corresponding LatLng.\r\n\t// The inverse of `project`.\r\n\tunproject: function (point) {\r\n\t\treturn this.projection.unproject(point);\r\n\t},\r\n\r\n\t// @method scale(zoom: Number): Number\r\n\t// Returns the scale used when transforming projected coordinates into\r\n\t// pixel coordinates for a particular zoom. For example, it returns\r\n\t// `256 * 2^zoom` for Mercator-based CRS.\r\n\tscale: function (zoom) {\r\n\t\treturn 256 * Math.pow(2, zoom);\r\n\t},\r\n\r\n\t// @method zoom(scale: Number): Number\r\n\t// Inverse of `scale()`, returns the zoom level corresponding to a scale\r\n\t// factor of `scale`.\r\n\tzoom: function (scale) {\r\n\t\treturn Math.log(scale / 256) / Math.LN2;\r\n\t},\r\n\r\n\t// @method getProjectedBounds(zoom: Number): Bounds\r\n\t// Returns the projection's bounds scaled and transformed for the provided `zoom`.\r\n\tgetProjectedBounds: function (zoom) {\r\n\t\tif (this.infinite) { return null; }\r\n\r\n\t\tvar b = this.projection.bounds,\r\n\t\t s = this.scale(zoom),\r\n\t\t min = this.transformation.transform(b.min, s),\r\n\t\t max = this.transformation.transform(b.max, s);\r\n\r\n\t\treturn new Bounds(min, max);\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates.\r\n\r\n\t// @property code: String\r\n\t// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)\r\n\t//\r\n\t// @property wrapLng: Number[]\r\n\t// An array of two numbers defining whether the longitude (horizontal) coordinate\r\n\t// axis wraps around a given range and how. Defaults to `[-180, 180]` in most\r\n\t// geographical CRSs. If `undefined`, the longitude axis does not wrap around.\r\n\t//\r\n\t// @property wrapLat: Number[]\r\n\t// Like `wrapLng`, but for the latitude (vertical) axis.\r\n\r\n\t// wrapLng: [min, max],\r\n\t// wrapLat: [min, max],\r\n\r\n\t// @property infinite: Boolean\r\n\t// If true, the coordinate space will be unbounded (infinite in both axes)\r\n\tinfinite: false,\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where lat and lng has been wrapped according to the\r\n\t// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.\r\n\twrapLatLng: function (latlng) {\r\n\t\tvar lng = this.wrapLng ? Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,\r\n\t\t lat = this.wrapLat ? Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,\r\n\t\t alt = latlng.alt;\r\n\r\n\t\treturn new LatLng(lat, lng, alt);\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring\r\n\t// that its center is within the CRS's bounds.\r\n\t// Only accepts actual `L.LatLngBounds` instances, not arrays.\r\n\twrapLatLngBounds: function (bounds) {\r\n\t\tvar center = bounds.getCenter(),\r\n\t\t newCenter = this.wrapLatLng(center),\r\n\t\t latShift = center.lat - newCenter.lat,\r\n\t\t lngShift = center.lng - newCenter.lng;\r\n\r\n\t\tif (latShift === 0 && lngShift === 0) {\r\n\t\t\treturn bounds;\r\n\t\t}\r\n\r\n\t\tvar sw = bounds.getSouthWest(),\r\n\t\t ne = bounds.getNorthEast(),\r\n\t\t newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),\r\n\t\t newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);\r\n\r\n\t\treturn new LatLngBounds(newSw, newNe);\r\n\t}\r\n};\r\n","import {CRS} from './CRS';\nimport * as Util from '../../core/Util';\n\n/*\n * @namespace CRS\n * @crs L.CRS.Earth\n *\n * Serves as the base for CRS that are global such that they cover the earth.\n * Can only be used as the base for other CRS and cannot be used directly,\n * since it does not have a `code`, `projection` or `transformation`. `distance()` returns\n * meters.\n */\n\nexport var Earth = Util.extend({}, CRS, {\n\twrapLng: [-180, 180],\n\n\t// Mean Earth Radius, as recommended for use by\n\t// the International Union of Geodesy and Geophysics,\n\t// see https://rosettacode.org/wiki/Haversine_formula\n\tR: 6371000,\n\n\t// distance between two geographical points using spherical law of cosines approximation\n\tdistance: function (latlng1, latlng2) {\n\t\tvar rad = Math.PI / 180,\n\t\t lat1 = latlng1.lat * rad,\n\t\t lat2 = latlng2.lat * rad,\n\t\t sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),\n\t\t sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),\n\t\t a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,\n\t\t c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n\t\treturn this.R * c;\n\t}\n});\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @projection L.Projection.SphericalMercator\r\n *\r\n * Spherical Mercator projection — the most common projection for online maps,\r\n * used by almost all free and commercial tile providers. Assumes that Earth is\r\n * a sphere. Used by the `EPSG:3857` CRS.\r\n */\r\n\r\nvar earthRadius = 6378137;\r\n\r\nexport var SphericalMercator = {\r\n\r\n\tR: earthRadius,\r\n\tMAX_LATITUDE: 85.0511287798,\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t max = this.MAX_LATITUDE,\r\n\t\t lat = Math.max(Math.min(max, latlng.lat), -max),\r\n\t\t sin = Math.sin(lat * d);\r\n\r\n\t\treturn new Point(\r\n\t\t\tthis.R * latlng.lng * d,\r\n\t\t\tthis.R * Math.log((1 + sin) / (1 - sin)) / 2);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI;\r\n\r\n\t\treturn new LatLng(\r\n\t\t\t(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,\r\n\t\t\tpoint.x * d / this.R);\r\n\t},\r\n\r\n\tbounds: (function () {\r\n\t\tvar d = earthRadius * Math.PI;\r\n\t\treturn new Bounds([-d, -d], [d, d]);\r\n\t})()\r\n};\r\n","import {Point} from './Point';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class Transformation\r\n * @aka L.Transformation\r\n *\r\n * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`\r\n * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing\r\n * the reverse. Used by Leaflet in its projections code.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var transformation = L.transformation(2, 5, -1, 10),\r\n * \tp = L.point(1, 2),\r\n * \tp2 = transformation.transform(p), // L.point(7, 8)\r\n * \tp3 = transformation.untransform(p2); // L.point(1, 2)\r\n * ```\r\n */\r\n\r\n\r\n// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)\r\n// Creates a `Transformation` object with the given coefficients.\r\nexport function Transformation(a, b, c, d) {\r\n\tif (Util.isArray(a)) {\r\n\t\t// use array properties\r\n\t\tthis._a = a[0];\r\n\t\tthis._b = a[1];\r\n\t\tthis._c = a[2];\r\n\t\tthis._d = a[3];\r\n\t\treturn;\r\n\t}\r\n\tthis._a = a;\r\n\tthis._b = b;\r\n\tthis._c = c;\r\n\tthis._d = d;\r\n}\r\n\r\nTransformation.prototype = {\r\n\t// @method transform(point: Point, scale?: Number): Point\r\n\t// Returns a transformed point, optionally multiplied by the given scale.\r\n\t// Only accepts actual `L.Point` instances, not arrays.\r\n\ttransform: function (point, scale) { // (Point, Number) -> Point\r\n\t\treturn this._transform(point.clone(), scale);\r\n\t},\r\n\r\n\t// destructive transform (faster)\r\n\t_transform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\tpoint.x = scale * (this._a * point.x + this._b);\r\n\t\tpoint.y = scale * (this._c * point.y + this._d);\r\n\t\treturn point;\r\n\t},\r\n\r\n\t// @method untransform(point: Point, scale?: Number): Point\r\n\t// Returns the reverse transformation of the given point, optionally divided\r\n\t// by the given scale. Only accepts actual `L.Point` instances, not arrays.\r\n\tuntransform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\treturn new Point(\r\n\t\t (point.x / scale - this._b) / this._a,\r\n\t\t (point.y / scale - this._d) / this._c);\r\n\t}\r\n};\r\n\r\n// factory L.transformation(a: Number, b: Number, c: Number, d: Number)\r\n\r\n// @factory L.transformation(a: Number, b: Number, c: Number, d: Number)\r\n// Instantiates a Transformation object with the given coefficients.\r\n\r\n// @alternative\r\n// @factory L.transformation(coefficients: Array): Transformation\r\n// Expects an coefficients array of the form\r\n// `[a: Number, b: Number, c: Number, d: Number]`.\r\n\r\nexport function toTransformation(a, b, c, d) {\r\n\treturn new Transformation(a, b, c, d);\r\n}\r\n","import {Earth} from './CRS.Earth';\r\nimport {SphericalMercator} from '../projection/Projection.SphericalMercator';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3857\r\n *\r\n * The most common CRS for online maps, used by almost all free and commercial\r\n * tile providers. Uses Spherical Mercator projection. Set in by default in\r\n * Map's `crs` option.\r\n */\r\n\r\nexport var EPSG3857 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:3857',\r\n\tprojection: SphericalMercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * SphericalMercator.R);\r\n\t\treturn toTransformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n\r\nexport var EPSG900913 = Util.extend({}, EPSG3857, {\r\n\tcode: 'EPSG:900913'\r\n});\r\n","import Browser from '../../core/Browser';\n\n// @namespace SVG; @section\n// There are several static functions which can be called without instantiating L.SVG:\n\n// @function create(name: String): SVGElement\n// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),\n// corresponding to the class name passed. For example, using 'line' will return\n// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).\nexport function svgCreate(name) {\n\treturn document.createElementNS('http://www.w3.org/2000/svg', name);\n}\n\n// @function pointsToPath(rings: Point[], closed: Boolean): String\n// Generates a SVG path string for multiple rings, with each ring turning\n// into \"M..L..L..\" instructions\nexport function pointsToPath(rings, closed) {\n\tvar str = '',\n\ti, j, len, len2, points, p;\n\n\tfor (i = 0, len = rings.length; i < len; i++) {\n\t\tpoints = rings[i];\n\n\t\tfor (j = 0, len2 = points.length; j < len2; j++) {\n\t\t\tp = points[j];\n\t\t\tstr += (j ? 'L' : 'M') + p.x + ' ' + p.y;\n\t\t}\n\n\t\t// closes the ring for polygons; \"x\" is VML syntax\n\t\tstr += closed ? (Browser.svg ? 'z' : 'x') : '';\n\t}\n\n\t// SVG complains about empty path strings\n\treturn str || 'M0 0';\n}\n\n\n\n\n","import * as Util from './Util';\r\nimport {svgCreate} from '../layer/vector/SVG.Util';\r\n\r\n/*\r\n * @namespace Browser\r\n * @aka L.Browser\r\n *\r\n * A namespace with static properties for browser/feature detection used by Leaflet internally.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * if (L.Browser.ielt9) {\r\n * alert('Upgrade your browser, dude!');\r\n * }\r\n * ```\r\n */\r\n\r\nvar style = document.documentElement.style;\r\n\r\n// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).\r\nvar ie = 'ActiveXObject' in window;\r\n\r\n// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.\r\nvar ielt9 = ie && !document.addEventListener;\r\n\r\n// @property edge: Boolean; `true` for the Edge web browser.\r\nvar edge = 'msLaunchUri' in navigator && !('documentMode' in document);\r\n\r\n// @property webkit: Boolean;\r\n// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).\r\nvar webkit = userAgentContains('webkit');\r\n\r\n// @property android: Boolean\r\n// **Deprecated.** `true` for any browser running on an Android platform.\r\nvar android = userAgentContains('android');\r\n\r\n// @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3.\r\nvar android23 = userAgentContains('android 2') || userAgentContains('android 3');\r\n\r\n/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */\r\nvar webkitVer = parseInt(/WebKit\\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit\r\n// @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome)\r\nvar androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);\r\n\r\n// @property opera: Boolean; `true` for the Opera browser\r\nvar opera = !!window.opera;\r\n\r\n// @property chrome: Boolean; `true` for the Chrome browser.\r\nvar chrome = !edge && userAgentContains('chrome');\r\n\r\n// @property gecko: Boolean; `true` for gecko-based browsers like Firefox.\r\nvar gecko = userAgentContains('gecko') && !webkit && !opera && !ie;\r\n\r\n// @property safari: Boolean; `true` for the Safari browser.\r\nvar safari = !chrome && userAgentContains('safari');\r\n\r\nvar phantom = userAgentContains('phantom');\r\n\r\n// @property opera12: Boolean\r\n// `true` for the Opera browser supporting CSS transforms (version 12 or later).\r\nvar opera12 = 'OTransition' in style;\r\n\r\n// @property win: Boolean; `true` when the browser is running in a Windows platform\r\nvar win = navigator.platform.indexOf('Win') === 0;\r\n\r\n// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.\r\nvar ie3d = ie && ('transition' in style);\r\n\r\n// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.\r\nvar webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;\r\n\r\n// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.\r\nvar gecko3d = 'MozPerspective' in style;\r\n\r\n// @property any3d: Boolean\r\n// `true` for all browsers supporting CSS transforms.\r\nvar any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;\r\n\r\n// @property mobile: Boolean; `true` for all browsers running in a mobile device.\r\nvar mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');\r\n\r\n// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.\r\nvar mobileWebkit = mobile && webkit;\r\n\r\n// @property mobileWebkit3d: Boolean\r\n// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.\r\nvar mobileWebkit3d = mobile && webkit3d;\r\n\r\n// @property msPointer: Boolean\r\n// `true` for browsers implementing the Microsoft touch events model (notably IE10).\r\nvar msPointer = !window.PointerEvent && window.MSPointerEvent;\r\n\r\n// @property pointer: Boolean\r\n// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).\r\nvar pointer = !!(window.PointerEvent || msPointer);\r\n\r\n// @property touchNative: Boolean\r\n// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).\r\n// **This does not necessarily mean** that the browser is running in a computer with\r\n// a touchscreen, it only means that the browser is capable of understanding\r\n// touch events.\r\nvar touchNative = 'ontouchstart' in window || !!window.TouchEvent;\r\n\r\n// @property touch: Boolean\r\n// `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events.\r\n// Note: pointer events will be preferred (if available), and processed for all `touch*` listeners.\r\nvar touch = !window.L_NO_TOUCH && (touchNative || pointer);\r\n\r\n// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.\r\nvar mobileOpera = mobile && opera;\r\n\r\n// @property mobileGecko: Boolean\r\n// `true` for gecko-based browsers running in a mobile device.\r\nvar mobileGecko = mobile && gecko;\r\n\r\n// @property retina: Boolean\r\n// `true` for browsers on a high-resolution \"retina\" screen or on any screen when browser's display zoom is more than 100%.\r\nvar retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;\r\n\r\n// @property passiveEvents: Boolean\r\n// `true` for browsers that support passive events.\r\nvar passiveEvents = (function () {\r\n\tvar supportsPassiveOption = false;\r\n\ttry {\r\n\t\tvar opts = Object.defineProperty({}, 'passive', {\r\n\t\t\tget: function () { // eslint-disable-line getter-return\r\n\t\t\t\tsupportsPassiveOption = true;\r\n\t\t\t}\r\n\t\t});\r\n\t\twindow.addEventListener('testPassiveEventSupport', Util.falseFn, opts);\r\n\t\twindow.removeEventListener('testPassiveEventSupport', Util.falseFn, opts);\r\n\t} catch (e) {\r\n\t\t// Errors can safely be ignored since this is only a browser support test.\r\n\t}\r\n\treturn supportsPassiveOption;\r\n}());\r\n\r\n// @property canvas: Boolean\r\n// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\r\nvar canvas = (function () {\r\n\treturn !!document.createElement('canvas').getContext;\r\n}());\r\n\r\n// @property svg: Boolean\r\n// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).\r\nvar svg = !!(document.createElementNS && svgCreate('svg').createSVGRect);\r\n\r\nvar inlineSvg = !!svg && (function () {\r\n\tvar div = document.createElement('div');\r\n\tdiv.innerHTML = '<svg/>';\r\n\treturn (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';\r\n})();\r\n\r\n// @property vml: Boolean\r\n// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).\r\nvar vml = !svg && (function () {\r\n\ttry {\r\n\t\tvar div = document.createElement('div');\r\n\t\tdiv.innerHTML = '<v:shape adj=\"1\"/>';\r\n\r\n\t\tvar shape = div.firstChild;\r\n\t\tshape.style.behavior = 'url(#default#VML)';\r\n\r\n\t\treturn shape && (typeof shape.adj === 'object');\r\n\r\n\t} catch (e) {\r\n\t\treturn false;\r\n\t}\r\n}());\r\n\r\n\r\n// @property mac: Boolean; `true` when the browser is running in a Mac platform\r\nvar mac = navigator.platform.indexOf('Mac') === 0;\r\n\r\n// @property mac: Boolean; `true` when the browser is running in a Linux platform\r\nvar linux = navigator.platform.indexOf('Linux') === 0;\r\n\r\nfunction userAgentContains(str) {\r\n\treturn navigator.userAgent.toLowerCase().indexOf(str) >= 0;\r\n}\r\n\r\n\r\nexport default {\r\n\tie: ie,\r\n\tielt9: ielt9,\r\n\tedge: edge,\r\n\twebkit: webkit,\r\n\tandroid: android,\r\n\tandroid23: android23,\r\n\tandroidStock: androidStock,\r\n\topera: opera,\r\n\tchrome: chrome,\r\n\tgecko: gecko,\r\n\tsafari: safari,\r\n\tphantom: phantom,\r\n\topera12: opera12,\r\n\twin: win,\r\n\tie3d: ie3d,\r\n\twebkit3d: webkit3d,\r\n\tgecko3d: gecko3d,\r\n\tany3d: any3d,\r\n\tmobile: mobile,\r\n\tmobileWebkit: mobileWebkit,\r\n\tmobileWebkit3d: mobileWebkit3d,\r\n\tmsPointer: msPointer,\r\n\tpointer: pointer,\r\n\ttouch: touch,\r\n\ttouchNative: touchNative,\r\n\tmobileOpera: mobileOpera,\r\n\tmobileGecko: mobileGecko,\r\n\tretina: retina,\r\n\tpassiveEvents: passiveEvents,\r\n\tcanvas: canvas,\r\n\tsvg: svg,\r\n\tvml: vml,\r\n\tinlineSvg: inlineSvg,\r\n\tmac: mac,\r\n\tlinux: linux\r\n};\r\n","import * as DomEvent from './DomEvent';\nimport Browser from '../core/Browser';\nimport {falseFn} from '../core/Util';\n\n/*\n * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.\n */\n\nvar POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown';\nvar POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove';\nvar POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup';\nvar POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel';\nvar pEvent = {\n\ttouchstart : POINTER_DOWN,\n\ttouchmove : POINTER_MOVE,\n\ttouchend : POINTER_UP,\n\ttouchcancel : POINTER_CANCEL\n};\nvar handle = {\n\ttouchstart : _onPointerStart,\n\ttouchmove : _handlePointer,\n\ttouchend : _handlePointer,\n\ttouchcancel : _handlePointer\n};\nvar _pointers = {};\nvar _pointerDocListener = false;\n\n// Provides a touch events wrapper for (ms)pointer events.\n// ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890\n\nexport function addPointerListener(obj, type, handler) {\n\tif (type === 'touchstart') {\n\t\t_addPointerDocListener();\n\t}\n\tif (!handle[type]) {\n\t\tconsole.warn('wrong event specified:', type);\n\t\treturn falseFn;\n\t}\n\thandler = handle[type].bind(this, handler);\n\tobj.addEventListener(pEvent[type], handler, false);\n\treturn handler;\n}\n\nexport function removePointerListener(obj, type, handler) {\n\tif (!pEvent[type]) {\n\t\tconsole.warn('wrong event specified:', type);\n\t\treturn;\n\t}\n\tobj.removeEventListener(pEvent[type], handler, false);\n}\n\nfunction _globalPointerDown(e) {\n\t_pointers[e.pointerId] = e;\n}\n\nfunction _globalPointerMove(e) {\n\tif (_pointers[e.pointerId]) {\n\t\t_pointers[e.pointerId] = e;\n\t}\n}\n\nfunction _globalPointerUp(e) {\n\tdelete _pointers[e.pointerId];\n}\n\nfunction _addPointerDocListener() {\n\t// need to keep track of what pointers and how many are active to provide e.touches emulation\n\tif (!_pointerDocListener) {\n\t\t// we listen document as any drags that end by moving the touch off the screen get fired there\n\t\tdocument.addEventListener(POINTER_DOWN, _globalPointerDown, true);\n\t\tdocument.addEventListener(POINTER_MOVE, _globalPointerMove, true);\n\t\tdocument.addEventListener(POINTER_UP, _globalPointerUp, true);\n\t\tdocument.addEventListener(POINTER_CANCEL, _globalPointerUp, true);\n\n\t\t_pointerDocListener = true;\n\t}\n}\n\nfunction _handlePointer(handler, e) {\n\tif (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; }\n\n\te.touches = [];\n\tfor (var i in _pointers) {\n\t\te.touches.push(_pointers[i]);\n\t}\n\te.changedTouches = [e];\n\n\thandler(e);\n}\n\nfunction _onPointerStart(handler, e) {\n\t// IE10 specific: MsTouch needs preventDefault. See #2000\n\tif (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {\n\t\tDomEvent.preventDefault(e);\n\t}\n\t_handlePointer(handler, e);\n}\n","import * as DomEvent from './DomEvent';\r\n\r\n/*\r\n * Extends the event handling code with double tap support for mobile browsers.\r\n *\r\n * Note: currently most browsers fire native dblclick, with only a few exceptions\r\n * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)\r\n */\r\n\r\nfunction makeDblclick(event) {\r\n\t// in modern browsers `type` cannot be just overridden:\r\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only\r\n\tvar newEvent = {},\r\n\t prop, i;\r\n\tfor (i in event) {\r\n\t\tprop = event[i];\r\n\t\tnewEvent[i] = prop && prop.bind ? prop.bind(event) : prop;\r\n\t}\r\n\tevent = newEvent;\r\n\tnewEvent.type = 'dblclick';\r\n\tnewEvent.detail = 2;\r\n\tnewEvent.isTrusted = false;\r\n\tnewEvent._simulated = true; // for debug purposes\r\n\treturn newEvent;\r\n}\r\n\r\nvar delay = 200;\r\nexport function addDoubleTapListener(obj, handler) {\r\n\t// Most browsers handle double tap natively\r\n\tobj.addEventListener('dblclick', handler);\r\n\r\n\t// On some platforms the browser doesn't fire native dblclicks for touch events.\r\n\t// It seems that in all such cases `detail` property of `click` event is always `1`.\r\n\t// So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.\r\n\tvar last = 0,\r\n\t detail;\r\n\tfunction simDblclick(e) {\r\n\t\tif (e.detail !== 1) {\r\n\t\t\tdetail = e.detail; // keep in sync to avoid false dblclick in some cases\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (e.pointerType === 'mouse' ||\r\n\t\t\t(e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// When clicking on an <input>, the browser generates a click on its\r\n\t\t// <label> (and vice versa) triggering two clicks in quick succession.\r\n\t\t// This ignores clicks on elements which are a label with a 'for'\r\n\t\t// attribute (or children of such a label), but not children of\r\n\t\t// a <input>.\r\n\t\tvar path = DomEvent.getPropagationPath(e);\r\n\t\tif (path.some(function (el) {\r\n\t\t\treturn el instanceof HTMLLabelElement && el.attributes.for;\r\n\t\t}) &&\r\n\t\t\t!path.some(function (el) {\r\n\t\t\t\treturn (\r\n\t\t\t\t\tel instanceof HTMLInputElement ||\r\n\t\t\t\t\tel instanceof HTMLSelectElement\r\n\t\t\t\t);\r\n\t\t\t})\r\n\t\t) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar now = Date.now();\r\n\t\tif (now - last <= delay) {\r\n\t\t\tdetail++;\r\n\t\t\tif (detail === 2) {\r\n\t\t\t\thandler(makeDblclick(e));\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tdetail = 1;\r\n\t\t}\r\n\t\tlast = now;\r\n\t}\r\n\r\n\tobj.addEventListener('click', simDblclick);\r\n\r\n\treturn {\r\n\t\tdblclick: handler,\r\n\t\tsimDblclick: simDblclick\r\n\t};\r\n}\r\n\r\nexport function removeDoubleTapListener(obj, handlers) {\r\n\tobj.removeEventListener('dblclick', handlers.dblclick);\r\n\tobj.removeEventListener('click', handlers.simDblclick);\r\n}\r\n","import * as DomEvent from './DomEvent';\r\nimport * as Util from '../core/Util';\r\nimport {Point} from '../geometry/Point';\r\nimport Browser from '../core/Browser';\r\n\r\n/*\r\n * @namespace DomUtil\r\n *\r\n * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)\r\n * tree, used by Leaflet internally.\r\n *\r\n * Most functions expecting or returning a `HTMLElement` also work for\r\n * SVG elements. The only difference is that classes refer to CSS classes\r\n * in HTML and SVG classes in SVG.\r\n */\r\n\r\n\r\n// @property TRANSFORM: String\r\n// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).\r\nexport var TRANSFORM = testProp(\r\n\t['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);\r\n\r\n// webkitTransition comes first because some browser versions that drop vendor prefix don't do\r\n// the same for the transitionend event, in particular the Android 4.1 stock browser\r\n\r\n// @property TRANSITION: String\r\n// Vendor-prefixed transition style name.\r\nexport var TRANSITION = testProp(\r\n\t['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);\r\n\r\n// @property TRANSITION_END: String\r\n// Vendor-prefixed transitionend event name.\r\nexport var TRANSITION_END =\r\n\tTRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';\r\n\r\n\r\n// @function get(id: String|HTMLElement): HTMLElement\r\n// Returns an element given its DOM id, or returns the element itself\r\n// if it was passed directly.\r\nexport function get(id) {\r\n\treturn typeof id === 'string' ? document.getElementById(id) : id;\r\n}\r\n\r\n// @function getStyle(el: HTMLElement, styleAttrib: String): String\r\n// Returns the value for a certain style attribute on an element,\r\n// including computed values or values set through CSS.\r\nexport function getStyle(el, style) {\r\n\tvar value = el.style[style] || (el.currentStyle && el.currentStyle[style]);\r\n\r\n\tif ((!value || value === 'auto') && document.defaultView) {\r\n\t\tvar css = document.defaultView.getComputedStyle(el, null);\r\n\t\tvalue = css ? css[style] : null;\r\n\t}\r\n\treturn value === 'auto' ? null : value;\r\n}\r\n\r\n// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement\r\n// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.\r\nexport function create(tagName, className, container) {\r\n\tvar el = document.createElement(tagName);\r\n\tel.className = className || '';\r\n\r\n\tif (container) {\r\n\t\tcontainer.appendChild(el);\r\n\t}\r\n\treturn el;\r\n}\r\n\r\n// @function remove(el: HTMLElement)\r\n// Removes `el` from its parent element\r\nexport function remove(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent) {\r\n\t\tparent.removeChild(el);\r\n\t}\r\n}\r\n\r\n// @function empty(el: HTMLElement)\r\n// Removes all of `el`'s children elements from `el`\r\nexport function empty(el) {\r\n\twhile (el.firstChild) {\r\n\t\tel.removeChild(el.firstChild);\r\n\t}\r\n}\r\n\r\n// @function toFront(el: HTMLElement)\r\n// Makes `el` the last child of its parent, so it renders in front of the other children.\r\nexport function toFront(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent && parent.lastChild !== el) {\r\n\t\tparent.appendChild(el);\r\n\t}\r\n}\r\n\r\n// @function toBack(el: HTMLElement)\r\n// Makes `el` the first child of its parent, so it renders behind the other children.\r\nexport function toBack(el) {\r\n\tvar parent = el.parentNode;\r\n\tif (parent && parent.firstChild !== el) {\r\n\t\tparent.insertBefore(el, parent.firstChild);\r\n\t}\r\n}\r\n\r\n// @function hasClass(el: HTMLElement, name: String): Boolean\r\n// Returns `true` if the element's class attribute contains `name`.\r\nexport function hasClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\treturn el.classList.contains(name);\r\n\t}\r\n\tvar className = getClass(el);\r\n\treturn className.length > 0 && new RegExp('(^|\\\\s)' + name + '(\\\\s|$)').test(className);\r\n}\r\n\r\n// @function addClass(el: HTMLElement, name: String)\r\n// Adds `name` to the element's class attribute.\r\nexport function addClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\tvar classes = Util.splitWords(name);\r\n\t\tfor (var i = 0, len = classes.length; i < len; i++) {\r\n\t\t\tel.classList.add(classes[i]);\r\n\t\t}\r\n\t} else if (!hasClass(el, name)) {\r\n\t\tvar className = getClass(el);\r\n\t\tsetClass(el, (className ? className + ' ' : '') + name);\r\n\t}\r\n}\r\n\r\n// @function removeClass(el: HTMLElement, name: String)\r\n// Removes `name` from the element's class attribute.\r\nexport function removeClass(el, name) {\r\n\tif (el.classList !== undefined) {\r\n\t\tel.classList.remove(name);\r\n\t} else {\r\n\t\tsetClass(el, Util.trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));\r\n\t}\r\n}\r\n\r\n// @function setClass(el: HTMLElement, name: String)\r\n// Sets the element's class.\r\nexport function setClass(el, name) {\r\n\tif (el.className.baseVal === undefined) {\r\n\t\tel.className = name;\r\n\t} else {\r\n\t\t// in case of SVG element\r\n\t\tel.className.baseVal = name;\r\n\t}\r\n}\r\n\r\n// @function getClass(el: HTMLElement): String\r\n// Returns the element's class.\r\nexport function getClass(el) {\r\n\t// Check if the element is an SVGElementInstance and use the correspondingElement instead\r\n\t// (Required for linked SVG elements in IE11.)\r\n\tif (el.correspondingElement) {\r\n\t\tel = el.correspondingElement;\r\n\t}\r\n\treturn el.className.baseVal === undefined ? el.className : el.className.baseVal;\r\n}\r\n\r\n// @function setOpacity(el: HTMLElement, opacity: Number)\r\n// Set the opacity of an element (including old IE support).\r\n// `opacity` must be a number from `0` to `1`.\r\nexport function setOpacity(el, value) {\r\n\tif ('opacity' in el.style) {\r\n\t\tel.style.opacity = value;\r\n\t} else if ('filter' in el.style) {\r\n\t\t_setOpacityIE(el, value);\r\n\t}\r\n}\r\n\r\nfunction _setOpacityIE(el, value) {\r\n\tvar filter = false,\r\n\t filterName = 'DXImageTransform.Microsoft.Alpha';\r\n\r\n\t// filters collection throws an error if we try to retrieve a filter that doesn't exist\r\n\ttry {\r\n\t\tfilter = el.filters.item(filterName);\r\n\t} catch (e) {\r\n\t\t// don't set opacity to 1 if we haven't already set an opacity,\r\n\t\t// it isn't needed and breaks transparent pngs.\r\n\t\tif (value === 1) { return; }\r\n\t}\r\n\r\n\tvalue = Math.round(value * 100);\r\n\r\n\tif (filter) {\r\n\t\tfilter.Enabled = (value !== 100);\r\n\t\tfilter.Opacity = value;\r\n\t} else {\r\n\t\tel.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';\r\n\t}\r\n}\r\n\r\n// @function testProp(props: String[]): String|false\r\n// Goes through the array of style names and returns the first name\r\n// that is a valid style name for an element. If no such name is found,\r\n// it returns false. Useful for vendor-prefixed styles like `transform`.\r\nexport function testProp(props) {\r\n\tvar style = document.documentElement.style;\r\n\r\n\tfor (var i = 0; i < props.length; i++) {\r\n\t\tif (props[i] in style) {\r\n\t\t\treturn props[i];\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n\r\n// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)\r\n// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels\r\n// and optionally scaled by `scale`. Does not have an effect if the\r\n// browser doesn't support 3D CSS transforms.\r\nexport function setTransform(el, offset, scale) {\r\n\tvar pos = offset || new Point(0, 0);\r\n\r\n\tel.style[TRANSFORM] =\r\n\t\t(Browser.ie3d ?\r\n\t\t\t'translate(' + pos.x + 'px,' + pos.y + 'px)' :\r\n\t\t\t'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +\r\n\t\t(scale ? ' scale(' + scale + ')' : '');\r\n}\r\n\r\n// @function setPosition(el: HTMLElement, position: Point)\r\n// Sets the position of `el` to coordinates specified by `position`,\r\n// using CSS translate or top/left positioning depending on the browser\r\n// (used by Leaflet internally to position its layers).\r\nexport function setPosition(el, point) {\r\n\r\n\t/*eslint-disable */\r\n\tel._leaflet_pos = point;\r\n\t/* eslint-enable */\r\n\r\n\tif (Browser.any3d) {\r\n\t\tsetTransform(el, point);\r\n\t} else {\r\n\t\tel.style.left = point.x + 'px';\r\n\t\tel.style.top = point.y + 'px';\r\n\t}\r\n}\r\n\r\n// @function getPosition(el: HTMLElement): Point\r\n// Returns the coordinates of an element previously positioned with setPosition.\r\nexport function getPosition(el) {\r\n\t// this method is only used for elements previously positioned using setPosition,\r\n\t// so it's safe to cache the position for performance\r\n\r\n\treturn el._leaflet_pos || new Point(0, 0);\r\n}\r\n\r\n// @function disableTextSelection()\r\n// Prevents the user from generating `selectstart` DOM events, usually generated\r\n// when the user drags the mouse through a page with text. Used internally\r\n// by Leaflet to override the behaviour of any click-and-drag interaction on\r\n// the map. Affects drag interactions on the whole document.\r\n\r\n// @function enableTextSelection()\r\n// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).\r\nexport var disableTextSelection;\r\nexport var enableTextSelection;\r\nvar _userSelect;\r\nif ('onselectstart' in document) {\r\n\tdisableTextSelection = function () {\r\n\t\tDomEvent.on(window, 'selectstart', DomEvent.preventDefault);\r\n\t};\r\n\tenableTextSelection = function () {\r\n\t\tDomEvent.off(window, 'selectstart', DomEvent.preventDefault);\r\n\t};\r\n} else {\r\n\tvar userSelectProperty = testProp(\r\n\t\t['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);\r\n\r\n\tdisableTextSelection = function () {\r\n\t\tif (userSelectProperty) {\r\n\t\t\tvar style = document.documentElement.style;\r\n\t\t\t_userSelect = style[userSelectProperty];\r\n\t\t\tstyle[userSelectProperty] = 'none';\r\n\t\t}\r\n\t};\r\n\tenableTextSelection = function () {\r\n\t\tif (userSelectProperty) {\r\n\t\t\tdocument.documentElement.style[userSelectProperty] = _userSelect;\r\n\t\t\t_userSelect = undefined;\r\n\t\t}\r\n\t};\r\n}\r\n\r\n// @function disableImageDrag()\r\n// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but\r\n// for `dragstart` DOM events, usually generated when the user drags an image.\r\nexport function disableImageDrag() {\r\n\tDomEvent.on(window, 'dragstart', DomEvent.preventDefault);\r\n}\r\n\r\n// @function enableImageDrag()\r\n// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).\r\nexport function enableImageDrag() {\r\n\tDomEvent.off(window, 'dragstart', DomEvent.preventDefault);\r\n}\r\n\r\nvar _outlineElement, _outlineStyle;\r\n// @function preventOutline(el: HTMLElement)\r\n// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)\r\n// of the element `el` invisible. Used internally by Leaflet to prevent\r\n// focusable elements from displaying an outline when the user performs a\r\n// drag interaction on them.\r\nexport function preventOutline(element) {\r\n\twhile (element.tabIndex === -1) {\r\n\t\telement = element.parentNode;\r\n\t}\r\n\tif (!element.style) { return; }\r\n\trestoreOutline();\r\n\t_outlineElement = element;\r\n\t_outlineStyle = element.style.outline;\r\n\telement.style.outline = 'none';\r\n\tDomEvent.on(window, 'keydown', restoreOutline);\r\n}\r\n\r\n// @function restoreOutline()\r\n// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().\r\nexport function restoreOutline() {\r\n\tif (!_outlineElement) { return; }\r\n\t_outlineElement.style.outline = _outlineStyle;\r\n\t_outlineElement = undefined;\r\n\t_outlineStyle = undefined;\r\n\tDomEvent.off(window, 'keydown', restoreOutline);\r\n}\r\n\r\n// @function getSizedParentNode(el: HTMLElement): HTMLElement\r\n// Finds the closest parent node which size (width and height) is not null.\r\nexport function getSizedParentNode(element) {\r\n\tdo {\r\n\t\telement = element.parentNode;\r\n\t} while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);\r\n\treturn element;\r\n}\r\n\r\n// @function getScale(el: HTMLElement): Object\r\n// Computes the CSS scale currently applied on the element.\r\n// Returns an object with `x` and `y` members as horizontal and vertical scales respectively,\r\n// and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).\r\nexport function getScale(element) {\r\n\tvar rect = element.getBoundingClientRect(); // Read-only in old browsers.\r\n\r\n\treturn {\r\n\t\tx: rect.width / element.offsetWidth || 1,\r\n\t\ty: rect.height / element.offsetHeight || 1,\r\n\t\tboundingClientRect: rect\r\n\t};\r\n}\r\n","import {Point} from '../geometry/Point';\r\nimport * as Util from '../core/Util';\r\nimport Browser from '../core/Browser';\r\nimport {addPointerListener, removePointerListener} from './DomEvent.Pointer';\r\nimport {addDoubleTapListener, removeDoubleTapListener} from './DomEvent.DoubleTap';\r\nimport {getScale} from './DomUtil';\r\n\r\n/*\r\n * @namespace DomEvent\r\n * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.\r\n */\r\n\r\n// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.\r\n\r\n// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n// Adds a listener function (`fn`) to a particular DOM event type of the\r\n// element `el`. You can optionally specify the context of the listener\r\n// (object the `this` keyword will point to). You can also pass several\r\n// space-separated types (e.g. `'click dblclick'`).\r\n\r\n// @alternative\r\n// @function on(el: HTMLElement, eventMap: Object, context?: Object): this\r\n// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\nexport function on(obj, types, fn, context) {\r\n\r\n\tif (types && typeof types === 'object') {\r\n\t\tfor (var type in types) {\r\n\t\t\taddOne(obj, type, types[type], fn);\r\n\t\t}\r\n\t} else {\r\n\t\ttypes = Util.splitWords(types);\r\n\r\n\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\taddOne(obj, types[i], fn, context);\r\n\t\t}\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\nvar eventsKey = '_leaflet_events';\r\n\r\n// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n// Removes a previously added listener function.\r\n// Note that if you passed a custom context to on, you must pass the same\r\n// context to `off` in order to remove the listener.\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement, eventMap: Object, context?: Object): this\r\n// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement, types: String): this\r\n// Removes all previously added listeners of given types.\r\n\r\n// @alternative\r\n// @function off(el: HTMLElement): this\r\n// Removes all previously added listeners from given HTMLElement\r\nexport function off(obj, types, fn, context) {\r\n\r\n\tif (arguments.length === 1) {\r\n\t\tbatchRemove(obj);\r\n\t\tdelete obj[eventsKey];\r\n\r\n\t} else if (types && typeof types === 'object') {\r\n\t\tfor (var type in types) {\r\n\t\t\tremoveOne(obj, type, types[type], fn);\r\n\t\t}\r\n\r\n\t} else {\r\n\t\ttypes = Util.splitWords(types);\r\n\r\n\t\tif (arguments.length === 2) {\r\n\t\t\tbatchRemove(obj, function (type) {\r\n\t\t\t\treturn Util.indexOf(types, type) !== -1;\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tremoveOne(obj, types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\nfunction batchRemove(obj, filterFn) {\r\n\tfor (var id in obj[eventsKey]) {\r\n\t\tvar type = id.split(/\\d/)[0];\r\n\t\tif (!filterFn || filterFn(type)) {\r\n\t\t\tremoveOne(obj, type, null, null, id);\r\n\t\t}\r\n\t}\r\n}\r\n\r\nvar mouseSubst = {\r\n\tmouseenter: 'mouseover',\r\n\tmouseleave: 'mouseout',\r\n\twheel: !('onwheel' in window) && 'mousewheel'\r\n};\r\n\r\nfunction addOne(obj, type, fn, context) {\r\n\tvar id = type + Util.stamp(fn) + (context ? '_' + Util.stamp(context) : '');\r\n\r\n\tif (obj[eventsKey] && obj[eventsKey][id]) { return this; }\r\n\r\n\tvar handler = function (e) {\r\n\t\treturn fn.call(context || obj, e || window.event);\r\n\t};\r\n\r\n\tvar originalHandler = handler;\r\n\r\n\tif (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\t// Needs DomEvent.Pointer.js\r\n\t\thandler = addPointerListener(obj, type, handler);\r\n\r\n\t} else if (Browser.touch && (type === 'dblclick')) {\r\n\t\thandler = addDoubleTapListener(obj, handler);\r\n\r\n\t} else if ('addEventListener' in obj) {\r\n\r\n\t\tif (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') {\r\n\t\t\tobj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false);\r\n\r\n\t\t} else if (type === 'mouseenter' || type === 'mouseleave') {\r\n\t\t\thandler = function (e) {\r\n\t\t\t\te = e || window.event;\r\n\t\t\t\tif (isExternalTarget(obj, e)) {\r\n\t\t\t\t\toriginalHandler(e);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t\tobj.addEventListener(mouseSubst[type], handler, false);\r\n\r\n\t\t} else {\r\n\t\t\tobj.addEventListener(type, originalHandler, false);\r\n\t\t}\r\n\r\n\t} else {\r\n\t\tobj.attachEvent('on' + type, handler);\r\n\t}\r\n\r\n\tobj[eventsKey] = obj[eventsKey] || {};\r\n\tobj[eventsKey][id] = handler;\r\n}\r\n\r\nfunction removeOne(obj, type, fn, context, id) {\r\n\tid = id || type + Util.stamp(fn) + (context ? '_' + Util.stamp(context) : '');\r\n\tvar handler = obj[eventsKey] && obj[eventsKey][id];\r\n\r\n\tif (!handler) { return this; }\r\n\r\n\tif (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\tremovePointerListener(obj, type, handler);\r\n\r\n\t} else if (Browser.touch && (type === 'dblclick')) {\r\n\t\tremoveDoubleTapListener(obj, handler);\r\n\r\n\t} else if ('removeEventListener' in obj) {\r\n\r\n\t\tobj.removeEventListener(mouseSubst[type] || type, handler, false);\r\n\r\n\t} else {\r\n\t\tobj.detachEvent('on' + type, handler);\r\n\t}\r\n\r\n\tobj[eventsKey][id] = null;\r\n}\r\n\r\n// @function stopPropagation(ev: DOMEvent): this\r\n// Stop the given event from propagation to parent elements. Used inside the listener functions:\r\n// ```js\r\n// L.DomEvent.on(div, 'click', function (ev) {\r\n// \tL.DomEvent.stopPropagation(ev);\r\n// });\r\n// ```\r\nexport function stopPropagation(e) {\r\n\r\n\tif (e.stopPropagation) {\r\n\t\te.stopPropagation();\r\n\t} else if (e.originalEvent) { // In case of Leaflet event.\r\n\t\te.originalEvent._stopped = true;\r\n\t} else {\r\n\t\te.cancelBubble = true;\r\n\t}\r\n\r\n\treturn this;\r\n}\r\n\r\n// @function disableScrollPropagation(el: HTMLElement): this\r\n// Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants).\r\nexport function disableScrollPropagation(el) {\r\n\taddOne(el, 'wheel', stopPropagation);\r\n\treturn this;\r\n}\r\n\r\n// @function disableClickPropagation(el: HTMLElement): this\r\n// Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`,\r\n// `'mousedown'` and `'touchstart'` events (plus browser variants).\r\nexport function disableClickPropagation(el) {\r\n\ton(el, 'mousedown touchstart dblclick contextmenu', stopPropagation);\r\n\tel['_leaflet_disable_click'] = true;\r\n\treturn this;\r\n}\r\n\r\n// @function preventDefault(ev: DOMEvent): this\r\n// Prevents the default action of the DOM Event `ev` from happening (such as\r\n// following a link in the href of the a element, or doing a POST request\r\n// with page reload when a `<form>` is submitted).\r\n// Use it inside listener functions.\r\nexport function preventDefault(e) {\r\n\tif (e.preventDefault) {\r\n\t\te.preventDefault();\r\n\t} else {\r\n\t\te.returnValue = false;\r\n\t}\r\n\treturn this;\r\n}\r\n\r\n// @function stop(ev: DOMEvent): this\r\n// Does `stopPropagation` and `preventDefault` at the same time.\r\nexport function stop(e) {\r\n\tpreventDefault(e);\r\n\tstopPropagation(e);\r\n\treturn this;\r\n}\r\n\r\n// @function getPropagationPath(ev: DOMEvent): Array\r\n// Compatibility polyfill for [`Event.composedPath()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath).\r\n// Returns an array containing the `HTMLElement`s that the given DOM event\r\n// should propagate to (if not stopped).\r\nexport function getPropagationPath(ev) {\r\n\tif (ev.composedPath) {\r\n\t\treturn ev.composedPath();\r\n\t}\r\n\r\n\tvar path = [];\r\n\tvar el = ev.target;\r\n\r\n\twhile (el) {\r\n\t\tpath.push(el);\r\n\t\tel = el.parentNode;\r\n\t}\r\n\treturn path;\r\n}\r\n\r\n\r\n// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point\r\n// Gets normalized mouse position from a DOM event relative to the\r\n// `container` (border excluded) or to the whole page if not specified.\r\nexport function getMousePosition(e, container) {\r\n\tif (!container) {\r\n\t\treturn new Point(e.clientX, e.clientY);\r\n\t}\r\n\r\n\tvar scale = getScale(container),\r\n\t offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y)\r\n\r\n\treturn new Point(\r\n\t\t// offset.left/top values are in page scale (like clientX/Y),\r\n\t\t// whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).\r\n\t\t(e.clientX - offset.left) / scale.x - container.clientLeft,\r\n\t\t(e.clientY - offset.top) / scale.y - container.clientTop\r\n\t);\r\n}\r\n\r\n\r\n// except , Safari and\r\n// We need double the scroll pixels (see #7403 and #4538) for all Browsers\r\n// except OSX (Mac) -> 3x, Chrome running on Linux 1x\r\n\r\nvar wheelPxFactor =\r\n\t(Browser.linux && Browser.chrome) ? window.devicePixelRatio :\r\n\tBrowser.mac ? window.devicePixelRatio * 3 :\r\n\twindow.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1;\r\n// @function getWheelDelta(ev: DOMEvent): Number\r\n// Gets normalized wheel delta from a wheel DOM event, in vertical\r\n// pixels scrolled (negative if scrolling down).\r\n// Events from pointing devices without precise scrolling are mapped to\r\n// a best guess of 60 pixels.\r\nexport function getWheelDelta(e) {\r\n\treturn (Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta\r\n\t (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels\r\n\t (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines\r\n\t (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages\r\n\t (e.deltaX || e.deltaZ) ? 0 :\t// Skip horizontal/depth wheel events\r\n\t e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels\r\n\t (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines\r\n\t e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages\r\n\t 0;\r\n}\r\n\r\n// check if element really left/entered the event target (for mouseenter/mouseleave)\r\nexport function isExternalTarget(el, e) {\r\n\r\n\tvar related = e.relatedTarget;\r\n\r\n\tif (!related) { return true; }\r\n\r\n\ttry {\r\n\t\twhile (related && (related !== el)) {\r\n\t\t\trelated = related.parentNode;\r\n\t\t}\r\n\t} catch (err) {\r\n\t\treturn false;\r\n\t}\r\n\treturn (related !== el);\r\n}\r\n\r\n// @function addListener(…): this\r\n// Alias to [`L.DomEvent.on`](#domevent-on)\r\nexport {on as addListener};\r\n\r\n// @function removeListener(…): this\r\n// Alias to [`L.DomEvent.off`](#domevent-off)\r\nexport {off as removeListener};\r\n","import * as Util from '../core/Util';\nimport {Evented} from '../core/Events';\nimport * as DomUtil from '../dom/DomUtil';\n\n\n/*\n * @class PosAnimation\n * @aka L.PosAnimation\n * @inherits Evented\n * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.\n *\n * @example\n * ```js\n * var myPositionMarker = L.marker([48.864716, 2.294694]).addTo(map);\n *\n * myPositionMarker.on(\"click\", function() {\n * \tvar pos = map.latLngToLayerPoint(myPositionMarker.getLatLng());\n * \tpos.y -= 25;\n * \tvar fx = new L.PosAnimation();\n *\n * \tfx.once('end',function() {\n * \t\tpos.y += 25;\n * \t\tfx.run(myPositionMarker._icon, pos, 0.8);\n * \t});\n *\n * \tfx.run(myPositionMarker._icon, pos, 0.3);\n * });\n *\n * ```\n *\n * @constructor L.PosAnimation()\n * Creates a `PosAnimation` object.\n *\n */\n\nexport var PosAnimation = Evented.extend({\n\n\t// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)\n\t// Run an animation of a given element to a new position, optionally setting\n\t// duration in seconds (`0.25` by default) and easing linearity factor (3rd\n\t// argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1),\n\t// `0.5` by default).\n\trun: function (el, newPos, duration, easeLinearity) {\n\t\tthis.stop();\n\n\t\tthis._el = el;\n\t\tthis._inProgress = true;\n\t\tthis._duration = duration || 0.25;\n\t\tthis._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);\n\n\t\tthis._startPos = DomUtil.getPosition(el);\n\t\tthis._offset = newPos.subtract(this._startPos);\n\t\tthis._startTime = +new Date();\n\n\t\t// @event start: Event\n\t\t// Fired when the animation starts\n\t\tthis.fire('start');\n\n\t\tthis._animate();\n\t},\n\n\t// @method stop()\n\t// Stops the animation (if currently running).\n\tstop: function () {\n\t\tif (!this._inProgress) { return; }\n\n\t\tthis._step(true);\n\t\tthis._complete();\n\t},\n\n\t_animate: function () {\n\t\t// animation loop\n\t\tthis._animId = Util.requestAnimFrame(this._animate, this);\n\t\tthis._step();\n\t},\n\n\t_step: function (round) {\n\t\tvar elapsed = (+new Date()) - this._startTime,\n\t\t duration = this._duration * 1000;\n\n\t\tif (elapsed < duration) {\n\t\t\tthis._runFrame(this._easeOut(elapsed / duration), round);\n\t\t} else {\n\t\t\tthis._runFrame(1);\n\t\t\tthis._complete();\n\t\t}\n\t},\n\n\t_runFrame: function (progress, round) {\n\t\tvar pos = this._startPos.add(this._offset.multiplyBy(progress));\n\t\tif (round) {\n\t\t\tpos._round();\n\t\t}\n\t\tDomUtil.setPosition(this._el, pos);\n\n\t\t// @event step: Event\n\t\t// Fired continuously during the animation.\n\t\tthis.fire('step');\n\t},\n\n\t_complete: function () {\n\t\tUtil.cancelAnimFrame(this._animId);\n\n\t\tthis._inProgress = false;\n\t\t// @event end: Event\n\t\t// Fired when the animation ends.\n\t\tthis.fire('end');\n\t},\n\n\t_easeOut: function (t) {\n\t\treturn 1 - Math.pow(1 - t, this._easeOutPower);\n\t}\n});\n","import * as Util from '../core/Util';\r\nimport {Evented} from '../core/Events';\r\nimport {EPSG3857} from '../geo/crs/CRS.EPSG3857';\r\nimport {Point, toPoint} from '../geometry/Point';\r\nimport {Bounds, toBounds} from '../geometry/Bounds';\r\nimport {LatLng, toLatLng} from '../geo/LatLng';\r\nimport {LatLngBounds, toLatLngBounds} from '../geo/LatLngBounds';\r\nimport Browser from '../core/Browser';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport {PosAnimation} from '../dom/PosAnimation';\r\n\r\n/*\r\n * @class Map\r\n * @aka L.Map\r\n * @inherits Evented\r\n *\r\n * The central class of the API — it is used to create a map on a page and manipulate it.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * // initialize the map on the \"map\" div with a given center and zoom\r\n * var map = L.map('map', {\r\n * \tcenter: [51.505, -0.09],\r\n * \tzoom: 13\r\n * });\r\n * ```\r\n *\r\n */\r\n\r\nexport var Map = Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section Map State Options\r\n\t\t// @option crs: CRS = L.CRS.EPSG3857\r\n\t\t// The [Coordinate Reference System](#crs) to use. Don't change this if you're not\r\n\t\t// sure what it means.\r\n\t\tcrs: EPSG3857,\r\n\r\n\t\t// @option center: LatLng = undefined\r\n\t\t// Initial geographic center of the map\r\n\t\tcenter: undefined,\r\n\r\n\t\t// @option zoom: Number = undefined\r\n\t\t// Initial map zoom level\r\n\t\tzoom: undefined,\r\n\r\n\t\t// @option minZoom: Number = *\r\n\t\t// Minimum zoom level of the map.\r\n\t\t// If not specified and at least one `GridLayer` or `TileLayer` is in the map,\r\n\t\t// the lowest of their `minZoom` options will be used instead.\r\n\t\tminZoom: undefined,\r\n\r\n\t\t// @option maxZoom: Number = *\r\n\t\t// Maximum zoom level of the map.\r\n\t\t// If not specified and at least one `GridLayer` or `TileLayer` is in the map,\r\n\t\t// the highest of their `maxZoom` options will be used instead.\r\n\t\tmaxZoom: undefined,\r\n\r\n\t\t// @option layers: Layer[] = []\r\n\t\t// Array of layers that will be added to the map initially\r\n\t\tlayers: [],\r\n\r\n\t\t// @option maxBounds: LatLngBounds = null\r\n\t\t// When this option is set, the map restricts the view to the given\r\n\t\t// geographical bounds, bouncing the user back if the user tries to pan\r\n\t\t// outside the view. To set the restriction dynamically, use\r\n\t\t// [`setMaxBounds`](#map-setmaxbounds) method.\r\n\t\tmaxBounds: undefined,\r\n\r\n\t\t// @option renderer: Renderer = *\r\n\t\t// The default method for drawing vector layers on the map. `L.SVG`\r\n\t\t// or `L.Canvas` by default depending on browser support.\r\n\t\trenderer: undefined,\r\n\r\n\r\n\t\t// @section Animation Options\r\n\t\t// @option zoomAnimation: Boolean = true\r\n\t\t// Whether the map zoom animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tzoomAnimation: true,\r\n\r\n\t\t// @option zoomAnimationThreshold: Number = 4\r\n\t\t// Won't animate zoom if the zoom difference exceeds this value.\r\n\t\tzoomAnimationThreshold: 4,\r\n\r\n\t\t// @option fadeAnimation: Boolean = true\r\n\t\t// Whether the tile fade animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tfadeAnimation: true,\r\n\r\n\t\t// @option markerZoomAnimation: Boolean = true\r\n\t\t// Whether markers animate their zoom with the zoom animation, if disabled\r\n\t\t// they will disappear for the length of the animation. By default it's\r\n\t\t// enabled in all browsers that support CSS3 Transitions except Android.\r\n\t\tmarkerZoomAnimation: true,\r\n\r\n\t\t// @option transform3DLimit: Number = 2^23\r\n\t\t// Defines the maximum size of a CSS translation transform. The default\r\n\t\t// value should not be changed unless a web browser positions layers in\r\n\t\t// the wrong place after doing a large `panBy`.\r\n\t\ttransform3DLimit: 8388608, // Precision limit of a 32-bit float\r\n\r\n\t\t// @section Interaction Options\r\n\t\t// @option zoomSnap: Number = 1\r\n\t\t// Forces the map's zoom level to always be a multiple of this, particularly\r\n\t\t// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.\r\n\t\t// By default, the zoom level snaps to the nearest integer; lower values\r\n\t\t// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`\r\n\t\t// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.\r\n\t\tzoomSnap: 1,\r\n\r\n\t\t// @option zoomDelta: Number = 1\r\n\t\t// Controls how much the map's zoom level will change after a\r\n\t\t// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`\r\n\t\t// or `-` on the keyboard, or using the [zoom controls](#control-zoom).\r\n\t\t// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.\r\n\t\tzoomDelta: 1,\r\n\r\n\t\t// @option trackResize: Boolean = true\r\n\t\t// Whether the map automatically handles browser window resize to update itself.\r\n\t\ttrackResize: true\r\n\t},\r\n\r\n\tinitialize: function (id, options) { // (HTMLElement or String, Object)\r\n\t\toptions = Util.setOptions(this, options);\r\n\r\n\t\t// Make sure to assign internal flags at the beginning,\r\n\t\t// to avoid inconsistent state in some edge cases.\r\n\t\tthis._handlers = [];\r\n\t\tthis._layers = {};\r\n\t\tthis._zoomBoundLayers = {};\r\n\t\tthis._sizeChanged = true;\r\n\r\n\t\tthis._initContainer(id);\r\n\t\tthis._initLayout();\r\n\r\n\t\t// hack for https://github.com/Leaflet/Leaflet/issues/1980\r\n\t\tthis._onResize = Util.bind(this._onResize, this);\r\n\r\n\t\tthis._initEvents();\r\n\r\n\t\tif (options.maxBounds) {\r\n\t\t\tthis.setMaxBounds(options.maxBounds);\r\n\t\t}\r\n\r\n\t\tif (options.zoom !== undefined) {\r\n\t\t\tthis._zoom = this._limitZoom(options.zoom);\r\n\t\t}\r\n\r\n\t\tif (options.center && options.zoom !== undefined) {\r\n\t\t\tthis.setView(toLatLng(options.center), options.zoom, {reset: true});\r\n\t\t}\r\n\r\n\t\tthis.callInitHooks();\r\n\r\n\t\t// don't animate on browsers without hardware-accelerated transitions or old Android/Opera\r\n\t\tthis._zoomAnimated = DomUtil.TRANSITION && Browser.any3d && !Browser.mobileOpera &&\r\n\t\t\t\tthis.options.zoomAnimation;\r\n\r\n\t\t// zoom transitions run with the same duration for all layers, so if one of transitionend events\r\n\t\t// happens after starting zoom animation (propagating to the map pane), we know that it ended globally\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tthis._createAnimProxy();\r\n\t\t\tDomEvent.on(this._proxy, DomUtil.TRANSITION_END, this._catchTransitionEnd, this);\r\n\t\t}\r\n\r\n\t\tthis._addLayers(this.options.layers);\r\n\t},\r\n\r\n\r\n\t// @section Methods for modifying map state\r\n\r\n\t// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) with the given\r\n\t// animation options.\r\n\tsetView: function (center, zoom, options) {\r\n\r\n\t\tzoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);\r\n\t\tcenter = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);\r\n\t\toptions = options || {};\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tif (this._loaded && !options.reset && options !== true) {\r\n\r\n\t\t\tif (options.animate !== undefined) {\r\n\t\t\t\toptions.zoom = Util.extend({animate: options.animate}, options.zoom);\r\n\t\t\t\toptions.pan = Util.extend({animate: options.animate, duration: options.duration}, options.pan);\r\n\t\t\t}\r\n\r\n\t\t\t// try animating pan or zoom\r\n\t\t\tvar moved = (this._zoom !== zoom) ?\r\n\t\t\t\tthis._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :\r\n\t\t\t\tthis._tryAnimatedPan(center, options.pan);\r\n\r\n\t\t\tif (moved) {\r\n\t\t\t\t// prevent resize handler call, the view will refresh after animation anyway\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\treturn this;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// animation didn't start, just reset the map view\r\n\t\tthis._resetView(center, zoom, options.pan && options.pan.noMoveStart);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setZoom(zoom: Number, options?: Zoom/pan options): this\r\n\t// Sets the zoom of the map.\r\n\tsetZoom: function (zoom, options) {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthis._zoom = zoom;\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn this.setView(this.getCenter(), zoom, {zoom: options});\r\n\t},\r\n\r\n\t// @method zoomIn(delta?: Number, options?: Zoom options): this\r\n\t// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomIn: function (delta, options) {\r\n\t\tdelta = delta || (Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom + delta, options);\r\n\t},\r\n\r\n\t// @method zoomOut(delta?: Number, options?: Zoom options): this\r\n\t// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomOut: function (delta, options) {\r\n\t\tdelta = delta || (Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom - delta, options);\r\n\t},\r\n\r\n\t// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified geographical point on the map\r\n\t// stationary (e.g. used internally for scroll zoom and double-click zoom).\r\n\t// @alternative\r\n\t// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.\r\n\tsetZoomAround: function (latlng, zoom, options) {\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t viewHalf = this.getSize().divideBy(2),\r\n\t\t containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),\r\n\r\n\t\t centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),\r\n\t\t newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));\r\n\r\n\t\treturn this.setView(newCenter, zoom, {zoom: options});\r\n\t},\r\n\r\n\t_getBoundsCenterZoom: function (bounds, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tbounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);\r\n\r\n\t\tvar paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),\r\n\t\t paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),\r\n\r\n\t\t zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));\r\n\r\n\t\tzoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;\r\n\r\n\t\tif (zoom === Infinity) {\r\n\t\t\treturn {\r\n\t\t\t\tcenter: bounds.getCenter(),\r\n\t\t\t\tzoom: zoom\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tvar paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),\r\n\r\n\t\t swPoint = this.project(bounds.getSouthWest(), zoom),\r\n\t\t nePoint = this.project(bounds.getNorthEast(), zoom),\r\n\t\t center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);\r\n\r\n\t\treturn {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom\r\n\t\t};\r\n\t},\r\n\r\n\t// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets a map view that contains the given geographical bounds with the\r\n\t// maximum zoom level possible.\r\n\tfitBounds: function (bounds, options) {\r\n\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthrow new Error('Bounds are not valid.');\r\n\t\t}\r\n\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.setView(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method fitWorld(options?: fitBounds options): this\r\n\t// Sets a map view that mostly contains the whole world with the maximum\r\n\t// zoom level possible.\r\n\tfitWorld: function (options) {\r\n\t\treturn this.fitBounds([[-90, -180], [90, 180]], options);\r\n\t},\r\n\r\n\t// @method panTo(latlng: LatLng, options?: Pan options): this\r\n\t// Pans the map to a given center.\r\n\tpanTo: function (center, options) { // (LatLng)\r\n\t\treturn this.setView(center, this._zoom, {pan: options});\r\n\t},\r\n\r\n\t// @method panBy(offset: Point, options?: Pan options): this\r\n\t// Pans the map by a given number of pixels (animated).\r\n\tpanBy: function (offset, options) {\r\n\t\toffset = toPoint(offset).round();\r\n\t\toptions = options || {};\r\n\r\n\t\tif (!offset.x && !offset.y) {\r\n\t\t\treturn this.fire('moveend');\r\n\t\t}\r\n\t\t// If we pan too far, Chrome gets issues with tiles\r\n\t\t// and makes them disappear or appear in the wrong place (slightly offset) #2602\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) {\r\n\t\t\tthis._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tif (!this._panAnim) {\r\n\t\t\tthis._panAnim = new PosAnimation();\r\n\r\n\t\t\tthis._panAnim.on({\r\n\t\t\t\t'step': this._onPanTransitionStep,\r\n\t\t\t\t'end': this._onPanTransitionEnd\r\n\t\t\t}, this);\r\n\t\t}\r\n\r\n\t\t// don't fire movestart if animating inertia\r\n\t\tif (!options.noMoveStart) {\r\n\t\t\tthis.fire('movestart');\r\n\t\t}\r\n\r\n\t\t// animate pan unless animate: false specified\r\n\t\tif (options.animate !== false) {\r\n\t\t\tDomUtil.addClass(this._mapPane, 'leaflet-pan-anim');\r\n\r\n\t\t\tvar newPos = this._getMapPanePos().subtract(offset).round();\r\n\t\t\tthis._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);\r\n\t\t} else {\r\n\t\t\tthis._rawPanBy(offset);\r\n\t\t\tthis.fire('move').fire('moveend');\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) performing a smooth\r\n\t// pan-zoom animation.\r\n\tflyTo: function (targetCenter, targetZoom, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tif (options.animate === false || !Browser.any3d) {\r\n\t\t\treturn this.setView(targetCenter, targetZoom, options);\r\n\t\t}\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tvar from = this.project(this.getCenter()),\r\n\t\t to = this.project(targetCenter),\r\n\t\t size = this.getSize(),\r\n\t\t startZoom = this._zoom;\r\n\r\n\t\ttargetCenter = toLatLng(targetCenter);\r\n\t\ttargetZoom = targetZoom === undefined ? startZoom : targetZoom;\r\n\r\n\t\tvar w0 = Math.max(size.x, size.y),\r\n\t\t w1 = w0 * this.getZoomScale(startZoom, targetZoom),\r\n\t\t u1 = (to.distanceTo(from)) || 1,\r\n\t\t rho = 1.42,\r\n\t\t rho2 = rho * rho;\r\n\r\n\t\tfunction r(i) {\r\n\t\t\tvar s1 = i ? -1 : 1,\r\n\t\t\t s2 = i ? w1 : w0,\r\n\t\t\t t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,\r\n\t\t\t b1 = 2 * s2 * rho2 * u1,\r\n\t\t\t b = t1 / b1,\r\n\t\t\t sq = Math.sqrt(b * b + 1) - b;\r\n\r\n\t\t\t // workaround for floating point precision bug when sq = 0, log = -Infinite,\r\n\t\t\t // thus triggering an infinite loop in flyTo\r\n\t\t\t var log = sq < 0.000000001 ? -18 : Math.log(sq);\r\n\r\n\t\t\treturn log;\r\n\t\t}\r\n\r\n\t\tfunction sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\r\n\t\tfunction cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\r\n\t\tfunction tanh(n) { return sinh(n) / cosh(n); }\r\n\r\n\t\tvar r0 = r(0);\r\n\r\n\t\tfunction w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }\r\n\t\tfunction u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }\r\n\r\n\t\tfunction easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }\r\n\r\n\t\tvar start = Date.now(),\r\n\t\t S = (r(1) - r0) / rho,\r\n\t\t duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;\r\n\r\n\t\tfunction frame() {\r\n\t\t\tvar t = (Date.now() - start) / duration,\r\n\t\t\t s = easeOut(t) * S;\r\n\r\n\t\t\tif (t <= 1) {\r\n\t\t\t\tthis._flyToFrame = Util.requestAnimFrame(frame, this);\r\n\r\n\t\t\t\tthis._move(\r\n\t\t\t\t\tthis.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),\r\n\t\t\t\t\tthis.getScaleZoom(w0 / w(s), startZoom),\r\n\t\t\t\t\t{flyTo: true});\r\n\r\n\t\t\t} else {\r\n\t\t\t\tthis\r\n\t\t\t\t\t._move(targetCenter, targetZoom)\r\n\t\t\t\t\t._moveEnd(true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._moveStart(true, options.noMoveStart);\r\n\r\n\t\tframe.call(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),\r\n\t// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).\r\n\tflyToBounds: function (bounds, options) {\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.flyTo(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method setMaxBounds(bounds: LatLngBounds): this\r\n\t// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).\r\n\tsetMaxBounds: function (bounds) {\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (this.listens('moveend', this._panInsideMaxBounds)) {\r\n\t\t\tthis.off('moveend', this._panInsideMaxBounds);\r\n\t\t}\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthis.options.maxBounds = null;\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tthis.options.maxBounds = bounds;\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\tthis._panInsideMaxBounds();\r\n\t\t}\r\n\r\n\t\treturn this.on('moveend', this._panInsideMaxBounds);\r\n\t},\r\n\r\n\t// @method setMinZoom(zoom: Number): this\r\n\t// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).\r\n\tsetMinZoom: function (zoom) {\r\n\t\tvar oldZoom = this.options.minZoom;\r\n\t\tthis.options.minZoom = zoom;\r\n\r\n\t\tif (this._loaded && oldZoom !== zoom) {\r\n\t\t\tthis.fire('zoomlevelschange');\r\n\r\n\t\t\tif (this.getZoom() < this.options.minZoom) {\r\n\t\t\t\treturn this.setZoom(zoom);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setMaxZoom(zoom: Number): this\r\n\t// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).\r\n\tsetMaxZoom: function (zoom) {\r\n\t\tvar oldZoom = this.options.maxZoom;\r\n\t\tthis.options.maxZoom = zoom;\r\n\r\n\t\tif (this._loaded && oldZoom !== zoom) {\r\n\t\t\tthis.fire('zoomlevelschange');\r\n\r\n\t\t\tif (this.getZoom() > this.options.maxZoom) {\r\n\t\t\t\treturn this.setZoom(zoom);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this\r\n\t// Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.\r\n\tpanInsideBounds: function (bounds, options) {\r\n\t\tthis._enforcingBounds = true;\r\n\t\tvar center = this.getCenter(),\r\n\t\t newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));\r\n\r\n\t\tif (!center.equals(newCenter)) {\r\n\t\t\tthis.panTo(newCenter, options);\r\n\t\t}\r\n\r\n\t\tthis._enforcingBounds = false;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method panInside(latlng: LatLng, options?: padding options): this\r\n\t// Pans the map the minimum amount to make the `latlng` visible. Use\r\n\t// padding options to fit the display to more restricted bounds.\r\n\t// If `latlng` is already within the (optionally padded) display bounds,\r\n\t// the map will not be panned.\r\n\tpanInside: function (latlng, options) {\r\n\t\toptions = options || {};\r\n\r\n\t\tvar paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),\r\n\t\t paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),\r\n\t\t pixelCenter = this.project(this.getCenter()),\r\n\t\t pixelPoint = this.project(latlng),\r\n\t\t pixelBounds = this.getPixelBounds(),\r\n\t\t paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),\r\n\t\t paddedSize = paddedBounds.getSize();\r\n\r\n\t\tif (!paddedBounds.contains(pixelPoint)) {\r\n\t\t\tthis._enforcingBounds = true;\r\n\t\t\tvar centerOffset = pixelPoint.subtract(paddedBounds.getCenter());\r\n\t\t\tvar offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);\r\n\t\t\tpixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;\r\n\t\t\tpixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;\r\n\t\t\tthis.panTo(this.unproject(pixelCenter), options);\r\n\t\t\tthis._enforcingBounds = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method invalidateSize(options: Zoom/pan options): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default. If `options.pan` is `false`, panning will not occur.\r\n\t// If `options.debounceMoveend` is `true`, it will delay `moveend` event so\r\n\t// that it doesn't happen often even if the method is called many\r\n\t// times in a row.\r\n\r\n\t// @alternative\r\n\t// @method invalidateSize(animate: Boolean): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default.\r\n\tinvalidateSize: function (options) {\r\n\t\tif (!this._loaded) { return this; }\r\n\r\n\t\toptions = Util.extend({\r\n\t\t\tanimate: false,\r\n\t\t\tpan: true\r\n\t\t}, options === true ? {animate: true} : options);\r\n\r\n\t\tvar oldSize = this.getSize();\r\n\t\tthis._sizeChanged = true;\r\n\t\tthis._lastCenter = null;\r\n\r\n\t\tvar newSize = this.getSize(),\r\n\t\t oldCenter = oldSize.divideBy(2).round(),\r\n\t\t newCenter = newSize.divideBy(2).round(),\r\n\t\t offset = oldCenter.subtract(newCenter);\r\n\r\n\t\tif (!offset.x && !offset.y) { return this; }\r\n\r\n\t\tif (options.animate && options.pan) {\r\n\t\t\tthis.panBy(offset);\r\n\r\n\t\t} else {\r\n\t\t\tif (options.pan) {\r\n\t\t\t\tthis._rawPanBy(offset);\r\n\t\t\t}\r\n\r\n\t\t\tthis.fire('move');\r\n\r\n\t\t\tif (options.debounceMoveend) {\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\tthis._sizeTimer = setTimeout(Util.bind(this.fire, this, 'moveend'), 200);\r\n\t\t\t} else {\r\n\t\t\t\tthis.fire('moveend');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @section Map state change events\r\n\t\t// @event resize: ResizeEvent\r\n\t\t// Fired when the map is resized.\r\n\t\treturn this.fire('resize', {\r\n\t\t\toldSize: oldSize,\r\n\t\t\tnewSize: newSize\r\n\t\t});\r\n\t},\r\n\r\n\t// @section Methods for modifying map state\r\n\t// @method stop(): this\r\n\t// Stops the currently running `panTo` or `flyTo` animation, if any.\r\n\tstop: function () {\r\n\t\tthis.setZoom(this._limitZoom(this._zoom));\r\n\t\tif (!this.options.zoomSnap) {\r\n\t\t\tthis.fire('viewreset');\r\n\t\t}\r\n\t\treturn this._stop();\r\n\t},\r\n\r\n\t// @section Geolocation methods\r\n\t// @method locate(options?: Locate options): this\r\n\t// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)\r\n\t// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,\r\n\t// and optionally sets the map view to the user's location with respect to\r\n\t// detection accuracy (or to the world view if geolocation failed).\r\n\t// Note that, if your page doesn't use HTTPS, this method will fail in\r\n\t// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))\r\n\t// See `Locate options` for more details.\r\n\tlocate: function (options) {\r\n\r\n\t\toptions = this._locateOptions = Util.extend({\r\n\t\t\ttimeout: 10000,\r\n\t\t\twatch: false\r\n\t\t\t// setView: false\r\n\t\t\t// maxZoom: <Number>\r\n\t\t\t// maximumAge: 0\r\n\t\t\t// enableHighAccuracy: false\r\n\t\t}, options);\r\n\r\n\t\tif (!('geolocation' in navigator)) {\r\n\t\t\tthis._handleGeolocationError({\r\n\t\t\t\tcode: 0,\r\n\t\t\t\tmessage: 'Geolocation not supported.'\r\n\t\t\t});\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar onResponse = Util.bind(this._handleGeolocationResponse, this),\r\n\t\t onError = Util.bind(this._handleGeolocationError, this);\r\n\r\n\t\tif (options.watch) {\r\n\t\t\tthis._locationWatchId =\r\n\t\t\t navigator.geolocation.watchPosition(onResponse, onError, options);\r\n\t\t} else {\r\n\t\t\tnavigator.geolocation.getCurrentPosition(onResponse, onError, options);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method stopLocate(): this\r\n\t// Stops watching location previously initiated by `map.locate({watch: true})`\r\n\t// and aborts resetting the map view if map.locate was called with\r\n\t// `{setView: true}`.\r\n\tstopLocate: function () {\r\n\t\tif (navigator.geolocation && navigator.geolocation.clearWatch) {\r\n\t\t\tnavigator.geolocation.clearWatch(this._locationWatchId);\r\n\t\t}\r\n\t\tif (this._locateOptions) {\r\n\t\t\tthis._locateOptions.setView = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_handleGeolocationError: function (error) {\r\n\t\tif (!this._container._leaflet_id) { return; }\r\n\r\n\t\tvar c = error.code,\r\n\t\t message = error.message ||\r\n\t\t (c === 1 ? 'permission denied' :\r\n\t\t (c === 2 ? 'position unavailable' : 'timeout'));\r\n\r\n\t\tif (this._locateOptions.setView && !this._loaded) {\r\n\t\t\tthis.fitWorld();\r\n\t\t}\r\n\r\n\t\t// @section Location events\r\n\t\t// @event locationerror: ErrorEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method) failed.\r\n\t\tthis.fire('locationerror', {\r\n\t\t\tcode: c,\r\n\t\t\tmessage: 'Geolocation error: ' + message + '.'\r\n\t\t});\r\n\t},\r\n\r\n\t_handleGeolocationResponse: function (pos) {\r\n\t\tif (!this._container._leaflet_id) { return; }\r\n\r\n\t\tvar lat = pos.coords.latitude,\r\n\t\t lng = pos.coords.longitude,\r\n\t\t latlng = new LatLng(lat, lng),\r\n\t\t bounds = latlng.toBounds(pos.coords.accuracy * 2),\r\n\t\t options = this._locateOptions;\r\n\r\n\t\tif (options.setView) {\r\n\t\t\tvar zoom = this.getBoundsZoom(bounds);\r\n\t\t\tthis.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);\r\n\t\t}\r\n\r\n\t\tvar data = {\r\n\t\t\tlatlng: latlng,\r\n\t\t\tbounds: bounds,\r\n\t\t\ttimestamp: pos.timestamp\r\n\t\t};\r\n\r\n\t\tfor (var i in pos.coords) {\r\n\t\t\tif (typeof pos.coords[i] === 'number') {\r\n\t\t\t\tdata[i] = pos.coords[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @event locationfound: LocationEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method)\r\n\t\t// went successfully.\r\n\t\tthis.fire('locationfound', data);\r\n\t},\r\n\r\n\t// TODO Appropriate docs section?\r\n\t// @section Other Methods\r\n\t// @method addHandler(name: String, HandlerClass: Function): this\r\n\t// Adds a new `Handler` to the map, given its name and constructor function.\r\n\taddHandler: function (name, HandlerClass) {\r\n\t\tif (!HandlerClass) { return this; }\r\n\r\n\t\tvar handler = this[name] = new HandlerClass(this);\r\n\r\n\t\tthis._handlers.push(handler);\r\n\r\n\t\tif (this.options[name]) {\r\n\t\t\thandler.enable();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove(): this\r\n\t// Destroys the map and clears all related event listeners.\r\n\tremove: function () {\r\n\r\n\t\tthis._initEvents(true);\r\n\t\tif (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }\r\n\r\n\t\tif (this._containerId !== this._container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is being reused by another instance');\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\t// throws error in IE6-8\r\n\t\t\tdelete this._container._leaflet_id;\r\n\t\t\tdelete this._containerId;\r\n\t\t} catch (e) {\r\n\t\t\t/*eslint-disable */\r\n\t\t\tthis._container._leaflet_id = undefined;\r\n\t\t\t/* eslint-enable */\r\n\t\t\tthis._containerId = undefined;\r\n\t\t}\r\n\r\n\t\tif (this._locationWatchId !== undefined) {\r\n\t\t\tthis.stopLocate();\r\n\t\t}\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tDomUtil.remove(this._mapPane);\r\n\r\n\t\tif (this._clearControlPos) {\r\n\t\t\tthis._clearControlPos();\r\n\t\t}\r\n\t\tif (this._resizeRequest) {\r\n\t\t\tUtil.cancelAnimFrame(this._resizeRequest);\r\n\t\t\tthis._resizeRequest = null;\r\n\t\t}\r\n\r\n\t\tthis._clearHandlers();\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\t// @section Map state change events\r\n\t\t\t// @event unload: Event\r\n\t\t\t// Fired when the map is destroyed with [remove](#map-remove) method.\r\n\t\t\tthis.fire('unload');\r\n\t\t}\r\n\r\n\t\tvar i;\r\n\t\tfor (i in this._layers) {\r\n\t\t\tthis._layers[i].remove();\r\n\t\t}\r\n\t\tfor (i in this._panes) {\r\n\t\t\tDomUtil.remove(this._panes[i]);\r\n\t\t}\r\n\r\n\t\tthis._layers = [];\r\n\t\tthis._panes = [];\r\n\t\tdelete this._mapPane;\r\n\t\tdelete this._renderer;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\t// @method createPane(name: String, container?: HTMLElement): HTMLElement\r\n\t// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,\r\n\t// then returns it. The pane is created as a child of `container`, or\r\n\t// as a child of the main map pane if not set.\r\n\tcreatePane: function (name, container) {\r\n\t\tvar className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),\r\n\t\t pane = DomUtil.create('div', className, container || this._mapPane);\r\n\r\n\t\tif (name) {\r\n\t\t\tthis._panes[name] = pane;\r\n\t\t}\r\n\t\treturn pane;\r\n\t},\r\n\r\n\t// @section Methods for Getting Map State\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the geographical center of the map view\r\n\tgetCenter: function () {\r\n\t\tthis._checkIfLoaded();\r\n\r\n\t\tif (this._lastCenter && !this._moved()) {\r\n\t\t\treturn this._lastCenter.clone();\r\n\t\t}\r\n\t\treturn this.layerPointToLatLng(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// @method getZoom(): Number\r\n\t// Returns the current zoom level of the map view\r\n\tgetZoom: function () {\r\n\t\treturn this._zoom;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the geographical bounds visible in the current map view\r\n\tgetBounds: function () {\r\n\t\tvar bounds = this.getPixelBounds(),\r\n\t\t sw = this.unproject(bounds.getBottomLeft()),\r\n\t\t ne = this.unproject(bounds.getTopRight());\r\n\r\n\t\treturn new LatLngBounds(sw, ne);\r\n\t},\r\n\r\n\t// @method getMinZoom(): Number\r\n\t// Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.\r\n\tgetMinZoom: function () {\r\n\t\treturn this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;\r\n\t},\r\n\r\n\t// @method getMaxZoom(): Number\r\n\t// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).\r\n\tgetMaxZoom: function () {\r\n\t\treturn this.options.maxZoom === undefined ?\r\n\t\t\t(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :\r\n\t\t\tthis.options.maxZoom;\r\n\t},\r\n\r\n\t// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number\r\n\t// Returns the maximum zoom level on which the given bounds fit to the map\r\n\t// view in its entirety. If `inside` (optional) is set to `true`, the method\r\n\t// instead returns the minimum zoom level on which the map view fits into\r\n\t// the given bounds in its entirety.\r\n\tgetBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number\r\n\t\tbounds = toLatLngBounds(bounds);\r\n\t\tpadding = toPoint(padding || [0, 0]);\r\n\r\n\t\tvar zoom = this.getZoom() || 0,\r\n\t\t min = this.getMinZoom(),\r\n\t\t max = this.getMaxZoom(),\r\n\t\t nw = bounds.getNorthWest(),\r\n\t\t se = bounds.getSouthEast(),\r\n\t\t size = this.getSize().subtract(padding),\r\n\t\t boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),\r\n\t\t snap = Browser.any3d ? this.options.zoomSnap : 1,\r\n\t\t scalex = size.x / boundsSize.x,\r\n\t\t scaley = size.y / boundsSize.y,\r\n\t\t scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);\r\n\r\n\t\tzoom = this.getScaleZoom(scale, zoom);\r\n\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level\r\n\t\t\tzoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;\r\n\t\t}\r\n\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the current size of the map container (in pixels).\r\n\tgetSize: function () {\r\n\t\tif (!this._size || this._sizeChanged) {\r\n\t\t\tthis._size = new Point(\r\n\t\t\t\tthis._container.clientWidth || 0,\r\n\t\t\t\tthis._container.clientHeight || 0);\r\n\r\n\t\t\tthis._sizeChanged = false;\r\n\t\t}\r\n\t\treturn this._size.clone();\r\n\t},\r\n\r\n\t// @method getPixelBounds(): Bounds\r\n\t// Returns the bounds of the current map view in projected pixel\r\n\t// coordinates (sometimes useful in layer and overlay implementations).\r\n\tgetPixelBounds: function (center, zoom) {\r\n\t\tvar topLeftPoint = this._getTopLeftPoint(center, zoom);\r\n\t\treturn new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));\r\n\t},\r\n\r\n\t// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to\r\n\t// the map pane? \"left point of the map layer\" can be confusing, specially\r\n\t// since there can be negative offsets.\r\n\t// @method getPixelOrigin(): Point\r\n\t// Returns the projected pixel coordinates of the top left point of\r\n\t// the map layer (useful in custom layer and overlay implementations).\r\n\tgetPixelOrigin: function () {\r\n\t\tthis._checkIfLoaded();\r\n\t\treturn this._pixelOrigin;\r\n\t},\r\n\r\n\t// @method getPixelWorldBounds(zoom?: Number): Bounds\r\n\t// Returns the world's bounds in pixel coordinates for zoom level `zoom`.\r\n\t// If `zoom` is omitted, the map's current zoom level is used.\r\n\tgetPixelWorldBounds: function (zoom) {\r\n\t\treturn this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method getPane(pane: String|HTMLElement): HTMLElement\r\n\t// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).\r\n\tgetPane: function (pane) {\r\n\t\treturn typeof pane === 'string' ? this._panes[pane] : pane;\r\n\t},\r\n\r\n\t// @method getPanes(): Object\r\n\t// Returns a plain object containing the names of all [panes](#map-pane) as keys and\r\n\t// the panes as values.\r\n\tgetPanes: function () {\r\n\t\treturn this._panes;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTML element that contains the map.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\r\n\t// @section Conversion Methods\r\n\r\n\t// @method getZoomScale(toZoom: Number, fromZoom: Number): Number\r\n\t// Returns the scale factor to be applied to a map transition from zoom level\r\n\t// `fromZoom` to `toZoom`. Used internally to help with zoom animations.\r\n\tgetZoomScale: function (toZoom, fromZoom) {\r\n\t\t// TODO replace with universal implementation after refactoring projections\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\treturn crs.scale(toZoom) / crs.scale(fromZoom);\r\n\t},\r\n\r\n\t// @method getScaleZoom(scale: Number, fromZoom: Number): Number\r\n\t// Returns the zoom level that the map would end up at, if it is at `fromZoom`\r\n\t// level and everything is scaled by a factor of `scale`. Inverse of\r\n\t// [`getZoomScale`](#map-getZoomScale).\r\n\tgetScaleZoom: function (scale, fromZoom) {\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\tvar zoom = crs.zoom(scale * crs.scale(fromZoom));\r\n\t\treturn isNaN(zoom) ? Infinity : zoom;\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng, zoom: Number): Point\r\n\t// Projects a geographical coordinate `LatLng` according to the projection\r\n\t// of the map's CRS, then scales it according to `zoom` and the CRS's\r\n\t// `Transformation`. The result is pixel coordinate relative to\r\n\t// the CRS origin.\r\n\tproject: function (latlng, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.latLngToPoint(toLatLng(latlng), zoom);\r\n\t},\r\n\r\n\t// @method unproject(point: Point, zoom: Number): LatLng\r\n\t// Inverse of [`project`](#map-project).\r\n\tunproject: function (point, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.pointToLatLng(toPoint(point), zoom);\r\n\t},\r\n\r\n\t// @method layerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding geographical coordinate (for the current zoom level).\r\n\tlayerPointToLatLng: function (point) {\r\n\t\tvar projectedPoint = toPoint(point).add(this.getPixelOrigin());\r\n\t\treturn this.unproject(projectedPoint);\r\n\t},\r\n\r\n\t// @method latLngToLayerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the [origin pixel](#map-getpixelorigin).\r\n\tlatLngToLayerPoint: function (latlng) {\r\n\t\tvar projectedPoint = this.project(toLatLng(latlng))._round();\r\n\t\treturn projectedPoint._subtract(this.getPixelOrigin());\r\n\t},\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the\r\n\t// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the\r\n\t// CRS's bounds.\r\n\t// By default this means longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees.\r\n\twrapLatLng: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLng(toLatLng(latlng));\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring that\r\n\t// its center is within the CRS's bounds.\r\n\t// By default this means the center longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees, and the majority of the bounds\r\n\t// overlaps the CRS's bounds.\r\n\twrapLatLngBounds: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates according to\r\n\t// the map's CRS. By default this measures distance in meters.\r\n\tdistance: function (latlng1, latlng2) {\r\n\t\treturn this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));\r\n\t},\r\n\r\n\t// @method containerPointToLayerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the map container, returns the corresponding\r\n\t// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).\r\n\tcontainerPointToLayerPoint: function (point) { // (Point)\r\n\t\treturn toPoint(point).subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method layerPointToContainerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding pixel coordinate relative to the map container.\r\n\tlayerPointToContainerPoint: function (point) { // (Point)\r\n\t\treturn toPoint(point).add(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method containerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the map container, returns\r\n\t// the corresponding geographical coordinate (for the current zoom level).\r\n\tcontainerPointToLatLng: function (point) {\r\n\t\tvar layerPoint = this.containerPointToLayerPoint(toPoint(point));\r\n\t\treturn this.layerPointToLatLng(layerPoint);\r\n\t},\r\n\r\n\t// @method latLngToContainerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the map container.\r\n\tlatLngToContainerPoint: function (latlng) {\r\n\t\treturn this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));\r\n\t},\r\n\r\n\t// @method mouseEventToContainerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to the\r\n\t// map container where the event took place.\r\n\tmouseEventToContainerPoint: function (e) {\r\n\t\treturn DomEvent.getMousePosition(e, this._container);\r\n\t},\r\n\r\n\t// @method mouseEventToLayerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to\r\n\t// the [origin pixel](#map-getpixelorigin) where the event took place.\r\n\tmouseEventToLayerPoint: function (e) {\r\n\t\treturn this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));\r\n\t},\r\n\r\n\t// @method mouseEventToLatLng(ev: MouseEvent): LatLng\r\n\t// Given a MouseEvent object, returns geographical coordinate where the\r\n\t// event took place.\r\n\tmouseEventToLatLng: function (e) { // (MouseEvent)\r\n\t\treturn this.layerPointToLatLng(this.mouseEventToLayerPoint(e));\r\n\t},\r\n\r\n\r\n\t// map initialization methods\r\n\r\n\t_initContainer: function (id) {\r\n\t\tvar container = this._container = DomUtil.get(id);\r\n\r\n\t\tif (!container) {\r\n\t\t\tthrow new Error('Map container not found.');\r\n\t\t} else if (container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is already initialized.');\r\n\t\t}\r\n\r\n\t\tDomEvent.on(container, 'scroll', this._onScroll, this);\r\n\t\tthis._containerId = Util.stamp(container);\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar container = this._container;\r\n\r\n\t\tthis._fadeAnimated = this.options.fadeAnimation && Browser.any3d;\r\n\r\n\t\tDomUtil.addClass(container, 'leaflet-container' +\r\n\t\t\t(Browser.touch ? ' leaflet-touch' : '') +\r\n\t\t\t(Browser.retina ? ' leaflet-retina' : '') +\r\n\t\t\t(Browser.ielt9 ? ' leaflet-oldie' : '') +\r\n\t\t\t(Browser.safari ? ' leaflet-safari' : '') +\r\n\t\t\t(this._fadeAnimated ? ' leaflet-fade-anim' : ''));\r\n\r\n\t\tvar position = DomUtil.getStyle(container, 'position');\r\n\r\n\t\tif (position !== 'absolute' && position !== 'relative' && position !== 'fixed' && position !== 'sticky') {\r\n\t\t\tcontainer.style.position = 'relative';\r\n\t\t}\r\n\r\n\t\tthis._initPanes();\r\n\r\n\t\tif (this._initControlPos) {\r\n\t\t\tthis._initControlPos();\r\n\t\t}\r\n\t},\r\n\r\n\t_initPanes: function () {\r\n\t\tvar panes = this._panes = {};\r\n\t\tthis._paneRenderers = {};\r\n\r\n\t\t// @section\r\n\t\t//\r\n\t\t// Panes are DOM elements used to control the ordering of layers on the map. You\r\n\t\t// can access panes with [`map.getPane`](#map-getpane) or\r\n\t\t// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the\r\n\t\t// [`map.createPane`](#map-createpane) method.\r\n\t\t//\r\n\t\t// Every map has the following default panes that differ only in zIndex.\r\n\t\t//\r\n\t\t// @pane mapPane: HTMLElement = 'auto'\r\n\t\t// Pane that contains all other map panes\r\n\r\n\t\tthis._mapPane = this.createPane('mapPane', this._container);\r\n\t\tDomUtil.setPosition(this._mapPane, new Point(0, 0));\r\n\r\n\t\t// @pane tilePane: HTMLElement = 200\r\n\t\t// Pane for `GridLayer`s and `TileLayer`s\r\n\t\tthis.createPane('tilePane');\r\n\t\t// @pane overlayPane: HTMLElement = 400\r\n\t\t// Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s\r\n\t\tthis.createPane('overlayPane');\r\n\t\t// @pane shadowPane: HTMLElement = 500\r\n\t\t// Pane for overlay shadows (e.g. `Marker` shadows)\r\n\t\tthis.createPane('shadowPane');\r\n\t\t// @pane markerPane: HTMLElement = 600\r\n\t\t// Pane for `Icon`s of `Marker`s\r\n\t\tthis.createPane('markerPane');\r\n\t\t// @pane tooltipPane: HTMLElement = 650\r\n\t\t// Pane for `Tooltip`s.\r\n\t\tthis.createPane('tooltipPane');\r\n\t\t// @pane popupPane: HTMLElement = 700\r\n\t\t// Pane for `Popup`s.\r\n\t\tthis.createPane('popupPane');\r\n\r\n\t\tif (!this.options.markerZoomAnimation) {\r\n\t\t\tDomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');\r\n\t\t\tDomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');\r\n\t\t}\r\n\t},\r\n\r\n\r\n\t// private methods that modify map state\r\n\r\n\t// @section Map state change events\r\n\t_resetView: function (center, zoom, noMoveStart) {\r\n\t\tDomUtil.setPosition(this._mapPane, new Point(0, 0));\r\n\r\n\t\tvar loading = !this._loaded;\r\n\t\tthis._loaded = true;\r\n\t\tzoom = this._limitZoom(zoom);\r\n\r\n\t\tthis.fire('viewprereset');\r\n\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\t\tthis\r\n\t\t\t._moveStart(zoomChanged, noMoveStart)\r\n\t\t\t._move(center, zoom)\r\n\t\t\t._moveEnd(zoomChanged);\r\n\r\n\t\t// @event viewreset: Event\r\n\t\t// Fired when the map needs to redraw its content (this usually happens\r\n\t\t// on map zoom or load). Very useful for creating custom overlays.\r\n\t\tthis.fire('viewreset');\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the map is initialized (when its center and zoom are set\r\n\t\t// for the first time).\r\n\t\tif (loading) {\r\n\t\t\tthis.fire('load');\r\n\t\t}\r\n\t},\r\n\r\n\t_moveStart: function (zoomChanged, noMoveStart) {\r\n\t\t// @event zoomstart: Event\r\n\t\t// Fired when the map zoom is about to change (e.g. before zoom animation).\r\n\t\t// @event movestart: Event\r\n\t\t// Fired when the view of the map starts changing (e.g. user starts dragging the map).\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomstart');\r\n\t\t}\r\n\t\tif (!noMoveStart) {\r\n\t\t\tthis.fire('movestart');\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_move: function (center, zoom, data, supressEvent) {\r\n\t\tif (zoom === undefined) {\r\n\t\t\tzoom = this._zoom;\r\n\t\t}\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\r\n\t\tthis._zoom = zoom;\r\n\t\tthis._lastCenter = center;\r\n\t\tthis._pixelOrigin = this._getNewPixelOrigin(center);\r\n\r\n\t\tif (!supressEvent) {\r\n\t\t\t// @event zoom: Event\r\n\t\t\t// Fired repeatedly during any change in zoom level,\r\n\t\t\t// including zoom and fly animations.\r\n\t\t\tif (zoomChanged || (data && data.pinch)) {\t// Always fire 'zoom' if pinching because #3530\r\n\t\t\t\tthis.fire('zoom', data);\r\n\t\t\t}\r\n\r\n\t\t\t// @event move: Event\r\n\t\t\t// Fired repeatedly during any movement of the map,\r\n\t\t\t// including pan and fly animations.\r\n\t\t\tthis.fire('move', data);\r\n\t\t} else if (data && data.pinch) {\t// Always fire 'zoom' if pinching because #3530\r\n\t\t\tthis.fire('zoom', data);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_moveEnd: function (zoomChanged) {\r\n\t\t// @event zoomend: Event\r\n\t\t// Fired when the map zoom changed, after any animations.\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomend');\r\n\t\t}\r\n\r\n\t\t// @event moveend: Event\r\n\t\t// Fired when the center of the map stops changing\r\n\t\t// (e.g. user stopped dragging the map or after non-centered zoom).\r\n\t\treturn this.fire('moveend');\r\n\t},\r\n\r\n\t_stop: function () {\r\n\t\tUtil.cancelAnimFrame(this._flyToFrame);\r\n\t\tif (this._panAnim) {\r\n\t\t\tthis._panAnim.stop();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_rawPanBy: function (offset) {\r\n\t\tDomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));\r\n\t},\r\n\r\n\t_getZoomSpan: function () {\r\n\t\treturn this.getMaxZoom() - this.getMinZoom();\r\n\t},\r\n\r\n\t_panInsideMaxBounds: function () {\r\n\t\tif (!this._enforcingBounds) {\r\n\t\t\tthis.panInsideBounds(this.options.maxBounds);\r\n\t\t}\r\n\t},\r\n\r\n\t_checkIfLoaded: function () {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthrow new Error('Set map center and zoom first.');\r\n\t\t}\r\n\t},\r\n\r\n\t// DOM event handling\r\n\r\n\t// @section Interaction events\r\n\t_initEvents: function (remove) {\r\n\t\tthis._targets = {};\r\n\t\tthis._targets[Util.stamp(this._container)] = this;\r\n\r\n\t\tvar onOff = remove ? DomEvent.off : DomEvent.on;\r\n\r\n\t\t// @event click: MouseEvent\r\n\t\t// Fired when the user clicks (or taps) the map.\r\n\t\t// @event dblclick: MouseEvent\r\n\t\t// Fired when the user double-clicks (or double-taps) the map.\r\n\t\t// @event mousedown: MouseEvent\r\n\t\t// Fired when the user pushes the mouse button on the map.\r\n\t\t// @event mouseup: MouseEvent\r\n\t\t// Fired when the user releases the mouse button on the map.\r\n\t\t// @event mouseover: MouseEvent\r\n\t\t// Fired when the mouse enters the map.\r\n\t\t// @event mouseout: MouseEvent\r\n\t\t// Fired when the mouse leaves the map.\r\n\t\t// @event mousemove: MouseEvent\r\n\t\t// Fired while the mouse moves over the map.\r\n\t\t// @event contextmenu: MouseEvent\r\n\t\t// Fired when the user pushes the right mouse button on the map, prevents\r\n\t\t// default browser context menu from showing if there are listeners on\r\n\t\t// this event. Also fired on mobile when the user holds a single touch\r\n\t\t// for a second (also called long press).\r\n\t\t// @event keypress: KeyboardEvent\r\n\t\t// Fired when the user presses a key from the keyboard that produces a character value while the map is focused.\r\n\t\t// @event keydown: KeyboardEvent\r\n\t\t// Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event,\r\n\t\t// the `keydown` event is fired for keys that produce a character value and for keys\r\n\t\t// that do not produce a character value.\r\n\t\t// @event keyup: KeyboardEvent\r\n\t\t// Fired when the user releases a key from the keyboard while the map is focused.\r\n\t\tonOff(this._container, 'click dblclick mousedown mouseup ' +\r\n\t\t\t'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);\r\n\r\n\t\tif (this.options.trackResize) {\r\n\t\t\tonOff(window, 'resize', this._onResize, this);\r\n\t\t}\r\n\r\n\t\tif (Browser.any3d && this.options.transform3DLimit) {\r\n\t\t\t(remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);\r\n\t\t}\r\n\t},\r\n\r\n\t_onResize: function () {\r\n\t\tUtil.cancelAnimFrame(this._resizeRequest);\r\n\t\tthis._resizeRequest = Util.requestAnimFrame(\r\n\t\t function () { this.invalidateSize({debounceMoveend: true}); }, this);\r\n\t},\r\n\r\n\t_onScroll: function () {\r\n\t\tthis._container.scrollTop = 0;\r\n\t\tthis._container.scrollLeft = 0;\r\n\t},\r\n\r\n\t_onMoveEnd: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\tif (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {\r\n\t\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have\r\n\t\t\t// a pixel offset on very high values, see: https://jsfiddle.net/dg6r5hhb/\r\n\t\t\tthis._resetView(this.getCenter(), this.getZoom());\r\n\t\t}\r\n\t},\r\n\r\n\t_findEventTargets: function (e, type) {\r\n\t\tvar targets = [],\r\n\t\t target,\r\n\t\t isHover = type === 'mouseout' || type === 'mouseover',\r\n\t\t src = e.target || e.srcElement,\r\n\t\t dragging = false;\r\n\r\n\t\twhile (src) {\r\n\t\t\ttarget = this._targets[Util.stamp(src)];\r\n\t\t\tif (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {\r\n\t\t\t\t// Prevent firing click after you just dragged an object.\r\n\t\t\t\tdragging = true;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (target && target.listens(type, true)) {\r\n\t\t\t\tif (isHover && !DomEvent.isExternalTarget(src, e)) { break; }\r\n\t\t\t\ttargets.push(target);\r\n\t\t\t\tif (isHover) { break; }\r\n\t\t\t}\r\n\t\t\tif (src === this._container) { break; }\r\n\t\t\tsrc = src.parentNode;\r\n\t\t}\r\n\t\tif (!targets.length && !dragging && !isHover && this.listens(type, true)) {\r\n\t\t\ttargets = [this];\r\n\t\t}\r\n\t\treturn targets;\r\n\t},\r\n\r\n\t_isClickDisabled: function (el) {\r\n\t\twhile (el && el !== this._container) {\r\n\t\t\tif (el['_leaflet_disable_click']) { return true; }\r\n\t\t\tel = el.parentNode;\r\n\t\t}\r\n\t},\r\n\r\n\t_handleDOMEvent: function (e) {\r\n\t\tvar el = (e.target || e.srcElement);\r\n\t\tif (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar type = e.type;\r\n\r\n\t\tif (type === 'mousedown') {\r\n\t\t\t// prevents outline when clicking on keyboard-focusable element\r\n\t\t\tDomUtil.preventOutline(el);\r\n\t\t}\r\n\r\n\t\tthis._fireDOMEvent(e, type);\r\n\t},\r\n\r\n\t_mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],\r\n\r\n\t_fireDOMEvent: function (e, type, canvasTargets) {\r\n\r\n\t\tif (e.type === 'click') {\r\n\t\t\t// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).\r\n\t\t\t// @event preclick: MouseEvent\r\n\t\t\t// Fired before mouse click on the map (sometimes useful when you\r\n\t\t\t// want something to happen on click before any existing click\r\n\t\t\t// handlers start running).\r\n\t\t\tvar synth = Util.extend({}, e);\r\n\t\t\tsynth.type = 'preclick';\r\n\t\t\tthis._fireDOMEvent(synth, synth.type, canvasTargets);\r\n\t\t}\r\n\r\n\t\t// Find the layer the event is propagating from and its parents.\r\n\t\tvar targets = this._findEventTargets(e, type);\r\n\r\n\t\tif (canvasTargets) {\r\n\t\t\tvar filtered = []; // pick only targets with listeners\r\n\t\t\tfor (var i = 0; i < canvasTargets.length; i++) {\r\n\t\t\t\tif (canvasTargets[i].listens(type, true)) {\r\n\t\t\t\t\tfiltered.push(canvasTargets[i]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\ttargets = filtered.concat(targets);\r\n\t\t}\r\n\r\n\t\tif (!targets.length) { return; }\r\n\r\n\t\tif (type === 'contextmenu') {\r\n\t\t\tDomEvent.preventDefault(e);\r\n\t\t}\r\n\r\n\t\tvar target = targets[0];\r\n\t\tvar data = {\r\n\t\t\toriginalEvent: e\r\n\t\t};\r\n\r\n\t\tif (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {\r\n\t\t\tvar isMarker = target.getLatLng && (!target._radius || target._radius <= 10);\r\n\t\t\tdata.containerPoint = isMarker ?\r\n\t\t\t\tthis.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);\r\n\t\t\tdata.layerPoint = this.containerPointToLayerPoint(data.containerPoint);\r\n\t\t\tdata.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);\r\n\t\t}\r\n\r\n\t\tfor (i = 0; i < targets.length; i++) {\r\n\t\t\ttargets[i].fire(type, data, true);\r\n\t\t\tif (data.originalEvent._stopped ||\r\n\t\t\t\t(targets[i].options.bubblingMouseEvents === false && Util.indexOf(this._mouseEvents, type) !== -1)) { return; }\r\n\t\t}\r\n\t},\r\n\r\n\t_draggableMoved: function (obj) {\r\n\t\tobj = obj.dragging && obj.dragging.enabled() ? obj : this;\r\n\t\treturn (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());\r\n\t},\r\n\r\n\t_clearHandlers: function () {\r\n\t\tfor (var i = 0, len = this._handlers.length; i < len; i++) {\r\n\t\t\tthis._handlers[i].disable();\r\n\t\t}\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method whenReady(fn: Function, context?: Object): this\r\n\t// Runs the given function `fn` when the map gets initialized with\r\n\t// a view (center and zoom) and at least one layer, or immediately\r\n\t// if it's already initialized, optionally passing a function context.\r\n\twhenReady: function (callback, context) {\r\n\t\tif (this._loaded) {\r\n\t\t\tcallback.call(context || this, {target: this});\r\n\t\t} else {\r\n\t\t\tthis.on('load', callback, context);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\r\n\t// private methods for getting map state\r\n\r\n\t_getMapPanePos: function () {\r\n\t\treturn DomUtil.getPosition(this._mapPane) || new Point(0, 0);\r\n\t},\r\n\r\n\t_moved: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\treturn pos && !pos.equals([0, 0]);\r\n\t},\r\n\r\n\t_getTopLeftPoint: function (center, zoom) {\r\n\t\tvar pixelOrigin = center && zoom !== undefined ?\r\n\t\t\tthis._getNewPixelOrigin(center, zoom) :\r\n\t\t\tthis.getPixelOrigin();\r\n\t\treturn pixelOrigin.subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t_getNewPixelOrigin: function (center, zoom) {\r\n\t\tvar viewHalf = this.getSize()._divideBy(2);\r\n\t\treturn this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();\r\n\t},\r\n\r\n\t_latLngToNewLayerPoint: function (latlng, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn this.project(latlng, zoom)._subtract(topLeft);\r\n\t},\r\n\r\n\t_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn toBounds([\r\n\t\t\tthis.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)\r\n\t\t]);\r\n\t},\r\n\r\n\t// layer point of the current center\r\n\t_getCenterLayerPoint: function () {\r\n\t\treturn this.containerPointToLayerPoint(this.getSize()._divideBy(2));\r\n\t},\r\n\r\n\t// offset of the specified place to the current center in pixels\r\n\t_getCenterOffset: function (latlng) {\r\n\t\treturn this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// adjust center for view to get inside bounds\r\n\t_limitCenter: function (center, zoom, bounds) {\r\n\r\n\t\tif (!bounds) { return center; }\r\n\r\n\t\tvar centerPoint = this.project(center, zoom),\r\n\t\t viewHalf = this.getSize().divideBy(2),\r\n\t\t viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),\r\n\t\t offset = this._getBoundsOffset(viewBounds, bounds, zoom);\r\n\r\n\t\t// If offset is less than a pixel, ignore.\r\n\t\t// This prevents unstable projections from getting into\r\n\t\t// an infinite loop of tiny offsets.\r\n\t\tif (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {\r\n\t\t\treturn center;\r\n\t\t}\r\n\r\n\t\treturn this.unproject(centerPoint.add(offset), zoom);\r\n\t},\r\n\r\n\t// adjust offset for view to get inside bounds\r\n\t_limitOffset: function (offset, bounds) {\r\n\t\tif (!bounds) { return offset; }\r\n\r\n\t\tvar viewBounds = this.getPixelBounds(),\r\n\t\t newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));\r\n\r\n\t\treturn offset.add(this._getBoundsOffset(newBounds, bounds));\r\n\t},\r\n\r\n\t// returns offset needed for pxBounds to get inside maxBounds at a specified zoom\r\n\t_getBoundsOffset: function (pxBounds, maxBounds, zoom) {\r\n\t\tvar projectedMaxBounds = toBounds(\r\n\t\t this.project(maxBounds.getNorthEast(), zoom),\r\n\t\t this.project(maxBounds.getSouthWest(), zoom)\r\n\t\t ),\r\n\t\t minOffset = projectedMaxBounds.min.subtract(pxBounds.min),\r\n\t\t maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),\r\n\r\n\t\t dx = this._rebound(minOffset.x, -maxOffset.x),\r\n\t\t dy = this._rebound(minOffset.y, -maxOffset.y);\r\n\r\n\t\treturn new Point(dx, dy);\r\n\t},\r\n\r\n\t_rebound: function (left, right) {\r\n\t\treturn left + right > 0 ?\r\n\t\t\tMath.round(left - right) / 2 :\r\n\t\t\tMath.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));\r\n\t},\r\n\r\n\t_limitZoom: function (zoom) {\r\n\t\tvar min = this.getMinZoom(),\r\n\t\t max = this.getMaxZoom(),\r\n\t\t snap = Browser.any3d ? this.options.zoomSnap : 1;\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / snap) * snap;\r\n\t\t}\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t_onPanTransitionStep: function () {\r\n\t\tthis.fire('move');\r\n\t},\r\n\r\n\t_onPanTransitionEnd: function () {\r\n\t\tDomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');\r\n\t\tthis.fire('moveend');\r\n\t},\r\n\r\n\t_tryAnimatedPan: function (center, options) {\r\n\t\t// difference between the new and current centers in pixels\r\n\t\tvar offset = this._getCenterOffset(center)._trunc();\r\n\r\n\t\t// don't animate too far unless animate: true specified in options\r\n\t\tif ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tthis.panBy(offset, options);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_createAnimProxy: function () {\r\n\r\n\t\tvar proxy = this._proxy = DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');\r\n\t\tthis._panes.mapPane.appendChild(proxy);\r\n\r\n\t\tthis.on('zoomanim', function (e) {\r\n\t\t\tvar prop = DomUtil.TRANSFORM,\r\n\t\t\t transform = this._proxy.style[prop];\r\n\r\n\t\t\tDomUtil.setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));\r\n\r\n\t\t\t// workaround for case when transform is the same and so transitionend event is not fired\r\n\t\t\tif (transform === this._proxy.style[prop] && this._animatingZoom) {\r\n\t\t\t\tthis._onZoomTransitionEnd();\r\n\t\t\t}\r\n\t\t}, this);\r\n\r\n\t\tthis.on('load moveend', this._animMoveEnd, this);\r\n\r\n\t\tthis._on('unload', this._destroyAnimProxy, this);\r\n\t},\r\n\r\n\t_destroyAnimProxy: function () {\r\n\t\tDomUtil.remove(this._proxy);\r\n\t\tthis.off('load moveend', this._animMoveEnd, this);\r\n\t\tdelete this._proxy;\r\n\t},\r\n\r\n\t_animMoveEnd: function () {\r\n\t\tvar c = this.getCenter(),\r\n\t\t z = this.getZoom();\r\n\t\tDomUtil.setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));\r\n\t},\r\n\r\n\t_catchTransitionEnd: function (e) {\r\n\t\tif (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {\r\n\t\t\tthis._onZoomTransitionEnd();\r\n\t\t}\r\n\t},\r\n\r\n\t_nothingToAnimate: function () {\r\n\t\treturn !this._container.getElementsByClassName('leaflet-zoom-animated').length;\r\n\t},\r\n\r\n\t_tryAnimatedZoom: function (center, zoom, options) {\r\n\r\n\t\tif (this._animatingZoom) { return true; }\r\n\r\n\t\toptions = options || {};\r\n\r\n\t\t// don't animate if disabled, not supported or zoom difference is too large\r\n\t\tif (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||\r\n\t\t Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }\r\n\r\n\t\t// offset is the pixel coords of the zoom origin relative to the current center\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);\r\n\r\n\t\t// don't animate if the zoom origin isn't within one screen from the current center, unless forced\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tUtil.requestAnimFrame(function () {\r\n\t\t\tthis\r\n\t\t\t ._moveStart(true, false)\r\n\t\t\t ._animateZoom(center, zoom, true);\r\n\t\t}, this);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_animateZoom: function (center, zoom, startAnim, noUpdate) {\r\n\t\tif (!this._mapPane) { return; }\r\n\r\n\t\tif (startAnim) {\r\n\t\t\tthis._animatingZoom = true;\r\n\r\n\t\t\t// remember what center/zoom to set after animation\r\n\t\t\tthis._animateToCenter = center;\r\n\t\t\tthis._animateToZoom = zoom;\r\n\r\n\t\t\tDomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');\r\n\t\t}\r\n\r\n\t\t// @section Other Events\r\n\t\t// @event zoomanim: ZoomAnimEvent\r\n\t\t// Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom.\r\n\t\tthis.fire('zoomanim', {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom,\r\n\t\t\tnoUpdate: noUpdate\r\n\t\t});\r\n\r\n\t\tif (!this._tempFireZoomEvent) {\r\n\t\t\tthis._tempFireZoomEvent = this._zoom !== this._animateToZoom;\r\n\t\t}\r\n\r\n\t\tthis._move(this._animateToCenter, this._animateToZoom, undefined, true);\r\n\r\n\t\t// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693\r\n\t\tsetTimeout(Util.bind(this._onZoomTransitionEnd, this), 250);\r\n\t},\r\n\r\n\t_onZoomTransitionEnd: function () {\r\n\t\tif (!this._animatingZoom) { return; }\r\n\r\n\t\tif (this._mapPane) {\r\n\t\t\tDomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');\r\n\t\t}\r\n\r\n\t\tthis._animatingZoom = false;\r\n\r\n\t\tthis._move(this._animateToCenter, this._animateToZoom, undefined, true);\r\n\r\n\t\tif (this._tempFireZoomEvent) {\r\n\t\t\tthis.fire('zoom');\r\n\t\t}\r\n\t\tdelete this._tempFireZoomEvent;\r\n\r\n\t\tthis.fire('move');\r\n\r\n\t\tthis._moveEnd(true);\r\n\t}\r\n});\r\n\r\n// @section\r\n\r\n// @factory L.map(id: String, options?: Map options)\r\n// Instantiates a map object given the DOM ID of a `<div>` element\r\n// and optionally an object literal with `Map options`.\r\n//\r\n// @alternative\r\n// @factory L.map(el: HTMLElement, options?: Map options)\r\n// Instantiates a map object given an instance of a `<div>` HTML element\r\n// and optionally an object literal with `Map options`.\r\nexport function createMap(id, options) {\r\n\treturn new Map(id, options);\r\n}\r\n","\r\nimport {Class} from '../core/Class';\r\nimport {Map} from '../map/Map';\r\nimport * as Util from '../core/Util';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class Control\r\n * @aka L.Control\r\n * @inherits Class\r\n *\r\n * L.Control is a base class for implementing map controls. Handles positioning.\r\n * All other controls extend from this class.\r\n */\r\n\r\nexport var Control = Class.extend({\r\n\t// @section\r\n\t// @aka Control Options\r\n\toptions: {\r\n\t\t// @option position: String = 'topright'\r\n\t\t// The position of the control (one of the map corners). Possible values are `'topleft'`,\r\n\t\t// `'topright'`, `'bottomleft'` or `'bottomright'`\r\n\t\tposition: 'topright'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tUtil.setOptions(this, options);\r\n\t},\r\n\r\n\t/* @section\r\n\t * Classes extending L.Control will inherit the following methods:\r\n\t *\r\n\t * @method getPosition: string\r\n\t * Returns the position of the control.\r\n\t */\r\n\tgetPosition: function () {\r\n\t\treturn this.options.position;\r\n\t},\r\n\r\n\t// @method setPosition(position: string): this\r\n\t// Sets the position of the control.\r\n\tsetPosition: function (position) {\r\n\t\tvar map = this._map;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.removeControl(this);\r\n\t\t}\r\n\r\n\t\tthis.options.position = position;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.addControl(this);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTMLElement that contains the control.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method addTo(map: Map): this\r\n\t// Adds the control to the given map.\r\n\taddTo: function (map) {\r\n\t\tthis.remove();\r\n\t\tthis._map = map;\r\n\r\n\t\tvar container = this._container = this.onAdd(map),\r\n\t\t pos = this.getPosition(),\r\n\t\t corner = map._controlCorners[pos];\r\n\r\n\t\tDomUtil.addClass(container, 'leaflet-control');\r\n\r\n\t\tif (pos.indexOf('bottom') !== -1) {\r\n\t\t\tcorner.insertBefore(container, corner.firstChild);\r\n\t\t} else {\r\n\t\t\tcorner.appendChild(container);\r\n\t\t}\r\n\r\n\t\tthis._map.on('unload', this.remove, this);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove: this\r\n\t// Removes the control from the map it is currently active on.\r\n\tremove: function () {\r\n\t\tif (!this._map) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tDomUtil.remove(this._container);\r\n\r\n\t\tif (this.onRemove) {\r\n\t\t\tthis.onRemove(this._map);\r\n\t\t}\r\n\r\n\t\tthis._map.off('unload', this.remove, this);\r\n\t\tthis._map = null;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_refocusOnMap: function (e) {\r\n\t\t// if map exists and event is not a keyboard event\r\n\t\tif (this._map && e && e.screenX > 0 && e.screenY > 0) {\r\n\t\t\tthis._map.getContainer().focus();\r\n\t\t}\r\n\t}\r\n});\r\n\r\nexport var control = function (options) {\r\n\treturn new Control(options);\r\n};\r\n\r\n/* @section Extension methods\r\n * @uninheritable\r\n *\r\n * Every control should extend from `L.Control` and (re-)implement the following methods.\r\n *\r\n * @method onAdd(map: Map): HTMLElement\r\n * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).\r\n *\r\n * @method onRemove(map: Map)\r\n * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).\r\n */\r\n\r\n/* @namespace Map\r\n * @section Methods for Layers and Controls\r\n */\r\nMap.include({\r\n\t// @method addControl(control: Control): this\r\n\t// Adds the given control to the map\r\n\taddControl: function (control) {\r\n\t\tcontrol.addTo(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeControl(control: Control): this\r\n\t// Removes the given control from the map\r\n\tremoveControl: function (control) {\r\n\t\tcontrol.remove();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initControlPos: function () {\r\n\t\tvar corners = this._controlCorners = {},\r\n\t\t l = 'leaflet-',\r\n\t\t container = this._controlContainer =\r\n\t\t DomUtil.create('div', l + 'control-container', this._container);\r\n\r\n\t\tfunction createCorner(vSide, hSide) {\r\n\t\t\tvar className = l + vSide + ' ' + l + hSide;\r\n\r\n\t\t\tcorners[vSide + hSide] = DomUtil.create('div', className, container);\r\n\t\t}\r\n\r\n\t\tcreateCorner('top', 'left');\r\n\t\tcreateCorner('top', 'right');\r\n\t\tcreateCorner('bottom', 'left');\r\n\t\tcreateCorner('bottom', 'right');\r\n\t},\r\n\r\n\t_clearControlPos: function () {\r\n\t\tfor (var i in this._controlCorners) {\r\n\t\t\tDomUtil.remove(this._controlCorners[i]);\r\n\t\t}\r\n\t\tDomUtil.remove(this._controlContainer);\r\n\t\tdelete this._controlCorners;\r\n\t\tdelete this._controlContainer;\r\n\t}\r\n});\r\n","\r\nimport {Control} from './Control';\r\nimport * as Util from '../core/Util';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class Control.Layers\r\n * @aka L.Control.Layers\r\n * @inherits Control\r\n *\r\n * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var baseLayers = {\r\n * \t\"Mapbox\": mapbox,\r\n * \t\"OpenStreetMap\": osm\r\n * };\r\n *\r\n * var overlays = {\r\n * \t\"Marker\": marker,\r\n * \t\"Roads\": roadsLayer\r\n * };\r\n *\r\n * L.control.layers(baseLayers, overlays).addTo(map);\r\n * ```\r\n *\r\n * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:\r\n *\r\n * ```js\r\n * {\r\n * \"<someName1>\": layer1,\r\n * \"<someName2>\": layer2\r\n * }\r\n * ```\r\n *\r\n * The layer names can contain HTML, which allows you to add additional styling to the items:\r\n *\r\n * ```js\r\n * {\"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>\": myLayer}\r\n * ```\r\n */\r\n\r\nexport var Layers = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Layers options\r\n\toptions: {\r\n\t\t// @option collapsed: Boolean = true\r\n\t\t// If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.\r\n\t\tcollapsed: true,\r\n\t\tposition: 'topright',\r\n\r\n\t\t// @option autoZIndex: Boolean = true\r\n\t\t// If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.\r\n\t\tautoZIndex: true,\r\n\r\n\t\t// @option hideSingleBase: Boolean = false\r\n\t\t// If `true`, the base layers in the control will be hidden when there is only one.\r\n\t\thideSingleBase: false,\r\n\r\n\t\t// @option sortLayers: Boolean = false\r\n\t\t// Whether to sort the layers. When `false`, layers will keep the order\r\n\t\t// in which they were added to the control.\r\n\t\tsortLayers: false,\r\n\r\n\t\t// @option sortFunction: Function = *\r\n\t\t// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)\r\n\t\t// that will be used for sorting the layers, when `sortLayers` is `true`.\r\n\t\t// The function receives both the `L.Layer` instances and their names, as in\r\n\t\t// `sortFunction(layerA, layerB, nameA, nameB)`.\r\n\t\t// By default, it sorts layers alphabetically by their name.\r\n\t\tsortFunction: function (layerA, layerB, nameA, nameB) {\r\n\t\t\treturn nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);\r\n\t\t}\r\n\t},\r\n\r\n\tinitialize: function (baseLayers, overlays, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tthis._layers = [];\r\n\t\tthis._lastZIndex = 0;\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tfor (var i in baseLayers) {\r\n\t\t\tthis._addLayer(baseLayers[i], i);\r\n\t\t}\r\n\r\n\t\tfor (i in overlays) {\r\n\t\t\tthis._addLayer(overlays[i], i, true);\r\n\t\t}\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._initLayout();\r\n\t\tthis._update();\r\n\r\n\t\tthis._map = map;\r\n\t\tmap.on('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\taddTo: function (map) {\r\n\t\tControl.prototype.addTo.call(this, map);\r\n\t\t// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.\r\n\t\treturn this._expandIfNotCollapsed();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tthis._map.off('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.off('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addBaseLayer(layer: Layer, name: String): this\r\n\t// Adds a base layer (radio button entry) with the given name to the control.\r\n\taddBaseLayer: function (layer, name) {\r\n\t\tthis._addLayer(layer, name);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method addOverlay(layer: Layer, name: String): this\r\n\t// Adds an overlay (checkbox entry) with the given name to the control.\r\n\taddOverlay: function (layer, name) {\r\n\t\tthis._addLayer(layer, name, true);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Remove the given layer from the control.\r\n\tremoveLayer: function (layer) {\r\n\t\tlayer.off('add remove', this._onLayerChange, this);\r\n\r\n\t\tvar obj = this._getLayer(Util.stamp(layer));\r\n\t\tif (obj) {\r\n\t\t\tthis._layers.splice(this._layers.indexOf(obj), 1);\r\n\t\t}\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method expand(): this\r\n\t// Expand the control container if collapsed.\r\n\texpand: function () {\r\n\t\tDomUtil.addClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\tthis._section.style.height = null;\r\n\t\tvar acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);\r\n\t\tif (acceptableHeight < this._section.clientHeight) {\r\n\t\t\tDomUtil.addClass(this._section, 'leaflet-control-layers-scrollbar');\r\n\t\t\tthis._section.style.height = acceptableHeight + 'px';\r\n\t\t} else {\r\n\t\t\tDomUtil.removeClass(this._section, 'leaflet-control-layers-scrollbar');\r\n\t\t}\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method collapse(): this\r\n\t// Collapse the control container if expanded.\r\n\tcollapse: function () {\r\n\t\tDomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar className = 'leaflet-control-layers',\r\n\t\t container = this._container = DomUtil.create('div', className),\r\n\t\t collapsed = this.options.collapsed;\r\n\r\n\t\t// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released\r\n\t\tcontainer.setAttribute('aria-haspopup', true);\r\n\r\n\t\tDomEvent.disableClickPropagation(container);\r\n\t\tDomEvent.disableScrollPropagation(container);\r\n\r\n\t\tvar section = this._section = DomUtil.create('section', className + '-list');\r\n\r\n\t\tif (collapsed) {\r\n\t\t\tthis._map.on('click', this.collapse, this);\r\n\r\n\t\t\tDomEvent.on(container, {\r\n\t\t\t\tmouseenter: this._expandSafely,\r\n\t\t\t\tmouseleave: this.collapse\r\n\t\t\t}, this);\r\n\t\t}\r\n\r\n\t\tvar link = this._layersLink = DomUtil.create('a', className + '-toggle', container);\r\n\t\tlink.href = '#';\r\n\t\tlink.title = 'Layers';\r\n\t\tlink.setAttribute('role', 'button');\r\n\r\n\t\tDomEvent.on(link, {\r\n\t\t\tkeydown: function (e) {\r\n\t\t\t\tif (e.keyCode === 13) {\r\n\t\t\t\t\tthis._expandSafely();\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t// Certain screen readers intercept the key event and instead send a click event\r\n\t\t\tclick: function (e) {\r\n\t\t\t\tDomEvent.preventDefault(e);\r\n\t\t\t\tthis._expandSafely();\r\n\t\t\t}\r\n\t\t}, this);\r\n\r\n\t\tif (!collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\r\n\t\tthis._baseLayersList = DomUtil.create('div', className + '-base', section);\r\n\t\tthis._separator = DomUtil.create('div', className + '-separator', section);\r\n\t\tthis._overlaysList = DomUtil.create('div', className + '-overlays', section);\r\n\r\n\t\tcontainer.appendChild(section);\r\n\t},\r\n\r\n\t_getLayer: function (id) {\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\r\n\t\t\tif (this._layers[i] && Util.stamp(this._layers[i].layer) === id) {\r\n\t\t\t\treturn this._layers[i];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_addLayer: function (layer, name, overlay) {\r\n\t\tif (this._map) {\r\n\t\t\tlayer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\tthis._layers.push({\r\n\t\t\tlayer: layer,\r\n\t\t\tname: name,\r\n\t\t\toverlay: overlay\r\n\t\t});\r\n\r\n\t\tif (this.options.sortLayers) {\r\n\t\t\tthis._layers.sort(Util.bind(function (a, b) {\r\n\t\t\t\treturn this.options.sortFunction(a.layer, b.layer, a.name, b.name);\r\n\t\t\t}, this));\r\n\t\t}\r\n\r\n\t\tif (this.options.autoZIndex && layer.setZIndex) {\r\n\t\t\tthis._lastZIndex++;\r\n\t\t\tlayer.setZIndex(this._lastZIndex);\r\n\t\t}\r\n\r\n\t\tthis._expandIfNotCollapsed();\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._container) { return this; }\r\n\r\n\t\tDomUtil.empty(this._baseLayersList);\r\n\t\tDomUtil.empty(this._overlaysList);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tvar baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;\r\n\r\n\t\tfor (i = 0; i < this._layers.length; i++) {\r\n\t\t\tobj = this._layers[i];\r\n\t\t\tthis._addItem(obj);\r\n\t\t\toverlaysPresent = overlaysPresent || obj.overlay;\r\n\t\t\tbaseLayersPresent = baseLayersPresent || !obj.overlay;\r\n\t\t\tbaseLayersCount += !obj.overlay ? 1 : 0;\r\n\t\t}\r\n\r\n\t\t// Hide base layers section if there's only one layer.\r\n\t\tif (this.options.hideSingleBase) {\r\n\t\t\tbaseLayersPresent = baseLayersPresent && baseLayersCount > 1;\r\n\t\t\tthis._baseLayersList.style.display = baseLayersPresent ? '' : 'none';\r\n\t\t}\r\n\r\n\t\tthis._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_onLayerChange: function (e) {\r\n\t\tif (!this._handlingClick) {\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\tvar obj = this._getLayer(Util.stamp(e.target));\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Layer events\r\n\t\t// @event baselayerchange: LayersControlEvent\r\n\t\t// Fired when the base layer is changed through the [layers control](#control-layers).\r\n\t\t// @event overlayadd: LayersControlEvent\r\n\t\t// Fired when an overlay is selected through the [layers control](#control-layers).\r\n\t\t// @event overlayremove: LayersControlEvent\r\n\t\t// Fired when an overlay is deselected through the [layers control](#control-layers).\r\n\t\t// @namespace Control.Layers\r\n\t\tvar type = obj.overlay ?\r\n\t\t\t(e.type === 'add' ? 'overlayadd' : 'overlayremove') :\r\n\t\t\t(e.type === 'add' ? 'baselayerchange' : null);\r\n\r\n\t\tif (type) {\r\n\t\t\tthis._map.fire(type, obj);\r\n\t\t}\r\n\t},\r\n\r\n\t// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)\r\n\t_createRadioElement: function (name, checked) {\r\n\r\n\t\tvar radioHtml = '<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\"' +\r\n\t\t\t\tname + '\"' + (checked ? ' checked=\"checked\"' : '') + '/>';\r\n\r\n\t\tvar radioFragment = document.createElement('div');\r\n\t\tradioFragment.innerHTML = radioHtml;\r\n\r\n\t\treturn radioFragment.firstChild;\r\n\t},\r\n\r\n\t_addItem: function (obj) {\r\n\t\tvar label = document.createElement('label'),\r\n\t\t checked = this._map.hasLayer(obj.layer),\r\n\t\t input;\r\n\r\n\t\tif (obj.overlay) {\r\n\t\t\tinput = document.createElement('input');\r\n\t\t\tinput.type = 'checkbox';\r\n\t\t\tinput.className = 'leaflet-control-layers-selector';\r\n\t\t\tinput.defaultChecked = checked;\r\n\t\t} else {\r\n\t\t\tinput = this._createRadioElement('leaflet-base-layers_' + Util.stamp(this), checked);\r\n\t\t}\r\n\r\n\t\tthis._layerControlInputs.push(input);\r\n\t\tinput.layerId = Util.stamp(obj.layer);\r\n\r\n\t\tDomEvent.on(input, 'click', this._onInputClick, this);\r\n\r\n\t\tvar name = document.createElement('span');\r\n\t\tname.innerHTML = ' ' + obj.name;\r\n\r\n\t\t// Helps from preventing layer control flicker when checkboxes are disabled\r\n\t\t// https://github.com/Leaflet/Leaflet/issues/2771\r\n\t\tvar holder = document.createElement('span');\r\n\r\n\t\tlabel.appendChild(holder);\r\n\t\tholder.appendChild(input);\r\n\t\tholder.appendChild(name);\r\n\r\n\t\tvar container = obj.overlay ? this._overlaysList : this._baseLayersList;\r\n\t\tcontainer.appendChild(label);\r\n\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn label;\r\n\t},\r\n\r\n\t_onInputClick: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input, layer;\r\n\t\tvar addedLayers = [],\r\n\t\t removedLayers = [];\r\n\r\n\t\tthis._handlingClick = true;\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\r\n\t\t\tif (input.checked) {\r\n\t\t\t\taddedLayers.push(layer);\r\n\t\t\t} else if (!input.checked) {\r\n\t\t\t\tremovedLayers.push(layer);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Bugfix issue 2318: Should remove all old layers before readding new ones\r\n\t\tfor (i = 0; i < removedLayers.length; i++) {\r\n\t\t\tif (this._map.hasLayer(removedLayers[i])) {\r\n\t\t\t\tthis._map.removeLayer(removedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (i = 0; i < addedLayers.length; i++) {\r\n\t\t\tif (!this._map.hasLayer(addedLayers[i])) {\r\n\t\t\t\tthis._map.addLayer(addedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tthis._refocusOnMap();\r\n\t},\r\n\r\n\t_checkDisabledLayers: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input,\r\n\t\t layer,\r\n\t\t zoom = this._map.getZoom();\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\t\t\tinput.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||\r\n\t\t\t (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_expandIfNotCollapsed: function () {\r\n\t\tif (this._map && !this.options.collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_expandSafely: function () {\r\n\t\tvar section = this._section;\r\n\t\tDomEvent.on(section, 'click', DomEvent.preventDefault);\r\n\t\tthis.expand();\r\n\t\tsetTimeout(function () {\r\n\t\t\tDomEvent.off(section, 'click', DomEvent.preventDefault);\r\n\t\t});\r\n\t}\r\n\r\n});\r\n\r\n\r\n// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)\r\n// Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.\r\nexport var layers = function (baseLayers, overlays, options) {\r\n\treturn new Layers(baseLayers, overlays, options);\r\n};\r\n","\r\nimport {Control} from './Control';\r\nimport {Map} from '../map/Map';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport * as DomEvent from '../dom/DomEvent';\r\n\r\n/*\r\n * @class Control.Zoom\r\n * @aka L.Control.Zoom\r\n * @inherits Control\r\n *\r\n * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.\r\n */\r\n\r\nexport var Zoom = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Zoom options\r\n\toptions: {\r\n\t\tposition: 'topleft',\r\n\r\n\t\t// @option zoomInText: String = '<span aria-hidden=\"true\">+</span>'\r\n\t\t// The text set on the 'zoom in' button.\r\n\t\tzoomInText: '<span aria-hidden=\"true\">+</span>',\r\n\r\n\t\t// @option zoomInTitle: String = 'Zoom in'\r\n\t\t// The title set on the 'zoom in' button.\r\n\t\tzoomInTitle: 'Zoom in',\r\n\r\n\t\t// @option zoomOutText: String = '<span aria-hidden=\"true\">&#x2212;</span>'\r\n\t\t// The text set on the 'zoom out' button.\r\n\t\tzoomOutText: '<span aria-hidden=\"true\">&#x2212;</span>',\r\n\r\n\t\t// @option zoomOutTitle: String = 'Zoom out'\r\n\t\t// The title set on the 'zoom out' button.\r\n\t\tzoomOutTitle: 'Zoom out'\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tvar zoomName = 'leaflet-control-zoom',\r\n\t\t container = DomUtil.create('div', zoomName + ' leaflet-bar'),\r\n\t\t options = this.options;\r\n\r\n\t\tthis._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,\r\n\t\t zoomName + '-in', container, this._zoomIn);\r\n\t\tthis._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,\r\n\t\t zoomName + '-out', container, this._zoomOut);\r\n\r\n\t\tthis._updateDisabled();\r\n\t\tmap.on('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\r\n\t\treturn container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\t},\r\n\r\n\tdisable: function () {\r\n\t\tthis._disabled = true;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\tenable: function () {\r\n\t\tthis._disabled = false;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_zoomIn: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {\r\n\t\t\tthis._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_zoomOut: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom > this._map.getMinZoom()) {\r\n\t\t\tthis._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_createButton: function (html, title, className, container, fn) {\r\n\t\tvar link = DomUtil.create('a', className, container);\r\n\t\tlink.innerHTML = html;\r\n\t\tlink.href = '#';\r\n\t\tlink.title = title;\r\n\r\n\t\t/*\r\n\t\t * Will force screen readers like VoiceOver to read this as \"Zoom in - button\"\r\n\t\t */\r\n\t\tlink.setAttribute('role', 'button');\r\n\t\tlink.setAttribute('aria-label', title);\r\n\r\n\t\tDomEvent.disableClickPropagation(link);\r\n\t\tDomEvent.on(link, 'click', DomEvent.stop);\r\n\t\tDomEvent.on(link, 'click', fn, this);\r\n\t\tDomEvent.on(link, 'click', this._refocusOnMap, this);\r\n\r\n\t\treturn link;\r\n\t},\r\n\r\n\t_updateDisabled: function () {\r\n\t\tvar map = this._map,\r\n\t\t className = 'leaflet-disabled';\r\n\r\n\t\tDomUtil.removeClass(this._zoomInButton, className);\r\n\t\tDomUtil.removeClass(this._zoomOutButton, className);\r\n\t\tthis._zoomInButton.setAttribute('aria-disabled', 'false');\r\n\t\tthis._zoomOutButton.setAttribute('aria-disabled', 'false');\r\n\r\n\t\tif (this._disabled || map._zoom === map.getMinZoom()) {\r\n\t\t\tDomUtil.addClass(this._zoomOutButton, className);\r\n\t\t\tthis._zoomOutButton.setAttribute('aria-disabled', 'true');\r\n\t\t}\r\n\t\tif (this._disabled || map._zoom === map.getMaxZoom()) {\r\n\t\t\tDomUtil.addClass(this._zoomInButton, className);\r\n\t\t\tthis._zoomInButton.setAttribute('aria-disabled', 'true');\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option zoomControl: Boolean = true\r\n// Whether a [zoom control](#control-zoom) is added to the map by default.\r\nMap.mergeOptions({\r\n\tzoomControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.zoomControl) {\r\n\t\t// @section Controls\r\n\t\t// @property zoomControl: Control.Zoom\r\n\t\t// The default zoom control (only available if the\r\n\t\t// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).\r\n\t\tthis.zoomControl = new Zoom();\r\n\t\tthis.addControl(this.zoomControl);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Zoom\r\n// @factory L.control.zoom(options: Control.Zoom options)\r\n// Creates a zoom control\r\nexport var zoom = function (options) {\r\n\treturn new Zoom(options);\r\n};\r\n","\nimport {Control} from './Control';\nimport * as DomUtil from '../dom/DomUtil';\n\n/*\n * @class Control.Scale\n * @aka L.Control.Scale\n * @inherits Control\n *\n * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.\n *\n * @example\n *\n * ```js\n * L.control.scale().addTo(map);\n * ```\n */\n\nexport var Scale = Control.extend({\n\t// @section\n\t// @aka Control.Scale options\n\toptions: {\n\t\tposition: 'bottomleft',\n\n\t\t// @option maxWidth: Number = 100\n\t\t// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).\n\t\tmaxWidth: 100,\n\n\t\t// @option metric: Boolean = True\n\t\t// Whether to show the metric scale line (m/km).\n\t\tmetric: true,\n\n\t\t// @option imperial: Boolean = True\n\t\t// Whether to show the imperial scale line (mi/ft).\n\t\timperial: true\n\n\t\t// @option updateWhenIdle: Boolean = false\n\t\t// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).\n\t},\n\n\tonAdd: function (map) {\n\t\tvar className = 'leaflet-control-scale',\n\t\t container = DomUtil.create('div', className),\n\t\t options = this.options;\n\n\t\tthis._addScales(options, className + '-line', container);\n\n\t\tmap.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t\tmap.whenReady(this._update, this);\n\n\t\treturn container;\n\t},\n\n\tonRemove: function (map) {\n\t\tmap.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t},\n\n\t_addScales: function (options, className, container) {\n\t\tif (options.metric) {\n\t\t\tthis._mScale = DomUtil.create('div', className, container);\n\t\t}\n\t\tif (options.imperial) {\n\t\t\tthis._iScale = DomUtil.create('div', className, container);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tvar map = this._map,\n\t\t y = map.getSize().y / 2;\n\n\t\tvar maxMeters = map.distance(\n\t\t\tmap.containerPointToLatLng([0, y]),\n\t\t\tmap.containerPointToLatLng([this.options.maxWidth, y]));\n\n\t\tthis._updateScales(maxMeters);\n\t},\n\n\t_updateScales: function (maxMeters) {\n\t\tif (this.options.metric && maxMeters) {\n\t\t\tthis._updateMetric(maxMeters);\n\t\t}\n\t\tif (this.options.imperial && maxMeters) {\n\t\t\tthis._updateImperial(maxMeters);\n\t\t}\n\t},\n\n\t_updateMetric: function (maxMeters) {\n\t\tvar meters = this._getRoundNum(maxMeters),\n\t\t label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';\n\n\t\tthis._updateScale(this._mScale, label, meters / maxMeters);\n\t},\n\n\t_updateImperial: function (maxMeters) {\n\t\tvar maxFeet = maxMeters * 3.2808399,\n\t\t maxMiles, miles, feet;\n\n\t\tif (maxFeet > 5280) {\n\t\t\tmaxMiles = maxFeet / 5280;\n\t\t\tmiles = this._getRoundNum(maxMiles);\n\t\t\tthis._updateScale(this._iScale, miles + ' mi', miles / maxMiles);\n\n\t\t} else {\n\t\t\tfeet = this._getRoundNum(maxFeet);\n\t\t\tthis._updateScale(this._iScale, feet + ' ft', feet / maxFeet);\n\t\t}\n\t},\n\n\t_updateScale: function (scale, text, ratio) {\n\t\tscale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';\n\t\tscale.innerHTML = text;\n\t},\n\n\t_getRoundNum: function (num) {\n\t\tvar pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),\n\t\t d = num / pow10;\n\n\t\td = d >= 10 ? 10 :\n\t\t d >= 5 ? 5 :\n\t\t d >= 3 ? 3 :\n\t\t d >= 2 ? 2 : 1;\n\n\t\treturn pow10 * d;\n\t}\n});\n\n\n// @factory L.control.scale(options?: Control.Scale options)\n// Creates an scale control with the given options.\nexport var scale = function (options) {\n\treturn new Scale(options);\n};\n","\r\nimport {Control} from './Control';\r\nimport {Map} from '../map/Map';\r\nimport * as Util from '../core/Util';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport Browser from '../core/Browser';\r\n\r\nvar ukrainianFlag = '<svg aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"8\" viewBox=\"0 0 12 8\" class=\"leaflet-attribution-flag\"><path fill=\"#4C7BE1\" d=\"M0 0h12v4H0z\"/><path fill=\"#FFD500\" d=\"M0 4h12v3H0z\"/><path fill=\"#E0BC00\" d=\"M0 7h12v1H0z\"/></svg>';\r\n\r\n\r\n/*\r\n * @class Control.Attribution\r\n * @aka L.Control.Attribution\r\n * @inherits Control\r\n *\r\n * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.\r\n */\r\n\r\nexport var Attribution = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Attribution options\r\n\toptions: {\r\n\t\tposition: 'bottomright',\r\n\r\n\t\t// @option prefix: String|false = 'Leaflet'\r\n\t\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\t\tprefix: '<a href=\"https://leafletjs.com\" title=\"A JavaScript library for interactive maps\">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._attributions = {};\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tmap.attributionControl = this;\r\n\t\tthis._container = DomUtil.create('div', 'leaflet-control-attribution');\r\n\t\tDomEvent.disableClickPropagation(this._container);\r\n\r\n\t\t// TODO ugly, refactor\r\n\t\tfor (var i in map._layers) {\r\n\t\t\tif (map._layers[i].getAttribution) {\r\n\t\t\t\tthis.addAttribution(map._layers[i].getAttribution());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._update();\r\n\r\n\t\tmap.on('layeradd', this._addAttribution, this);\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('layeradd', this._addAttribution, this);\r\n\t},\r\n\r\n\t_addAttribution: function (ev) {\r\n\t\tif (ev.layer.getAttribution) {\r\n\t\t\tthis.addAttribution(ev.layer.getAttribution());\r\n\t\t\tev.layer.once('remove', function () {\r\n\t\t\t\tthis.removeAttribution(ev.layer.getAttribution());\r\n\t\t\t}, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setPrefix(prefix: String|false): this\r\n\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\tsetPrefix: function (prefix) {\r\n\t\tthis.options.prefix = prefix;\r\n\t\tthis._update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addAttribution(text: String): this\r\n\t// Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).\r\n\taddAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (!this._attributions[text]) {\r\n\t\t\tthis._attributions[text] = 0;\r\n\t\t}\r\n\t\tthis._attributions[text]++;\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeAttribution(text: String): this\r\n\t// Removes an attribution text.\r\n\tremoveAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (this._attributions[text]) {\r\n\t\t\tthis._attributions[text]--;\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar attribs = [];\r\n\r\n\t\tfor (var i in this._attributions) {\r\n\t\t\tif (this._attributions[i]) {\r\n\t\t\t\tattribs.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar prefixAndAttribs = [];\r\n\r\n\t\tif (this.options.prefix) {\r\n\t\t\tprefixAndAttribs.push(this.options.prefix);\r\n\t\t}\r\n\t\tif (attribs.length) {\r\n\t\t\tprefixAndAttribs.push(attribs.join(', '));\r\n\t\t}\r\n\r\n\t\tthis._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden=\"true\">|</span> ');\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option attributionControl: Boolean = true\r\n// Whether a [attribution control](#control-attribution) is added to the map by default.\r\nMap.mergeOptions({\r\n\tattributionControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.attributionControl) {\r\n\t\tnew Attribution().addTo(this);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Attribution\r\n// @factory L.control.attribution(options: Control.Attribution options)\r\n// Creates an attribution control.\r\nexport var attribution = function (options) {\r\n\treturn new Attribution(options);\r\n};\r\n","import {Control, control} from './Control';\nimport {Layers, layers} from './Control.Layers';\nimport {Zoom, zoom} from './Control.Zoom';\nimport {Scale, scale} from './Control.Scale';\nimport {Attribution, attribution} from './Control.Attribution';\n\nControl.Layers = Layers;\nControl.Zoom = Zoom;\nControl.Scale = Scale;\nControl.Attribution = Attribution;\n\ncontrol.layers = layers;\ncontrol.zoom = zoom;\ncontrol.scale = scale;\ncontrol.attribution = attribution;\n\nexport {Control, control};\n","import {Class} from './Class';\n\n/*\n\tL.Handler is a base class for handler classes that are used internally to inject\n\tinteraction features like dragging to classes like Map and Marker.\n*/\n\n// @class Handler\n// @aka L.Handler\n// Abstract class for map interaction handlers\n\nexport var Handler = Class.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t},\n\n\t// @method enable(): this\n\t// Enables the handler\n\tenable: function () {\n\t\tif (this._enabled) { return this; }\n\n\t\tthis._enabled = true;\n\t\tthis.addHooks();\n\t\treturn this;\n\t},\n\n\t// @method disable(): this\n\t// Disables the handler\n\tdisable: function () {\n\t\tif (!this._enabled) { return this; }\n\n\t\tthis._enabled = false;\n\t\tthis.removeHooks();\n\t\treturn this;\n\t},\n\n\t// @method enabled(): Boolean\n\t// Returns `true` if the handler is enabled\n\tenabled: function () {\n\t\treturn !!this._enabled;\n\t}\n\n\t// @section Extension methods\n\t// Classes inheriting from `Handler` must implement the two following methods:\n\t// @method addHooks()\n\t// Called when the handler is enabled, should add event hooks.\n\t// @method removeHooks()\n\t// Called when the handler is disabled, should remove the event hooks added previously.\n});\n\n// @section There is static function which can be called without instantiating L.Handler:\n// @function addTo(map: Map, name: String): this\n// Adds a new Handler to the given map with the given name.\nHandler.addTo = function (map, name) {\n\tmap.addHandler(name, this);\n\treturn this;\n};\n","import Browser from './Browser';\nexport {Browser};\n\nexport {Class} from './Class';\n\nimport {Evented} from './Events';\nimport {Events} from './Events';\nexport {Evented};\nexport var Mixin = {Events: Events};\n\nexport {Handler} from './Handler';\n\nimport * as Util from './Util';\nexport {Util};\nexport {extend, bind, stamp, setOptions} from './Util';\n","import {Evented} from '../core/Events';\r\nimport Browser from '../core/Browser';\r\nimport * as DomEvent from './DomEvent';\r\nimport * as DomUtil from './DomUtil';\r\nimport * as Util from '../core/Util';\r\nimport {Point} from '../geometry/Point';\r\n\r\n/*\r\n * @class Draggable\r\n * @aka L.Draggable\r\n * @inherits Evented\r\n *\r\n * A class for making DOM elements draggable (including touch support).\r\n * Used internally for map and marker dragging. Only works for elements\r\n * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).\r\n *\r\n * @example\r\n * ```js\r\n * var draggable = new L.Draggable(elementToDrag);\r\n * draggable.enable();\r\n * ```\r\n */\r\n\r\nvar START = Browser.touch ? 'touchstart mousedown' : 'mousedown';\r\n\r\nexport var Draggable = Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section\r\n\t\t// @aka Draggable options\r\n\t\t// @option clickTolerance: Number = 3\r\n\t\t// The max number of pixels a user can shift the mouse pointer during a click\r\n\t\t// for it to be considered a valid click (as opposed to a mouse drag).\r\n\t\tclickTolerance: 3\r\n\t},\r\n\r\n\t// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)\r\n\t// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).\r\n\tinitialize: function (element, dragStartTarget, preventOutline, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._element = element;\r\n\t\tthis._dragStartTarget = dragStartTarget || element;\r\n\t\tthis._preventOutline = preventOutline;\r\n\t},\r\n\r\n\t// @method enable()\r\n\t// Enables the dragging ability\r\n\tenable: function () {\r\n\t\tif (this._enabled) { return; }\r\n\r\n\t\tDomEvent.on(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = true;\r\n\t},\r\n\r\n\t// @method disable()\r\n\t// Disables the dragging ability\r\n\tdisable: function () {\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\t// If we're currently dragging this draggable,\r\n\t\t// disabling it counts as first ending the drag.\r\n\t\tif (Draggable._dragging === this) {\r\n\t\t\tthis.finishDrag(true);\r\n\t\t}\r\n\r\n\t\tDomEvent.off(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = false;\r\n\t\tthis._moved = false;\r\n\t},\r\n\r\n\t_onDown: function (e) {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\tthis._moved = false;\r\n\r\n\t\tif (DomUtil.hasClass(this._element, 'leaflet-zoom-anim')) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length !== 1) {\r\n\t\t\t// Finish dragging to avoid conflict with touchZoom\r\n\t\t\tif (Draggable._dragging === this) {\r\n\t\t\t\tthis.finishDrag();\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }\r\n\t\tDraggable._dragging = this; // Prevent dragging multiple objects at once.\r\n\r\n\t\tif (this._preventOutline) {\r\n\t\t\tDomUtil.preventOutline(this._element);\r\n\t\t}\r\n\r\n\t\tDomUtil.disableImageDrag();\r\n\t\tDomUtil.disableTextSelection();\r\n\r\n\t\tif (this._moving) { return; }\r\n\r\n\t\t// @event down: Event\r\n\t\t// Fired when a drag is about to start.\r\n\t\tthis.fire('down');\r\n\r\n\t\tvar first = e.touches ? e.touches[0] : e,\r\n\t\t sizedParent = DomUtil.getSizedParentNode(this._element);\r\n\r\n\t\tthis._startPoint = new Point(first.clientX, first.clientY);\r\n\t\tthis._startPos = DomUtil.getPosition(this._element);\r\n\r\n\t\t// Cache the scale, so that we can continuously compensate for it during drag (_onMove).\r\n\t\tthis._parentScale = DomUtil.getScale(sizedParent);\r\n\r\n\t\tvar mouseevent = e.type === 'mousedown';\r\n\t\tDomEvent.on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this);\r\n\t\tDomEvent.on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this);\r\n\t},\r\n\r\n\t_onMove: function (e) {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length > 1) {\r\n\t\t\tthis._moved = true;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\r\n\t\t offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);\r\n\r\n\t\tif (!offset.x && !offset.y) { return; }\r\n\t\tif (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }\r\n\r\n\t\t// We assume that the parent container's position, border and scale do not change for the duration of the drag.\r\n\t\t// Therefore there is no need to account for the position and border (they are eliminated by the subtraction)\r\n\t\t// and we can use the cached value for the scale.\r\n\t\toffset.x /= this._parentScale.x;\r\n\t\toffset.y /= this._parentScale.y;\r\n\r\n\t\tDomEvent.preventDefault(e);\r\n\r\n\t\tif (!this._moved) {\r\n\t\t\t// @event dragstart: Event\r\n\t\t\t// Fired when a drag starts\r\n\t\t\tthis.fire('dragstart');\r\n\r\n\t\t\tthis._moved = true;\r\n\r\n\t\t\tDomUtil.addClass(document.body, 'leaflet-dragging');\r\n\r\n\t\t\tthis._lastTarget = e.target || e.srcElement;\r\n\t\t\t// IE and Edge do not give the <use> element, so fetch it\r\n\t\t\t// if necessary\r\n\t\t\tif (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {\r\n\t\t\t\tthis._lastTarget = this._lastTarget.correspondingUseElement;\r\n\t\t\t}\r\n\t\t\tDomUtil.addClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t}\r\n\r\n\t\tthis._newPos = this._startPos.add(offset);\r\n\t\tthis._moving = true;\r\n\r\n\t\tthis._lastEvent = e;\r\n\t\tthis._updatePosition();\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tvar e = {originalEvent: this._lastEvent};\r\n\r\n\t\t// @event predrag: Event\r\n\t\t// Fired continuously during dragging *before* each corresponding\r\n\t\t// update of the element's position.\r\n\t\tthis.fire('predrag', e);\r\n\t\tDomUtil.setPosition(this._element, this._newPos);\r\n\r\n\t\t// @event drag: Event\r\n\t\t// Fired continuously during dragging.\r\n\t\tthis.fire('drag', e);\r\n\t},\r\n\r\n\t_onUp: function () {\r\n\t\t// Ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (!this._enabled) { return; }\r\n\t\tthis.finishDrag();\r\n\t},\r\n\r\n\tfinishDrag: function (noInertia) {\r\n\t\tDomUtil.removeClass(document.body, 'leaflet-dragging');\r\n\r\n\t\tif (this._lastTarget) {\r\n\t\t\tDomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t\tthis._lastTarget = null;\r\n\t\t}\r\n\r\n\t\tDomEvent.off(document, 'mousemove touchmove', this._onMove, this);\r\n\t\tDomEvent.off(document, 'mouseup touchend touchcancel', this._onUp, this);\r\n\r\n\t\tDomUtil.enableImageDrag();\r\n\t\tDomUtil.enableTextSelection();\r\n\r\n\t\tif (this._moved && this._moving) {\r\n\r\n\t\t\t// @event dragend: DragEndEvent\r\n\t\t\t// Fired when the drag ends.\r\n\t\t\tthis.fire('dragend', {\r\n\t\t\t\tnoInertia: noInertia,\r\n\t\t\t\tdistance: this._newPos.distanceTo(this._startPos)\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._moving = false;\r\n\t\tDraggable._dragging = false;\r\n\t}\r\n\r\n});\r\n","import {Point, toPoint} from './Point';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLng} from '../geo/LatLng';\r\n\r\n\r\n/*\r\n * @namespace LineUtil\r\n *\r\n * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.\r\n */\r\n\r\n// Simplify polyline with vertex reduction and Douglas-Peucker simplification.\r\n// Improves rendering performance dramatically by lessening the number of points to draw.\r\n\r\n// @function simplify(points: Point[], tolerance: Number): Point[]\r\n// Dramatically reduces the number of points in a polyline while retaining\r\n// its shape and returns a new array of simplified points, using the\r\n// [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm).\r\n// Used for a huge performance boost when processing/displaying Leaflet polylines for\r\n// each zoom level and also reducing visual noise. tolerance affects the amount of\r\n// simplification (lesser value means higher quality but slower and with more points).\r\n// Also released as a separated micro-library [Simplify.js](https://mourner.github.io/simplify-js/).\r\nexport function simplify(points, tolerance) {\r\n\tif (!tolerance || !points.length) {\r\n\t\treturn points.slice();\r\n\t}\r\n\r\n\tvar sqTolerance = tolerance * tolerance;\r\n\r\n\t // stage 1: vertex reduction\r\n\t points = _reducePoints(points, sqTolerance);\r\n\r\n\t // stage 2: Douglas-Peucker simplification\r\n\t points = _simplifyDP(points, sqTolerance);\r\n\r\n\treturn points;\r\n}\r\n\r\n// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number\r\n// Returns the distance between point `p` and segment `p1` to `p2`.\r\nexport function pointToSegmentDistance(p, p1, p2) {\r\n\treturn Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));\r\n}\r\n\r\n// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number\r\n// Returns the closest point from a point `p` on a segment `p1` to `p2`.\r\nexport function closestPointOnSegment(p, p1, p2) {\r\n\treturn _sqClosestPointOnSegment(p, p1, p2);\r\n}\r\n\r\n// Ramer-Douglas-Peucker simplification, see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\r\nfunction _simplifyDP(points, sqTolerance) {\r\n\r\n\tvar len = points.length,\r\n\t ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,\r\n\t markers = new ArrayConstructor(len);\r\n\r\n\t markers[0] = markers[len - 1] = 1;\r\n\r\n\t_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);\r\n\r\n\tvar i,\r\n\t newPoints = [];\r\n\r\n\tfor (i = 0; i < len; i++) {\r\n\t\tif (markers[i]) {\r\n\t\t\tnewPoints.push(points[i]);\r\n\t\t}\r\n\t}\r\n\r\n\treturn newPoints;\r\n}\r\n\r\nfunction _simplifyDPStep(points, markers, sqTolerance, first, last) {\r\n\r\n\tvar maxSqDist = 0,\r\n\tindex, i, sqDist;\r\n\r\n\tfor (i = first + 1; i <= last - 1; i++) {\r\n\t\tsqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);\r\n\r\n\t\tif (sqDist > maxSqDist) {\r\n\t\t\tindex = i;\r\n\t\t\tmaxSqDist = sqDist;\r\n\t\t}\r\n\t}\r\n\r\n\tif (maxSqDist > sqTolerance) {\r\n\t\tmarkers[index] = 1;\r\n\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, first, index);\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, index, last);\r\n\t}\r\n}\r\n\r\n// reduce points that are too close to each other to a single point\r\nfunction _reducePoints(points, sqTolerance) {\r\n\tvar reducedPoints = [points[0]];\r\n\r\n\tfor (var i = 1, prev = 0, len = points.length; i < len; i++) {\r\n\t\tif (_sqDist(points[i], points[prev]) > sqTolerance) {\r\n\t\t\treducedPoints.push(points[i]);\r\n\t\t\tprev = i;\r\n\t\t}\r\n\t}\r\n\tif (prev < len - 1) {\r\n\t\treducedPoints.push(points[len - 1]);\r\n\t}\r\n\treturn reducedPoints;\r\n}\r\n\r\nvar _lastCode;\r\n\r\n// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean\r\n// Clips the segment a to b by rectangular bounds with the\r\n// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)\r\n// (modifying the segment points directly!). Used by Leaflet to only show polyline\r\n// points that are on the screen or near, increasing performance.\r\nexport function clipSegment(a, b, bounds, useLastCode, round) {\r\n\tvar codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),\r\n\t codeB = _getBitCode(b, bounds),\r\n\r\n\t codeOut, p, newCode;\r\n\r\n\t // save 2nd code to avoid calculating it on the next segment\r\n\t _lastCode = codeB;\r\n\r\n\twhile (true) {\r\n\t\t// if a,b is inside the clip window (trivial accept)\r\n\t\tif (!(codeA | codeB)) {\r\n\t\t\treturn [a, b];\r\n\t\t}\r\n\r\n\t\t// if a,b is outside the clip window (trivial reject)\r\n\t\tif (codeA & codeB) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// other cases\r\n\t\tcodeOut = codeA || codeB;\r\n\t\tp = _getEdgeIntersection(a, b, codeOut, bounds, round);\r\n\t\tnewCode = _getBitCode(p, bounds);\r\n\r\n\t\tif (codeOut === codeA) {\r\n\t\t\ta = p;\r\n\t\t\tcodeA = newCode;\r\n\t\t} else {\r\n\t\t\tb = p;\r\n\t\t\tcodeB = newCode;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport function _getEdgeIntersection(a, b, code, bounds, round) {\r\n\tvar dx = b.x - a.x,\r\n\t dy = b.y - a.y,\r\n\t min = bounds.min,\r\n\t max = bounds.max,\r\n\t x, y;\r\n\r\n\tif (code & 8) { // top\r\n\t\tx = a.x + dx * (max.y - a.y) / dy;\r\n\t\ty = max.y;\r\n\r\n\t} else if (code & 4) { // bottom\r\n\t\tx = a.x + dx * (min.y - a.y) / dy;\r\n\t\ty = min.y;\r\n\r\n\t} else if (code & 2) { // right\r\n\t\tx = max.x;\r\n\t\ty = a.y + dy * (max.x - a.x) / dx;\r\n\r\n\t} else if (code & 1) { // left\r\n\t\tx = min.x;\r\n\t\ty = a.y + dy * (min.x - a.x) / dx;\r\n\t}\r\n\r\n\treturn new Point(x, y, round);\r\n}\r\n\r\nexport function _getBitCode(p, bounds) {\r\n\tvar code = 0;\r\n\r\n\tif (p.x < bounds.min.x) { // left\r\n\t\tcode |= 1;\r\n\t} else if (p.x > bounds.max.x) { // right\r\n\t\tcode |= 2;\r\n\t}\r\n\r\n\tif (p.y < bounds.min.y) { // bottom\r\n\t\tcode |= 4;\r\n\t} else if (p.y > bounds.max.y) { // top\r\n\t\tcode |= 8;\r\n\t}\r\n\r\n\treturn code;\r\n}\r\n\r\n// square distance (to avoid unnecessary Math.sqrt calls)\r\nfunction _sqDist(p1, p2) {\r\n\tvar dx = p2.x - p1.x,\r\n\t dy = p2.y - p1.y;\r\n\treturn dx * dx + dy * dy;\r\n}\r\n\r\n// return closest point on segment or distance to that point\r\nexport function _sqClosestPointOnSegment(p, p1, p2, sqDist) {\r\n\tvar x = p1.x,\r\n\t y = p1.y,\r\n\t dx = p2.x - x,\r\n\t dy = p2.y - y,\r\n\t dot = dx * dx + dy * dy,\r\n\t t;\r\n\r\n\tif (dot > 0) {\r\n\t\tt = ((p.x - x) * dx + (p.y - y) * dy) / dot;\r\n\r\n\t\tif (t > 1) {\r\n\t\t\tx = p2.x;\r\n\t\t\ty = p2.y;\r\n\t\t} else if (t > 0) {\r\n\t\t\tx += dx * t;\r\n\t\t\ty += dy * t;\r\n\t\t}\r\n\t}\r\n\r\n\tdx = p.x - x;\r\n\tdy = p.y - y;\r\n\r\n\treturn sqDist ? dx * dx + dy * dy : new Point(x, y);\r\n}\r\n\r\n\r\n// @function isFlat(latlngs: LatLng[]): Boolean\r\n// Returns true if `latlngs` is a flat array, false is nested.\r\nexport function isFlat(latlngs) {\r\n\treturn !Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');\r\n}\r\n\r\nexport function _flat(latlngs) {\r\n\tconsole.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');\r\n\treturn isFlat(latlngs);\r\n}\r\n\r\n/* @function polylineCenter(latlngs: LatLng[], crs: CRS): LatLng\r\n * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polyline.\r\n */\r\nexport function polylineCenter(latlngs, crs) {\r\n\tvar i, halfDist, segDist, dist, p1, p2, ratio, center;\r\n\r\n\tif (!latlngs || latlngs.length === 0) {\r\n\t\tthrow new Error('latlngs not passed');\r\n\t}\r\n\r\n\tif (!isFlat(latlngs)) {\r\n\t\tconsole.warn('latlngs are not flat! Only the first ring will be used');\r\n\t\tlatlngs = latlngs[0];\r\n\t}\r\n\r\n\tvar points = [];\r\n\tfor (var j in latlngs) {\r\n\t\tpoints.push(crs.project(toLatLng(latlngs[j])));\r\n\t}\r\n\r\n\tvar len = points.length;\r\n\r\n\tfor (i = 0, halfDist = 0; i < len - 1; i++) {\r\n\t\thalfDist += points[i].distanceTo(points[i + 1]) / 2;\r\n\t}\r\n\r\n\t// The line is so small in the current view that all points are on the same pixel.\r\n\tif (halfDist === 0) {\r\n\t\tcenter = points[0];\r\n\t} else {\r\n\t\tfor (i = 0, dist = 0; i < len - 1; i++) {\r\n\t\t\tp1 = points[i];\r\n\t\t\tp2 = points[i + 1];\r\n\t\t\tsegDist = p1.distanceTo(p2);\r\n\t\t\tdist += segDist;\r\n\r\n\t\t\tif (dist > halfDist) {\r\n\t\t\t\tratio = (dist - halfDist) / segDist;\r\n\t\t\t\tcenter = [\r\n\t\t\t\t\tp2.x - ratio * (p2.x - p1.x),\r\n\t\t\t\t\tp2.y - ratio * (p2.y - p1.y)\r\n\t\t\t\t];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn crs.unproject(toPoint(center));\r\n}\r\n","import * as LineUtil from './LineUtil';\r\nimport {toLatLng} from '../geo/LatLng';\r\nimport {toPoint} from './Point';\r\n/*\r\n * @namespace PolyUtil\r\n * Various utility functions for polygon geometries.\r\n */\r\n\r\n/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]\r\n * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).\r\n * Used by Leaflet to only show polygon points that are on the screen or near, increasing\r\n * performance. Note that polygon points needs different algorithm for clipping\r\n * than polyline, so there's a separate method for it.\r\n */\r\nexport function clipPolygon(points, bounds, round) {\r\n\tvar clippedPoints,\r\n\t edges = [1, 4, 2, 8],\r\n\t i, j, k,\r\n\t a, b,\r\n\t len, edge, p;\r\n\r\n\tfor (i = 0, len = points.length; i < len; i++) {\r\n\t\tpoints[i]._code = LineUtil._getBitCode(points[i], bounds);\r\n\t}\r\n\r\n\t// for each edge (left, bottom, right, top)\r\n\tfor (k = 0; k < 4; k++) {\r\n\t\tedge = edges[k];\r\n\t\tclippedPoints = [];\r\n\r\n\t\tfor (i = 0, len = points.length, j = len - 1; i < len; j = i++) {\r\n\t\t\ta = points[i];\r\n\t\t\tb = points[j];\r\n\r\n\t\t\t// if a is inside the clip window\r\n\t\t\tif (!(a._code & edge)) {\r\n\t\t\t\t// if b is outside the clip window (a->b goes out of screen)\r\n\t\t\t\tif (b._code & edge) {\r\n\t\t\t\t\tp = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\t\tp._code = LineUtil._getBitCode(p, bounds);\r\n\t\t\t\t\tclippedPoints.push(p);\r\n\t\t\t\t}\r\n\t\t\t\tclippedPoints.push(a);\r\n\r\n\t\t\t// else if b is inside the clip window (a->b enters the screen)\r\n\t\t\t} else if (!(b._code & edge)) {\r\n\t\t\t\tp = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\tp._code = LineUtil._getBitCode(p, bounds);\r\n\t\t\t\tclippedPoints.push(p);\r\n\t\t\t}\r\n\t\t}\r\n\t\tpoints = clippedPoints;\r\n\t}\r\n\r\n\treturn points;\r\n}\r\n\r\n/* @function polygonCenter(latlngs: LatLng[] crs: CRS): LatLng\r\n * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon.\r\n */\r\nexport function polygonCenter(latlngs, crs) {\r\n\tvar i, j, p1, p2, f, area, x, y, center;\r\n\r\n\tif (!latlngs || latlngs.length === 0) {\r\n\t\tthrow new Error('latlngs not passed');\r\n\t}\r\n\r\n\tif (!LineUtil.isFlat(latlngs)) {\r\n\t\tconsole.warn('latlngs are not flat! Only the first ring will be used');\r\n\t\tlatlngs = latlngs[0];\r\n\t}\r\n\r\n\tvar points = [];\r\n\tfor (var k in latlngs) {\r\n\t\tpoints.push(crs.project(toLatLng(latlngs[k])));\r\n\t}\r\n\r\n\tvar len = points.length;\r\n\tarea = x = y = 0;\r\n\r\n\t// polygon centroid algorithm;\r\n\tfor (i = 0, j = len - 1; i < len; j = i++) {\r\n\t\tp1 = points[i];\r\n\t\tp2 = points[j];\r\n\r\n\t\tf = p1.y * p2.x - p2.y * p1.x;\r\n\t\tx += (p1.x + p2.x) * f;\r\n\t\ty += (p1.y + p2.y) * f;\r\n\t\tarea += f * 3;\r\n\t}\r\n\r\n\tif (area === 0) {\r\n\t\t// Polygon is so small that all points are on same pixel.\r\n\t\tcenter = points[0];\r\n\t} else {\r\n\t\tcenter = [x / area, y / area];\r\n\t}\r\n\treturn crs.unproject(toPoint(center));\r\n}\r\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @section\r\n * Leaflet comes with a set of already defined Projections out of the box:\r\n *\r\n * @projection L.Projection.LonLat\r\n *\r\n * Equirectangular, or Plate Carree projection — the most simple projection,\r\n * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as\r\n * latitude. Also suitable for flat worlds, e.g. game maps. Used by the\r\n * `EPSG:4326` and `Simple` CRS.\r\n */\r\n\r\nexport var LonLat = {\r\n\tproject: function (latlng) {\r\n\t\treturn new Point(latlng.lng, latlng.lat);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\treturn new LatLng(point.y, point.x);\r\n\t},\r\n\r\n\tbounds: new Bounds([-180, -90], [180, 90])\r\n};\r\n","import {LatLng} from '../LatLng';\r\nimport {Bounds} from '../../geometry/Bounds';\r\nimport {Point} from '../../geometry/Point';\r\n\r\n/*\r\n * @namespace Projection\r\n * @projection L.Projection.Mercator\r\n *\r\n * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS.\r\n */\r\n\r\nexport var Mercator = {\r\n\tR: 6378137,\r\n\tR_MINOR: 6356752.314245179,\r\n\r\n\tbounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t r = this.R,\r\n\t\t y = latlng.lat * d,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t con = e * Math.sin(y);\r\n\r\n\t\tvar ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\ty = -r * Math.log(Math.max(ts, 1E-10));\r\n\r\n\t\treturn new Point(latlng.lng * d * r, y);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI,\r\n\t\t r = this.R,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t ts = Math.exp(-point.y / r),\r\n\t\t phi = Math.PI / 2 - 2 * Math.atan(ts);\r\n\r\n\t\tfor (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {\r\n\t\t\tcon = e * Math.sin(phi);\r\n\t\t\tcon = Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\t\tdphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;\r\n\t\t\tphi += dphi;\r\n\t\t}\r\n\r\n\t\treturn new LatLng(phi * d, point.x * d / r);\r\n\t}\r\n};\r\n","/*\n * @class Projection\n\n * An object with methods for projecting geographical coordinates of the world onto\n * a flat surface (and back). See [Map projection](https://en.wikipedia.org/wiki/Map_projection).\n\n * @property bounds: Bounds\n * The bounds (specified in CRS units) where the projection is valid\n\n * @method project(latlng: LatLng): Point\n * Projects geographical coordinates into a 2D point.\n * Only accepts actual `L.LatLng` instances, not arrays.\n\n * @method unproject(point: Point): LatLng\n * The inverse of `project`. Projects a 2D point into a geographical location.\n * Only accepts actual `L.Point` instances, not arrays.\n\n * Note that the projection instances do not inherit from Leaflet's `Class` object,\n * and can't be instantiated. Also, new classes can't inherit from them,\n * and methods can't be added to them with the `include` function.\n\n */\n\nexport {LonLat} from './Projection.LonLat';\nexport {Mercator} from './Projection.Mercator';\nexport {SphericalMercator} from './Projection.SphericalMercator';\n","import {Earth} from './CRS.Earth';\r\nimport {Mercator} from '../projection/Projection.Mercator';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3395\r\n *\r\n * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.\r\n */\r\nexport var EPSG3395 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:3395',\r\n\tprojection: Mercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * Mercator.R);\r\n\t\treturn toTransformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n","import {Earth} from './CRS.Earth';\r\nimport {LonLat} from '../projection/Projection.LonLat';\r\nimport {toTransformation} from '../../geometry/Transformation';\r\nimport * as Util from '../../core/Util';\r\n\r\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG4326\r\n *\r\n * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.\r\n *\r\n * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),\r\n * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer`\r\n * with this CRS, ensure that there are two 256x256 pixel tiles covering the\r\n * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),\r\n * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.\r\n */\r\n\r\nexport var EPSG4326 = Util.extend({}, Earth, {\r\n\tcode: 'EPSG:4326',\r\n\tprojection: LonLat,\r\n\ttransformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)\r\n});\r\n","import {CRS} from './CRS';\nimport {LonLat} from '../projection/Projection.LonLat';\nimport {toTransformation} from '../../geometry/Transformation';\nimport * as Util from '../../core/Util';\n\n/*\n * @namespace CRS\n * @crs L.CRS.Simple\n *\n * A simple CRS that maps longitude and latitude into `x` and `y` directly.\n * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`\n * axis should still be inverted (going from bottom to top). `distance()` returns\n * simple euclidean distance.\n */\n\nexport var Simple = Util.extend({}, CRS, {\n\tprojection: LonLat,\n\ttransformation: toTransformation(1, 0, -1, 0),\n\n\tscale: function (zoom) {\n\t\treturn Math.pow(2, zoom);\n\t},\n\n\tzoom: function (scale) {\n\t\treturn Math.log(scale) / Math.LN2;\n\t},\n\n\tdistance: function (latlng1, latlng2) {\n\t\tvar dx = latlng2.lng - latlng1.lng,\n\t\t dy = latlng2.lat - latlng1.lat;\n\n\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t},\n\n\tinfinite: true\n});\n","import {CRS} from './CRS';\nimport {Earth} from './CRS.Earth';\nimport {EPSG3395} from './CRS.EPSG3395';\nimport {EPSG3857, EPSG900913} from './CRS.EPSG3857';\nimport {EPSG4326} from './CRS.EPSG4326';\nimport {Simple} from './CRS.Simple';\n\nCRS.Earth = Earth;\nCRS.EPSG3395 = EPSG3395;\nCRS.EPSG3857 = EPSG3857;\nCRS.EPSG900913 = EPSG900913;\nCRS.EPSG4326 = EPSG4326;\nCRS.Simple = Simple;\n\nexport {CRS};\n","import {Evented} from '../core/Events';\nimport {Map} from '../map/Map';\nimport * as Util from '../core/Util';\n\n/*\n * @class Layer\n * @inherits Evented\n * @aka L.Layer\n * @aka ILayer\n *\n * A set of methods from the Layer base class that all Leaflet layers use.\n * Inherits all methods, options and events from `L.Evented`.\n *\n * @example\n *\n * ```js\n * var layer = L.marker(latlng).addTo(map);\n * layer.addTo(map);\n * layer.remove();\n * ```\n *\n * @event add: Event\n * Fired after the layer is added to a map\n *\n * @event remove: Event\n * Fired after the layer is removed from a map\n */\n\n\nexport var Layer = Evented.extend({\n\n\t// Classes extending `L.Layer` will inherit the following options:\n\toptions: {\n\t\t// @option pane: String = 'overlayPane'\n\t\t// By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.\n\t\tpane: 'overlayPane',\n\n\t\t// @option attribution: String = null\n\t\t// String to be shown in the attribution control, e.g. \"© OpenStreetMap contributors\". It describes the layer data and is often a legal obligation towards copyright holders and tile providers.\n\t\tattribution: null,\n\n\t\tbubblingMouseEvents: true\n\t},\n\n\t/* @section\n\t * Classes extending `L.Layer` will inherit the following methods:\n\t *\n\t * @method addTo(map: Map|LayerGroup): this\n\t * Adds the layer to the given map or layer group.\n\t */\n\taddTo: function (map) {\n\t\tmap.addLayer(this);\n\t\treturn this;\n\t},\n\n\t// @method remove: this\n\t// Removes the layer from the map it is currently active on.\n\tremove: function () {\n\t\treturn this.removeFrom(this._map || this._mapToAdd);\n\t},\n\n\t// @method removeFrom(map: Map): this\n\t// Removes the layer from the given map\n\t//\n\t// @alternative\n\t// @method removeFrom(group: LayerGroup): this\n\t// Removes the layer from the given `LayerGroup`\n\tremoveFrom: function (obj) {\n\t\tif (obj) {\n\t\t\tobj.removeLayer(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getPane(name? : String): HTMLElement\n\t// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.\n\tgetPane: function (name) {\n\t\treturn this._map.getPane(name ? (this.options[name] || name) : this.options.pane);\n\t},\n\n\taddInteractiveTarget: function (targetEl) {\n\t\tthis._map._targets[Util.stamp(targetEl)] = this;\n\t\treturn this;\n\t},\n\n\tremoveInteractiveTarget: function (targetEl) {\n\t\tdelete this._map._targets[Util.stamp(targetEl)];\n\t\treturn this;\n\t},\n\n\t// @method getAttribution: String\n\t// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).\n\tgetAttribution: function () {\n\t\treturn this.options.attribution;\n\t},\n\n\t_layerAdd: function (e) {\n\t\tvar map = e.target;\n\n\t\t// check in case layer gets added and then removed before the map is ready\n\t\tif (!map.hasLayer(this)) { return; }\n\n\t\tthis._map = map;\n\t\tthis._zoomAnimated = map._zoomAnimated;\n\n\t\tif (this.getEvents) {\n\t\t\tvar events = this.getEvents();\n\t\t\tmap.on(events, this);\n\t\t\tthis.once('remove', function () {\n\t\t\t\tmap.off(events, this);\n\t\t\t}, this);\n\t\t}\n\n\t\tthis.onAdd(map);\n\n\t\tthis.fire('add');\n\t\tmap.fire('layeradd', {layer: this});\n\t}\n});\n\n/* @section Extension methods\n * @uninheritable\n *\n * Every layer should extend from `L.Layer` and (re-)implement the following methods.\n *\n * @method onAdd(map: Map): this\n * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).\n *\n * @method onRemove(map: Map): this\n * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).\n *\n * @method getEvents(): Object\n * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.\n *\n * @method getAttribution(): String\n * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.\n *\n * @method beforeAdd(map: Map): this\n * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.\n */\n\n\n/* @namespace Map\n * @section Layer events\n *\n * @event layeradd: LayerEvent\n * Fired when a new layer is added to the map.\n *\n * @event layerremove: LayerEvent\n * Fired when some layer is removed from the map\n *\n * @section Methods for Layers and Controls\n */\nMap.include({\n\t// @method addLayer(layer: Layer): this\n\t// Adds the given layer to the map\n\taddLayer: function (layer) {\n\t\tif (!layer._layerAdd) {\n\t\t\tthrow new Error('The provided object is not a Layer.');\n\t\t}\n\n\t\tvar id = Util.stamp(layer);\n\t\tif (this._layers[id]) { return this; }\n\t\tthis._layers[id] = layer;\n\n\t\tlayer._mapToAdd = this;\n\n\t\tif (layer.beforeAdd) {\n\t\t\tlayer.beforeAdd(this);\n\t\t}\n\n\t\tthis.whenReady(layer._layerAdd, layer);\n\n\t\treturn this;\n\t},\n\n\t// @method removeLayer(layer: Layer): this\n\t// Removes the given layer from the map.\n\tremoveLayer: function (layer) {\n\t\tvar id = Util.stamp(layer);\n\n\t\tif (!this._layers[id]) { return this; }\n\n\t\tif (this._loaded) {\n\t\t\tlayer.onRemove(this);\n\t\t}\n\n\t\tdelete this._layers[id];\n\n\t\tif (this._loaded) {\n\t\t\tthis.fire('layerremove', {layer: layer});\n\t\t\tlayer.fire('remove');\n\t\t}\n\n\t\tlayer._map = layer._mapToAdd = null;\n\n\t\treturn this;\n\t},\n\n\t// @method hasLayer(layer: Layer): Boolean\n\t// Returns `true` if the given layer is currently added to the map\n\thasLayer: function (layer) {\n\t\treturn Util.stamp(layer) in this._layers;\n\t},\n\n\t/* @method eachLayer(fn: Function, context?: Object): this\n\t * Iterates over the layers of the map, optionally specifying context of the iterator function.\n\t * ```\n\t * map.eachLayer(function(layer){\n\t * layer.bindPopup('Hello');\n\t * });\n\t * ```\n\t */\n\teachLayer: function (method, context) {\n\t\tfor (var i in this._layers) {\n\t\t\tmethod.call(context, this._layers[i]);\n\t\t}\n\t\treturn this;\n\t},\n\n\t_addLayers: function (layers) {\n\t\tlayers = layers ? (Util.isArray(layers) ? layers : [layers]) : [];\n\n\t\tfor (var i = 0, len = layers.length; i < len; i++) {\n\t\t\tthis.addLayer(layers[i]);\n\t\t}\n\t},\n\n\t_addZoomLimit: function (layer) {\n\t\tif (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {\n\t\t\tthis._zoomBoundLayers[Util.stamp(layer)] = layer;\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_removeZoomLimit: function (layer) {\n\t\tvar id = Util.stamp(layer);\n\n\t\tif (this._zoomBoundLayers[id]) {\n\t\t\tdelete this._zoomBoundLayers[id];\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_updateZoomLevels: function () {\n\t\tvar minZoom = Infinity,\n\t\t maxZoom = -Infinity,\n\t\t oldZoomSpan = this._getZoomSpan();\n\n\t\tfor (var i in this._zoomBoundLayers) {\n\t\t\tvar options = this._zoomBoundLayers[i].options;\n\n\t\t\tminZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);\n\t\t\tmaxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);\n\t\t}\n\n\t\tthis._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;\n\t\tthis._layersMinZoom = minZoom === Infinity ? undefined : minZoom;\n\n\t\t// @section Map state change events\n\t\t// @event zoomlevelschange: Event\n\t\t// Fired when the number of zoomlevels on the map is changed due\n\t\t// to adding or removing a layer.\n\t\tif (oldZoomSpan !== this._getZoomSpan()) {\n\t\t\tthis.fire('zoomlevelschange');\n\t\t}\n\n\t\tif (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {\n\t\t\tthis.setZoom(this._layersMaxZoom);\n\t\t}\n\t\tif (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {\n\t\t\tthis.setZoom(this._layersMinZoom);\n\t\t}\n\t}\n});\n","\r\nimport {Layer} from './Layer';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class LayerGroup\r\n * @aka L.LayerGroup\r\n * @inherits Interactive layer\r\n *\r\n * Used to group several layers and handle them as one. If you add it to the map,\r\n * any layers added or removed from the group will be added/removed on the map as\r\n * well. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.layerGroup([marker1, marker2])\r\n * \t.addLayer(polyline)\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nexport var LayerGroup = Layer.extend({\r\n\r\n\tinitialize: function (layers, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tvar i, len;\r\n\r\n\t\tif (layers) {\r\n\t\t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n\t\t\t\tthis.addLayer(layers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addLayer(layer: Layer): this\r\n\t// Adds the given layer to the group.\r\n\taddLayer: function (layer) {\r\n\t\tvar id = this.getLayerId(layer);\r\n\r\n\t\tthis._layers[id] = layer;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.addLayer(layer);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Removes the given layer from the group.\r\n\t// @alternative\r\n\t// @method removeLayer(id: Number): this\r\n\t// Removes the layer with the given internal ID from the group.\r\n\tremoveLayer: function (layer) {\r\n\t\tvar id = layer in this._layers ? layer : this.getLayerId(layer);\r\n\r\n\t\tif (this._map && this._layers[id]) {\r\n\t\t\tthis._map.removeLayer(this._layers[id]);\r\n\t\t}\r\n\r\n\t\tdelete this._layers[id];\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method hasLayer(layer: Layer): Boolean\r\n\t// Returns `true` if the given layer is currently added to the group.\r\n\t// @alternative\r\n\t// @method hasLayer(id: Number): Boolean\r\n\t// Returns `true` if the given internal ID is currently added to the group.\r\n\thasLayer: function (layer) {\r\n\t\tvar layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);\r\n\t\treturn layerId in this._layers;\r\n\t},\r\n\r\n\t// @method clearLayers(): this\r\n\t// Removes all the layers from the group.\r\n\tclearLayers: function () {\r\n\t\treturn this.eachLayer(this.removeLayer, this);\r\n\t},\r\n\r\n\t// @method invoke(methodName: String, …): this\r\n\t// Calls `methodName` on every layer contained in this group, passing any\r\n\t// additional parameters. Has no effect if the layers contained do not\r\n\t// implement `methodName`.\r\n\tinvoke: function (methodName) {\r\n\t\tvar args = Array.prototype.slice.call(arguments, 1),\r\n\t\t i, layer;\r\n\r\n\t\tfor (i in this._layers) {\r\n\t\t\tlayer = this._layers[i];\r\n\r\n\t\t\tif (layer[methodName]) {\r\n\t\t\t\tlayer[methodName].apply(layer, args);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis.eachLayer(map.addLayer, map);\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tthis.eachLayer(map.removeLayer, map);\r\n\t},\r\n\r\n\t// @method eachLayer(fn: Function, context?: Object): this\r\n\t// Iterates over the layers of the group, optionally specifying context of the iterator function.\r\n\t// ```js\r\n\t// group.eachLayer(function (layer) {\r\n\t// \tlayer.bindPopup('Hello');\r\n\t// });\r\n\t// ```\r\n\teachLayer: function (method, context) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmethod.call(context, this._layers[i]);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getLayer(id: Number): Layer\r\n\t// Returns the layer with the given internal ID.\r\n\tgetLayer: function (id) {\r\n\t\treturn this._layers[id];\r\n\t},\r\n\r\n\t// @method getLayers(): Layer[]\r\n\t// Returns an array of all the layers added to the group.\r\n\tgetLayers: function () {\r\n\t\tvar layers = [];\r\n\t\tthis.eachLayer(layers.push, layers);\r\n\t\treturn layers;\r\n\t},\r\n\r\n\t// @method setZIndex(zIndex: Number): this\r\n\t// Calls `setZIndex` on every layer contained in this group, passing the z-index.\r\n\tsetZIndex: function (zIndex) {\r\n\t\treturn this.invoke('setZIndex', zIndex);\r\n\t},\r\n\r\n\t// @method getLayerId(layer: Layer): Number\r\n\t// Returns the internal ID for a layer\r\n\tgetLayerId: function (layer) {\r\n\t\treturn Util.stamp(layer);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.layerGroup(layers?: Layer[], options?: Object)\r\n// Create a layer group, optionally given an initial set of layers and an `options` object.\r\nexport var layerGroup = function (layers, options) {\r\n\treturn new LayerGroup(layers, options);\r\n};\r\n","import {LayerGroup} from './LayerGroup';\r\nimport {LatLngBounds} from '../geo/LatLngBounds';\r\n\r\n/*\r\n * @class FeatureGroup\r\n * @aka L.FeatureGroup\r\n * @inherits LayerGroup\r\n *\r\n * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:\r\n * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))\r\n * * Events are propagated to the `FeatureGroup`, so if the group has an event\r\n * handler, it will handle events from any of the layers. This includes mouse events\r\n * and custom events.\r\n * * Has `layeradd` and `layerremove` events\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.featureGroup([marker1, marker2, polyline])\r\n * \t.bindPopup('Hello world!')\r\n * \t.on('click', function() { alert('Clicked on a member of the group!'); })\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nexport var FeatureGroup = LayerGroup.extend({\r\n\r\n\taddLayer: function (layer) {\r\n\t\tif (this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlayer.addEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.addLayer.call(this, layer);\r\n\r\n\t\t// @event layeradd: LayerEvent\r\n\t\t// Fired when a layer is added to this `FeatureGroup`\r\n\t\treturn this.fire('layeradd', {layer: layer});\r\n\t},\r\n\r\n\tremoveLayer: function (layer) {\r\n\t\tif (!this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tif (layer in this._layers) {\r\n\t\t\tlayer = this._layers[layer];\r\n\t\t}\r\n\r\n\t\tlayer.removeEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.removeLayer.call(this, layer);\r\n\r\n\t\t// @event layerremove: LayerEvent\r\n\t\t// Fired when a layer is removed from this `FeatureGroup`\r\n\t\treturn this.fire('layerremove', {layer: layer});\r\n\t},\r\n\r\n\t// @method setStyle(style: Path options): this\r\n\t// Sets the given path options to each layer of the group that has a `setStyle` method.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.invoke('setStyle', style);\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer group to the top of all other layers\r\n\tbringToFront: function () {\r\n\t\treturn this.invoke('bringToFront');\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer group to the back of all other layers\r\n\tbringToBack: function () {\r\n\t\treturn this.invoke('bringToBack');\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).\r\n\tgetBounds: function () {\r\n\t\tvar bounds = new LatLngBounds();\r\n\r\n\t\tfor (var id in this._layers) {\r\n\t\t\tvar layer = this._layers[id];\r\n\t\t\tbounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());\r\n\t\t}\r\n\t\treturn bounds;\r\n\t}\r\n});\r\n\r\n// @factory L.featureGroup(layers?: Layer[], options?: Object)\r\n// Create a feature group, optionally given an initial set of layers and an `options` object.\r\nexport var featureGroup = function (layers, options) {\r\n\treturn new FeatureGroup(layers, options);\r\n};\r\n","import {Class} from '../../core/Class';\r\nimport {setOptions} from '../../core/Util';\r\nimport {toPoint as point} from '../../geometry/Point';\r\nimport Browser from '../../core/Browser';\r\n\r\n/*\r\n * @class Icon\r\n * @aka L.Icon\r\n *\r\n * Represents an icon to provide when creating a marker.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var myIcon = L.icon({\r\n * iconUrl: 'my-icon.png',\r\n * iconRetinaUrl: 'my-icon@2x.png',\r\n * iconSize: [38, 95],\r\n * iconAnchor: [22, 94],\r\n * popupAnchor: [-3, -76],\r\n * shadowUrl: 'my-icon-shadow.png',\r\n * shadowRetinaUrl: 'my-icon-shadow@2x.png',\r\n * shadowSize: [68, 95],\r\n * shadowAnchor: [22, 94]\r\n * });\r\n *\r\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\r\n * ```\r\n *\r\n * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.\r\n *\r\n */\r\n\r\nexport var Icon = Class.extend({\r\n\r\n\t/* @section\r\n\t * @aka Icon options\r\n\t *\r\n\t * @option iconUrl: String = null\r\n\t * **(required)** The URL to the icon image (absolute or relative to your script path).\r\n\t *\r\n\t * @option iconRetinaUrl: String = null\r\n\t * The URL to a retina sized version of the icon image (absolute or relative to your\r\n\t * script path). Used for Retina screen devices.\r\n\t *\r\n\t * @option iconSize: Point = null\r\n\t * Size of the icon image in pixels.\r\n\t *\r\n\t * @option iconAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the icon (relative to its top left corner). The icon\r\n\t * will be aligned so that this point is at the marker's geographical location. Centered\r\n\t * by default if size is specified, also can be set in CSS with negative margins.\r\n\t *\r\n\t * @option popupAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which popups will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option tooltipAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which tooltips will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option shadowUrl: String = null\r\n\t * The URL to the icon shadow image. If not specified, no shadow image will be created.\r\n\t *\r\n\t * @option shadowRetinaUrl: String = null\r\n\t *\r\n\t * @option shadowSize: Point = null\r\n\t * Size of the shadow image in pixels.\r\n\t *\r\n\t * @option shadowAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the shadow (relative to its top left corner) (the same\r\n\t * as iconAnchor if not specified).\r\n\t *\r\n\t * @option className: String = ''\r\n\t * A custom class name to assign to both icon and shadow images. Empty by default.\r\n\t */\r\n\r\n\toptions: {\r\n\t\tpopupAnchor: [0, 0],\r\n\t\ttooltipAnchor: [0, 0],\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tsetOptions(this, options);\r\n\t},\r\n\r\n\t// @method createIcon(oldIcon?: HTMLElement): HTMLElement\r\n\t// Called internally when the icon has to be shown, returns a `<img>` HTML element\r\n\t// styled according to the options.\r\n\tcreateIcon: function (oldIcon) {\r\n\t\treturn this._createIcon('icon', oldIcon);\r\n\t},\r\n\r\n\t// @method createShadow(oldIcon?: HTMLElement): HTMLElement\r\n\t// As `createIcon`, but for the shadow beneath it.\r\n\tcreateShadow: function (oldIcon) {\r\n\t\treturn this._createIcon('shadow', oldIcon);\r\n\t},\r\n\r\n\t_createIcon: function (name, oldIcon) {\r\n\t\tvar src = this._getIconUrl(name);\r\n\r\n\t\tif (!src) {\r\n\t\t\tif (name === 'icon') {\r\n\t\t\t\tthrow new Error('iconUrl not set in Icon options (see the docs).');\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tvar img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);\r\n\t\tthis._setIconStyles(img, name);\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\timg.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\treturn img;\r\n\t},\r\n\r\n\t_setIconStyles: function (img, name) {\r\n\t\tvar options = this.options;\r\n\t\tvar sizeOption = options[name + 'Size'];\r\n\r\n\t\tif (typeof sizeOption === 'number') {\r\n\t\t\tsizeOption = [sizeOption, sizeOption];\r\n\t\t}\r\n\r\n\t\tvar size = point(sizeOption),\r\n\t\t anchor = point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||\r\n\t\t size && size.divideBy(2, true));\r\n\r\n\t\timg.className = 'leaflet-marker-' + name + ' ' + (options.className || '');\r\n\r\n\t\tif (anchor) {\r\n\t\t\timg.style.marginLeft = (-anchor.x) + 'px';\r\n\t\t\timg.style.marginTop = (-anchor.y) + 'px';\r\n\t\t}\r\n\r\n\t\tif (size) {\r\n\t\t\timg.style.width = size.x + 'px';\r\n\t\t\timg.style.height = size.y + 'px';\r\n\t\t}\r\n\t},\r\n\r\n\t_createImg: function (src, el) {\r\n\t\tel = el || document.createElement('img');\r\n\t\tel.src = src;\r\n\t\treturn el;\r\n\t},\r\n\r\n\t_getIconUrl: function (name) {\r\n\t\treturn Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.icon(options: Icon options)\r\n// Creates an icon instance with the given options.\r\nexport function icon(options) {\r\n\treturn new Icon(options);\r\n}\r\n","import {Icon} from './Icon';\nimport * as DomUtil from '../../dom/DomUtil';\n\n/*\n * @miniclass Icon.Default (Icon)\n * @aka L.Icon.Default\n * @section\n *\n * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when\n * no icon is specified. Points to the blue marker image distributed with Leaflet\n * releases.\n *\n * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`\n * (which is a set of `Icon options`).\n *\n * If you want to _completely_ replace the default icon, override the\n * `L.Marker.prototype.options.icon` with your own icon instead.\n */\n\nexport var IconDefault = Icon.extend({\n\n\toptions: {\n\t\ticonUrl: 'marker-icon.png',\n\t\ticonRetinaUrl: 'marker-icon-2x.png',\n\t\tshadowUrl: 'marker-shadow.png',\n\t\ticonSize: [25, 41],\n\t\ticonAnchor: [12, 41],\n\t\tpopupAnchor: [1, -34],\n\t\ttooltipAnchor: [16, -28],\n\t\tshadowSize: [41, 41]\n\t},\n\n\t_getIconUrl: function (name) {\n\t\tif (typeof IconDefault.imagePath !== 'string') {\t// Deprecated, backwards-compatibility only\n\t\t\tIconDefault.imagePath = this._detectIconPath();\n\t\t}\n\n\t\t// @option imagePath: String\n\t\t// `Icon.Default` will try to auto-detect the location of the\n\t\t// blue icon images. If you are placing these images in a non-standard\n\t\t// way, set this option to point to the right path.\n\t\treturn (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);\n\t},\n\n\t_stripUrl: function (path) {\t// separate function to use in tests\n\t\tvar strip = function (str, re, idx) {\n\t\t\tvar match = re.exec(str);\n\t\t\treturn match && match[idx];\n\t\t};\n\t\tpath = strip(path, /^url\\((['\"])?(.+)\\1\\)$/, 2);\n\t\treturn path && strip(path, /^(.*)marker-icon\\.png$/, 1);\n\t},\n\n\t_detectIconPath: function () {\n\t\tvar el = DomUtil.create('div', 'leaflet-default-icon-path', document.body);\n\t\tvar path = DomUtil.getStyle(el, 'background-image') ||\n\t\t DomUtil.getStyle(el, 'backgroundImage');\t// IE8\n\n\t\tdocument.body.removeChild(el);\n\t\tpath = this._stripUrl(path);\n\t\tif (path) { return path; }\n\t\tvar link = document.querySelector('link[href$=\"leaflet.css\"]');\n\t\tif (!link) { return ''; }\n\t\treturn link.href.substring(0, link.href.length - 'leaflet.css'.length - 1);\n\t}\n});\n","import {Handler} from '../../core/Handler';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {Draggable} from '../../dom/Draggable';\nimport {toBounds} from '../../geometry/Bounds';\nimport {toPoint} from '../../geometry/Point';\nimport {requestAnimFrame, cancelAnimFrame} from '../../core/Util';\n\n/*\n * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.\n */\n\n\n/* @namespace Marker\n * @section Interaction handlers\n *\n * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:\n *\n * ```js\n * marker.dragging.disable();\n * ```\n *\n * @property dragging: Handler\n * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).\n */\n\nexport var MarkerDrag = Handler.extend({\n\tinitialize: function (marker) {\n\t\tthis._marker = marker;\n\t},\n\n\taddHooks: function () {\n\t\tvar icon = this._marker._icon;\n\n\t\tif (!this._draggable) {\n\t\t\tthis._draggable = new Draggable(icon, icon, true);\n\t\t}\n\n\t\tthis._draggable.on({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).enable();\n\n\t\tDomUtil.addClass(icon, 'leaflet-marker-draggable');\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._draggable.off({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).disable();\n\n\t\tif (this._marker._icon) {\n\t\t\tDomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');\n\t\t}\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\t_adjustPan: function (e) {\n\t\tvar marker = this._marker,\n\t\t map = marker._map,\n\t\t speed = this._marker.options.autoPanSpeed,\n\t\t padding = this._marker.options.autoPanPadding,\n\t\t iconPos = DomUtil.getPosition(marker._icon),\n\t\t bounds = map.getPixelBounds(),\n\t\t origin = map.getPixelOrigin();\n\n\t\tvar panBounds = toBounds(\n\t\t\tbounds.min._subtract(origin).add(padding),\n\t\t\tbounds.max._subtract(origin).subtract(padding)\n\t\t);\n\n\t\tif (!panBounds.contains(iconPos)) {\n\t\t\t// Compute incremental movement\n\t\t\tvar movement = toPoint(\n\t\t\t\t(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -\n\t\t\t\t(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),\n\n\t\t\t\t(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -\n\t\t\t\t(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)\n\t\t\t).multiplyBy(speed);\n\n\t\t\tmap.panBy(movement, {animate: false});\n\n\t\t\tthis._draggable._newPos._add(movement);\n\t\t\tthis._draggable._startPos._add(movement);\n\n\t\t\tDomUtil.setPosition(marker._icon, this._draggable._newPos);\n\t\t\tthis._onDrag(e);\n\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDragStart: function () {\n\t\t// @section Dragging events\n\t\t// @event dragstart: Event\n\t\t// Fired when the user starts dragging the marker.\n\n\t\t// @event movestart: Event\n\t\t// Fired when the marker starts moving (because of dragging).\n\n\t\tthis._oldLatLng = this._marker.getLatLng();\n\n\t\t// When using ES6 imports it could not be set when `Popup` was not imported as well\n\t\tthis._marker.closePopup && this._marker.closePopup();\n\n\t\tthis._marker\n\t\t\t.fire('movestart')\n\t\t\t.fire('dragstart');\n\t},\n\n\t_onPreDrag: function (e) {\n\t\tif (this._marker.options.autoPan) {\n\t\t\tcancelAnimFrame(this._panRequest);\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tvar marker = this._marker,\n\t\t shadow = marker._shadow,\n\t\t iconPos = DomUtil.getPosition(marker._icon),\n\t\t latlng = marker._map.layerPointToLatLng(iconPos);\n\n\t\t// update shadow position\n\t\tif (shadow) {\n\t\t\tDomUtil.setPosition(shadow, iconPos);\n\t\t}\n\n\t\tmarker._latlng = latlng;\n\t\te.latlng = latlng;\n\t\te.oldLatLng = this._oldLatLng;\n\n\t\t// @event drag: Event\n\t\t// Fired repeatedly while the user drags the marker.\n\t\tmarker\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_onDragEnd: function (e) {\n\t\t// @event dragend: DragEndEvent\n\t\t// Fired when the user stops dragging the marker.\n\n\t\t cancelAnimFrame(this._panRequest);\n\n\t\t// @event moveend: Event\n\t\t// Fired when the marker stops moving (because of dragging).\n\t\tdelete this._oldLatLng;\n\t\tthis._marker\n\t\t .fire('moveend')\n\t\t .fire('dragend', e);\n\t}\n});\n","import {Layer} from '../Layer';\r\nimport {IconDefault} from './Icon.Default';\r\nimport * as Util from '../../core/Util';\r\nimport {toLatLng as latLng} from '../../geo/LatLng';\r\nimport {toPoint as point} from '../../geometry/Point';\r\nimport * as DomUtil from '../../dom/DomUtil';\r\nimport * as DomEvent from '../../dom/DomEvent';\r\nimport {MarkerDrag} from './Marker.Drag';\r\n\r\n/*\r\n * @class Marker\r\n * @inherits Interactive layer\r\n * @aka L.Marker\r\n * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.marker([50.5, 30.5]).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var Marker = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka Marker options\r\n\toptions: {\r\n\t\t// @option icon: Icon = *\r\n\t\t// Icon instance to use for rendering the marker.\r\n\t\t// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.\r\n\t\t// If not specified, a common instance of `L.Icon.Default` is used.\r\n\t\ticon: new IconDefault(),\r\n\r\n\t\t// Option inherited from \"Interactive layer\" abstract class\r\n\t\tinteractive: true,\r\n\r\n\t\t// @option keyboard: Boolean = true\r\n\t\t// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.\r\n\t\tkeyboard: true,\r\n\r\n\t\t// @option title: String = ''\r\n\t\t// Text for the browser tooltip that appear on marker hover (no tooltip by default).\r\n\t\t// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).\r\n\t\ttitle: '',\r\n\r\n\t\t// @option alt: String = 'Marker'\r\n\t\t// Text for the `alt` attribute of the icon image.\r\n\t\t// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).\r\n\t\talt: 'Marker',\r\n\r\n\t\t// @option zIndexOffset: Number = 0\r\n\t\t// By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).\r\n\t\tzIndexOffset: 0,\r\n\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the marker.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option riseOnHover: Boolean = false\r\n\t\t// If `true`, the marker will get on top of others when you hover the mouse over it.\r\n\t\triseOnHover: false,\r\n\r\n\t\t// @option riseOffset: Number = 250\r\n\t\t// The z-index offset used for the `riseOnHover` feature.\r\n\t\triseOffset: 250,\r\n\r\n\t\t// @option pane: String = 'markerPane'\r\n\t\t// `Map pane` where the markers icon will be added.\r\n\t\tpane: 'markerPane',\r\n\r\n\t\t// @option shadowPane: String = 'shadowPane'\r\n\t\t// `Map pane` where the markers shadow will be added.\r\n\t\tshadowPane: 'shadowPane',\r\n\r\n\t\t// @option bubblingMouseEvents: Boolean = false\r\n\t\t// When `true`, a mouse event on this marker will trigger the same event on the map\r\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\r\n\t\tbubblingMouseEvents: false,\r\n\r\n\t\t// @option autoPanOnFocus: Boolean = true\r\n\t\t// When `true`, the map will pan whenever the marker is focused (via\r\n\t\t// e.g. pressing `tab` on the keyboard) to ensure the marker is\r\n\t\t// visible within the map's bounds\r\n\t\tautoPanOnFocus: true,\r\n\r\n\t\t// @section Draggable marker options\r\n\t\t// @option draggable: Boolean = false\r\n\t\t// Whether the marker is draggable with mouse/touch or not.\r\n\t\tdraggable: false,\r\n\r\n\t\t// @option autoPan: Boolean = false\r\n\t\t// Whether to pan the map when dragging this marker near its edge or not.\r\n\t\tautoPan: false,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(50, 50)\r\n\t\t// Distance (in pixels to the left/right and to the top/bottom) of the\r\n\t\t// map edge to start panning the map.\r\n\t\tautoPanPadding: [50, 50],\r\n\r\n\t\t// @option autoPanSpeed: Number = 10\r\n\t\t// Number of pixels the map should pan by.\r\n\t\tautoPanSpeed: 10\r\n\t},\r\n\r\n\t/* @section\r\n\t *\r\n\t * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:\r\n\t */\r\n\r\n\tinitialize: function (latlng, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\t\tthis._latlng = latLng(latlng);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.on('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._initIcon();\r\n\t\tthis.update();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (this.dragging && this.dragging.enabled()) {\r\n\t\t\tthis.options.draggable = true;\r\n\t\t\tthis.dragging.removeHooks();\r\n\t\t}\r\n\t\tdelete this.dragging;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.off('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._removeIcon();\r\n\t\tthis._removeShadow();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\treturn {\r\n\t\t\tzoom: this.update,\r\n\t\t\tviewreset: this.update\r\n\t\t};\r\n\t},\r\n\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the current geographical position of the marker.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Changes the marker position to the given point.\r\n\tsetLatLng: function (latlng) {\r\n\t\tvar oldLatLng = this._latlng;\r\n\t\tthis._latlng = latLng(latlng);\r\n\t\tthis.update();\r\n\r\n\t\t// @event move: Event\r\n\t\t// Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.\r\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\r\n\t},\r\n\r\n\t// @method setZIndexOffset(offset: Number): this\r\n\t// Changes the [zIndex offset](#marker-zindexoffset) of the marker.\r\n\tsetZIndexOffset: function (offset) {\r\n\t\tthis.options.zIndexOffset = offset;\r\n\t\treturn this.update();\r\n\t},\r\n\r\n\t// @method getIcon: Icon\r\n\t// Returns the current icon used by the marker\r\n\tgetIcon: function () {\r\n\t\treturn this.options.icon;\r\n\t},\r\n\r\n\t// @method setIcon(icon: Icon): this\r\n\t// Changes the marker icon.\r\n\tsetIcon: function (icon) {\r\n\r\n\t\tthis.options.icon = icon;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._initIcon();\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\tif (this._popup) {\r\n\t\t\tthis.bindPopup(this._popup, this._popup.options);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetElement: function () {\r\n\t\treturn this._icon;\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tif (this._icon && this._map) {\r\n\t\t\tvar pos = this._map.latLngToLayerPoint(this._latlng).round();\r\n\t\t\tthis._setPos(pos);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initIcon: function () {\r\n\t\tvar options = this.options,\r\n\t\t classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\r\n\r\n\t\tvar icon = options.icon.createIcon(this._icon),\r\n\t\t addIcon = false;\r\n\r\n\t\t// if we're not reusing the icon, remove the old one and init new one\r\n\t\tif (icon !== this._icon) {\r\n\t\t\tif (this._icon) {\r\n\t\t\t\tthis._removeIcon();\r\n\t\t\t}\r\n\t\t\taddIcon = true;\r\n\r\n\t\t\tif (options.title) {\r\n\t\t\t\ticon.title = options.title;\r\n\t\t\t}\r\n\r\n\t\t\tif (icon.tagName === 'IMG') {\r\n\t\t\t\ticon.alt = options.alt || '';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tDomUtil.addClass(icon, classToAdd);\r\n\r\n\t\tif (options.keyboard) {\r\n\t\t\ticon.tabIndex = '0';\r\n\t\t\ticon.setAttribute('role', 'button');\r\n\t\t}\r\n\r\n\t\tthis._icon = icon;\r\n\r\n\t\tif (options.riseOnHover) {\r\n\t\t\tthis.on({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.options.autoPanOnFocus) {\r\n\t\t\tDomEvent.on(icon, 'focus', this._panOnFocus, this);\r\n\t\t}\r\n\r\n\t\tvar newShadow = options.icon.createShadow(this._shadow),\r\n\t\t addShadow = false;\r\n\r\n\t\tif (newShadow !== this._shadow) {\r\n\t\t\tthis._removeShadow();\r\n\t\t\taddShadow = true;\r\n\t\t}\r\n\r\n\t\tif (newShadow) {\r\n\t\t\tDomUtil.addClass(newShadow, classToAdd);\r\n\t\t\tnewShadow.alt = '';\r\n\t\t}\r\n\t\tthis._shadow = newShadow;\r\n\r\n\r\n\t\tif (options.opacity < 1) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\r\n\t\tif (addIcon) {\r\n\t\t\tthis.getPane().appendChild(this._icon);\r\n\t\t}\r\n\t\tthis._initInteraction();\r\n\t\tif (newShadow && addShadow) {\r\n\t\t\tthis.getPane(options.shadowPane).appendChild(this._shadow);\r\n\t\t}\r\n\t},\r\n\r\n\t_removeIcon: function () {\r\n\t\tif (this.options.riseOnHover) {\r\n\t\t\tthis.off({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tif (this.options.autoPanOnFocus) {\r\n\t\t\tDomEvent.off(this._icon, 'focus', this._panOnFocus, this);\r\n\t\t}\r\n\r\n\t\tDomUtil.remove(this._icon);\r\n\t\tthis.removeInteractiveTarget(this._icon);\r\n\r\n\t\tthis._icon = null;\r\n\t},\r\n\r\n\t_removeShadow: function () {\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.remove(this._shadow);\r\n\t\t}\r\n\t\tthis._shadow = null;\r\n\t},\r\n\r\n\t_setPos: function (pos) {\r\n\r\n\t\tif (this._icon) {\r\n\t\t\tDomUtil.setPosition(this._icon, pos);\r\n\t\t}\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.setPosition(this._shadow, pos);\r\n\t\t}\r\n\r\n\t\tthis._zIndex = pos.y + this.options.zIndexOffset;\r\n\r\n\t\tthis._resetZIndex();\r\n\t},\r\n\r\n\t_updateZIndex: function (offset) {\r\n\t\tif (this._icon) {\r\n\t\t\tthis._icon.style.zIndex = this._zIndex + offset;\r\n\t\t}\r\n\t},\r\n\r\n\t_animateZoom: function (opt) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();\r\n\r\n\t\tthis._setPos(pos);\r\n\t},\r\n\r\n\t_initInteraction: function () {\r\n\r\n\t\tif (!this.options.interactive) { return; }\r\n\r\n\t\tDomUtil.addClass(this._icon, 'leaflet-interactive');\r\n\r\n\t\tthis.addInteractiveTarget(this._icon);\r\n\r\n\t\tif (MarkerDrag) {\r\n\t\t\tvar draggable = this.options.draggable;\r\n\t\t\tif (this.dragging) {\r\n\t\t\t\tdraggable = this.dragging.enabled();\r\n\t\t\t\tthis.dragging.disable();\r\n\t\t\t}\r\n\r\n\t\t\tthis.dragging = new MarkerDrag(this);\r\n\r\n\t\t\tif (draggable) {\r\n\t\t\t\tthis.dragging.enable();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Changes the opacity of the marker.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\t\tif (this._map) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tvar opacity = this.options.opacity;\r\n\r\n\t\tif (this._icon) {\r\n\t\t\tDomUtil.setOpacity(this._icon, opacity);\r\n\t\t}\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tDomUtil.setOpacity(this._shadow, opacity);\r\n\t\t}\r\n\t},\r\n\r\n\t_bringToFront: function () {\r\n\t\tthis._updateZIndex(this.options.riseOffset);\r\n\t},\r\n\r\n\t_resetZIndex: function () {\r\n\t\tthis._updateZIndex(0);\r\n\t},\r\n\r\n\t_panOnFocus: function () {\r\n\t\tvar map = this._map;\r\n\t\tif (!map) { return; }\r\n\r\n\t\tvar iconOpts = this.options.icon.options;\r\n\t\tvar size = iconOpts.iconSize ? point(iconOpts.iconSize) : point(0, 0);\r\n\t\tvar anchor = iconOpts.iconAnchor ? point(iconOpts.iconAnchor) : point(0, 0);\r\n\r\n\t\tmap.panInside(this._latlng, {\r\n\t\t\tpaddingTopLeft: anchor,\r\n\t\t\tpaddingBottomRight: size.subtract(anchor)\r\n\t\t});\r\n\t},\r\n\r\n\t_getPopupAnchor: function () {\r\n\t\treturn this.options.icon.options.popupAnchor;\r\n\t},\r\n\r\n\t_getTooltipAnchor: function () {\r\n\t\treturn this.options.icon.options.tooltipAnchor;\r\n\t}\r\n});\r\n\r\n\r\n// factory L.marker(latlng: LatLng, options? : Marker options)\r\n\r\n// @factory L.marker(latlng: LatLng, options? : Marker options)\r\n// Instantiates a Marker object given a geographical point and optionally an options object.\r\nexport function marker(latlng, options) {\r\n\treturn new Marker(latlng, options);\r\n}\r\n","import {Layer} from '../Layer';\nimport * as Util from '../../core/Util';\n\n/*\n * @class Path\n * @aka L.Path\n * @inherits Interactive layer\n *\n * An abstract class that contains options and constants shared between vector\n * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.\n */\n\nexport var Path = Layer.extend({\n\n\t// @section\n\t// @aka Path options\n\toptions: {\n\t\t// @option stroke: Boolean = true\n\t\t// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.\n\t\tstroke: true,\n\n\t\t// @option color: String = '#3388ff'\n\t\t// Stroke color\n\t\tcolor: '#3388ff',\n\n\t\t// @option weight: Number = 3\n\t\t// Stroke width in pixels\n\t\tweight: 3,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Stroke opacity\n\t\topacity: 1,\n\n\t\t// @option lineCap: String= 'round'\n\t\t// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.\n\t\tlineCap: 'round',\n\n\t\t// @option lineJoin: String = 'round'\n\t\t// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.\n\t\tlineJoin: 'round',\n\n\t\t// @option dashArray: String = null\n\t\t// A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashArray: null,\n\n\t\t// @option dashOffset: String = null\n\t\t// A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashOffset: null,\n\n\t\t// @option fill: Boolean = depends\n\t\t// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.\n\t\tfill: false,\n\n\t\t// @option fillColor: String = *\n\t\t// Fill color. Defaults to the value of the [`color`](#path-color) option\n\t\tfillColor: null,\n\n\t\t// @option fillOpacity: Number = 0.2\n\t\t// Fill opacity.\n\t\tfillOpacity: 0.2,\n\n\t\t// @option fillRule: String = 'evenodd'\n\t\t// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.\n\t\tfillRule: 'evenodd',\n\n\t\t// className: '',\n\n\t\t// Option inherited from \"Interactive layer\" abstract class\n\t\tinteractive: true,\n\n\t\t// @option bubblingMouseEvents: Boolean = true\n\t\t// When `true`, a mouse event on this path will trigger the same event on the map\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\n\t\tbubblingMouseEvents: true\n\t},\n\n\tbeforeAdd: function (map) {\n\t\t// Renderer is set here because we need to call renderer.getEvents\n\t\t// before this.getEvents.\n\t\tthis._renderer = map.getRenderer(this);\n\t},\n\n\tonAdd: function () {\n\t\tthis._renderer._initPath(this);\n\t\tthis._reset();\n\t\tthis._renderer._addPath(this);\n\t},\n\n\tonRemove: function () {\n\t\tthis._renderer._removePath(this);\n\t},\n\n\t// @method redraw(): this\n\t// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._renderer._updatePath(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method setStyle(style: Path options): this\n\t// Changes the appearance of a Path based on the options in the `Path options` object.\n\tsetStyle: function (style) {\n\t\tUtil.setOptions(this, style);\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._updateStyle(this);\n\t\t\tif (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) {\n\t\t\t\tthis._updateBounds();\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToFront(): this\n\t// Brings the layer to the top of all path layers.\n\tbringToFront: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToFront(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack(): this\n\t// Brings the layer to the bottom of all path layers.\n\tbringToBack: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToBack(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetElement: function () {\n\t\treturn this._path;\n\t},\n\n\t_reset: function () {\n\t\t// defined in child classes\n\t\tthis._project();\n\t\tthis._update();\n\t},\n\n\t_clickTolerance: function () {\n\t\t// used when doing hit detection for Canvas layers\n\t\treturn (this.options.stroke ? this.options.weight / 2 : 0) +\n\t\t (this._renderer.options.tolerance || 0);\n\t}\n});\n","import {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport {toLatLng} from '../../geo/LatLng';\nimport {Bounds} from '../../geometry/Bounds';\n\n\n/*\n * @class CircleMarker\n * @aka L.CircleMarker\n * @inherits Path\n *\n * A circle of a fixed size with radius specified in pixels. Extends `Path`.\n */\n\nexport var CircleMarker = Path.extend({\n\n\t// @section\n\t// @aka CircleMarker options\n\toptions: {\n\t\tfill: true,\n\n\t\t// @option radius: Number = 10\n\t\t// Radius of the circle marker, in pixels\n\t\tradius: 10\n\t},\n\n\tinitialize: function (latlng, options) {\n\t\tUtil.setOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis._radius = this.options.radius;\n\t},\n\n\t// @method setLatLng(latLng: LatLng): this\n\t// Sets the position of a circle marker to a new location.\n\tsetLatLng: function (latlng) {\n\t\tvar oldLatLng = this._latlng;\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis.redraw();\n\n\t\t// @event move: Event\n\t\t// Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\n\t},\n\n\t// @method getLatLng(): LatLng\n\t// Returns the current geographical position of the circle marker\n\tgetLatLng: function () {\n\t\treturn this._latlng;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle marker. Units are in pixels.\n\tsetRadius: function (radius) {\n\t\tthis.options.radius = this._radius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of the circle\n\tgetRadius: function () {\n\t\treturn this._radius;\n\t},\n\n\tsetStyle : function (options) {\n\t\tvar radius = options && options.radius || this._radius;\n\t\tPath.prototype.setStyle.call(this, options);\n\t\tthis.setRadius(radius);\n\t\treturn this;\n\t},\n\n\t_project: function () {\n\t\tthis._point = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._updateBounds();\n\t},\n\n\t_updateBounds: function () {\n\t\tvar r = this._radius,\n\t\t r2 = this._radiusY || r,\n\t\t w = this._clickTolerance(),\n\t\t p = [r + w, r2 + w];\n\t\tthis._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));\n\t},\n\n\t_update: function () {\n\t\tif (this._map) {\n\t\t\tthis._updatePath();\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updateCircle(this);\n\t},\n\n\t_empty: function () {\n\t\treturn this._radius && !this._renderer._bounds.intersects(this._pxBounds);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\treturn p.distanceTo(this._point) <= this._radius + this._clickTolerance();\n\t}\n});\n\n\n// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)\n// Instantiates a circle marker object given a geographical point, and an optional options object.\nexport function circleMarker(latlng, options) {\n\treturn new CircleMarker(latlng, options);\n}\n","import {CircleMarker} from './CircleMarker';\nimport {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport {toLatLng} from '../../geo/LatLng';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Earth} from '../../geo/crs/CRS.Earth';\n\n\n/*\n * @class Circle\n * @aka L.Circle\n * @inherits CircleMarker\n *\n * A class for drawing circle overlays on a map. Extends `CircleMarker`.\n *\n * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).\n *\n * @example\n *\n * ```js\n * L.circle([50.5, 30.5], {radius: 200}).addTo(map);\n * ```\n */\n\nexport var Circle = CircleMarker.extend({\n\n\tinitialize: function (latlng, options, legacyOptions) {\n\t\tif (typeof options === 'number') {\n\t\t\t// Backwards compatibility with 0.7.x factory (latlng, radius, options?)\n\t\t\toptions = Util.extend({}, legacyOptions, {radius: options});\n\t\t}\n\t\tUtil.setOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\n\t\tif (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }\n\n\t\t// @section\n\t\t// @aka Circle options\n\t\t// @option radius: Number; Radius of the circle, in meters.\n\t\tthis._mRadius = this.options.radius;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle. Units are in meters.\n\tsetRadius: function (radius) {\n\t\tthis._mRadius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of a circle. Units are in meters.\n\tgetRadius: function () {\n\t\treturn this._mRadius;\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\tvar half = [this._radius, this._radiusY || this._radius];\n\n\t\treturn new LatLngBounds(\n\t\t\tthis._map.layerPointToLatLng(this._point.subtract(half)),\n\t\t\tthis._map.layerPointToLatLng(this._point.add(half)));\n\t},\n\n\tsetStyle: Path.prototype.setStyle,\n\n\t_project: function () {\n\n\t\tvar lng = this._latlng.lng,\n\t\t lat = this._latlng.lat,\n\t\t map = this._map,\n\t\t crs = map.options.crs;\n\n\t\tif (crs.distance === Earth.distance) {\n\t\t\tvar d = Math.PI / 180,\n\t\t\t latR = (this._mRadius / Earth.R) / d,\n\t\t\t top = map.project([lat + latR, lng]),\n\t\t\t bottom = map.project([lat - latR, lng]),\n\t\t\t p = top.add(bottom).divideBy(2),\n\t\t\t lat2 = map.unproject(p).lat,\n\t\t\t lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /\n\t\t\t (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;\n\n\t\t\tif (isNaN(lngR) || lngR === 0) {\n\t\t\t\tlngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425\n\t\t\t}\n\n\t\t\tthis._point = p.subtract(map.getPixelOrigin());\n\t\t\tthis._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;\n\t\t\tthis._radiusY = p.y - top.y;\n\n\t\t} else {\n\t\t\tvar latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));\n\n\t\t\tthis._point = map.latLngToLayerPoint(this._latlng);\n\t\t\tthis._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;\n\t\t}\n\n\t\tthis._updateBounds();\n\t}\n});\n\n// @factory L.circle(latlng: LatLng, options?: Circle options)\n// Instantiates a circle object given a geographical point, and an options object\n// which contains the circle radius.\n// @alternative\n// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)\n// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.\n// Do not use in new applications or plugins.\nexport function circle(latlng, options, legacyOptions) {\n\treturn new Circle(latlng, options, legacyOptions);\n}\n","import {Path} from './Path';\nimport * as Util from '../../core/Util';\nimport * as LineUtil from '../../geometry/LineUtil';\nimport {LatLng, toLatLng} from '../../geo/LatLng';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Bounds} from '../../geometry/Bounds';\nimport {Point} from '../../geometry/Point';\n\n/*\n * @class Polyline\n * @aka L.Polyline\n * @inherits Path\n *\n * A class for drawing polyline overlays on a map. Extends `Path`.\n *\n * @example\n *\n * ```js\n * // create a red polyline from an array of LatLng points\n * var latlngs = [\n * \t[45.51, -122.68],\n * \t[37.77, -122.43],\n * \t[34.04, -118.2]\n * ];\n *\n * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polyline\n * map.fitBounds(polyline.getBounds());\n * ```\n *\n * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:\n *\n * ```js\n * // create a red polyline from an array of arrays of LatLng points\n * var latlngs = [\n * \t[[45.51, -122.68],\n * \t [37.77, -122.43],\n * \t [34.04, -118.2]],\n * \t[[40.78, -73.91],\n * \t [41.83, -87.62],\n * \t [32.76, -96.72]]\n * ];\n * ```\n */\n\n\nexport var Polyline = Path.extend({\n\n\t// @section\n\t// @aka Polyline options\n\toptions: {\n\t\t// @option smoothFactor: Number = 1.0\n\t\t// How much to simplify the polyline on each zoom level. More means\n\t\t// better performance and smoother look, and less means more accurate representation.\n\t\tsmoothFactor: 1.0,\n\n\t\t// @option noClip: Boolean = false\n\t\t// Disable polyline clipping.\n\t\tnoClip: false\n\t},\n\n\tinitialize: function (latlngs, options) {\n\t\tUtil.setOptions(this, options);\n\t\tthis._setLatLngs(latlngs);\n\t},\n\n\t// @method getLatLngs(): LatLng[]\n\t// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.\n\tgetLatLngs: function () {\n\t\treturn this._latlngs;\n\t},\n\n\t// @method setLatLngs(latlngs: LatLng[]): this\n\t// Replaces all the points in the polyline with the given array of geographical points.\n\tsetLatLngs: function (latlngs) {\n\t\tthis._setLatLngs(latlngs);\n\t\treturn this.redraw();\n\t},\n\n\t// @method isEmpty(): Boolean\n\t// Returns `true` if the Polyline has no LatLngs.\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length;\n\t},\n\n\t// @method closestLayerPoint(p: Point): Point\n\t// Returns the point closest to `p` on the Polyline.\n\tclosestLayerPoint: function (p) {\n\t\tvar minDistance = Infinity,\n\t\t minPoint = null,\n\t\t closest = LineUtil._sqClosestPointOnSegment,\n\t\t p1, p2;\n\n\t\tfor (var j = 0, jLen = this._parts.length; j < jLen; j++) {\n\t\t\tvar points = this._parts[j];\n\n\t\t\tfor (var i = 1, len = points.length; i < len; i++) {\n\t\t\t\tp1 = points[i - 1];\n\t\t\t\tp2 = points[i];\n\n\t\t\t\tvar sqDist = closest(p, p1, p2, true);\n\n\t\t\t\tif (sqDist < minDistance) {\n\t\t\t\t\tminDistance = sqDist;\n\t\t\t\t\tminPoint = closest(p, p1, p2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (minPoint) {\n\t\t\tminPoint.distance = Math.sqrt(minDistance);\n\t\t}\n\t\treturn minPoint;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\t\treturn LineUtil.polylineCenter(this._defaultShape(), this._map.options.crs);\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\treturn this._bounds;\n\t},\n\n\t// @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this\n\t// Adds a given point to the polyline. By default, adds to the first ring of\n\t// the polyline in case of a multi-polyline, but can be overridden by passing\n\t// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).\n\taddLatLng: function (latlng, latlngs) {\n\t\tlatlngs = latlngs || this._defaultShape();\n\t\tlatlng = toLatLng(latlng);\n\t\tlatlngs.push(latlng);\n\t\tthis._bounds.extend(latlng);\n\t\treturn this.redraw();\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tthis._bounds = new LatLngBounds();\n\t\tthis._latlngs = this._convertLatLngs(latlngs);\n\t},\n\n\t_defaultShape: function () {\n\t\treturn LineUtil.isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];\n\t},\n\n\t// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = [],\n\t\t flat = LineUtil.isFlat(latlngs);\n\n\t\tfor (var i = 0, len = latlngs.length; i < len; i++) {\n\t\t\tif (flat) {\n\t\t\t\tresult[i] = toLatLng(latlngs[i]);\n\t\t\t\tthis._bounds.extend(result[i]);\n\t\t\t} else {\n\t\t\t\tresult[i] = this._convertLatLngs(latlngs[i]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t},\n\n\t_project: function () {\n\t\tvar pxBounds = new Bounds();\n\t\tthis._rings = [];\n\t\tthis._projectLatlngs(this._latlngs, this._rings, pxBounds);\n\n\t\tif (this._bounds.isValid() && pxBounds.isValid()) {\n\t\t\tthis._rawPxBounds = pxBounds;\n\t\t\tthis._updateBounds();\n\t\t}\n\t},\n\n\t_updateBounds: function () {\n\t\tvar w = this._clickTolerance(),\n\t\t p = new Point(w, w);\n\n\t\tif (!this._rawPxBounds) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._pxBounds = new Bounds([\n\t\t\tthis._rawPxBounds.min.subtract(p),\n\t\t\tthis._rawPxBounds.max.add(p)\n\t\t]);\n\t},\n\n\t// recursively turns latlngs into a set of rings with projected coordinates\n\t_projectLatlngs: function (latlngs, result, projectedBounds) {\n\t\tvar flat = latlngs[0] instanceof LatLng,\n\t\t len = latlngs.length,\n\t\t i, ring;\n\n\t\tif (flat) {\n\t\t\tring = [];\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tring[i] = this._map.latLngToLayerPoint(latlngs[i]);\n\t\t\t\tprojectedBounds.extend(ring[i]);\n\t\t\t}\n\t\t\tresult.push(ring);\n\t\t} else {\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tthis._projectLatlngs(latlngs[i], result, projectedBounds);\n\t\t\t}\n\t\t}\n\t},\n\n\t// clip polyline by renderer bounds so that we have less to render for performance\n\t_clipPoints: function () {\n\t\tvar bounds = this._renderer._bounds;\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tvar parts = this._parts,\n\t\t i, j, k, len, len2, segment, points;\n\n\t\tfor (i = 0, k = 0, len = this._rings.length; i < len; i++) {\n\t\t\tpoints = this._rings[i];\n\n\t\t\tfor (j = 0, len2 = points.length; j < len2 - 1; j++) {\n\t\t\t\tsegment = LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);\n\n\t\t\t\tif (!segment) { continue; }\n\n\t\t\t\tparts[k] = parts[k] || [];\n\t\t\t\tparts[k].push(segment[0]);\n\n\t\t\t\t// if segment goes out of screen, or it's the last one, it's the end of the line part\n\t\t\t\tif ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {\n\t\t\t\t\tparts[k].push(segment[1]);\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// simplify each clipped part of the polyline for performance\n\t_simplifyPoints: function () {\n\t\tvar parts = this._parts,\n\t\t tolerance = this.options.smoothFactor;\n\n\t\tfor (var i = 0, len = parts.length; i < len; i++) {\n\t\t\tparts[i] = LineUtil.simplify(parts[i], tolerance);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tif (!this._map) { return; }\n\n\t\tthis._clipPoints();\n\t\tthis._simplifyPoints();\n\t\tthis._updatePath();\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p, closed) {\n\t\tvar i, j, k, len, len2, part,\n\t\t w = this._clickTolerance();\n\n\t\tif (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }\n\n\t\t// hit detection for polylines\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tif (!closed && (j === 0)) { continue; }\n\n\t\t\t\tif (LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n});\n\n// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)\n// Instantiates a polyline object given an array of geographical points and\n// optionally an options object. You can create a `Polyline` object with\n// multiple separate lines (`MultiPolyline`) by passing an array of arrays\n// of geographic points.\nexport function polyline(latlngs, options) {\n\treturn new Polyline(latlngs, options);\n}\n\n// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.\nPolyline._flat = LineUtil._flat;\n","import {Polyline} from './Polyline';\nimport {LatLng} from '../../geo/LatLng';\nimport * as LineUtil from '../../geometry/LineUtil';\nimport {Point} from '../../geometry/Point';\nimport {Bounds} from '../../geometry/Bounds';\nimport * as PolyUtil from '../../geometry/PolyUtil';\n\n/*\n * @class Polygon\n * @aka L.Polygon\n * @inherits Polyline\n *\n * A class for drawing polygon overlays on a map. Extends `Polyline`.\n *\n * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.\n *\n *\n * @example\n *\n * ```js\n * // create a red polygon from an array of LatLng points\n * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];\n *\n * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polygon\n * map.fitBounds(polygon.getBounds());\n * ```\n *\n * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:\n *\n * ```js\n * var latlngs = [\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ];\n * ```\n *\n * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.\n *\n * ```js\n * var latlngs = [\n * [ // first polygon\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ],\n * [ // second polygon\n * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]\n * ]\n * ];\n * ```\n */\n\nexport var Polygon = Polyline.extend({\n\n\toptions: {\n\t\tfill: true\n\t},\n\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length || !this._latlngs[0].length;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\t\treturn PolyUtil.polygonCenter(this._defaultShape(), this._map.options.crs);\n\t},\n\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = Polyline.prototype._convertLatLngs.call(this, latlngs),\n\t\t len = result.length;\n\n\t\t// remove last point if it equals first one\n\t\tif (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {\n\t\t\tresult.pop();\n\t\t}\n\t\treturn result;\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tPolyline.prototype._setLatLngs.call(this, latlngs);\n\t\tif (LineUtil.isFlat(this._latlngs)) {\n\t\t\tthis._latlngs = [this._latlngs];\n\t\t}\n\t},\n\n\t_defaultShape: function () {\n\t\treturn LineUtil.isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];\n\t},\n\n\t_clipPoints: function () {\n\t\t// polygons need a different clipping algorithm so we redefine that\n\n\t\tvar bounds = this._renderer._bounds,\n\t\t w = this.options.weight,\n\t\t p = new Point(w, w);\n\n\t\t// increase clip padding by stroke width to avoid stroke on clip edges\n\t\tbounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tfor (var i = 0, len = this._rings.length, clipped; i < len; i++) {\n\t\t\tclipped = PolyUtil.clipPolygon(this._rings[i], bounds, true);\n\t\t\tif (clipped.length) {\n\t\t\t\tthis._parts.push(clipped);\n\t\t\t}\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this, true);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\tvar inside = false,\n\t\t part, p1, p2, i, j, k, len, len2;\n\n\t\tif (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }\n\n\t\t// ray casting algorithm for detecting if point is in polygon\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tp1 = part[j];\n\t\t\t\tp2 = part[k];\n\n\t\t\t\tif (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {\n\t\t\t\t\tinside = !inside;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// also check if it's on polygon stroke\n\t\treturn inside || Polyline.prototype._containsPoint.call(this, p, true);\n\t}\n\n});\n\n\n// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)\nexport function polygon(latlngs, options) {\n\treturn new Polygon(latlngs, options);\n}\n","import {LayerGroup} from './LayerGroup';\r\nimport {FeatureGroup} from './FeatureGroup';\r\nimport * as Util from '../core/Util';\r\nimport {Marker} from './marker/Marker';\r\nimport {Circle} from './vector/Circle';\r\nimport {CircleMarker} from './vector/CircleMarker';\r\nimport {Polyline} from './vector/Polyline';\r\nimport {Polygon} from './vector/Polygon';\r\nimport {LatLng} from '../geo/LatLng';\r\nimport * as LineUtil from '../geometry/LineUtil';\r\nimport {toLatLng} from '../geo/LatLng';\r\n\r\n\r\n/*\r\n * @class GeoJSON\r\n * @aka L.GeoJSON\r\n * @inherits FeatureGroup\r\n *\r\n * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse\r\n * GeoJSON data and display it on the map. Extends `FeatureGroup`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.geoJSON(data, {\r\n * \tstyle: function (feature) {\r\n * \t\treturn {color: feature.properties.color};\r\n * \t}\r\n * }).bindPopup(function (layer) {\r\n * \treturn layer.feature.properties.description;\r\n * }).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var GeoJSON = FeatureGroup.extend({\r\n\r\n\t/* @section\r\n\t * @aka GeoJSON options\r\n\t *\r\n\t * @option pointToLayer: Function = *\r\n\t * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally\r\n\t * called when data is added, passing the GeoJSON point feature and its `LatLng`.\r\n\t * The default is to spawn a default `Marker`:\r\n\t * ```js\r\n\t * function(geoJsonPoint, latlng) {\r\n\t * \treturn L.marker(latlng);\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option style: Function = *\r\n\t * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,\r\n\t * called internally when data is added.\r\n\t * The default value is to not override any defaults:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn {}\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option onEachFeature: Function = *\r\n\t * A `Function` that will be called once for each created `Feature`, after it has\r\n\t * been created and styled. Useful for attaching events and popups to features.\r\n\t * The default is to do nothing with the newly created layers:\r\n\t * ```js\r\n\t * function (feature, layer) {}\r\n\t * ```\r\n\t *\r\n\t * @option filter: Function = *\r\n\t * A `Function` that will be used to decide whether to include a feature or not.\r\n\t * The default is to include all features:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn true;\r\n\t * }\r\n\t * ```\r\n\t * Note: dynamically changing the `filter` option will have effect only on newly\r\n\t * added data. It will _not_ re-evaluate already included features.\r\n\t *\r\n\t * @option coordsToLatLng: Function = *\r\n\t * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.\r\n\t * The default is the `coordsToLatLng` static method.\r\n\t *\r\n\t * @option markersInheritOptions: Boolean = false\r\n\t * Whether default Markers for \"Point\" type Features inherit from group options.\r\n\t */\r\n\r\n\tinitialize: function (geojson, options) {\r\n\t\tUtil.setOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tif (geojson) {\r\n\t\t\tthis.addData(geojson);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addData( <GeoJSON> data ): this\r\n\t// Adds a GeoJSON object to the layer.\r\n\taddData: function (geojson) {\r\n\t\tvar features = Util.isArray(geojson) ? geojson : geojson.features,\r\n\t\t i, len, feature;\r\n\r\n\t\tif (features) {\r\n\t\t\tfor (i = 0, len = features.length; i < len; i++) {\r\n\t\t\t\t// only add this if geometry or geometries are set and not null\r\n\t\t\t\tfeature = features[i];\r\n\t\t\t\tif (feature.geometries || feature.geometry || feature.features || feature.coordinates) {\r\n\t\t\t\t\tthis.addData(feature);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar options = this.options;\r\n\r\n\t\tif (options.filter && !options.filter(geojson)) { return this; }\r\n\r\n\t\tvar layer = geometryToLayer(geojson, options);\r\n\t\tif (!layer) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tlayer.feature = asFeature(geojson);\r\n\r\n\t\tlayer.defaultOptions = layer.options;\r\n\t\tthis.resetStyle(layer);\r\n\r\n\t\tif (options.onEachFeature) {\r\n\t\t\toptions.onEachFeature(geojson, layer);\r\n\t\t}\r\n\r\n\t\treturn this.addLayer(layer);\r\n\t},\r\n\r\n\t// @method resetStyle( <Path> layer? ): this\r\n\t// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.\r\n\t// If `layer` is omitted, the style of all features in the current layer is reset.\r\n\tresetStyle: function (layer) {\r\n\t\tif (layer === undefined) {\r\n\t\t\treturn this.eachLayer(this.resetStyle, this);\r\n\t\t}\r\n\t\t// reset any custom styles\r\n\t\tlayer.options = Util.extend({}, layer.defaultOptions);\r\n\t\tthis._setLayerStyle(layer, this.options.style);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setStyle( <Function> style ): this\r\n\t// Changes styles of GeoJSON vector layers with the given style function.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.eachLayer(function (layer) {\r\n\t\t\tthis._setLayerStyle(layer, style);\r\n\t\t}, this);\r\n\t},\r\n\r\n\t_setLayerStyle: function (layer, style) {\r\n\t\tif (layer.setStyle) {\r\n\t\t\tif (typeof style === 'function') {\r\n\t\t\t\tstyle = style(layer.feature);\r\n\t\t\t}\r\n\t\t\tlayer.setStyle(style);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @section\r\n// There are several static functions which can be called without instantiating L.GeoJSON:\r\n\r\n// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer\r\n// Creates a `Layer` from a given GeoJSON feature. Can use a custom\r\n// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)\r\n// functions if provided as options.\r\nexport function geometryToLayer(geojson, options) {\r\n\r\n\tvar geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,\r\n\t coords = geometry ? geometry.coordinates : null,\r\n\t layers = [],\r\n\t pointToLayer = options && options.pointToLayer,\r\n\t _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,\r\n\t latlng, latlngs, i, len;\r\n\r\n\tif (!coords && !geometry) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tswitch (geometry.type) {\r\n\tcase 'Point':\r\n\t\tlatlng = _coordsToLatLng(coords);\r\n\t\treturn _pointToLayer(pointToLayer, geojson, latlng, options);\r\n\r\n\tcase 'MultiPoint':\r\n\t\tfor (i = 0, len = coords.length; i < len; i++) {\r\n\t\t\tlatlng = _coordsToLatLng(coords[i]);\r\n\t\t\tlayers.push(_pointToLayer(pointToLayer, geojson, latlng, options));\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tcase 'LineString':\r\n\tcase 'MultiLineString':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);\r\n\t\treturn new Polyline(latlngs, options);\r\n\r\n\tcase 'Polygon':\r\n\tcase 'MultiPolygon':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);\r\n\t\treturn new Polygon(latlngs, options);\r\n\r\n\tcase 'GeometryCollection':\r\n\t\tfor (i = 0, len = geometry.geometries.length; i < len; i++) {\r\n\t\t\tvar geoLayer = geometryToLayer({\r\n\t\t\t\tgeometry: geometry.geometries[i],\r\n\t\t\t\ttype: 'Feature',\r\n\t\t\t\tproperties: geojson.properties\r\n\t\t\t}, options);\r\n\r\n\t\t\tif (geoLayer) {\r\n\t\t\t\tlayers.push(geoLayer);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tcase 'FeatureCollection':\r\n\t\tfor (i = 0, len = geometry.features.length; i < len; i++) {\r\n\t\t\tvar featureLayer = geometryToLayer(geometry.features[i], options);\r\n\r\n\t\t\tif (featureLayer) {\r\n\t\t\t\tlayers.push(featureLayer);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tdefault:\r\n\t\tthrow new Error('Invalid GeoJSON object.');\r\n\t}\r\n}\r\n\r\nfunction _pointToLayer(pointToLayerFn, geojson, latlng, options) {\r\n\treturn pointToLayerFn ?\r\n\t\tpointToLayerFn(geojson, latlng) :\r\n\t\tnew Marker(latlng, options && options.markersInheritOptions && options);\r\n}\r\n\r\n// @function coordsToLatLng(coords: Array): LatLng\r\n// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)\r\n// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.\r\nexport function coordsToLatLng(coords) {\r\n\treturn new LatLng(coords[1], coords[0], coords[2]);\r\n}\r\n\r\n// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array\r\n// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.\r\n// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).\r\n// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.\r\nexport function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {\r\n\tvar latlngs = [];\r\n\r\n\tfor (var i = 0, len = coords.length, latlng; i < len; i++) {\r\n\t\tlatlng = levelsDeep ?\r\n\t\t\tcoordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :\r\n\t\t\t(_coordsToLatLng || coordsToLatLng)(coords[i]);\r\n\r\n\t\tlatlngs.push(latlng);\r\n\t}\r\n\r\n\treturn latlngs;\r\n}\r\n\r\n// @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array\r\n// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function.\r\nexport function latLngToCoords(latlng, precision) {\r\n\tlatlng = toLatLng(latlng);\r\n\treturn latlng.alt !== undefined ?\r\n\t\t[Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision), Util.formatNum(latlng.alt, precision)] :\r\n\t\t[Util.formatNum(latlng.lng, precision), Util.formatNum(latlng.lat, precision)];\r\n}\r\n\r\n// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array\r\n// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)\r\n// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function.\r\nexport function latLngsToCoords(latlngs, levelsDeep, closed, precision) {\r\n\tvar coords = [];\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\t// Check for flat arrays required to ensure unbalanced arrays are correctly converted in recursion\r\n\t\tcoords.push(levelsDeep ?\r\n\t\t\tlatLngsToCoords(latlngs[i], LineUtil.isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) :\r\n\t\t\tlatLngToCoords(latlngs[i], precision));\r\n\t}\r\n\r\n\tif (!levelsDeep && closed) {\r\n\t\tcoords.push(coords[0].slice());\r\n\t}\r\n\r\n\treturn coords;\r\n}\r\n\r\nexport function getFeature(layer, newGeometry) {\r\n\treturn layer.feature ?\r\n\t\tUtil.extend({}, layer.feature, {geometry: newGeometry}) :\r\n\t\tasFeature(newGeometry);\r\n}\r\n\r\n// @function asFeature(geojson: Object): Object\r\n// Normalize GeoJSON geometries/features into GeoJSON features.\r\nexport function asFeature(geojson) {\r\n\tif (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {\r\n\t\treturn geojson;\r\n\t}\r\n\r\n\treturn {\r\n\t\ttype: 'Feature',\r\n\t\tproperties: {},\r\n\t\tgeometry: geojson\r\n\t};\r\n}\r\n\r\nvar PointToGeoJSON = {\r\n\ttoGeoJSON: function (precision) {\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'Point',\r\n\t\t\tcoordinates: latLngToCoords(this.getLatLng(), precision)\r\n\t\t});\r\n\t}\r\n};\r\n\r\n// @namespace Marker\r\n// @section Other methods\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).\r\nMarker.include(PointToGeoJSON);\r\n\r\n// @namespace CircleMarker\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).\r\nCircle.include(PointToGeoJSON);\r\nCircleMarker.include(PointToGeoJSON);\r\n\r\n\r\n// @namespace Polyline\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).\r\nPolyline.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar multi = !LineUtil.isFlat(this._latlngs);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'LineString',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n// @namespace Polygon\r\n// @method toGeoJSON(precision?: Number|false): Object\r\n// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).\r\nPolygon.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar holes = !LineUtil.isFlat(this._latlngs),\r\n\t\t multi = holes && !LineUtil.isFlat(this._latlngs[0]);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);\r\n\r\n\t\tif (!holes) {\r\n\t\t\tcoords = [coords];\r\n\t\t}\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'Polygon',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n\r\n// @namespace LayerGroup\r\nLayerGroup.include({\r\n\ttoMultiPoint: function (precision) {\r\n\t\tvar coords = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tcoords.push(layer.toGeoJSON(precision).geometry.coordinates);\r\n\t\t});\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'MultiPoint',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t},\r\n\r\n\t// @method toGeoJSON(precision?: Number|false): Object\r\n\t// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.\r\n\t// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).\r\n\ttoGeoJSON: function (precision) {\r\n\r\n\t\tvar type = this.feature && this.feature.geometry && this.feature.geometry.type;\r\n\r\n\t\tif (type === 'MultiPoint') {\r\n\t\t\treturn this.toMultiPoint(precision);\r\n\t\t}\r\n\r\n\t\tvar isGeometryCollection = type === 'GeometryCollection',\r\n\t\t jsons = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tif (layer.toGeoJSON) {\r\n\t\t\t\tvar json = layer.toGeoJSON(precision);\r\n\t\t\t\tif (isGeometryCollection) {\r\n\t\t\t\t\tjsons.push(json.geometry);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvar feature = asFeature(json);\r\n\t\t\t\t\t// Squash nested feature collections\r\n\t\t\t\t\tif (feature.type === 'FeatureCollection') {\r\n\t\t\t\t\t\tjsons.push.apply(jsons, feature.features);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tjsons.push(feature);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (isGeometryCollection) {\r\n\t\t\treturn getFeature(this, {\r\n\t\t\t\tgeometries: jsons,\r\n\t\t\t\ttype: 'GeometryCollection'\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'FeatureCollection',\r\n\t\t\tfeatures: jsons\r\n\t\t};\r\n\t}\r\n});\r\n\r\n// @namespace GeoJSON\r\n// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)\r\n// Creates a GeoJSON layer. Optionally accepts an object in\r\n// [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map\r\n// (you can alternatively add it later with `addData` method) and an `options` object.\r\nexport function geoJSON(geojson, options) {\r\n\treturn new GeoJSON(geojson, options);\r\n}\r\n\r\n// Backward compatibility.\r\nexport var geoJson = geoJSON;\r\n","import {Layer} from './Layer';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLngBounds} from '../geo/LatLngBounds';\r\nimport {Bounds} from '../geometry/Bounds';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class ImageOverlay\r\n * @aka L.ImageOverlay\r\n * @inherits Interactive layer\r\n *\r\n * Used to load and display a single image over specific bounds of the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\r\n * \timageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\r\n * L.imageOverlay(imageUrl, imageBounds).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var ImageOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka ImageOverlay options\r\n\toptions: {\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the image overlay.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the image.\r\n\t\t// If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false,\r\n\r\n\t\t// @option errorOverlayUrl: String = ''\r\n\t\t// URL to the overlay image to show in place of the overlay that failed to load.\r\n\t\terrorOverlayUrl: '',\r\n\r\n\t\t// @option zIndex: Number = 1\r\n\t\t// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.\r\n\t\tzIndex: 1,\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom class name to assign to the image. Empty by default.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\tinitialize: function (url, bounds, options) { // (String, LatLngBounds, Object)\r\n\t\tthis._url = url;\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tUtil.setOptions(this, options);\r\n\t},\r\n\r\n\tonAdd: function () {\r\n\t\tif (!this._image) {\r\n\t\t\tthis._initImage();\r\n\r\n\t\t\tif (this.options.opacity < 1) {\r\n\t\t\t\tthis._updateOpacity();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.addClass(this._image, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._image);\r\n\t\t}\r\n\r\n\t\tthis.getPane().appendChild(this._image);\r\n\t\tthis._reset();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tDomUtil.remove(this._image);\r\n\t\tif (this.options.interactive) {\r\n\t\t\tthis.removeInteractiveTarget(this._image);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Sets the opacity of the overlay.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetStyle: function (styleOpts) {\r\n\t\tif (styleOpts.opacity) {\r\n\t\t\tthis.setOpacity(styleOpts.opacity);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer to the top of all overlays.\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toFront(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer to the bottom of all overlays.\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toBack(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setUrl(url: String): this\r\n\t// Changes the URL of the image.\r\n\tsetUrl: function (url) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._image.src = url;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setBounds(bounds: LatLngBounds): this\r\n\t// Update the bounds that this ImageOverlay covers\r\n\tsetBounds: function (bounds) {\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._reset();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._reset,\r\n\t\t\tviewreset: this._reset\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method setZIndex(value: Number): this\r\n\t// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.\r\n\tsetZIndex: function (value) {\r\n\t\tthis.options.zIndex = value;\r\n\t\tthis._updateZIndex();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Get the bounds that this ImageOverlay covers\r\n\tgetBounds: function () {\r\n\t\treturn this._bounds;\r\n\t},\r\n\r\n\t// @method getElement(): HTMLElement\r\n\t// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)\r\n\t// used by this overlay.\r\n\tgetElement: function () {\r\n\t\treturn this._image;\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'IMG';\r\n\t\tvar img = this._image = wasElementSupplied ? this._url : DomUtil.create('img');\r\n\r\n\t\tDomUtil.addClass(img, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { DomUtil.addClass(img, 'leaflet-zoom-animated'); }\r\n\t\tif (this.options.className) { DomUtil.addClass(img, this.options.className); }\r\n\r\n\t\timg.onselectstart = Util.falseFn;\r\n\t\timg.onmousemove = Util.falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the ImageOverlay layer has loaded its image\r\n\t\timg.onload = Util.bind(this.fire, this, 'load');\r\n\t\timg.onerror = Util.bind(this._overlayOnError, this, 'error');\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\timg.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\tif (this.options.zIndex) {\r\n\t\t\tthis._updateZIndex();\r\n\t\t}\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tthis._url = img.src;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\timg.src = this._url;\r\n\t\timg.alt = this.options.alt;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar scale = this._map.getZoomScale(e.zoom),\r\n\t\t offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;\r\n\r\n\t\tDomUtil.setTransform(this._image, offset, scale);\r\n\t},\r\n\r\n\t_reset: function () {\r\n\t\tvar image = this._image,\r\n\t\t bounds = new Bounds(\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getNorthWest()),\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getSouthEast())),\r\n\t\t size = bounds.getSize();\r\n\r\n\t\tDomUtil.setPosition(image, bounds.min);\r\n\r\n\t\timage.style.width = size.x + 'px';\r\n\t\timage.style.height = size.y + 'px';\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tDomUtil.setOpacity(this._image, this.options.opacity);\r\n\t},\r\n\r\n\t_updateZIndex: function () {\r\n\t\tif (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {\r\n\t\t\tthis._image.style.zIndex = this.options.zIndex;\r\n\t\t}\r\n\t},\r\n\r\n\t_overlayOnError: function () {\r\n\t\t// @event error: Event\r\n\t\t// Fired when the ImageOverlay layer fails to load its image\r\n\t\tthis.fire('error');\r\n\r\n\t\tvar errorUrl = this.options.errorOverlayUrl;\r\n\t\tif (errorUrl && this._url !== errorUrl) {\r\n\t\t\tthis._url = errorUrl;\r\n\t\t\tthis._image.src = errorUrl;\r\n\t\t}\r\n\t},\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the center of the ImageOverlay.\r\n\tgetCenter: function () {\r\n\t\treturn this._bounds.getCenter();\r\n\t}\r\n});\r\n\r\n// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)\r\n// Instantiates an image overlay object given the URL of the image and the\r\n// geographical bounds it is tied to.\r\nexport var imageOverlay = function (url, bounds, options) {\r\n\treturn new ImageOverlay(url, bounds, options);\r\n};\r\n","import {ImageOverlay} from './ImageOverlay';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport * as Util from '../core/Util';\r\n\r\n/*\r\n * @class VideoOverlay\r\n * @aka L.VideoOverlay\r\n * @inherits ImageOverlay\r\n *\r\n * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.\r\n *\r\n * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)\r\n * HTML5 element.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',\r\n * \tvideoBounds = [[ 32, -130], [ 13, -100]];\r\n * L.videoOverlay(videoUrl, videoBounds ).addTo(map);\r\n * ```\r\n */\r\n\r\nexport var VideoOverlay = ImageOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka VideoOverlay options\r\n\toptions: {\r\n\t\t// @option autoplay: Boolean = true\r\n\t\t// Whether the video starts playing automatically when loaded.\r\n\t\t// On some browsers autoplay will only work with `muted: true`\r\n\t\tautoplay: true,\r\n\r\n\t\t// @option loop: Boolean = true\r\n\t\t// Whether the video will loop back to the beginning when played.\r\n\t\tloop: true,\r\n\r\n\t\t// @option keepAspectRatio: Boolean = true\r\n\t\t// Whether the video will save aspect ratio after the projection.\r\n\t\t// Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)\r\n\t\tkeepAspectRatio: true,\r\n\r\n\t\t// @option muted: Boolean = false\r\n\t\t// Whether the video starts on mute when loaded.\r\n\t\tmuted: false,\r\n\r\n\t\t// @option playsInline: Boolean = true\r\n\t\t// Mobile browsers will play the video right where it is instead of open it up in fullscreen mode.\r\n\t\tplaysInline: true\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'VIDEO';\r\n\t\tvar vid = this._image = wasElementSupplied ? this._url : DomUtil.create('video');\r\n\r\n\t\tDomUtil.addClass(vid, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { DomUtil.addClass(vid, 'leaflet-zoom-animated'); }\r\n\t\tif (this.options.className) { DomUtil.addClass(vid, this.options.className); }\r\n\r\n\t\tvid.onselectstart = Util.falseFn;\r\n\t\tvid.onmousemove = Util.falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the video has finished loading the first frame\r\n\t\tvid.onloadeddata = Util.bind(this.fire, this, 'load');\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tvar sourceElements = vid.getElementsByTagName('source');\r\n\t\t\tvar sources = [];\r\n\t\t\tfor (var j = 0; j < sourceElements.length; j++) {\r\n\t\t\t\tsources.push(sourceElements[j].src);\r\n\t\t\t}\r\n\r\n\t\t\tthis._url = (sourceElements.length > 0) ? sources : [vid.src];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!Util.isArray(this._url)) { this._url = [this._url]; }\r\n\r\n\t\tif (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) {\r\n\t\t\tvid.style['objectFit'] = 'fill';\r\n\t\t}\r\n\t\tvid.autoplay = !!this.options.autoplay;\r\n\t\tvid.loop = !!this.options.loop;\r\n\t\tvid.muted = !!this.options.muted;\r\n\t\tvid.playsInline = !!this.options.playsInline;\r\n\t\tfor (var i = 0; i < this._url.length; i++) {\r\n\t\t\tvar source = DomUtil.create('source');\r\n\t\t\tsource.src = this._url[i];\r\n\t\t\tvid.appendChild(source);\r\n\t\t}\r\n\t}\r\n\r\n\t// @method getElement(): HTMLVideoElement\r\n\t// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)\r\n\t// used by this overlay.\r\n});\r\n\r\n\r\n// @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)\r\n// Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the\r\n// geographical bounds it is tied to.\r\n\r\nexport function videoOverlay(video, bounds, options) {\r\n\treturn new VideoOverlay(video, bounds, options);\r\n}\r\n","import {ImageOverlay} from './ImageOverlay';\nimport * as DomUtil from '../dom/DomUtil';\nimport * as Util from '../core/Util';\n\n/*\n * @class SVGOverlay\n * @aka L.SVGOverlay\n * @inherits ImageOverlay\n *\n * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`.\n *\n * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element.\n *\n * @example\n *\n * ```js\n * var svgElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n * svgElement.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n * svgElement.setAttribute('viewBox', \"0 0 200 200\");\n * svgElement.innerHTML = '<rect width=\"200\" height=\"200\"/><rect x=\"75\" y=\"23\" width=\"50\" height=\"50\" style=\"fill:red\"/><rect x=\"75\" y=\"123\" width=\"50\" height=\"50\" style=\"fill:#0013ff\"/>';\n * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ];\n * L.svgOverlay(svgElement, svgElementBounds).addTo(map);\n * ```\n */\n\nexport var SVGOverlay = ImageOverlay.extend({\n\t_initImage: function () {\n\t\tvar el = this._image = this._url;\n\n\t\tDomUtil.addClass(el, 'leaflet-image-layer');\n\t\tif (this._zoomAnimated) { DomUtil.addClass(el, 'leaflet-zoom-animated'); }\n\t\tif (this.options.className) { DomUtil.addClass(el, this.options.className); }\n\n\t\tel.onselectstart = Util.falseFn;\n\t\tel.onmousemove = Util.falseFn;\n\t}\n\n\t// @method getElement(): SVGElement\n\t// Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)\n\t// used by this overlay.\n});\n\n\n// @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options)\n// Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to.\n// A viewBox attribute is required on the SVG element to zoom in and out properly.\n\nexport function svgOverlay(el, bounds, options) {\n\treturn new SVGOverlay(el, bounds, options);\n}\n","import {Map} from '../map/Map';\r\nimport {Layer} from './Layer';\r\nimport {FeatureGroup} from './FeatureGroup';\r\nimport * as Util from '../core/Util';\r\nimport {toLatLng, LatLng} from '../geo/LatLng';\r\nimport {toPoint} from '../geometry/Point';\r\nimport * as DomUtil from '../dom/DomUtil';\r\n\r\n/*\r\n * @class DivOverlay\r\n * @inherits Interactive layer\r\n * @aka L.DivOverlay\r\n * Base model for L.Popup and L.Tooltip. Inherit from it for custom overlays like plugins.\r\n */\r\n\r\n// @namespace DivOverlay\r\nexport var DivOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka DivOverlay options\r\n\toptions: {\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If true, the popup/tooltip will listen to the mouse events.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option offset: Point = Point(0, 0)\r\n\t\t// The offset of the overlay position.\r\n\t\toffset: [0, 0],\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the overlay.\r\n\t\tclassName: '',\r\n\r\n\t\t// @option pane: String = undefined\r\n\t\t// `Map pane` where the overlay will be added.\r\n\t\tpane: undefined,\r\n\r\n\t\t// @option content: String|HTMLElement|Function = ''\r\n\t\t// Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be\r\n\t\t// passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay.\r\n\t\tcontent: ''\r\n\t},\r\n\r\n\tinitialize: function (options, source) {\r\n\t\tif (options && (options instanceof LatLng || Util.isArray(options))) {\r\n\t\t\tthis._latlng = toLatLng(options);\r\n\t\t\tUtil.setOptions(this, source);\r\n\t\t} else {\r\n\t\t\tUtil.setOptions(this, options);\r\n\t\t\tthis._source = source;\r\n\t\t}\r\n\t\tif (this.options.content) {\r\n\t\t\tthis._content = this.options.content;\r\n\t\t}\r\n\t},\r\n\r\n\t// @method openOn(map: Map): this\r\n\t// Adds the overlay to the map.\r\n\t// Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`.\r\n\topenOn: function (map) {\r\n\t\tmap = arguments.length ? map : this._source._map; // experimental, not the part of public api\r\n\t\tif (!map.hasLayer(this)) {\r\n\t\t\tmap.addLayer(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method close(): this\r\n\t// Closes the overlay.\r\n\t// Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)`\r\n\t// and `layer.closePopup()`/`.closeTooltip()`.\r\n\tclose: function () {\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.removeLayer(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method toggle(layer?: Layer): this\r\n\t// Opens or closes the overlay bound to layer depending on its current state.\r\n\t// Argument may be omitted only for overlay bound to layer.\r\n\t// Alternative to `layer.togglePopup()`/`.toggleTooltip()`.\r\n\ttoggle: function (layer) {\r\n\t\tif (this._map) {\r\n\t\t\tthis.close();\r\n\t\t} else {\r\n\t\t\tif (arguments.length) {\r\n\t\t\t\tthis._source = layer;\r\n\t\t\t} else {\r\n\t\t\t\tlayer = this._source;\r\n\t\t\t}\r\n\t\t\tthis._prepareOpen();\r\n\r\n\t\t\t// open the overlay on the map\r\n\t\t\tthis.openOn(layer._map);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = map._zoomAnimated;\r\n\r\n\t\tif (!this._container) {\r\n\t\t\tthis._initLayout();\r\n\t\t}\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 0);\r\n\t\t}\r\n\r\n\t\tclearTimeout(this._removeTimeout);\r\n\t\tthis.getPane().appendChild(this._container);\r\n\t\tthis.update();\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 1);\r\n\t\t}\r\n\r\n\t\tthis.bringToFront();\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.addClass(this._container, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tDomUtil.setOpacity(this._container, 0);\r\n\t\t\tthis._removeTimeout = setTimeout(Util.bind(DomUtil.remove, undefined, this._container), 200);\r\n\t\t} else {\r\n\t\t\tDomUtil.remove(this._container);\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-interactive');\r\n\t\t\tthis.removeInteractiveTarget(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\t// @namespace DivOverlay\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the geographical point of the overlay.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Sets the geographical point where the overlay will open.\r\n\tsetLatLng: function (latlng) {\r\n\t\tthis._latlng = toLatLng(latlng);\r\n\t\tif (this._map) {\r\n\t\t\tthis._updatePosition();\r\n\t\t\tthis._adjustPan();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContent: String|HTMLElement\r\n\t// Returns the content of the overlay.\r\n\tgetContent: function () {\r\n\t\treturn this._content;\r\n\t},\r\n\r\n\t// @method setContent(htmlContent: String|HTMLElement|Function): this\r\n\t// Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function.\r\n\t// The function should return a `String` or `HTMLElement` to be used in the overlay.\r\n\tsetContent: function (content) {\r\n\t\tthis._content = content;\r\n\t\tthis.update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getElement: String|HTMLElement\r\n\t// Returns the HTML container of the overlay.\r\n\tgetElement: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method update: null\r\n\t// Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded.\r\n\tupdate: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tthis._container.style.visibility = 'hidden';\r\n\r\n\t\tthis._updateContent();\r\n\t\tthis._updateLayout();\r\n\t\tthis._updatePosition();\r\n\r\n\t\tthis._container.style.visibility = '';\r\n\r\n\t\tthis._adjustPan();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._updatePosition,\r\n\t\t\tviewreset: this._updatePosition\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method isOpen: Boolean\r\n\t// Returns `true` when the overlay is visible on the map.\r\n\tisOpen: function () {\r\n\t\treturn !!this._map && this._map.hasLayer(this);\r\n\t},\r\n\r\n\t// @method bringToFront: this\r\n\t// Brings this overlay in front of other overlays (in the same map pane).\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toFront(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack: this\r\n\t// Brings this overlay to the back of other overlays (in the same map pane).\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tDomUtil.toBack(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)\r\n\t_prepareOpen: function (latlng) {\r\n\t\tvar source = this._source;\r\n\t\tif (!source._map) { return false; }\r\n\r\n\t\tif (source instanceof FeatureGroup) {\r\n\t\t\tsource = null;\r\n\t\t\tvar layers = this._source._layers;\r\n\t\t\tfor (var id in layers) {\r\n\t\t\t\tif (layers[id]._map) {\r\n\t\t\t\t\tsource = layers[id];\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!source) { return false; } // Unable to get source layer.\r\n\r\n\t\t\t// set overlay source to this layer\r\n\t\t\tthis._source = source;\r\n\t\t}\r\n\r\n\t\tif (!latlng) {\r\n\t\t\tif (source.getCenter) {\r\n\t\t\t\tlatlng = source.getCenter();\r\n\t\t\t} else if (source.getLatLng) {\r\n\t\t\t\tlatlng = source.getLatLng();\r\n\t\t\t} else if (source.getBounds) {\r\n\t\t\t\tlatlng = source.getBounds().getCenter();\r\n\t\t\t} else {\r\n\t\t\t\tthrow new Error('Unable to get source layer LatLng.');\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.setLatLng(latlng);\r\n\r\n\t\tif (this._map) {\r\n\t\t\t// update the overlay (content, layout, etc...)\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_updateContent: function () {\r\n\t\tif (!this._content) { return; }\r\n\r\n\t\tvar node = this._contentNode;\r\n\t\tvar content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;\r\n\r\n\t\tif (typeof content === 'string') {\r\n\t\t\tnode.innerHTML = content;\r\n\t\t} else {\r\n\t\t\twhile (node.hasChildNodes()) {\r\n\t\t\t\tnode.removeChild(node.firstChild);\r\n\t\t\t}\r\n\t\t\tnode.appendChild(content);\r\n\t\t}\r\n\r\n\t\t// @namespace DivOverlay\r\n\t\t// @section DivOverlay events\r\n\t\t// @event contentupdate: Event\r\n\t\t// Fired when the content of the overlay is updated\r\n\t\tthis.fire('contentupdate');\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng),\r\n\t\t offset = toPoint(this.options.offset),\r\n\t\t anchor = this._getAnchor();\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tDomUtil.setPosition(this._container, pos.add(anchor));\r\n\t\t} else {\r\n\t\t\toffset = offset.add(pos).add(anchor);\r\n\t\t}\r\n\r\n\t\tvar bottom = this._containerBottom = -offset.y,\r\n\t\t left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;\r\n\r\n\t\t// bottom position the overlay in case the height of the overlay changes (images loading etc)\r\n\t\tthis._container.style.bottom = bottom + 'px';\r\n\t\tthis._container.style.left = left + 'px';\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\treturn [0, 0];\r\n\t}\r\n\r\n});\r\n\r\nMap.include({\r\n\t_initOverlay: function (OverlayClass, content, latlng, options) {\r\n\t\tvar overlay = content;\r\n\t\tif (!(overlay instanceof OverlayClass)) {\r\n\t\t\toverlay = new OverlayClass(options).setContent(content);\r\n\t\t}\r\n\t\tif (latlng) {\r\n\t\t\toverlay.setLatLng(latlng);\r\n\t\t}\r\n\t\treturn overlay;\r\n\t}\r\n});\r\n\r\n\r\nLayer.include({\r\n\t_initOverlay: function (OverlayClass, old, content, options) {\r\n\t\tvar overlay = content;\r\n\t\tif (overlay instanceof OverlayClass) {\r\n\t\t\tUtil.setOptions(overlay, options);\r\n\t\t\toverlay._source = this;\r\n\t\t} else {\r\n\t\t\toverlay = (old && !options) ? old : new OverlayClass(options, this);\r\n\t\t\toverlay.setContent(content);\r\n\t\t}\r\n\t\treturn overlay;\r\n\t}\r\n});\r\n","import {DivOverlay} from './DivOverlay';\r\nimport * as DomEvent from '../dom/DomEvent';\r\nimport * as DomUtil from '../dom/DomUtil';\r\nimport {Point, toPoint} from '../geometry/Point';\r\nimport {Map} from '../map/Map';\r\nimport {Layer} from './Layer';\r\nimport {Path} from './vector/Path';\r\nimport {FeatureGroup} from './FeatureGroup';\r\n\r\n/*\r\n * @class Popup\r\n * @inherits DivOverlay\r\n * @aka L.Popup\r\n * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to\r\n * open popups while making sure that only one popup is open at one time\r\n * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.\r\n *\r\n * @example\r\n *\r\n * If you want to just bind a popup to marker click and then open it, it's really easy:\r\n *\r\n * ```js\r\n * marker.bindPopup(popupContent).openPopup();\r\n * ```\r\n * Path overlays like polylines also have a `bindPopup` method.\r\n *\r\n * A popup can be also standalone:\r\n *\r\n * ```js\r\n * var popup = L.popup()\r\n * \t.setLatLng(latlng)\r\n * \t.setContent('<p>Hello world!<br />This is a nice popup.</p>')\r\n * \t.openOn(map);\r\n * ```\r\n * or\r\n * ```js\r\n * var popup = L.popup(latlng, {content: '<p>Hello world!<br />This is a nice popup.</p>')\r\n * \t.openOn(map);\r\n * ```\r\n */\r\n\r\n\r\n// @namespace Popup\r\nexport var Popup = DivOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka Popup options\r\n\toptions: {\r\n\t\t// @option pane: String = 'popupPane'\r\n\t\t// `Map pane` where the popup will be added.\r\n\t\tpane: 'popupPane',\r\n\r\n\t\t// @option offset: Point = Point(0, 7)\r\n\t\t// The offset of the popup position.\r\n\t\toffset: [0, 7],\r\n\r\n\t\t// @option maxWidth: Number = 300\r\n\t\t// Max width of the popup, in pixels.\r\n\t\tmaxWidth: 300,\r\n\r\n\t\t// @option minWidth: Number = 50\r\n\t\t// Min width of the popup, in pixels.\r\n\t\tminWidth: 50,\r\n\r\n\t\t// @option maxHeight: Number = null\r\n\t\t// If set, creates a scrollable container of the given height\r\n\t\t// inside a popup if its content exceeds it.\r\n\t\t// The scrollable container can be styled using the\r\n\t\t// `leaflet-popup-scrolled` CSS class selector.\r\n\t\tmaxHeight: null,\r\n\r\n\t\t// @option autoPan: Boolean = true\r\n\t\t// Set it to `false` if you don't want the map to do panning animation\r\n\t\t// to fit the opened popup.\r\n\t\tautoPan: true,\r\n\r\n\t\t// @option autoPanPaddingTopLeft: Point = null\r\n\t\t// The margin between the popup and the top left corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingTopLeft: null,\r\n\r\n\t\t// @option autoPanPaddingBottomRight: Point = null\r\n\t\t// The margin between the popup and the bottom right corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingBottomRight: null,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(5, 5)\r\n\t\t// Equivalent of setting both top left and bottom right autopan padding to the same value.\r\n\t\tautoPanPadding: [5, 5],\r\n\r\n\t\t// @option keepInView: Boolean = false\r\n\t\t// Set it to `true` if you want to prevent users from panning the popup\r\n\t\t// off of the screen while it is open.\r\n\t\tkeepInView: false,\r\n\r\n\t\t// @option closeButton: Boolean = true\r\n\t\t// Controls the presence of a close button in the popup.\r\n\t\tcloseButton: true,\r\n\r\n\t\t// @option autoClose: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the popup closing when another popup is opened.\r\n\t\tautoClose: true,\r\n\r\n\t\t// @option closeOnEscapeKey: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the ESC key for closing of the popup.\r\n\t\tcloseOnEscapeKey: true,\r\n\r\n\t\t// @option closeOnClick: Boolean = *\r\n\t\t// Set it if you want to override the default behavior of the popup closing when user clicks\r\n\t\t// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method openOn(map: Map): this\r\n\t// Alternative to `map.openPopup(popup)`.\r\n\t// Adds the popup to the map and closes the previous one.\r\n\topenOn: function (map) {\r\n\t\tmap = arguments.length ? map : this._source._map; // experimental, not the part of public api\r\n\r\n\t\tif (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) {\r\n\t\t\tmap.removeLayer(map._popup);\r\n\t\t}\r\n\t\tmap._popup = this;\r\n\r\n\t\treturn DivOverlay.prototype.openOn.call(this, map);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tDivOverlay.prototype.onAdd.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupopen: PopupEvent\r\n\t\t// Fired when a popup is opened in the map\r\n\t\tmap.fire('popupopen', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupopen: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is opened\r\n\t\t\tthis._source.fire('popupopen', {popup: this}, true);\r\n\t\t\t// For non-path layers, we toggle the popup when clicking\r\n\t\t\t// again the layer, so prevent the map to reopen it.\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.on('preclick', DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tDivOverlay.prototype.onRemove.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupclose: PopupEvent\r\n\t\t// Fired when a popup in the map is closed\r\n\t\tmap.fire('popupclose', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupclose: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is closed\r\n\t\t\tthis._source.fire('popupclose', {popup: this}, true);\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.off('preclick', DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\r\n\r\n\t\tif (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {\r\n\t\t\tevents.preclick = this.close;\r\n\t\t}\r\n\r\n\t\tif (this.options.keepInView) {\r\n\t\t\tevents.moveend = this._adjustPan;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar prefix = 'leaflet-popup',\r\n\t\t container = this._container = DomUtil.create('div',\r\n\t\t\tprefix + ' ' + (this.options.className || '') +\r\n\t\t\t' leaflet-zoom-animated');\r\n\r\n\t\tvar wrapper = this._wrapper = DomUtil.create('div', prefix + '-content-wrapper', container);\r\n\t\tthis._contentNode = DomUtil.create('div', prefix + '-content', wrapper);\r\n\r\n\t\tDomEvent.disableClickPropagation(container);\r\n\t\tDomEvent.disableScrollPropagation(this._contentNode);\r\n\t\tDomEvent.on(container, 'contextmenu', DomEvent.stopPropagation);\r\n\r\n\t\tthis._tipContainer = DomUtil.create('div', prefix + '-tip-container', container);\r\n\t\tthis._tip = DomUtil.create('div', prefix + '-tip', this._tipContainer);\r\n\r\n\t\tif (this.options.closeButton) {\r\n\t\t\tvar closeButton = this._closeButton = DomUtil.create('a', prefix + '-close-button', container);\r\n\t\t\tcloseButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399\r\n\t\t\tcloseButton.setAttribute('aria-label', 'Close popup');\r\n\t\t\tcloseButton.href = '#close';\r\n\t\t\tcloseButton.innerHTML = '<span aria-hidden=\"true\">&#215;</span>';\r\n\r\n\t\t\tDomEvent.on(closeButton, 'click', function (ev) {\r\n\t\t\t\tDomEvent.preventDefault(ev);\r\n\t\t\t\tthis.close();\r\n\t\t\t}, this);\r\n\t\t}\r\n\t},\r\n\r\n\t_updateLayout: function () {\r\n\t\tvar container = this._contentNode,\r\n\t\t style = container.style;\r\n\r\n\t\tstyle.width = '';\r\n\t\tstyle.whiteSpace = 'nowrap';\r\n\r\n\t\tvar width = container.offsetWidth;\r\n\t\twidth = Math.min(width, this.options.maxWidth);\r\n\t\twidth = Math.max(width, this.options.minWidth);\r\n\r\n\t\tstyle.width = (width + 1) + 'px';\r\n\t\tstyle.whiteSpace = '';\r\n\r\n\t\tstyle.height = '';\r\n\r\n\t\tvar height = container.offsetHeight,\r\n\t\t maxHeight = this.options.maxHeight,\r\n\t\t scrolledClass = 'leaflet-popup-scrolled';\r\n\r\n\t\tif (maxHeight && height > maxHeight) {\r\n\t\t\tstyle.height = maxHeight + 'px';\r\n\t\t\tDomUtil.addClass(container, scrolledClass);\r\n\t\t} else {\r\n\t\t\tDomUtil.removeClass(container, scrolledClass);\r\n\t\t}\r\n\r\n\t\tthis._containerWidth = this._container.offsetWidth;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),\r\n\t\t anchor = this._getAnchor();\r\n\t\tDomUtil.setPosition(this._container, pos.add(anchor));\r\n\t},\r\n\r\n\t_adjustPan: function () {\r\n\t\tif (!this.options.autoPan) { return; }\r\n\t\tif (this._map._panAnim) { this._map._panAnim.stop(); }\r\n\r\n\t\t// We can endlessly recurse if keepInView is set and the view resets.\r\n\t\t// Let's guard against that by exiting early if we're responding to our own autopan.\r\n\t\tif (this._autopanning) {\r\n\t\t\tthis._autopanning = false;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar map = this._map,\r\n\t\t marginBottom = parseInt(DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,\r\n\t\t containerHeight = this._container.offsetHeight + marginBottom,\r\n\t\t containerWidth = this._containerWidth,\r\n\t\t layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);\r\n\r\n\t\tlayerPos._add(DomUtil.getPosition(this._container));\r\n\r\n\t\tvar containerPos = map.layerPointToContainerPoint(layerPos),\r\n\t\t padding = toPoint(this.options.autoPanPadding),\r\n\t\t paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),\r\n\t\t paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),\r\n\t\t size = map.getSize(),\r\n\t\t dx = 0,\r\n\t\t dy = 0;\r\n\r\n\t\tif (containerPos.x + containerWidth + paddingBR.x > size.x) { // right\r\n\t\t\tdx = containerPos.x + containerWidth - size.x + paddingBR.x;\r\n\t\t}\r\n\t\tif (containerPos.x - dx - paddingTL.x < 0) { // left\r\n\t\t\tdx = containerPos.x - paddingTL.x;\r\n\t\t}\r\n\t\tif (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom\r\n\t\t\tdy = containerPos.y + containerHeight - size.y + paddingBR.y;\r\n\t\t}\r\n\t\tif (containerPos.y - dy - paddingTL.y < 0) { // top\r\n\t\t\tdy = containerPos.y - paddingTL.y;\r\n\t\t}\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event autopanstart: Event\r\n\t\t// Fired when the map starts autopanning when opening a popup.\r\n\t\tif (dx || dy) {\r\n\t\t\t// Track that we're autopanning, as this function will be re-ran on moveend\r\n\t\t\tif (this.options.keepInView) {\r\n\t\t\t\tthis._autopanning = true;\r\n\t\t\t}\r\n\r\n\t\t\tmap\r\n\t\t\t .fire('autopanstart')\r\n\t\t\t .panBy([dx, dy]);\r\n\t\t}\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\t// Where should we anchor the popup on the source layer?\r\n\t\treturn toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);\r\n\t}\r\n\r\n});\r\n\r\n// @namespace Popup\r\n// @factory L.popup(options?: Popup options, source?: Layer)\r\n// Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.\r\n// @alternative\r\n// @factory L.popup(latlng: LatLng, options?: Popup options)\r\n// Instantiates a `Popup` object given `latlng` where the popup will open and an optional `options` object that describes its appearance and location.\r\nexport var popup = function (options, source) {\r\n\treturn new Popup(options, source);\r\n};\r\n\r\n\r\n/* @namespace Map\r\n * @section Interaction Options\r\n * @option closePopupOnClick: Boolean = true\r\n * Set it to `false` if you don't want popups to close when user clicks the map.\r\n */\r\nMap.mergeOptions({\r\n\tclosePopupOnClick: true\r\n});\r\n\r\n\r\n// @namespace Map\r\n// @section Methods for Layers and Controls\r\nMap.include({\r\n\t// @method openPopup(popup: Popup): this\r\n\t// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).\r\n\t// @alternative\r\n\t// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this\r\n\t// Creates a popup with the specified content and options and opens it in the given point on a map.\r\n\topenPopup: function (popup, latlng, options) {\r\n\t\tthis._initOverlay(Popup, popup, latlng, options)\r\n\t\t .openOn(this);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(popup?: Popup): this\r\n\t// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).\r\n\tclosePopup: function (popup) {\r\n\t\tpopup = arguments.length ? popup : this._popup;\r\n\t\tif (popup) {\r\n\t\t\tpopup.close();\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n/*\r\n * @namespace Layer\r\n * @section Popup methods example\r\n *\r\n * All layers share a set of methods convenient for binding popups to it.\r\n *\r\n * ```js\r\n * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\r\n * layer.openPopup();\r\n * layer.closePopup();\r\n * ```\r\n *\r\n * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.\r\n */\r\n\r\n// @section Popup methods\r\nLayer.include({\r\n\r\n\t// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this\r\n\t// Binds a popup to the layer with the passed `content` and sets up the\r\n\t// necessary event listeners. If a `Function` is passed it will receive\r\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\r\n\tbindPopup: function (content, options) {\r\n\t\tthis._popup = this._initOverlay(Popup, this._popup, content, options);\r\n\t\tif (!this._popupHandlersAdded) {\r\n\t\t\tthis.on({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = true;\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method unbindPopup(): this\r\n\t// Removes the popup previously bound with `bindPopup`.\r\n\tunbindPopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis.off({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = false;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method openPopup(latlng?: LatLng): this\r\n\t// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.\r\n\topenPopup: function (latlng) {\r\n\t\tif (this._popup) {\r\n\t\t\tif (!(this instanceof FeatureGroup)) {\r\n\t\t\t\tthis._popup._source = this;\r\n\t\t\t}\r\n\t\t\tif (this._popup._prepareOpen(latlng || this._latlng)) {\r\n\t\t\t\t// open the popup on the map\r\n\t\t\t\tthis._popup.openOn(this._map);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(): this\r\n\t// Closes the popup bound to this layer if it is open.\r\n\tclosePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.close();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method togglePopup(): this\r\n\t// Opens or closes the popup bound to this layer depending on its current state.\r\n\ttogglePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.toggle(this);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method isPopupOpen(): boolean\r\n\t// Returns `true` if the popup bound to this layer is currently open.\r\n\tisPopupOpen: function () {\r\n\t\treturn (this._popup ? this._popup.isOpen() : false);\r\n\t},\r\n\r\n\t// @method setPopupContent(content: String|HTMLElement|Popup): this\r\n\t// Sets the content of the popup bound to this layer.\r\n\tsetPopupContent: function (content) {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getPopup(): Popup\r\n\t// Returns the popup bound to this layer.\r\n\tgetPopup: function () {\r\n\t\treturn this._popup;\r\n\t},\r\n\r\n\t_openPopup: function (e) {\r\n\t\tif (!this._popup || !this._map) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t// prevent map click\r\n\t\tDomEvent.stop(e);\r\n\r\n\t\tvar target = e.layer || e.target;\r\n\t\tif (this._popup._source === target && !(target instanceof Path)) {\r\n\t\t\t// treat it like a marker and figure out\r\n\t\t\t// if we should toggle it open/closed\r\n\t\t\tif (this._map.hasLayer(this._popup)) {\r\n\t\t\t\tthis.closePopup();\r\n\t\t\t} else {\r\n\t\t\t\tthis.openPopup(e.latlng);\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis._popup._source = target;\r\n\t\tthis.openPopup(e.latlng);\r\n\t},\r\n\r\n\t_movePopup: function (e) {\r\n\t\tthis._popup.setLatLng(e.latlng);\r\n\t},\r\n\r\n\t_onKeyPress: function (e) {\r\n\t\tif (e.originalEvent.keyCode === 13) {\r\n\t\t\tthis._openPopup(e);\r\n\t\t}\r\n\t}\r\n});\r\n","import {DivOverlay} from './DivOverlay';\nimport {toPoint} from '../geometry/Point';\nimport {Map} from '../map/Map';\nimport {Layer} from './Layer';\nimport * as DomUtil from '../dom/DomUtil';\nimport * as DomEvent from '../dom/DomEvent';\nimport * as Util from '../core/Util';\nimport {FeatureGroup} from './FeatureGroup';\n\n/*\n * @class Tooltip\n * @inherits DivOverlay\n * @aka L.Tooltip\n * Used to display small texts on top of map layers.\n *\n * @example\n * If you want to just bind a tooltip to marker:\n *\n * ```js\n * marker.bindTooltip(\"my tooltip text\").openTooltip();\n * ```\n * Path overlays like polylines also have a `bindTooltip` method.\n *\n * A tooltip can be also standalone:\n *\n * ```js\n * var tooltip = L.tooltip()\n * \t.setLatLng(latlng)\n * \t.setContent('Hello world!<br />This is a nice tooltip.')\n * \t.addTo(map);\n * ```\n * or\n * ```js\n * var tooltip = L.tooltip(latlng, {content: 'Hello world!<br />This is a nice tooltip.'})\n * \t.addTo(map);\n * ```\n *\n *\n * Note about tooltip offset. Leaflet takes two options in consideration\n * for computing tooltip offsetting:\n * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.\n * Add a positive x offset to move the tooltip to the right, and a positive y offset to\n * move it to the bottom. Negatives will move to the left and top.\n * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You\n * should adapt this value if you use a custom icon.\n */\n\n\n// @namespace Tooltip\nexport var Tooltip = DivOverlay.extend({\n\n\t// @section\n\t// @aka Tooltip options\n\toptions: {\n\t\t// @option pane: String = 'tooltipPane'\n\t\t// `Map pane` where the tooltip will be added.\n\t\tpane: 'tooltipPane',\n\n\t\t// @option offset: Point = Point(0, 0)\n\t\t// Optional offset of the tooltip position.\n\t\toffset: [0, 0],\n\n\t\t// @option direction: String = 'auto'\n\t\t// Direction where to open the tooltip. Possible values are: `right`, `left`,\n\t\t// `top`, `bottom`, `center`, `auto`.\n\t\t// `auto` will dynamically switch between `right` and `left` according to the tooltip\n\t\t// position on the map.\n\t\tdirection: 'auto',\n\n\t\t// @option permanent: Boolean = false\n\t\t// Whether to open the tooltip permanently or only on mouseover.\n\t\tpermanent: false,\n\n\t\t// @option sticky: Boolean = false\n\t\t// If true, the tooltip will follow the mouse instead of being fixed at the feature center.\n\t\tsticky: false,\n\n\t\t// @option opacity: Number = 0.9\n\t\t// Tooltip container opacity.\n\t\topacity: 0.9\n\t},\n\n\tonAdd: function (map) {\n\t\tDivOverlay.prototype.onAdd.call(this, map);\n\t\tthis.setOpacity(this.options.opacity);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipopen: TooltipEvent\n\t\t// Fired when a tooltip is opened in the map.\n\t\tmap.fire('tooltipopen', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\tthis.addEventParent(this._source);\n\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipopen: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is opened.\n\t\t\tthis._source.fire('tooltipopen', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tonRemove: function (map) {\n\t\tDivOverlay.prototype.onRemove.call(this, map);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipclose: TooltipEvent\n\t\t// Fired when a tooltip in the map is closed.\n\t\tmap.fire('tooltipclose', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\tthis.removeEventParent(this._source);\n\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipclose: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is closed.\n\t\t\tthis._source.fire('tooltipclose', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\n\n\t\tif (!this.options.permanent) {\n\t\t\tevents.preclick = this.close;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t_initLayout: function () {\n\t\tvar prefix = 'leaflet-tooltip',\n\t\t className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\n\n\t\tthis._contentNode = this._container = DomUtil.create('div', className);\n\n\t\tthis._container.setAttribute('role', 'tooltip');\n\t\tthis._container.setAttribute('id', 'leaflet-tooltip-' + Util.stamp(this));\n\t},\n\n\t_updateLayout: function () {},\n\n\t_adjustPan: function () {},\n\n\t_setPosition: function (pos) {\n\t\tvar subX, subY,\n\t\t map = this._map,\n\t\t container = this._container,\n\t\t centerPoint = map.latLngToContainerPoint(map.getCenter()),\n\t\t tooltipPoint = map.layerPointToContainerPoint(pos),\n\t\t direction = this.options.direction,\n\t\t tooltipWidth = container.offsetWidth,\n\t\t tooltipHeight = container.offsetHeight,\n\t\t offset = toPoint(this.options.offset),\n\t\t anchor = this._getAnchor();\n\n\t\tif (direction === 'top') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = tooltipHeight;\n\t\t} else if (direction === 'bottom') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = 0;\n\t\t} else if (direction === 'center') {\n\t\t\tsubX = tooltipWidth / 2;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (direction === 'right') {\n\t\t\tsubX = 0;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (direction === 'left') {\n\t\t\tsubX = tooltipWidth;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else if (tooltipPoint.x < centerPoint.x) {\n\t\t\tdirection = 'right';\n\t\t\tsubX = 0;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t} else {\n\t\t\tdirection = 'left';\n\t\t\tsubX = tooltipWidth + (offset.x + anchor.x) * 2;\n\t\t\tsubY = tooltipHeight / 2;\n\t\t}\n\n\t\tpos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);\n\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-right');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-left');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-top');\n\t\tDomUtil.removeClass(container, 'leaflet-tooltip-bottom');\n\t\tDomUtil.addClass(container, 'leaflet-tooltip-' + direction);\n\t\tDomUtil.setPosition(container, pos);\n\t},\n\n\t_updatePosition: function () {\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._setPosition(pos);\n\t},\n\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\n\t\tif (this._container) {\n\t\t\tDomUtil.setOpacity(this._container, opacity);\n\t\t}\n\t},\n\n\t_animateZoom: function (e) {\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);\n\t\tthis._setPosition(pos);\n\t},\n\n\t_getAnchor: function () {\n\t\t// Where should we anchor the tooltip on the source layer?\n\t\treturn toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);\n\t}\n\n});\n\n// @namespace Tooltip\n// @factory L.tooltip(options?: Tooltip options, source?: Layer)\n// Instantiates a `Tooltip` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.\n// @alternative\n// @factory L.tooltip(latlng: LatLng, options?: Tooltip options)\n// Instantiates a `Tooltip` object given `latlng` where the tooltip will open and an optional `options` object that describes its appearance and location.\nexport var tooltip = function (options, source) {\n\treturn new Tooltip(options, source);\n};\n\n// @namespace Map\n// @section Methods for Layers and Controls\nMap.include({\n\n\t// @method openTooltip(tooltip: Tooltip): this\n\t// Opens the specified tooltip.\n\t// @alternative\n\t// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this\n\t// Creates a tooltip with the specified content and options and open it.\n\topenTooltip: function (tooltip, latlng, options) {\n\t\tthis._initOverlay(Tooltip, tooltip, latlng, options)\n\t\t .openOn(this);\n\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(tooltip: Tooltip): this\n\t// Closes the tooltip given as parameter.\n\tcloseTooltip: function (tooltip) {\n\t\ttooltip.close();\n\t\treturn this;\n\t}\n\n});\n\n/*\n * @namespace Layer\n * @section Tooltip methods example\n *\n * All layers share a set of methods convenient for binding tooltips to it.\n *\n * ```js\n * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);\n * layer.openTooltip();\n * layer.closeTooltip();\n * ```\n */\n\n// @section Tooltip methods\nLayer.include({\n\n\t// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this\n\t// Binds a tooltip to the layer with the passed `content` and sets up the\n\t// necessary event listeners. If a `Function` is passed it will receive\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\n\tbindTooltip: function (content, options) {\n\n\t\tif (this._tooltip && this.isTooltipOpen()) {\n\t\t\tthis.unbindTooltip();\n\t\t}\n\n\t\tthis._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options);\n\t\tthis._initTooltipInteractions();\n\n\t\tif (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {\n\t\t\tthis.openTooltip();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method unbindTooltip(): this\n\t// Removes the tooltip previously bound with `bindTooltip`.\n\tunbindTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._initTooltipInteractions(true);\n\t\t\tthis.closeTooltip();\n\t\t\tthis._tooltip = null;\n\t\t}\n\t\treturn this;\n\t},\n\n\t_initTooltipInteractions: function (remove) {\n\t\tif (!remove && this._tooltipHandlersAdded) { return; }\n\t\tvar onOff = remove ? 'off' : 'on',\n\t\t events = {\n\t\t\tremove: this.closeTooltip,\n\t\t\tmove: this._moveTooltip\n\t\t };\n\t\tif (!this._tooltip.options.permanent) {\n\t\t\tevents.mouseover = this._openTooltip;\n\t\t\tevents.mouseout = this.closeTooltip;\n\t\t\tevents.click = this._openTooltip;\n\t\t\tif (this._map) {\n\t\t\t\tthis._addFocusListeners();\n\t\t\t} else {\n\t\t\t\tevents.add = this._addFocusListeners;\n\t\t\t}\n\t\t} else {\n\t\t\tevents.add = this._openTooltip;\n\t\t}\n\t\tif (this._tooltip.options.sticky) {\n\t\t\tevents.mousemove = this._moveTooltip;\n\t\t}\n\t\tthis[onOff](events);\n\t\tthis._tooltipHandlersAdded = !remove;\n\t},\n\n\t// @method openTooltip(latlng?: LatLng): this\n\t// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.\n\topenTooltip: function (latlng) {\n\t\tif (this._tooltip) {\n\t\t\tif (!(this instanceof FeatureGroup)) {\n\t\t\t\tthis._tooltip._source = this;\n\t\t\t}\n\t\t\tif (this._tooltip._prepareOpen(latlng)) {\n\t\t\t\t// open the tooltip on the map\n\t\t\t\tthis._tooltip.openOn(this._map);\n\n\t\t\t\tif (this.getElement) {\n\t\t\t\t\tthis._setAriaDescribedByOnLayer(this);\n\t\t\t\t} else if (this.eachLayer) {\n\t\t\t\t\tthis.eachLayer(this._setAriaDescribedByOnLayer, this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(): this\n\t// Closes the tooltip bound to this layer if it is open.\n\tcloseTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\treturn this._tooltip.close();\n\t\t}\n\t},\n\n\t// @method toggleTooltip(): this\n\t// Opens or closes the tooltip bound to this layer depending on its current state.\n\ttoggleTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.toggle(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method isTooltipOpen(): boolean\n\t// Returns `true` if the tooltip bound to this layer is currently open.\n\tisTooltipOpen: function () {\n\t\treturn this._tooltip.isOpen();\n\t},\n\n\t// @method setTooltipContent(content: String|HTMLElement|Tooltip): this\n\t// Sets the content of the tooltip bound to this layer.\n\tsetTooltipContent: function (content) {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.setContent(content);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getTooltip(): Tooltip\n\t// Returns the tooltip bound to this layer.\n\tgetTooltip: function () {\n\t\treturn this._tooltip;\n\t},\n\n\t_addFocusListeners: function () {\n\t\tif (this.getElement) {\n\t\t\tthis._addFocusListenersOnLayer(this);\n\t\t} else if (this.eachLayer) {\n\t\t\tthis.eachLayer(this._addFocusListenersOnLayer, this);\n\t\t}\n\t},\n\n\t_addFocusListenersOnLayer: function (layer) {\n\t\tvar el = layer.getElement();\n\t\tif (el) {\n\t\t\tDomEvent.on(el, 'focus', function () {\n\t\t\t\tthis._tooltip._source = layer;\n\t\t\t\tthis.openTooltip();\n\t\t\t}, this);\n\t\t\tDomEvent.on(el, 'blur', this.closeTooltip, this);\n\t\t}\n\t},\n\n\t_setAriaDescribedByOnLayer: function (layer) {\n\t\tvar el = layer.getElement();\n\t\tif (el) {\n\t\t\tel.setAttribute('aria-describedby', this._tooltip._container.id);\n\t\t}\n\t},\n\n\n\t_openTooltip: function (e) {\n\t\tif (!this._tooltip || !this._map || (this._map.dragging && this._map.dragging.moving())) {\n\t\t\treturn;\n\t\t}\n\t\tthis._tooltip._source = e.layer || e.target;\n\n\t\tthis.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined);\n\t},\n\n\t_moveTooltip: function (e) {\n\t\tvar latlng = e.latlng, containerPoint, layerPoint;\n\t\tif (this._tooltip.options.sticky && e.originalEvent) {\n\t\t\tcontainerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);\n\t\t\tlayerPoint = this._map.containerPointToLayerPoint(containerPoint);\n\t\t\tlatlng = this._map.layerPointToLatLng(layerPoint);\n\t\t}\n\t\tthis._tooltip.setLatLng(latlng);\n\t}\n});\n","import {Icon} from './Icon';\nimport {toPoint as point} from '../../geometry/Point';\nimport {empty} from '../../dom/DomUtil';\n\n/*\n * @class DivIcon\n * @aka L.DivIcon\n * @inherits Icon\n *\n * Represents a lightweight icon for markers that uses a simple `<div>`\n * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.\n *\n * @example\n * ```js\n * var myIcon = L.divIcon({className: 'my-div-icon'});\n * // you can set .my-div-icon styles in CSS\n *\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n * ```\n *\n * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.\n */\n\nexport var DivIcon = Icon.extend({\n\toptions: {\n\t\t// @section\n\t\t// @aka DivIcon options\n\t\ticonSize: [12, 12], // also can be set through CSS\n\n\t\t// iconAnchor: (Point),\n\t\t// popupAnchor: (Point),\n\n\t\t// @option html: String|HTMLElement = ''\n\t\t// Custom HTML code to put inside the div element, empty by default. Alternatively,\n\t\t// an instance of `HTMLElement`.\n\t\thtml: false,\n\n\t\t// @option bgPos: Point = [0, 0]\n\t\t// Optional relative position of the background, in pixels\n\t\tbgPos: null,\n\n\t\tclassName: 'leaflet-div-icon'\n\t},\n\n\tcreateIcon: function (oldIcon) {\n\t\tvar div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),\n\t\t options = this.options;\n\n\t\tif (options.html instanceof Element) {\n\t\t\tempty(div);\n\t\t\tdiv.appendChild(options.html);\n\t\t} else {\n\t\t\tdiv.innerHTML = options.html !== false ? options.html : '';\n\t\t}\n\n\t\tif (options.bgPos) {\n\t\t\tvar bgPos = point(options.bgPos);\n\t\t\tdiv.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';\n\t\t}\n\t\tthis._setIconStyles(div, 'icon');\n\n\t\treturn div;\n\t},\n\n\tcreateShadow: function () {\n\t\treturn null;\n\t}\n});\n\n// @factory L.divIcon(options: DivIcon options)\n// Creates a `DivIcon` instance with the given options.\nexport function divIcon(options) {\n\treturn new DivIcon(options);\n}\n","import {Icon} from './Icon';\nexport {icon} from './Icon';\nimport {IconDefault} from './Icon.Default';\nIcon.Default = IconDefault;\nexport {Icon};\n\nexport {DivIcon, divIcon} from './DivIcon';\nexport {Marker, marker} from './Marker';\n","import {Layer} from '../Layer';\nimport Browser from '../../core/Browser';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {Point} from '../../geometry/Point';\nimport {Bounds} from '../../geometry/Bounds';\nimport {LatLngBounds, toLatLngBounds as latLngBounds} from '../../geo/LatLngBounds';\n\n/*\n * @class GridLayer\n * @inherits Layer\n * @aka L.GridLayer\n *\n * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.\n * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.\n *\n *\n * @section Synchronous usage\n * @example\n *\n * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords){\n * // create a <canvas> element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // get a canvas context and draw something on it using coords.x, coords.y and coords.z\n * var ctx = tile.getContext('2d');\n *\n * // return the tile so it can be rendered on screen\n * return tile;\n * }\n * });\n * ```\n *\n * @section Asynchronous usage\n * @example\n *\n * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords, done){\n * var error;\n *\n * // create a <canvas> element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // draw something asynchronously and pass the tile to the done() callback\n * setTimeout(function() {\n * done(error, tile);\n * }, 1000);\n *\n * return tile;\n * }\n * });\n * ```\n *\n * @section\n */\n\n\nexport var GridLayer = Layer.extend({\n\n\t// @section\n\t// @aka GridLayer options\n\toptions: {\n\t\t// @option tileSize: Number|Point = 256\n\t\t// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.\n\t\ttileSize: 256,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Opacity of the tiles. Can be used in the `createTile()` function.\n\t\topacity: 1,\n\n\t\t// @option updateWhenIdle: Boolean = (depends)\n\t\t// Load new tiles only when panning ends.\n\t\t// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.\n\t\t// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the\n\t\t// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.\n\t\tupdateWhenIdle: Browser.mobile,\n\n\t\t// @option updateWhenZooming: Boolean = true\n\t\t// By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.\n\t\tupdateWhenZooming: true,\n\n\t\t// @option updateInterval: Number = 200\n\t\t// Tiles will not update more than once every `updateInterval` milliseconds when panning.\n\t\tupdateInterval: 200,\n\n\t\t// @option zIndex: Number = 1\n\t\t// The explicit zIndex of the tile layer.\n\t\tzIndex: 1,\n\n\t\t// @option bounds: LatLngBounds = undefined\n\t\t// If set, tiles will only be loaded inside the set `LatLngBounds`.\n\t\tbounds: null,\n\n\t\t// @option minZoom: Number = 0\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\n\t\tminZoom: 0,\n\n\t\t// @option maxZoom: Number = undefined\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\n\t\tmaxZoom: undefined,\n\n\t\t// @option maxNativeZoom: Number = undefined\n\t\t// Maximum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded\n\t\t// from `maxNativeZoom` level and auto-scaled.\n\t\tmaxNativeZoom: undefined,\n\n\t\t// @option minNativeZoom: Number = undefined\n\t\t// Minimum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels lower than `minNativeZoom` will be loaded\n\t\t// from `minNativeZoom` level and auto-scaled.\n\t\tminNativeZoom: undefined,\n\n\t\t// @option noWrap: Boolean = false\n\t\t// Whether the layer is wrapped around the antimeridian. If `true`, the\n\t\t// GridLayer will only be displayed once at low zoom levels. Has no\n\t\t// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used\n\t\t// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting\n\t\t// tiles outside the CRS limits.\n\t\tnoWrap: false,\n\n\t\t// @option pane: String = 'tilePane'\n\t\t// `Map pane` where the grid layer will be added.\n\t\tpane: 'tilePane',\n\n\t\t// @option className: String = ''\n\t\t// A custom class name to assign to the tile layer. Empty by default.\n\t\tclassName: '',\n\n\t\t// @option keepBuffer: Number = 2\n\t\t// When panning the map, keep this many rows and columns of tiles before unloading them.\n\t\tkeepBuffer: 2\n\t},\n\n\tinitialize: function (options) {\n\t\tUtil.setOptions(this, options);\n\t},\n\n\tonAdd: function () {\n\t\tthis._initContainer();\n\n\t\tthis._levels = {};\n\t\tthis._tiles = {};\n\n\t\tthis._resetView(); // implicit _update() call\n\t},\n\n\tbeforeAdd: function (map) {\n\t\tmap._addZoomLimit(this);\n\t},\n\n\tonRemove: function (map) {\n\t\tthis._removeAllTiles();\n\t\tDomUtil.remove(this._container);\n\t\tmap._removeZoomLimit(this);\n\t\tthis._container = null;\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t// @method bringToFront: this\n\t// Brings the tile layer to the top of all tile layers.\n\tbringToFront: function () {\n\t\tif (this._map) {\n\t\t\tDomUtil.toFront(this._container);\n\t\t\tthis._setAutoZIndex(Math.max);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack: this\n\t// Brings the tile layer to the bottom of all tile layers.\n\tbringToBack: function () {\n\t\tif (this._map) {\n\t\t\tDomUtil.toBack(this._container);\n\t\t\tthis._setAutoZIndex(Math.min);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getContainer: HTMLElement\n\t// Returns the HTML element that contains the tiles for this layer.\n\tgetContainer: function () {\n\t\treturn this._container;\n\t},\n\n\t// @method setOpacity(opacity: Number): this\n\t// Changes the [opacity](#gridlayer-opacity) of the grid layer.\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\t\tthis._updateOpacity();\n\t\treturn this;\n\t},\n\n\t// @method setZIndex(zIndex: Number): this\n\t// Changes the [zIndex](#gridlayer-zindex) of the grid layer.\n\tsetZIndex: function (zIndex) {\n\t\tthis.options.zIndex = zIndex;\n\t\tthis._updateZIndex();\n\n\t\treturn this;\n\t},\n\n\t// @method isLoading: Boolean\n\t// Returns `true` if any tile in the grid layer has not finished loading.\n\tisLoading: function () {\n\t\treturn this._loading;\n\t},\n\n\t// @method redraw: this\n\t// Causes the layer to clear all the tiles and request them again.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._removeAllTiles();\n\t\t\tvar tileZoom = this._clampZoom(this._map.getZoom());\n\t\t\tif (tileZoom !== this._tileZoom) {\n\t\t\t\tthis._tileZoom = tileZoom;\n\t\t\t\tthis._updateLevels();\n\t\t\t}\n\t\t\tthis._update();\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewprereset: this._invalidateAll,\n\t\t\tviewreset: this._resetView,\n\t\t\tzoom: this._resetView,\n\t\t\tmoveend: this._onMoveEnd\n\t\t};\n\n\t\tif (!this.options.updateWhenIdle) {\n\t\t\t// update tiles on move, but not more often than once per given interval\n\t\t\tif (!this._onMove) {\n\t\t\t\tthis._onMove = Util.throttle(this._onMoveEnd, this.options.updateInterval, this);\n\t\t\t}\n\n\t\t\tevents.move = this._onMove;\n\t\t}\n\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._animateZoom;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t// @section Extension methods\n\t// Layers extending `GridLayer` shall reimplement the following method.\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\n\t// Called only internally, must be overridden by classes extending `GridLayer`.\n\t// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback\n\t// is specified, it must be called when the tile has finished loading and drawing.\n\tcreateTile: function () {\n\t\treturn document.createElement('div');\n\t},\n\n\t// @section\n\t// @method getTileSize: Point\n\t// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.\n\tgetTileSize: function () {\n\t\tvar s = this.options.tileSize;\n\t\treturn s instanceof Point ? s : new Point(s, s);\n\t},\n\n\t_updateZIndex: function () {\n\t\tif (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {\n\t\t\tthis._container.style.zIndex = this.options.zIndex;\n\t\t}\n\t},\n\n\t_setAutoZIndex: function (compare) {\n\t\t// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)\n\n\t\tvar layers = this.getPane().children,\n\t\t edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min\n\n\t\tfor (var i = 0, len = layers.length, zIndex; i < len; i++) {\n\n\t\t\tzIndex = layers[i].style.zIndex;\n\n\t\t\tif (layers[i] !== this._container && zIndex) {\n\t\t\t\tedgeZIndex = compare(edgeZIndex, +zIndex);\n\t\t\t}\n\t\t}\n\n\t\tif (isFinite(edgeZIndex)) {\n\t\t\tthis.options.zIndex = edgeZIndex + compare(-1, 1);\n\t\t\tthis._updateZIndex();\n\t\t}\n\t},\n\n\t_updateOpacity: function () {\n\t\tif (!this._map) { return; }\n\n\t\t// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles\n\t\tif (Browser.ielt9) { return; }\n\n\t\tDomUtil.setOpacity(this._container, this.options.opacity);\n\n\t\tvar now = +new Date(),\n\t\t nextFrame = false,\n\t\t willPrune = false;\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar tile = this._tiles[key];\n\t\t\tif (!tile.current || !tile.loaded) { continue; }\n\n\t\t\tvar fade = Math.min(1, (now - tile.loaded) / 200);\n\n\t\t\tDomUtil.setOpacity(tile.el, fade);\n\t\t\tif (fade < 1) {\n\t\t\t\tnextFrame = true;\n\t\t\t} else {\n\t\t\t\tif (tile.active) {\n\t\t\t\t\twillPrune = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis._onOpaqueTile(tile);\n\t\t\t\t}\n\t\t\t\ttile.active = true;\n\t\t\t}\n\t\t}\n\n\t\tif (willPrune && !this._noPrune) { this._pruneTiles(); }\n\n\t\tif (nextFrame) {\n\t\t\tUtil.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = Util.requestAnimFrame(this._updateOpacity, this);\n\t\t}\n\t},\n\n\t_onOpaqueTile: Util.falseFn,\n\n\t_initContainer: function () {\n\t\tif (this._container) { return; }\n\n\t\tthis._container = DomUtil.create('div', 'leaflet-layer ' + (this.options.className || ''));\n\t\tthis._updateZIndex();\n\n\t\tif (this.options.opacity < 1) {\n\t\t\tthis._updateOpacity();\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t},\n\n\t_updateLevels: function () {\n\n\t\tvar zoom = this._tileZoom,\n\t\t maxZoom = this.options.maxZoom;\n\n\t\tif (zoom === undefined) { return undefined; }\n\n\t\tfor (var z in this._levels) {\n\t\t\tz = Number(z);\n\t\t\tif (this._levels[z].el.children.length || z === zoom) {\n\t\t\t\tthis._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);\n\t\t\t\tthis._onUpdateLevel(z);\n\t\t\t} else {\n\t\t\t\tDomUtil.remove(this._levels[z].el);\n\t\t\t\tthis._removeTilesAtZoom(z);\n\t\t\t\tthis._onRemoveLevel(z);\n\t\t\t\tdelete this._levels[z];\n\t\t\t}\n\t\t}\n\n\t\tvar level = this._levels[zoom],\n\t\t map = this._map;\n\n\t\tif (!level) {\n\t\t\tlevel = this._levels[zoom] = {};\n\n\t\t\tlevel.el = DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);\n\t\t\tlevel.el.style.zIndex = maxZoom;\n\n\t\t\tlevel.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();\n\t\t\tlevel.zoom = zoom;\n\n\t\t\tthis._setZoomTransform(level, map.getCenter(), map.getZoom());\n\n\t\t\t// force the browser to consider the newly added element for transition\n\t\t\tUtil.falseFn(level.el.offsetWidth);\n\n\t\t\tthis._onCreateLevel(level);\n\t\t}\n\n\t\tthis._level = level;\n\n\t\treturn level;\n\t},\n\n\t_onUpdateLevel: Util.falseFn,\n\n\t_onRemoveLevel: Util.falseFn,\n\n\t_onCreateLevel: Util.falseFn,\n\n\t_pruneTiles: function () {\n\t\tif (!this._map) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar key, tile;\n\n\t\tvar zoom = this._map.getZoom();\n\t\tif (zoom > this.options.maxZoom ||\n\t\t\tzoom < this.options.minZoom) {\n\t\t\tthis._removeAllTiles();\n\t\t\treturn;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\ttile.retain = tile.current;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\tif (tile.current && !tile.active) {\n\t\t\t\tvar coords = tile.coords;\n\t\t\t\tif (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {\n\t\t\t\t\tthis._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\tif (!this._tiles[key].retain) {\n\t\t\t\tthis._removeTile(key);\n\t\t\t}\n\t\t}\n\t},\n\n\t_removeTilesAtZoom: function (zoom) {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (this._tiles[key].coords.z !== zoom) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_removeAllTiles: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_invalidateAll: function () {\n\t\tfor (var z in this._levels) {\n\t\t\tDomUtil.remove(this._levels[z].el);\n\t\t\tthis._onRemoveLevel(Number(z));\n\t\t\tdelete this._levels[z];\n\t\t}\n\t\tthis._removeAllTiles();\n\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t_retainParent: function (x, y, z, minZoom) {\n\t\tvar x2 = Math.floor(x / 2),\n\t\t y2 = Math.floor(y / 2),\n\t\t z2 = z - 1,\n\t\t coords2 = new Point(+x2, +y2);\n\t\tcoords2.z = +z2;\n\n\t\tvar key = this._tileCoordsToKey(coords2),\n\t\t tile = this._tiles[key];\n\n\t\tif (tile && tile.active) {\n\t\t\ttile.retain = true;\n\t\t\treturn true;\n\n\t\t} else if (tile && tile.loaded) {\n\t\t\ttile.retain = true;\n\t\t}\n\n\t\tif (z2 > minZoom) {\n\t\t\treturn this._retainParent(x2, y2, z2, minZoom);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_retainChildren: function (x, y, z, maxZoom) {\n\n\t\tfor (var i = 2 * x; i < 2 * x + 2; i++) {\n\t\t\tfor (var j = 2 * y; j < 2 * y + 2; j++) {\n\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = z + 1;\n\n\t\t\t\tvar key = this._tileCoordsToKey(coords),\n\t\t\t\t tile = this._tiles[key];\n\n\t\t\t\tif (tile && tile.active) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t\tcontinue;\n\n\t\t\t\t} else if (tile && tile.loaded) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t}\n\n\t\t\t\tif (z + 1 < maxZoom) {\n\t\t\t\t\tthis._retainChildren(i, j, z + 1, maxZoom);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetView: function (e) {\n\t\tvar animating = e && (e.pinch || e.flyTo);\n\t\tthis._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);\n\t},\n\n\t_animateZoom: function (e) {\n\t\tthis._setView(e.center, e.zoom, true, e.noUpdate);\n\t},\n\n\t_clampZoom: function (zoom) {\n\t\tvar options = this.options;\n\n\t\tif (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {\n\t\t\treturn options.minNativeZoom;\n\t\t}\n\n\t\tif (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {\n\t\t\treturn options.maxNativeZoom;\n\t\t}\n\n\t\treturn zoom;\n\t},\n\n\t_setView: function (center, zoom, noPrune, noUpdate) {\n\t\tvar tileZoom = Math.round(zoom);\n\t\tif ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||\n\t\t (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {\n\t\t\ttileZoom = undefined;\n\t\t} else {\n\t\t\ttileZoom = this._clampZoom(tileZoom);\n\t\t}\n\n\t\tvar tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);\n\n\t\tif (!noUpdate || tileZoomChanged) {\n\n\t\t\tthis._tileZoom = tileZoom;\n\n\t\t\tif (this._abortLoading) {\n\t\t\t\tthis._abortLoading();\n\t\t\t}\n\n\t\t\tthis._updateLevels();\n\t\t\tthis._resetGrid();\n\n\t\t\tif (tileZoom !== undefined) {\n\t\t\t\tthis._update(center);\n\t\t\t}\n\n\t\t\tif (!noPrune) {\n\t\t\t\tthis._pruneTiles();\n\t\t\t}\n\n\t\t\t// Flag to prevent _updateOpacity from pruning tiles during\n\t\t\t// a zoom anim or a pinch gesture\n\t\t\tthis._noPrune = !!noPrune;\n\t\t}\n\n\t\tthis._setZoomTransforms(center, zoom);\n\t},\n\n\t_setZoomTransforms: function (center, zoom) {\n\t\tfor (var i in this._levels) {\n\t\t\tthis._setZoomTransform(this._levels[i], center, zoom);\n\t\t}\n\t},\n\n\t_setZoomTransform: function (level, center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, level.zoom),\n\t\t translate = level.origin.multiplyBy(scale)\n\t\t .subtract(this._map._getNewPixelOrigin(center, zoom)).round();\n\n\t\tif (Browser.any3d) {\n\t\t\tDomUtil.setTransform(level.el, translate, scale);\n\t\t} else {\n\t\t\tDomUtil.setPosition(level.el, translate);\n\t\t}\n\t},\n\n\t_resetGrid: function () {\n\t\tvar map = this._map,\n\t\t crs = map.options.crs,\n\t\t tileSize = this._tileSize = this.getTileSize(),\n\t\t tileZoom = this._tileZoom;\n\n\t\tvar bounds = this._map.getPixelWorldBounds(this._tileZoom);\n\t\tif (bounds) {\n\t\t\tthis._globalTileRange = this._pxBoundsToTileRange(bounds);\n\t\t}\n\n\t\tthis._wrapX = crs.wrapLng && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),\n\t\t\tMath.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)\n\t\t];\n\t\tthis._wrapY = crs.wrapLat && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),\n\t\t\tMath.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)\n\t\t];\n\t},\n\n\t_onMoveEnd: function () {\n\t\tif (!this._map || this._map._animatingZoom) { return; }\n\n\t\tthis._update();\n\t},\n\n\t_getTiledPixelBounds: function (center) {\n\t\tvar map = this._map,\n\t\t mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),\n\t\t scale = map.getZoomScale(mapZoom, this._tileZoom),\n\t\t pixelCenter = map.project(center, this._tileZoom).floor(),\n\t\t halfSize = map.getSize().divideBy(scale * 2);\n\n\t\treturn new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));\n\t},\n\n\t// Private method to load tiles in the grid's active zoom level according to map bounds\n\t_update: function (center) {\n\t\tvar map = this._map;\n\t\tif (!map) { return; }\n\t\tvar zoom = this._clampZoom(map.getZoom());\n\n\t\tif (center === undefined) { center = map.getCenter(); }\n\t\tif (this._tileZoom === undefined) { return; }\t// if out of minzoom/maxzoom\n\n\t\tvar pixelBounds = this._getTiledPixelBounds(center),\n\t\t tileRange = this._pxBoundsToTileRange(pixelBounds),\n\t\t tileCenter = tileRange.getCenter(),\n\t\t queue = [],\n\t\t margin = this.options.keepBuffer,\n\t\t noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),\n\t\t tileRange.getTopRight().add([margin, -margin]));\n\n\t\t// Sanity check: panic if the tile range contains Infinity somewhere.\n\t\tif (!(isFinite(tileRange.min.x) &&\n\t\t isFinite(tileRange.min.y) &&\n\t\t isFinite(tileRange.max.x) &&\n\t\t isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar c = this._tiles[key].coords;\n\t\t\tif (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {\n\t\t\t\tthis._tiles[key].current = false;\n\t\t\t}\n\t\t}\n\n\t\t// _update just loads more tiles. If the tile zoom level differs too much\n\t\t// from the map's, let _setView reset levels and prune old tiles.\n\t\tif (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }\n\n\t\t// create a queue of coordinates to load tiles from\n\t\tfor (var j = tileRange.min.y; j <= tileRange.max.y; j++) {\n\t\t\tfor (var i = tileRange.min.x; i <= tileRange.max.x; i++) {\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = this._tileZoom;\n\n\t\t\t\tif (!this._isValidTile(coords)) { continue; }\n\n\t\t\t\tvar tile = this._tiles[this._tileCoordsToKey(coords)];\n\t\t\t\tif (tile) {\n\t\t\t\t\ttile.current = true;\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push(coords);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sort tile queue to load tiles in order of their distance to center\n\t\tqueue.sort(function (a, b) {\n\t\t\treturn a.distanceTo(tileCenter) - b.distanceTo(tileCenter);\n\t\t});\n\n\t\tif (queue.length !== 0) {\n\t\t\t// if it's the first batch of tiles to load\n\t\t\tif (!this._loading) {\n\t\t\t\tthis._loading = true;\n\t\t\t\t// @event loading: Event\n\t\t\t\t// Fired when the grid layer starts loading tiles.\n\t\t\t\tthis.fire('loading');\n\t\t\t}\n\n\t\t\t// create DOM fragment to append tiles in one batch\n\t\t\tvar fragment = document.createDocumentFragment();\n\n\t\t\tfor (i = 0; i < queue.length; i++) {\n\t\t\t\tthis._addTile(queue[i], fragment);\n\t\t\t}\n\n\t\t\tthis._level.el.appendChild(fragment);\n\t\t}\n\t},\n\n\t_isValidTile: function (coords) {\n\t\tvar crs = this._map.options.crs;\n\n\t\tif (!crs.infinite) {\n\t\t\t// don't load tile if it's out of bounds and not wrapped\n\t\t\tvar bounds = this._globalTileRange;\n\t\t\tif ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||\n\t\t\t (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }\n\t\t}\n\n\t\tif (!this.options.bounds) { return true; }\n\n\t\t// don't load tile if it doesn't intersect the bounds in options\n\t\tvar tileBounds = this._tileCoordsToBounds(coords);\n\t\treturn latLngBounds(this.options.bounds).overlaps(tileBounds);\n\t},\n\n\t_keyToBounds: function (key) {\n\t\treturn this._tileCoordsToBounds(this._keyToTileCoords(key));\n\t},\n\n\t_tileCoordsToNwSe: function (coords) {\n\t\tvar map = this._map,\n\t\t tileSize = this.getTileSize(),\n\t\t nwPoint = coords.scaleBy(tileSize),\n\t\t sePoint = nwPoint.add(tileSize),\n\t\t nw = map.unproject(nwPoint, coords.z),\n\t\t se = map.unproject(sePoint, coords.z);\n\t\treturn [nw, se];\n\t},\n\n\t// converts tile coordinates to its geographical bounds\n\t_tileCoordsToBounds: function (coords) {\n\t\tvar bp = this._tileCoordsToNwSe(coords),\n\t\t bounds = new LatLngBounds(bp[0], bp[1]);\n\n\t\tif (!this.options.noWrap) {\n\t\t\tbounds = this._map.wrapLatLngBounds(bounds);\n\t\t}\n\t\treturn bounds;\n\t},\n\t// converts tile coordinates to key for the tile cache\n\t_tileCoordsToKey: function (coords) {\n\t\treturn coords.x + ':' + coords.y + ':' + coords.z;\n\t},\n\n\t// converts tile cache key to coordinates\n\t_keyToTileCoords: function (key) {\n\t\tvar k = key.split(':'),\n\t\t coords = new Point(+k[0], +k[1]);\n\t\tcoords.z = +k[2];\n\t\treturn coords;\n\t},\n\n\t_removeTile: function (key) {\n\t\tvar tile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\tDomUtil.remove(tile.el);\n\n\t\tdelete this._tiles[key];\n\n\t\t// @event tileunload: TileEvent\n\t\t// Fired when a tile is removed (e.g. when a tile goes off the screen).\n\t\tthis.fire('tileunload', {\n\t\t\ttile: tile.el,\n\t\t\tcoords: this._keyToTileCoords(key)\n\t\t});\n\t},\n\n\t_initTile: function (tile) {\n\t\tDomUtil.addClass(tile, 'leaflet-tile');\n\n\t\tvar tileSize = this.getTileSize();\n\t\ttile.style.width = tileSize.x + 'px';\n\t\ttile.style.height = tileSize.y + 'px';\n\n\t\ttile.onselectstart = Util.falseFn;\n\t\ttile.onmousemove = Util.falseFn;\n\n\t\t// update opacity on tiles in IE7-8 because of filter inheritance problems\n\t\tif (Browser.ielt9 && this.options.opacity < 1) {\n\t\t\tDomUtil.setOpacity(tile, this.options.opacity);\n\t\t}\n\t},\n\n\t_addTile: function (coords, container) {\n\t\tvar tilePos = this._getTilePos(coords),\n\t\t key = this._tileCoordsToKey(coords);\n\n\t\tvar tile = this.createTile(this._wrapCoords(coords), Util.bind(this._tileReady, this, coords));\n\n\t\tthis._initTile(tile);\n\n\t\t// if createTile is defined with a second argument (\"done\" callback),\n\t\t// we know that tile is async and will be ready later; otherwise\n\t\tif (this.createTile.length < 2) {\n\t\t\t// mark tile as ready, but delay one frame for opacity animation to happen\n\t\t\tUtil.requestAnimFrame(Util.bind(this._tileReady, this, coords, null, tile));\n\t\t}\n\n\t\tDomUtil.setPosition(tile, tilePos);\n\n\t\t// save tile in cache\n\t\tthis._tiles[key] = {\n\t\t\tel: tile,\n\t\t\tcoords: coords,\n\t\t\tcurrent: true\n\t\t};\n\n\t\tcontainer.appendChild(tile);\n\t\t// @event tileloadstart: TileEvent\n\t\t// Fired when a tile is requested and starts loading.\n\t\tthis.fire('tileloadstart', {\n\t\t\ttile: tile,\n\t\t\tcoords: coords\n\t\t});\n\t},\n\n\t_tileReady: function (coords, err, tile) {\n\t\tif (err) {\n\t\t\t// @event tileerror: TileErrorEvent\n\t\t\t// Fired when there is an error loading a tile.\n\t\t\tthis.fire('tileerror', {\n\t\t\t\terror: err,\n\t\t\t\ttile: tile,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tvar key = this._tileCoordsToKey(coords);\n\n\t\ttile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\ttile.loaded = +new Date();\n\t\tif (this._map._fadeAnimated) {\n\t\t\tDomUtil.setOpacity(tile.el, 0);\n\t\t\tUtil.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = Util.requestAnimFrame(this._updateOpacity, this);\n\t\t} else {\n\t\t\ttile.active = true;\n\t\t\tthis._pruneTiles();\n\t\t}\n\n\t\tif (!err) {\n\t\t\tDomUtil.addClass(tile.el, 'leaflet-tile-loaded');\n\n\t\t\t// @event tileload: TileEvent\n\t\t\t// Fired when a tile loads.\n\t\t\tthis.fire('tileload', {\n\t\t\t\ttile: tile.el,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tif (this._noTilesToLoad()) {\n\t\t\tthis._loading = false;\n\t\t\t// @event load: Event\n\t\t\t// Fired when the grid layer loaded all visible tiles.\n\t\t\tthis.fire('load');\n\n\t\t\tif (Browser.ielt9 || !this._map._fadeAnimated) {\n\t\t\t\tUtil.requestAnimFrame(this._pruneTiles, this);\n\t\t\t} else {\n\t\t\t\t// Wait a bit more than 0.2 secs (the duration of the tile fade-in)\n\t\t\t\t// to trigger a pruning.\n\t\t\t\tsetTimeout(Util.bind(this._pruneTiles, this), 250);\n\t\t\t}\n\t\t}\n\t},\n\n\t_getTilePos: function (coords) {\n\t\treturn coords.scaleBy(this.getTileSize()).subtract(this._level.origin);\n\t},\n\n\t_wrapCoords: function (coords) {\n\t\tvar newCoords = new Point(\n\t\t\tthis._wrapX ? Util.wrapNum(coords.x, this._wrapX) : coords.x,\n\t\t\tthis._wrapY ? Util.wrapNum(coords.y, this._wrapY) : coords.y);\n\t\tnewCoords.z = coords.z;\n\t\treturn newCoords;\n\t},\n\n\t_pxBoundsToTileRange: function (bounds) {\n\t\tvar tileSize = this.getTileSize();\n\t\treturn new Bounds(\n\t\t\tbounds.min.unscaleBy(tileSize).floor(),\n\t\t\tbounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));\n\t},\n\n\t_noTilesToLoad: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (!this._tiles[key].loaded) { return false; }\n\t\t}\n\t\treturn true;\n\t}\n});\n\n// @factory L.gridLayer(options?: GridLayer options)\n// Creates a new instance of GridLayer with the supplied options.\nexport function gridLayer(options) {\n\treturn new GridLayer(options);\n}\n","import {GridLayer} from './GridLayer';\r\nimport Browser from '../../core/Browser';\r\nimport * as Util from '../../core/Util';\r\nimport * as DomEvent from '../../dom/DomEvent';\r\nimport * as DomUtil from '../../dom/DomUtil';\r\n\r\n\r\n/*\r\n * @class TileLayer\r\n * @inherits GridLayer\r\n * @aka L.TileLayer\r\n * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors'}).addTo(map);\n * ```\r\n *\r\n * @section URL template\r\n * @example\r\n *\r\n * A string of the following form:\r\n *\r\n * ```\r\n * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\r\n * ```\r\n *\r\n * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add \"&commat;2x\" to the URL to load retina tiles.\r\n *\r\n * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:\r\n *\r\n * ```\r\n * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\r\n * ```\r\n */\r\n\r\n\r\nexport var TileLayer = GridLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer options\r\n\toptions: {\r\n\t\t// @option minZoom: Number = 0\r\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\r\n\t\tminZoom: 0,\r\n\r\n\t\t// @option maxZoom: Number = 18\r\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\r\n\t\tmaxZoom: 18,\r\n\r\n\t\t// @option subdomains: String|String[] = 'abc'\r\n\t\t// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.\r\n\t\tsubdomains: 'abc',\r\n\r\n\t\t// @option errorTileUrl: String = ''\r\n\t\t// URL to the tile image to show in place of the tile that failed to load.\r\n\t\terrorTileUrl: '',\r\n\r\n\t\t// @option zoomOffset: Number = 0\r\n\t\t// The zoom number used in tile URLs will be offset with this value.\r\n\t\tzoomOffset: 0,\r\n\r\n\t\t// @option tms: Boolean = false\r\n\t\t// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).\r\n\t\ttms: false,\r\n\r\n\t\t// @option zoomReverse: Boolean = false\r\n\t\t// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)\r\n\t\tzoomReverse: false,\r\n\r\n\t\t// @option detectRetina: Boolean = false\r\n\t\t// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.\r\n\t\tdetectRetina: false,\r\n\r\n\t\t// @option crossOrigin: Boolean|String = false\r\n\t\t// Whether the crossOrigin attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.\r\n\t\t// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.\r\n\t\tcrossOrigin: false,\r\n\r\n\t\t// @option referrerPolicy: Boolean|String = false\r\n\t\t// Whether the referrerPolicy attribute will be added to the tiles.\r\n\t\t// If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.\r\n\t\t// This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer\r\n\t\t// (e.g. to validate an API token).\r\n\t\t// Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.\r\n\t\treferrerPolicy: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\toptions = Util.setOptions(this, options);\r\n\r\n\t\t// detecting retina displays, adjusting tileSize and zoom levels\r\n\t\tif (options.detectRetina && Browser.retina && options.maxZoom > 0) {\r\n\r\n\t\t\toptions.tileSize = Math.floor(options.tileSize / 2);\r\n\r\n\t\t\tif (!options.zoomReverse) {\r\n\t\t\t\toptions.zoomOffset++;\r\n\t\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);\r\n\t\t\t} else {\r\n\t\t\t\toptions.zoomOffset--;\r\n\t\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom + 1);\r\n\t\t\t}\r\n\r\n\t\t\toptions.minZoom = Math.max(0, options.minZoom);\r\n\t\t} else if (!options.zoomReverse) {\r\n\t\t\t// make sure maxZoom is gte minZoom\r\n\t\t\toptions.maxZoom = Math.max(options.minZoom, options.maxZoom);\r\n\t\t} else {\r\n\t\t\t// make sure minZoom is lte maxZoom\r\n\t\t\toptions.minZoom = Math.min(options.maxZoom, options.minZoom);\r\n\t\t}\r\n\r\n\t\tif (typeof options.subdomains === 'string') {\r\n\t\t\toptions.subdomains = options.subdomains.split('');\r\n\t\t}\r\n\r\n\t\tthis.on('tileunload', this._onTileRemove);\r\n\t},\r\n\r\n\t// @method setUrl(url: String, noRedraw?: Boolean): this\r\n\t// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).\r\n\t// If the URL does not change, the layer will not be redrawn unless\r\n\t// the noRedraw parameter is set to false.\r\n\tsetUrl: function (url, noRedraw) {\r\n\t\tif (this._url === url && noRedraw === undefined) {\r\n\t\t\tnoRedraw = true;\r\n\t\t}\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\r\n\t// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)\r\n\t// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`\r\n\t// callback is called when the tile has been loaded.\r\n\tcreateTile: function (coords, done) {\r\n\t\tvar tile = document.createElement('img');\r\n\r\n\t\tDomEvent.on(tile, 'load', Util.bind(this._tileOnLoad, this, done, tile));\r\n\t\tDomEvent.on(tile, 'error', Util.bind(this._tileOnError, this, done, tile));\r\n\r\n\t\tif (this.options.crossOrigin || this.options.crossOrigin === '') {\r\n\t\t\ttile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;\r\n\t\t}\r\n\r\n\t\t// for this new option we follow the documented behavior\r\n\t\t// more closely by only setting the property when string\r\n\t\tif (typeof this.options.referrerPolicy === 'string') {\r\n\t\t\ttile.referrerPolicy = this.options.referrerPolicy;\r\n\t\t}\r\n\r\n\t\t// The alt attribute is set to the empty string,\r\n\t\t// allowing screen readers to ignore the decorative image tiles.\r\n\t\t// https://www.w3.org/WAI/tutorials/images/decorative/\r\n\t\t// https://www.w3.org/TR/html-aria/#el-img-empty-alt\r\n\t\ttile.alt = '';\r\n\r\n\t\ttile.src = this.getTileUrl(coords);\r\n\r\n\t\treturn tile;\r\n\t},\r\n\r\n\t// @section Extension methods\r\n\t// @uninheritable\r\n\t// Layers extending `TileLayer` might reimplement the following method.\r\n\t// @method getTileUrl(coords: Object): String\r\n\t// Called only internally, returns the URL for a tile given its coordinates.\r\n\t// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.\r\n\tgetTileUrl: function (coords) {\r\n\t\tvar data = {\r\n\t\t\tr: Browser.retina ? '@2x' : '',\r\n\t\t\ts: this._getSubdomain(coords),\r\n\t\t\tx: coords.x,\r\n\t\t\ty: coords.y,\r\n\t\t\tz: this._getZoomForUrl()\r\n\t\t};\r\n\t\tif (this._map && !this._map.options.crs.infinite) {\r\n\t\t\tvar invertedY = this._globalTileRange.max.y - coords.y;\r\n\t\t\tif (this.options.tms) {\r\n\t\t\t\tdata['y'] = invertedY;\r\n\t\t\t}\r\n\t\t\tdata['-y'] = invertedY;\r\n\t\t}\r\n\r\n\t\treturn Util.template(this._url, Util.extend(data, this.options));\r\n\t},\r\n\r\n\t_tileOnLoad: function (done, tile) {\r\n\t\t// For https://github.com/Leaflet/Leaflet/issues/3332\r\n\t\tif (Browser.ielt9) {\r\n\t\t\tsetTimeout(Util.bind(done, this, null, tile), 0);\r\n\t\t} else {\r\n\t\t\tdone(null, tile);\r\n\t\t}\r\n\t},\r\n\r\n\t_tileOnError: function (done, tile, e) {\r\n\t\tvar errorUrl = this.options.errorTileUrl;\r\n\t\tif (errorUrl && tile.getAttribute('src') !== errorUrl) {\r\n\t\t\ttile.src = errorUrl;\r\n\t\t}\r\n\t\tdone(e, tile);\r\n\t},\r\n\r\n\t_onTileRemove: function (e) {\r\n\t\te.tile.onload = null;\r\n\t},\r\n\r\n\t_getZoomForUrl: function () {\r\n\t\tvar zoom = this._tileZoom,\r\n\t\tmaxZoom = this.options.maxZoom,\r\n\t\tzoomReverse = this.options.zoomReverse,\r\n\t\tzoomOffset = this.options.zoomOffset;\r\n\r\n\t\tif (zoomReverse) {\r\n\t\t\tzoom = maxZoom - zoom;\r\n\t\t}\r\n\r\n\t\treturn zoom + zoomOffset;\r\n\t},\r\n\r\n\t_getSubdomain: function (tilePoint) {\r\n\t\tvar index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;\r\n\t\treturn this.options.subdomains[index];\r\n\t},\r\n\r\n\t// stops loading all tiles in the background layer\r\n\t_abortLoading: function () {\r\n\t\tvar i, tile;\r\n\t\tfor (i in this._tiles) {\r\n\t\t\tif (this._tiles[i].coords.z !== this._tileZoom) {\r\n\t\t\t\ttile = this._tiles[i].el;\r\n\r\n\t\t\t\ttile.onload = Util.falseFn;\r\n\t\t\t\ttile.onerror = Util.falseFn;\r\n\r\n\t\t\t\tif (!tile.complete) {\r\n\t\t\t\t\ttile.src = Util.emptyImageUrl;\r\n\t\t\t\t\tvar coords = this._tiles[i].coords;\r\n\t\t\t\t\tDomUtil.remove(tile);\r\n\t\t\t\t\tdelete this._tiles[i];\r\n\t\t\t\t\t// @event tileabort: TileEvent\r\n\t\t\t\t\t// Fired when a tile was loading but is now not wanted.\r\n\t\t\t\t\tthis.fire('tileabort', {\r\n\t\t\t\t\t\ttile: tile,\r\n\t\t\t\t\t\tcoords: coords\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_removeTile: function (key) {\r\n\t\tvar tile = this._tiles[key];\r\n\t\tif (!tile) { return; }\r\n\r\n\t\t// Cancels any pending http requests associated with the tile\r\n\t\ttile.el.setAttribute('src', Util.emptyImageUrl);\r\n\r\n\t\treturn GridLayer.prototype._removeTile.call(this, key);\r\n\t},\r\n\r\n\t_tileReady: function (coords, err, tile) {\r\n\t\tif (!this._map || (tile && tile.getAttribute('src') === Util.emptyImageUrl)) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\treturn GridLayer.prototype._tileReady.call(this, coords, err, tile);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)\r\n// Instantiates a tile layer object given a `URL template` and optionally an options object.\r\n\r\nexport function tileLayer(url, options) {\r\n\treturn new TileLayer(url, options);\r\n}\r\n","import {TileLayer} from './TileLayer';\r\nimport {extend, setOptions, getParamString} from '../../core/Util';\r\nimport Browser from '../../core/Browser';\r\nimport {EPSG4326} from '../../geo/crs/CRS.EPSG4326';\r\nimport {toBounds} from '../../geometry/Bounds';\r\n\r\n/*\r\n * @class TileLayer.WMS\r\n * @inherits TileLayer\r\n * @aka L.TileLayer.WMS\r\n * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var nexrad = L.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\r\n * \tlayers: 'nexrad-n0r-900913',\r\n * \tformat: 'image/png',\r\n * \ttransparent: true,\r\n * \tattribution: \"Weather data © 2012 IEM Nexrad\"\r\n * });\r\n * ```\r\n */\r\n\r\nexport var TileLayerWMS = TileLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer.WMS options\r\n\t// If any custom options not documented here are used, they will be sent to the\r\n\t// WMS server as extra parameters in each request URL. This can be useful for\r\n\t// [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html).\r\n\tdefaultWmsParams: {\r\n\t\tservice: 'WMS',\r\n\t\trequest: 'GetMap',\r\n\r\n\t\t// @option layers: String = ''\r\n\t\t// **(required)** Comma-separated list of WMS layers to show.\r\n\t\tlayers: '',\r\n\r\n\t\t// @option styles: String = ''\r\n\t\t// Comma-separated list of WMS styles.\r\n\t\tstyles: '',\r\n\r\n\t\t// @option format: String = 'image/jpeg'\r\n\t\t// WMS image format (use `'image/png'` for layers with transparency).\r\n\t\tformat: 'image/jpeg',\r\n\r\n\t\t// @option transparent: Boolean = false\r\n\t\t// If `true`, the WMS service will return images with transparency.\r\n\t\ttransparent: false,\r\n\r\n\t\t// @option version: String = '1.1.1'\r\n\t\t// Version of the WMS service to use\r\n\t\tversion: '1.1.1'\r\n\t},\r\n\r\n\toptions: {\r\n\t\t// @option crs: CRS = null\r\n\t\t// Coordinate Reference System to use for the WMS requests, defaults to\r\n\t\t// map CRS. Don't change this if you're not sure what it means.\r\n\t\tcrs: null,\r\n\r\n\t\t// @option uppercase: Boolean = false\r\n\t\t// If `true`, WMS request parameter keys will be uppercase.\r\n\t\tuppercase: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tvar wmsParams = extend({}, this.defaultWmsParams);\r\n\r\n\t\t// all keys that are not TileLayer options go to WMS params\r\n\t\tfor (var i in options) {\r\n\t\t\tif (!(i in this.options)) {\r\n\t\t\t\twmsParams[i] = options[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions = setOptions(this, options);\r\n\r\n\t\tvar realRetina = options.detectRetina && Browser.retina ? 2 : 1;\r\n\t\tvar tileSize = this.getTileSize();\r\n\t\twmsParams.width = tileSize.x * realRetina;\r\n\t\twmsParams.height = tileSize.y * realRetina;\r\n\r\n\t\tthis.wmsParams = wmsParams;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\r\n\t\tthis._crs = this.options.crs || map.options.crs;\r\n\t\tthis._wmsVersion = parseFloat(this.wmsParams.version);\r\n\r\n\t\tvar projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';\r\n\t\tthis.wmsParams[projectionKey] = this._crs.code;\r\n\r\n\t\tTileLayer.prototype.onAdd.call(this, map);\r\n\t},\r\n\r\n\tgetTileUrl: function (coords) {\r\n\r\n\t\tvar tileBounds = this._tileCoordsToNwSe(coords),\r\n\t\t crs = this._crs,\r\n\t\t bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),\r\n\t\t min = bounds.min,\r\n\t\t max = bounds.max,\r\n\t\t bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?\r\n\t\t [min.y, min.x, max.y, max.x] :\r\n\t\t [min.x, min.y, max.x, max.y]).join(','),\r\n\t\t url = TileLayer.prototype.getTileUrl.call(this, coords);\r\n\t\treturn url +\r\n\t\t\tgetParamString(this.wmsParams, url, this.options.uppercase) +\r\n\t\t\t(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;\r\n\t},\r\n\r\n\t// @method setParams(params: Object, noRedraw?: Boolean): this\r\n\t// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).\r\n\tsetParams: function (params, noRedraw) {\r\n\r\n\t\textend(this.wmsParams, params);\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)\r\n// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.\r\nexport function tileLayerWMS(url, options) {\r\n\treturn new TileLayerWMS(url, options);\r\n}\r\n","export {GridLayer, gridLayer} from './GridLayer';\nimport {TileLayer, tileLayer} from './TileLayer';\nimport {TileLayerWMS, tileLayerWMS} from './TileLayer.WMS';\nTileLayer.WMS = TileLayerWMS;\ntileLayer.wms = tileLayerWMS;\nexport {TileLayer, tileLayer};\n","import {Layer} from '../Layer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as Util from '../../core/Util';\nimport Browser from '../../core/Browser';\nimport {Bounds} from '../../geometry/Bounds';\n\n\n\n/*\n * @class Renderer\n * @inherits Layer\n * @aka L.Renderer\n *\n * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the\n * DOM container of the renderer, its bounds, and its zoom animation.\n *\n * A `Renderer` works as an implicit layer group for all `Path`s - the renderer\n * itself can be added or removed to the map. All paths use a renderer, which can\n * be implicit (the map will decide the type of renderer and use it automatically)\n * or explicit (using the [`renderer`](#path-renderer) option of the path).\n *\n * Do not use this class directly, use `SVG` and `Canvas` instead.\n *\n * @event update: Event\n * Fired when the renderer updates its bounds, center and zoom, for example when\n * its map has moved\n */\n\nexport var Renderer = Layer.extend({\n\n\t// @section\n\t// @aka Renderer options\n\toptions: {\n\t\t// @option padding: Number = 0.1\n\t\t// How much to extend the clip area around the map view (relative to its size)\n\t\t// e.g. 0.1 would be 10% of map view in each direction\n\t\tpadding: 0.1\n\t},\n\n\tinitialize: function (options) {\n\t\tUtil.setOptions(this, options);\n\t\tUtil.stamp(this);\n\t\tthis._layers = this._layers || {};\n\t},\n\n\tonAdd: function () {\n\t\tif (!this._container) {\n\t\t\tthis._initContainer(); // defined by renderer implementations\n\n\t\t\tif (this._zoomAnimated) {\n\t\t\t\tDomUtil.addClass(this._container, 'leaflet-zoom-animated');\n\t\t\t}\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t\tthis._update();\n\t\tthis.on('update', this._updatePaths, this);\n\t},\n\n\tonRemove: function () {\n\t\tthis.off('update', this._updatePaths, this);\n\t\tthis._destroyContainer();\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewreset: this._reset,\n\t\t\tzoom: this._onZoom,\n\t\t\tmoveend: this._update,\n\t\t\tzoomend: this._onZoomEnd\n\t\t};\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._onAnimZoom;\n\t\t}\n\t\treturn events;\n\t},\n\n\t_onAnimZoom: function (ev) {\n\t\tthis._updateTransform(ev.center, ev.zoom);\n\t},\n\n\t_onZoom: function () {\n\t\tthis._updateTransform(this._map.getCenter(), this._map.getZoom());\n\t},\n\n\t_updateTransform: function (center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, this._zoom),\n\t\t viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),\n\t\t currentCenterPoint = this._map.project(this._center, zoom),\n\n\t\t topLeftOffset = viewHalf.multiplyBy(-scale).add(currentCenterPoint)\n\t\t\t\t .subtract(this._map._getNewPixelOrigin(center, zoom));\n\n\t\tif (Browser.any3d) {\n\t\t\tDomUtil.setTransform(this._container, topLeftOffset, scale);\n\t\t} else {\n\t\t\tDomUtil.setPosition(this._container, topLeftOffset);\n\t\t}\n\t},\n\n\t_reset: function () {\n\t\tthis._update();\n\t\tthis._updateTransform(this._center, this._zoom);\n\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._reset();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._project();\n\t\t}\n\t},\n\n\t_updatePaths: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._update();\n\t\t}\n\t},\n\n\t_update: function () {\n\t\t// Update pixel bounds of renderer container (for positioning/sizing/clipping later)\n\t\t// Subclasses are responsible of firing the 'update' event.\n\t\tvar p = this.options.padding,\n\t\t size = this._map.getSize(),\n\t\t min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();\n\n\t\tthis._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());\n\n\t\tthis._center = this._map.getCenter();\n\t\tthis._zoom = this._map.getZoom();\n\t}\n});\n","import {Renderer} from './Renderer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport Browser from '../../core/Browser';\nimport * as Util from '../../core/Util';\nimport {Bounds} from '../../geometry/Bounds';\n\n/*\n * @class Canvas\n * @inherits Renderer\n * @aka L.Canvas\n *\n * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](https://caniuse.com/canvas), Canvas is not\n * available in all web browsers, notably IE8, and overlapping geometries might\n * not display properly in some edge cases.\n *\n * @example\n *\n * Use Canvas by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.canvas()\n * });\n * ```\n *\n * Use a Canvas renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.canvas({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nexport var Canvas = Renderer.extend({\n\n\t// @section\n\t// @aka Canvas options\n\toptions: {\n\t\t// @option tolerance: Number = 0\n\t\t// How much to extend the click tolerance around a path/object on the map.\n\t\ttolerance: 0\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = Renderer.prototype.getEvents.call(this);\n\t\tevents.viewprereset = this._onViewPreReset;\n\t\treturn events;\n\t},\n\n\t_onViewPreReset: function () {\n\t\t// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once\n\t\tthis._postponeUpdatePaths = true;\n\t},\n\n\tonAdd: function () {\n\t\tRenderer.prototype.onAdd.call(this);\n\n\t\t// Redraw vectors since canvas is cleared upon removal,\n\t\t// in case of removing the renderer itself from the map.\n\t\tthis._draw();\n\t},\n\n\t_initContainer: function () {\n\t\tvar container = this._container = document.createElement('canvas');\n\n\t\tDomEvent.on(container, 'mousemove', this._onMouseMove, this);\n\t\tDomEvent.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);\n\t\tDomEvent.on(container, 'mouseout', this._handleMouseOut, this);\n\t\tcontainer['_leaflet_disable_events'] = true;\n\n\t\tthis._ctx = container.getContext('2d');\n\t},\n\n\t_destroyContainer: function () {\n\t\tUtil.cancelAnimFrame(this._redrawRequest);\n\t\tdelete this._ctx;\n\t\tDomUtil.remove(this._container);\n\t\tDomEvent.off(this._container);\n\t\tdelete this._container;\n\t},\n\n\t_updatePaths: function () {\n\t\tif (this._postponeUpdatePaths) { return; }\n\n\t\tvar layer;\n\t\tthis._redrawBounds = null;\n\t\tfor (var id in this._layers) {\n\t\t\tlayer = this._layers[id];\n\t\t\tlayer._update();\n\t\t}\n\t\tthis._redraw();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t container = this._container,\n\t\t size = b.getSize(),\n\t\t m = Browser.retina ? 2 : 1;\n\n\t\tDomUtil.setPosition(container, b.min);\n\n\t\t// set canvas size (also clearing it); use double size on retina\n\t\tcontainer.width = m * size.x;\n\t\tcontainer.height = m * size.y;\n\t\tcontainer.style.width = size.x + 'px';\n\t\tcontainer.style.height = size.y + 'px';\n\n\t\tif (Browser.retina) {\n\t\t\tthis._ctx.scale(2, 2);\n\t\t}\n\n\t\t// translate so we use the same path coordinates after canvas element moves\n\t\tthis._ctx.translate(-b.min.x, -b.min.y);\n\n\t\t// Tell paths to redraw themselves\n\t\tthis.fire('update');\n\t},\n\n\t_reset: function () {\n\t\tRenderer.prototype._reset.call(this);\n\n\t\tif (this._postponeUpdatePaths) {\n\t\t\tthis._postponeUpdatePaths = false;\n\t\t\tthis._updatePaths();\n\t\t}\n\t},\n\n\t_initPath: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._layers[Util.stamp(layer)] = layer;\n\n\t\tvar order = layer._order = {\n\t\t\tlayer: layer,\n\t\t\tprev: this._drawLast,\n\t\t\tnext: null\n\t\t};\n\t\tif (this._drawLast) { this._drawLast.next = order; }\n\t\tthis._drawLast = order;\n\t\tthis._drawFirst = this._drawFirst || this._drawLast;\n\t},\n\n\t_addPath: function (layer) {\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\tthis._drawLast = prev;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\tdelete layer._order;\n\n\t\tdelete this._layers[Util.stamp(layer)];\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updatePath: function (layer) {\n\t\t// Redraw the union of the layer's old pixel\n\t\t// bounds and the new pixel bounds.\n\t\tthis._extendRedrawBounds(layer);\n\t\tlayer._project();\n\t\tlayer._update();\n\t\t// The redraw will extend the redraw bounds\n\t\t// with the new pixel bounds.\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateDashArray: function (layer) {\n\t\tif (typeof layer.options.dashArray === 'string') {\n\t\t\tvar parts = layer.options.dashArray.split(/[, ]+/),\n\t\t\t dashArray = [],\n\t\t\t dashValue,\n\t\t\t i;\n\t\t\tfor (i = 0; i < parts.length; i++) {\n\t\t\t\tdashValue = Number(parts[i]);\n\t\t\t\t// Ignore dash array containing invalid lengths\n\t\t\t\tif (isNaN(dashValue)) { return; }\n\t\t\t\tdashArray.push(dashValue);\n\t\t\t}\n\t\t\tlayer.options._dashArray = dashArray;\n\t\t} else {\n\t\t\tlayer.options._dashArray = layer.options.dashArray;\n\t\t}\n\t},\n\n\t_requestRedraw: function (layer) {\n\t\tif (!this._map) { return; }\n\n\t\tthis._extendRedrawBounds(layer);\n\t\tthis._redrawRequest = this._redrawRequest || Util.requestAnimFrame(this._redraw, this);\n\t},\n\n\t_extendRedrawBounds: function (layer) {\n\t\tif (layer._pxBounds) {\n\t\t\tvar padding = (layer.options.weight || 0) + 1;\n\t\t\tthis._redrawBounds = this._redrawBounds || new Bounds();\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));\n\t\t}\n\t},\n\n\t_redraw: function () {\n\t\tthis._redrawRequest = null;\n\n\t\tif (this._redrawBounds) {\n\t\t\tthis._redrawBounds.min._floor();\n\t\t\tthis._redrawBounds.max._ceil();\n\t\t}\n\n\t\tthis._clear(); // clear layers in redraw bounds\n\t\tthis._draw(); // draw layers\n\n\t\tthis._redrawBounds = null;\n\t},\n\n\t_clear: function () {\n\t\tvar bounds = this._redrawBounds;\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t} else {\n\t\t\tthis._ctx.save();\n\t\t\tthis._ctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\t\tthis._ctx.clearRect(0, 0, this._container.width, this._container.height);\n\t\t\tthis._ctx.restore();\n\t\t}\n\t},\n\n\t_draw: function () {\n\t\tvar layer, bounds = this._redrawBounds;\n\t\tthis._ctx.save();\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.beginPath();\n\t\t\tthis._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t\tthis._ctx.clip();\n\t\t}\n\n\t\tthis._drawing = true;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {\n\t\t\t\tlayer._updatePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._drawing = false;\n\n\t\tthis._ctx.restore(); // Restore state before clipping.\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tif (!this._drawing) { return; }\n\n\t\tvar i, j, len2, p,\n\t\t parts = layer._parts,\n\t\t len = parts.length,\n\t\t ctx = this._ctx;\n\n\t\tif (!len) { return; }\n\n\t\tctx.beginPath();\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tfor (j = 0, len2 = parts[i].length; j < len2; j++) {\n\t\t\t\tp = parts[i][j];\n\t\t\t\tctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);\n\t\t\t}\n\t\t\tif (closed) {\n\t\t\t\tctx.closePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\n\t\t// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature\n\t},\n\n\t_updateCircle: function (layer) {\n\n\t\tif (!this._drawing || layer._empty()) { return; }\n\n\t\tvar p = layer._point,\n\t\t ctx = this._ctx,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;\n\n\t\tif (s !== 1) {\n\t\t\tctx.save();\n\t\t\tctx.scale(1, s);\n\t\t}\n\n\t\tctx.beginPath();\n\t\tctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);\n\n\t\tif (s !== 1) {\n\t\t\tctx.restore();\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\t},\n\n\t_fillStroke: function (ctx, layer) {\n\t\tvar options = layer.options;\n\n\t\tif (options.fill) {\n\t\t\tctx.globalAlpha = options.fillOpacity;\n\t\t\tctx.fillStyle = options.fillColor || options.color;\n\t\t\tctx.fill(options.fillRule || 'evenodd');\n\t\t}\n\n\t\tif (options.stroke && options.weight !== 0) {\n\t\t\tif (ctx.setLineDash) {\n\t\t\t\tctx.setLineDash(layer.options && layer.options._dashArray || []);\n\t\t\t}\n\t\t\tctx.globalAlpha = options.opacity;\n\t\t\tctx.lineWidth = options.weight;\n\t\t\tctx.strokeStyle = options.color;\n\t\t\tctx.lineCap = options.lineCap;\n\t\t\tctx.lineJoin = options.lineJoin;\n\t\t\tctx.stroke();\n\t\t}\n\t},\n\n\t// Canvas obviously doesn't have mouse events for individual drawn objects,\n\t// so we emulate that by calculating what's under the mouse on mousemove/click manually\n\n\t_onClick: function (e) {\n\t\tvar point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tif (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {\n\t\t\t\t\tclickedLayer = layer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._fireEvent(clickedLayer ? [clickedLayer] : false, e);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }\n\n\t\tvar point = this._map.mouseEventToLayerPoint(e);\n\t\tthis._handleMouseHover(e, point);\n\t},\n\n\n\t_handleMouseOut: function (e) {\n\t\tvar layer = this._hoveredLayer;\n\t\tif (layer) {\n\t\t\t// if we're leaving the layer, fire mouseout\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-interactive');\n\t\t\tthis._fireEvent([layer], e, 'mouseout');\n\t\t\tthis._hoveredLayer = null;\n\t\t\tthis._mouseHoverThrottled = false;\n\t\t}\n\t},\n\n\t_handleMouseHover: function (e, point) {\n\t\tif (this._mouseHoverThrottled) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar layer, candidateHoveredLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tcandidateHoveredLayer = layer;\n\t\t\t}\n\t\t}\n\n\t\tif (candidateHoveredLayer !== this._hoveredLayer) {\n\t\t\tthis._handleMouseOut(e);\n\n\t\t\tif (candidateHoveredLayer) {\n\t\t\t\tDomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor\n\t\t\t\tthis._fireEvent([candidateHoveredLayer], e, 'mouseover');\n\t\t\t\tthis._hoveredLayer = candidateHoveredLayer;\n\t\t\t}\n\t\t}\n\n\t\tthis._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);\n\n\t\tthis._mouseHoverThrottled = true;\n\t\tsetTimeout(Util.bind(function () {\n\t\t\tthis._mouseHoverThrottled = false;\n\t\t}, this), 32);\n\t},\n\n\t_fireEvent: function (layers, e, type) {\n\t\tthis._map._fireDOMEvent(e, type || e.type, layers);\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tvar order = layer._order;\n\n\t\tif (!order) { return; }\n\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\t// Already last\n\t\t\treturn;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else if (next) {\n\t\t\t// Update first entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\torder.prev = this._drawLast;\n\t\tthis._drawLast.next = order;\n\n\t\torder.next = null;\n\t\tthis._drawLast = order;\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tvar order = layer._order;\n\n\t\tif (!order) { return; }\n\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\t// Already first\n\t\t\treturn;\n\t\t}\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else if (prev) {\n\t\t\t// Update last entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawLast = prev;\n\t\t}\n\n\t\torder.prev = null;\n\n\t\torder.next = this._drawFirst;\n\t\tthis._drawFirst.prev = order;\n\t\tthis._drawFirst = order;\n\n\t\tthis._requestRedraw(layer);\n\t}\n});\n\n// @factory L.canvas(options?: Renderer options)\n// Creates a Canvas renderer with the given options.\nexport function canvas(options) {\n\treturn Browser.canvas ? new Canvas(options) : null;\n}\n","import * as DomUtil from '../../dom/DomUtil';\nimport * as Util from '../../core/Util';\nimport {Renderer} from './Renderer';\n\n/*\n * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!\n */\n\n\nexport var vmlCreate = (function () {\n\ttry {\n\t\tdocument.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');\n\t\treturn function (name) {\n\t\t\treturn document.createElement('<lvml:' + name + ' class=\"lvml\">');\n\t\t};\n\t} catch (e) {\n\t\t// Do not return fn from catch block so `e` can be garbage collected\n\t\t// See https://github.com/Leaflet/Leaflet/pull/7279\n\t}\n\treturn function (name) {\n\t\treturn document.createElement('<' + name + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">');\n\t};\n})();\n\n\n/*\n * @class SVG\n *\n *\n * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility\n * with old versions of Internet Explorer.\n */\n\n// mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences\nexport var vmlMixin = {\n\n\t_initContainer: function () {\n\t\tthis._container = DomUtil.create('div', 'leaflet-vml-container');\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom) { return; }\n\t\tRenderer.prototype._update.call(this);\n\t\tthis.fire('update');\n\t},\n\n\t_initPath: function (layer) {\n\t\tvar container = layer._container = vmlCreate('shape');\n\n\t\tDomUtil.addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));\n\n\t\tcontainer.coordsize = '1 1';\n\n\t\tlayer._path = vmlCreate('path');\n\t\tcontainer.appendChild(layer._path);\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[Util.stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tvar container = layer._container;\n\t\tthis._container.appendChild(container);\n\n\t\tif (layer.options.interactive) {\n\t\t\tlayer.addInteractiveTarget(container);\n\t\t}\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar container = layer._container;\n\t\tDomUtil.remove(container);\n\t\tlayer.removeInteractiveTarget(container);\n\t\tdelete this._layers[Util.stamp(layer)];\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar stroke = layer._stroke,\n\t\t fill = layer._fill,\n\t\t options = layer.options,\n\t\t container = layer._container;\n\n\t\tcontainer.stroked = !!options.stroke;\n\t\tcontainer.filled = !!options.fill;\n\n\t\tif (options.stroke) {\n\t\t\tif (!stroke) {\n\t\t\t\tstroke = layer._stroke = vmlCreate('stroke');\n\t\t\t}\n\t\t\tcontainer.appendChild(stroke);\n\t\t\tstroke.weight = options.weight + 'px';\n\t\t\tstroke.color = options.color;\n\t\t\tstroke.opacity = options.opacity;\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tstroke.dashStyle = Util.isArray(options.dashArray) ?\n\t\t\t\t options.dashArray.join(' ') :\n\t\t\t\t options.dashArray.replace(/( *, *)/g, ' ');\n\t\t\t} else {\n\t\t\t\tstroke.dashStyle = '';\n\t\t\t}\n\t\t\tstroke.endcap = options.lineCap.replace('butt', 'flat');\n\t\t\tstroke.joinstyle = options.lineJoin;\n\n\t\t} else if (stroke) {\n\t\t\tcontainer.removeChild(stroke);\n\t\t\tlayer._stroke = null;\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tif (!fill) {\n\t\t\t\tfill = layer._fill = vmlCreate('fill');\n\t\t\t}\n\t\t\tcontainer.appendChild(fill);\n\t\t\tfill.color = options.fillColor || options.color;\n\t\t\tfill.opacity = options.fillOpacity;\n\n\t\t} else if (fill) {\n\t\t\tcontainer.removeChild(fill);\n\t\t\tlayer._fill = null;\n\t\t}\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point.round(),\n\t\t r = Math.round(layer._radius),\n\t\t r2 = Math.round(layer._radiusY || r);\n\n\t\tthis._setPath(layer, layer._empty() ? 'M0 0' :\n\t\t\t'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.v = path;\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tDomUtil.toFront(layer._container);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tDomUtil.toBack(layer._container);\n\t}\n};\n","import {Renderer} from './Renderer';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport Browser from '../../core/Browser';\nimport {stamp} from '../../core/Util';\nimport {svgCreate, pointsToPath} from './SVG.Util';\nexport {pointsToPath};\nimport {vmlMixin, vmlCreate} from './SVG.VML';\n\nexport var create = Browser.vml ? vmlCreate : svgCreate;\n\n/*\n * @class SVG\n * @inherits Renderer\n * @aka L.SVG\n *\n * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](https://caniuse.com/svg), SVG is not\n * available in all web browsers, notably Android 2.x and 3.x.\n *\n * Although SVG is not available on IE7 and IE8, these browsers support\n * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)\n * (a now deprecated technology), and the SVG renderer will fall back to VML in\n * this case.\n *\n * @example\n *\n * Use SVG by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.svg()\n * });\n * ```\n *\n * Use a SVG renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.svg({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nexport var SVG = Renderer.extend({\n\n\t_initContainer: function () {\n\t\tthis._container = create('svg');\n\n\t\t// makes it possible to click through svg root; we'll reset it back in individual paths\n\t\tthis._container.setAttribute('pointer-events', 'none');\n\n\t\tthis._rootGroup = create('g');\n\t\tthis._container.appendChild(this._rootGroup);\n\t},\n\n\t_destroyContainer: function () {\n\t\tDomUtil.remove(this._container);\n\t\tDomEvent.off(this._container);\n\t\tdelete this._container;\n\t\tdelete this._rootGroup;\n\t\tdelete this._svgSize;\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t size = b.getSize(),\n\t\t container = this._container;\n\n\t\t// set size of svg-container if changed\n\t\tif (!this._svgSize || !this._svgSize.equals(size)) {\n\t\t\tthis._svgSize = size;\n\t\t\tcontainer.setAttribute('width', size.x);\n\t\t\tcontainer.setAttribute('height', size.y);\n\t\t}\n\n\t\t// movement: update container viewBox so that we don't have to change coordinates of individual layers\n\t\tDomUtil.setPosition(container, b.min);\n\t\tcontainer.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));\n\n\t\tthis.fire('update');\n\t},\n\n\t// methods below are called by vector layers implementations\n\n\t_initPath: function (layer) {\n\t\tvar path = layer._path = create('path');\n\n\t\t// @namespace Path\n\t\t// @option className: String = null\n\t\t// Custom class name set on an element. Only for SVG renderer.\n\t\tif (layer.options.className) {\n\t\t\tDomUtil.addClass(path, layer.options.className);\n\t\t}\n\n\t\tif (layer.options.interactive) {\n\t\t\tDomUtil.addClass(path, 'leaflet-interactive');\n\t\t}\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tif (!this._rootGroup) { this._initContainer(); }\n\t\tthis._rootGroup.appendChild(layer._path);\n\t\tlayer.addInteractiveTarget(layer._path);\n\t},\n\n\t_removePath: function (layer) {\n\t\tDomUtil.remove(layer._path);\n\t\tlayer.removeInteractiveTarget(layer._path);\n\t\tdelete this._layers[stamp(layer)];\n\t},\n\n\t_updatePath: function (layer) {\n\t\tlayer._project();\n\t\tlayer._update();\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar path = layer._path,\n\t\t options = layer.options;\n\n\t\tif (!path) { return; }\n\n\t\tif (options.stroke) {\n\t\t\tpath.setAttribute('stroke', options.color);\n\t\t\tpath.setAttribute('stroke-opacity', options.opacity);\n\t\t\tpath.setAttribute('stroke-width', options.weight);\n\t\t\tpath.setAttribute('stroke-linecap', options.lineCap);\n\t\t\tpath.setAttribute('stroke-linejoin', options.lineJoin);\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tpath.setAttribute('stroke-dasharray', options.dashArray);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dasharray');\n\t\t\t}\n\n\t\t\tif (options.dashOffset) {\n\t\t\t\tpath.setAttribute('stroke-dashoffset', options.dashOffset);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dashoffset');\n\t\t\t}\n\t\t} else {\n\t\t\tpath.setAttribute('stroke', 'none');\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tpath.setAttribute('fill', options.fillColor || options.color);\n\t\t\tpath.setAttribute('fill-opacity', options.fillOpacity);\n\t\t\tpath.setAttribute('fill-rule', options.fillRule || 'evenodd');\n\t\t} else {\n\t\t\tpath.setAttribute('fill', 'none');\n\t\t}\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tthis._setPath(layer, pointsToPath(layer._parts, closed));\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t r2 = Math.max(Math.round(layer._radiusY), 1) || r,\n\t\t arc = 'a' + r + ',' + r2 + ' 0 1,0 ';\n\n\t\t// drawing a circle with two half-arcs\n\t\tvar d = layer._empty() ? 'M0 0' :\n\t\t\t'M' + (p.x - r) + ',' + p.y +\n\t\t\tarc + (r * 2) + ',0 ' +\n\t\t\tarc + (-r * 2) + ',0 ';\n\n\t\tthis._setPath(layer, d);\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.setAttribute('d', path);\n\t},\n\n\t// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements\n\t_bringToFront: function (layer) {\n\t\tDomUtil.toFront(layer._path);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tDomUtil.toBack(layer._path);\n\t}\n});\n\nif (Browser.vml) {\n\tSVG.include(vmlMixin);\n}\n\n// @namespace SVG\n// @factory L.svg(options?: Renderer options)\n// Creates a SVG renderer with the given options.\nexport function svg(options) {\n\treturn Browser.svg || Browser.vml ? new SVG(options) : null;\n}\n","import {Map} from '../../map/Map';\nimport {canvas} from './Canvas';\nimport {svg} from './SVG';\n\nMap.include({\n\t// @namespace Map; @method getRenderer(layer: Path): Renderer\n\t// Returns the instance of `Renderer` that should be used to render the given\n\t// `Path`. It will ensure that the `renderer` options of the map and paths\n\t// are respected, and that the renderers do exist on the map.\n\tgetRenderer: function (layer) {\n\t\t// @namespace Path; @option renderer: Renderer\n\t\t// Use this specific instance of `Renderer` for this path. Takes\n\t\t// precedence over the map's [default renderer](#map-renderer).\n\t\tvar renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;\n\n\t\tif (!renderer) {\n\t\t\trenderer = this._renderer = this._createRenderer();\n\t\t}\n\n\t\tif (!this.hasLayer(renderer)) {\n\t\t\tthis.addLayer(renderer);\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_getPaneRenderer: function (name) {\n\t\tif (name === 'overlayPane' || name === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar renderer = this._paneRenderers[name];\n\t\tif (renderer === undefined) {\n\t\t\trenderer = this._createRenderer({pane: name});\n\t\t\tthis._paneRenderers[name] = renderer;\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_createRenderer: function (options) {\n\t\t// @namespace Map; @option preferCanvas: Boolean = false\n\t\t// Whether `Path`s should be rendered on a `Canvas` renderer.\n\t\t// By default, all `Path`s are rendered in a `SVG` renderer.\n\t\treturn (this.options.preferCanvas && canvas(options)) || svg(options);\n\t}\n});\n","import {Polygon} from './Polygon';\nimport {toLatLngBounds} from '../../geo/LatLngBounds';\n\n/*\n * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.\n */\n\n/*\n * @class Rectangle\n * @aka L.Rectangle\n * @inherits Polygon\n *\n * A class for drawing rectangle overlays on a map. Extends `Polygon`.\n *\n * @example\n *\n * ```js\n * // define rectangle geographical bounds\n * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n *\n * // create an orange rectangle\n * L.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n *\n * // zoom the map to the rectangle bounds\n * map.fitBounds(bounds);\n * ```\n *\n */\n\n\nexport var Rectangle = Polygon.extend({\n\tinitialize: function (latLngBounds, options) {\n\t\tPolygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);\n\t},\n\n\t// @method setBounds(latLngBounds: LatLngBounds): this\n\t// Redraws the rectangle with the passed bounds.\n\tsetBounds: function (latLngBounds) {\n\t\treturn this.setLatLngs(this._boundsToLatLngs(latLngBounds));\n\t},\n\n\t_boundsToLatLngs: function (latLngBounds) {\n\t\tlatLngBounds = toLatLngBounds(latLngBounds);\n\t\treturn [\n\t\t\tlatLngBounds.getSouthWest(),\n\t\t\tlatLngBounds.getNorthWest(),\n\t\t\tlatLngBounds.getNorthEast(),\n\t\t\tlatLngBounds.getSouthEast()\n\t\t];\n\t}\n});\n\n\n// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)\nexport function rectangle(latLngBounds, options) {\n\treturn new Rectangle(latLngBounds, options);\n}\n","export {Renderer} from './Renderer';\nexport {Canvas, canvas} from './Canvas';\nimport {SVG, create, pointsToPath, svg} from './SVG';\nSVG.create = create;\nSVG.pointsToPath = pointsToPath;\nexport {SVG, svg};\nimport './Renderer.getRenderer';\t// This is a bit of a hack, but needed because circular dependencies\n\nexport {Path} from './Path';\nexport {CircleMarker, circleMarker} from './CircleMarker';\nexport {Circle, circle} from './Circle';\nexport {Polyline, polyline} from './Polyline';\nexport {Polygon, polygon} from './Polygon';\nexport {Rectangle, rectangle} from './Rectangle';\n","export {Layer} from './Layer';\nexport {LayerGroup, layerGroup} from './LayerGroup';\nexport {FeatureGroup, featureGroup} from './FeatureGroup';\nimport {GeoJSON, geoJSON, geoJson, geometryToLayer, coordsToLatLng, coordsToLatLngs, latLngToCoords, latLngsToCoords, getFeature, asFeature} from './GeoJSON';\nGeoJSON.geometryToLayer = geometryToLayer;\nGeoJSON.coordsToLatLng = coordsToLatLng;\nGeoJSON.coordsToLatLngs = coordsToLatLngs;\nGeoJSON.latLngToCoords = latLngToCoords;\nGeoJSON.latLngsToCoords = latLngsToCoords;\nGeoJSON.getFeature = getFeature;\nGeoJSON.asFeature = asFeature;\nexport {GeoJSON, geoJSON, geoJson};\n\nexport {ImageOverlay, imageOverlay} from './ImageOverlay';\nexport {VideoOverlay, videoOverlay} from './VideoOverlay';\nexport {SVGOverlay, svgOverlay} from './SVGOverlay';\n\nexport {DivOverlay} from './DivOverlay';\nexport {Popup, popup} from './Popup';\nexport {Tooltip, tooltip} from './Tooltip';\n\nexport * from './marker/index';\nexport * from './tile/index';\nexport * from './vector/index';\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport * as DomEvent from '../../dom/DomEvent';\nimport {LatLngBounds} from '../../geo/LatLngBounds';\nimport {Bounds} from '../../geometry/Bounds';\n\n/*\n * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map\n * (zoom to a selected bounding box), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option boxZoom: Boolean = true\n\t// Whether the map can be zoomed to a rectangular area specified by\n\t// dragging the mouse while pressing the shift key.\n\tboxZoom: true\n});\n\nexport var BoxZoom = Handler.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t\tthis._container = map._container;\n\t\tthis._pane = map._panes.overlayPane;\n\t\tthis._resetStateTimeout = 0;\n\t\tmap.on('unload', this._destroy, this);\n\t},\n\n\taddHooks: function () {\n\t\tDomEvent.on(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tmoved: function () {\n\t\treturn this._moved;\n\t},\n\n\t_destroy: function () {\n\t\tDomUtil.remove(this._pane);\n\t\tdelete this._pane;\n\t},\n\n\t_resetState: function () {\n\t\tthis._resetStateTimeout = 0;\n\t\tthis._moved = false;\n\t},\n\n\t_clearDeferredResetState: function () {\n\t\tif (this._resetStateTimeout !== 0) {\n\t\t\tclearTimeout(this._resetStateTimeout);\n\t\t\tthis._resetStateTimeout = 0;\n\t\t}\n\t},\n\n\t_onMouseDown: function (e) {\n\t\tif (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }\n\n\t\t// Clear the deferred resetState if it hasn't executed yet, otherwise it\n\t\t// will interrupt the interaction and orphan a box element in the container.\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetState();\n\n\t\tDomUtil.disableTextSelection();\n\t\tDomUtil.disableImageDrag();\n\n\t\tthis._startPoint = this._map.mouseEventToContainerPoint(e);\n\n\t\tDomEvent.on(document, {\n\t\t\tcontextmenu: DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._moved) {\n\t\t\tthis._moved = true;\n\n\t\t\tthis._box = DomUtil.create('div', 'leaflet-zoom-box', this._container);\n\t\t\tDomUtil.addClass(this._container, 'leaflet-crosshair');\n\n\t\t\tthis._map.fire('boxzoomstart');\n\t\t}\n\n\t\tthis._point = this._map.mouseEventToContainerPoint(e);\n\n\t\tvar bounds = new Bounds(this._point, this._startPoint),\n\t\t size = bounds.getSize();\n\n\t\tDomUtil.setPosition(this._box, bounds.min);\n\n\t\tthis._box.style.width = size.x + 'px';\n\t\tthis._box.style.height = size.y + 'px';\n\t},\n\n\t_finish: function () {\n\t\tif (this._moved) {\n\t\t\tDomUtil.remove(this._box);\n\t\t\tDomUtil.removeClass(this._container, 'leaflet-crosshair');\n\t\t}\n\n\t\tDomUtil.enableTextSelection();\n\t\tDomUtil.enableImageDrag();\n\n\t\tDomEvent.off(document, {\n\t\t\tcontextmenu: DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseUp: function (e) {\n\t\tif ((e.which !== 1) && (e.button !== 1)) { return; }\n\n\t\tthis._finish();\n\n\t\tif (!this._moved) { return; }\n\t\t// Postpone to next JS tick so internal click event handling\n\t\t// still see it as \"moved\".\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetStateTimeout = setTimeout(Util.bind(this._resetState, this), 0);\n\n\t\tvar bounds = new LatLngBounds(\n\t\t this._map.containerPointToLatLng(this._startPoint),\n\t\t this._map.containerPointToLatLng(this._point));\n\n\t\tthis._map\n\t\t\t.fitBounds(bounds)\n\t\t\t.fire('boxzoomend', {boxZoomBounds: bounds});\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.keyCode === 27) {\n\t\t\tthis._finish();\n\t\t\tthis._clearDeferredResetState();\n\t\t\tthis._resetState();\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property boxZoom: Handler\n// Box (shift-drag with mouse) zoom handler.\nMap.addInitHook('addHandler', 'boxZoom', BoxZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\n\n/*\n * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\n\nMap.mergeOptions({\n\t// @option doubleClickZoom: Boolean|String = true\n\t// Whether the map can be zoomed in by double clicking on it and\n\t// zoomed out by double clicking while holding shift. If passed\n\t// `'center'`, double-click zoom will zoom to the center of the\n\t// view regardless of where the mouse was.\n\tdoubleClickZoom: true\n});\n\nexport var DoubleClickZoom = Handler.extend({\n\taddHooks: function () {\n\t\tthis._map.on('dblclick', this._onDoubleClick, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._map.off('dblclick', this._onDoubleClick, this);\n\t},\n\n\t_onDoubleClick: function (e) {\n\t\tvar map = this._map,\n\t\t oldZoom = map.getZoom(),\n\t\t delta = map.options.zoomDelta,\n\t\t zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;\n\n\t\tif (map.options.doubleClickZoom === 'center') {\n\t\t\tmap.setZoom(zoom);\n\t\t} else {\n\t\t\tmap.setZoomAround(e.containerPoint, zoom);\n\t\t}\n\t}\n});\n\n// @section Handlers\n//\n// Map properties include interaction handlers that allow you to control\n// interaction behavior in runtime, enabling or disabling certain features such\n// as dragging or touch zoom (see `Handler` methods). For example:\n//\n// ```js\n// map.doubleClickZoom.disable();\n// ```\n//\n// @property doubleClickZoom: Handler\n// Double click zoom handler.\nMap.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport {Draggable} from '../../dom/Draggable';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport {toLatLngBounds as latLngBounds} from '../../geo/LatLngBounds';\nimport {toBounds} from '../../geometry/Bounds';\n\n/*\n * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option dragging: Boolean = true\n\t// Whether the map is draggable with mouse/touch or not.\n\tdragging: true,\n\n\t// @section Panning Inertia Options\n\t// @option inertia: Boolean = *\n\t// If enabled, panning of the map will have an inertia effect where\n\t// the map builds momentum while dragging and continues moving in\n\t// the same direction for some time. Feels especially nice on touch\n\t// devices. Enabled by default.\n\tinertia: true,\n\n\t// @option inertiaDeceleration: Number = 3000\n\t// The rate with which the inertial movement slows down, in pixels/second².\n\tinertiaDeceleration: 3400, // px/s^2\n\n\t// @option inertiaMaxSpeed: Number = Infinity\n\t// Max speed of the inertial movement, in pixels/second.\n\tinertiaMaxSpeed: Infinity, // px/s\n\n\t// @option easeLinearity: Number = 0.2\n\teaseLinearity: 0.2,\n\n\t// TODO refactor, move to CRS\n\t// @option worldCopyJump: Boolean = false\n\t// With this option enabled, the map tracks when you pan to another \"copy\"\n\t// of the world and seamlessly jumps to the original one so that all overlays\n\t// like markers and vector layers are still visible.\n\tworldCopyJump: false,\n\n\t// @option maxBoundsViscosity: Number = 0.0\n\t// If `maxBounds` is set, this option will control how solid the bounds\n\t// are when dragging the map around. The default value of `0.0` allows the\n\t// user to drag outside the bounds at normal speed, higher values will\n\t// slow down map dragging outside bounds, and `1.0` makes the bounds fully\n\t// solid, preventing the user from dragging outside the bounds.\n\tmaxBoundsViscosity: 0.0\n});\n\nexport var Drag = Handler.extend({\n\taddHooks: function () {\n\t\tif (!this._draggable) {\n\t\t\tvar map = this._map;\n\n\t\t\tthis._draggable = new Draggable(map._mapPane, map._container);\n\n\t\t\tthis._draggable.on({\n\t\t\t\tdragstart: this._onDragStart,\n\t\t\t\tdrag: this._onDrag,\n\t\t\t\tdragend: this._onDragEnd\n\t\t\t}, this);\n\n\t\t\tthis._draggable.on('predrag', this._onPreDragLimit, this);\n\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\tthis._draggable.on('predrag', this._onPreDragWrap, this);\n\t\t\t\tmap.on('zoomend', this._onZoomEnd, this);\n\n\t\t\t\tmap.whenReady(this._onZoomEnd, this);\n\t\t\t}\n\t\t}\n\t\tDomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');\n\t\tthis._draggable.enable();\n\t\tthis._positions = [];\n\t\tthis._times = [];\n\t},\n\n\tremoveHooks: function () {\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-grab');\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-touch-drag');\n\t\tthis._draggable.disable();\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\tmoving: function () {\n\t\treturn this._draggable && this._draggable._moving;\n\t},\n\n\t_onDragStart: function () {\n\t\tvar map = this._map;\n\n\t\tmap._stop();\n\t\tif (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {\n\t\t\tvar bounds = latLngBounds(this._map.options.maxBounds);\n\n\t\t\tthis._offsetLimit = toBounds(\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)\n\t\t\t\t\t.add(this._map.getSize()));\n\n\t\t\tthis._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));\n\t\t} else {\n\t\t\tthis._offsetLimit = null;\n\t\t}\n\n\t\tmap\n\t\t .fire('movestart')\n\t\t .fire('dragstart');\n\n\t\tif (map.options.inertia) {\n\t\t\tthis._positions = [];\n\t\t\tthis._times = [];\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tif (this._map.options.inertia) {\n\t\t\tvar time = this._lastTime = +new Date(),\n\t\t\t pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;\n\n\t\t\tthis._positions.push(pos);\n\t\t\tthis._times.push(time);\n\n\t\t\tthis._prunePositions(time);\n\t\t}\n\n\t\tthis._map\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_prunePositions: function (time) {\n\t\twhile (this._positions.length > 1 && time - this._times[0] > 50) {\n\t\t\tthis._positions.shift();\n\t\t\tthis._times.shift();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tvar pxCenter = this._map.getSize().divideBy(2),\n\t\t pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);\n\n\t\tthis._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;\n\t\tthis._worldWidth = this._map.getPixelWorldBounds().getSize().x;\n\t},\n\n\t_viscousLimit: function (value, threshold) {\n\t\treturn value - (value - threshold) * this._viscosity;\n\t},\n\n\t_onPreDragLimit: function () {\n\t\tif (!this._viscosity || !this._offsetLimit) { return; }\n\n\t\tvar offset = this._draggable._newPos.subtract(this._draggable._startPos);\n\n\t\tvar limit = this._offsetLimit;\n\t\tif (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }\n\t\tif (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }\n\t\tif (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }\n\t\tif (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }\n\n\t\tthis._draggable._newPos = this._draggable._startPos.add(offset);\n\t},\n\n\t_onPreDragWrap: function () {\n\t\t// TODO refactor to be able to adjust map pane position after zoom\n\t\tvar worldWidth = this._worldWidth,\n\t\t halfWidth = Math.round(worldWidth / 2),\n\t\t dx = this._initialWorldOffset,\n\t\t x = this._draggable._newPos.x,\n\t\t newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,\n\t\t newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,\n\t\t newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;\n\n\t\tthis._draggable._absPos = this._draggable._newPos.clone();\n\t\tthis._draggable._newPos.x = newX;\n\t},\n\n\t_onDragEnd: function (e) {\n\t\tvar map = this._map,\n\t\t options = map.options,\n\n\t\t noInertia = !options.inertia || e.noInertia || this._times.length < 2;\n\n\t\tmap.fire('dragend', e);\n\n\t\tif (noInertia) {\n\t\t\tmap.fire('moveend');\n\n\t\t} else {\n\t\t\tthis._prunePositions(+new Date());\n\n\t\t\tvar direction = this._lastPos.subtract(this._positions[0]),\n\t\t\t duration = (this._lastTime - this._times[0]) / 1000,\n\t\t\t ease = options.easeLinearity,\n\n\t\t\t speedVector = direction.multiplyBy(ease / duration),\n\t\t\t speed = speedVector.distanceTo([0, 0]),\n\n\t\t\t limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),\n\t\t\t limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),\n\n\t\t\t decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),\n\t\t\t offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();\n\n\t\t\tif (!offset.x && !offset.y) {\n\t\t\t\tmap.fire('moveend');\n\n\t\t\t} else {\n\t\t\t\toffset = map._limitOffset(offset, map.options.maxBounds);\n\n\t\t\t\tUtil.requestAnimFrame(function () {\n\t\t\t\t\tmap.panBy(offset, {\n\t\t\t\t\t\tduration: decelerationDuration,\n\t\t\t\t\t\teaseLinearity: ease,\n\t\t\t\t\t\tnoMoveStart: true,\n\t\t\t\t\t\tanimate: true\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property dragging: Handler\n// Map dragging handler (by both mouse and touch).\nMap.addInitHook('addHandler', 'dragging', Drag);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport {on, off, stop} from '../../dom/DomEvent';\nimport {toPoint} from '../../geometry/Point';\n\n\n/*\n * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.\n */\n\n// @namespace Map\n// @section Keyboard Navigation Options\nMap.mergeOptions({\n\t// @option keyboard: Boolean = true\n\t// Makes the map focusable and allows users to navigate the map with keyboard\n\t// arrows and `+`/`-` keys.\n\tkeyboard: true,\n\n\t// @option keyboardPanDelta: Number = 80\n\t// Amount of pixels to pan when pressing an arrow key.\n\tkeyboardPanDelta: 80\n});\n\nexport var Keyboard = Handler.extend({\n\n\tkeyCodes: {\n\t\tleft: [37],\n\t\tright: [39],\n\t\tdown: [40],\n\t\tup: [38],\n\t\tzoomIn: [187, 107, 61, 171],\n\t\tzoomOut: [189, 109, 54, 173]\n\t},\n\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\n\t\tthis._setPanDelta(map.options.keyboardPanDelta);\n\t\tthis._setZoomDelta(map.options.zoomDelta);\n\t},\n\n\taddHooks: function () {\n\t\tvar container = this._map._container;\n\n\t\t// make the container focusable by tabbing\n\t\tif (container.tabIndex <= 0) {\n\t\t\tcontainer.tabIndex = '0';\n\t\t}\n\n\t\ton(container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.on({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._removeHooks();\n\n\t\toff(this._map._container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.off({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\t_onMouseDown: function () {\n\t\tif (this._focused) { return; }\n\n\t\tvar body = document.body,\n\t\t docEl = document.documentElement,\n\t\t top = body.scrollTop || docEl.scrollTop,\n\t\t left = body.scrollLeft || docEl.scrollLeft;\n\n\t\tthis._map._container.focus();\n\n\t\twindow.scrollTo(left, top);\n\t},\n\n\t_onFocus: function () {\n\t\tthis._focused = true;\n\t\tthis._map.fire('focus');\n\t},\n\n\t_onBlur: function () {\n\t\tthis._focused = false;\n\t\tthis._map.fire('blur');\n\t},\n\n\t_setPanDelta: function (panDelta) {\n\t\tvar keys = this._panKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.left.length; i < len; i++) {\n\t\t\tkeys[codes.left[i]] = [-1 * panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.right.length; i < len; i++) {\n\t\t\tkeys[codes.right[i]] = [panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.down.length; i < len; i++) {\n\t\t\tkeys[codes.down[i]] = [0, panDelta];\n\t\t}\n\t\tfor (i = 0, len = codes.up.length; i < len; i++) {\n\t\t\tkeys[codes.up[i]] = [0, -1 * panDelta];\n\t\t}\n\t},\n\n\t_setZoomDelta: function (zoomDelta) {\n\t\tvar keys = this._zoomKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.zoomIn.length; i < len; i++) {\n\t\t\tkeys[codes.zoomIn[i]] = zoomDelta;\n\t\t}\n\t\tfor (i = 0, len = codes.zoomOut.length; i < len; i++) {\n\t\t\tkeys[codes.zoomOut[i]] = -zoomDelta;\n\t\t}\n\t},\n\n\t_addHooks: function () {\n\t\ton(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_removeHooks: function () {\n\t\toff(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.altKey || e.ctrlKey || e.metaKey) { return; }\n\n\t\tvar key = e.keyCode,\n\t\t map = this._map,\n\t\t offset;\n\n\t\tif (key in this._panKeys) {\n\t\t\tif (!map._panAnim || !map._panAnim._inProgress) {\n\t\t\t\toffset = this._panKeys[key];\n\t\t\t\tif (e.shiftKey) {\n\t\t\t\t\toffset = toPoint(offset).multiplyBy(3);\n\t\t\t\t}\n\n\t\t\t\tif (map.options.maxBounds) {\n\t\t\t\t\toffset = map._limitOffset(toPoint(offset), map.options.maxBounds);\n\t\t\t\t}\n\n\t\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\t\tvar newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));\n\t\t\t\t\tmap.panTo(newLatLng);\n\t\t\t\t} else {\n\t\t\t\t\tmap.panBy(offset);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (key in this._zoomKeys) {\n\t\t\tmap.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);\n\n\t\t} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {\n\t\t\tmap.closePopup();\n\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tstop(e);\n\t}\n});\n\n// @section Handlers\n// @section Handlers\n// @property keyboard: Handler\n// Keyboard navigation handler.\nMap.addInitHook('addHandler', 'keyboard', Keyboard);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport * as Util from '../../core/Util';\n\n/*\n * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Mouse wheel options\n\t// @option scrollWheelZoom: Boolean|String = true\n\t// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,\n\t// it will zoom to the center of the view regardless of where the mouse was.\n\tscrollWheelZoom: true,\n\n\t// @option wheelDebounceTime: Number = 40\n\t// Limits the rate at which a wheel can fire (in milliseconds). By default\n\t// user can't zoom via wheel more often than once per 40 ms.\n\twheelDebounceTime: 40,\n\n\t// @option wheelPxPerZoomLevel: Number = 60\n\t// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))\n\t// mean a change of one full zoom level. Smaller values will make wheel-zooming\n\t// faster (and vice versa).\n\twheelPxPerZoomLevel: 60\n});\n\nexport var ScrollWheelZoom = Handler.extend({\n\taddHooks: function () {\n\t\tDomEvent.on(this._map._container, 'wheel', this._onWheelScroll, this);\n\n\t\tthis._delta = 0;\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._map._container, 'wheel', this._onWheelScroll, this);\n\t},\n\n\t_onWheelScroll: function (e) {\n\t\tvar delta = DomEvent.getWheelDelta(e);\n\n\t\tvar debounce = this._map.options.wheelDebounceTime;\n\n\t\tthis._delta += delta;\n\t\tthis._lastMousePos = this._map.mouseEventToContainerPoint(e);\n\n\t\tif (!this._startTime) {\n\t\t\tthis._startTime = +new Date();\n\t\t}\n\n\t\tvar left = Math.max(debounce - (+new Date() - this._startTime), 0);\n\n\t\tclearTimeout(this._timer);\n\t\tthis._timer = setTimeout(Util.bind(this._performZoom, this), left);\n\n\t\tDomEvent.stop(e);\n\t},\n\n\t_performZoom: function () {\n\t\tvar map = this._map,\n\t\t zoom = map.getZoom(),\n\t\t snap = this._map.options.zoomSnap || 0;\n\n\t\tmap._stop(); // stop panning and fly animations if any\n\n\t\t// map the delta with a sigmoid function to -4..4 range leaning on -1..1\n\t\tvar d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),\n\t\t d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,\n\t\t d4 = snap ? Math.ceil(d3 / snap) * snap : d3,\n\t\t delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;\n\n\t\tthis._delta = 0;\n\t\tthis._startTime = null;\n\n\t\tif (!delta) { return; }\n\n\t\tif (map.options.scrollWheelZoom === 'center') {\n\t\t\tmap.setZoom(zoom + delta);\n\t\t} else {\n\t\t\tmap.setZoomAround(this._lastMousePos, zoom + delta);\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property scrollWheelZoom: Handler\n// Scroll wheel zoom handler.\nMap.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport {Point} from '../../geometry/Point';\nimport * as Util from '../../core/Util';\nimport Browser from '../../core/Browser';\n\n/*\n * L.Map.TapHold is used to simulate `contextmenu` event on long hold,\n * which otherwise is not fired by mobile Safari.\n */\n\nvar tapHoldDelay = 600;\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option tapHold: Boolean\n\t// Enables simulation of `contextmenu` event, default is `true` for mobile Safari.\n\ttapHold: Browser.touchNative && Browser.safari && Browser.mobile,\n\n\t// @option tapTolerance: Number = 15\n\t// The max number of pixels a user can shift his finger during touch\n\t// for it to be considered a valid tap.\n\ttapTolerance: 15\n});\n\nexport var TapHold = Handler.extend({\n\taddHooks: function () {\n\t\tDomEvent.on(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomEvent.off(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\t_onDown: function (e) {\n\t\tclearTimeout(this._holdTimeout);\n\t\tif (e.touches.length !== 1) { return; }\n\n\t\tvar first = e.touches[0];\n\t\tthis._startPos = this._newPos = new Point(first.clientX, first.clientY);\n\n\t\tthis._holdTimeout = setTimeout(Util.bind(function () {\n\t\t\tthis._cancel();\n\t\t\tif (!this._isTapValid()) { return; }\n\n\t\t\t// prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events\n\t\t\tDomEvent.on(document, 'touchend', DomEvent.preventDefault);\n\t\t\tDomEvent.on(document, 'touchend touchcancel', this._cancelClickPrevent);\n\t\t\tthis._simulateEvent('contextmenu', first);\n\t\t}, this), tapHoldDelay);\n\n\t\tDomEvent.on(document, 'touchend touchcancel contextmenu', this._cancel, this);\n\t\tDomEvent.on(document, 'touchmove', this._onMove, this);\n\t},\n\n\t_cancelClickPrevent: function cancelClickPrevent() {\n\t\tDomEvent.off(document, 'touchend', DomEvent.preventDefault);\n\t\tDomEvent.off(document, 'touchend touchcancel', cancelClickPrevent);\n\t},\n\n\t_cancel: function () {\n\t\tclearTimeout(this._holdTimeout);\n\t\tDomEvent.off(document, 'touchend touchcancel contextmenu', this._cancel, this);\n\t\tDomEvent.off(document, 'touchmove', this._onMove, this);\n\t},\n\n\t_onMove: function (e) {\n\t\tvar first = e.touches[0];\n\t\tthis._newPos = new Point(first.clientX, first.clientY);\n\t},\n\n\t_isTapValid: function () {\n\t\treturn this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;\n\t},\n\n\t_simulateEvent: function (type, e) {\n\t\tvar simulatedEvent = new MouseEvent(type, {\n\t\t\tbubbles: true,\n\t\t\tcancelable: true,\n\t\t\tview: window,\n\t\t\t// detail: 1,\n\t\t\tscreenX: e.screenX,\n\t\t\tscreenY: e.screenY,\n\t\t\tclientX: e.clientX,\n\t\t\tclientY: e.clientY,\n\t\t\t// button: 2,\n\t\t\t// buttons: 2\n\t\t});\n\n\t\tsimulatedEvent._simulated = true;\n\n\t\te.target.dispatchEvent(simulatedEvent);\n\t}\n});\n\n// @section Handlers\n// @property tapHold: Handler\n// Long tap handler to simulate `contextmenu` event (useful in mobile Safari).\nMap.addInitHook('addHandler', 'tapHold', TapHold);\n","import {Map} from '../Map';\nimport {Handler} from '../../core/Handler';\nimport * as DomEvent from '../../dom/DomEvent';\nimport * as Util from '../../core/Util';\nimport * as DomUtil from '../../dom/DomUtil';\nimport Browser from '../../core/Browser';\n\n/*\n * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option touchZoom: Boolean|String = *\n\t// Whether the map can be zoomed by touch-dragging with two fingers. If\n\t// passed `'center'`, it will zoom to the center of the view regardless of\n\t// where the touch events (fingers) were. Enabled for touch-capable web\n\t// browsers.\n\ttouchZoom: Browser.touch,\n\n\t// @option bounceAtZoomLimits: Boolean = true\n\t// Set it to false if you don't want the map to zoom beyond min/max zoom\n\t// and then bounce back when pinch-zooming.\n\tbounceAtZoomLimits: true\n});\n\nexport var TouchZoom = Handler.extend({\n\taddHooks: function () {\n\t\tDomUtil.addClass(this._map._container, 'leaflet-touch-zoom');\n\t\tDomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tDomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');\n\t\tDomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\t_onTouchStart: function (e) {\n\t\tvar map = this._map;\n\t\tif (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }\n\n\t\tvar p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]);\n\n\t\tthis._centerPoint = map.getSize()._divideBy(2);\n\t\tthis._startLatLng = map.containerPointToLatLng(this._centerPoint);\n\t\tif (map.options.touchZoom !== 'center') {\n\t\t\tthis._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));\n\t\t}\n\n\t\tthis._startDist = p1.distanceTo(p2);\n\t\tthis._startZoom = map.getZoom();\n\n\t\tthis._moved = false;\n\t\tthis._zooming = true;\n\n\t\tmap._stop();\n\n\t\tDomEvent.on(document, 'touchmove', this._onTouchMove, this);\n\t\tDomEvent.on(document, 'touchend touchcancel', this._onTouchEnd, this);\n\n\t\tDomEvent.preventDefault(e);\n\t},\n\n\t_onTouchMove: function (e) {\n\t\tif (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }\n\n\t\tvar map = this._map,\n\t\t p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]),\n\t\t scale = p1.distanceTo(p2) / this._startDist;\n\n\t\tthis._zoom = map.getScaleZoom(scale, this._startZoom);\n\n\t\tif (!map.options.bounceAtZoomLimits && (\n\t\t\t(this._zoom < map.getMinZoom() && scale < 1) ||\n\t\t\t(this._zoom > map.getMaxZoom() && scale > 1))) {\n\t\t\tthis._zoom = map._limitZoom(this._zoom);\n\t\t}\n\n\t\tif (map.options.touchZoom === 'center') {\n\t\t\tthis._center = this._startLatLng;\n\t\t\tif (scale === 1) { return; }\n\t\t} else {\n\t\t\t// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng\n\t\t\tvar delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);\n\t\t\tif (scale === 1 && delta.x === 0 && delta.y === 0) { return; }\n\t\t\tthis._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);\n\t\t}\n\n\t\tif (!this._moved) {\n\t\t\tmap._moveStart(true, false);\n\t\t\tthis._moved = true;\n\t\t}\n\n\t\tUtil.cancelAnimFrame(this._animRequest);\n\n\t\tvar moveFn = Util.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}, undefined);\n\t\tthis._animRequest = Util.requestAnimFrame(moveFn, this, true);\n\n\t\tDomEvent.preventDefault(e);\n\t},\n\n\t_onTouchEnd: function () {\n\t\tif (!this._moved || !this._zooming) {\n\t\t\tthis._zooming = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._zooming = false;\n\t\tUtil.cancelAnimFrame(this._animRequest);\n\n\t\tDomEvent.off(document, 'touchmove', this._onTouchMove, this);\n\t\tDomEvent.off(document, 'touchend touchcancel', this._onTouchEnd, this);\n\n\t\t// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.\n\t\tif (this._map.options.zoomAnimation) {\n\t\t\tthis._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);\n\t\t} else {\n\t\t\tthis._map._resetView(this._center, this._map._limitZoom(this._zoom));\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property touchZoom: Handler\n// Touch zoom handler.\nMap.addInitHook('addHandler', 'touchZoom', TouchZoom);\n","import {Map} from './Map';\nimport {BoxZoom} from './handler/Map.BoxZoom';\nMap.BoxZoom = BoxZoom;\nimport {DoubleClickZoom} from './handler/Map.DoubleClickZoom';\nMap.DoubleClickZoom = DoubleClickZoom;\nimport {Drag} from './handler/Map.Drag';\nMap.Drag = Drag;\nimport {Keyboard} from './handler/Map.Keyboard';\nMap.Keyboard = Keyboard;\nimport {ScrollWheelZoom} from './handler/Map.ScrollWheelZoom';\nMap.ScrollWheelZoom = ScrollWheelZoom;\nimport {TapHold} from './handler/Map.TapHold';\nMap.TapHold = TapHold;\nimport {TouchZoom} from './handler/Map.TouchZoom';\nMap.TouchZoom = TouchZoom;\n\nexport {Map, createMap as map} from './Map';\n"],"names":/* @preserve * Leaflet 1.9.3, a JS library for interactive maps. https://leafletjs.com * (c) 2010-2022 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).leaflet={})}(this,function(t){"use strict";function l(t){for(var e,i,n=1,o=arguments.length;n<o;n++)for(e in i=arguments[n])t[e]=i[e];return t}var R=Object.create||function(t){return N.prototype=t,new N};function N(){}function a(t,e){var i,n=Array.prototype.slice;return t.bind?t.bind.apply(t,n.call(arguments,1)):(i=n.call(arguments,2),function(){return t.apply(e,i.length?i.concat(n.call(arguments)):arguments)})}var D=0;function h(t){return"_leaflet_id"in t||(t._leaflet_id=++D),t._leaflet_id}function j(t,e,i){var n,o,s=function(){n=!1,o&&(r.apply(i,o),o=!1)},r=function(){n?o=arguments:(t.apply(i,arguments),setTimeout(s,e),n=!0)};return r}function H(t,e,i){var n=e[1],e=e[0],o=n-e;return t===n&&i?t:((t-e)%o+o)%o+e}function u(){return!1}function i(t,e){return!1===e?t:(e=Math.pow(10,void 0===e?6:e),Math.round(t*e)/e)}function F(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function W(t){return F(t).split(/\s+/)}function c(t,e){for(var i in Object.prototype.hasOwnProperty.call(t,"options")||(t.options=t.options?R(t.options):{}),e)t.options[i]=e[i];return t.options}function U(t,e,i){var n,o=[];for(n in t)o.push(encodeURIComponent(i?n.toUpperCase():n)+"="+encodeURIComponent(t[n]));return(e&&-1!==e.indexOf("?")?"&":"?")+o.join("&")}var V=/\{ *([\w_ -]+) *\}/g;function q(t,i){return t.replace(V,function(t,e){e=i[e];if(void 0===e)throw new Error("No value provided for variable "+t);return e="function"==typeof e?e(i):e})}var d=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)};function G(t,e){for(var i=0;i<t.length;i++)if(t[i]===e)return i;return-1}var K="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";function Y(t){return window["webkit"+t]||window["moz"+t]||window["ms"+t]}var X=0;function J(t){var e=+new Date,i=Math.max(0,16-(e-X));return X=e+i,window.setTimeout(t,i)}var $=window.requestAnimationFrame||Y("RequestAnimationFrame")||J,Q=window.cancelAnimationFrame||Y("CancelAnimationFrame")||Y("CancelRequestAnimationFrame")||function(t){window.clearTimeout(t)};function x(t,e,i){if(!i||$!==J)return $.call(window,a(t,e));t.call(e)}function r(t){t&&Q.call(window,t)}var tt={__proto__:null,extend:l,create:R,bind:a,get lastId(){return D},stamp:h,throttle:j,wrapNum:H,falseFn:u,formatNum:i,trim:F,splitWords:W,setOptions:c,getParamString:U,template:q,isArray:d,indexOf:G,emptyImageUrl:K,requestFn:$,cancelFn:Q,requestAnimFrame:x,cancelAnimFrame:r};function et(){}et.extend=function(t){function e(){c(this),this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()}var i,n=e.__super__=this.prototype,o=R(n);for(i in(o.constructor=e).prototype=o,this)Object.prototype.hasOwnProperty.call(this,i)&&"prototype"!==i&&"__super__"!==i&&(e[i]=this[i]);if(t.statics&&l(e,t.statics),t.includes){var s=t.includes;if("undefined"!=typeof L&&L&&L.Mixin){s=d(s)?s:[s];for(var r=0;r<s.length;r++)s[r]===L.Mixin.Events&&console.warn("Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.",(new Error).stack)}l.apply(null,[o].concat(t.includes))}return l(o,t),delete o.statics,delete o.includes,o.options&&(o.options=n.options?R(n.options):{},l(o.options,t.options)),o._initHooks=[],o.callInitHooks=function(){if(!this._initHooksCalled){n.callInitHooks&&n.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,e=o._initHooks.length;t<e;t++)o._initHooks[t].call(this)}},e},et.include=function(t){var e=this.prototype.options;return l(this.prototype,t),t.options&&(this.prototype.options=e,this.mergeOptions(t.options)),this},et.mergeOptions=function(t){return l(this.prototype.options,t),this},et.addInitHook=function(t){var e=Array.prototype.slice.call(arguments,1),i="function"==typeof t?t:function(){this[t].apply(this,e)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i),this};var e={on:function(t,e,i){if("object"==typeof t)for(var n in t)this._on(n,t[n],e);else for(var o=0,s=(t=W(t)).length;o<s;o++)this._on(t[o],e,i);return this},off:function(t,e,i){if(arguments.length)if("object"==typeof t)for(var n in t)this._off(n,t[n],e);else{t=W(t);for(var o=1===arguments.length,s=0,r=t.length;s<r;s++)o?this._off(t[s]):this._off(t[s],e,i)}else delete this._events;return this},_on:function(t,e,i,n){"function"!=typeof e?console.warn("wrong listener type: "+typeof e):!1===this._listens(t,e,i)&&(e={fn:e,ctx:i=i===this?void 0:i},n&&(e.once=!0),this._events=this._events||{},this._events[t]=this._events[t]||[],this._events[t].push(e))},_off:function(t,e,i){var n,o,s;if(this._events&&(n=this._events[t]))if(1===arguments.length){if(this._firingCount)for(o=0,s=n.length;o<s;o++)n[o].fn=u;delete this._events[t]}else"function"!=typeof e?console.warn("wrong listener type: "+typeof e):!1!==(e=this._listens(t,e,i))&&(i=n[e],this._firingCount&&(i.fn=u,this._events[t]=n=n.slice()),n.splice(e,1))},fire:function(t,e,i){if(this.listens(t,i)){var n=l({},e,{type:t,target:this,sourceTarget:e&&e.sourceTarget||this});if(this._events){var o=this._events[t];if(o){this._firingCount=this._firingCount+1||1;for(var s=0,r=o.length;s<r;s++){var a=o[s],h=a.fn;a.once&&this.off(t,h,a.ctx),h.call(a.ctx||this,n)}this._firingCount--}}i&&this._propagateEvent(n)}return this},listens:function(t,e,i,n){"string"!=typeof t&&console.warn('"string" type argument expected');var o=e,s=("function"!=typeof e&&(n=!!e,i=o=void 0),this._events&&this._events[t]);if(s&&s.length&&!1!==this._listens(t,o,i))return!0;if(n)for(var r in this._eventParents)if(this._eventParents[r].listens(t,e,i,n))return!0;return!1},_listens:function(t,e,i){if(this._events){var n=this._events[t]||[];if(!e)return!!n.length;i===this&&(i=void 0);for(var o=0,s=n.length;o<s;o++)if(n[o].fn===e&&n[o].ctx===i)return o}return!1},once:function(t,e,i){if("object"==typeof t)for(var n in t)this._on(n,t[n],e,!0);else for(var o=0,s=(t=W(t)).length;o<s;o++)this._on(t[o],e,i,!0);return this},addEventParent:function(t){return this._eventParents=this._eventParents||{},this._eventParents[h(t)]=t,this},removeEventParent:function(t){return this._eventParents&&delete this._eventParents[h(t)],this},_propagateEvent:function(t){for(var e in this._eventParents)this._eventParents[e].fire(t.type,l({layer:t.target,propagatedFrom:t.target},t),!0)}},it=(e.addEventListener=e.on,e.removeEventListener=e.clearAllEventListeners=e.off,e.addOneTimeEventListener=e.once,e.fireEvent=e.fire,e.hasEventListeners=e.listens,et.extend(e));function p(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e}var nt=Math.trunc||function(t){return 0<t?Math.floor(t):Math.ceil(t)};function m(t,e,i){return t instanceof p?t:d(t)?new p(t[0],t[1]):null==t?t:"object"==typeof t&&"x"in t&&"y"in t?new p(t.x,t.y):new p(t,e,i)}function f(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n<o;n++)this.extend(i[n])}function _(t,e){return!t||t instanceof f?t:new f(t,e)}function s(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n<o;n++)this.extend(i[n])}function g(t,e){return t instanceof s?t:new s(t,e)}function v(t,e,i){if(isNaN(t)||isNaN(e))throw new Error("Invalid LatLng object: ("+t+", "+e+")");this.lat=+t,this.lng=+e,void 0!==i&&(this.alt=+i)}function w(t,e,i){return t instanceof v?t:d(t)&&"object"!=typeof t[0]?3===t.length?new v(t[0],t[1],t[2]):2===t.length?new v(t[0],t[1]):null:null==t?t:"object"==typeof t&&"lat"in t?new v(t.lat,"lng"in t?t.lng:t.lon,t.alt):void 0===e?null:new v(t,e,i)}p.prototype={clone:function(){return new p(this.x,this.y)},add:function(t){return this.clone()._add(m(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(m(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new p(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new p(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=nt(this.x),this.y=nt(this.y),this},distanceTo:function(t){var e=(t=m(t)).x-this.x,t=t.y-this.y;return Math.sqrt(e*e+t*t)},equals:function(t){return(t=m(t)).x===this.x&&t.y===this.y},contains:function(t){return t=m(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+i(this.x)+", "+i(this.y)+")"}},f.prototype={extend:function(t){var e,i;if(t){if(t instanceof p||"number"==typeof t[0]||"x"in t)e=i=m(t);else if(e=(t=_(t)).min,i=t.max,!e||!i)return this;this.min||this.max?(this.min.x=Math.min(e.x,this.min.x),this.max.x=Math.max(i.x,this.max.x),this.min.y=Math.min(e.y,this.min.y),this.max.y=Math.max(i.y,this.max.y)):(this.min=e.clone(),this.max=i.clone())}return this},getCenter:function(t){return m((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return m(this.min.x,this.max.y)},getTopRight:function(){return m(this.max.x,this.min.y)},getTopLeft:function(){return this.min},getBottomRight:function(){return this.max},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var e,i;return(t=("number"==typeof t[0]||t instanceof p?m:_)(t))instanceof f?(e=t.min,i=t.max):e=i=t,e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.x<i.x,t=t.y>e.y&&n.y<i.y;return o&&t},isValid:function(){return!(!this.min||!this.max)},pad:function(t){var e=this.min,i=this.max,n=Math.abs(e.x-i.x)*t,t=Math.abs(e.y-i.y)*t;return _(m(e.x-n,e.y-t),m(i.x+n,i.y+t))},equals:function(t){return!!t&&(t=_(t),this.min.equals(t.getTopLeft())&&this.max.equals(t.getBottomRight()))}},s.prototype={extend:function(t){var e,i,n=this._southWest,o=this._northEast;if(t instanceof v)i=e=t;else{if(!(t instanceof s))return t?this.extend(w(t)||g(t)):this;if(e=t._southWest,i=t._northEast,!e||!i)return this}return n||o?(n.lat=Math.min(e.lat,n.lat),n.lng=Math.min(e.lng,n.lng),o.lat=Math.max(i.lat,o.lat),o.lng=Math.max(i.lng,o.lng)):(this._southWest=new v(e.lat,e.lng),this._northEast=new v(i.lat,i.lng)),this},pad:function(t){var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,t=Math.abs(e.lng-i.lng)*t;return new s(new v(e.lat-n,e.lng-t),new v(i.lat+n,i.lng+t))},getCenter:function(){return new v((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new v(this.getNorth(),this.getWest())},getSouthEast:function(){return new v(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t=("number"==typeof t[0]||t instanceof v||"lat"in t?w:g)(t);var e,i,n=this._southWest,o=this._northEast;return t instanceof s?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t,e.lat>=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.lat<i.lat,t=t.lng>e.lng&&n.lng<i.lng;return o&&t},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t,e){return!!t&&(t=g(t),this._southWest.equals(t.getSouthWest(),e)&&this._northEast.equals(t.getNorthEast(),e))},isValid:function(){return!(!this._southWest||!this._northEast)}};var ot={latLngToPoint:function(t,e){t=this.projection.project(t),e=this.scale(e);return this.transformation._transform(t,e)},pointToLatLng:function(t,e){e=this.scale(e),t=this.transformation.untransform(t,e);return this.projection.unproject(t)},project:function(t){return this.projection.project(t)},unproject:function(t){return this.projection.unproject(t)},scale:function(t){return 256*Math.pow(2,t)},zoom:function(t){return Math.log(t/256)/Math.LN2},getProjectedBounds:function(t){var e;return this.infinite?null:(e=this.projection.bounds,t=this.scale(t),new f(this.transformation.transform(e.min,t),this.transformation.transform(e.max,t)))},infinite:!(v.prototype={equals:function(t,e){return!!t&&(t=w(t),Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng))<=(void 0===e?1e-9:e))},toString:function(t){return"LatLng("+i(this.lat,t)+", "+i(this.lng,t)+")"},distanceTo:function(t){return st.distance(this,w(t))},wrap:function(){return st.wrapLatLng(this)},toBounds:function(t){var t=180*t/40075017,e=t/Math.cos(Math.PI/180*this.lat);return g([this.lat-t,this.lng-e],[this.lat+t,this.lng+e])},clone:function(){return new v(this.lat,this.lng,this.alt)}}),wrapLatLng:function(t){var e=this.wrapLng?H(t.lng,this.wrapLng,!0):t.lng;return new v(this.wrapLat?H(t.lat,this.wrapLat,!0):t.lat,e,t.alt)},wrapLatLngBounds:function(t){var e=t.getCenter(),i=this.wrapLatLng(e),n=e.lat-i.lat,e=e.lng-i.lng;return 0==n&&0==e?t:(i=t.getSouthWest(),t=t.getNorthEast(),new s(new v(i.lat-n,i.lng-e),new v(t.lat-n,t.lng-e)))}},st=l({},ot,{wrapLng:[-180,180],R:6371e3,distance:function(t,e){var i=Math.PI/180,n=t.lat*i,o=e.lat*i,s=Math.sin((e.lat-t.lat)*i/2),e=Math.sin((e.lng-t.lng)*i/2),t=s*s+Math.cos(n)*Math.cos(o)*e*e,i=2*Math.atan2(Math.sqrt(t),Math.sqrt(1-t));return this.R*i}}),rt=6378137,rt={R:rt,MAX_LATITUDE:85.0511287798,project:function(t){var e=Math.PI/180,i=this.MAX_LATITUDE,i=Math.max(Math.min(i,t.lat),-i),i=Math.sin(i*e);return new p(this.R*t.lng*e,this.R*Math.log((1+i)/(1-i))/2)},unproject:function(t){var e=180/Math.PI;return new v((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*e,t.x*e/this.R)},bounds:new f([-(rt=rt*Math.PI),-rt],[rt,rt])};function at(t,e,i,n){d(t)?(this._a=t[0],this._b=t[1],this._c=t[2],this._d=t[3]):(this._a=t,this._b=e,this._c=i,this._d=n)}function ht(t,e,i,n){return new at(t,e,i,n)}at.prototype={transform:function(t,e){return this._transform(t.clone(),e)},_transform:function(t,e){return t.x=(e=e||1)*(this._a*t.x+this._b),t.y=e*(this._c*t.y+this._d),t},untransform:function(t,e){return new p((t.x/(e=e||1)-this._b)/this._a,(t.y/e-this._d)/this._c)}};var lt=l({},st,{code:"EPSG:3857",projection:rt,transformation:ht(lt=.5/(Math.PI*rt.R),.5,-lt,.5)}),ut=l({},lt,{code:"EPSG:900913"});function ct(t){return document.createElementNS("http://www.w3.org/2000/svg",t)}function dt(t,e){for(var i,n,o,s,r="",a=0,h=t.length;a<h;a++){for(i=0,n=(o=t[a]).length;i<n;i++)r+=(i?"L":"M")+(s=o[i]).x+" "+s.y;r+=e?b.svg?"z":"x":""}return r||"M0 0"}var _t=document.documentElement.style,pt="ActiveXObject"in window,mt=pt&&!document.addEventListener,n="msLaunchUri"in navigator&&!("documentMode"in document),ft=y("webkit"),gt=y("android"),vt=y("android 2")||y("android 3"),yt=parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1],10),yt=gt&&y("Google")&&yt<537&&!("AudioNode"in window),xt=!!window.opera,wt=!n&&y("chrome"),bt=y("gecko")&&!ft&&!xt&&!pt,Pt=!wt&&y("safari"),Lt=y("phantom"),o="OTransition"in _t,Tt=0===navigator.platform.indexOf("Win"),Mt=pt&&"transition"in _t,zt="WebKitCSSMatrix"in window&&"m11"in new window.WebKitCSSMatrix&&!vt,_t="MozPerspective"in _t,Ct=!window.L_DISABLE_3D&&(Mt||zt||_t)&&!o&&!Lt,Zt="undefined"!=typeof orientation||y("mobile"),St=Zt&&ft,Et=Zt&&zt,kt=!window.PointerEvent&&window.MSPointerEvent,Ot=!(!window.PointerEvent&&!kt),At="ontouchstart"in window||!!window.TouchEvent,Bt=!window.L_NO_TOUCH&&(At||Ot),It=Zt&&xt,Rt=Zt&&bt,Nt=1<(window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI),Dt=function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("testPassiveEventSupport",u,e),window.removeEventListener("testPassiveEventSupport",u,e)}catch(t){}return t}(),jt=!!document.createElement("canvas").getContext,Ht=!(!document.createElementNS||!ct("svg").createSVGRect),Ft=!!Ht&&((Ft=document.createElement("div")).innerHTML="<svg/>","http://www.w3.org/2000/svg"===(Ft.firstChild&&Ft.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='<v:shape adj="1"/>',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Ft,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Wt=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Wt,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Wt,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=W(e),o=0,s=n.length;o<s;o++)t.classList.add(n[o]);else ve(t,e)||ye(t,((i=xe(t))?i+" ":"")+e)}function z(t,e){void 0!==t.classList?t.classList.remove(e):ye(t,F((" "+xe(t)+" ").replace(" "+e+" "," ")))}function ye(t,e){void 0===t.className.baseVal?t.className=e:t.className.baseVal=e}function xe(t){return void 0===(t=t.correspondingElement?t.correspondingElement:t).className.baseVal?t.className:t.className.baseVal}function C(t,e){if("opacity"in t.style)t.style.opacity=e;else if("filter"in t.style){var i=!1,n="DXImageTransform.Microsoft.Alpha";try{i=t.filters.item(n)}catch(t){if(1===e)return}e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=" progid:"+n+"(opacity="+e+")"}}function we(t){for(var e=document.documentElement.style,i=0;i<t.length;i++)if(t[i]in e)return t[i];return!1}function be(t,e,i){e=e||new p(0,0);t.style[ue]=(b.ie3d?"translate("+e.x+"px,"+e.y+"px)":"translate3d("+e.x+"px,"+e.y+"px,0)")+(i?" scale("+i+")":"")}function Z(t,e){t._leaflet_pos=e,b.any3d?be(t,e):(t.style.left=e.x+"px",t.style.top=e.y+"px")}function Pe(t){return t._leaflet_pos||new p(0,0)}function Le(){S(window,"dragstart",O)}function Te(){k(window,"dragstart",O)}function Me(t){for(;-1===t.tabIndex;)t=t.parentNode;t.style&&(ze(),le=(he=t).style.outline,t.style.outline="none",S(window,"keydown",ze))}function ze(){he&&(he.style.outline=le,le=he=void 0,k(window,"keydown",ze))}function Ce(t){for(;!((t=t.parentNode).offsetWidth&&t.offsetHeight||t===document.body););return t}function Ze(t){var e=t.getBoundingClientRect();return{x:e.width/t.offsetWidth||1,y:e.height/t.offsetHeight||1,boundingClientRect:e}}ae="onselectstart"in document?(re=function(){S(window,"selectstart",O)},function(){k(window,"selectstart",O)}):(se=we(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]),re=function(){var t;se&&(t=document.documentElement.style,oe=t[se],t[se]="none")},function(){se&&(document.documentElement.style[se]=oe,oe=void 0)});pt={__proto__:null,TRANSFORM:ue,TRANSITION:ce,TRANSITION_END:de,get:_e,getStyle:pe,create:P,remove:T,empty:me,toFront:fe,toBack:ge,hasClass:ve,addClass:M,removeClass:z,setClass:ye,getClass:xe,setOpacity:C,testProp:we,setTransform:be,setPosition:Z,getPosition:Pe,get disableTextSelection(){return re},get enableTextSelection(){return ae},disableImageDrag:Le,enableImageDrag:Te,preventOutline:Me,restoreOutline:ze,getSizedParentNode:Ce,getScale:Ze};function S(t,e,i,n){if(e&&"object"==typeof e)for(var o in e)ke(t,o,e[o],i);else for(var s=0,r=(e=W(e)).length;s<r;s++)ke(t,e[s],i,n);return this}var E="_leaflet_events";function k(t,e,i,n){if(1===arguments.length)Se(t),delete t[E];else if(e&&"object"==typeof e)for(var o in e)Oe(t,o,e[o],i);else if(e=W(e),2===arguments.length)Se(t,function(t){return-1!==G(e,t)});else for(var s=0,r=e.length;s<r;s++)Oe(t,e[s],i,n);return this}function Se(t,e){for(var i in t[E]){var n=i.split(/\d/)[0];e&&!e(n)||Oe(t,n,null,null,i)}}var Ee={mouseenter:"mouseover",mouseleave:"mouseout",wheel:!("onwheel"in window)&&"mousewheel"};function ke(e,t,i,n){var o,s,r=t+h(i)+(n?"_"+h(n):"");e[E]&&e[E][r]||(s=o=function(t){return i.call(n||e,t||window.event)},!b.touchNative&&b.pointer&&0===t.indexOf("touch")?o=Jt(e,t,o):b.touch&&"dblclick"===t?o=ne(e,o):"addEventListener"in e?"touchstart"===t||"touchmove"===t||"wheel"===t||"mousewheel"===t?e.addEventListener(Ee[t]||t,o,!!b.passiveEvents&&{passive:!1}):"mouseenter"===t||"mouseleave"===t?e.addEventListener(Ee[t],o=function(t){t=t||window.event,Fe(e,t)&&s(t)},!1):e.addEventListener(t,s,!1):e.attachEvent("on"+t,o),e[E]=e[E]||{},e[E][r]=o)}function Oe(t,e,i,n,o){o=o||e+h(i)+(n?"_"+h(n):"");var s,r,i=t[E]&&t[E][o];i&&(!b.touchNative&&b.pointer&&0===e.indexOf("touch")?(n=t,r=i,Gt[s=e]?n.removeEventListener(Gt[s],r,!1):console.warn("wrong event specified:",s)):b.touch&&"dblclick"===e?(n=i,(r=t).removeEventListener("dblclick",n.dblclick),r.removeEventListener("click",n.simDblclick)):"removeEventListener"in t?t.removeEventListener(Ee[e]||e,i,!1):t.detachEvent("on"+e,i),t[E][o]=null)}function Ae(t){return t.stopPropagation?t.stopPropagation():t.originalEvent?t.originalEvent._stopped=!0:t.cancelBubble=!0,this}function Be(t){return ke(t,"wheel",Ae),this}function Ie(t){return S(t,"mousedown touchstart dblclick contextmenu",Ae),t._leaflet_disable_click=!0,this}function O(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this}function Re(t){return O(t),Ae(t),this}function Ne(t){if(t.composedPath)return t.composedPath();for(var e=[],i=t.target;i;)e.push(i),i=i.parentNode;return e}function De(t,e){var i,n;return e?(n=(i=Ze(e)).boundingClientRect,new p((t.clientX-n.left)/i.x-e.clientLeft,(t.clientY-n.top)/i.y-e.clientTop)):new p(t.clientX,t.clientY)}var je=b.linux&&b.chrome?window.devicePixelRatio:b.mac?3*window.devicePixelRatio:0<window.devicePixelRatio?2*window.devicePixelRatio:1;function He(t){return b.edge?t.wheelDeltaY/2:t.deltaY&&0===t.deltaMode?-t.deltaY/je:t.deltaY&&1===t.deltaMode?20*-t.deltaY:t.deltaY&&2===t.deltaMode?60*-t.deltaY:t.deltaX||t.deltaZ?0:t.wheelDelta?(t.wheelDeltaY||t.wheelDelta)/2:t.detail&&Math.abs(t.detail)<32765?20*-t.detail:t.detail?t.detail/-32765*60:0}function Fe(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(t){return!1}return i!==t}var mt={__proto__:null,on:S,off:k,stopPropagation:Ae,disableScrollPropagation:Be,disableClickPropagation:Ie,preventDefault:O,stop:Re,getPropagationPath:Ne,getMousePosition:De,getWheelDelta:He,isExternalTarget:Fe,addListener:S,removeListener:k},We=it.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=Pe(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=x(this._animate,this),this._step()},_step:function(t){var e=+new Date-this._startTime,i=1e3*this._duration;e<i?this._runFrame(this._easeOut(e/i),t):(this._runFrame(1),this._complete())},_runFrame:function(t,e){t=this._startPos.add(this._offset.multiplyBy(t));e&&t._round(),Z(this._el,t),this.fire("step")},_complete:function(){r(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),A=it.extend({options:{crs:lt,center:void 0,zoom:void 0,minZoom:void 0,maxZoom:void 0,layers:[],maxBounds:void 0,renderer:void 0,zoomAnimation:!0,zoomAnimationThreshold:4,fadeAnimation:!0,markerZoomAnimation:!0,transform3DLimit:8388608,zoomSnap:1,zoomDelta:1,trackResize:!0},initialize:function(t,e){e=c(this,e),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this._initContainer(t),this._initLayout(),this._onResize=a(this._onResize,this),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),void 0!==e.zoom&&(this._zoom=this._limitZoom(e.zoom)),e.center&&void 0!==e.zoom&&this.setView(w(e.center),e.zoom,{reset:!0}),this.callInitHooks(),this._zoomAnimated=ce&&b.any3d&&!b.mobileOpera&&this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),S(this._proxy,de,this._catchTransitionEnd,this)),this._addLayers(this.options.layers)},setView:function(t,e,i){if((e=void 0===e?this._zoom:this._limitZoom(e),t=this._limitCenter(w(t),e,this.options.maxBounds),i=i||{},this._stop(),this._loaded&&!i.reset&&!0!==i)&&(void 0!==i.animate&&(i.zoom=l({animate:i.animate},i.zoom),i.pan=l({animate:i.animate,duration:i.duration},i.pan)),this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,i.zoom):this._tryAnimatedPan(t,i.pan)))return clearTimeout(this._sizeTimer),this;return this._resetView(t,e,i.pan&&i.pan.noMoveStart),this},setZoom:function(t,e){return this._loaded?this.setView(this.getCenter(),t,{zoom:e}):(this._zoom=t,this)},zoomIn:function(t,e){return t=t||(b.any3d?this.options.zoomDelta:1),this.setZoom(this._zoom+t,e)},zoomOut:function(t,e){return t=t||(b.any3d?this.options.zoomDelta:1),this.setZoom(this._zoom-t,e)},setZoomAround:function(t,e,i){var n=this.getZoomScale(e),o=this.getSize().divideBy(2),t=(t instanceof p?t:this.latLngToContainerPoint(t)).subtract(o).multiplyBy(1-1/n),n=this.containerPointToLatLng(o.add(t));return this.setView(n,e,{zoom:i})},_getBoundsCenterZoom:function(t,e){e=e||{},t=t.getBounds?t.getBounds():g(t);var i=m(e.paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.getBoundsZoom(t,!1,i.add(n));return(o="number"==typeof e.maxZoom?Math.min(e.maxZoom,o):o)===1/0?{center:t.getCenter(),zoom:o}:(e=n.subtract(i).divideBy(2),n=this.project(t.getSouthWest(),o),i=this.project(t.getNorthEast(),o),{center:this.unproject(n.add(i).divideBy(2).add(e),o),zoom:o})},fitBounds:function(t,e){if((t=g(t)).isValid())return t=this._getBoundsCenterZoom(t,e),this.setView(t.center,t.zoom,e);throw new Error("Bounds are not valid.")},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,e){return this.setView(t,this._zoom,{pan:e})},panBy:function(t,e){var i;return e=e||{},(t=m(t).round()).x||t.y?(!0===e.animate||this.getSize().contains(t)?(this._panAnim||(this._panAnim=new We,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),e.noMoveStart||this.fire("movestart"),!1!==e.animate?(M(this._mapPane,"leaflet-pan-anim"),i=this._getMapPanePos().subtract(t).round(),this._panAnim.run(this._mapPane,i,e.duration||.25,e.easeLinearity)):(this._rawPanBy(t),this.fire("move").fire("moveend"))):this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom()),this):this.fire("moveend")},flyTo:function(n,o,t){if(!1===(t=t||{}).animate||!b.any3d)return this.setView(n,o,t);this._stop();var s=this.project(this.getCenter()),r=this.project(n),e=this.getSize(),a=this._zoom,h=(n=w(n),o=void 0===o?a:o,Math.max(e.x,e.y)),i=h*this.getZoomScale(a,o),l=r.distanceTo(s)||1,u=1.42,c=u*u;function d(t){t=(i*i-h*h+(t?-1:1)*c*c*l*l)/(2*(t?i:h)*c*l),t=Math.sqrt(t*t+1)-t;return t<1e-9?-18:Math.log(t)}function _(t){return(Math.exp(t)-Math.exp(-t))/2}function p(t){return(Math.exp(t)+Math.exp(-t))/2}var m=d(0);function f(t){return h*(p(m)*(_(t=m+u*t)/p(t))-_(m))/c}var g=Date.now(),v=(d(1)-m)/u,y=t.duration?1e3*t.duration:1e3*v*.8;return this._moveStart(!0,t.noMoveStart),function t(){var e=(Date.now()-g)/y,i=(1-Math.pow(1-e,1.5))*v;e<=1?(this._flyToFrame=x(t,this),this._move(this.unproject(s.add(r.subtract(s).multiplyBy(f(i)/l)),a),this.getScaleZoom(h/(e=i,h*(p(m)/p(m+u*e))),a),{flyTo:!0})):this._move(n,o)._moveEnd(!0)}.call(this),this},flyToBounds:function(t,e){t=this._getBoundsCenterZoom(t,e);return this.flyTo(t.center,t.zoom,e)},setMaxBounds:function(t){return t=g(t),this.listens("moveend",this._panInsideMaxBounds)&&this.off("moveend",this._panInsideMaxBounds),t.isValid()?(this.options.maxBounds=t,this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds)):(this.options.maxBounds=null,this)},setMinZoom:function(t){var e=this.options.minZoom;return this.options.minZoom=t,this._loaded&&e!==t&&(this.fire("zoomlevelschange"),this.getZoom()<this.options.minZoom)?this.setZoom(t):this},setMaxZoom:function(t){var e=this.options.maxZoom;return this.options.maxZoom=t,this._loaded&&e!==t&&(this.fire("zoomlevelschange"),this.getZoom()>this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!Fe(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;s<i.length;s++)i[s].listens(e,!0)&&o.push(i[s]);n=o.concat(n)}if(n.length){"contextmenu"===e&&O(t);var r,a=n[0],h={originalEvent:t};for("keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(r=a.getLatLng&&(!a._radius||a._radius<=10),h.containerPoint=r?this.latLngToContainerPoint(a.getLatLng()):this.mouseEventToContainerPoint(t),h.layerPoint=this.containerPointToLayerPoint(h.containerPoint),h.latlng=r?a.getLatLng():this.layerPointToLatLng(h.layerPoint)),s=0;s<n.length;s++)if(n[s].fire(e,h,!0),h.originalEvent._stopped||!1===n[s].options.bubblingMouseEvents&&-1!==G(this._mouseEvents,e))return}},_draggableMoved:function(t){return(t=t.dragging&&t.dragging.enabled()?t:this).dragging&&t.dragging.moved()||this.boxZoom&&this.boxZoom.moved()},_clearHandlers:function(){for(var t=0,e=this._handlers.length;t<e;t++)this._handlers[t].disable()},whenReady:function(t,e){return this._loaded?t.call(e||this,{target:this}):this.on("load",t,e),this},_getMapPanePos:function(){return Pe(this._mapPane)||new p(0,0)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(t,e){return(t&&void 0!==e?this._getNewPixelOrigin(t,e):this.getPixelOrigin()).subtract(this._getMapPanePos())},_getNewPixelOrigin:function(t,e){var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._add(this._getMapPanePos())._round()},_latLngToNewLayerPoint:function(t,e,i){i=this._getNewPixelOrigin(i,e);return this.project(t,e)._subtract(i)},_latLngBoundsToNewLayerBounds:function(t,e,i){i=this._getNewPixelOrigin(i,e);return _([this.project(t.getSouthWest(),e)._subtract(i),this.project(t.getNorthWest(),e)._subtract(i),this.project(t.getSouthEast(),e)._subtract(i),this.project(t.getNorthEast(),e)._subtract(i)])},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,e,i){var n,o;return!i||(n=this.project(t,e),o=this.getSize().divideBy(2),o=new f(n.subtract(o),n.add(o)),o=this._getBoundsOffset(o,i,e),Math.abs(o.x)<=1&&Math.abs(o.y)<=1)?t:this.unproject(n.add(o),e)},_limitOffset:function(t,e){var i;return e?(i=new f((i=this.getPixelBounds()).min.add(t),i.max.add(t)),t.add(this._getBoundsOffset(i,e))):t},_getBoundsOffset:function(t,e,i){e=_(this.project(e.getNorthEast(),i),this.project(e.getSouthWest(),i)),i=e.min.subtract(t.min),e=e.max.subtract(t.max);return new p(this._rebound(i.x,-e.x),this._rebound(i.y,-e.y))},_rebound:function(t,e){return 0<t+e?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom(),n=b.any3d?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(e,Math.min(i,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){z(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){t=this._getCenterOffset(t)._trunc();return!(!0!==(e&&e.animate)&&!this.getSize().contains(t))&&(this.panBy(t,e),!0)},_createAnimProxy:function(){var t=this._proxy=P("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(t){var e=ue,i=this._proxy.style[e];be(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),i===this._proxy.style[e]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",this._animMoveEnd,this),this._on("unload",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){T(this._proxy),this.off("load moveend",this._animMoveEnd,this),delete this._proxy},_animMoveEnd:function(){var t=this.getCenter(),e=this.getZoom();be(this._proxy,this.project(t,e),this.getZoomScale(e,1))},_catchTransitionEnd:function(t){this._animatingZoom&&0<=t.propertyName.indexOf("transform")&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(!this._animatingZoom){if(i=i||{},!this._zoomAnimated||!1===i.animate||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var Ve,B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0<t.screenX&&0<t.screenY&&this._map.getContainer().focus()}}),qe=(A.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){var i=this._controlCorners={},n="leaflet-",o=this._controlContainer=P("div",n+"control-container",this._container);function t(t,e){i[t+e]=P("div",n+t+" "+n+e,o)}t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){for(var t in this._controlCorners)T(this._controlCorners[t]);T(this._controlContainer),delete this._controlCorners,delete this._controlContainer}}),B.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,e,i,n){return i<n?-1:n<i?1:0}},initialize:function(t,e,i){for(var n in c(this,i),this._layerControlInputs=[],this._layers=[],this._lastZIndex=0,this._handlingClick=!1,t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0)},onAdd:function(t){this._initLayout(),this._update(),(this._map=t).on("zoomend",this._checkDisabledLayers,this);for(var e=0;e<this._layers.length;e++)this._layers[e].layer.on("add remove",this._onLayerChange,this);return this._container},addTo:function(t){return B.prototype.addTo.call(this,t),this._expandIfNotCollapsed()},onRemove:function(){this._map.off("zoomend",this._checkDisabledLayers,this);for(var t=0;t<this._layers.length;t++)this._layers[t].layer.off("add remove",this._onLayerChange,this)},addBaseLayer:function(t,e){return this._addLayer(t,e),this._map?this._update():this},addOverlay:function(t,e){return this._addLayer(t,e,!0),this._map?this._update():this},removeLayer:function(t){t.off("add remove",this._onLayerChange,this);t=this._getLayer(h(t));return t&&this._layers.splice(this._layers.indexOf(t),1),this._map?this._update():this},expand:function(){M(this._container,"leaflet-control-layers-expanded"),this._section.style.height=null;var t=this._map.getSize().y-(this._container.offsetTop+50);return t<this._section.clientHeight?(M(this._section,"leaflet-control-layers-scrollbar"),this._section.style.height=t+"px"):z(this._section,"leaflet-control-layers-scrollbar"),this._checkDisabledLayers(),this},collapse:function(){return z(this._container,"leaflet-control-layers-expanded"),this},_initLayout:function(){var t="leaflet-control-layers",e=this._container=P("div",t),i=this.options.collapsed,n=(e.setAttribute("aria-haspopup",!0),Ie(e),Be(e),this._section=P("section",t+"-list")),o=(i&&(this._map.on("click",this.collapse,this),S(e,{mouseenter:this._expandSafely,mouseleave:this.collapse},this)),this._layersLink=P("a",t+"-toggle",e));o.href="#",o.title="Layers",o.setAttribute("role","button"),S(o,{keydown:function(t){13===t.keyCode&&this._expandSafely()},click:function(t){O(t),this._expandSafely()}},this),i||this.expand(),this._baseLayersList=P("div",t+"-base",n),this._separator=P("div",t+"-separator",n),this._overlaysList=P("div",t+"-overlays",n),e.appendChild(n)},_getLayer:function(t){for(var e=0;e<this._layers.length;e++)if(this._layers[e]&&h(this._layers[e].layer)===t)return this._layers[e]},_addLayer:function(t,e,i){this._map&&t.on("add remove",this._onLayerChange,this),this._layers.push({layer:t,name:e,overlay:i}),this.options.sortLayers&&this._layers.sort(a(function(t,e){return this.options.sortFunction(t.layer,e.layer,t.name,e.name)},this)),this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex)),this._expandIfNotCollapsed()},_update:function(){if(this._container){me(this._baseLayersList),me(this._overlaysList),this._layerControlInputs=[];for(var t,e,i,n=0,o=0;o<this._layers.length;o++)i=this._layers[o],this._addItem(i),e=e||i.overlay,t=t||!i.overlay,n+=i.overlay?0:1;this.options.hideSingleBase&&(this._baseLayersList.style.display=(t=t&&1<n)?"":"none"),this._separator.style.display=e&&t?"":"none"}return this},_onLayerChange:function(t){this._handlingClick||this._update();var e=this._getLayer(h(t.target)),t=e.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;t&&this._map.fire(t,e)},_createRadioElement:function(t,e){t='<input type="radio" class="leaflet-control-layers-selector" name="'+t+'"'+(e?' checked="checked"':"")+"/>",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;s<o.length;s++)this._map.hasLayer(o[s])&&this._map.removeLayer(o[s]);for(s=0;s<n.length;s++)this._map.hasLayer(n[s])||this._map.addLayer(n[s]);this._handlingClick=!1,this._refocusOnMap()},_checkDisabledLayers:function(){for(var t,e,i=this._layerControlInputs,n=this._map.getZoom(),o=i.length-1;0<=o;o--)t=i[o],e=this._getLayer(t.layerId).layer,t.disabled=void 0!==e.options.minZoom&&n<e.options.minZoom||void 0!==e.options.maxZoom&&n>e.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section;S(t,"click",O),this.expand(),setTimeout(function(){k(t,"click",O)})}})),Ge=B.extend({options:{position:"topleft",zoomInText:'<span aria-hidden="true">+</span>',zoomInTitle:"Zoom in",zoomOutText:'<span aria-hidden="true">&#x2212;</span>',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoom<this._map.getMaxZoom()&&this._map.zoomIn(this._map.options.zoomDelta*(t.shiftKey?3:1))},_zoomOut:function(t){!this._disabled&&this._map._zoom>this._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ke=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new Ge,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280<t?(i=this._getRoundNum(e=t/5280),this._updateScale(this._iScale,i+" mi",i/e)):(i=this._getRoundNum(t),this._updateScale(this._iScale,i+" ft",i/t))},_updateScale:function(t,e,i){t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),t=t/e;return e*(t=10<=t?10:5<=t?5:3<=t?3:2<=t?2:1)}})),Ye=B.extend({options:{position:"bottomright",prefix:'<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">'+(b.inlineSvg?'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg> ':"")+"Leaflet</a>"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' <span aria-hidden="true">|</span> ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ye).addTo(this)}),B.Layers=qe,B.Zoom=Ge,B.Scale=Ke,B.Attribution=Ye,Ue.layers=function(t,e,i){return new qe(t,e,i)},Ue.zoom=function(t){return new Ge(t)},Ue.scale=function(t){return new Ke(t)},Ue.attribution=function(t){return new Ye(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Xe=b.touch?"touchstart mousedown":"mousedown",Je=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Xe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Je._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Xe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Je._dragging===this&&this.finishDrag():Je._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Je._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1<t.touches.length?this._moved=!0:!(e=new p((e=t.touches&&1===t.touches.length?t.touches[0]:t).clientX,e.clientY)._subtract(this._startPoint)).x&&!e.y||Math.abs(e.x)+Math.abs(e.y)<this.options.clickTolerance||(e.x/=this._parentScale.x,e.y/=this._parentScale.y,O(t),this._moved||(this.fire("dragstart"),this._moved=!0,M(document.body,"leaflet-dragging"),this._lastTarget=t.target||t.srcElement,window.SVGElementInstance&&this._lastTarget instanceof window.SVGElementInstance&&(this._lastTarget=this._lastTarget.correspondingUseElement),M(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(e),this._moving=!0,this._lastEvent=t,this._updatePosition()))},_updatePosition:function(){var t={originalEvent:this._lastEvent};this.fire("predrag",t),Z(this._element,this._newPos),this.fire("drag",t)},_onUp:function(){this._enabled&&this.finishDrag()},finishDrag:function(t){z(document.body,"leaflet-dragging"),this._lastTarget&&(z(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null),k(document,"mousemove touchmove",this._onMove,this),k(document,"mouseup touchend touchcancel",this._onUp,this),Te(),ae(),this._moved&&this._moving&&this.fire("dragend",{noInertia:t,distance:this._newPos.distanceTo(this._startPos)}),this._moving=!1,Je._dragging=!1}});function $e(t,e){if(e&&t.length){var i=t=function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;n<s;n++)(function(t,e){var i=e.x-t.x,e=e.y-t.y;return i*i+e*e})(t[n],t[o])>e&&(i.push(t[n]),o=n);o<s-1&&i.push(t[s-1]);return i}(t,e=e*e),n=i.length,o=new(typeof Uint8Array!=void 0+""?Uint8Array:Array)(n);o[0]=o[n-1]=1,function t(e,i,n,o,s){var r,a,h,l=0;for(a=o+1;a<=s-1;a++)h=ni(e[a],e[o],e[s],!0),l<h&&(r=a,l=h);n<l&&(i[r]=1,t(e,i,n,o,r),t(e,i,n,r,s))}(i,o,e,0,n-1);var s,r=[];for(s=0;s<n;s++)o[s]&&r.push(i[s]);return r}return t.slice()}function Qe(t,e,i){return Math.sqrt(ni(t,e,i,!0))}function ti(t,e,i,n,o){var s,r,a,h=n?Ve:ii(t,i),l=ii(e,i);for(Ve=l;;){if(!(h|l))return[t,e];if(h&l)return!1;a=ii(r=ei(t,e,s=h||l,i,o),i),s===h?(t=r,h=a):(e=r,l=a)}}function ei(t,e,i,n,o){var s,r,a=e.x-t.x,e=e.y-t.y,h=n.min,n=n.max;return 8&i?(s=t.x+a*(n.y-t.y)/e,r=n.y):4&i?(s=t.x+a*(h.y-t.y)/e,r=h.y):2&i?(s=n.x,r=t.y+e*(n.x-t.x)/a):1&i&&(s=h.x,r=t.y+e*(h.x-t.x)/a),new p(s,r,o)}function ii(t,e){var i=0;return t.x<e.min.x?i|=1:t.x>e.max.x&&(i|=2),t.y<e.min.y?i|=4:t.y>e.max.y&&(i|=8),i}function ni(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0<a&&(1<(a=((t.x-o)*s+(t.y-e)*r)/a)?(o=i.x,e=i.y):0<a&&(o+=s*a,e+=r*a)),s=t.x-o,r=t.y-e,n?s*s+r*r:new p(o,e)}function I(t){return!d(t[0])||"object"!=typeof t[0][0]&&void 0!==t[0][0]}function oi(t){return console.warn("Deprecated use of _flat, please use L.LineUtil.isFlat instead."),I(t)}function si(t,e){var i,n,o,s,r;if(!t||0===t.length)throw new Error("latlngs not passed");I(t)||(console.warn("latlngs are not flat! Only the first ring will be used"),t=t[0]);var a,h=[];for(a in t)h.push(e.project(w(t[a])));for(var l=h.length,u=0,c=0;u<l-1;u++)c+=h[u].distanceTo(h[u+1])/2;if(0===c)r=h[0];else for(i=u=0;u<l-1;u++)if(n=h[u],o=h[u+1],c<(i+=s=n.distanceTo(o))){r=[o.x-(s=(i-c)/s)*(o.x-n.x),o.y-s*(o.y-n.y)];break}return e.unproject(m(r))}gt={__proto__:null,simplify:$e,pointToSegmentDistance:Qe,closestPointOnSegment:function(t,e,i){return ni(t,e,i)},clipSegment:ti,_getEdgeIntersection:ei,_getBitCode:ii,_sqClosestPointOnSegment:ni,isFlat:I,_flat:oi,polylineCenter:si};function ri(t,e,i){for(var n,o,s,r,a,h,l,u=[1,4,2,8],c=0,d=t.length;c<d;c++)t[c]._code=ii(t[c],e);for(s=0;s<4;s++){for(h=u[s],n=[],c=0,o=(d=t.length)-1;c<d;o=c++)r=t[c],a=t[o],r._code&h?a._code&h||((l=ei(a,r,h,e,i))._code=ii(l,e),n.push(l)):(a._code&h&&((l=ei(a,r,h,e,i))._code=ii(l,e),n.push(l)),n.push(r));t=n}return t}function ai(t,e){var i,n,o,s,r,a;if(!t||0===t.length)throw new Error("latlngs not passed");I(t)||(console.warn("latlngs are not flat! Only the first ring will be used"),t=t[0]);var h,l=[];for(h in t)l.push(e.project(w(t[h])));for(var u=l.length,c=s=r=0,d=0,_=u-1;d<u;_=d++)i=l[d],n=l[_],o=i.y*n.x-n.y*i.x,s+=(i.x+n.x)*o,r+=(i.y+n.y)*o,c+=3*o;return a=0===c?l[0]:[s/c,r/c],e.unproject(m(a))}var vt={__proto__:null,clipPolygon:ri,polygonCenter:ai},yt={project:function(t){return new p(t.lng,t.lat)},unproject:function(t){return new v(t.y,t.x)},bounds:new f([-180,-90],[180,90])},xt={R:6378137,R_MINOR:6356752.314245179,bounds:new f([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(t){var e=Math.PI/180,i=this.R,n=t.lat*e,o=this.R_MINOR/i,o=Math.sqrt(1-o*o),s=o*Math.sin(n),s=Math.tan(Math.PI/4-n/2)/Math.pow((1-s)/(1+s),o/2),n=-i*Math.log(Math.max(s,1e-10));return new p(t.lng*e*i,n)},unproject:function(t){for(var e,i=180/Math.PI,n=this.R,o=this.R_MINOR/n,s=Math.sqrt(1-o*o),r=Math.exp(-t.y/n),a=Math.PI/2-2*Math.atan(r),h=0,l=.1;h<15&&1e-7<Math.abs(l);h++)e=s*Math.sin(a),e=Math.pow((1-e)/(1+e),s/2),a+=l=Math.PI/2-2*Math.atan(r*e)-a;return new v(a*i,t.x*i/n)}},wt={__proto__:null,LonLat:yt,Mercator:xt,SphericalMercator:rt},Pt=l({},st,{code:"EPSG:3395",projection:xt,transformation:ht(bt=.5/(Math.PI*xt.R),.5,-bt,.5)}),hi=l({},st,{code:"EPSG:4326",projection:yt,transformation:ht(1/180,1,-1/180,.5)}),Lt=l({},ot,{projection:yt,transformation:ht(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,e){var i=e.lng-t.lng,e=e.lat-t.lat;return Math.sqrt(i*i+e*e)},infinite:!0}),o=(ot.Earth=st,ot.EPSG3395=Pt,ot.EPSG3857=lt,ot.EPSG900913=ut,ot.EPSG4326=hi,ot.Simple=Lt,it.extend({options:{pane:"overlayPane",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[h(t)]=this},removeInteractiveTarget:function(t){return delete this._map._targets[h(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var e,i=t.target;i.hasLayer(this)&&(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents&&(e=this.getEvents(),i.on(e,this),this.once("remove",function(){i.off(e,this)},this)),this.onAdd(i),this.fire("add"),i.fire("layeradd",{layer:this}))}})),li=(A.include({addLayer:function(t){var e;if(t._layerAdd)return e=h(t),this._layers[e]||((this._layers[e]=t)._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t)),this;throw new Error("The provided object is not a Layer.")},removeLayer:function(t){var e=h(t);return this._layers[e]&&(this._loaded&&t.onRemove(this),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null),this},hasLayer:function(t){return h(t)in this._layers},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},_addLayers:function(t){for(var e=0,i=(t=t?d(t)?t:[t]:[]).length;e<i;e++)this.addLayer(t[e])},_addZoomLimit:function(t){isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[h(t)]=t,this._updateZoomLevels())},_removeZoomLimit:function(t){t=h(t);this._zoomBoundLayers[t]&&(delete this._zoomBoundLayers[t],this._updateZoomLevels())},_updateZoomLevels:function(){var t,e=1/0,i=-1/0,n=this._getZoomSpan();for(t in this._zoomBoundLayers)var o=this._zoomBoundLayers[t].options,e=void 0===o.minZoom?e:Math.min(e,o.minZoom),i=void 0===o.maxZoom?i:Math.max(i,o.maxZoom);this._layersMaxZoom=i===-1/0?void 0:i,this._layersMinZoom=e===1/0?void 0:e,n!==this._getZoomSpan()&&this.fire("zoomlevelschange"),void 0===this.options.maxZoom&&this._layersMaxZoom&&this.getZoom()>this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()<this._layersMinZoom&&this.setZoom(this._layersMinZoom)}}),o.extend({initialize:function(t,e){var i,n;if(c(this,e),this._layers={},t)for(i=0,n=t.length;i<n;i++)this.addLayer(t[i])},addLayer:function(t){var e=this.getLayerId(t);return this._layers[e]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){t=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[t]&&this._map.removeLayer(this._layers[t]),delete this._layers[t],this},hasLayer:function(t){return("number"==typeof t?t:this.getLayerId(t))in this._layers},clearLayers:function(){return this.eachLayer(this.removeLayer,this)},invoke:function(t){var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)(i=this._layers[e])[t]&&i[t].apply(i,n);return this},onAdd:function(t){this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t)},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];return this.eachLayer(t.push,t),t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:h})),ui=li.extend({addLayer:function(t){return this.hasLayer(t)?this:(t.addEventParent(this),li.prototype.addLayer.call(this,t),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?((t=t in this._layers?this._layers[t]:t).removeEventParent(this),li.prototype.removeLayer.call(this,t),this.fire("layerremove",{layer:t})):this},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t,e=new s;for(t in this._layers){var i=this._layers[t];e.extend(i.getBounds?i.getBounds():i.getLatLng())}return e}}),ci=et.extend({options:{popupAnchor:[0,0],tooltipAnchor:[0,0],crossOrigin:!1},initialize:function(t){c(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(i)return i=this._createImg(i,e&&"IMG"===e.tagName?e:null),this._setIconStyles(i,t),!this.options.crossOrigin&&""!==this.options.crossOrigin||(i.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),i;if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null},_setIconStyles:function(t,e){var i=this.options,n=i[e+"Size"],n=m(n="number"==typeof n?[n,n]:n),o=m("shadow"===e&&i.shadowAnchor||i.iconAnchor||n&&n.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),o&&(t.style.marginLeft=-o.x+"px",t.style.marginTop=-o.y+"px"),n&&(t.style.width=n.x+"px",t.style.height=n.y+"px")},_createImg:function(t,e){return(e=e||document.createElement("img")).src=t,e},_getIconUrl:function(t){return b.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}});var di=ci.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return"string"!=typeof di.imagePath&&(di.imagePath=this._detectIconPath()),(this.options.imagePath||di.imagePath)+ci.prototype._getIconUrl.call(this,t)},_stripUrl:function(t){function e(t,e,i){return(e=e.exec(t))&&e[i]}return(t=e(t,/^url\((['"])?(.+)\1\)$/,2))&&e(t,/^(.*)marker-icon\.png$/,1)},_detectIconPath:function(){var t=P("div","leaflet-default-icon-path",document.body),e=pe(t,"background-image")||pe(t,"backgroundImage");return document.body.removeChild(t),(e=this._stripUrl(e))?e:(t=document.querySelector('link[href$="leaflet.css"]'))?t.href.substring(0,t.href.length-"leaflet.css".length-1):""}}),_i=n.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new Je(t,t,!0)),this._draggable.on({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).enable(),M(t,"leaflet-marker-draggable")},removeHooks:function(){this._draggable.off({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).disable(),this._marker._icon&&z(this._marker._icon,"leaflet-marker-draggable")},moved:function(){return this._draggable&&this._draggable._moved},_adjustPan:function(t){var e=this._marker,i=e._map,n=this._marker.options.autoPanSpeed,o=this._marker.options.autoPanPadding,s=Pe(e._icon),r=i.getPixelBounds(),a=i.getPixelOrigin(),a=_(r.min._subtract(a).add(o),r.max._subtract(a).subtract(o));a.contains(s)||(o=m((Math.max(a.max.x,s.x)-a.max.x)/(r.max.x-a.max.x)-(Math.min(a.min.x,s.x)-a.min.x)/(r.min.x-a.min.x),(Math.max(a.max.y,s.y)-a.max.y)/(r.max.y-a.max.y)-(Math.min(a.min.y,s.y)-a.min.y)/(r.min.y-a.min.y)).multiplyBy(n),i.panBy(o,{animate:!1}),this._draggable._newPos._add(o),this._draggable._startPos._add(o),Z(e._icon,this._draggable._newPos),this._onDrag(t),this._panRequest=x(this._adjustPan.bind(this,t)))},_onDragStart:function(){this._oldLatLng=this._marker.getLatLng(),this._marker.closePopup&&this._marker.closePopup(),this._marker.fire("movestart").fire("dragstart")},_onPreDrag:function(t){this._marker.options.autoPan&&(r(this._panRequest),this._panRequest=x(this._adjustPan.bind(this,t)))},_onDrag:function(t){var e=this._marker,i=e._shadow,n=Pe(e._icon),o=e._map.layerPointToLatLng(n);i&&Z(i,n),e._latlng=o,t.latlng=o,t.oldLatLng=this._oldLatLng,e.fire("move",t).fire("drag",t)},_onDragEnd:function(t){r(this._panRequest),delete this._oldLatLng,this._marker.fire("moveend").fire("dragend",t)}}),pi=o.extend({options:{icon:new di,interactive:!0,keyboard:!0,title:"",alt:"Marker",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",shadowPane:"shadowPane",bubblingMouseEvents:!1,autoPanOnFocus:!0,draggable:!1,autoPan:!1,autoPanPadding:[50,50],autoPanSpeed:10},initialize:function(t,e){c(this,e),this._latlng=w(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),delete this.dragging,this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var e=this._latlng;return this._latlng=w(t),this.update(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},getIcon:function(){return this.options.icon},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){var t;return this._icon&&this._map&&(t=this._map.latLngToLayerPoint(this._latlng).round(),this._setPos(t)),this},_initIcon:function(){var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1,i=(i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),"IMG"===i.tagName&&(i.alt=t.alt||"")),M(i,e),t.keyboard&&(i.tabIndex="0",i.setAttribute("role","button")),this._icon=i,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex}),this.options.autoPanOnFocus&&S(i,"focus",this._panOnFocus,this),t.icon.createShadow(this._shadow)),o=!1;i!==this._shadow&&(this._removeShadow(),o=!0),i&&(M(i,e),i.alt=""),this._shadow=i,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),i&&o&&this.getPane(t.shadowPane).appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),this.options.autoPanOnFocus&&k(this._icon,"focus",this._panOnFocus,this),T(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&T(this._shadow),this._shadow=null},_setPos:function(t){this._icon&&Z(this._icon,t),this._shadow&&Z(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon&&(this._icon.style.zIndex=this._zIndex+t)},_animateZoom:function(t){t=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(t)},_initInteraction:function(){var t;this.options.interactive&&(M(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),_i&&(t=this.options.draggable,this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new _i(this),t&&this.dragging.enable()))},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;this._icon&&C(this._icon,t),this._shadow&&C(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_panOnFocus:function(){var t,e,i=this._map;i&&(t=(e=this.options.icon.options).iconSize?m(e.iconSize):m(0,0),e=e.iconAnchor?m(e.iconAnchor):m(0,0),i.panInside(this._latlng,{paddingTopLeft:e,paddingBottomRight:t.subtract(e)}))},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor}});var mi=o.extend({options:{stroke:!0,color:"#3388ff",weight:3,opacity:1,lineCap:"round",lineJoin:"round",dashArray:null,dashOffset:null,fill:!1,fillColor:null,fillOpacity:.2,fillRule:"evenodd",interactive:!0,bubblingMouseEvents:!0},beforeAdd:function(t){this._renderer=t.getRenderer(this)},onAdd:function(){this._renderer._initPath(this),this._reset(),this._renderer._addPath(this)},onRemove:function(){this._renderer._removePath(this)},redraw:function(){return this._map&&this._renderer._updatePath(this),this},setStyle:function(t){return c(this,t),this._renderer&&(this._renderer._updateStyle(this),this.options.stroke&&t&&Object.prototype.hasOwnProperty.call(t,"weight")&&this._updateBounds()),this},bringToFront:function(){return this._renderer&&this._renderer._bringToFront(this),this},bringToBack:function(){return this._renderer&&this._renderer._bringToBack(this),this},getElement:function(){return this._path},_reset:function(){this._project(),this._update()},_clickTolerance:function(){return(this.options.stroke?this.options.weight/2:0)+(this._renderer.options.tolerance||0)}}),fi=mi.extend({options:{fill:!0,radius:10},initialize:function(t,e){c(this,e),this._latlng=w(t),this._radius=this.options.radius},setLatLng:function(t){var e=this._latlng;return this._latlng=w(t),this.redraw(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},getLatLng:function(){return this._latlng},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius},setStyle:function(t){var e=t&&t.radius||this._radius;return mi.prototype.setStyle.call(this,t),this.setRadius(e),this},_project:function(){this._point=this._map.latLngToLayerPoint(this._latlng),this._updateBounds()},_updateBounds:function(){var t=this._radius,e=this._radiusY||t,i=this._clickTolerance(),t=[t+i,e+i];this._pxBounds=new f(this._point.subtract(t),this._point.add(t))},_update:function(){this._map&&this._updatePath()},_updatePath:function(){this._renderer._updateCircle(this)},_empty:function(){return this._radius&&!this._renderer._bounds.intersects(this._pxBounds)},_containsPoint:function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()}});var gi=fi.extend({initialize:function(t,e,i){if(c(this,e="number"==typeof e?l({},i,{radius:e}):e),this._latlng=w(t),isNaN(this.options.radius))throw new Error("Circle radius cannot be NaN");this._mRadius=this.options.radius},setRadius:function(t){return this._mRadius=t,this.redraw()},getRadius:function(){return this._mRadius},getBounds:function(){var t=[this._radius,this._radiusY||this._radius];return new s(this._map.layerPointToLatLng(this._point.subtract(t)),this._map.layerPointToLatLng(this._point.add(t)))},setStyle:mi.prototype.setStyle,_project:function(){var t,e,i,n,o,s=this._latlng.lng,r=this._latlng.lat,a=this._map,h=a.options.crs;h.distance===st.distance?(n=Math.PI/180,o=this._mRadius/st.R/n,t=a.project([r+o,s]),e=a.project([r-o,s]),e=t.add(e).divideBy(2),i=a.unproject(e).lat,n=Math.acos((Math.cos(o*n)-Math.sin(r*n)*Math.sin(i*n))/(Math.cos(r*n)*Math.cos(i*n)))/n,!isNaN(n)&&0!==n||(n=o/Math.cos(Math.PI/180*r)),this._point=e.subtract(a.getPixelOrigin()),this._radius=isNaN(n)?0:e.x-a.project([i,s-n]).x,this._radiusY=e.y-t.y):(o=h.unproject(h.project(this._latlng).subtract([this._mRadius,0])),this._point=a.latLngToLayerPoint(this._latlng),this._radius=this._point.x-a.latLngToLayerPoint(o).x),this._updateBounds()}});var vi=mi.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,e){c(this,e),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var e=1/0,i=null,n=ni,o=0,s=this._parts.length;o<s;o++)for(var r=this._parts[o],a=1,h=r.length;a<h;a++){var l,u,c=n(t,l=r[a-1],u=r[a],!0);c<e&&(e=c,i=n(t,l,u))}return i&&(i.distance=Math.sqrt(e)),i},getCenter:function(){if(this._map)return si(this._defaultShape(),this._map.options.crs);throw new Error("Must add layer to map before using getCenter()")},getBounds:function(){return this._bounds},addLatLng:function(t,e){return e=e||this._defaultShape(),t=w(t),e.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new s,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return I(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var e=[],i=I(t),n=0,o=t.length;n<o;n++)i?(e[n]=w(t[n]),this._bounds.extend(e[n])):e[n]=this._convertLatLngs(t[n]);return e},_project:function(){var t=new f;this._rings=[],this._projectLatlngs(this._latlngs,this._rings,t),this._bounds.isValid()&&t.isValid()&&(this._rawPxBounds=t,this._updateBounds())},_updateBounds:function(){var t=this._clickTolerance(),t=new p(t,t);this._rawPxBounds&&(this._pxBounds=new f([this._rawPxBounds.min.subtract(t),this._rawPxBounds.max.add(t)]))},_projectLatlngs:function(t,e,i){var n,o,s=t[0]instanceof v,r=t.length;if(s){for(o=[],n=0;n<r;n++)o[n]=this._map.latLngToLayerPoint(t[n]),i.extend(o[n]);e.push(o)}else for(n=0;n<r;n++)this._projectLatlngs(t[n],e,i)},_clipPoints:function(){var t=this._renderer._bounds;if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else for(var e,i,n,o,s=this._parts,r=0,a=0,h=this._rings.length;r<h;r++)for(e=0,i=(o=this._rings[r]).length;e<i-1;e++)(n=ti(o[e],o[e+1],t,e,!0))&&(s[a]=s[a]||[],s[a].push(n[0]),n[1]===o[e+1]&&e!==i-2||(s[a].push(n[1]),a++))},_simplifyPoints:function(){for(var t=this._parts,e=this.options.smoothFactor,i=0,n=t.length;i<n;i++)t[i]=$e(t[i],e)},_update:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),this._updatePath())},_updatePath:function(){this._renderer._updatePoly(this)},_containsPoint:function(t,e){var i,n,o,s,r,a,h=this._clickTolerance();if(this._pxBounds&&this._pxBounds.contains(t))for(i=0,s=this._parts.length;i<s;i++)for(n=0,o=(r=(a=this._parts[i]).length)-1;n<r;o=n++)if((e||0!==n)&&Qe(t,a[o],a[n])<=h)return!0;return!1}});vi._flat=oi;var yi=vi.extend({options:{fill:!0},isEmpty:function(){return!this._latlngs.length||!this._latlngs[0].length},getCenter:function(){if(this._map)return ai(this._defaultShape(),this._map.options.crs);throw new Error("Must add layer to map before using getCenter()")},_convertLatLngs:function(t){var t=vi.prototype._convertLatLngs.call(this,t),e=t.length;return 2<=e&&t[0]instanceof v&&t[0].equals(t[e-1])&&t.pop(),t},_setLatLngs:function(t){vi.prototype._setLatLngs.call(this,t),I(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return(I(this._latlngs[0])?this._latlngs:this._latlngs[0])[0]},_clipPoints:function(){var t=this._renderer._bounds,e=this.options.weight,e=new p(e,e),t=new f(t.min.subtract(e),t.max.add(e));if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else for(var i,n=0,o=this._rings.length;n<o;n++)(i=ri(this._rings[n],t,!0)).length&&this._parts.push(i)},_updatePath:function(){this._renderer._updatePoly(this,!0)},_containsPoint:function(t){var e,i,n,o,s,r,a,h,l=!1;if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(o=0,a=this._parts.length;o<a;o++)for(s=0,r=(h=(e=this._parts[o]).length)-1;s<h;r=s++)i=e[s],n=e[r],i.y>t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||vi.prototype._containsPoint.call(this,t,!0)}});var xi=ui.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;e<i;e++)((n=o[e]).geometries||n.geometry||n.features||n.coordinates)&&this.addData(n);return this}var s,r=this.options;return(!r.filter||r.filter(t))&&(s=wi(t,r))?(s.feature=Ci(t),s.defaultOptions=s.options,this.resetStyle(s),r.onEachFeature&&r.onEachFeature(t,s),this.addLayer(s)):this},resetStyle:function(t){return void 0===t?this.eachLayer(this.resetStyle,this):(t.options=l({},t.defaultOptions),this._setLayerStyle(t,this.options.style),this)},setStyle:function(e){return this.eachLayer(function(t){this._setLayerStyle(t,e)},this)},_setLayerStyle:function(t,e){t.setStyle&&("function"==typeof e&&(e=e(t.feature)),t.setStyle(e))}});function wi(t,e){var i,n,o,s,r="Feature"===t.type?t.geometry:t,a=r?r.coordinates:null,h=[],l=e&&e.pointToLayer,u=e&&e.coordsToLatLng||Pi;if(!a&&!r)return null;switch(r.type){case"Point":return bi(l,t,i=u(a),e);case"MultiPoint":for(o=0,s=a.length;o<s;o++)i=u(a[o]),h.push(bi(l,t,i,e));return new ui(h);case"LineString":case"MultiLineString":return n=Li(a,"LineString"===r.type?0:1,u),new vi(n,e);case"Polygon":case"MultiPolygon":return n=Li(a,"Polygon"===r.type?1:2,u),new yi(n,e);case"GeometryCollection":for(o=0,s=r.geometries.length;o<s;o++){var c=wi({geometry:r.geometries[o],type:"Feature",properties:t.properties},e);c&&h.push(c)}return new ui(h);case"FeatureCollection":for(o=0,s=r.features.length;o<s;o++){var d=wi(r.features[o],e);d&&h.push(d)}return new ui(h);default:throw new Error("Invalid GeoJSON object.")}}function bi(t,e,i,n){return t?t(e,i):new pi(i,n&&n.markersInheritOptions&&n)}function Pi(t){return new v(t[1],t[0],t[2])}function Li(t,e,i){for(var n,o=[],s=0,r=t.length;s<r;s++)n=e?Li(t[s],e-1,i):(i||Pi)(t[s]),o.push(n);return o}function Ti(t,e){return void 0!==(t=w(t)).alt?[i(t.lng,e),i(t.lat,e),i(t.alt,e)]:[i(t.lng,e),i(t.lat,e)]}function Mi(t,e,i,n){for(var o=[],s=0,r=t.length;s<r;s++)o.push(e?Mi(t[s],I(t[s])?0:e-1,i,n):Ti(t[s],n));return!e&&i&&o.push(o[0].slice()),o}function zi(t,e){return t.feature?l({},t.feature,{geometry:e}):Ci(e)}function Ci(t){return"Feature"===t.type||"FeatureCollection"===t.type?t:{type:"Feature",properties:{},geometry:t}}Tt={toGeoJSON:function(t){return zi(this,{type:"Point",coordinates:Ti(this.getLatLng(),t)})}};function Zi(t,e){return new xi(t,e)}pi.include(Tt),gi.include(Tt),fi.include(Tt),vi.include({toGeoJSON:function(t){var e=!I(this._latlngs);return zi(this,{type:(e?"Multi":"")+"LineString",coordinates:Mi(this._latlngs,e?1:0,!1,t)})}}),yi.include({toGeoJSON:function(t){var e=!I(this._latlngs),i=e&&!I(this._latlngs[0]),t=Mi(this._latlngs,i?2:e?1:0,!0,t);return zi(this,{type:(i?"Multi":"")+"Polygon",coordinates:t=e?t:[t]})}}),li.include({toMultiPoint:function(e){var i=[];return this.eachLayer(function(t){i.push(t.toGeoJSON(e).geometry.coordinates)}),zi(this,{type:"MultiPoint",coordinates:i})},toGeoJSON:function(e){var i,n,t=this.feature&&this.feature.geometry&&this.feature.geometry.type;return"MultiPoint"===t?this.toMultiPoint(e):(i="GeometryCollection"===t,n=[],this.eachLayer(function(t){t.toGeoJSON&&(t=t.toGeoJSON(e),i?n.push(t.geometry):"FeatureCollection"===(t=Ci(t)).type?n.push.apply(n,t.features):n.push(t))}),i?zi(this,{geometries:n,type:"GeometryCollection"}):{type:"FeatureCollection",features:n})}});var Mt=Zi,Si=o.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1,errorOverlayUrl:"",zIndex:1,className:""},initialize:function(t,e,i){this._url=t,this._bounds=g(e),c(this,i)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(M(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){T(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&fe(this._image),this},bringToBack:function(){return this._map&&ge(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=g(t),this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t="IMG"===this._url.tagName,e=this._image=t?this._url:P("img");M(e,"leaflet-image-layer"),this._zoomAnimated&&M(e,"leaflet-zoom-animated"),this.options.className&&M(e,this.options.className),e.onselectstart=u,e.onmousemove=u,e.onload=a(this.fire,this,"load"),e.onerror=a(this._overlayOnError,this,"error"),!this.options.crossOrigin&&""!==this.options.crossOrigin||(e.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),this.options.zIndex&&this._updateZIndex(),t?this._url=e.src:(e.src=this._url,e.alt=this.options.alt)},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),t=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;be(this._image,t,e)},_reset:function(){var t=this._image,e=new f(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),i=e.getSize();Z(t,e.min),t.style.width=i.x+"px",t.style.height=i.y+"px"},_updateOpacity:function(){C(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire("error");var t=this.options.errorOverlayUrl;t&&this._url!==t&&(this._url=t,this._image.src=t)},getCenter:function(){return this._bounds.getCenter()}}),Ei=Si.extend({options:{autoplay:!0,loop:!0,keepAspectRatio:!0,muted:!1,playsInline:!0},_initImage:function(){var t="VIDEO"===this._url.tagName,e=this._image=t?this._url:P("video");if(M(e,"leaflet-image-layer"),this._zoomAnimated&&M(e,"leaflet-zoom-animated"),this.options.className&&M(e,this.options.className),e.onselectstart=u,e.onmousemove=u,e.onloadeddata=a(this.fire,this,"load"),t){for(var i=e.getElementsByTagName("source"),n=[],o=0;o<i.length;o++)n.push(i[o].src);this._url=0<i.length?n:[e.src]}else{d(this._url)||(this._url=[this._url]),!this.options.keepAspectRatio&&Object.prototype.hasOwnProperty.call(e.style,"objectFit")&&(e.style.objectFit="fill"),e.autoplay=!!this.options.autoplay,e.loop=!!this.options.loop,e.muted=!!this.options.muted,e.playsInline=!!this.options.playsInline;for(var s=0;s<this._url.length;s++){var r=P("source");r.src=this._url[s],e.appendChild(r)}}}});var ki=Si.extend({_initImage:function(){var t=this._image=this._url;M(t,"leaflet-image-layer"),this._zoomAnimated&&M(t,"leaflet-zoom-animated"),this.options.className&&M(t,this.options.className),t.onselectstart=u,t.onmousemove=u}});var Oi=o.extend({options:{interactive:!1,offset:[0,0],className:"",pane:void 0,content:""},initialize:function(t,e){t&&(t instanceof v||d(t))?(this._latlng=w(t),c(this,e)):(c(this,t),this._source=e),this.options.content&&(this._content=this.options.content)},openOn:function(t){return(t=arguments.length?t:this._source._map).hasLayer(this)||t.addLayer(this),this},close:function(){return this._map&&this._map.removeLayer(this),this},toggle:function(t){return this._map?this.close():(arguments.length?this._source=t:t=this._source,this._prepareOpen(),this.openOn(t._map)),this},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&C(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&C(this._container,1),this.bringToFront(),this.options.interactive&&(M(this._container,"leaflet-interactive"),this.addInteractiveTarget(this._container))},onRemove:function(t){t._fadeAnimated?(C(this._container,0),this._removeTimeout=setTimeout(a(T,void 0,this._container),200)):T(this._container),this.options.interactive&&(z(this._container,"leaflet-interactive"),this.removeInteractiveTarget(this._container))},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=w(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&fe(this._container),this},bringToBack:function(){return this._map&&ge(this._container),this},_prepareOpen:function(t){if(!(i=this._source)._map)return!1;if(i instanceof ui){var e,i=null,n=this._source._layers;for(e in n)if(n[e]._map){i=n[e];break}if(!i)return!1;this._source=i}if(!t)if(i.getCenter)t=i.getCenter();else if(i.getLatLng)t=i.getLatLng();else{if(!i.getBounds)throw new Error("Unable to get source layer LatLng.");t=i.getBounds().getCenter()}return this.setLatLng(t),this._map&&this.update(),!0},_updateContent:function(){if(this._content){var t=this._contentNode,e="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof e)t.innerHTML=e;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(e)}this.fire("contentupdate")}},_updatePosition:function(){var t,e,i;this._map&&(e=this._map.latLngToLayerPoint(this._latlng),t=m(this.options.offset),i=this._getAnchor(),this._zoomAnimated?Z(this._container,e.add(i)):t=t.add(e).add(i),e=this._containerBottom=-t.y,i=this._containerLeft=-Math.round(this._containerWidth/2)+t.x,this._container.style.bottom=e+"px",this._container.style.left=i+"px")},_getAnchor:function(){return[0,0]}}),Ai=(A.include({_initOverlay:function(t,e,i,n){var o=e;return o instanceof t||(o=new t(n).setContent(e)),i&&o.setLatLng(i),o}}),o.include({_initOverlay:function(t,e,i,n){var o=i;return o instanceof t?(c(o,n),o._source=this):(o=e&&!n?e:new t(n,this)).setContent(i),o}}),Oi.extend({options:{pane:"popupPane",offset:[0,7],maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,closeOnEscapeKey:!0,className:""},openOn:function(t){return!(t=arguments.length?t:this._source._map).hasLayer(this)&&t._popup&&t._popup.options.autoClose&&t.removeLayer(t._popup),t._popup=this,Oi.prototype.openOn.call(this,t)},onAdd:function(t){Oi.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof mi||this._source.on("preclick",Ae))},onRemove:function(t){Oi.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof mi||this._source.off("preclick",Ae))},getEvents:function(){var t=Oi.prototype.getEvents.call(this);return(void 0!==this.options.closeOnClick?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this.close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_initLayout:function(){var t="leaflet-popup",e=this._container=P("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated"),i=this._wrapper=P("div",t+"-content-wrapper",e);this._contentNode=P("div",t+"-content",i),Ie(e),Be(this._contentNode),S(e,"contextmenu",Ae),this._tipContainer=P("div",t+"-tip-container",e),this._tip=P("div",t+"-tip",this._tipContainer),this.options.closeButton&&((i=this._closeButton=P("a",t+"-close-button",e)).setAttribute("role","button"),i.setAttribute("aria-label","Close popup"),i.href="#close",i.innerHTML='<span aria-hidden="true">&#215;</span>',S(i,"click",function(t){O(t),this.close()},this))},_updateLayout:function(){var t=this._contentNode,e=t.style,i=(e.width="",e.whiteSpace="nowrap",t.offsetWidth),i=Math.min(i,this.options.maxWidth),i=(i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="",t.offsetHeight),n=this.options.maxHeight,o="leaflet-popup-scrolled";(n&&n<i?(e.height=n+"px",M):z)(t,o),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var t=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();Z(this._container,t.add(e))},_adjustPan:function(){var t,e,i,n,o,s,r,a;this.options.autoPan&&(this._map._panAnim&&this._map._panAnim.stop(),this._autopanning?this._autopanning=!1:(t=this._map,e=parseInt(pe(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+e,a=this._containerWidth,(i=new p(this._containerLeft,-e-this._containerBottom))._add(Pe(this._container)),i=t.layerPointToContainerPoint(i),o=m(this.options.autoPanPadding),n=m(this.options.autoPanPaddingTopLeft||o),o=m(this.options.autoPanPaddingBottomRight||o),s=t.getSize(),r=0,i.x+a+o.x>s.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Bi=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Ai,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Ai,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ui||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof mi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Oi.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Oi.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Oi.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Oi.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.x<o.x?(s="right",0):(s="left",r+2*(h.x+l.x)),a/2);t=t.subtract(m(e,i,!0)).add(h).add(l),z(n,"leaflet-tooltip-right"),z(n,"leaflet-tooltip-left"),z(n,"leaflet-tooltip-top"),z(n,"leaflet-tooltip-bottom"),M(n,"leaflet-tooltip-"+s),Z(n,t)},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},setOpacity:function(t){this.options.opacity=t,this._container&&C(this._container,t)},_animateZoom:function(t){t=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(t)},_getAnchor:function(){return m(this._source&&this._source._getTooltipAnchor&&!this.options.sticky?this._source._getTooltipAnchor():[0,0])}})),Ii=(A.include({openTooltip:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closeTooltip:function(t){return t.close(),this}}),o.include({bindTooltip:function(t,e){return this._tooltip&&this.isTooltipOpen()&&this.unbindTooltip(),this._tooltip=this._initOverlay(Bi,this._tooltip,t,e),this._initTooltipInteractions(),this._tooltip.options.permanent&&this._map&&this._map.hasLayer(this)&&this.openTooltip(),this},unbindTooltip:function(){return this._tooltip&&(this._initTooltipInteractions(!0),this.closeTooltip(),this._tooltip=null),this},_initTooltipInteractions:function(t){var e,i;!t&&this._tooltipHandlersAdded||(e=t?"off":"on",i={remove:this.closeTooltip,move:this._moveTooltip},this._tooltip.options.permanent?i.add=this._openTooltip:(i.mouseover=this._openTooltip,i.mouseout=this.closeTooltip,i.click=this._openTooltip,this._map?this._addFocusListeners():i.add=this._addFocusListeners),this._tooltip.options.sticky&&(i.mousemove=this._moveTooltip),this[e](i),this._tooltipHandlersAdded=!t)},openTooltip:function(t){return this._tooltip&&(this instanceof ui||(this._tooltip._source=this),this._tooltip._prepareOpen(t)&&(this._tooltip.openOn(this._map),this.getElement?this._setAriaDescribedByOnLayer(this):this.eachLayer&&this.eachLayer(this._setAriaDescribedByOnLayer,this))),this},closeTooltip:function(){if(this._tooltip)return this._tooltip.close()},toggleTooltip:function(){return this._tooltip&&this._tooltip.toggle(this),this},isTooltipOpen:function(){return this._tooltip.isOpen()},setTooltipContent:function(t){return this._tooltip&&this._tooltip.setContent(t),this},getTooltip:function(){return this._tooltip},_addFocusListeners:function(){this.getElement?this._addFocusListenersOnLayer(this):this.eachLayer&&this.eachLayer(this._addFocusListenersOnLayer,this)},_addFocusListenersOnLayer:function(t){var e=t.getElement();e&&(S(e,"focus",function(){this._tooltip._source=t,this.openTooltip()},this),S(e,"blur",this.closeTooltip,this))},_setAriaDescribedByOnLayer:function(t){t=t.getElement();t&&t.setAttribute("aria-describedby",this._tooltip._container.id)},_openTooltip:function(t){!this._tooltip||!this._map||this._map.dragging&&this._map.dragging.moving()||(this._tooltip._source=t.layer||t.target,this.openTooltip(this._tooltip.options.sticky?t.latlng:void 0))},_moveTooltip:function(t){var e=t.latlng;this._tooltip.options.sticky&&t.originalEvent&&(t=this._map.mouseEventToContainerPoint(t.originalEvent),t=this._map.containerPointToLayerPoint(t),e=this._map.layerPointToLatLng(t)),this._tooltip.setLatLng(e)}}),ci.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var t=t&&"DIV"===t.tagName?t:document.createElement("div"),e=this.options;return e.html instanceof Element?(me(t),t.appendChild(e.html)):t.innerHTML=!1!==e.html?e.html:"",e.bgPos&&(e=m(e.bgPos),t.style.backgroundPosition=-e.x+"px "+-e.y+"px"),this._setIconStyles(t,"icon"),t},createShadow:function(){return null}}));ci.Default=di;var Ri=o.extend({options:{tileSize:256,opacity:1,updateWhenIdle:b.mobile,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:void 0,maxNativeZoom:void 0,minNativeZoom:void 0,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){c(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),T(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=void 0},bringToFront:function(){return this._map&&(fe(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(ge(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){var t;return this._map&&(this._removeAllTiles(),(t=this._clampZoom(this._map.getZoom()))!==this._tileZoom&&(this._tileZoom=t,this._updateLevels()),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=j(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return document.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof p?t:new p(t,t)},_updateZIndex:function(){this._container&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var e,i=this.getPane().children,n=-t(-1/0,1/0),o=0,s=i.length;o<s;o++)e=i[o].style.zIndex,i[o]!==this._container&&e&&(n=t(n,+e));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex())},_updateOpacity:function(){if(this._map&&!b.ielt9){C(this._container,this.options.opacity);var t,e=+new Date,i=!1,n=!1;for(t in this._tiles){var o,s=this._tiles[t];s.current&&s.loaded&&(o=Math.min(1,(e-s.loaded)/200),C(s.el,o),o<1?i=!0:(s.active?n=!0:this._onOpaqueTile(s),s.active=!0))}n&&!this._noPrune&&this._pruneTiles(),i&&(r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this))}},_onOpaqueTile:u,_initContainer:function(){this._container||(this._container=P("div","leaflet-layer "+(this.options.className||"")),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container))},_updateLevels:function(){var t=this._tileZoom,e=this.options.maxZoom;if(void 0!==t){for(var i in this._levels)i=Number(i),this._levels[i].el.children.length||i===t?(this._levels[i].el.style.zIndex=e-Math.abs(t-i),this._onUpdateLevel(i)):(T(this._levels[i].el),this._removeTilesAtZoom(i),this._onRemoveLevel(i),delete this._levels[i]);var n=this._levels[t],o=this._map;return n||((n=this._levels[t]={}).el=P("div","leaflet-tile-container leaflet-zoom-animated",this._container),n.el.style.zIndex=e,n.origin=o.project(o.unproject(o.getPixelOrigin()),t).round(),n.zoom=t,this._setZoomTransform(n,o.getCenter(),o.getZoom()),u(n.el.offsetWidth),this._onCreateLevel(n)),this._level=n}},_onUpdateLevel:u,_onRemoveLevel:u,_onCreateLevel:u,_pruneTiles:function(){if(this._map){var t,e,i,n=this._map.getZoom();if(n>this.options.maxZoom||n<this.options.minZoom)this._removeAllTiles();else{for(t in this._tiles)(i=this._tiles[t]).retain=i.current;for(t in this._tiles)(i=this._tiles[t]).current&&!i.active&&(e=i.coords,this._retainParent(e.x,e.y,e.z,e.z-5)||this._retainChildren(e.x,e.y,e.z,e.z+2));for(t in this._tiles)this._tiles[t].retain||this._removeTile(t)}}},_removeTilesAtZoom:function(t){for(var e in this._tiles)this._tiles[e].coords.z===t&&this._removeTile(e)},_removeAllTiles:function(){for(var t in this._tiles)this._removeTile(t)},_invalidateAll:function(){for(var t in this._levels)T(this._levels[t].el),this._onRemoveLevel(Number(t)),delete this._levels[t];this._removeAllTiles(),this._tileZoom=void 0},_retainParent:function(t,e,i,n){var t=Math.floor(t/2),e=Math.floor(e/2),i=i-1,o=new p(+t,+e),o=(o.z=i,this._tileCoordsToKey(o)),o=this._tiles[o];return o&&o.active?o.retain=!0:(o&&o.loaded&&(o.retain=!0),n<i&&this._retainParent(t,e,i,n))},_retainChildren:function(t,e,i,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*e;s<2*e+2;s++){var r=new p(o,s),r=(r.z=i+1,this._tileCoordsToKey(r)),r=this._tiles[r];r&&r.active?r.retain=!0:(r&&r.loaded&&(r.retain=!0),i+1<n&&this._retainChildren(o,s,i+1,n))}},_resetView:function(t){t=t&&(t.pinch||t.flyTo);this._setView(this._map.getCenter(),this._map.getZoom(),t,t)},_animateZoom:function(t){this._setView(t.center,t.zoom,!0,t.noUpdate)},_clampZoom:function(t){var e=this.options;return void 0!==e.minNativeZoom&&t<e.minNativeZoom?e.minNativeZoom:void 0!==e.maxNativeZoom&&e.maxNativeZoom<t?e.maxNativeZoom:t},_setView:function(t,e,i,n){var o=Math.round(e),o=void 0!==this.options.maxZoom&&o>this.options.maxZoom||void 0!==this.options.minZoom&&o<this.options.minZoom?void 0:this._clampZoom(o),s=this.options.updateWhenZooming&&o!==this._tileZoom;n&&!s||(this._tileZoom=o,this._abortLoading&&this._abortLoading(),this._updateLevels(),this._resetGrid(),void 0!==o&&this._update(t),i||this._pruneTiles(),this._noPrune=!!i),this._setZoomTransforms(t,e)},_setZoomTransforms:function(t,e){for(var i in this._levels)this._setZoomTransform(this._levels[i],t,e)},_setZoomTransform:function(t,e,i){var n=this._map.getZoomScale(i,t.zoom),e=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(e,i)).round();b.any3d?be(t.el,e,n):Z(t.el,e)},_resetGrid:function(){var t=this._map,e=t.options.crs,i=this._tileSize=this.getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=e.wrapLng&&!this.options.noWrap&&[Math.floor(t.project([0,e.wrapLng[0]],n).x/i.x),Math.ceil(t.project([0,e.wrapLng[1]],n).x/i.y)],this._wrapY=e.wrapLat&&!this.options.noWrap&&[Math.floor(t.project([e.wrapLat[0],0],n).y/i.x),Math.ceil(t.project([e.wrapLat[1],0],n).y/i.y)]},_onMoveEnd:function(){this._map&&!this._map._animatingZoom&&this._update()},_getTiledPixelBounds:function(t){var e=this._map,i=e._animatingZoom?Math.max(e._animateToZoom,e.getZoom()):e.getZoom(),i=e.getZoomScale(i,this._tileZoom),t=e.project(t,this._tileZoom).floor(),e=e.getSize().divideBy(2*i);return new f(t.subtract(e),t.add(e))},_update:function(t){var e=this._map;if(e){var i=this._clampZoom(e.getZoom());if(void 0===t&&(t=e.getCenter()),void 0!==this._tileZoom){var n,e=this._getTiledPixelBounds(t),o=this._pxBoundsToTileRange(e),s=o.getCenter(),r=[],e=this.options.keepBuffer,a=new f(o.getBottomLeft().subtract([e,-e]),o.getTopRight().add([e,-e]));if(!(isFinite(o.min.x)&&isFinite(o.min.y)&&isFinite(o.max.x)&&isFinite(o.max.y)))throw new Error("Attempted to load an infinite number of tiles");for(n in this._tiles){var h=this._tiles[n].coords;h.z===this._tileZoom&&a.contains(new p(h.x,h.y))||(this._tiles[n].current=!1)}if(1<Math.abs(i-this._tileZoom))this._setView(t,i);else{for(var l=o.min.y;l<=o.max.y;l++)for(var u=o.min.x;u<=o.max.x;u++){var c,d=new p(u,l);d.z=this._tileZoom,this._isValidTile(d)&&((c=this._tiles[this._tileCoordsToKey(d)])?c.current=!0:r.push(d))}if(r.sort(function(t,e){return t.distanceTo(s)-e.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire("loading"));for(var _=document.createDocumentFragment(),u=0;u<r.length;u++)this._addTile(r[u],_);this._level.el.appendChild(_)}}}}},_isValidTile:function(t){var e=this._map.options.crs;if(!e.infinite){var i=this._globalTileRange;if(!e.wrapLng&&(t.x<i.min.x||t.x>i.max.x)||!e.wrapLat&&(t.y<i.min.y||t.y>i.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Ni=Ri.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0<e.maxZoom?(e.tileSize=Math.floor(e.tileSize/2),e.zoomReverse?(e.zoomOffset--,e.minZoom=Math.min(e.maxZoom,e.minZoom+1)):(e.zoomOffset++,e.maxZoom=Math.max(e.minZoom,e.maxZoom-1)),e.minZoom=Math.max(0,e.minZoom)):e.zoomReverse?e.minZoom=Math.min(e.maxZoom,e.minZoom):e.maxZoom=Math.max(e.minZoom,e.maxZoom),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),this.on("tileunload",this._onTileRemove)},setUrl:function(t,e){return this._url===t&&void 0===e&&(e=!0),this._url=t,e||this.redraw(),this},createTile:function(t,e){var i=document.createElement("img");return S(i,"load",a(this._tileOnLoad,this,e,i)),S(i,"error",a(this._tileOnError,this,e,i)),!this.options.crossOrigin&&""!==this.options.crossOrigin||(i.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),"string"==typeof this.options.referrerPolicy&&(i.referrerPolicy=this.options.referrerPolicy),i.alt="",i.src=this.getTileUrl(t),i},getTileUrl:function(t){var e={r:b.retina?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};return this._map&&!this._map.options.crs.infinite&&(t=this._globalTileRange.max.y-t.y,this.options.tms&&(e.y=t),e["-y"]=t),q(this._url,l(e,this.options))},_tileOnLoad:function(t,e){b.ielt9?setTimeout(a(t,this,null,e),0):t(null,e)},_tileOnError:function(t,e,i){var n=this.options.errorTileUrl;n&&e.getAttribute("src")!==n&&(e.src=n),t(i,e)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,e=this.options.maxZoom;return(t=this.options.zoomReverse?e-t:t)+this.options.zoomOffset},_getSubdomain:function(t){t=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[t]},_abortLoading:function(){var t,e,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&((i=this._tiles[t].el).onload=u,i.onerror=u,i.complete||(i.src=K,e=this._tiles[t].coords,T(i),delete this._tiles[t],this.fire("tileabort",{tile:i,coords:e})))},_removeTile:function(t){var e=this._tiles[t];if(e)return e.el.setAttribute("src",K),Ri.prototype._removeTile.call(this,t)},_tileReady:function(t,e,i){if(this._map&&(!i||i.getAttribute("src")!==K))return Ri.prototype._tileReady.call(this,t,e,i)}});function Di(t,e){return new Ni(t,e)}var ji=Ni.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var i,n=l({},this.defaultWmsParams);for(i in e)i in this.options||(n[i]=e[i]);var t=(e=c(this,e)).detectRetina&&b.retina?2:1,o=this.getTileSize();n.width=o.x*t,n.height=o.y*t,this.wmsParams=n},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=1.3<=this._wmsVersion?"crs":"srs";this.wmsParams[e]=this._crs.code,Ni.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._tileCoordsToNwSe(t),i=this._crs,i=_(i.project(e[0]),i.project(e[1])),e=i.min,i=i.max,e=(1.3<=this._wmsVersion&&this._crs===hi?[e.y,e.x,i.y,i.x]:[e.x,e.y,i.x,i.y]).join(","),i=Ni.prototype.getTileUrl.call(this,t);return i+U(this.wmsParams,i,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+e},setParams:function(t,e){return l(this.wmsParams,t),e||this.redraw(),this}});Ni.WMS=ji,Di.wms=function(t,e){return new ji(t,e)};var Hi=o.extend({options:{padding:.1},initialize:function(t){c(this,t),h(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&M(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){this.off("update",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,e){var i=this._map.getZoomScale(e,this._zoom),n=this._map.getSize().multiplyBy(.5+this.options.padding),o=this._map.project(this._center,e),n=n.multiplyBy(-i).add(o).subtract(this._map._getNewPixelOrigin(t,e));b.any3d?be(this._container,n,i):Z(this._container,n)},_reset:function(){for(var t in this._update(),this._updateTransform(this._center,this._zoom),this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,e=this._map.getSize(),i=this._map.containerPointToLayerPoint(e.multiplyBy(-t)).round();this._bounds=new f(i,i.add(e.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),Fi=Hi.extend({options:{tolerance:0},getEvents:function(){var t=Hi.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){Hi.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement("canvas");S(t,"mousemove",this._onMouseMove,this),S(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this),S(t,"mouseout",this._handleMouseOut,this),t._leaflet_disable_events=!0,this._ctx=t.getContext("2d")},_destroyContainer:function(){r(this._redrawRequest),delete this._ctx,T(this._container),k(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){for(var t in this._redrawBounds=null,this._layers)this._layers[t]._update();this._redraw()}},_update:function(){var t,e,i,n;this._map._animatingZoom&&this._bounds||(Hi.prototype._update.call(this),t=this._bounds,e=this._container,i=t.getSize(),n=b.retina?2:1,Z(e,t.min),e.width=n*i.x,e.height=n*i.y,e.style.width=i.x+"px",e.style.height=i.y+"px",b.retina&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update"))},_reset:function(){Hi.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t);t=(this._layers[h(t)]=t)._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=t),this._drawLast=t,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var e=t._order,i=e.next,e=e.prev;i?i.prev=e:this._drawLast=e,e?e.next=i:this._drawFirst=i,delete t._order,delete this._layers[h(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if("string"==typeof t.options.dashArray){for(var e,i=t.options.dashArray.split(/[, ]+/),n=[],o=0;o<i.length;o++){if(e=Number(i[o]),isNaN(e))return;n.push(e)}t.options._dashArray=n}else t.options._dashArray=t.options.dashArray},_requestRedraw:function(t){this._map&&(this._extendRedrawBounds(t),this._redrawRequest=this._redrawRequest||x(this._redraw,this))},_extendRedrawBounds:function(t){var e;t._pxBounds&&(e=(t.options.weight||0)+1,this._redrawBounds=this._redrawBounds||new f,this._redrawBounds.extend(t._pxBounds.min.subtract([e,e])),this._redrawBounds.extend(t._pxBounds.max.add([e,e])))},_redraw:function(){this._redrawRequest=null,this._redrawBounds&&(this._redrawBounds.min._floor(),this._redrawBounds.max._ceil()),this._clear(),this._draw(),this._redrawBounds=null},_clear:function(){var t,e=this._redrawBounds;e?(t=e.getSize(),this._ctx.clearRect(e.min.x,e.min.y,t.x,t.y)):(this._ctx.save(),this._ctx.setTransform(1,0,0,1,0,0),this._ctx.clearRect(0,0,this._container.width,this._container.height),this._ctx.restore())},_draw:function(){var t,e,i=this._redrawBounds;this._ctx.save(),i&&(e=i.getSize(),this._ctx.beginPath(),this._ctx.rect(i.min.x,i.min.y,e.x,e.y),this._ctx.clip()),this._drawing=!0;for(var n=this._drawFirst;n;n=n.next)t=n.layer,(!i||t._pxBounds&&t._pxBounds.intersects(i))&&t._updatePath();this._drawing=!1,this._ctx.restore()},_updatePoly:function(t,e){if(this._drawing){var i,n,o,s,r=t._parts,a=r.length,h=this._ctx;if(a){for(h.beginPath(),i=0;i<a;i++){for(n=0,o=r[i].length;n<o;n++)s=r[i][n],h[n?"lineTo":"moveTo"](s.x,s.y);e&&h.closePath()}this._fillStroke(h,t)}}},_updateCircle:function(t){var e,i,n,o;this._drawing&&!t._empty()&&(e=t._point,i=this._ctx,n=Math.max(Math.round(t._radius),1),1!=(o=(Math.max(Math.round(t._radiusY),1)||n)/n)&&(i.save(),i.scale(1,o)),i.beginPath(),i.arc(e.x,e.y/o,n,0,2*Math.PI,!1),1!=o&&i.restore(),this._fillStroke(i,t))},_fillStroke:function(t,e){var i=e.options;i.fill&&(t.globalAlpha=i.fillOpacity,t.fillStyle=i.fillColor||i.color,t.fill(i.fillRule||"evenodd")),i.stroke&&0!==i.weight&&(t.setLineDash&&t.setLineDash(e.options&&e.options._dashArray||[]),t.globalAlpha=i.opacity,t.lineWidth=i.weight,t.strokeStyle=i.color,t.lineCap=i.lineCap,t.lineJoin=i.lineJoin,t.stroke())},_onClick:function(t){for(var e,i,n=this._map.mouseEventToLayerPoint(t),o=this._drawFirst;o;o=o.next)(e=o.layer).options.interactive&&e._containsPoint(n)&&(("click"===t.type||"preclick"===t.type)&&this._map._draggableMoved(e)||(i=e));this._fireEvent(!!i&&[i],t)},_onMouseMove:function(t){var e;!this._map||this._map.dragging.moving()||this._map._animatingZoom||(e=this._map.mouseEventToLayerPoint(t),this._handleMouseHover(t,e))},_handleMouseOut:function(t){var e=this._hoveredLayer;e&&(z(this._container,"leaflet-interactive"),this._fireEvent([e],t,"mouseout"),this._hoveredLayer=null,this._mouseHoverThrottled=!1)},_handleMouseHover:function(t,e){if(!this._mouseHoverThrottled){for(var i,n,o=this._drawFirst;o;o=o.next)(i=o.layer).options.interactive&&i._containsPoint(e)&&(n=i);n!==this._hoveredLayer&&(this._handleMouseOut(t),n&&(M(this._container,"leaflet-interactive"),this._fireEvent([n],t,"mouseover"),this._hoveredLayer=n)),this._fireEvent(!!this._hoveredLayer&&[this._hoveredLayer],t),this._mouseHoverThrottled=!0,setTimeout(a(function(){this._mouseHoverThrottled=!1},this),32)}},_fireEvent:function(t,e,i){this._map._fireDOMEvent(e,i||e.type,t)},_bringToFront:function(t){var e,i,n=t._order;n&&(e=n.next,i=n.prev,e&&((e.prev=i)?i.next=e:e&&(this._drawFirst=e),n.prev=this._drawLast,(this._drawLast.next=n).next=null,this._drawLast=n,this._requestRedraw(t)))},_bringToBack:function(t){var e,i,n=t._order;n&&(e=n.next,(i=n.prev)&&((i.next=e)?e.prev=i:i&&(this._drawLast=i),n.prev=null,n.next=this._drawFirst,this._drawFirst.prev=n,this._drawFirst=n,this._requestRedraw(t)))}});function Wi(t){return b.canvas?new Fi(t):null}var Ui=function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return document.createElement("<lvml:"+t+' class="lvml">')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Hi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Ui("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Ui("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Ui("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Ui("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},Vi=b.vml?Ui:ct,qi=Hi.extend({_initContainer:function(){this._container=Vi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=Vi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Hi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=Vi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Gi(t){return b.svg||b.vml?new qi(t):null}b.vml&&qi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Wi(t)||Gi(t)}});var Ki=yi.extend({initialize:function(t,e){yi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});qi.create=Vi,qi.pointsToPath=dt,xi.geometryToLayer=wi,xi.coordsToLatLng=Pi,xi.coordsToLatLngs=Li,xi.latLngToCoords=Ti,xi.latLngsToCoords=Mi,xi.getFeature=zi,xi.asFeature=Ci,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Je(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1<this._positions.length&&50<t-this._times[0];)this._positions.shift(),this._times.shift()},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,e){return t-(t-e)*this._viscosity},_onPreDragLimit:function(){var t,e;this._viscosity&&this._offsetLimit&&(t=this._draggable._newPos.subtract(this._draggable._startPos),e=this._offsetLimit,t.x<e.min.x&&(t.x=this._viscousLimit(t.x,e.min.x)),t.y<e.min.y&&(t.y=this._viscousLimit(t.y,e.min.y)),t.x>e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)<Math.abs(n+i)?o:n;this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=t},_onDragEnd:function(t){var e,i,n,o,s=this._map,r=s.options,a=!r.inertia||t.noInertia||this._times.length<2;s.fire("dragend",t),!a&&(this._prunePositions(+new Date),t=this._lastPos.subtract(this._positions[0]),a=(this._lastTime-this._times[0])/1e3,e=r.easeLinearity,a=(t=t.multiplyBy(e/a)).distanceTo([0,0]),i=Math.min(r.inertiaMaxSpeed,a),t=t.multiplyBy(i/a),n=i/(r.inertiaDeceleration*e),(o=t.multiplyBy(-n/2).round()).x||o.y)?(o=s._limitOffset(o,s.options.maxBounds),x(function(){s.panBy(o,{duration:n,easeLinearity:e,noMoveStart:!0,animate:!0})})):s.fire("moveend")}})),St=(A.addInitHook("addHandler","dragging",Zt),A.mergeOptions({keyboard:!0,keyboardPanDelta:80}),n.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),S(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),k(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){var t,e,i;this._focused||(i=document.body,t=document.documentElement,e=i.scrollTop||t.scrollTop,i=i.scrollLeft||t.scrollLeft,this._map._container.focus(),window.scrollTo(i,e))},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){for(var e=this._panKeys={},i=this.keyCodes,n=0,o=i.left.length;n<o;n++)e[i.left[n]]=[-1*t,0];for(n=0,o=i.right.length;n<o;n++)e[i.right[n]]=[t,0];for(n=0,o=i.down.length;n<o;n++)e[i.down[n]]=[0,t];for(n=0,o=i.up.length;n<o;n++)e[i.up[n]]=[0,-1*t]},_setZoomDelta:function(t){for(var e=this._zoomKeys={},i=this.keyCodes,n=0,o=i.zoomIn.length;n<o;n++)e[i.zoomIn[n]]=t;for(n=0,o=i.zoomOut.length;n<o;n++)e[i.zoomOut[n]]=-t},_addHooks:function(){S(document,"keydown",this._onKeyDown,this)},_removeHooks:function(){k(document,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){if(!(t.altKey||t.ctrlKey||t.metaKey)){var e,i,n=t.keyCode,o=this._map;if(n in this._panKeys)o._panAnim&&o._panAnim._inProgress||(i=this._panKeys[n],t.shiftKey&&(i=m(i).multiplyBy(3)),o.options.maxBounds&&(i=o._limitOffset(m(i),o.options.maxBounds)),o.options.worldCopyJump?(e=o.wrapLatLng(o.unproject(o.project(o.getCenter()).add(i))),o.panTo(e)):o.panBy(i));else if(n in this._zoomKeys)o.setZoom(o.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[n]);else{if(27!==n||!o._popup||!o._popup.options.closeOnEscapeKey)return;o.closePopup()}Re(t)}}})),Et=(A.addInitHook("addHandler","keyboard",St),A.mergeOptions({scrollWheelZoom:!0,wheelDebounceTime:40,wheelPxPerZoomLevel:60}),n.extend({addHooks:function(){S(this._map._container,"wheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){k(this._map._container,"wheel",this._onWheelScroll,this)},_onWheelScroll:function(t){var e=He(t),i=this._map.options.wheelDebounceTime,e=(this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date),Math.max(i-(+new Date-this._startTime),0));clearTimeout(this._timer),this._timer=setTimeout(a(this._performZoom,this),e),Re(t)},_performZoom:function(){var t=this._map,e=t.getZoom(),i=this._map.options.zoomSnap||0,n=(t._stop(),this._delta/(4*this._map.options.wheelPxPerZoomLevel)),n=4*Math.log(2/(1+Math.exp(-Math.abs(n))))/Math.LN2,i=i?Math.ceil(n/i)*i:n,n=t._limitZoom(e+(0<this._delta?i:-i))-e;this._delta=0,this._startTime=null,n&&("center"===t.options.scrollWheelZoom?t.setZoom(e+n):t.setZoomAround(this._lastMousePos,e+n))}})),kt=(A.addInitHook("addHandler","scrollWheelZoom",Et),A.mergeOptions({tapHold:b.touchNative&&b.safari&&b.mobile,tapTolerance:15}),n.extend({addHooks:function(){S(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){k(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){var e;clearTimeout(this._holdTimeout),1===t.touches.length&&(e=t.touches[0],this._startPos=this._newPos=new p(e.clientX,e.clientY),this._holdTimeout=setTimeout(a(function(){this._cancel(),this._isTapValid()&&(S(document,"touchend",O),S(document,"touchend touchcancel",this._cancelClickPrevent),this._simulateEvent("contextmenu",e))},this),600),S(document,"touchend touchcancel contextmenu",this._cancel,this),S(document,"touchmove",this._onMove,this))},_cancelClickPrevent:function t(){k(document,"touchend",O),k(document,"touchend touchcancel",t)},_cancel:function(){clearTimeout(this._holdTimeout),k(document,"touchend touchcancel contextmenu",this._cancel,this),k(document,"touchmove",this._onMove,this)},_onMove:function(t){t=t.touches[0];this._newPos=new p(t.clientX,t.clientY)},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_simulateEvent:function(t,e){t=new MouseEvent(t,{bubbles:!0,cancelable:!0,view:window,screenX:e.screenX,screenY:e.screenY,clientX:e.clientX,clientY:e.clientY});t._simulated=!0,e.target.dispatchEvent(t)}})),Ot=(A.addInitHook("addHandler","tapHold",kt),A.mergeOptions({touchZoom:b.touch,bounceAtZoomLimits:!0}),n.extend({addHooks:function(){M(this._map._container,"leaflet-touch-zoom"),S(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){z(this._map._container,"leaflet-touch-zoom"),k(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var e,i,n=this._map;!t.touches||2!==t.touches.length||n._animatingZoom||this._zooming||(e=n.mouseEventToContainerPoint(t.touches[0]),i=n.mouseEventToContainerPoint(t.touches[1]),this._centerPoint=n.getSize()._divideBy(2),this._startLatLng=n.containerPointToLatLng(this._centerPoint),"center"!==n.options.touchZoom&&(this._pinchStartLatLng=n.containerPointToLatLng(e.add(i)._divideBy(2))),this._startDist=e.distanceTo(i),this._startZoom=n.getZoom(),this._moved=!1,this._zooming=!0,n._stop(),S(document,"touchmove",this._onTouchMove,this),S(document,"touchend touchcancel",this._onTouchEnd,this),O(t))},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),o=i.distanceTo(n)/this._startDist;if(this._zoom=e.getScaleZoom(o,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoom<e.getMinZoom()&&o<1||this._zoom>e.getMaxZoom()&&1<o)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1==o)return}else{i=i._add(n)._divideBy(2)._subtract(this._centerPoint);if(1==o&&0===i.x&&0===i.y)return;this._center=e.unproject(e.project(this._pinchStartLatLng,this._zoom).subtract(i),this._zoom)}this._moved||(e._moveStart(!0,!1),this._moved=!0),r(this._animRequest);n=a(e._move,e,this._center,this._zoom,{pinch:!0,round:!1},void 0);this._animRequest=x(n,this,!0),O(t)}},_onTouchEnd:function(){this._moved&&this._zooming?(this._zooming=!1,r(this._animRequest),k(document,"touchmove",this._onTouchMove,this),k(document,"touchend touchcancel",this._onTouchEnd,this),this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom))):this._zooming=!1}})),Yi=(A.addInitHook("addHandler","touchZoom",Ot),A.BoxZoom=_t,A.DoubleClickZoom=Ct,A.Drag=Zt,A.Keyboard=St,A.ScrollWheelZoom=Et,A.TapHold=kt,A.TouchZoom=Ot,t.Bounds=f,t.Browser=b,t.CRS=ot,t.Canvas=Fi,t.Circle=gi,t.CircleMarker=fi,t.Class=et,t.Control=B,t.DivIcon=Ii,t.DivOverlay=Oi,t.DomEvent=mt,t.DomUtil=pt,t.Draggable=Je,t.Evented=it,t.FeatureGroup=ui,t.GeoJSON=xi,t.GridLayer=Ri,t.Handler=n,t.Icon=ci,t.ImageOverlay=Si,t.LatLng=v,t.LatLngBounds=s,t.Layer=o,t.LayerGroup=li,t.LineUtil=gt,t.Map=A,t.Marker=pi,t.Mixin=ft,t.Path=mi,t.Point=p,t.PolyUtil=vt,t.Polygon=yi,t.Polyline=vi,t.Popup=Ai,t.PosAnimation=We,t.Projection=wt,t.Rectangle=Ki,t.Renderer=Hi,t.SVG=qi,t.SVGOverlay=ki,t.TileLayer=Ni,t.Tooltip=Bi,t.Transformation=at,t.Util=tt,t.VideoOverlay=Ei,t.bind=a,t.bounds=_,t.canvas=Wi,t.circle=function(t,e,i){return new gi(t,e,i)},t.circleMarker=function(t,e){return new fi(t,e)},t.control=Ue,t.divIcon=function(t){return new Ii(t)},t.extend=l,t.featureGroup=function(t,e){return new ui(t,e)},t.geoJSON=Zi,t.geoJson=Mt,t.gridLayer=function(t){return new Ri(t)},t.icon=function(t){return new ci(t)},t.imageOverlay=function(t,e,i){return new Si(t,e,i)},t.latLng=w,t.latLngBounds=g,t.layerGroup=function(t,e){return new li(t,e)},t.map=function(t,e){return new A(t,e)},t.marker=function(t,e){return new pi(t,e)},t.point=m,t.polygon=function(t,e){return new yi(t,e)},t.polyline=function(t,e){return new vi(t,e)},t.popup=function(t,e){return new Ai(t,e)},t.rectangle=function(t,e){return new Ki(t,e)},t.setOptions=c,t.stamp=h,t.svg=Gi,t.svgOverlay=function(t,e,i){return new ki(t,e,i)},t.tileLayer=Di,t.tooltip=function(t,e){return new Bi(t,e)},t.transformation=ht,t.version="1.9.3",t.videoOverlay=function(t,e,i){return new Ei(t,e,i)},window.L);t.noConflict=function(){return window.L=Yi,this},window.L=t}); //# sourceMappingURL=leaflet.js.map/** * @license Paged.js v0.4.1 | MIT | https://gitlab.pagedmedia.org/tools/pagedjs */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.PagedPolyfill = factory()); })(this, (function () { 'use strict'; var eventEmitter = {exports: {}}; var d$3 = {exports: {}}; var isImplemented$6 = function () { var assign = Object.assign, obj; if (typeof assign !== "function") return false; obj = { foo: "raz" }; assign(obj, { bar: "dwa" }, { trzy: "trzy" }); return (obj.foo + obj.bar + obj.trzy) === "razdwatrzy"; }; var isImplemented$5 = function () { try { Object.keys("primitive"); return true; } catch (e) { return false; } }; // eslint-disable-next-line no-empty-function var noop$4 = function () {}; var _undefined = noop$4(); // Support ES3 engines var isValue$5 = function (val) { return (val !== _undefined) && (val !== null); }; var isValue$4 = isValue$5; var keys$2 = Object.keys; var shim$5 = function (object) { return keys$2(isValue$4(object) ? Object(object) : object); }; var keys$1 = isImplemented$5() ? Object.keys : shim$5; var isValue$3 = isValue$5; var validValue$1 = function (value) { if (!isValue$3(value)) throw new TypeError("Cannot use null or undefined"); return value; }; var keys = keys$1 , value$3 = validValue$1 , max$1 = Math.max; var shim$4 = function (dest, src /*, …srcn*/) { var error, i, length = max$1(arguments.length, 2), assign; dest = Object(value$3(dest)); assign = function (key) { try { dest[key] = src[key]; } catch (e) { if (!error) error = e; } }; for (i = 1; i < length; ++i) { src = arguments[i]; keys(src).forEach(assign); } if (error !== undefined) throw error; return dest; }; var assign$2 = isImplemented$6() ? Object.assign : shim$4; var isValue$2 = isValue$5; var forEach$1 = Array.prototype.forEach, create$6 = Object.create; var process = function (src, obj) { var key; for (key in src) obj[key] = src[key]; }; // eslint-disable-next-line no-unused-vars var normalizeOptions = function (opts1 /*, …options*/) { var result = create$6(null); forEach$1.call(arguments, function (options) { if (!isValue$2(options)) return; process(Object(options), result); }); return result; }; var isCallable$1 = function (obj) { return typeof obj === "function"; }; var str = "razdwatrzy"; var isImplemented$4 = function () { if (typeof str.contains !== "function") return false; return (str.contains("dwa") === true) && (str.contains("foo") === false); }; var indexOf$3 = String.prototype.indexOf; var shim$3 = function (searchString/*, position*/) { return indexOf$3.call(this, searchString, arguments[1]) > -1; }; var contains$1 = isImplemented$4() ? String.prototype.contains : shim$3; var assign$1 = assign$2 , normalizeOpts = normalizeOptions , isCallable = isCallable$1 , contains = contains$1 , d$2; d$2 = d$3.exports = function (dscr, value/*, options*/) { var c, e, w, options, desc; if ((arguments.length < 2) || (typeof dscr !== 'string')) { options = value; value = dscr; dscr = null; } else { options = arguments[2]; } if (dscr == null) { c = w = true; e = false; } else { c = contains.call(dscr, 'c'); e = contains.call(dscr, 'e'); w = contains.call(dscr, 'w'); } desc = { value: value, configurable: c, enumerable: e, writable: w }; return !options ? desc : assign$1(normalizeOpts(options), desc); }; d$2.gs = function (dscr, get, set/*, options*/) { var c, e, options, desc; if (typeof dscr !== 'string') { options = set; set = get; get = dscr; dscr = null; } else { options = arguments[3]; } if (get == null) { get = undefined; } else if (!isCallable(get)) { options = get; get = set = undefined; } else if (set == null) { set = undefined; } else if (!isCallable(set)) { options = set; set = undefined; } if (dscr == null) { c = true; e = false; } else { c = contains.call(dscr, 'c'); e = contains.call(dscr, 'e'); } desc = { get: get, set: set, configurable: c, enumerable: e }; return !options ? desc : assign$1(normalizeOpts(options), desc); }; var validCallable = function (fn) { if (typeof fn !== "function") throw new TypeError(fn + " is not a function"); return fn; }; (function (module, exports) { var d = d$3.exports , callable = validCallable , apply = Function.prototype.apply, call = Function.prototype.call , create = Object.create, defineProperty = Object.defineProperty , defineProperties = Object.defineProperties , hasOwnProperty = Object.prototype.hasOwnProperty , descriptor = { configurable: true, enumerable: false, writable: true } , on, once, off, emit, methods, descriptors, base; on = function (type, listener) { var data; callable(listener); if (!hasOwnProperty.call(this, '__ee__')) { data = descriptor.value = create(null); defineProperty(this, '__ee__', descriptor); descriptor.value = null; } else { data = this.__ee__; } if (!data[type]) data[type] = listener; else if (typeof data[type] === 'object') data[type].push(listener); else data[type] = [data[type], listener]; return this; }; once = function (type, listener) { var once, self; callable(listener); self = this; on.call(this, type, once = function () { off.call(self, type, once); apply.call(listener, this, arguments); }); once.__eeOnceListener__ = listener; return this; }; off = function (type, listener) { var data, listeners, candidate, i; callable(listener); if (!hasOwnProperty.call(this, '__ee__')) return this; data = this.__ee__; if (!data[type]) return this; listeners = data[type]; if (typeof listeners === 'object') { for (i = 0; (candidate = listeners[i]); ++i) { if ((candidate === listener) || (candidate.__eeOnceListener__ === listener)) { if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; else listeners.splice(i, 1); } } } else { if ((listeners === listener) || (listeners.__eeOnceListener__ === listener)) { delete data[type]; } } return this; }; emit = function (type) { var i, l, listener, listeners, args; if (!hasOwnProperty.call(this, '__ee__')) return; listeners = this.__ee__[type]; if (!listeners) return; if (typeof listeners === 'object') { l = arguments.length; args = new Array(l - 1); for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; listeners = listeners.slice(); for (i = 0; (listener = listeners[i]); ++i) { apply.call(listener, this, args); } } else { switch (arguments.length) { case 1: call.call(listeners, this); break; case 2: call.call(listeners, this, arguments[1]); break; case 3: call.call(listeners, this, arguments[1], arguments[2]); break; default: l = arguments.length; args = new Array(l - 1); for (i = 1; i < l; ++i) { args[i - 1] = arguments[i]; } apply.call(listeners, this, args); } } }; methods = { on: on, once: once, off: off, emit: emit }; descriptors = { on: d(on), once: d(once), off: d(off), emit: d(emit) }; base = defineProperties({}, descriptors); module.exports = exports = function (o) { return (o == null) ? create(base) : defineProperties(Object(o), descriptors); }; exports.methods = methods; }(eventEmitter, eventEmitter.exports)); var EventEmitter = eventEmitter.exports; /** * Hooks allow for injecting functions that must all complete in order before finishing * They will execute in parallel but all must finish before continuing * Functions may return a promise if they are asycn. * From epubjs/src/utils/hooks * @param {any} context scope of this * @example this.content = new Hook(this); */ class Hook { constructor(context){ this.context = context || this; this.hooks = []; } /** * Adds a function to be run before a hook completes * @example this.content.register(function(){...}); * @return {undefined} void */ register(){ for(var i = 0; i < arguments.length; ++i) { if (typeof arguments[i] === "function") { this.hooks.push(arguments[i]); } else { // unpack array for(var j = 0; j < arguments[i].length; ++j) { this.hooks.push(arguments[i][j]); } } } } /** * Triggers a hook to run all functions * @example this.content.trigger(args).then(function(){...}); * @return {Promise} results */ trigger(){ var args = arguments; var context = this.context; var promises = []; this.hooks.forEach(function(task) { var executing = task.apply(context, args); if(executing && typeof executing["then"] === "function") { // Task is a function that returns a promise promises.push(executing); } else { // Otherwise Task resolves immediately, add resolved promise with result promises.push(new Promise((resolve, reject) => { resolve(executing); })); } }); return Promise.all(promises); } /** * Triggers a hook to run all functions synchronously * @example this.content.trigger(args).then(function(){...}); * @return {Array} results */ triggerSync(){ var args = arguments; var context = this.context; var results = []; this.hooks.forEach(function(task) { var executing = task.apply(context, args); results.push(executing); }); return results; } // Adds a function to be run before a hook completes list(){ return this.hooks; } clear(){ return this.hooks = []; } } function getBoundingClientRect(element) { if (!element) { return; } let rect; if (typeof element.getBoundingClientRect !== "undefined") { rect = element.getBoundingClientRect(); } else { let range = document.createRange(); range.selectNode(element); rect = range.getBoundingClientRect(); } return rect; } function getClientRects(element) { if (!element) { return; } let rect; if (typeof element.getClientRects !== "undefined") { rect = element.getClientRects(); } else { let range = document.createRange(); range.selectNode(element); rect = range.getClientRects(); } return rect; } /** * Generates a UUID * based on: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript * @returns {string} uuid */ function UUID() { var d = new Date().getTime(); if (typeof performance !== "undefined" && typeof performance.now === "function") { d += performance.now(); //use high-precision timer if available } return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); }); } function attr(element, attributes) { for (var i = 0; i < attributes.length; i++) { if (element.hasAttribute(attributes[i])) { return element.getAttribute(attributes[i]); } } } /* Based on by https://mths.be/cssescape v1.5.1 by @mathias | MIT license * Allows # and . */ function querySelectorEscape(value) { if (arguments.length == 0) { throw new TypeError("`CSS.escape` requires an argument."); } var string = String(value); var length = string.length; var index = -1; var codeUnit; var result = ""; var firstCodeUnit = string.charCodeAt(0); while (++index < length) { codeUnit = string.charCodeAt(index); // Note: there’s no need to special-case astral symbols, surrogate // pairs, or lone surrogates. // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER // (U+FFFD). if (codeUnit == 0x0000) { result += "\uFFFD"; continue; } if ( // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is // U+007F, […] (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || // If the character is the first character and is in the range [0-9] // (U+0030 to U+0039), […] (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || // If the character is the second character and is in the range [0-9] // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] ( index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002D ) ) { // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point result += "\\" + codeUnit.toString(16) + " "; continue; } if ( // If the character is the first character and is a `-` (U+002D), and // there is no second character, […] index == 0 && length == 1 && codeUnit == 0x002D ) { result += "\\" + string.charAt(index); continue; } // support for period character in id if (codeUnit == 0x002E) { if (string.charAt(0) == "#") { result += "\\."; continue; } } // If the character is not handled by one of the above rules and is // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to // U+005A), or [a-z] (U+0061 to U+007A), […] if ( codeUnit >= 0x0080 || codeUnit == 0x002D || codeUnit == 0x005F || codeUnit == 35 || // Allow # codeUnit == 46 || // Allow . codeUnit >= 0x0030 && codeUnit <= 0x0039 || codeUnit >= 0x0041 && codeUnit <= 0x005A || codeUnit >= 0x0061 && codeUnit <= 0x007A ) { // the character itself result += string.charAt(index); continue; } // Otherwise, the escaped character. // https://drafts.csswg.org/cssom/#escape-a-character result += "\\" + string.charAt(index); } return result; } /** * Creates a new pending promise and provides methods to resolve or reject it. * From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible * @returns {object} defered */ function defer() { this.resolve = null; this.reject = null; this.id = UUID(); this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); Object.freeze(this); } const requestIdleCallback = typeof window !== "undefined" && ("requestIdleCallback" in window ? window.requestIdleCallback : window.requestAnimationFrame); function CSSValueToString(obj) { return obj.value + (obj.unit || ""); } function isElement(node) { return node && node.nodeType === 1; } function isText(node) { return node && node.nodeType === 3; } function* walk$2(start, limiter) { let node = start; while (node) { yield node; if (node.childNodes.length) { node = node.firstChild; } else if (node.nextSibling) { if (limiter && node === limiter) { node = undefined; break; } node = node.nextSibling; } else { while (node) { node = node.parentNode; if (limiter && node === limiter) { node = undefined; break; } if (node && node.nextSibling) { node = node.nextSibling; break; } } } } } function nodeAfter(node, limiter) { if (limiter && node === limiter) { return; } let significantNode = nextSignificantNode(node); if (significantNode) { return significantNode; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } significantNode = nextSignificantNode(node); if (significantNode) { return significantNode; } } } } function nodeBefore(node, limiter) { if (limiter && node === limiter) { return; } let significantNode = previousSignificantNode(node); if (significantNode) { return significantNode; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } significantNode = previousSignificantNode(node); if (significantNode) { return significantNode; } } } } function elementAfter(node, limiter) { let after = nodeAfter(node, limiter); while (after && after.nodeType !== 1) { after = nodeAfter(after, limiter); } return after; } function elementBefore(node, limiter) { let before = nodeBefore(node, limiter); while (before && before.nodeType !== 1) { before = nodeBefore(before, limiter); } return before; } function displayedElementAfter(node, limiter) { let after = elementAfter(node, limiter); while (after && after.dataset.undisplayed) { after = elementAfter(after, limiter); } return after; } function displayedElementBefore(node, limiter) { let before = elementBefore(node, limiter); while (before && before.dataset.undisplayed) { before = elementBefore(before, limiter); } return before; } function rebuildAncestors(node) { let parent, ancestor; let ancestors = []; let added = []; let fragment = document.createDocumentFragment(); // Handle rowspan on table if (node.nodeName === "TR") { let previousRow = node.previousElementSibling; let previousRowDistance = 1; while (previousRow) { // previous row has more columns, might indicate a rowspan. if (previousRow.childElementCount > node.childElementCount) { const initialColumns = Array.from(node.children); while (node.firstChild) { node.firstChild.remove(); } let k = 0; for (let j = 0; j < previousRow.children.length; j++) { let column = previousRow.children[j]; if (column.rowSpan && column.rowSpan > previousRowDistance) { const duplicatedColumn = column.cloneNode(true); // Adjust rowspan value duplicatedColumn.rowSpan = column.rowSpan - previousRowDistance; // Add the column to the row node.appendChild(duplicatedColumn); } else { // Fill the gap with the initial columns (if exists) const initialColumn = initialColumns[k++]; // The initial column can be undefined if the newly created table has less columns than the original table if (initialColumn) { node.appendChild(initialColumn); } } } } previousRow = previousRow.previousElementSibling; previousRowDistance++; } } // Gather all ancestors let element = node; while(element.parentNode && element.parentNode.nodeType === 1) { ancestors.unshift(element.parentNode); element = element.parentNode; } for (var i = 0; i < ancestors.length; i++) { ancestor = ancestors[i]; parent = ancestor.cloneNode(false); parent.setAttribute("data-split-from", parent.getAttribute("data-ref")); // ancestor.setAttribute("data-split-to", parent.getAttribute("data-ref")); if (parent.hasAttribute("id")) { let dataID = parent.getAttribute("id"); parent.setAttribute("data-id", dataID); parent.removeAttribute("id"); } // This is handled by css :not, but also tidied up here if (parent.hasAttribute("data-break-before")) { parent.removeAttribute("data-break-before"); } if (parent.hasAttribute("data-previous-break-after")) { parent.removeAttribute("data-previous-break-after"); } if (added.length) { let container = added[added.length-1]; container.appendChild(parent); } else { fragment.appendChild(parent); } added.push(parent); // rebuild table rows if (parent.nodeName === "TD" && ancestor.parentElement.contains(ancestor)) { let td = ancestor; let prev = parent; while ((td = td.previousElementSibling)) { let sib = td.cloneNode(false); parent.parentElement.insertBefore(sib, prev); prev = sib; } } } added = undefined; return fragment; } /* export function split(bound, cutElement, breakAfter) { let needsRemoval = []; let index = indexOf(cutElement); if (!breakAfter && index === 0) { return; } if (breakAfter && index === (cutElement.parentNode.children.length - 1)) { return; } // Create a fragment with rebuilt ancestors let fragment = rebuildAncestors(cutElement); // Clone cut if (!breakAfter) { let clone = cutElement.cloneNode(true); let ref = cutElement.parentNode.getAttribute('data-ref'); let parent = fragment.querySelector("[data-ref='" + ref + "']"); parent.appendChild(clone); needsRemoval.push(cutElement); } // Remove all after cut let next = nodeAfter(cutElement, bound); while (next) { let clone = next.cloneNode(true); let ref = next.parentNode.getAttribute('data-ref'); let parent = fragment.querySelector("[data-ref='" + ref + "']"); parent.appendChild(clone); needsRemoval.push(next); next = nodeAfter(next, bound); } // Remove originals needsRemoval.forEach((node) => { if (node) { node.remove(); } }); // Insert after bounds bound.parentNode.insertBefore(fragment, bound.nextSibling); return [bound, bound.nextSibling]; } */ function needsBreakBefore(node) { if( typeof node !== "undefined" && typeof node.dataset !== "undefined" && typeof node.dataset.breakBefore !== "undefined" && (node.dataset.breakBefore === "always" || node.dataset.breakBefore === "page" || node.dataset.breakBefore === "left" || node.dataset.breakBefore === "right" || node.dataset.breakBefore === "recto" || node.dataset.breakBefore === "verso") ) { return true; } return false; } function needsPreviousBreakAfter(node) { if( typeof node !== "undefined" && typeof node.dataset !== "undefined" && typeof node.dataset.previousBreakAfter !== "undefined" && (node.dataset.previousBreakAfter === "always" || node.dataset.previousBreakAfter === "page" || node.dataset.previousBreakAfter === "left" || node.dataset.previousBreakAfter === "right" || node.dataset.previousBreakAfter === "recto" || node.dataset.previousBreakAfter === "verso") ) { return true; } return false; } function needsPageBreak(node, previousSignificantNode) { if (typeof node === "undefined" || !previousSignificantNode || isIgnorable(node)) { return false; } if (node.dataset && node.dataset.undisplayed) { return false; } let previousSignificantNodePage = previousSignificantNode.dataset ? previousSignificantNode.dataset.page : undefined; if (typeof previousSignificantNodePage === "undefined") { const nodeWithNamedPage = getNodeWithNamedPage(previousSignificantNode); if (nodeWithNamedPage) { previousSignificantNodePage = nodeWithNamedPage.dataset.page; } } let currentNodePage = node.dataset ? node.dataset.page : undefined; if (typeof currentNodePage === "undefined") { const nodeWithNamedPage = getNodeWithNamedPage(node, previousSignificantNode); if (nodeWithNamedPage) { currentNodePage = nodeWithNamedPage.dataset.page; } } return currentNodePage !== previousSignificantNodePage; } function *words(node) { let currentText = node.nodeValue; let max = currentText.length; let currentOffset = 0; let currentLetter; let range; const significantWhitespaces = node.parentElement && node.parentElement.nodeName === "PRE"; while (currentOffset < max) { currentLetter = currentText[currentOffset]; if (/^[\S\u202F\u00A0]$/.test(currentLetter) || significantWhitespaces) { if (!range) { range = document.createRange(); range.setStart(node, currentOffset); } } else { if (range) { range.setEnd(node, currentOffset); yield range; range = undefined; } } currentOffset += 1; } if (range) { range.setEnd(node, currentOffset); yield range; } } function *letters(wordRange) { let currentText = wordRange.startContainer; let max = currentText.length; let currentOffset = wordRange.startOffset; // let currentLetter; let range; while(currentOffset < max) { // currentLetter = currentText[currentOffset]; range = document.createRange(); range.setStart(currentText, currentOffset); range.setEnd(currentText, currentOffset+1); yield range; currentOffset += 1; } } function isContainer(node) { let container; if (typeof node.tagName === "undefined") { return true; } if (node.style && node.style.display === "none") { return false; } switch (node.tagName) { // Inline case "A": case "ABBR": case "ACRONYM": case "B": case "BDO": case "BIG": case "BR": case "BUTTON": case "CITE": case "CODE": case "DFN": case "EM": case "I": case "IMG": case "INPUT": case "KBD": case "LABEL": case "MAP": case "OBJECT": case "Q": case "SAMP": case "SCRIPT": case "SELECT": case "SMALL": case "SPAN": case "STRONG": case "SUB": case "SUP": case "TEXTAREA": case "TIME": case "TT": case "VAR": case "P": case "H1": case "H2": case "H3": case "H4": case "H5": case "H6": case "FIGCAPTION": case "BLOCKQUOTE": case "PRE": case "LI": case "TD": case "DT": case "DD": case "VIDEO": case "CANVAS": container = false; break; default: container = true; } return container; } function cloneNode(n, deep=false) { return n.cloneNode(deep); } function findElement(node, doc, forceQuery) { const ref = node.getAttribute("data-ref"); return findRef(ref, doc, forceQuery); } function findRef(ref, doc, forceQuery) { if (!forceQuery && doc.indexOfRefs && doc.indexOfRefs[ref]) { return doc.indexOfRefs[ref]; } else { return doc.querySelector(`[data-ref='${ref}']`); } } function validNode(node) { if (isText(node)) { return true; } if (isElement(node) && node.dataset.ref) { return true; } return false; } function prevValidNode(node) { while (!validNode(node)) { if (node.previousSibling) { node = node.previousSibling; } else { node = node.parentNode; } if (!node) { break; } } return node; } function indexOf$2(node) { let parent = node.parentNode; if (!parent) { return 0; } return Array.prototype.indexOf.call(parent.childNodes, node); } function child(node, index) { return node.childNodes[index]; } function hasContent(node) { if (isElement(node)) { return true; } else if (isText(node) && node.textContent.trim().length) { return true; } return false; } function indexOfTextNode(node, parent) { if (!isText(node)) { return -1; } let nodeTextContent = node.textContent; let child; let index = -1; for (var i = 0; i < parent.childNodes.length; i++) { child = parent.childNodes[i]; if (child.nodeType === 3) { let text = parent.childNodes[i].textContent; if (text.includes(nodeTextContent)) { index = i; break; } } } return index; } /** * Throughout, whitespace is defined as one of the characters * "\t" TAB \u0009 * "\n" LF \u000A * "\r" CR \u000D * " " SPC \u0020 * * This does not use Javascript's "\s" because that includes non-breaking * spaces (and also some other characters). */ /** * Determine if a node should be ignored by the iterator functions. * taken from https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace#Whitespace_helper_functions * * @param {Node} node An object implementing the DOM1 |Node| interface. * @return {boolean} true if the node is: * 1) A |Text| node that is all whitespace * 2) A |Comment| node * and otherwise false. */ function isIgnorable(node) { return (node.nodeType === 8) || // A comment node ((node.nodeType === 3) && isAllWhitespace(node)); // a text node, all whitespace } /** * Determine whether a node's text content is entirely whitespace. * * @param {Node} node A node implementing the |CharacterData| interface (i.e., a |Text|, |Comment|, or |CDATASection| node * @return {boolean} true if all of the text content of |nod| is whitespace, otherwise false. */ function isAllWhitespace(node) { return !(/[^\t\n\r ]/.test(node.textContent)); } /** * Version of |previousSibling| that skips nodes that are entirely * whitespace or comments. (Normally |previousSibling| is a property * of all DOM nodes that gives the sibling node, the node that is * a child of the same parent, that occurs immediately before the * reference node.) * * @param {ChildNode} sib The reference node. * @return {Node|null} Either: * 1) The closest previous sibling to |sib| that is not ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function previousSignificantNode(sib) { while ((sib = sib.previousSibling)) { if (!isIgnorable(sib)) return sib; } return null; } function getNodeWithNamedPage(node, limiter) { if (node && node.dataset && node.dataset.page) { return node; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } if (node.dataset && node.dataset.page) { return node; } } } return null; } function breakInsideAvoidParentNode(node) { while ((node = node.parentNode)) { if (node && node.dataset && node.dataset.breakInside === "avoid") { return node; } } return null; } /** * Find a parent with a given node name. * @param {Node} node - initial Node * @param {string} nodeName - node name (eg. "TD", "TABLE", "STRONG"...) * @param {Node} limiter - go up to the parent until there's no more parent or the current node is equals to the limiter * @returns {Node|undefined} - Either: * 1) The closest parent for a the given node name, or * 2) undefined if no such node exists. */ function parentOf(node, nodeName, limiter) { if (limiter && node === limiter) { return; } if (node.parentNode) { while ((node = node.parentNode)) { if (limiter && node === limiter) { return; } if (node.nodeName === nodeName) { return node; } } } } /** * Version of |nextSibling| that skips nodes that are entirely * whitespace or comments. * * @param {ChildNode} sib The reference node. * @return {Node|null} Either: * 1) The closest next sibling to |sib| that is not ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function nextSignificantNode(sib) { while ((sib = sib.nextSibling)) { if (!isIgnorable(sib)) return sib; } return null; } function filterTree(content, func, what) { const treeWalker = document.createTreeWalker( content || this.dom, what || NodeFilter.SHOW_ALL, func ? { acceptNode: func } : null, false ); let node; let current; node = treeWalker.nextNode(); while(node) { current = node; node = treeWalker.nextNode(); current.parentNode.removeChild(current); } } /** * BreakToken * @class */ class BreakToken { constructor(node, offset) { this.node = node; this.offset = offset; } equals(otherBreakToken) { if (!otherBreakToken) { return false; } if (this["node"] && otherBreakToken["node"] && this["node"] !== otherBreakToken["node"]) { return false; } if (this["offset"] && otherBreakToken["offset"] && this["offset"] !== otherBreakToken["offset"]) { return false; } return true; } toJSON(hash) { let node; let index = 0; if (!this.node) { return {}; } if (isElement(this.node) && this.node.dataset.ref) { node = this.node.dataset.ref; } else if (hash) { node = this.node.parentElement.dataset.ref; } if (this.node.parentElement) { const children = Array.from(this.node.parentElement.childNodes); index = children.indexOf(this.node); } return JSON.stringify({ "node": node, "index" : index, "offset": this.offset }); } } /** * Render result. * @class */ class RenderResult { constructor(breakToken, error) { this.breakToken = breakToken; this.error = error; } } class OverflowContentError extends Error { constructor(message, items) { super(message); this.items = items; } } const MAX_CHARS_PER_BREAK = 1500; /** * Layout * @class */ class Layout { constructor(element, hooks, options) { this.element = element; this.bounds = this.element.getBoundingClientRect(); this.parentBounds = this.element.offsetParent.getBoundingClientRect(); let gap = parseFloat(window.getComputedStyle(this.element).columnGap); if (gap) { let leftMargin = this.bounds.left - this.parentBounds.left; this.gap = gap - leftMargin; } else { this.gap = 0; } if (hooks) { this.hooks = hooks; } else { this.hooks = {}; this.hooks.layout = new Hook(); this.hooks.renderNode = new Hook(); this.hooks.layoutNode = new Hook(); this.hooks.beforeOverflow = new Hook(); this.hooks.onOverflow = new Hook(); this.hooks.afterOverflowRemoved = new Hook(); this.hooks.onBreakToken = new Hook(); } this.settings = options || {}; this.maxChars = this.settings.maxChars || MAX_CHARS_PER_BREAK; this.forceRenderBreak = false; } async renderTo(wrapper, source, breakToken, bounds = this.bounds) { let start = this.getStart(source, breakToken); let walker = walk$2(start, source); let node; let prevNode; let done; let next; let hasRenderedContent = false; let newBreakToken; let length = 0; let prevBreakToken = breakToken || new BreakToken(start); while (!done && !newBreakToken) { next = walker.next(); prevNode = node; node = next.value; done = next.done; if (!node) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", prevNode); return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [prevNode])); } this.rebuildTableFromBreakToken(newBreakToken, wrapper); return new RenderResult(newBreakToken); } this.hooks && this.hooks.layoutNode.trigger(node); // Check if the rendered element has a break set if (hasRenderedContent && this.shouldBreak(node, start)) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } else { this.rebuildTableFromBreakToken(newBreakToken, wrapper); } if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", node); let after = newBreakToken.node && nodeAfter(newBreakToken.node); if (after) { newBreakToken = new BreakToken(after); } else { return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [node])); } } length = 0; break; } if (node.dataset && node.dataset.page) { let named = node.dataset.page; let page = this.element.closest(".pagedjs_page"); page.classList.add("pagedjs_named_page"); page.classList.add("pagedjs_" + named + "_page"); if (!node.dataset.splitFrom) { page.classList.add("pagedjs_" + named + "_first_page"); } } // Should the Node be a shallow or deep clone let shallow = isContainer(node); let rendered = this.append(node, wrapper, breakToken, shallow); length += rendered.textContent.length; // Check if layout has content yet if (!hasRenderedContent) { hasRenderedContent = hasContent(node); } // Skip to the next node if a deep clone was rendered if (!shallow) { walker = walk$2(nodeAfter(node, source), source); } if (this.forceRenderBreak) { this.hooks && this.hooks.layout.trigger(wrapper, this); newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (!newBreakToken) { newBreakToken = this.breakAt(node); } else { this.rebuildTableFromBreakToken(newBreakToken, wrapper); } length = 0; this.forceRenderBreak = false; break; } // Only check x characters if (length >= this.maxChars) { this.hooks && this.hooks.layout.trigger(wrapper, this); let imgs = wrapper.querySelectorAll("img"); if (imgs.length) { await this.waitForImages(imgs); } newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken); if (newBreakToken) { length = 0; this.rebuildTableFromBreakToken(newBreakToken, wrapper); } if (newBreakToken && newBreakToken.equals(prevBreakToken)) { console.warn("Unable to layout item: ", node); let after = newBreakToken.node && nodeAfter(newBreakToken.node); if (after) { newBreakToken = new BreakToken(after); } else { return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [node])); } } } } return new RenderResult(newBreakToken); } breakAt(node, offset = 0) { let newBreakToken = new BreakToken( node, offset ); let breakHooks = this.hooks.onBreakToken.triggerSync(newBreakToken, undefined, node, this); breakHooks.forEach((newToken) => { if (typeof newToken != "undefined") { newBreakToken = newToken; } }); return newBreakToken; } shouldBreak(node, limiter) { let previousNode = nodeBefore(node, limiter); let parentNode = node.parentNode; let parentBreakBefore = needsBreakBefore(node) && parentNode && !previousNode && needsBreakBefore(parentNode); let doubleBreakBefore; if (parentBreakBefore) { doubleBreakBefore = node.dataset.breakBefore === parentNode.dataset.breakBefore; } return !doubleBreakBefore && needsBreakBefore(node) || needsPreviousBreakAfter(node) || needsPageBreak(node, previousNode); } forceBreak() { this.forceRenderBreak = true; } getStart(source, breakToken) { let start; let node = breakToken && breakToken.node; if (node) { start = node; } else { start = source.firstChild; } return start; } append(node, dest, breakToken, shallow = true, rebuild = true) { let clone = cloneNode(node, !shallow); if (node.parentNode && isElement(node.parentNode)) { let parent = findElement(node.parentNode, dest); // Rebuild chain if (parent) { parent.appendChild(clone); } else if (rebuild) { let fragment = rebuildAncestors(node); parent = findElement(node.parentNode, fragment); if (!parent) { dest.appendChild(clone); } else if (breakToken && isText(breakToken.node) && breakToken.offset > 0) { clone.textContent = clone.textContent.substring(breakToken.offset); parent.appendChild(clone); } else { parent.appendChild(clone); } dest.appendChild(fragment); } else { dest.appendChild(clone); } } else { dest.appendChild(clone); } if (clone.dataset && clone.dataset.ref) { if (!dest.indexOfRefs) { dest.indexOfRefs = {}; } dest.indexOfRefs[clone.dataset.ref] = clone; } let nodeHooks = this.hooks.renderNode.triggerSync(clone, node, this); nodeHooks.forEach((newNode) => { if (typeof newNode != "undefined") { clone = newNode; } }); return clone; } rebuildTableFromBreakToken(breakToken, dest) { if (!breakToken || !breakToken.node) { return; } let node = breakToken.node; let td = isElement(node) ? node.closest("td") : node.parentElement.closest("td"); if (td) { let rendered = findElement(td, dest, true); if (!rendered) { return; } while ((td = td.nextElementSibling)) { this.append(td, dest, null, true); } } } async waitForImages(imgs) { let results = Array.from(imgs).map(async (img) => { return this.awaitImageLoaded(img); }); await Promise.all(results); } async awaitImageLoaded(image) { return new Promise(resolve => { if (image.complete !== true) { image.onload = function () { let {width, height} = window.getComputedStyle(image); resolve(width, height); }; image.onerror = function (e) { let {width, height} = window.getComputedStyle(image); resolve(width, height, e); }; } else { let {width, height} = window.getComputedStyle(image); resolve(width, height); } }); } avoidBreakInside(node, limiter) { let breakNode; if (node === limiter) { return; } while (node.parentNode) { node = node.parentNode; if (node === limiter) { break; } if (window.getComputedStyle(node)["break-inside"] === "avoid") { breakNode = node; break; } } return breakNode; } createBreakToken(overflow, rendered, source) { let container = overflow.startContainer; let offset = overflow.startOffset; let node, renderedNode, parent, index, temp; if (isElement(container)) { temp = child(container, offset); if (isElement(temp)) { renderedNode = findElement(temp, rendered); if (!renderedNode) { // Find closest element with data-ref let prevNode = prevValidNode(temp); if (!isElement(prevNode)) { prevNode = prevNode.parentElement; } renderedNode = findElement(prevNode, rendered); // Check if temp is the last rendered node at its level. if (!temp.nextSibling) { // We need to ensure that the previous sibling of temp is fully rendered. const renderedNodeFromSource = findElement(renderedNode, source); const walker = document.createTreeWalker(renderedNodeFromSource, NodeFilter.SHOW_ELEMENT); const lastChildOfRenderedNodeFromSource = walker.lastChild(); const lastChildOfRenderedNodeMatchingFromRendered = findElement(lastChildOfRenderedNodeFromSource, rendered); // Check if we found that the last child in source if (!lastChildOfRenderedNodeMatchingFromRendered) { // Pending content to be rendered before virtual break token return; } // Otherwise we will return a break token as per below } // renderedNode is actually the last unbroken box that does not overflow. // Break Token is therefore the next sibling of renderedNode within source node. node = findElement(renderedNode, source).nextSibling; offset = 0; } else { node = findElement(renderedNode, source); offset = 0; } } else { renderedNode = findElement(container, rendered); if (!renderedNode) { renderedNode = findElement(prevValidNode(container), rendered); } parent = findElement(renderedNode, source); index = indexOfTextNode(temp, parent); // No seperatation for the first textNode of an element if(index === 0) { node = parent; offset = 0; } else { node = child(parent, index); offset = 0; } } } else { renderedNode = findElement(container.parentNode, rendered); if (!renderedNode) { renderedNode = findElement(prevValidNode(container.parentNode), rendered); } parent = findElement(renderedNode, source); index = indexOfTextNode(container, parent); if (index === -1) { return; } node = child(parent, index); offset += node.textContent.indexOf(container.textContent); } if (!node) { return; } return new BreakToken( node, offset ); } findBreakToken(rendered, source, bounds = this.bounds, prevBreakToken, extract = true) { let overflow = this.findOverflow(rendered, bounds); let breakToken, breakLetter; let overflowHooks = this.hooks.onOverflow.triggerSync(overflow, rendered, bounds, this); overflowHooks.forEach((newOverflow) => { if (typeof newOverflow != "undefined") { overflow = newOverflow; } }); if (overflow) { breakToken = this.createBreakToken(overflow, rendered, source); // breakToken is nullable let breakHooks = this.hooks.onBreakToken.triggerSync(breakToken, overflow, rendered, this); breakHooks.forEach((newToken) => { if (typeof newToken != "undefined") { breakToken = newToken; } }); // Stop removal if we are in a loop if (breakToken && breakToken.equals(prevBreakToken)) { return breakToken; } if (breakToken && breakToken["node"] && breakToken["offset"] && breakToken["node"].textContent) { breakLetter = breakToken["node"].textContent.charAt(breakToken["offset"]); } else { breakLetter = undefined; } if (breakToken && breakToken.node && extract) { let removed = this.removeOverflow(overflow, breakLetter); this.hooks && this.hooks.afterOverflowRemoved.trigger(removed, rendered, this); } } return breakToken; } hasOverflow(element, bounds = this.bounds) { let constrainingElement = element && element.parentNode; // this gets the element, instead of the wrapper for the width workaround let {width, height} = element.getBoundingClientRect(); let scrollWidth = constrainingElement ? constrainingElement.scrollWidth : 0; let scrollHeight = constrainingElement ? constrainingElement.scrollHeight : 0; return Math.max(Math.floor(width), scrollWidth) > Math.round(bounds.width) || Math.max(Math.floor(height), scrollHeight) > Math.round(bounds.height); } findOverflow(rendered, bounds = this.bounds, gap = this.gap) { if (!this.hasOverflow(rendered, bounds)) return; let start = Math.floor(bounds.left); let end = Math.round(bounds.right + gap); let vStart = Math.round(bounds.top); let vEnd = Math.round(bounds.bottom); let range; let walker = walk$2(rendered.firstChild, rendered); // Find Start let next, done, node, offset, skip, breakAvoid, prev, br; while (!done) { next = walker.next(); done = next.done; node = next.value; skip = false; breakAvoid = false; prev = undefined; br = undefined; if (node) { let pos = getBoundingClientRect(node); let left = Math.round(pos.left); let right = Math.floor(pos.right); let top = Math.round(pos.top); let bottom = Math.floor(pos.bottom); if (!range && (left >= end || top >= vEnd)) { // Check if it is a float let isFloat = false; // Check if the node is inside a break-inside: avoid table cell const insideTableCell = parentOf(node, "TD", rendered); if (insideTableCell && window.getComputedStyle(insideTableCell)["break-inside"] === "avoid") { // breaking inside a table cell produces unexpected result, as a workaround, we forcibly avoid break inside in a cell. // But we take the whole row, not just the cell that is causing the break. prev = insideTableCell.parentElement; } else if (isElement(node)) { let styles = window.getComputedStyle(node); isFloat = styles.getPropertyValue("float") !== "none"; skip = styles.getPropertyValue("break-inside") === "avoid"; breakAvoid = node.dataset.breakBefore === "avoid" || node.dataset.previousBreakAfter === "avoid"; prev = breakAvoid && nodeBefore(node, rendered); br = node.tagName === "BR" || node.tagName === "WBR"; } let tableRow; if (node.nodeName === "TR") { tableRow = node; } else { tableRow = parentOf(node, "TR", rendered); } if (tableRow) { // honor break-inside="avoid" in parent tbody/thead let container = tableRow.parentElement; if (["TBODY", "THEAD"].includes(container.nodeName)) { let styles = window.getComputedStyle(container); if (styles.getPropertyValue("break-inside") === "avoid") prev = container; } // Check if the node is inside a row with a rowspan const table = parentOf(tableRow, "TABLE", rendered); const rowspan = table.querySelector("[colspan]"); if (table && rowspan) { let columnCount = 0; for (const cell of Array.from(table.rows[0].cells)) { columnCount += parseInt(cell.getAttribute("colspan") || "1"); } if (tableRow.cells.length !== columnCount) { let previousRow = tableRow.previousElementSibling; let previousRowColumnCount; while (previousRow !== null) { previousRowColumnCount = 0; for (const cell of Array.from(previousRow.cells)) { previousRowColumnCount += parseInt(cell.getAttribute("colspan") || "1"); } if (previousRowColumnCount === columnCount) { break; } previousRow = previousRow.previousElementSibling; } if (previousRowColumnCount === columnCount) { prev = previousRow; } } } } if (prev) { range = document.createRange(); range.selectNode(prev); break; } if (!br && !isFloat && isElement(node)) { range = document.createRange(); range.selectNode(node); break; } if (isText(node) && node.textContent.trim().length) { range = document.createRange(); range.selectNode(node); break; } } if (!range && isText(node) && node.textContent.trim().length && !breakInsideAvoidParentNode(node.parentNode)) { let rects = getClientRects(node); let rect; left = 0; top = 0; for (var i = 0; i != rects.length; i++) { rect = rects[i]; if (rect.width > 0 && (!left || rect.left > left)) { left = rect.left; } if (rect.height > 0 && (!top || rect.top > top)) { top = rect.top; } } if (left >= end || top >= vEnd) { range = document.createRange(); offset = this.textBreak(node, start, end, vStart, vEnd); if (!offset) { range = undefined; } else { range.setStart(node, offset); } break; } } // Skip children if (skip || (right <= end && bottom <= vEnd)) { next = nodeAfter(node, rendered); if (next) { walker = walk$2(next, rendered); } } } } // Find End if (range) { range.setEndAfter(rendered.lastChild); return range; } } findEndToken(rendered, source) { if (rendered.childNodes.length === 0) { return; } let lastChild = rendered.lastChild; let lastNodeIndex; while (lastChild && lastChild.lastChild) { if (!validNode(lastChild)) { // Only get elements with refs lastChild = lastChild.previousSibling; } else if (!validNode(lastChild.lastChild)) { // Deal with invalid dom items lastChild = prevValidNode(lastChild.lastChild); break; } else { lastChild = lastChild.lastChild; } } if (isText(lastChild)) { if (lastChild.parentNode.dataset.ref) { lastNodeIndex = indexOf$2(lastChild); lastChild = lastChild.parentNode; } else { lastChild = lastChild.previousSibling; } } let original = findElement(lastChild, source); if (lastNodeIndex) { original = original.childNodes[lastNodeIndex]; } let after = nodeAfter(original); return this.breakAt(after); } textBreak(node, start, end, vStart, vEnd) { let wordwalker = words(node); let left = 0; let right = 0; let top = 0; let bottom = 0; let word, next, done, pos; let offset; while (!done) { next = wordwalker.next(); word = next.value; done = next.done; if (!word) { break; } pos = getBoundingClientRect(word); left = Math.floor(pos.left); right = Math.floor(pos.right); top = Math.floor(pos.top); bottom = Math.floor(pos.bottom); if (left >= end || top >= vEnd) { offset = word.startOffset; break; } if (right > end || bottom > vEnd) { let letterwalker = letters(word); let letter, nextLetter, doneLetter; while (!doneLetter) { nextLetter = letterwalker.next(); letter = nextLetter.value; doneLetter = nextLetter.done; if (!letter) { break; } pos = getBoundingClientRect(letter); left = Math.floor(pos.left); top = Math.floor(pos.top); if (left >= end || top >= vEnd) { offset = letter.startOffset; done = true; break; } } } } return offset; } removeOverflow(overflow, breakLetter) { let {startContainer} = overflow; let extracted = overflow.extractContents(); this.hyphenateAtBreak(startContainer, breakLetter); return extracted; } hyphenateAtBreak(startContainer, breakLetter) { if (isText(startContainer)) { let startText = startContainer.textContent; let prevLetter = startText[startText.length - 1]; // Add a hyphen if previous character is a letter or soft hyphen if ( (breakLetter && /^\w|\u00AD$/.test(prevLetter) && /^\w|\u00AD$/.test(breakLetter)) || (!breakLetter && /^\w|\u00AD$/.test(prevLetter)) ) { startContainer.parentNode.classList.add("pagedjs_hyphen"); startContainer.textContent += this.settings.hyphenGlyph || "\u2011"; } } } equalTokens(a, b) { if (!a || !b) { return false; } if (a["node"] && b["node"] && a["node"] !== b["node"]) { return false; } if (a["offset"] && b["offset"] && a["offset"] !== b["offset"]) { return false; } return true; } } EventEmitter(Layout.prototype); /** * Render a page * @class */ class Page { constructor(pagesArea, pageTemplate, blank, hooks, options) { this.pagesArea = pagesArea; this.pageTemplate = pageTemplate; this.blank = blank; this.width = undefined; this.height = undefined; this.hooks = hooks; this.settings = options || {}; // this.element = this.create(this.pageTemplate); } create(template, after) { //let documentFragment = document.createRange().createContextualFragment( TEMPLATE ); //let page = documentFragment.children[0]; let clone = document.importNode(this.pageTemplate.content, true); let page, index; if (after) { this.pagesArea.insertBefore(clone, after.nextElementSibling); index = Array.prototype.indexOf.call(this.pagesArea.children, after.nextElementSibling); page = this.pagesArea.children[index]; } else { this.pagesArea.appendChild(clone); page = this.pagesArea.lastChild; } let pagebox = page.querySelector(".pagedjs_pagebox"); let area = page.querySelector(".pagedjs_page_content"); let footnotesArea = page.querySelector(".pagedjs_footnote_area"); let size = area.getBoundingClientRect(); area.style.columnWidth = Math.round(size.width) + "px"; area.style.columnGap = "calc(var(--pagedjs-margin-right) + var(--pagedjs-margin-left) + var(--pagedjs-bleed-right) + var(--pagedjs-bleed-left) + var(--pagedjs-column-gap-offset))"; // area.style.overflow = "scroll"; this.width = Math.round(size.width); this.height = Math.round(size.height); this.element = page; this.pagebox = pagebox; this.area = area; this.footnotesArea = footnotesArea; return page; } createWrapper() { let wrapper = document.createElement("div"); this.area.appendChild(wrapper); this.wrapper = wrapper; return wrapper; } index(pgnum) { this.position = pgnum; let page = this.element; // let pagebox = this.pagebox; let index = pgnum + 1; let id = `page-${index}`; this.id = id; // page.dataset.pageNumber = index; page.dataset.pageNumber = index; page.setAttribute("id", id); if (this.name) { page.classList.add("pagedjs_" + this.name + "_page"); } if (this.blank) { page.classList.add("pagedjs_blank_page"); } if (pgnum === 0) { page.classList.add("pagedjs_first_page"); } if (pgnum % 2 !== 1) { page.classList.remove("pagedjs_left_page"); page.classList.add("pagedjs_right_page"); } else { page.classList.remove("pagedjs_right_page"); page.classList.add("pagedjs_left_page"); } } /* size(width, height) { if (width === this.width && height === this.height) { return; } this.width = width; this.height = height; this.element.style.width = Math.round(width) + "px"; this.element.style.height = Math.round(height) + "px"; this.element.style.columnWidth = Math.round(width) + "px"; } */ async layout(contents, breakToken, maxChars) { this.clear(); this.startToken = breakToken; let settings = this.settings; if (!settings.maxChars && maxChars) { settings.maxChars = maxChars; } this.layoutMethod = new Layout(this.area, this.hooks, settings); let renderResult = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken); let newBreakToken = renderResult.breakToken; this.addListeners(contents); this.endToken = newBreakToken; return newBreakToken; } async append(contents, breakToken) { if (!this.layoutMethod) { return this.layout(contents, breakToken); } let renderResult = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken); let newBreakToken = renderResult.breakToken; this.endToken = newBreakToken; return newBreakToken; } getByParent(ref, entries) { let e; for (var i = 0; i < entries.length; i++) { e = entries[i]; if (e.dataset.ref === ref) { return e; } } } onOverflow(func) { this._onOverflow = func; } onUnderflow(func) { this._onUnderflow = func; } clear() { this.removeListeners(); this.wrapper && this.wrapper.remove(); this.createWrapper(); } addListeners(contents) { if (typeof ResizeObserver !== "undefined") { this.addResizeObserver(contents); } else { this._checkOverflowAfterResize = this.checkOverflowAfterResize.bind(this, contents); this.element.addEventListener("overflow", this._checkOverflowAfterResize, false); this.element.addEventListener("underflow", this._checkOverflowAfterResize, false); } // TODO: fall back to mutation observer? this._onScroll = function () { if (this.listening) { this.element.scrollLeft = 0; } }.bind(this); // Keep scroll left from changing this.element.addEventListener("scroll", this._onScroll); this.listening = true; return true; } removeListeners() { this.listening = false; if (typeof ResizeObserver !== "undefined" && this.ro) { this.ro.disconnect(); } else if (this.element) { this.element.removeEventListener("overflow", this._checkOverflowAfterResize, false); this.element.removeEventListener("underflow", this._checkOverflowAfterResize, false); } this.element && this.element.removeEventListener("scroll", this._onScroll); } addResizeObserver(contents) { let wrapper = this.wrapper; let prevHeight = wrapper.getBoundingClientRect().height; this.ro = new ResizeObserver(entries => { if (!this.listening) { return; } requestAnimationFrame(() => { for (let entry of entries) { const cr = entry.contentRect; if (cr.height > prevHeight) { this.checkOverflowAfterResize(contents); prevHeight = wrapper.getBoundingClientRect().height; } else if (cr.height < prevHeight) { // TODO: calc line height && (prevHeight - cr.height) >= 22 this.checkUnderflowAfterResize(contents); prevHeight = cr.height; } } }); }); this.ro.observe(wrapper); } checkOverflowAfterResize(contents) { if (!this.listening || !this.layoutMethod) { return; } let newBreakToken = this.layoutMethod.findBreakToken(this.wrapper, contents, this.startToken); if (newBreakToken) { this.endToken = newBreakToken; this._onOverflow && this._onOverflow(newBreakToken); } } checkUnderflowAfterResize(contents) { if (!this.listening || !this.layoutMethod) { return; } let endToken = this.layoutMethod.findEndToken(this.wrapper, contents); if (endToken) { this._onUnderflow && this._onUnderflow(endToken); } } destroy() { this.removeListeners(); this.element.remove(); this.element = undefined; this.wrapper = undefined; } } EventEmitter(Page.prototype); /** * Render a flow of text offscreen * @class */ class ContentParser { constructor(content, cb) { if (content && content.nodeType) { // handle dom this.dom = this.add(content); } else if (typeof content === "string") { this.dom = this.parse(content); } return this.dom; } parse(markup, mime) { let range = document.createRange(); let fragment = range.createContextualFragment(markup); this.addRefs(fragment); return fragment; } add(contents) { // let fragment = document.createDocumentFragment(); // // let children = [...contents.childNodes]; // for (let child of children) { // let clone = child.cloneNode(true); // fragment.appendChild(clone); // } this.addRefs(contents); return contents; } addRefs(content) { var treeWalker = document.createTreeWalker( content, NodeFilter.SHOW_ELEMENT, null, false ); let node = treeWalker.nextNode(); while(node) { if (!node.hasAttribute("data-ref")) { let uuid = UUID(); node.setAttribute("data-ref", uuid); } if (node.id) { node.setAttribute("data-id", node.id); } // node.setAttribute("data-children", node.childNodes.length); // node.setAttribute("data-text", node.textContent.trim().length); node = treeWalker.nextNode(); } } find(ref) { return this.refs[ref]; } destroy() { this.refs = undefined; this.dom = undefined; } } /** * Queue for handling tasks one at a time * @class * @param {scope} context what this will resolve to in the tasks */ class Queue { constructor(context){ this._q = []; this.context = context; this.tick = requestAnimationFrame; this.running = false; this.paused = false; } /** * Add an item to the queue * @return {Promise} enqueued */ enqueue() { var deferred, promise; var queued; var task = [].shift.call(arguments); var args = arguments; // Handle single args without context // if(args && !Array.isArray(args)) { // args = [args]; // } if(!task) { throw new Error("No Task Provided"); } if(typeof task === "function"){ deferred = new defer(); promise = deferred.promise; queued = { "task" : task, "args" : args, //"context" : context, "deferred" : deferred, "promise" : promise }; } else { // Task is a promise queued = { "promise" : task }; } this._q.push(queued); // Wait to start queue flush if (this.paused == false && !this.running) { this.run(); } return queued.promise; } /** * Run one item * @return {Promise} dequeued */ dequeue(){ var inwait, task, result; if(this._q.length && !this.paused) { inwait = this._q.shift(); task = inwait.task; if(task){ // console.log(task) result = task.apply(this.context, inwait.args); if(result && typeof result["then"] === "function") { // Task is a function that returns a promise return result.then(function(){ inwait.deferred.resolve.apply(this.context, arguments); }.bind(this), function() { inwait.deferred.reject.apply(this.context, arguments); }.bind(this)); } else { // Task resolves immediately inwait.deferred.resolve.apply(this.context, result); return inwait.promise; } } else if(inwait.promise) { // Task is a promise return inwait.promise; } } else { inwait = new defer(); inwait.deferred.resolve(); return inwait.promise; } } // Run All Immediately dump(){ while(this._q.length) { this.dequeue(); } } /** * Run all tasks sequentially, at convince * @return {Promise} all run */ run(){ if(!this.running){ this.running = true; this.defered = new defer(); } this.tick.call(window, () => { if(this._q.length) { this.dequeue() .then(function(){ this.run(); }.bind(this)); } else { this.defered.resolve(); this.running = undefined; } }); // Unpause if(this.paused == true) { this.paused = false; } return this.defered.promise; } /** * Flush all, as quickly as possible * @return {Promise} ran */ flush(){ if(this.running){ return this.running; } if(this._q.length) { this.running = this.dequeue() .then(function(){ this.running = undefined; return this.flush(); }.bind(this)); return this.running; } } /** * Clear all items in wait * @return {void} */ clear(){ this._q = []; } /** * Get the number of tasks in the queue * @return {number} tasks */ length(){ return this._q.length; } /** * Pause a running queue * @return {void} */ pause(){ this.paused = true; } /** * End the queue * @return {void} */ stop(){ this._q = []; this.running = false; this.paused = true; } } const TEMPLATE = ` <div class="pagedjs_page"> <div class="pagedjs_sheet"> <div class="pagedjs_bleed pagedjs_bleed-top"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-bottom"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-left"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_bleed pagedjs_bleed-right"> <div class="pagedjs_marks-crop"></div> <div class="pagedjs_marks-middle"> <div class="pagedjs_marks-cross"></div> </div> <div class="pagedjs_marks-crop"></div> </div> <div class="pagedjs_pagebox"> <div class="pagedjs_margin-top-left-corner-holder"> <div class="pagedjs_margin pagedjs_margin-top-left-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-top"> <div class="pagedjs_margin pagedjs_margin-top-left"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-top-center"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-top-right"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-top-right-corner-holder"> <div class="pagedjs_margin pagedjs_margin-top-right-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-right"> <div class="pagedjs_margin pagedjs_margin-right-top"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-right-middle"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-right-bottom"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-left"> <div class="pagedjs_margin pagedjs_margin-left-top"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-left-middle"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-left-bottom"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom-left-corner-holder"> <div class="pagedjs_margin pagedjs_margin-bottom-left-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom"> <div class="pagedjs_margin pagedjs_margin-bottom-left"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-bottom-center"><div class="pagedjs_margin-content"></div></div> <div class="pagedjs_margin pagedjs_margin-bottom-right"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_margin-bottom-right-corner-holder"> <div class="pagedjs_margin pagedjs_margin-bottom-right-corner"><div class="pagedjs_margin-content"></div></div> </div> <div class="pagedjs_area"> <div class="pagedjs_page_content"></div> <div class="pagedjs_footnote_area"> <div class="pagedjs_footnote_content pagedjs_footnote_empty"> <div class="pagedjs_footnote_inner_content"></div> </div> </div> </div> </div> </div> </div>`; /** * Chop up text into flows * @class */ class Chunker { constructor(content, renderTo, options) { // this.preview = preview; this.settings = options || {}; this.hooks = {}; this.hooks.beforeParsed = new Hook(this); this.hooks.filter = new Hook(this); this.hooks.afterParsed = new Hook(this); this.hooks.beforePageLayout = new Hook(this); this.hooks.layout = new Hook(this); this.hooks.renderNode = new Hook(this); this.hooks.layoutNode = new Hook(this); this.hooks.onOverflow = new Hook(this); this.hooks.afterOverflowRemoved = new Hook(this); this.hooks.onBreakToken = new Hook(); this.hooks.afterPageLayout = new Hook(this); this.hooks.finalizePage = new Hook(this); this.hooks.afterRendered = new Hook(this); this.pages = []; this.total = 0; this.q = new Queue(this); this.stopped = false; this.rendered = false; this.content = content; this.charsPerBreak = []; this.maxChars; if (content) { this.flow(content, renderTo); } } setup(renderTo) { this.pagesArea = document.createElement("div"); this.pagesArea.classList.add("pagedjs_pages"); if (renderTo) { renderTo.appendChild(this.pagesArea); } else { document.querySelector("body").appendChild(this.pagesArea); } this.pageTemplate = document.createElement("template"); this.pageTemplate.innerHTML = TEMPLATE; } async flow(content, renderTo) { let parsed; await this.hooks.beforeParsed.trigger(content, this); parsed = new ContentParser(content); this.hooks.filter.triggerSync(parsed); this.source = parsed; this.breakToken = undefined; if (this.pagesArea && this.pageTemplate) { this.q.clear(); this.removePages(); } else { this.setup(renderTo); } this.emit("rendering", parsed); await this.hooks.afterParsed.trigger(parsed, this); await this.loadFonts(); let rendered = await this.render(parsed, this.breakToken); while (rendered.canceled) { this.start(); rendered = await this.render(parsed, this.breakToken); } this.rendered = true; this.pagesArea.style.setProperty("--pagedjs-page-count", this.total); await this.hooks.afterRendered.trigger(this.pages, this); this.emit("rendered", this.pages); return this; } // oversetPages() { // let overset = []; // for (let i = 0; i < this.pages.length; i++) { // let page = this.pages[i]; // if (page.overset) { // overset.push(page); // // page.overset = false; // } // } // return overset; // } // // async handleOverset(parsed) { // let overset = this.oversetPages(); // if (overset.length) { // console.log("overset", overset); // let index = this.pages.indexOf(overset[0]) + 1; // console.log("INDEX", index); // // // Remove pages // // this.removePages(index); // // // await this.render(parsed, overset[0].overset); // // // return this.handleOverset(parsed); // } // } async render(parsed, startAt) { let renderer = this.layout(parsed, startAt); let done = false; let result; while (!done) { result = await this.q.enqueue(() => { return this.renderAsync(renderer); }); done = result.done; } return result; } start() { this.rendered = false; this.stopped = false; } stop() { this.stopped = true; // this.q.clear(); } renderOnIdle(renderer) { return new Promise(resolve => { requestIdleCallback(async () => { if (this.stopped) { return resolve({ done: true, canceled: true }); } let result = await renderer.next(); if (this.stopped) { resolve({ done: true, canceled: true }); } else { resolve(result); } }); }); } async renderAsync(renderer) { if (this.stopped) { return { done: true, canceled: true }; } let result = await renderer.next(); if (this.stopped) { return { done: true, canceled: true }; } else { return result; } } async handleBreaks(node, force) { let currentPage = this.total + 1; let currentPosition = currentPage % 2 === 0 ? "left" : "right"; // TODO: Recto and Verso should reverse for rtl languages let currentSide = currentPage % 2 === 0 ? "verso" : "recto"; let previousBreakAfter; let breakBefore; let page; if (currentPage === 1) { return; } if (node && typeof node.dataset !== "undefined" && typeof node.dataset.previousBreakAfter !== "undefined") { previousBreakAfter = node.dataset.previousBreakAfter; } if (node && typeof node.dataset !== "undefined" && typeof node.dataset.breakBefore !== "undefined") { breakBefore = node.dataset.breakBefore; } if (force) { page = this.addPage(true); } else if( previousBreakAfter && (previousBreakAfter === "left" || previousBreakAfter === "right") && previousBreakAfter !== currentPosition) { page = this.addPage(true); } else if( previousBreakAfter && (previousBreakAfter === "verso" || previousBreakAfter === "recto") && previousBreakAfter !== currentSide) { page = this.addPage(true); } else if( breakBefore && (breakBefore === "left" || breakBefore === "right") && breakBefore !== currentPosition) { page = this.addPage(true); } else if( breakBefore && (breakBefore === "verso" || breakBefore === "recto") && breakBefore !== currentSide) { page = this.addPage(true); } if (page) { await this.hooks.beforePageLayout.trigger(page, undefined, undefined, this); this.emit("page", page); // await this.hooks.layout.trigger(page.element, page, undefined, this); await this.hooks.afterPageLayout.trigger(page.element, page, undefined, this); await this.hooks.finalizePage.trigger(page.element, page, undefined, this); this.emit("renderedPage", page); } } async *layout(content, startAt) { let breakToken = startAt || false; let tokens = []; while (breakToken !== undefined && (true)) { if (breakToken && breakToken.node) { await this.handleBreaks(breakToken.node); } else { await this.handleBreaks(content.firstChild); } let page = this.addPage(); await this.hooks.beforePageLayout.trigger(page, content, breakToken, this); this.emit("page", page); // Layout content in the page, starting from the breakToken breakToken = await page.layout(content, breakToken, this.maxChars); if (breakToken) { let newToken = breakToken.toJSON(true); if (tokens.lastIndexOf(newToken) > -1) { // loop let err = new OverflowContentError("Layout repeated", [breakToken.node]); console.error("Layout repeated at: ", breakToken.node); return err; } else { tokens.push(newToken); } } await this.hooks.afterPageLayout.trigger(page.element, page, breakToken, this); await this.hooks.finalizePage.trigger(page.element, page, undefined, this); this.emit("renderedPage", page); this.recoredCharLength(page.wrapper.textContent.length); yield breakToken; // Stop if we get undefined, showing we have reached the end of the content } } recoredCharLength(length) { if (length === 0) { return; } this.charsPerBreak.push(length); // Keep the length of the last few breaks if (this.charsPerBreak.length > 4) { this.charsPerBreak.shift(); } this.maxChars = this.charsPerBreak.reduce((a, b) => a + b, 0) / (this.charsPerBreak.length); } removePages(fromIndex=0) { if (fromIndex >= this.pages.length) { return; } // Remove pages for (let i = fromIndex; i < this.pages.length; i++) { this.pages[i].destroy(); } if (fromIndex > 0) { this.pages.splice(fromIndex); } else { this.pages = []; } this.total = this.pages.length; } addPage(blank) { let lastPage = this.pages[this.pages.length - 1]; // Create a new page from the template let page = new Page(this.pagesArea, this.pageTemplate, blank, this.hooks, this.settings); this.pages.push(page); // Create the pages page.create(undefined, lastPage && lastPage.element); page.index(this.total); if (!blank) { // Listen for page overflow page.onOverflow((overflowToken) => { console.warn("overflow on", page.id, overflowToken); // Only reflow while rendering if (this.rendered) { return; } let index = this.pages.indexOf(page) + 1; // Stop the rendering this.stop(); // Set the breakToken to resume at this.breakToken = overflowToken; // Remove pages this.removePages(index); if (this.rendered === true) { this.rendered = false; this.q.enqueue(async () => { this.start(); await this.render(this.source, this.breakToken); this.rendered = true; }); } }); page.onUnderflow((overflowToken) => { // console.log("underflow on", page.id, overflowToken); // page.append(this.source, overflowToken); }); } this.total = this.pages.length; return page; } /* insertPage(index, blank) { let lastPage = this.pages[index]; // Create a new page from the template let page = new Page(this.pagesArea, this.pageTemplate, blank, this.hooks); let total = this.pages.splice(index, 0, page); // Create the pages page.create(undefined, lastPage && lastPage.element); page.index(index + 1); for (let i = index + 2; i < this.pages.length; i++) { this.pages[i].index(i); } if (!blank) { // Listen for page overflow page.onOverflow((overflowToken) => { if (total < this.pages.length) { this.pages[total].layout(this.source, overflowToken); } else { let newPage = this.addPage(); newPage.layout(this.source, overflowToken); } }); page.onUnderflow(() => { // console.log("underflow on", page.id); }); } this.total += 1; return page; } */ async clonePage(originalPage) { let lastPage = this.pages[this.pages.length - 1]; let page = new Page(this.pagesArea, this.pageTemplate, false, this.hooks); this.pages.push(page); // Create the pages page.create(undefined, lastPage && lastPage.element); page.index(this.total); await this.hooks.beforePageLayout.trigger(page, undefined, undefined, this); this.emit("page", page); for (const className of originalPage.element.classList) { if (className !== "pagedjs_left_page" && className !== "pagedjs_right_page") { page.element.classList.add(className); } } await this.hooks.afterPageLayout.trigger(page.element, page, undefined, this); await this.hooks.finalizePage.trigger(page.element, page, undefined, this); this.emit("renderedPage", page); } loadFonts() { let fontPromises = []; (document.fonts || []).forEach((fontFace) => { if (fontFace.status !== "loaded") { let fontLoaded = fontFace.load().then((r) => { return fontFace.family; }, (r) => { console.warn("Failed to preload font-family:", fontFace.family); return fontFace.family; }); fontPromises.push(fontLoaded); } }); return Promise.all(fontPromises).catch((err) => { console.warn(err); }); } destroy() { this.pagesArea.remove(); this.pageTemplate.remove(); } } EventEmitter(Chunker.prototype); var syntax = {exports: {}}; var create$5 = {}; // // list // ┌──────┐ // ┌──────────────┼─head │ // │ │ tail─┼──────────────┐ // │ └──────┘ │ // ▼ ▼ // item item item item // ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ // null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │ // │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null // ├──────┤ ├──────┤ ├──────┤ ├──────┤ // │ data │ │ data │ │ data │ │ data │ // └──────┘ └──────┘ └──────┘ └──────┘ // function createItem(data) { return { prev: null, next: null, data: data }; } function allocateCursor(node, prev, next) { var cursor; if (cursors !== null) { cursor = cursors; cursors = cursors.cursor; cursor.prev = prev; cursor.next = next; cursor.cursor = node.cursor; } else { cursor = { prev: prev, next: next, cursor: node.cursor }; } node.cursor = cursor; return cursor; } function releaseCursor(node) { var cursor = node.cursor; node.cursor = cursor.cursor; cursor.prev = null; cursor.next = null; cursor.cursor = cursors; cursors = cursor; } var cursors = null; var List$6 = function() { this.cursor = null; this.head = null; this.tail = null; }; List$6.createItem = createItem; List$6.prototype.createItem = createItem; List$6.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) { var cursor = this.cursor; while (cursor !== null) { if (cursor.prev === prevOld) { cursor.prev = prevNew; } if (cursor.next === nextOld) { cursor.next = nextNew; } cursor = cursor.cursor; } }; List$6.prototype.getSize = function() { var size = 0; var cursor = this.head; while (cursor) { size++; cursor = cursor.next; } return size; }; List$6.prototype.fromArray = function(array) { var cursor = null; this.head = null; for (var i = 0; i < array.length; i++) { var item = createItem(array[i]); if (cursor !== null) { cursor.next = item; } else { this.head = item; } item.prev = cursor; cursor = item; } this.tail = cursor; return this; }; List$6.prototype.toArray = function() { var cursor = this.head; var result = []; while (cursor) { result.push(cursor.data); cursor = cursor.next; } return result; }; List$6.prototype.toJSON = List$6.prototype.toArray; List$6.prototype.isEmpty = function() { return this.head === null; }; List$6.prototype.first = function() { return this.head && this.head.data; }; List$6.prototype.last = function() { return this.tail && this.tail.data; }; List$6.prototype.each = function(fn, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, null, this.head); while (cursor.next !== null) { item = cursor.next; cursor.next = item.next; fn.call(context, item.data, item, this); } // pop cursor releaseCursor(this); }; List$6.prototype.forEach = List$6.prototype.each; List$6.prototype.eachRight = function(fn, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, this.tail, null); while (cursor.prev !== null) { item = cursor.prev; cursor.prev = item.prev; fn.call(context, item.data, item, this); } // pop cursor releaseCursor(this); }; List$6.prototype.forEachRight = List$6.prototype.eachRight; List$6.prototype.reduce = function(fn, initialValue, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, null, this.head); var acc = initialValue; while (cursor.next !== null) { item = cursor.next; cursor.next = item.next; acc = fn.call(context, acc, item.data, item, this); } // pop cursor releaseCursor(this); return acc; }; List$6.prototype.reduceRight = function(fn, initialValue, context) { var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, this.tail, null); var acc = initialValue; while (cursor.prev !== null) { item = cursor.prev; cursor.prev = item.prev; acc = fn.call(context, acc, item.data, item, this); } // pop cursor releaseCursor(this); return acc; }; List$6.prototype.nextUntil = function(start, fn, context) { if (start === null) { return; } var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, null, start); while (cursor.next !== null) { item = cursor.next; cursor.next = item.next; if (fn.call(context, item.data, item, this)) { break; } } // pop cursor releaseCursor(this); }; List$6.prototype.prevUntil = function(start, fn, context) { if (start === null) { return; } var item; if (context === undefined) { context = this; } // push cursor var cursor = allocateCursor(this, start, null); while (cursor.prev !== null) { item = cursor.prev; cursor.prev = item.prev; if (fn.call(context, item.data, item, this)) { break; } } // pop cursor releaseCursor(this); }; List$6.prototype.some = function(fn, context) { var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { if (fn.call(context, cursor.data, cursor, this)) { return true; } cursor = cursor.next; } return false; }; List$6.prototype.map = function(fn, context) { var result = new List$6(); var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { result.appendData(fn.call(context, cursor.data, cursor, this)); cursor = cursor.next; } return result; }; List$6.prototype.filter = function(fn, context) { var result = new List$6(); var cursor = this.head; if (context === undefined) { context = this; } while (cursor !== null) { if (fn.call(context, cursor.data, cursor, this)) { result.appendData(cursor.data); } cursor = cursor.next; } return result; }; List$6.prototype.clear = function() { this.head = null; this.tail = null; }; List$6.prototype.copy = function() { var result = new List$6(); var cursor = this.head; while (cursor !== null) { result.insert(createItem(cursor.data)); cursor = cursor.next; } return result; }; List$6.prototype.prepend = function(item) { // head // ^ // item this.updateCursors(null, item, this.head, item); // insert to the beginning of the list if (this.head !== null) { // new item <- first item this.head.prev = item; // new item -> first item item.next = this.head; } else { // if list has no head, then it also has no tail // in this case tail points to the new item this.tail = item; } // head always points to new item this.head = item; return this; }; List$6.prototype.prependData = function(data) { return this.prepend(createItem(data)); }; List$6.prototype.append = function(item) { return this.insert(item); }; List$6.prototype.appendData = function(data) { return this.insert(createItem(data)); }; List$6.prototype.insert = function(item, before) { if (before !== undefined && before !== null) { // prev before // ^ // item this.updateCursors(before.prev, item, before, item); if (before.prev === null) { // insert to the beginning of list if (this.head !== before) { throw new Error('before doesn\'t belong to list'); } // since head points to before therefore list doesn't empty // no need to check tail this.head = item; before.prev = item; item.next = before; this.updateCursors(null, item); } else { // insert between two items before.prev.next = item; item.prev = before.prev; before.prev = item; item.next = before; } } else { // tail // ^ // item this.updateCursors(this.tail, item, null, item); // insert to the ending of the list if (this.tail !== null) { // last item -> new item this.tail.next = item; // last item <- new item item.prev = this.tail; } else { // if list has no tail, then it also has no head // in this case head points to new item this.head = item; } // tail always points to new item this.tail = item; } return this; }; List$6.prototype.insertData = function(data, before) { return this.insert(createItem(data), before); }; List$6.prototype.remove = function(item) { // item // ^ // prev next this.updateCursors(item, item.prev, item, item.next); if (item.prev !== null) { item.prev.next = item.next; } else { if (this.head !== item) { throw new Error('item doesn\'t belong to list'); } this.head = item.next; } if (item.next !== null) { item.next.prev = item.prev; } else { if (this.tail !== item) { throw new Error('item doesn\'t belong to list'); } this.tail = item.prev; } item.prev = null; item.next = null; return item; }; List$6.prototype.push = function(data) { this.insert(createItem(data)); }; List$6.prototype.pop = function() { if (this.tail !== null) { return this.remove(this.tail); } }; List$6.prototype.unshift = function(data) { this.prepend(createItem(data)); }; List$6.prototype.shift = function() { if (this.head !== null) { return this.remove(this.head); } }; List$6.prototype.prependList = function(list) { return this.insertList(list, this.head); }; List$6.prototype.appendList = function(list) { return this.insertList(list); }; List$6.prototype.insertList = function(list, before) { // ignore empty lists if (list.head === null) { return this; } if (before !== undefined && before !== null) { this.updateCursors(before.prev, list.tail, before, list.head); // insert in the middle of dist list if (before.prev !== null) { // before.prev <-> list.head before.prev.next = list.head; list.head.prev = before.prev; } else { this.head = list.head; } before.prev = list.tail; list.tail.next = before; } else { this.updateCursors(this.tail, list.tail, null, list.head); // insert to end of the list if (this.tail !== null) { // if destination list has a tail, then it also has a head, // but head doesn't change // dest tail -> source head this.tail.next = list.head; // dest tail <- source head list.head.prev = this.tail; } else { // if list has no a tail, then it also has no a head // in this case points head to new item this.head = list.head; } // tail always start point to new item this.tail = list.tail; } list.head = null; list.tail = null; return this; }; List$6.prototype.replace = function(oldItem, newItemOrList) { if ('head' in newItemOrList) { this.insertList(newItemOrList, oldItem); } else { this.insert(newItemOrList, oldItem); } this.remove(oldItem); }; var List_1 = List$6; var createCustomError$3 = function createCustomError(name, message) { // use Object.create(), because some VMs prevent setting line/column otherwise // (iOS Safari 10 even throws an exception) var error = Object.create(SyntaxError.prototype); var errorStack = new Error(); error.name = name; error.message = message; Object.defineProperty(error, 'stack', { get: function() { return (errorStack.stack || '').replace(/^(.+\n){1,3}/, name + ': ' + message + '\n'); } }); return error; }; var createCustomError$2 = createCustomError$3; var MAX_LINE_LENGTH = 100; var OFFSET_CORRECTION = 60; var TAB_REPLACEMENT = ' '; function sourceFragment(error, extraLines) { function processLines(start, end) { return lines.slice(start, end).map(function(line, idx) { var num = String(start + idx + 1); while (num.length < maxNumLength) { num = ' ' + num; } return num + ' |' + line; }).join('\n'); } var lines = error.source.split(/\r\n?|\n|\f/); var line = error.line; var column = error.column; var startLine = Math.max(1, line - extraLines) - 1; var endLine = Math.min(line + extraLines, lines.length + 1); var maxNumLength = Math.max(4, String(endLine).length) + 1; var cutLeft = 0; // column correction according to replaced tab before column column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length; if (column > MAX_LINE_LENGTH) { cutLeft = column - OFFSET_CORRECTION + 3; column = OFFSET_CORRECTION - 2; } for (var i = startLine; i <= endLine; i++) { if (i >= 0 && i < lines.length) { lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT); lines[i] = (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') + lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) + (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : ''); } } return [ processLines(startLine, line), new Array(column + maxNumLength + 2).join('-') + '^', processLines(line, endLine) ].filter(Boolean).join('\n'); } var SyntaxError$4 = function(message, source, offset, line, column) { var error = createCustomError$2('SyntaxError', message); error.source = source; error.offset = offset; error.line = line; error.column = column; error.sourceFragment = function(extraLines) { return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines); }; Object.defineProperty(error, 'formattedMessage', { get: function() { return ( 'Parse error: ' + error.message + '\n' + sourceFragment(error, 2) ); } }); // for backward capability error.parseError = { offset: offset, line: line, column: column }; return error; }; var _SyntaxError$1 = SyntaxError$4; // CSS Syntax Module Level 3 // https://www.w3.org/TR/css-syntax-3/ var TYPE$H = { EOF: 0, // <EOF-token> Ident: 1, // <ident-token> Function: 2, // <function-token> AtKeyword: 3, // <at-keyword-token> Hash: 4, // <hash-token> String: 5, // <string-token> BadString: 6, // <bad-string-token> Url: 7, // <url-token> BadUrl: 8, // <bad-url-token> Delim: 9, // <delim-token> Number: 10, // <number-token> Percentage: 11, // <percentage-token> Dimension: 12, // <dimension-token> WhiteSpace: 13, // <whitespace-token> CDO: 14, // <CDO-token> CDC: 15, // <CDC-token> Colon: 16, // <colon-token> : Semicolon: 17, // <semicolon-token> ; Comma: 18, // <comma-token> , LeftSquareBracket: 19, // <[-token> RightSquareBracket: 20, // <]-token> LeftParenthesis: 21, // <(-token> RightParenthesis: 22, // <)-token> LeftCurlyBracket: 23, // <{-token> RightCurlyBracket: 24, // <}-token> Comment: 25 }; var NAME$3 = Object.keys(TYPE$H).reduce(function(result, key) { result[TYPE$H[key]] = key; return result; }, {}); var _const = { TYPE: TYPE$H, NAME: NAME$3 }; var EOF$1 = 0; // https://drafts.csswg.org/css-syntax-3/ // § 4.2. Definitions // digit // A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9). function isDigit$5(code) { return code >= 0x0030 && code <= 0x0039; } // hex digit // A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F), // or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f). function isHexDigit$4(code) { return ( isDigit$5(code) || // 0 .. 9 (code >= 0x0041 && code <= 0x0046) || // A .. F (code >= 0x0061 && code <= 0x0066) // a .. f ); } // uppercase letter // A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z). function isUppercaseLetter$1(code) { return code >= 0x0041 && code <= 0x005A; } // lowercase letter // A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z). function isLowercaseLetter(code) { return code >= 0x0061 && code <= 0x007A; } // letter // An uppercase letter or a lowercase letter. function isLetter(code) { return isUppercaseLetter$1(code) || isLowercaseLetter(code); } // non-ASCII code point // A code point with a value equal to or greater than U+0080 <control>. function isNonAscii(code) { return code >= 0x0080; } // name-start code point // A letter, a non-ASCII code point, or U+005F LOW LINE (_). function isNameStart(code) { return isLetter(code) || isNonAscii(code) || code === 0x005F; } // name code point // A name-start code point, a digit, or U+002D HYPHEN-MINUS (-). function isName$2(code) { return isNameStart(code) || isDigit$5(code) || code === 0x002D; } // non-printable code point // A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION, // or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE. function isNonPrintable(code) { return ( (code >= 0x0000 && code <= 0x0008) || (code === 0x000B) || (code >= 0x000E && code <= 0x001F) || (code === 0x007F) ); } // newline // U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition, // as they are converted to U+000A LINE FEED during preprocessing. // TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED function isNewline$1(code) { return code === 0x000A || code === 0x000D || code === 0x000C; } // whitespace // A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE. function isWhiteSpace$2(code) { return isNewline$1(code) || code === 0x0020 || code === 0x0009; } // § 4.3.8. Check if two code points are a valid escape function isValidEscape$2(first, second) { // If the first code point is not U+005C REVERSE SOLIDUS (\), return false. if (first !== 0x005C) { return false; } // Otherwise, if the second code point is a newline or EOF, return false. if (isNewline$1(second) || second === EOF$1) { return false; } // Otherwise, return true. return true; } // § 4.3.9. Check if three code points would start an identifier function isIdentifierStart$2(first, second, third) { // Look at the first code point: // U+002D HYPHEN-MINUS if (first === 0x002D) { // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS, // or the second and third code points are a valid escape, return true. Otherwise, return false. return ( isNameStart(second) || second === 0x002D || isValidEscape$2(second, third) ); } // name-start code point if (isNameStart(first)) { // Return true. return true; } // U+005C REVERSE SOLIDUS (\) if (first === 0x005C) { // If the first and second code points are a valid escape, return true. Otherwise, return false. return isValidEscape$2(first, second); } // anything else // Return false. return false; } // § 4.3.10. Check if three code points would start a number function isNumberStart$1(first, second, third) { // Look at the first code point: // U+002B PLUS SIGN (+) // U+002D HYPHEN-MINUS (-) if (first === 0x002B || first === 0x002D) { // If the second code point is a digit, return true. if (isDigit$5(second)) { return 2; } // Otherwise, if the second code point is a U+002E FULL STOP (.) // and the third code point is a digit, return true. // Otherwise, return false. return second === 0x002E && isDigit$5(third) ? 3 : 0; } // U+002E FULL STOP (.) if (first === 0x002E) { // If the second code point is a digit, return true. Otherwise, return false. return isDigit$5(second) ? 2 : 0; } // digit if (isDigit$5(first)) { // Return true. return 1; } // anything else // Return false. return 0; } // // Misc // // detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark) function isBOM$2(code) { // UTF-16BE if (code === 0xFEFF) { return 1; } // UTF-16LE if (code === 0xFFFE) { return 1; } return 0; } // Fast code category // // https://drafts.csswg.org/css-syntax/#tokenizer-definitions // > non-ASCII code point // > A code point with a value equal to or greater than U+0080 <control> // > name-start code point // > A letter, a non-ASCII code point, or U+005F LOW LINE (_). // > name code point // > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-) // That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only var CATEGORY = new Array(0x80); charCodeCategory$1.Eof = 0x80; charCodeCategory$1.WhiteSpace = 0x82; charCodeCategory$1.Digit = 0x83; charCodeCategory$1.NameStart = 0x84; charCodeCategory$1.NonPrintable = 0x85; for (var i = 0; i < CATEGORY.length; i++) { switch (true) { case isWhiteSpace$2(i): CATEGORY[i] = charCodeCategory$1.WhiteSpace; break; case isDigit$5(i): CATEGORY[i] = charCodeCategory$1.Digit; break; case isNameStart(i): CATEGORY[i] = charCodeCategory$1.NameStart; break; case isNonPrintable(i): CATEGORY[i] = charCodeCategory$1.NonPrintable; break; default: CATEGORY[i] = i || charCodeCategory$1.Eof; } } function charCodeCategory$1(code) { return code < 0x80 ? CATEGORY[code] : charCodeCategory$1.NameStart; } var charCodeDefinitions$1 = { isDigit: isDigit$5, isHexDigit: isHexDigit$4, isUppercaseLetter: isUppercaseLetter$1, isLowercaseLetter: isLowercaseLetter, isLetter: isLetter, isNonAscii: isNonAscii, isNameStart: isNameStart, isName: isName$2, isNonPrintable: isNonPrintable, isNewline: isNewline$1, isWhiteSpace: isWhiteSpace$2, isValidEscape: isValidEscape$2, isIdentifierStart: isIdentifierStart$2, isNumberStart: isNumberStart$1, isBOM: isBOM$2, charCodeCategory: charCodeCategory$1 }; var charCodeDef = charCodeDefinitions$1; var isDigit$4 = charCodeDef.isDigit; var isHexDigit$3 = charCodeDef.isHexDigit; var isUppercaseLetter = charCodeDef.isUppercaseLetter; var isName$1 = charCodeDef.isName; var isWhiteSpace$1 = charCodeDef.isWhiteSpace; var isValidEscape$1 = charCodeDef.isValidEscape; function getCharCode(source, offset) { return offset < source.length ? source.charCodeAt(offset) : 0; } function getNewlineLength$1(source, offset, code) { if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) { return 2; } return 1; } function cmpChar$5(testStr, offset, referenceCode) { var code = testStr.charCodeAt(offset); // code.toLowerCase() for A..Z if (isUppercaseLetter(code)) { code = code | 32; } return code === referenceCode; } function cmpStr$6(testStr, start, end, referenceStr) { if (end - start !== referenceStr.length) { return false; } if (start < 0 || end > testStr.length) { return false; } for (var i = start; i < end; i++) { var testCode = testStr.charCodeAt(i); var referenceCode = referenceStr.charCodeAt(i - start); // testCode.toLowerCase() for A..Z if (isUppercaseLetter(testCode)) { testCode = testCode | 32; } if (testCode !== referenceCode) { return false; } } return true; } function findWhiteSpaceStart$1(source, offset) { for (; offset >= 0; offset--) { if (!isWhiteSpace$1(source.charCodeAt(offset))) { break; } } return offset + 1; } function findWhiteSpaceEnd$1(source, offset) { for (; offset < source.length; offset++) { if (!isWhiteSpace$1(source.charCodeAt(offset))) { break; } } return offset; } function findDecimalNumberEnd(source, offset) { for (; offset < source.length; offset++) { if (!isDigit$4(source.charCodeAt(offset))) { break; } } return offset; } // § 4.3.7. Consume an escaped code point function consumeEscaped$1(source, offset) { // It assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed and // that the next input code point has already been verified to be part of a valid escape. offset += 2; // hex digit if (isHexDigit$3(getCharCode(source, offset - 1))) { // Consume as many hex digits as possible, but no more than 5. // Note that this means 1-6 hex digits have been consumed in total. for (var maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) { if (!isHexDigit$3(getCharCode(source, offset))) { break; } } // If the next input code point is whitespace, consume it as well. var code = getCharCode(source, offset); if (isWhiteSpace$1(code)) { offset += getNewlineLength$1(source, offset, code); } } return offset; } // §4.3.11. Consume a name // Note: This algorithm does not do the verification of the first few code points that are necessary // to ensure the returned code points would constitute an <ident-token>. If that is the intended use, // ensure that the stream starts with an identifier before calling this algorithm. function consumeName$1(source, offset) { // Let result initially be an empty string. // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); // name code point if (isName$1(code)) { // Append the code point to result. continue; } // the stream starts with a valid escape if (isValidEscape$1(code, getCharCode(source, offset + 1))) { // Consume an escaped code point. Append the returned code point to result. offset = consumeEscaped$1(source, offset) - 1; continue; } // anything else // Reconsume the current input code point. Return result. break; } return offset; } // §4.3.12. Consume a number function consumeNumber$5(source, offset) { var code = source.charCodeAt(offset); // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-), // consume it and append it to repr. if (code === 0x002B || code === 0x002D) { code = source.charCodeAt(offset += 1); } // 3. While the next input code point is a digit, consume it and append it to repr. if (isDigit$4(code)) { offset = findDecimalNumberEnd(source, offset + 1); code = source.charCodeAt(offset); } // 4. If the next 2 input code points are U+002E FULL STOP (.) followed by a digit, then: if (code === 0x002E && isDigit$4(source.charCodeAt(offset + 1))) { // 4.1 Consume them. // 4.2 Append them to repr. code = source.charCodeAt(offset += 2); // 4.3 Set type to "number". // TODO // 4.4 While the next input code point is a digit, consume it and append it to repr. offset = findDecimalNumberEnd(source, offset); } // 5. If the next 2 or 3 input code points are U+0045 LATIN CAPITAL LETTER E (E) // or U+0065 LATIN SMALL LETTER E (e), ... , followed by a digit, then: if (cmpChar$5(source, offset, 101 /* e */)) { var sign = 0; code = source.charCodeAt(offset + 1); // ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ... if (code === 0x002D || code === 0x002B) { sign = 1; code = source.charCodeAt(offset + 2); } // ... followed by a digit if (isDigit$4(code)) { // 5.1 Consume them. // 5.2 Append them to repr. // 5.3 Set type to "number". // TODO // 5.4 While the next input code point is a digit, consume it and append it to repr. offset = findDecimalNumberEnd(source, offset + 1 + sign + 1); } } return offset; } // § 4.3.14. Consume the remnants of a bad url // ... its sole use is to consume enough of the input stream to reach a recovery point // where normal tokenizing can resume. function consumeBadUrlRemnants$1(source, offset) { // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); // U+0029 RIGHT PARENTHESIS ()) // EOF if (code === 0x0029) { // Return. offset++; break; } if (isValidEscape$1(code, getCharCode(source, offset + 1))) { // Consume an escaped code point. // Note: This allows an escaped right parenthesis ("\)") to be encountered // without ending the <bad-url-token>. This is otherwise identical to // the "anything else" clause. offset = consumeEscaped$1(source, offset); } } return offset; } var utils$2 = { consumeEscaped: consumeEscaped$1, consumeName: consumeName$1, consumeNumber: consumeNumber$5, consumeBadUrlRemnants: consumeBadUrlRemnants$1, cmpChar: cmpChar$5, cmpStr: cmpStr$6, getNewlineLength: getNewlineLength$1, findWhiteSpaceStart: findWhiteSpaceStart$1, findWhiteSpaceEnd: findWhiteSpaceEnd$1 }; var constants$2 = _const; var TYPE$G = constants$2.TYPE; var NAME$2 = constants$2.NAME; var utils$1 = utils$2; var cmpStr$5 = utils$1.cmpStr; var EOF = TYPE$G.EOF; var WHITESPACE$c = TYPE$G.WhiteSpace; var COMMENT$a = TYPE$G.Comment; var OFFSET_MASK$1 = 0x00FFFFFF; var TYPE_SHIFT$1 = 24; var TokenStream$4 = function() { this.offsetAndType = null; this.balance = null; this.reset(); }; TokenStream$4.prototype = { reset: function() { this.eof = false; this.tokenIndex = -1; this.tokenType = 0; this.tokenStart = this.firstCharOffset; this.tokenEnd = this.firstCharOffset; }, lookupType: function(offset) { offset += this.tokenIndex; if (offset < this.tokenCount) { return this.offsetAndType[offset] >> TYPE_SHIFT$1; } return EOF; }, lookupOffset: function(offset) { offset += this.tokenIndex; if (offset < this.tokenCount) { return this.offsetAndType[offset - 1] & OFFSET_MASK$1; } return this.source.length; }, lookupValue: function(offset, referenceStr) { offset += this.tokenIndex; if (offset < this.tokenCount) { return cmpStr$5( this.source, this.offsetAndType[offset - 1] & OFFSET_MASK$1, this.offsetAndType[offset] & OFFSET_MASK$1, referenceStr ); } return false; }, getTokenStart: function(tokenIndex) { if (tokenIndex === this.tokenIndex) { return this.tokenStart; } if (tokenIndex > 0) { return tokenIndex < this.tokenCount ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK$1 : this.offsetAndType[this.tokenCount] & OFFSET_MASK$1; } return this.firstCharOffset; }, // TODO: -> skipUntilBalanced getRawLength: function(startToken, mode) { var cursor = startToken; var balanceEnd; var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK$1; var type; loop: for (; cursor < this.tokenCount; cursor++) { balanceEnd = this.balance[cursor]; // stop scanning on balance edge that points to offset before start token if (balanceEnd < startToken) { break loop; } type = this.offsetAndType[cursor] >> TYPE_SHIFT$1; // check token is stop type switch (mode(type, this.source, offset)) { case 1: break loop; case 2: cursor++; break loop; default: // fast forward to the end of balanced block if (this.balance[balanceEnd] === cursor) { cursor = balanceEnd; } offset = this.offsetAndType[cursor] & OFFSET_MASK$1; } } return cursor - this.tokenIndex; }, isBalanceEdge: function(pos) { return this.balance[this.tokenIndex] < pos; }, isDelim: function(code, offset) { if (offset) { return ( this.lookupType(offset) === TYPE$G.Delim && this.source.charCodeAt(this.lookupOffset(offset)) === code ); } return ( this.tokenType === TYPE$G.Delim && this.source.charCodeAt(this.tokenStart) === code ); }, getTokenValue: function() { return this.source.substring(this.tokenStart, this.tokenEnd); }, getTokenLength: function() { return this.tokenEnd - this.tokenStart; }, substrToCursor: function(start) { return this.source.substring(start, this.tokenStart); }, skipWS: function() { for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) { if ((this.offsetAndType[i] >> TYPE_SHIFT$1) !== WHITESPACE$c) { break; } } if (skipTokenCount > 0) { this.skip(skipTokenCount); } }, skipSC: function() { while (this.tokenType === WHITESPACE$c || this.tokenType === COMMENT$a) { this.next(); } }, skip: function(tokenCount) { var next = this.tokenIndex + tokenCount; if (next < this.tokenCount) { this.tokenIndex = next; this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK$1; next = this.offsetAndType[next]; this.tokenType = next >> TYPE_SHIFT$1; this.tokenEnd = next & OFFSET_MASK$1; } else { this.tokenIndex = this.tokenCount; this.next(); } }, next: function() { var next = this.tokenIndex + 1; if (next < this.tokenCount) { this.tokenIndex = next; this.tokenStart = this.tokenEnd; next = this.offsetAndType[next]; this.tokenType = next >> TYPE_SHIFT$1; this.tokenEnd = next & OFFSET_MASK$1; } else { this.tokenIndex = this.tokenCount; this.eof = true; this.tokenType = EOF; this.tokenStart = this.tokenEnd = this.source.length; } }, forEachToken(fn) { for (var i = 0, offset = this.firstCharOffset; i < this.tokenCount; i++) { var start = offset; var item = this.offsetAndType[i]; var end = item & OFFSET_MASK$1; var type = item >> TYPE_SHIFT$1; offset = end; fn(type, start, end, i); } }, dump() { var tokens = new Array(this.tokenCount); this.forEachToken((type, start, end, index) => { tokens[index] = { idx: index, type: NAME$2[type], chunk: this.source.substring(start, end), balance: this.balance[index] }; }); return tokens; } }; var TokenStream_1 = TokenStream$4; function noop$3(value) { return value; } function generateMultiplier(multiplier) { if (multiplier.min === 0 && multiplier.max === 0) { return '*'; } if (multiplier.min === 0 && multiplier.max === 1) { return '?'; } if (multiplier.min === 1 && multiplier.max === 0) { return multiplier.comma ? '#' : '+'; } if (multiplier.min === 1 && multiplier.max === 1) { return ''; } return ( (multiplier.comma ? '#' : '') + (multiplier.min === multiplier.max ? '{' + multiplier.min + '}' : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}' ) ); } function generateTypeOpts(node) { switch (node.type) { case 'Range': return ( ' [' + (node.min === null ? '-∞' : node.min) + ',' + (node.max === null ? '∞' : node.max) + ']' ); default: throw new Error('Unknown node type `' + node.type + '`'); } } function generateSequence(node, decorate, forceBraces, compact) { var combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' '; var result = node.terms.map(function(term) { return generate$2(term, decorate, forceBraces, compact); }).join(combinator); if (node.explicit || forceBraces) { result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]'); } return result; } function generate$2(node, decorate, forceBraces, compact) { var result; switch (node.type) { case 'Group': result = generateSequence(node, decorate, forceBraces, compact) + (node.disallowEmpty ? '!' : ''); break; case 'Multiplier': // return since node is a composition return ( generate$2(node.term, decorate, forceBraces, compact) + decorate(generateMultiplier(node), node) ); case 'Type': result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>'; break; case 'Property': result = '<\'' + node.name + '\'>'; break; case 'Keyword': result = node.name; break; case 'AtKeyword': result = '@' + node.name; break; case 'Function': result = node.name + '('; break; case 'String': case 'Token': result = node.value; break; case 'Comma': result = ','; break; default: throw new Error('Unknown node type `' + node.type + '`'); } return decorate(result, node); } var generate_1 = function(node, options) { var decorate = noop$3; var forceBraces = false; var compact = false; if (typeof options === 'function') { decorate = options; } else if (options) { forceBraces = Boolean(options.forceBraces); compact = Boolean(options.compact); if (typeof options.decorate === 'function') { decorate = options.decorate; } } return generate$2(node, decorate, forceBraces, compact); }; const createCustomError$1 = createCustomError$3; const generate$1 = generate_1; const defaultLoc = { offset: 0, line: 1, column: 1 }; function locateMismatch(matchResult, node) { const tokens = matchResult.tokens; const longestMatch = matchResult.longestMatch; const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null; const badNode = mismatchNode !== node ? mismatchNode : null; let mismatchOffset = 0; let mismatchLength = 0; let entries = 0; let css = ''; let start; let end; for (let i = 0; i < tokens.length; i++) { const token = tokens[i].value; if (i === longestMatch) { mismatchLength = token.length; mismatchOffset = css.length; } if (badNode !== null && tokens[i].node === badNode) { if (i <= longestMatch) { entries++; } else { entries = 0; } } css += token; } if (longestMatch === tokens.length || entries > 1) { // last start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css); end = buildLoc(start); } else { start = fromLoc(badNode, 'start') || buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset)); end = fromLoc(badNode, 'end') || buildLoc(start, css.substr(mismatchOffset, mismatchLength)); } return { css, mismatchOffset, mismatchLength, start, end }; } function fromLoc(node, point) { const value = node && node.loc && node.loc[point]; if (value) { return 'line' in value ? buildLoc(value) : value; } return null; } function buildLoc({ offset, line, column }, extra) { const loc = { offset, line, column }; if (extra) { const lines = extra.split(/\n|\r\n?|\f/); loc.offset += extra.length; loc.line += lines.length - 1; loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1; } return loc; } const SyntaxReferenceError$1 = function(type, referenceName) { const error = createCustomError$1( 'SyntaxReferenceError', type + (referenceName ? ' `' + referenceName + '`' : '') ); error.reference = referenceName; return error; }; const SyntaxMatchError$1 = function(message, syntax, node, matchResult) { const error = createCustomError$1('SyntaxMatchError', message); const { css, mismatchOffset, mismatchLength, start, end } = locateMismatch(matchResult, node); error.rawMessage = message; error.syntax = syntax ? generate$1(syntax) : '<generic>'; error.css = css; error.mismatchOffset = mismatchOffset; error.mismatchLength = mismatchLength; error.message = message + '\n' + ' syntax: ' + error.syntax + '\n' + ' value: ' + (css || '<empty string>') + '\n' + ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^'; Object.assign(error, start); error.loc = { source: (node && node.loc && node.loc.source) || '<unknown>', start, end }; return error; }; var error = { SyntaxReferenceError: SyntaxReferenceError$1, SyntaxMatchError: SyntaxMatchError$1 }; var hasOwnProperty$7 = Object.prototype.hasOwnProperty; var keywords$1 = Object.create(null); var properties$1 = Object.create(null); var HYPHENMINUS$5 = 45; // '-'.charCodeAt() function isCustomProperty$1(str, offset) { offset = offset || 0; return str.length - offset >= 2 && str.charCodeAt(offset) === HYPHENMINUS$5 && str.charCodeAt(offset + 1) === HYPHENMINUS$5; } function getVendorPrefix(str, offset) { offset = offset || 0; // verdor prefix should be at least 3 chars length if (str.length - offset >= 3) { // vendor prefix starts with hyper minus following non-hyper minus if (str.charCodeAt(offset) === HYPHENMINUS$5 && str.charCodeAt(offset + 1) !== HYPHENMINUS$5) { // vendor prefix should contain a hyper minus at the ending var secondDashIndex = str.indexOf('-', offset + 2); if (secondDashIndex !== -1) { return str.substring(offset, secondDashIndex + 1); } } } return ''; } function getKeywordDescriptor(keyword) { if (hasOwnProperty$7.call(keywords$1, keyword)) { return keywords$1[keyword]; } var name = keyword.toLowerCase(); if (hasOwnProperty$7.call(keywords$1, name)) { return keywords$1[keyword] = keywords$1[name]; } var custom = isCustomProperty$1(name, 0); var vendor = !custom ? getVendorPrefix(name, 0) : ''; return keywords$1[keyword] = Object.freeze({ basename: name.substr(vendor.length), name: name, vendor: vendor, prefix: vendor, custom: custom }); } function getPropertyDescriptor(property) { if (hasOwnProperty$7.call(properties$1, property)) { return properties$1[property]; } var name = property; var hack = property[0]; if (hack === '/') { hack = property[1] === '/' ? '//' : '/'; } else if (hack !== '_' && hack !== '*' && hack !== '$' && hack !== '#' && hack !== '+' && hack !== '&') { hack = ''; } var custom = isCustomProperty$1(name, hack.length); // re-use result when possible (the same as for lower case) if (!custom) { name = name.toLowerCase(); if (hasOwnProperty$7.call(properties$1, name)) { return properties$1[property] = properties$1[name]; } } var vendor = !custom ? getVendorPrefix(name, hack.length) : ''; var prefix = name.substr(0, hack.length + vendor.length); return properties$1[property] = Object.freeze({ basename: name.substr(prefix.length), name: name.substr(hack.length), hack: hack, vendor: vendor, prefix: prefix, custom: custom }); } var names$2 = { keyword: getKeywordDescriptor, property: getPropertyDescriptor, isCustomProperty: isCustomProperty$1, vendorPrefix: getVendorPrefix }; var MIN_SIZE = 16 * 1024; var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported var adoptBuffer$2 = function adoptBuffer(buffer, size) { if (buffer === null || buffer.length < size) { return new SafeUint32Array(Math.max(size + 1024, MIN_SIZE)); } return buffer; }; var TokenStream$3 = TokenStream_1; var adoptBuffer$1 = adoptBuffer$2; var constants$1 = _const; var TYPE$F = constants$1.TYPE; var charCodeDefinitions = charCodeDefinitions$1; var isNewline = charCodeDefinitions.isNewline; var isName = charCodeDefinitions.isName; var isValidEscape = charCodeDefinitions.isValidEscape; var isNumberStart = charCodeDefinitions.isNumberStart; var isIdentifierStart$1 = charCodeDefinitions.isIdentifierStart; var charCodeCategory = charCodeDefinitions.charCodeCategory; var isBOM$1 = charCodeDefinitions.isBOM; var utils = utils$2; var cmpStr$4 = utils.cmpStr; var getNewlineLength = utils.getNewlineLength; var findWhiteSpaceEnd = utils.findWhiteSpaceEnd; var consumeEscaped = utils.consumeEscaped; var consumeName = utils.consumeName; var consumeNumber$4 = utils.consumeNumber; var consumeBadUrlRemnants = utils.consumeBadUrlRemnants; var OFFSET_MASK = 0x00FFFFFF; var TYPE_SHIFT = 24; function tokenize$3(source, stream) { function getCharCode(offset) { return offset < sourceLength ? source.charCodeAt(offset) : 0; } // § 4.3.3. Consume a numeric token function consumeNumericToken() { // Consume a number and let number be the result. offset = consumeNumber$4(source, offset); // If the next 3 input code points would start an identifier, then: if (isIdentifierStart$1(getCharCode(offset), getCharCode(offset + 1), getCharCode(offset + 2))) { // Create a <dimension-token> with the same value and type flag as number, and a unit set initially to the empty string. // Consume a name. Set the <dimension-token>’s unit to the returned value. // Return the <dimension-token>. type = TYPE$F.Dimension; offset = consumeName(source, offset); return; } // Otherwise, if the next input code point is U+0025 PERCENTAGE SIGN (%), consume it. if (getCharCode(offset) === 0x0025) { // Create a <percentage-token> with the same value as number, and return it. type = TYPE$F.Percentage; offset++; return; } // Otherwise, create a <number-token> with the same value and type flag as number, and return it. type = TYPE$F.Number; } // § 4.3.4. Consume an ident-like token function consumeIdentLikeToken() { const nameStartOffset = offset; // Consume a name, and let string be the result. offset = consumeName(source, offset); // If string’s value is an ASCII case-insensitive match for "url", // and the next input code point is U+0028 LEFT PARENTHESIS ((), consume it. if (cmpStr$4(source, nameStartOffset, offset, 'url') && getCharCode(offset) === 0x0028) { // While the next two input code points are whitespace, consume the next input code point. offset = findWhiteSpaceEnd(source, offset + 1); // If the next one or two input code points are U+0022 QUOTATION MARK ("), U+0027 APOSTROPHE ('), // or whitespace followed by U+0022 QUOTATION MARK (") or U+0027 APOSTROPHE ('), // then create a <function-token> with its value set to string and return it. if (getCharCode(offset) === 0x0022 || getCharCode(offset) === 0x0027) { type = TYPE$F.Function; offset = nameStartOffset + 4; return; } // Otherwise, consume a url token, and return it. consumeUrlToken(); return; } // Otherwise, if the next input code point is U+0028 LEFT PARENTHESIS ((), consume it. // Create a <function-token> with its value set to string and return it. if (getCharCode(offset) === 0x0028) { type = TYPE$F.Function; offset++; return; } // Otherwise, create an <ident-token> with its value set to string and return it. type = TYPE$F.Ident; } // § 4.3.5. Consume a string token function consumeStringToken(endingCodePoint) { // This algorithm may be called with an ending code point, which denotes the code point // that ends the string. If an ending code point is not specified, // the current input code point is used. if (!endingCodePoint) { endingCodePoint = getCharCode(offset++); } // Initially create a <string-token> with its value set to the empty string. type = TYPE$F.String; // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); switch (charCodeCategory(code)) { // ending code point case endingCodePoint: // Return the <string-token>. offset++; return; // EOF case charCodeCategory.Eof: // This is a parse error. Return the <string-token>. return; // newline case charCodeCategory.WhiteSpace: if (isNewline(code)) { // This is a parse error. Reconsume the current input code point, // create a <bad-string-token>, and return it. offset += getNewlineLength(source, offset, code); type = TYPE$F.BadString; return; } break; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the next input code point is EOF, do nothing. if (offset === source.length - 1) { break; } var nextCode = getCharCode(offset + 1); // Otherwise, if the next input code point is a newline, consume it. if (isNewline(nextCode)) { offset += getNewlineLength(source, offset + 1, nextCode); } else if (isValidEscape(code, nextCode)) { // Otherwise, (the stream starts with a valid escape) consume // an escaped code point and append the returned code point to // the <string-token>’s value. offset = consumeEscaped(source, offset) - 1; } break; // anything else // Append the current input code point to the <string-token>’s value. } } } // § 4.3.6. Consume a url token // Note: This algorithm assumes that the initial "url(" has already been consumed. // This algorithm also assumes that it’s being called to consume an "unquoted" value, like url(foo). // A quoted value, like url("foo"), is parsed as a <function-token>. Consume an ident-like token // automatically handles this distinction; this algorithm shouldn’t be called directly otherwise. function consumeUrlToken() { // Initially create a <url-token> with its value set to the empty string. type = TYPE$F.Url; // Consume as much whitespace as possible. offset = findWhiteSpaceEnd(source, offset); // Repeatedly consume the next input code point from the stream: for (; offset < source.length; offset++) { var code = source.charCodeAt(offset); switch (charCodeCategory(code)) { // U+0029 RIGHT PARENTHESIS ()) case 0x0029: // Return the <url-token>. offset++; return; // EOF case charCodeCategory.Eof: // This is a parse error. Return the <url-token>. return; // whitespace case charCodeCategory.WhiteSpace: // Consume as much whitespace as possible. offset = findWhiteSpaceEnd(source, offset); // If the next input code point is U+0029 RIGHT PARENTHESIS ()) or EOF, // consume it and return the <url-token> // (if EOF was encountered, this is a parse error); if (getCharCode(offset) === 0x0029 || offset >= source.length) { if (offset < source.length) { offset++; } return; } // otherwise, consume the remnants of a bad url, create a <bad-url-token>, // and return it. offset = consumeBadUrlRemnants(source, offset); type = TYPE$F.BadUrl; return; // U+0022 QUOTATION MARK (") // U+0027 APOSTROPHE (') // U+0028 LEFT PARENTHESIS (() // non-printable code point case 0x0022: case 0x0027: case 0x0028: case charCodeCategory.NonPrintable: // This is a parse error. Consume the remnants of a bad url, // create a <bad-url-token>, and return it. offset = consumeBadUrlRemnants(source, offset); type = TYPE$F.BadUrl; return; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the stream starts with a valid escape, consume an escaped code point and // append the returned code point to the <url-token>’s value. if (isValidEscape(code, getCharCode(offset + 1))) { offset = consumeEscaped(source, offset) - 1; break; } // Otherwise, this is a parse error. Consume the remnants of a bad url, // create a <bad-url-token>, and return it. offset = consumeBadUrlRemnants(source, offset); type = TYPE$F.BadUrl; return; // anything else // Append the current input code point to the <url-token>’s value. } } } if (!stream) { stream = new TokenStream$3(); } // ensure source is a string source = String(source || ''); var sourceLength = source.length; var offsetAndType = adoptBuffer$1(stream.offsetAndType, sourceLength + 1); // +1 because of eof-token var balance = adoptBuffer$1(stream.balance, sourceLength + 1); var tokenCount = 0; var start = isBOM$1(getCharCode(0)); var offset = start; var balanceCloseType = 0; var balanceStart = 0; var balancePrev = 0; // https://drafts.csswg.org/css-syntax-3/#consume-token // § 4.3.1. Consume a token while (offset < sourceLength) { var code = source.charCodeAt(offset); var type = 0; balance[tokenCount] = sourceLength; switch (charCodeCategory(code)) { // whitespace case charCodeCategory.WhiteSpace: // Consume as much whitespace as possible. Return a <whitespace-token>. type = TYPE$F.WhiteSpace; offset = findWhiteSpaceEnd(source, offset + 1); break; // U+0022 QUOTATION MARK (") case 0x0022: // Consume a string token and return it. consumeStringToken(); break; // U+0023 NUMBER SIGN (#) case 0x0023: // If the next input code point is a name code point or the next two input code points are a valid escape, then: if (isName(getCharCode(offset + 1)) || isValidEscape(getCharCode(offset + 1), getCharCode(offset + 2))) { // Create a <hash-token>. type = TYPE$F.Hash; // If the next 3 input code points would start an identifier, set the <hash-token>’s type flag to "id". // if (isIdentifierStart(getCharCode(offset + 1), getCharCode(offset + 2), getCharCode(offset + 3))) { // // TODO: set id flag // } // Consume a name, and set the <hash-token>’s value to the returned string. offset = consumeName(source, offset + 1); // Return the <hash-token>. } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+0027 APOSTROPHE (') case 0x0027: // Consume a string token and return it. consumeStringToken(); break; // U+0028 LEFT PARENTHESIS (() case 0x0028: // Return a <(-token>. type = TYPE$F.LeftParenthesis; offset++; break; // U+0029 RIGHT PARENTHESIS ()) case 0x0029: // Return a <)-token>. type = TYPE$F.RightParenthesis; offset++; break; // U+002B PLUS SIGN (+) case 0x002B: // If the input stream starts with a number, ... if (isNumberStart(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+002C COMMA (,) case 0x002C: // Return a <comma-token>. type = TYPE$F.Comma; offset++; break; // U+002D HYPHEN-MINUS (-) case 0x002D: // If the input stream starts with a number, reconsume the current input code point, consume a numeric token, and return it. if (isNumberStart(code, getCharCode(offset + 1), getCharCode(offset + 2))) { consumeNumericToken(); } else { // Otherwise, if the next 2 input code points are U+002D HYPHEN-MINUS U+003E GREATER-THAN SIGN (->), consume them and return a <CDC-token>. if (getCharCode(offset + 1) === 0x002D && getCharCode(offset + 2) === 0x003E) { type = TYPE$F.CDC; offset = offset + 3; } else { // Otherwise, if the input stream starts with an identifier, ... if (isIdentifierStart$1(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } } } break; // U+002E FULL STOP (.) case 0x002E: // If the input stream starts with a number, ... if (isNumberStart(code, getCharCode(offset + 1), getCharCode(offset + 2))) { // ... reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+002F SOLIDUS (/) case 0x002F: // If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A ASTERISK (*), if (getCharCode(offset + 1) === 0x002A) { // ... consume them and all following code points up to and including the first U+002A ASTERISK (*) // followed by a U+002F SOLIDUS (/), or up to an EOF code point. type = TYPE$F.Comment; offset = source.indexOf('*/', offset + 2) + 2; if (offset === 1) { offset = source.length; } } else { type = TYPE$F.Delim; offset++; } break; // U+003A COLON (:) case 0x003A: // Return a <colon-token>. type = TYPE$F.Colon; offset++; break; // U+003B SEMICOLON (;) case 0x003B: // Return a <semicolon-token>. type = TYPE$F.Semicolon; offset++; break; // U+003C LESS-THAN SIGN (<) case 0x003C: // If the next 3 input code points are U+0021 EXCLAMATION MARK U+002D HYPHEN-MINUS U+002D HYPHEN-MINUS (!--), ... if (getCharCode(offset + 1) === 0x0021 && getCharCode(offset + 2) === 0x002D && getCharCode(offset + 3) === 0x002D) { // ... consume them and return a <CDO-token>. type = TYPE$F.CDO; offset = offset + 4; } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+0040 COMMERCIAL AT (@) case 0x0040: // If the next 3 input code points would start an identifier, ... if (isIdentifierStart$1(getCharCode(offset + 1), getCharCode(offset + 2), getCharCode(offset + 3))) { // ... consume a name, create an <at-keyword-token> with its value set to the returned value, and return it. type = TYPE$F.AtKeyword; offset = consumeName(source, offset + 1); } else { // Otherwise, return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+005B LEFT SQUARE BRACKET ([) case 0x005B: // Return a <[-token>. type = TYPE$F.LeftSquareBracket; offset++; break; // U+005C REVERSE SOLIDUS (\) case 0x005C: // If the input stream starts with a valid escape, ... if (isValidEscape(code, getCharCode(offset + 1))) { // ... reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); } else { // Otherwise, this is a parse error. Return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } break; // U+005D RIGHT SQUARE BRACKET (]) case 0x005D: // Return a <]-token>. type = TYPE$F.RightSquareBracket; offset++; break; // U+007B LEFT CURLY BRACKET ({) case 0x007B: // Return a <{-token>. type = TYPE$F.LeftCurlyBracket; offset++; break; // U+007D RIGHT CURLY BRACKET (}) case 0x007D: // Return a <}-token>. type = TYPE$F.RightCurlyBracket; offset++; break; // digit case charCodeCategory.Digit: // Reconsume the current input code point, consume a numeric token, and return it. consumeNumericToken(); break; // name-start code point case charCodeCategory.NameStart: // Reconsume the current input code point, consume an ident-like token, and return it. consumeIdentLikeToken(); break; // EOF case charCodeCategory.Eof: // Return an <EOF-token>. break; // anything else default: // Return a <delim-token> with its value set to the current input code point. type = TYPE$F.Delim; offset++; } switch (type) { case balanceCloseType: balancePrev = balanceStart & OFFSET_MASK; balanceStart = balance[balancePrev]; balanceCloseType = balanceStart >> TYPE_SHIFT; balance[tokenCount] = balancePrev; balance[balancePrev++] = tokenCount; for (; balancePrev < tokenCount; balancePrev++) { if (balance[balancePrev] === sourceLength) { balance[balancePrev] = tokenCount; } } break; case TYPE$F.LeftParenthesis: case TYPE$F.Function: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$F.RightParenthesis; balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount; break; case TYPE$F.LeftSquareBracket: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$F.RightSquareBracket; balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount; break; case TYPE$F.LeftCurlyBracket: balance[tokenCount] = balanceStart; balanceCloseType = TYPE$F.RightCurlyBracket; balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount; break; } offsetAndType[tokenCount++] = (type << TYPE_SHIFT) | offset; } // finalize buffers offsetAndType[tokenCount] = (TYPE$F.EOF << TYPE_SHIFT) | offset; // <EOF-token> balance[tokenCount] = sourceLength; balance[sourceLength] = sourceLength; // prevents false positive balance match with any token while (balanceStart !== 0) { balancePrev = balanceStart & OFFSET_MASK; balanceStart = balance[balancePrev]; balance[balancePrev] = sourceLength; } // update stream stream.source = source; stream.firstCharOffset = start; stream.offsetAndType = offsetAndType; stream.tokenCount = tokenCount; stream.balance = balance; stream.reset(); stream.next(); return stream; } // extend tokenizer with constants Object.keys(constants$1).forEach(function(key) { tokenize$3[key] = constants$1[key]; }); // extend tokenizer with static methods from utils Object.keys(charCodeDefinitions).forEach(function(key) { tokenize$3[key] = charCodeDefinitions[key]; }); Object.keys(utils).forEach(function(key) { tokenize$3[key] = utils[key]; }); var tokenizer$3 = tokenize$3; var isDigit$3 = tokenizer$3.isDigit; var cmpChar$4 = tokenizer$3.cmpChar; var TYPE$E = tokenizer$3.TYPE; var DELIM$6 = TYPE$E.Delim; var WHITESPACE$b = TYPE$E.WhiteSpace; var COMMENT$9 = TYPE$E.Comment; var IDENT$i = TYPE$E.Ident; var NUMBER$9 = TYPE$E.Number; var DIMENSION$7 = TYPE$E.Dimension; var PLUSSIGN$8 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$4 = 0x002D; // U+002D HYPHEN-MINUS (-) var N$4 = 0x006E; // U+006E LATIN SMALL LETTER N (n) var DISALLOW_SIGN$1 = true; var ALLOW_SIGN$1 = false; function isDelim$1(token, code) { return token !== null && token.type === DELIM$6 && token.value.charCodeAt(0) === code; } function skipSC(token, offset, getNextToken) { while (token !== null && (token.type === WHITESPACE$b || token.type === COMMENT$9)) { token = getNextToken(++offset); } return offset; } function checkInteger$1(token, valueOffset, disallowSign, offset) { if (!token) { return 0; } var code = token.value.charCodeAt(valueOffset); if (code === PLUSSIGN$8 || code === HYPHENMINUS$4) { if (disallowSign) { // Number sign is not allowed return 0; } valueOffset++; } for (; valueOffset < token.value.length; valueOffset++) { if (!isDigit$3(token.value.charCodeAt(valueOffset))) { // Integer is expected return 0; } } return offset + 1; } // ... <signed-integer> // ... ['+' | '-'] <signless-integer> function consumeB$1(token, offset_, getNextToken) { var sign = false; var offset = skipSC(token, offset_, getNextToken); token = getNextToken(offset); if (token === null) { return offset_; } if (token.type !== NUMBER$9) { if (isDelim$1(token, PLUSSIGN$8) || isDelim$1(token, HYPHENMINUS$4)) { sign = true; offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); if (token === null && token.type !== NUMBER$9) { return 0; } } else { return offset_; } } if (!sign) { var code = token.value.charCodeAt(0); if (code !== PLUSSIGN$8 && code !== HYPHENMINUS$4) { // Number sign is expected return 0; } } return checkInteger$1(token, sign ? 0 : 1, sign, offset); } // An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb var genericAnPlusB = function anPlusB(token, getNextToken) { /* eslint-disable brace-style*/ var offset = 0; if (!token) { return 0; } // <integer> if (token.type === NUMBER$9) { return checkInteger$1(token, 0, ALLOW_SIGN$1, offset); // b } // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> // -n- <signless-integer> // <dashndashdigit-ident> else if (token.type === IDENT$i && token.value.charCodeAt(0) === HYPHENMINUS$4) { // expect 1st char is N if (!cmpChar$4(token.value, 1, N$4)) { return 0; } switch (token.value.length) { // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> case 2: return consumeB$1(getNextToken(++offset), offset, getNextToken); // -n- <signless-integer> case 3: if (token.value.charCodeAt(2) !== HYPHENMINUS$4) { return 0; } offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger$1(token, 0, DISALLOW_SIGN$1, offset); // <dashndashdigit-ident> default: if (token.value.charCodeAt(2) !== HYPHENMINUS$4) { return 0; } return checkInteger$1(token, 3, DISALLOW_SIGN$1, offset); } } // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> // '+'? n- <signless-integer> // '+'? <ndashdigit-ident> else if (token.type === IDENT$i || (isDelim$1(token, PLUSSIGN$8) && getNextToken(offset + 1).type === IDENT$i)) { // just ignore a plus if (token.type !== IDENT$i) { token = getNextToken(++offset); } if (token === null || !cmpChar$4(token.value, 0, N$4)) { return 0; } switch (token.value.length) { // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> case 1: return consumeB$1(getNextToken(++offset), offset, getNextToken); // '+'? n- <signless-integer> case 2: if (token.value.charCodeAt(1) !== HYPHENMINUS$4) { return 0; } offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger$1(token, 0, DISALLOW_SIGN$1, offset); // '+'? <ndashdigit-ident> default: if (token.value.charCodeAt(1) !== HYPHENMINUS$4) { return 0; } return checkInteger$1(token, 2, DISALLOW_SIGN$1, offset); } } // <ndashdigit-dimension> // <ndash-dimension> <signless-integer> // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> else if (token.type === DIMENSION$7) { var code = token.value.charCodeAt(0); var sign = code === PLUSSIGN$8 || code === HYPHENMINUS$4 ? 1 : 0; for (var i = sign; i < token.value.length; i++) { if (!isDigit$3(token.value.charCodeAt(i))) { break; } } if (i === sign) { // Integer is expected return 0; } if (!cmpChar$4(token.value, i, N$4)) { return 0; } // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> if (i + 1 === token.value.length) { return consumeB$1(getNextToken(++offset), offset, getNextToken); } else { if (token.value.charCodeAt(i + 1) !== HYPHENMINUS$4) { return 0; } // <ndash-dimension> <signless-integer> if (i + 2 === token.value.length) { offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger$1(token, 0, DISALLOW_SIGN$1, offset); } // <ndashdigit-dimension> else { return checkInteger$1(token, i + 2, DISALLOW_SIGN$1, offset); } } } return 0; }; var isHexDigit$2 = tokenizer$3.isHexDigit; var cmpChar$3 = tokenizer$3.cmpChar; var TYPE$D = tokenizer$3.TYPE; var IDENT$h = TYPE$D.Ident; var DELIM$5 = TYPE$D.Delim; var NUMBER$8 = TYPE$D.Number; var DIMENSION$6 = TYPE$D.Dimension; var PLUSSIGN$7 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$3 = 0x002D; // U+002D HYPHEN-MINUS (-) var QUESTIONMARK$2 = 0x003F; // U+003F QUESTION MARK (?) var U$2 = 0x0075; // U+0075 LATIN SMALL LETTER U (u) function isDelim(token, code) { return token !== null && token.type === DELIM$5 && token.value.charCodeAt(0) === code; } function startsWith$1(token, code) { return token.value.charCodeAt(0) === code; } function hexSequence(token, offset, allowDash) { for (var pos = offset, hexlen = 0; pos < token.value.length; pos++) { var code = token.value.charCodeAt(pos); if (code === HYPHENMINUS$3 && allowDash && hexlen !== 0) { if (hexSequence(token, offset + hexlen + 1, false) > 0) { return 6; // dissallow following question marks } return 0; // dash at the ending of a hex sequence is not allowed } if (!isHexDigit$2(code)) { return 0; // not a hex digit } if (++hexlen > 6) { return 0; // too many hex digits } } return hexlen; } function withQuestionMarkSequence(consumed, length, getNextToken) { if (!consumed) { return 0; // nothing consumed } while (isDelim(getNextToken(length), QUESTIONMARK$2)) { if (++consumed > 6) { return 0; // too many question marks } length++; } return length; } // https://drafts.csswg.org/css-syntax/#urange // Informally, the <urange> production has three forms: // U+0001 // Defines a range consisting of a single code point, in this case the code point "1". // U+0001-00ff // Defines a range of codepoints between the first and the second value, in this case // the range between "1" and "ff" (255 in decimal) inclusive. // U+00?? // Defines a range of codepoints where the "?" characters range over all hex digits, // in this case defining the same as the value U+0000-00ff. // In each form, a maximum of 6 digits is allowed for each hexadecimal number (if you treat "?" as a hexadecimal digit). // // <urange> = // u '+' <ident-token> '?'* | // u <dimension-token> '?'* | // u <number-token> '?'* | // u <number-token> <dimension-token> | // u <number-token> <number-token> | // u '+' '?'+ var genericUrange = function urange(token, getNextToken) { var length = 0; // should start with `u` or `U` if (token === null || token.type !== IDENT$h || !cmpChar$3(token.value, 0, U$2)) { return 0; } token = getNextToken(++length); if (token === null) { return 0; } // u '+' <ident-token> '?'* // u '+' '?'+ if (isDelim(token, PLUSSIGN$7)) { token = getNextToken(++length); if (token === null) { return 0; } if (token.type === IDENT$h) { // u '+' <ident-token> '?'* return withQuestionMarkSequence(hexSequence(token, 0, true), ++length, getNextToken); } if (isDelim(token, QUESTIONMARK$2)) { // u '+' '?'+ return withQuestionMarkSequence(1, ++length, getNextToken); } // Hex digit or question mark is expected return 0; } // u <number-token> '?'* // u <number-token> <dimension-token> // u <number-token> <number-token> if (token.type === NUMBER$8) { if (!startsWith$1(token, PLUSSIGN$7)) { return 0; } var consumedHexLength = hexSequence(token, 1, true); if (consumedHexLength === 0) { return 0; } token = getNextToken(++length); if (token === null) { // u <number-token> <eof> return length; } if (token.type === DIMENSION$6 || token.type === NUMBER$8) { // u <number-token> <dimension-token> // u <number-token> <number-token> if (!startsWith$1(token, HYPHENMINUS$3) || !hexSequence(token, 1, false)) { return 0; } return length + 1; } // u <number-token> '?'* return withQuestionMarkSequence(consumedHexLength, length, getNextToken); } // u <dimension-token> '?'* if (token.type === DIMENSION$6) { if (!startsWith$1(token, PLUSSIGN$7)) { return 0; } return withQuestionMarkSequence(hexSequence(token, 1, true), ++length, getNextToken); } return 0; }; var tokenizer$2 = tokenizer$3; var isIdentifierStart = tokenizer$2.isIdentifierStart; var isHexDigit$1 = tokenizer$2.isHexDigit; var isDigit$2 = tokenizer$2.isDigit; var cmpStr$3 = tokenizer$2.cmpStr; var consumeNumber$3 = tokenizer$2.consumeNumber; var TYPE$C = tokenizer$2.TYPE; var anPlusB = genericAnPlusB; var urange = genericUrange; var cssWideKeywords$1 = ['unset', 'initial', 'inherit']; var calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc(']; // https://www.w3.org/TR/css-values-3/#lengths var LENGTH = { // absolute length units 'px': true, 'mm': true, 'cm': true, 'in': true, 'pt': true, 'pc': true, 'q': true, // relative length units 'em': true, 'ex': true, 'ch': true, 'rem': true, // viewport-percentage lengths 'vh': true, 'vw': true, 'vmin': true, 'vmax': true, 'vm': true }; var ANGLE = { 'deg': true, 'grad': true, 'rad': true, 'turn': true }; var TIME = { 's': true, 'ms': true }; var FREQUENCY = { 'hz': true, 'khz': true }; // https://www.w3.org/TR/css-values-3/#resolution (https://drafts.csswg.org/css-values/#resolution) var RESOLUTION = { 'dpi': true, 'dpcm': true, 'dppx': true, 'x': true // https://github.com/w3c/csswg-drafts/issues/461 }; // https://drafts.csswg.org/css-grid/#fr-unit var FLEX = { 'fr': true }; // https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume var DECIBEL = { 'db': true }; // https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch var SEMITONES = { 'st': true }; // safe char code getter function charCode(str, index) { return index < str.length ? str.charCodeAt(index) : 0; } function eqStr(actual, expected) { return cmpStr$3(actual, 0, actual.length, expected); } function eqStrAny(actual, expected) { for (var i = 0; i < expected.length; i++) { if (eqStr(actual, expected[i])) { return true; } } return false; } // IE postfix hack, i.e. 123\0 or 123px\9 function isPostfixIeHack(str, offset) { if (offset !== str.length - 2) { return false; } return ( str.charCodeAt(offset) === 0x005C && // U+005C REVERSE SOLIDUS (\) isDigit$2(str.charCodeAt(offset + 1)) ); } function outOfRange(opts, value, numEnd) { if (opts && opts.type === 'Range') { var num = Number( numEnd !== undefined && numEnd !== value.length ? value.substr(0, numEnd) : value ); if (isNaN(num)) { return true; } if (opts.min !== null && num < opts.min) { return true; } if (opts.max !== null && num > opts.max) { return true; } } return false; } function consumeFunction(token, getNextToken) { var startIdx = token.index; var length = 0; // balanced token consuming do { length++; if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // TODO: implement // can be used wherever <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> values are allowed // https://drafts.csswg.org/css-values/#calc-notation function calc(next) { return function(token, getNextToken, opts) { if (token === null) { return 0; } if (token.type === TYPE$C.Function && eqStrAny(token.value, calcFunctionNames)) { return consumeFunction(token, getNextToken); } return next(token, getNextToken, opts); }; } function tokenType(expectedTokenType) { return function(token) { if (token === null || token.type !== expectedTokenType) { return 0; } return 1; }; } function func(name) { name = name + '('; return function(token, getNextToken) { if (token !== null && eqStr(token.value, name)) { return consumeFunction(token, getNextToken); } return 0; }; } // ========================= // Complex types // // https://drafts.csswg.org/css-values-4/#custom-idents // 4.2. Author-defined Identifiers: the <custom-ident> type // Some properties accept arbitrary author-defined identifiers as a component value. // This generic data type is denoted by <custom-ident>, and represents any valid CSS identifier // that would not be misinterpreted as a pre-defined keyword in that property’s value definition. // // See also: https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident function customIdent(token) { if (token === null || token.type !== TYPE$C.Ident) { return 0; } var name = token.value.toLowerCase(); // The CSS-wide keywords are not valid <custom-ident>s if (eqStrAny(name, cssWideKeywords$1)) { return 0; } // The default keyword is reserved and is also not a valid <custom-ident> if (eqStr(name, 'default')) { return 0; } // TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident) // Specifications using <custom-ident> must specify clearly what other keywords // are excluded from <custom-ident>, if any—for example by saying that any pre-defined keywords // in that property’s value definition are excluded. Excluded keywords are excluded // in all ASCII case permutations. return 1; } // https://drafts.csswg.org/css-variables/#typedef-custom-property-name // A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo. // The <custom-property-name> production corresponds to this: it’s defined as any valid identifier // that starts with two dashes, except -- itself, which is reserved for future use by CSS. // NOTE: Current implementation treat `--` as a valid name since most (all?) major browsers treat it as valid. function customPropertyName(token) { // ... defined as any valid identifier if (token === null || token.type !== TYPE$C.Ident) { return 0; } // ... that starts with two dashes (U+002D HYPHEN-MINUS) if (charCode(token.value, 0) !== 0x002D || charCode(token.value, 1) !== 0x002D) { return 0; } return 1; } // https://drafts.csswg.org/css-color-4/#hex-notation // The syntax of a <hex-color> is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits. // In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or // letters a-f (the case of the letters doesn’t matter - #00ff00 is identical to #00FF00). function hexColor(token) { if (token === null || token.type !== TYPE$C.Hash) { return 0; } var length = token.value.length; // valid values (length): #rgb (4), #rgba (5), #rrggbb (7), #rrggbbaa (9) if (length !== 4 && length !== 5 && length !== 7 && length !== 9) { return 0; } for (var i = 1; i < length; i++) { if (!isHexDigit$1(token.value.charCodeAt(i))) { return 0; } } return 1; } function idSelector(token) { if (token === null || token.type !== TYPE$C.Hash) { return 0; } if (!isIdentifierStart(charCode(token.value, 1), charCode(token.value, 2), charCode(token.value, 3))) { return 0; } return 1; } // https://drafts.csswg.org/css-syntax/#any-value // It represents the entirety of what a valid declaration can have as its value. function declarationValue(token, getNextToken) { if (!token) { return 0; } var length = 0; var level = 0; var startIdx = token.index; // The <declaration-value> production matches any sequence of one or more tokens, // so long as the sequence ... scan: do { switch (token.type) { // ... does not contain <bad-string-token>, <bad-url-token>, case TYPE$C.BadString: case TYPE$C.BadUrl: break scan; // ... unmatched <)-token>, <]-token>, or <}-token>, case TYPE$C.RightCurlyBracket: case TYPE$C.RightParenthesis: case TYPE$C.RightSquareBracket: if (token.balance > token.index || token.balance < startIdx) { break scan; } level--; break; // ... or top-level <semicolon-token> tokens case TYPE$C.Semicolon: if (level === 0) { break scan; } break; // ... or <delim-token> tokens with a value of "!" case TYPE$C.Delim: if (token.value === '!' && level === 0) { break scan; } break; case TYPE$C.Function: case TYPE$C.LeftParenthesis: case TYPE$C.LeftSquareBracket: case TYPE$C.LeftCurlyBracket: level++; break; } length++; // until balance closing if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // https://drafts.csswg.org/css-syntax/#any-value // The <any-value> production is identical to <declaration-value>, but also // allows top-level <semicolon-token> tokens and <delim-token> tokens // with a value of "!". It represents the entirety of what valid CSS can be in any context. function anyValue(token, getNextToken) { if (!token) { return 0; } var startIdx = token.index; var length = 0; // The <any-value> production matches any sequence of one or more tokens, // so long as the sequence ... scan: do { switch (token.type) { // ... does not contain <bad-string-token>, <bad-url-token>, case TYPE$C.BadString: case TYPE$C.BadUrl: break scan; // ... unmatched <)-token>, <]-token>, or <}-token>, case TYPE$C.RightCurlyBracket: case TYPE$C.RightParenthesis: case TYPE$C.RightSquareBracket: if (token.balance > token.index || token.balance < startIdx) { break scan; } break; } length++; // until balance closing if (token.balance <= startIdx) { break; } } while (token = getNextToken(length)); return length; } // ========================= // Dimensions // function dimension(type) { return function(token, getNextToken, opts) { if (token === null || token.type !== TYPE$C.Dimension) { return 0; } var numberEnd = consumeNumber$3(token.value, 0); // check unit if (type !== null) { // check for IE postfix hack, i.e. 123px\0 or 123px\9 var reverseSolidusOffset = token.value.indexOf('\\', numberEnd); var unit = reverseSolidusOffset === -1 || !isPostfixIeHack(token.value, reverseSolidusOffset) ? token.value.substr(numberEnd) : token.value.substring(numberEnd, reverseSolidusOffset); if (type.hasOwnProperty(unit.toLowerCase()) === false) { return 0; } } // check range if specified if (outOfRange(opts, token.value, numberEnd)) { return 0; } return 1; }; } // ========================= // Percentage // // §5.5. Percentages: the <percentage> type // https://drafts.csswg.org/css-values-4/#percentages function percentage(token, getNextToken, opts) { // ... corresponds to the <percentage-token> production if (token === null || token.type !== TYPE$C.Percentage) { return 0; } // check range if specified if (outOfRange(opts, token.value, token.value.length - 1)) { return 0; } return 1; } // ========================= // Numeric // // https://drafts.csswg.org/css-values-4/#numbers // The value <zero> represents a literal number with the value 0. Expressions that merely // evaluate to a <number> with the value 0 (for example, calc(0)) do not match <zero>; // only literal <number-token>s do. function zero(next) { if (typeof next !== 'function') { next = function() { return 0; }; } return function(token, getNextToken, opts) { if (token !== null && token.type === TYPE$C.Number) { if (Number(token.value) === 0) { return 1; } } return next(token, getNextToken, opts); }; } // § 5.3. Real Numbers: the <number> type // https://drafts.csswg.org/css-values-4/#numbers // Number values are denoted by <number>, and represent real numbers, possibly with a fractional component. // ... It corresponds to the <number-token> production function number(token, getNextToken, opts) { if (token === null) { return 0; } var numberEnd = consumeNumber$3(token.value, 0); var isNumber = numberEnd === token.value.length; if (!isNumber && !isPostfixIeHack(token.value, numberEnd)) { return 0; } // check range if specified if (outOfRange(opts, token.value, numberEnd)) { return 0; } return 1; } // §5.2. Integers: the <integer> type // https://drafts.csswg.org/css-values-4/#integers function integer(token, getNextToken, opts) { // ... corresponds to a subset of the <number-token> production if (token === null || token.type !== TYPE$C.Number) { return 0; } // The first digit of an integer may be immediately preceded by `-` or `+` to indicate the integer’s sign. var i = token.value.charCodeAt(0) === 0x002B || // U+002B PLUS SIGN (+) token.value.charCodeAt(0) === 0x002D ? 1 : 0; // U+002D HYPHEN-MINUS (-) // When written literally, an integer is one or more decimal digits 0 through 9 ... for (; i < token.value.length; i++) { if (!isDigit$2(token.value.charCodeAt(i))) { return 0; } } // check range if specified if (outOfRange(opts, token.value, i)) { return 0; } return 1; } var generic$1 = { // token types 'ident-token': tokenType(TYPE$C.Ident), 'function-token': tokenType(TYPE$C.Function), 'at-keyword-token': tokenType(TYPE$C.AtKeyword), 'hash-token': tokenType(TYPE$C.Hash), 'string-token': tokenType(TYPE$C.String), 'bad-string-token': tokenType(TYPE$C.BadString), 'url-token': tokenType(TYPE$C.Url), 'bad-url-token': tokenType(TYPE$C.BadUrl), 'delim-token': tokenType(TYPE$C.Delim), 'number-token': tokenType(TYPE$C.Number), 'percentage-token': tokenType(TYPE$C.Percentage), 'dimension-token': tokenType(TYPE$C.Dimension), 'whitespace-token': tokenType(TYPE$C.WhiteSpace), 'CDO-token': tokenType(TYPE$C.CDO), 'CDC-token': tokenType(TYPE$C.CDC), 'colon-token': tokenType(TYPE$C.Colon), 'semicolon-token': tokenType(TYPE$C.Semicolon), 'comma-token': tokenType(TYPE$C.Comma), '[-token': tokenType(TYPE$C.LeftSquareBracket), ']-token': tokenType(TYPE$C.RightSquareBracket), '(-token': tokenType(TYPE$C.LeftParenthesis), ')-token': tokenType(TYPE$C.RightParenthesis), '{-token': tokenType(TYPE$C.LeftCurlyBracket), '}-token': tokenType(TYPE$C.RightCurlyBracket), // token type aliases 'string': tokenType(TYPE$C.String), 'ident': tokenType(TYPE$C.Ident), // complex types 'custom-ident': customIdent, 'custom-property-name': customPropertyName, 'hex-color': hexColor, 'id-selector': idSelector, // element( <id-selector> ) 'an-plus-b': anPlusB, 'urange': urange, 'declaration-value': declarationValue, 'any-value': anyValue, // dimensions 'dimension': calc(dimension(null)), 'angle': calc(dimension(ANGLE)), 'decibel': calc(dimension(DECIBEL)), 'frequency': calc(dimension(FREQUENCY)), 'flex': calc(dimension(FLEX)), 'length': calc(zero(dimension(LENGTH))), 'resolution': calc(dimension(RESOLUTION)), 'semitones': calc(dimension(SEMITONES)), 'time': calc(dimension(TIME)), // percentage 'percentage': calc(percentage), // numeric 'zero': zero(), 'number': calc(number), 'integer': calc(integer), // old IE stuff '-ms-legacy-expression': func('expression') }; var createCustomError = createCustomError$3; var _SyntaxError = function SyntaxError(message, input, offset) { var error = createCustomError('SyntaxError', message); error.input = input; error.offset = offset; error.rawMessage = message; error.message = error.rawMessage + '\n' + ' ' + error.input + '\n' + '--' + new Array((error.offset || error.input.length) + 1).join('-') + '^'; return error; }; var SyntaxError$3 = _SyntaxError; var TAB$1 = 9; var N$3 = 10; var F$2 = 12; var R$2 = 13; var SPACE$2 = 32; var Tokenizer$1 = function(str) { this.str = str; this.pos = 0; }; Tokenizer$1.prototype = { charCodeAt: function(pos) { return pos < this.str.length ? this.str.charCodeAt(pos) : 0; }, charCode: function() { return this.charCodeAt(this.pos); }, nextCharCode: function() { return this.charCodeAt(this.pos + 1); }, nextNonWsCode: function(pos) { return this.charCodeAt(this.findWsEnd(pos)); }, findWsEnd: function(pos) { for (; pos < this.str.length; pos++) { var code = this.str.charCodeAt(pos); if (code !== R$2 && code !== N$3 && code !== F$2 && code !== SPACE$2 && code !== TAB$1) { break; } } return pos; }, substringToPos: function(end) { return this.str.substring(this.pos, this.pos = end); }, eat: function(code) { if (this.charCode() !== code) { this.error('Expect `' + String.fromCharCode(code) + '`'); } this.pos++; }, peek: function() { return this.pos < this.str.length ? this.str.charAt(this.pos++) : ''; }, error: function(message) { throw new SyntaxError$3(message, this.str, this.pos); } }; var tokenizer$1 = Tokenizer$1; var Tokenizer = tokenizer$1; var TAB = 9; var N$2 = 10; var F$1 = 12; var R$1 = 13; var SPACE$1 = 32; var EXCLAMATIONMARK$3 = 33; // ! var NUMBERSIGN$4 = 35; // # var AMPERSAND$1 = 38; // & var APOSTROPHE = 39; // ' var LEFTPARENTHESIS$7 = 40; // ( var RIGHTPARENTHESIS$7 = 41; // ) var ASTERISK$6 = 42; // * var PLUSSIGN$6 = 43; // + var COMMA$4 = 44; // , var HYPERMINUS = 45; // - var LESSTHANSIGN = 60; // < var GREATERTHANSIGN$2 = 62; // > var QUESTIONMARK$1 = 63; // ? var COMMERCIALAT = 64; // @ var LEFTSQUAREBRACKET$4 = 91; // [ var RIGHTSQUAREBRACKET$2 = 93; // ] var LEFTCURLYBRACKET$4 = 123; // { var VERTICALLINE$3 = 124; // | var RIGHTCURLYBRACKET$2 = 125; // } var INFINITY = 8734; // ∞ var NAME_CHAR = createCharMap(function(ch) { return /[a-zA-Z0-9\-]/.test(ch); }); var COMBINATOR_PRECEDENCE = { ' ': 1, '&&': 2, '||': 3, '|': 4 }; function createCharMap(fn) { var array = typeof Uint32Array === 'function' ? new Uint32Array(128) : new Array(128); for (var i = 0; i < 128; i++) { array[i] = fn(String.fromCharCode(i)) ? 1 : 0; } return array; } function scanSpaces(tokenizer) { return tokenizer.substringToPos( tokenizer.findWsEnd(tokenizer.pos) ); } function scanWord(tokenizer) { var end = tokenizer.pos; for (; end < tokenizer.str.length; end++) { var code = tokenizer.str.charCodeAt(end); if (code >= 128 || NAME_CHAR[code] === 0) { break; } } if (tokenizer.pos === end) { tokenizer.error('Expect a keyword'); } return tokenizer.substringToPos(end); } function scanNumber(tokenizer) { var end = tokenizer.pos; for (; end < tokenizer.str.length; end++) { var code = tokenizer.str.charCodeAt(end); if (code < 48 || code > 57) { break; } } if (tokenizer.pos === end) { tokenizer.error('Expect a number'); } return tokenizer.substringToPos(end); } function scanString(tokenizer) { var end = tokenizer.str.indexOf('\'', tokenizer.pos + 1); if (end === -1) { tokenizer.pos = tokenizer.str.length; tokenizer.error('Expect an apostrophe'); } return tokenizer.substringToPos(end + 1); } function readMultiplierRange(tokenizer) { var min = null; var max = null; tokenizer.eat(LEFTCURLYBRACKET$4); min = scanNumber(tokenizer); if (tokenizer.charCode() === COMMA$4) { tokenizer.pos++; if (tokenizer.charCode() !== RIGHTCURLYBRACKET$2) { max = scanNumber(tokenizer); } } else { max = min; } tokenizer.eat(RIGHTCURLYBRACKET$2); return { min: Number(min), max: max ? Number(max) : 0 }; } function readMultiplier(tokenizer) { var range = null; var comma = false; switch (tokenizer.charCode()) { case ASTERISK$6: tokenizer.pos++; range = { min: 0, max: 0 }; break; case PLUSSIGN$6: tokenizer.pos++; range = { min: 1, max: 0 }; break; case QUESTIONMARK$1: tokenizer.pos++; range = { min: 0, max: 1 }; break; case NUMBERSIGN$4: tokenizer.pos++; comma = true; if (tokenizer.charCode() === LEFTCURLYBRACKET$4) { range = readMultiplierRange(tokenizer); } else { range = { min: 1, max: 0 }; } break; case LEFTCURLYBRACKET$4: range = readMultiplierRange(tokenizer); break; default: return null; } return { type: 'Multiplier', comma: comma, min: range.min, max: range.max, term: null }; } function maybeMultiplied(tokenizer, node) { var multiplier = readMultiplier(tokenizer); if (multiplier !== null) { multiplier.term = node; return multiplier; } return node; } function maybeToken(tokenizer) { var ch = tokenizer.peek(); if (ch === '') { return null; } return { type: 'Token', value: ch }; } function readProperty$1(tokenizer) { var name; tokenizer.eat(LESSTHANSIGN); tokenizer.eat(APOSTROPHE); name = scanWord(tokenizer); tokenizer.eat(APOSTROPHE); tokenizer.eat(GREATERTHANSIGN$2); return maybeMultiplied(tokenizer, { type: 'Property', name: name }); } // https://drafts.csswg.org/css-values-3/#numeric-ranges // 4.1. Range Restrictions and Range Definition Notation // // Range restrictions can be annotated in the numeric type notation using CSS bracketed // range notation—[min,max]—within the angle brackets, after the identifying keyword, // indicating a closed range between (and including) min and max. // For example, <integer [0, 10]> indicates an integer between 0 and 10, inclusive. function readTypeRange(tokenizer) { // use null for Infinity to make AST format JSON serializable/deserializable var min = null; // -Infinity var max = null; // Infinity var sign = 1; tokenizer.eat(LEFTSQUAREBRACKET$4); if (tokenizer.charCode() === HYPERMINUS) { tokenizer.peek(); sign = -1; } if (sign == -1 && tokenizer.charCode() === INFINITY) { tokenizer.peek(); } else { min = sign * Number(scanNumber(tokenizer)); } scanSpaces(tokenizer); tokenizer.eat(COMMA$4); scanSpaces(tokenizer); if (tokenizer.charCode() === INFINITY) { tokenizer.peek(); } else { sign = 1; if (tokenizer.charCode() === HYPERMINUS) { tokenizer.peek(); sign = -1; } max = sign * Number(scanNumber(tokenizer)); } tokenizer.eat(RIGHTSQUAREBRACKET$2); // If no range is indicated, either by using the bracketed range notation // or in the property description, then [−∞,∞] is assumed. if (min === null && max === null) { return null; } return { type: 'Range', min: min, max: max }; } function readType(tokenizer) { var name; var opts = null; tokenizer.eat(LESSTHANSIGN); name = scanWord(tokenizer); if (tokenizer.charCode() === LEFTPARENTHESIS$7 && tokenizer.nextCharCode() === RIGHTPARENTHESIS$7) { tokenizer.pos += 2; name += '()'; } if (tokenizer.charCodeAt(tokenizer.findWsEnd(tokenizer.pos)) === LEFTSQUAREBRACKET$4) { scanSpaces(tokenizer); opts = readTypeRange(tokenizer); } tokenizer.eat(GREATERTHANSIGN$2); return maybeMultiplied(tokenizer, { type: 'Type', name: name, opts: opts }); } function readKeywordOrFunction(tokenizer) { var name; name = scanWord(tokenizer); if (tokenizer.charCode() === LEFTPARENTHESIS$7) { tokenizer.pos++; return { type: 'Function', name: name }; } return maybeMultiplied(tokenizer, { type: 'Keyword', name: name }); } function regroupTerms(terms, combinators) { function createGroup(terms, combinator) { return { type: 'Group', terms: terms, combinator: combinator, disallowEmpty: false, explicit: false }; } combinators = Object.keys(combinators).sort(function(a, b) { return COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b]; }); while (combinators.length > 0) { var combinator = combinators.shift(); for (var i = 0, subgroupStart = 0; i < terms.length; i++) { var term = terms[i]; if (term.type === 'Combinator') { if (term.value === combinator) { if (subgroupStart === -1) { subgroupStart = i - 1; } terms.splice(i, 1); i--; } else { if (subgroupStart !== -1 && i - subgroupStart > 1) { terms.splice( subgroupStart, i - subgroupStart, createGroup(terms.slice(subgroupStart, i), combinator) ); i = subgroupStart + 1; } subgroupStart = -1; } } } if (subgroupStart !== -1 && combinators.length) { terms.splice( subgroupStart, i - subgroupStart, createGroup(terms.slice(subgroupStart, i), combinator) ); } } return combinator; } function readImplicitGroup(tokenizer) { var terms = []; var combinators = {}; var token; var prevToken = null; var prevTokenPos = tokenizer.pos; while (token = peek(tokenizer)) { if (token.type !== 'Spaces') { if (token.type === 'Combinator') { // check for combinator in group beginning and double combinator sequence if (prevToken === null || prevToken.type === 'Combinator') { tokenizer.pos = prevTokenPos; tokenizer.error('Unexpected combinator'); } combinators[token.value] = true; } else if (prevToken !== null && prevToken.type !== 'Combinator') { combinators[' '] = true; // a b terms.push({ type: 'Combinator', value: ' ' }); } terms.push(token); prevToken = token; prevTokenPos = tokenizer.pos; } } // check for combinator in group ending if (prevToken !== null && prevToken.type === 'Combinator') { tokenizer.pos -= prevTokenPos; tokenizer.error('Unexpected combinator'); } return { type: 'Group', terms: terms, combinator: regroupTerms(terms, combinators) || ' ', disallowEmpty: false, explicit: false }; } function readGroup(tokenizer) { var result; tokenizer.eat(LEFTSQUAREBRACKET$4); result = readImplicitGroup(tokenizer); tokenizer.eat(RIGHTSQUAREBRACKET$2); result.explicit = true; if (tokenizer.charCode() === EXCLAMATIONMARK$3) { tokenizer.pos++; result.disallowEmpty = true; } return result; } function peek(tokenizer) { var code = tokenizer.charCode(); if (code < 128 && NAME_CHAR[code] === 1) { return readKeywordOrFunction(tokenizer); } switch (code) { case RIGHTSQUAREBRACKET$2: // don't eat, stop scan a group break; case LEFTSQUAREBRACKET$4: return maybeMultiplied(tokenizer, readGroup(tokenizer)); case LESSTHANSIGN: return tokenizer.nextCharCode() === APOSTROPHE ? readProperty$1(tokenizer) : readType(tokenizer); case VERTICALLINE$3: return { type: 'Combinator', value: tokenizer.substringToPos( tokenizer.nextCharCode() === VERTICALLINE$3 ? tokenizer.pos + 2 : tokenizer.pos + 1 ) }; case AMPERSAND$1: tokenizer.pos++; tokenizer.eat(AMPERSAND$1); return { type: 'Combinator', value: '&&' }; case COMMA$4: tokenizer.pos++; return { type: 'Comma' }; case APOSTROPHE: return maybeMultiplied(tokenizer, { type: 'String', value: scanString(tokenizer) }); case SPACE$1: case TAB: case N$2: case R$1: case F$1: return { type: 'Spaces', value: scanSpaces(tokenizer) }; case COMMERCIALAT: code = tokenizer.nextCharCode(); if (code < 128 && NAME_CHAR[code] === 1) { tokenizer.pos++; return { type: 'AtKeyword', name: scanWord(tokenizer) }; } return maybeToken(tokenizer); case ASTERISK$6: case PLUSSIGN$6: case QUESTIONMARK$1: case NUMBERSIGN$4: case EXCLAMATIONMARK$3: // prohibited tokens (used as a multiplier start) break; case LEFTCURLYBRACKET$4: // LEFTCURLYBRACKET is allowed since mdn/data uses it w/o quoting // check next char isn't a number, because it's likely a disjoined multiplier code = tokenizer.nextCharCode(); if (code < 48 || code > 57) { return maybeToken(tokenizer); } break; default: return maybeToken(tokenizer); } } function parse$2(source) { var tokenizer = new Tokenizer(source); var result = readImplicitGroup(tokenizer); if (tokenizer.pos !== source.length) { tokenizer.error('Unexpected input'); } // reduce redundant groups with single group term if (result.terms.length === 1 && result.terms[0].type === 'Group') { result = result.terms[0]; } return result; } // warm up parse to elimitate code branches that never execute // fix soft deoptimizations (insufficient type feedback) parse$2('[a&&<b>#|<\'c\'>*||e() f{2} /,(% g#{1,2} h{2,})]!'); var parse_1 = parse$2; var noop$2 = function() {}; function ensureFunction$1(value) { return typeof value === 'function' ? value : noop$2; } var walk$1 = function(node, options, context) { function walk(node) { enter.call(context, node); switch (node.type) { case 'Group': node.terms.forEach(walk); break; case 'Multiplier': walk(node.term); break; case 'Type': case 'Property': case 'Keyword': case 'AtKeyword': case 'Function': case 'String': case 'Token': case 'Comma': break; default: throw new Error('Unknown type: ' + node.type); } leave.call(context, node); } var enter = noop$2; var leave = noop$2; if (typeof options === 'function') { enter = options; } else if (options) { enter = ensureFunction$1(options.enter); leave = ensureFunction$1(options.leave); } if (enter === noop$2 && leave === noop$2) { throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function'); } walk(node); }; var tokenize$2 = tokenizer$3; var TokenStream$2 = TokenStream_1; var tokenStream = new TokenStream$2(); var astToTokens = { decorator: function(handlers) { var curNode = null; var prev = { len: 0, node: null }; var nodes = [prev]; var buffer = ''; return { children: handlers.children, node: function(node) { var tmp = curNode; curNode = node; handlers.node.call(this, node); curNode = tmp; }, chunk: function(chunk) { buffer += chunk; if (prev.node !== curNode) { nodes.push({ len: chunk.length, node: curNode }); } else { prev.len += chunk.length; } }, result: function() { return prepareTokens$1(buffer, nodes); } }; } }; function prepareTokens$1(str, nodes) { var tokens = []; var nodesOffset = 0; var nodesIndex = 0; var currentNode = nodes ? nodes[nodesIndex].node : null; tokenize$2(str, tokenStream); while (!tokenStream.eof) { if (nodes) { while (nodesIndex < nodes.length && nodesOffset + nodes[nodesIndex].len <= tokenStream.tokenStart) { nodesOffset += nodes[nodesIndex++].len; currentNode = nodes[nodesIndex].node; } } tokens.push({ type: tokenStream.tokenType, value: tokenStream.getTokenValue(), index: tokenStream.tokenIndex, // TODO: remove it, temporary solution balance: tokenStream.balance[tokenStream.tokenIndex], // TODO: remove it, temporary solution node: currentNode }); tokenStream.next(); // console.log({ ...tokens[tokens.length - 1], node: undefined }); } return tokens; } var prepareTokens_1 = function(value, syntax) { if (typeof value === 'string') { return prepareTokens$1(value, null); } return syntax.generate(value, astToTokens); }; var parse$1 = parse_1; var MATCH$1 = { type: 'Match' }; var MISMATCH$1 = { type: 'Mismatch' }; var DISALLOW_EMPTY$1 = { type: 'DisallowEmpty' }; var LEFTPARENTHESIS$6 = 40; // ( var RIGHTPARENTHESIS$6 = 41; // ) function createCondition(match, thenBranch, elseBranch) { // reduce node count if (thenBranch === MATCH$1 && elseBranch === MISMATCH$1) { return match; } if (match === MATCH$1 && thenBranch === MATCH$1 && elseBranch === MATCH$1) { return match; } if (match.type === 'If' && match.else === MISMATCH$1 && thenBranch === MATCH$1) { thenBranch = match.then; match = match.match; } return { type: 'If', match: match, then: thenBranch, else: elseBranch }; } function isFunctionType(name) { return ( name.length > 2 && name.charCodeAt(name.length - 2) === LEFTPARENTHESIS$6 && name.charCodeAt(name.length - 1) === RIGHTPARENTHESIS$6 ); } function isEnumCapatible(term) { return ( term.type === 'Keyword' || term.type === 'AtKeyword' || term.type === 'Function' || term.type === 'Type' && isFunctionType(term.name) ); } function buildGroupMatchGraph(combinator, terms, atLeastOneTermMatched) { switch (combinator) { case ' ': // Juxtaposing components means that all of them must occur, in the given order. // // a b c // = // match a // then match b // then match c // then MATCH // else MISMATCH // else MISMATCH // else MISMATCH var result = MATCH$1; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; result = createCondition( term, result, MISMATCH$1 ); } return result; case '|': // A bar (|) separates two or more alternatives: exactly one of them must occur. // // a | b | c // = // match a // then MATCH // else match b // then MATCH // else match c // then MATCH // else MISMATCH var result = MISMATCH$1; var map = null; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; // reduce sequence of keywords into a Enum if (isEnumCapatible(term)) { if (map === null && i > 0 && isEnumCapatible(terms[i - 1])) { map = Object.create(null); result = createCondition( { type: 'Enum', map: map }, MATCH$1, result ); } if (map !== null) { var key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase(); if (key in map === false) { map[key] = term; continue; } } } map = null; // create a new conditonal node result = createCondition( term, MATCH$1, result ); } return result; case '&&': // A double ampersand (&&) separates two or more components, // all of which must occur, in any order. // Use MatchOnce for groups with a large number of terms, // since &&-groups produces at least N!-node trees if (terms.length > 5) { return { type: 'MatchOnce', terms: terms, all: true }; } // Use a combination tree for groups with small number of terms // // a && b && c // = // match a // then [b && c] // else match b // then [a && c] // else match c // then [a && b] // else MISMATCH // // a && b // = // match a // then match b // then MATCH // else MISMATCH // else match b // then match a // then MATCH // else MISMATCH // else MISMATCH var result = MISMATCH$1; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; var thenClause; if (terms.length > 1) { thenClause = buildGroupMatchGraph( combinator, terms.filter(function(newGroupTerm) { return newGroupTerm !== term; }), false ); } else { thenClause = MATCH$1; } result = createCondition( term, thenClause, result ); } return result; case '||': // A double bar (||) separates two or more options: // one or more of them must occur, in any order. // Use MatchOnce for groups with a large number of terms, // since ||-groups produces at least N!-node trees if (terms.length > 5) { return { type: 'MatchOnce', terms: terms, all: false }; } // Use a combination tree for groups with small number of terms // // a || b || c // = // match a // then [b || c] // else match b // then [a || c] // else match c // then [a || b] // else MISMATCH // // a || b // = // match a // then match b // then MATCH // else MATCH // else match b // then match a // then MATCH // else MATCH // else MISMATCH var result = atLeastOneTermMatched ? MATCH$1 : MISMATCH$1; for (var i = terms.length - 1; i >= 0; i--) { var term = terms[i]; var thenClause; if (terms.length > 1) { thenClause = buildGroupMatchGraph( combinator, terms.filter(function(newGroupTerm) { return newGroupTerm !== term; }), true ); } else { thenClause = MATCH$1; } result = createCondition( term, thenClause, result ); } return result; } } function buildMultiplierMatchGraph(node) { var result = MATCH$1; var matchTerm = buildMatchGraph$1(node.term); if (node.max === 0) { // disable repeating of empty match to prevent infinite loop matchTerm = createCondition( matchTerm, DISALLOW_EMPTY$1, MISMATCH$1 ); // an occurrence count is not limited, make a cycle; // to collect more terms on each following matching mismatch result = createCondition( matchTerm, null, // will be a loop MISMATCH$1 ); result.then = createCondition( MATCH$1, MATCH$1, result // make a loop ); if (node.comma) { result.then.else = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH$1 ); } } else { // create a match node chain for [min .. max] interval with optional matches for (var i = node.min || 1; i <= node.max; i++) { if (node.comma && result !== MATCH$1) { result = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH$1 ); } result = createCondition( matchTerm, createCondition( MATCH$1, MATCH$1, result ), MISMATCH$1 ); } } if (node.min === 0) { // allow zero match result = createCondition( MATCH$1, MATCH$1, result ); } else { // create a match node chain to collect [0 ... min - 1] required matches for (var i = 0; i < node.min - 1; i++) { if (node.comma && result !== MATCH$1) { result = createCondition( { type: 'Comma', syntax: node }, result, MISMATCH$1 ); } result = createCondition( matchTerm, result, MISMATCH$1 ); } } return result; } function buildMatchGraph$1(node) { if (typeof node === 'function') { return { type: 'Generic', fn: node }; } switch (node.type) { case 'Group': var result = buildGroupMatchGraph( node.combinator, node.terms.map(buildMatchGraph$1), false ); if (node.disallowEmpty) { result = createCondition( result, DISALLOW_EMPTY$1, MISMATCH$1 ); } return result; case 'Multiplier': return buildMultiplierMatchGraph(node); case 'Type': case 'Property': return { type: node.type, name: node.name, syntax: node }; case 'Keyword': return { type: node.type, name: node.name.toLowerCase(), syntax: node }; case 'AtKeyword': return { type: node.type, name: '@' + node.name.toLowerCase(), syntax: node }; case 'Function': return { type: node.type, name: node.name.toLowerCase() + '(', syntax: node }; case 'String': // convert a one char length String to a Token if (node.value.length === 3) { return { type: 'Token', value: node.value.charAt(1), syntax: node }; } // otherwise use it as is return { type: node.type, value: node.value.substr(1, node.value.length - 2).replace(/\\'/g, '\''), syntax: node }; case 'Token': return { type: node.type, value: node.value, syntax: node }; case 'Comma': return { type: node.type, syntax: node }; default: throw new Error('Unknown node type:', node.type); } } var matchGraph$1 = { MATCH: MATCH$1, MISMATCH: MISMATCH$1, DISALLOW_EMPTY: DISALLOW_EMPTY$1, buildMatchGraph: function(syntaxTree, ref) { if (typeof syntaxTree === 'string') { syntaxTree = parse$1(syntaxTree); } return { type: 'MatchGraph', match: buildMatchGraph$1(syntaxTree), syntax: ref || null, source: syntaxTree }; } }; var hasOwnProperty$6 = Object.prototype.hasOwnProperty; var matchGraph = matchGraph$1; var MATCH = matchGraph.MATCH; var MISMATCH = matchGraph.MISMATCH; var DISALLOW_EMPTY = matchGraph.DISALLOW_EMPTY; var TYPE$B = _const.TYPE; var STUB = 0; var TOKEN = 1; var OPEN_SYNTAX = 2; var CLOSE_SYNTAX = 3; var EXIT_REASON_MATCH = 'Match'; var EXIT_REASON_MISMATCH = 'Mismatch'; var EXIT_REASON_ITERATION_LIMIT = 'Maximum iteration number exceeded (please fill an issue on https://github.com/csstree/csstree/issues)'; var ITERATION_LIMIT = 15000; var totalIterationCount = 0; function reverseList(list) { var prev = null; var next = null; var item = list; while (item !== null) { next = item.prev; item.prev = prev; prev = item; item = next; } return prev; } function areStringsEqualCaseInsensitive(testStr, referenceStr) { if (testStr.length !== referenceStr.length) { return false; } for (var i = 0; i < testStr.length; i++) { var testCode = testStr.charCodeAt(i); var referenceCode = referenceStr.charCodeAt(i); // testCode.toLowerCase() for U+0041 LATIN CAPITAL LETTER A (A) .. U+005A LATIN CAPITAL LETTER Z (Z). if (testCode >= 0x0041 && testCode <= 0x005A) { testCode = testCode | 32; } if (testCode !== referenceCode) { return false; } } return true; } function isContextEdgeDelim(token) { if (token.type !== TYPE$B.Delim) { return false; } // Fix matching for unicode-range: U+30??, U+FF00-FF9F // Probably we need to check out previous match instead return token.value !== '?'; } function isCommaContextStart(token) { if (token === null) { return true; } return ( token.type === TYPE$B.Comma || token.type === TYPE$B.Function || token.type === TYPE$B.LeftParenthesis || token.type === TYPE$B.LeftSquareBracket || token.type === TYPE$B.LeftCurlyBracket || isContextEdgeDelim(token) ); } function isCommaContextEnd(token) { if (token === null) { return true; } return ( token.type === TYPE$B.RightParenthesis || token.type === TYPE$B.RightSquareBracket || token.type === TYPE$B.RightCurlyBracket || token.type === TYPE$B.Delim ); } function internalMatch(tokens, state, syntaxes) { function moveToNextToken() { do { tokenIndex++; token = tokenIndex < tokens.length ? tokens[tokenIndex] : null; } while (token !== null && (token.type === TYPE$B.WhiteSpace || token.type === TYPE$B.Comment)); } function getNextToken(offset) { var nextIndex = tokenIndex + offset; return nextIndex < tokens.length ? tokens[nextIndex] : null; } function stateSnapshotFromSyntax(nextState, prev) { return { nextState: nextState, matchStack: matchStack, syntaxStack: syntaxStack, thenStack: thenStack, tokenIndex: tokenIndex, prev: prev }; } function pushThenStack(nextState) { thenStack = { nextState: nextState, matchStack: matchStack, syntaxStack: syntaxStack, prev: thenStack }; } function pushElseStack(nextState) { elseStack = stateSnapshotFromSyntax(nextState, elseStack); } function addTokenToMatch() { matchStack = { type: TOKEN, syntax: state.syntax, token: token, prev: matchStack }; moveToNextToken(); syntaxStash = null; if (tokenIndex > longestMatch) { longestMatch = tokenIndex; } } function openSyntax() { syntaxStack = { syntax: state.syntax, opts: state.syntax.opts || (syntaxStack !== null && syntaxStack.opts) || null, prev: syntaxStack }; matchStack = { type: OPEN_SYNTAX, syntax: state.syntax, token: matchStack.token, prev: matchStack }; } function closeSyntax() { if (matchStack.type === OPEN_SYNTAX) { matchStack = matchStack.prev; } else { matchStack = { type: CLOSE_SYNTAX, syntax: syntaxStack.syntax, token: matchStack.token, prev: matchStack }; } syntaxStack = syntaxStack.prev; } var syntaxStack = null; var thenStack = null; var elseStack = null; // null – stashing allowed, nothing stashed // false – stashing disabled, nothing stashed // anithing else – fail stashable syntaxes, some syntax stashed var syntaxStash = null; var iterationCount = 0; // count iterations and prevent infinite loop var exitReason = null; var token = null; var tokenIndex = -1; var longestMatch = 0; var matchStack = { type: STUB, syntax: null, token: null, prev: null }; moveToNextToken(); while (exitReason === null && ++iterationCount < ITERATION_LIMIT) { // function mapList(list, fn) { // var result = []; // while (list) { // result.unshift(fn(list)); // list = list.prev; // } // return result; // } // console.log('--\n', // '#' + iterationCount, // require('util').inspect({ // match: mapList(matchStack, x => x.type === TOKEN ? x.token && x.token.value : x.syntax ? ({ [OPEN_SYNTAX]: '<', [CLOSE_SYNTAX]: '</' }[x.type] || x.type) + '!' + x.syntax.name : null), // token: token && token.value, // tokenIndex, // syntax: syntax.type + (syntax.id ? ' #' + syntax.id : '') // }, { depth: null }) // ); switch (state.type) { case 'Match': if (thenStack === null) { // turn to MISMATCH when some tokens left unmatched if (token !== null) { // doesn't mismatch if just one token left and it's an IE hack if (tokenIndex !== tokens.length - 1 || (token.value !== '\\0' && token.value !== '\\9')) { state = MISMATCH; break; } } // break the main loop, return a result - MATCH exitReason = EXIT_REASON_MATCH; break; } // go to next syntax (`then` branch) state = thenStack.nextState; // check match is not empty if (state === DISALLOW_EMPTY) { if (thenStack.matchStack === matchStack) { state = MISMATCH; break; } else { state = MATCH; } } // close syntax if needed while (thenStack.syntaxStack !== syntaxStack) { closeSyntax(); } // pop stack thenStack = thenStack.prev; break; case 'Mismatch': // when some syntax is stashed if (syntaxStash !== null && syntaxStash !== false) { // there is no else branches or a branch reduce match stack if (elseStack === null || tokenIndex > elseStack.tokenIndex) { // restore state from the stash elseStack = syntaxStash; syntaxStash = false; // disable stashing } } else if (elseStack === null) { // no else branches -> break the main loop // return a result - MISMATCH exitReason = EXIT_REASON_MISMATCH; break; } // go to next syntax (`else` branch) state = elseStack.nextState; // restore all the rest stack states thenStack = elseStack.thenStack; syntaxStack = elseStack.syntaxStack; matchStack = elseStack.matchStack; tokenIndex = elseStack.tokenIndex; token = tokenIndex < tokens.length ? tokens[tokenIndex] : null; // pop stack elseStack = elseStack.prev; break; case 'MatchGraph': state = state.match; break; case 'If': // IMPORTANT: else stack push must go first, // since it stores the state of thenStack before changes if (state.else !== MISMATCH) { pushElseStack(state.else); } if (state.then !== MATCH) { pushThenStack(state.then); } state = state.match; break; case 'MatchOnce': state = { type: 'MatchOnceBuffer', syntax: state, index: 0, mask: 0 }; break; case 'MatchOnceBuffer': var terms = state.syntax.terms; if (state.index === terms.length) { // no matches at all or it's required all terms to be matched if (state.mask === 0 || state.syntax.all) { state = MISMATCH; break; } // a partial match is ok state = MATCH; break; } // all terms are matched if (state.mask === (1 << terms.length) - 1) { state = MATCH; break; } for (; state.index < terms.length; state.index++) { var matchFlag = 1 << state.index; if ((state.mask & matchFlag) === 0) { // IMPORTANT: else stack push must go first, // since it stores the state of thenStack before changes pushElseStack(state); pushThenStack({ type: 'AddMatchOnce', syntax: state.syntax, mask: state.mask | matchFlag }); // match state = terms[state.index++]; break; } } break; case 'AddMatchOnce': state = { type: 'MatchOnceBuffer', syntax: state.syntax, index: 0, mask: state.mask }; break; case 'Enum': if (token !== null) { var name = token.value.toLowerCase(); // drop \0 and \9 hack from keyword name if (name.indexOf('\\') !== -1) { name = name.replace(/\\[09].*$/, ''); } if (hasOwnProperty$6.call(state.map, name)) { state = state.map[name]; break; } } state = MISMATCH; break; case 'Generic': var opts = syntaxStack !== null ? syntaxStack.opts : null; var lastTokenIndex = tokenIndex + Math.floor(state.fn(token, getNextToken, opts)); if (!isNaN(lastTokenIndex) && lastTokenIndex > tokenIndex) { while (tokenIndex < lastTokenIndex) { addTokenToMatch(); } state = MATCH; } else { state = MISMATCH; } break; case 'Type': case 'Property': var syntaxDict = state.type === 'Type' ? 'types' : 'properties'; var dictSyntax = hasOwnProperty$6.call(syntaxes, syntaxDict) ? syntaxes[syntaxDict][state.name] : null; if (!dictSyntax || !dictSyntax.match) { throw new Error( 'Bad syntax reference: ' + (state.type === 'Type' ? '<' + state.name + '>' : '<\'' + state.name + '\'>') ); } // stash a syntax for types with low priority if (syntaxStash !== false && token !== null && state.type === 'Type') { var lowPriorityMatching = // https://drafts.csswg.org/css-values-4/#custom-idents // When parsing positionally-ambiguous keywords in a property value, a <custom-ident> production // can only claim the keyword if no other unfulfilled production can claim it. (state.name === 'custom-ident' && token.type === TYPE$B.Ident) || // https://drafts.csswg.org/css-values-4/#lengths // ... if a `0` could be parsed as either a <number> or a <length> in a property (such as line-height), // it must parse as a <number> (state.name === 'length' && token.value === '0'); if (lowPriorityMatching) { if (syntaxStash === null) { syntaxStash = stateSnapshotFromSyntax(state, elseStack); } state = MISMATCH; break; } } openSyntax(); state = dictSyntax.match; break; case 'Keyword': var name = state.name; if (token !== null) { var keywordName = token.value; // drop \0 and \9 hack from keyword name if (keywordName.indexOf('\\') !== -1) { keywordName = keywordName.replace(/\\[09].*$/, ''); } if (areStringsEqualCaseInsensitive(keywordName, name)) { addTokenToMatch(); state = MATCH; break; } } state = MISMATCH; break; case 'AtKeyword': case 'Function': if (token !== null && areStringsEqualCaseInsensitive(token.value, state.name)) { addTokenToMatch(); state = MATCH; break; } state = MISMATCH; break; case 'Token': if (token !== null && token.value === state.value) { addTokenToMatch(); state = MATCH; break; } state = MISMATCH; break; case 'Comma': if (token !== null && token.type === TYPE$B.Comma) { if (isCommaContextStart(matchStack.token)) { state = MISMATCH; } else { addTokenToMatch(); state = isCommaContextEnd(token) ? MISMATCH : MATCH; } } else { state = isCommaContextStart(matchStack.token) || isCommaContextEnd(token) ? MATCH : MISMATCH; } break; case 'String': var string = ''; for (var lastTokenIndex = tokenIndex; lastTokenIndex < tokens.length && string.length < state.value.length; lastTokenIndex++) { string += tokens[lastTokenIndex].value; } if (areStringsEqualCaseInsensitive(string, state.value)) { while (tokenIndex < lastTokenIndex) { addTokenToMatch(); } state = MATCH; } else { state = MISMATCH; } break; default: throw new Error('Unknown node type: ' + state.type); } } totalIterationCount += iterationCount; switch (exitReason) { case null: console.warn('[csstree-match] BREAK after ' + ITERATION_LIMIT + ' iterations'); exitReason = EXIT_REASON_ITERATION_LIMIT; matchStack = null; break; case EXIT_REASON_MATCH: while (syntaxStack !== null) { closeSyntax(); } break; default: matchStack = null; } return { tokens: tokens, reason: exitReason, iterations: iterationCount, match: matchStack, longestMatch: longestMatch }; } function matchAsList(tokens, matchGraph, syntaxes) { var matchResult = internalMatch(tokens, matchGraph, syntaxes || {}); if (matchResult.match !== null) { var item = reverseList(matchResult.match).prev; matchResult.match = []; while (item !== null) { switch (item.type) { case STUB: break; case OPEN_SYNTAX: case CLOSE_SYNTAX: matchResult.match.push({ type: item.type, syntax: item.syntax }); break; default: matchResult.match.push({ token: item.token.value, node: item.token.node }); break; } item = item.prev; } } return matchResult; } function matchAsTree$1(tokens, matchGraph, syntaxes) { var matchResult = internalMatch(tokens, matchGraph, syntaxes || {}); if (matchResult.match === null) { return matchResult; } var item = matchResult.match; var host = matchResult.match = { syntax: matchGraph.syntax || null, match: [] }; var hostStack = [host]; // revert a list and start with 2nd item since 1st is a stub item item = reverseList(item).prev; // build a tree while (item !== null) { switch (item.type) { case OPEN_SYNTAX: host.match.push(host = { syntax: item.syntax, match: [] }); hostStack.push(host); break; case CLOSE_SYNTAX: hostStack.pop(); host = hostStack[hostStack.length - 1]; break; default: host.match.push({ syntax: item.syntax || null, token: item.token.value, node: item.token.node }); } item = item.prev; } return matchResult; } var match = { matchAsList: matchAsList, matchAsTree: matchAsTree$1, getTotalIterationCount: function() { return totalIterationCount; } }; function getTrace(node) { function shouldPutToTrace(syntax) { if (syntax === null) { return false; } return ( syntax.type === 'Type' || syntax.type === 'Property' || syntax.type === 'Keyword' ); } function hasMatch(matchNode) { if (Array.isArray(matchNode.match)) { // use for-loop for better perfomance for (var i = 0; i < matchNode.match.length; i++) { if (hasMatch(matchNode.match[i])) { if (shouldPutToTrace(matchNode.syntax)) { result.unshift(matchNode.syntax); } return true; } } } else if (matchNode.node === node) { result = shouldPutToTrace(matchNode.syntax) ? [matchNode.syntax] : []; return true; } return false; } var result = null; if (this.matched !== null) { hasMatch(this.matched); } return result; } function testNode(match, node, fn) { var trace = getTrace.call(match, node); if (trace === null) { return false; } return trace.some(fn); } function isType(node, type) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Type' && matchNode.name === type; }); } function isProperty(node, property) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Property' && matchNode.name === property; }); } function isKeyword(node) { return testNode(this, node, function(matchNode) { return matchNode.type === 'Keyword'; }); } var trace$1 = { getTrace: getTrace, isType: isType, isProperty: isProperty, isKeyword: isKeyword }; var List$5 = List_1; function getFirstMatchNode(matchNode) { if ('node' in matchNode) { return matchNode.node; } return getFirstMatchNode(matchNode.match[0]); } function getLastMatchNode(matchNode) { if ('node' in matchNode) { return matchNode.node; } return getLastMatchNode(matchNode.match[matchNode.match.length - 1]); } function matchFragments(lexer, ast, match, type, name) { function findFragments(matchNode) { if (matchNode.syntax !== null && matchNode.syntax.type === type && matchNode.syntax.name === name) { var start = getFirstMatchNode(matchNode); var end = getLastMatchNode(matchNode); lexer.syntax.walk(ast, function(node, item, list) { if (node === start) { var nodes = new List$5(); do { nodes.appendData(item.data); if (item.data === end) { break; } item = item.next; } while (item !== null); fragments.push({ parent: list, nodes: nodes }); } }); } if (Array.isArray(matchNode.match)) { matchNode.match.forEach(findFragments); } } var fragments = []; if (match.matched !== null) { findFragments(match.matched); } return fragments; } var search$1 = { matchFragments: matchFragments }; var List$4 = List_1; var hasOwnProperty$5 = Object.prototype.hasOwnProperty; function isValidNumber(value) { // Number.isInteger(value) && value >= 0 return ( typeof value === 'number' && isFinite(value) && Math.floor(value) === value && value >= 0 ); } function isValidLocation(loc) { return ( Boolean(loc) && isValidNumber(loc.offset) && isValidNumber(loc.line) && isValidNumber(loc.column) ); } function createNodeStructureChecker(type, fields) { return function checkNode(node, warn) { if (!node || node.constructor !== Object) { return warn(node, 'Type of node should be an Object'); } for (var key in node) { var valid = true; if (hasOwnProperty$5.call(node, key) === false) { continue; } if (key === 'type') { if (node.type !== type) { warn(node, 'Wrong node type `' + node.type + '`, expected `' + type + '`'); } } else if (key === 'loc') { if (node.loc === null) { continue; } else if (node.loc && node.loc.constructor === Object) { if (typeof node.loc.source !== 'string') { key += '.source'; } else if (!isValidLocation(node.loc.start)) { key += '.start'; } else if (!isValidLocation(node.loc.end)) { key += '.end'; } else { continue; } } valid = false; } else if (fields.hasOwnProperty(key)) { for (var i = 0, valid = false; !valid && i < fields[key].length; i++) { var fieldType = fields[key][i]; switch (fieldType) { case String: valid = typeof node[key] === 'string'; break; case Boolean: valid = typeof node[key] === 'boolean'; break; case null: valid = node[key] === null; break; default: if (typeof fieldType === 'string') { valid = node[key] && node[key].type === fieldType; } else if (Array.isArray(fieldType)) { valid = node[key] instanceof List$4; } } } } else { warn(node, 'Unknown field `' + key + '` for ' + type + ' node type'); } if (!valid) { warn(node, 'Bad value for `' + type + '.' + key + '`'); } } for (var key in fields) { if (hasOwnProperty$5.call(fields, key) && hasOwnProperty$5.call(node, key) === false) { warn(node, 'Field `' + type + '.' + key + '` is missed'); } } }; } function processStructure(name, nodeType) { var structure = nodeType.structure; var fields = { type: String, loc: true }; var docs = { type: '"' + name + '"' }; for (var key in structure) { if (hasOwnProperty$5.call(structure, key) === false) { continue; } var docsTypes = []; var fieldTypes = fields[key] = Array.isArray(structure[key]) ? structure[key].slice() : [structure[key]]; for (var i = 0; i < fieldTypes.length; i++) { var fieldType = fieldTypes[i]; if (fieldType === String || fieldType === Boolean) { docsTypes.push(fieldType.name); } else if (fieldType === null) { docsTypes.push('null'); } else if (typeof fieldType === 'string') { docsTypes.push('<' + fieldType + '>'); } else if (Array.isArray(fieldType)) { docsTypes.push('List'); // TODO: use type enum } else { throw new Error('Wrong value `' + fieldType + '` in `' + name + '.' + key + '` structure definition'); } } docs[key] = docsTypes.join(' | '); } return { docs: docs, check: createNodeStructureChecker(name, fields) }; } var structure = { getStructureFromConfig: function(config) { var structure = {}; if (config.node) { for (var name in config.node) { if (hasOwnProperty$5.call(config.node, name)) { var nodeType = config.node[name]; if (nodeType.structure) { structure[name] = processStructure(name, nodeType); } else { throw new Error('Missed `structure` field in `' + name + '` node type definition'); } } } } return structure; } }; var SyntaxReferenceError = error.SyntaxReferenceError; var SyntaxMatchError = error.SyntaxMatchError; var names$1 = names$2; var generic = generic$1; var parse = parse_1; var generate = generate_1; var walk = walk$1; var prepareTokens = prepareTokens_1; var buildMatchGraph = matchGraph$1.buildMatchGraph; var matchAsTree = match.matchAsTree; var trace = trace$1; var search = search$1; var getStructureFromConfig = structure.getStructureFromConfig; var cssWideKeywords = buildMatchGraph('inherit | initial | unset'); var cssWideKeywordsWithExpression = buildMatchGraph('inherit | initial | unset | <-ms-legacy-expression>'); function dumpMapSyntax(map, compact, syntaxAsAst) { var result = {}; for (var name in map) { if (map[name].syntax) { result[name] = syntaxAsAst ? map[name].syntax : generate(map[name].syntax, { compact: compact }); } } return result; } function dumpAtruleMapSyntax(map, compact, syntaxAsAst) { const result = {}; for (const [name, atrule] of Object.entries(map)) { result[name] = { prelude: atrule.prelude && ( syntaxAsAst ? atrule.prelude.syntax : generate(atrule.prelude.syntax, { compact }) ), descriptors: atrule.descriptors && dumpMapSyntax(atrule.descriptors, compact, syntaxAsAst) }; } return result; } function valueHasVar(tokens) { for (var i = 0; i < tokens.length; i++) { if (tokens[i].value.toLowerCase() === 'var(') { return true; } } return false; } function buildMatchResult(match, error, iterations) { return { matched: match, iterations: iterations, error: error, getTrace: trace.getTrace, isType: trace.isType, isProperty: trace.isProperty, isKeyword: trace.isKeyword }; } function matchSyntax(lexer, syntax, value, useCommon) { var tokens = prepareTokens(value, lexer.syntax); var result; if (valueHasVar(tokens)) { return buildMatchResult(null, new Error('Matching for a tree with var() is not supported')); } if (useCommon) { result = matchAsTree(tokens, lexer.valueCommonSyntax, lexer); } if (!useCommon || !result.match) { result = matchAsTree(tokens, syntax.match, lexer); if (!result.match) { return buildMatchResult( null, new SyntaxMatchError(result.reason, syntax.syntax, value, result), result.iterations ); } } return buildMatchResult(result.match, null, result.iterations); } var Lexer$1 = function(config, syntax, structure) { this.valueCommonSyntax = cssWideKeywords; this.syntax = syntax; this.generic = false; this.atrules = {}; this.properties = {}; this.types = {}; this.structure = structure || getStructureFromConfig(config); if (config) { if (config.types) { for (var name in config.types) { this.addType_(name, config.types[name]); } } if (config.generic) { this.generic = true; for (var name in generic) { this.addType_(name, generic[name]); } } if (config.atrules) { for (var name in config.atrules) { this.addAtrule_(name, config.atrules[name]); } } if (config.properties) { for (var name in config.properties) { this.addProperty_(name, config.properties[name]); } } } }; Lexer$1.prototype = { structure: {}, checkStructure: function(ast) { function collectWarning(node, message) { warns.push({ node: node, message: message }); } var structure = this.structure; var warns = []; this.syntax.walk(ast, function(node) { if (structure.hasOwnProperty(node.type)) { structure[node.type].check(node, collectWarning); } else { collectWarning(node, 'Unknown node type `' + node.type + '`'); } }); return warns.length ? warns : false; }, createDescriptor: function(syntax, type, name, parent = null) { var ref = { type: type, name: name }; var descriptor = { type: type, name: name, parent: parent, syntax: null, match: null }; if (typeof syntax === 'function') { descriptor.match = buildMatchGraph(syntax, ref); } else { if (typeof syntax === 'string') { // lazy parsing on first access Object.defineProperty(descriptor, 'syntax', { get: function() { Object.defineProperty(descriptor, 'syntax', { value: parse(syntax) }); return descriptor.syntax; } }); } else { descriptor.syntax = syntax; } // lazy graph build on first access Object.defineProperty(descriptor, 'match', { get: function() { Object.defineProperty(descriptor, 'match', { value: buildMatchGraph(descriptor.syntax, ref) }); return descriptor.match; } }); } return descriptor; }, addAtrule_: function(name, syntax) { if (!syntax) { return; } this.atrules[name] = { type: 'Atrule', name: name, prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null, descriptors: syntax.descriptors ? Object.keys(syntax.descriptors).reduce((res, descName) => { res[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name); return res; }, {}) : null }; }, addProperty_: function(name, syntax) { if (!syntax) { return; } this.properties[name] = this.createDescriptor(syntax, 'Property', name); }, addType_: function(name, syntax) { if (!syntax) { return; } this.types[name] = this.createDescriptor(syntax, 'Type', name); if (syntax === generic['-ms-legacy-expression']) { this.valueCommonSyntax = cssWideKeywordsWithExpression; } }, checkAtruleName: function(atruleName) { if (!this.getAtrule(atruleName)) { return new SyntaxReferenceError('Unknown at-rule', '@' + atruleName); } }, checkAtrulePrelude: function(atruleName, prelude) { let error = this.checkAtruleName(atruleName); if (error) { return error; } var atrule = this.getAtrule(atruleName); if (!atrule.prelude && prelude) { return new SyntaxError('At-rule `@' + atruleName + '` should not contain a prelude'); } if (atrule.prelude && !prelude) { return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude'); } }, checkAtruleDescriptorName: function(atruleName, descriptorName) { let error = this.checkAtruleName(atruleName); if (error) { return error; } var atrule = this.getAtrule(atruleName); var descriptor = names$1.keyword(descriptorName); if (!atrule.descriptors) { return new SyntaxError('At-rule `@' + atruleName + '` has no known descriptors'); } if (!atrule.descriptors[descriptor.name] && !atrule.descriptors[descriptor.basename]) { return new SyntaxReferenceError('Unknown at-rule descriptor', descriptorName); } }, checkPropertyName: function(propertyName) { var property = names$1.property(propertyName); // don't match syntax for a custom property if (property.custom) { return new Error('Lexer matching doesn\'t applicable for custom properties'); } if (!this.getProperty(propertyName)) { return new SyntaxReferenceError('Unknown property', propertyName); } }, matchAtrulePrelude: function(atruleName, prelude) { var error = this.checkAtrulePrelude(atruleName, prelude); if (error) { return buildMatchResult(null, error); } if (!prelude) { return buildMatchResult(null, null); } return matchSyntax(this, this.getAtrule(atruleName).prelude, prelude, false); }, matchAtruleDescriptor: function(atruleName, descriptorName, value) { var error = this.checkAtruleDescriptorName(atruleName, descriptorName); if (error) { return buildMatchResult(null, error); } var atrule = this.getAtrule(atruleName); var descriptor = names$1.keyword(descriptorName); return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false); }, matchDeclaration: function(node) { if (node.type !== 'Declaration') { return buildMatchResult(null, new Error('Not a Declaration node')); } return this.matchProperty(node.property, node.value); }, matchProperty: function(propertyName, value) { var error = this.checkPropertyName(propertyName); if (error) { return buildMatchResult(null, error); } return matchSyntax(this, this.getProperty(propertyName), value, true); }, matchType: function(typeName, value) { var typeSyntax = this.getType(typeName); if (!typeSyntax) { return buildMatchResult(null, new SyntaxReferenceError('Unknown type', typeName)); } return matchSyntax(this, typeSyntax, value, false); }, match: function(syntax, value) { if (typeof syntax !== 'string' && (!syntax || !syntax.type)) { return buildMatchResult(null, new SyntaxReferenceError('Bad syntax')); } if (typeof syntax === 'string' || !syntax.match) { syntax = this.createDescriptor(syntax, 'Type', 'anonymous'); } return matchSyntax(this, syntax, value, false); }, findValueFragments: function(propertyName, value, type, name) { return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name); }, findDeclarationValueFragments: function(declaration, type, name) { return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name); }, findAllFragments: function(ast, type, name) { var result = []; this.syntax.walk(ast, { visit: 'Declaration', enter: function(declaration) { result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name)); }.bind(this) }); return result; }, getAtrule: function(atruleName, fallbackBasename = true) { var atrule = names$1.keyword(atruleName); var atruleEntry = atrule.vendor && fallbackBasename ? this.atrules[atrule.name] || this.atrules[atrule.basename] : this.atrules[atrule.name]; return atruleEntry || null; }, getAtrulePrelude: function(atruleName, fallbackBasename = true) { const atrule = this.getAtrule(atruleName, fallbackBasename); return atrule && atrule.prelude || null; }, getAtruleDescriptor: function(atruleName, name) { return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators ? this.atrules[atruleName].declarators[name] || null : null; }, getProperty: function(propertyName, fallbackBasename = true) { var property = names$1.property(propertyName); var propertyEntry = property.vendor && fallbackBasename ? this.properties[property.name] || this.properties[property.basename] : this.properties[property.name]; return propertyEntry || null; }, getType: function(name) { return this.types.hasOwnProperty(name) ? this.types[name] : null; }, validate: function() { function validate(syntax, name, broken, descriptor) { if (broken.hasOwnProperty(name)) { return broken[name]; } broken[name] = false; if (descriptor.syntax !== null) { walk(descriptor.syntax, function(node) { if (node.type !== 'Type' && node.type !== 'Property') { return; } var map = node.type === 'Type' ? syntax.types : syntax.properties; var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties; if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) { broken[name] = true; } }, this); } } var brokenTypes = {}; var brokenProperties = {}; for (var key in this.types) { validate(this, key, brokenTypes, this.types[key]); } for (var key in this.properties) { validate(this, key, brokenProperties, this.properties[key]); } brokenTypes = Object.keys(brokenTypes).filter(function(name) { return brokenTypes[name]; }); brokenProperties = Object.keys(brokenProperties).filter(function(name) { return brokenProperties[name]; }); if (brokenTypes.length || brokenProperties.length) { return { types: brokenTypes, properties: brokenProperties }; } return null; }, dump: function(syntaxAsAst, pretty) { return { generic: this.generic, types: dumpMapSyntax(this.types, !pretty, syntaxAsAst), properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst), atrules: dumpAtruleMapSyntax(this.atrules, !pretty, syntaxAsAst) }; }, toString: function() { return JSON.stringify(this.dump()); } }; var Lexer_1 = Lexer$1; var definitionSyntax$1 = { SyntaxError: _SyntaxError, parse: parse_1, generate: generate_1, walk: walk$1 }; var adoptBuffer = adoptBuffer$2; var isBOM = tokenizer$3.isBOM; var N$1 = 10; var F = 12; var R = 13; function computeLinesAndColumns(host, source) { var sourceLength = source.length; var lines = adoptBuffer(host.lines, sourceLength); // +1 var line = host.startLine; var columns = adoptBuffer(host.columns, sourceLength); var column = host.startColumn; var startOffset = source.length > 0 ? isBOM(source.charCodeAt(0)) : 0; for (var i = startOffset; i < sourceLength; i++) { // -1 var code = source.charCodeAt(i); lines[i] = line; columns[i] = column++; if (code === N$1 || code === R || code === F) { if (code === R && i + 1 < sourceLength && source.charCodeAt(i + 1) === N$1) { i++; lines[i] = line; columns[i] = column; } line++; column = 1; } } lines[i] = line; columns[i] = column; host.lines = lines; host.columns = columns; } var OffsetToLocation$1 = function() { this.lines = null; this.columns = null; this.linesAndColumnsComputed = false; }; OffsetToLocation$1.prototype = { setSource: function(source, startOffset, startLine, startColumn) { this.source = source; this.startOffset = typeof startOffset === 'undefined' ? 0 : startOffset; this.startLine = typeof startLine === 'undefined' ? 1 : startLine; this.startColumn = typeof startColumn === 'undefined' ? 1 : startColumn; this.linesAndColumnsComputed = false; }, ensureLinesAndColumnsComputed: function() { if (!this.linesAndColumnsComputed) { computeLinesAndColumns(this, this.source); this.linesAndColumnsComputed = true; } }, getLocation: function(offset, filename) { this.ensureLinesAndColumnsComputed(); return { source: filename, offset: this.startOffset + offset, line: this.lines[offset], column: this.columns[offset] }; }, getLocationRange: function(start, end, filename) { this.ensureLinesAndColumnsComputed(); return { source: filename, start: { offset: this.startOffset + start, line: this.lines[start], column: this.columns[start] }, end: { offset: this.startOffset + end, line: this.lines[end], column: this.columns[end] } }; } }; var OffsetToLocation_1 = OffsetToLocation$1; var TYPE$A = tokenizer$3.TYPE; var WHITESPACE$a = TYPE$A.WhiteSpace; var COMMENT$8 = TYPE$A.Comment; var sequence$1 = function readSequence(recognizer) { var children = this.createList(); var child = null; var context = { recognizer: recognizer, space: null, ignoreWS: false, ignoreWSAfter: false }; this.scanner.skipSC(); while (!this.scanner.eof) { switch (this.scanner.tokenType) { case COMMENT$8: this.scanner.next(); continue; case WHITESPACE$a: if (context.ignoreWS) { this.scanner.next(); } else { context.space = this.WhiteSpace(); } continue; } child = recognizer.getNode.call(this, context); if (child === undefined) { break; } if (context.space !== null) { children.push(context.space); context.space = null; } children.push(child); if (context.ignoreWSAfter) { context.ignoreWSAfter = false; context.ignoreWS = true; } else { context.ignoreWS = false; } } return children; }; var OffsetToLocation = OffsetToLocation_1; var SyntaxError$2 = _SyntaxError$1; var TokenStream$1 = TokenStream_1; var List$3 = List_1; var tokenize$1 = tokenizer$3; var constants = _const; var { findWhiteSpaceStart, cmpStr: cmpStr$2 } = utils$2; var sequence = sequence$1; var noop$1 = function() {}; var TYPE$z = constants.TYPE; var NAME$1 = constants.NAME; var WHITESPACE$9 = TYPE$z.WhiteSpace; var COMMENT$7 = TYPE$z.Comment; var IDENT$g = TYPE$z.Ident; var FUNCTION$6 = TYPE$z.Function; var URL$4 = TYPE$z.Url; var HASH$5 = TYPE$z.Hash; var PERCENTAGE$3 = TYPE$z.Percentage; var NUMBER$7 = TYPE$z.Number; var NUMBERSIGN$3 = 0x0023; // U+0023 NUMBER SIGN (#) var NULL = 0; function createParseContext(name) { return function() { return this[name](); }; } function processConfig(config) { var parserConfig = { context: {}, scope: {}, atrule: {}, pseudo: {} }; if (config.parseContext) { for (var name in config.parseContext) { switch (typeof config.parseContext[name]) { case 'function': parserConfig.context[name] = config.parseContext[name]; break; case 'string': parserConfig.context[name] = createParseContext(config.parseContext[name]); break; } } } if (config.scope) { for (var name in config.scope) { parserConfig.scope[name] = config.scope[name]; } } if (config.atrule) { for (var name in config.atrule) { var atrule = config.atrule[name]; if (atrule.parse) { parserConfig.atrule[name] = atrule.parse; } } } if (config.pseudo) { for (var name in config.pseudo) { var pseudo = config.pseudo[name]; if (pseudo.parse) { parserConfig.pseudo[name] = pseudo.parse; } } } if (config.node) { for (var name in config.node) { parserConfig[name] = config.node[name].parse; } } return parserConfig; } var create$4 = function createParser(config) { var parser = { scanner: new TokenStream$1(), locationMap: new OffsetToLocation(), filename: '<unknown>', needPositions: false, onParseError: noop$1, onParseErrorThrow: false, parseAtrulePrelude: true, parseRulePrelude: true, parseValue: true, parseCustomProperty: false, readSequence: sequence, createList: function() { return new List$3(); }, createSingleNodeList: function(node) { return new List$3().appendData(node); }, getFirstListNode: function(list) { return list && list.first(); }, getLastListNode: function(list) { return list.last(); }, parseWithFallback: function(consumer, fallback) { var startToken = this.scanner.tokenIndex; try { return consumer.call(this); } catch (e) { if (this.onParseErrorThrow) { throw e; } var fallbackNode = fallback.call(this, startToken); this.onParseErrorThrow = true; this.onParseError(e, fallbackNode); this.onParseErrorThrow = false; return fallbackNode; } }, lookupNonWSType: function(offset) { do { var type = this.scanner.lookupType(offset++); if (type !== WHITESPACE$9) { return type; } } while (type !== NULL); return NULL; }, eat: function(tokenType) { if (this.scanner.tokenType !== tokenType) { var offset = this.scanner.tokenStart; var message = NAME$1[tokenType] + ' is expected'; // tweak message and offset switch (tokenType) { case IDENT$g: // when identifier is expected but there is a function or url if (this.scanner.tokenType === FUNCTION$6 || this.scanner.tokenType === URL$4) { offset = this.scanner.tokenEnd - 1; message = 'Identifier is expected but function found'; } else { message = 'Identifier is expected'; } break; case HASH$5: if (this.scanner.isDelim(NUMBERSIGN$3)) { this.scanner.next(); offset++; message = 'Name is expected'; } break; case PERCENTAGE$3: if (this.scanner.tokenType === NUMBER$7) { offset = this.scanner.tokenEnd; message = 'Percent sign is expected'; } break; default: // when test type is part of another token show error for current position + 1 // e.g. eat(HYPHENMINUS) will fail on "-foo", but pointing on "-" is odd if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === tokenType) { offset = offset + 1; } } this.error(message, offset); } this.scanner.next(); }, consume: function(tokenType) { var value = this.scanner.getTokenValue(); this.eat(tokenType); return value; }, consumeFunctionName: function() { var name = this.scanner.source.substring(this.scanner.tokenStart, this.scanner.tokenEnd - 1); this.eat(FUNCTION$6); return name; }, getLocation: function(start, end) { if (this.needPositions) { return this.locationMap.getLocationRange( start, end, this.filename ); } return null; }, getLocationFromList: function(list) { if (this.needPositions) { var head = this.getFirstListNode(list); var tail = this.getLastListNode(list); return this.locationMap.getLocationRange( head !== null ? head.loc.start.offset - this.locationMap.startOffset : this.scanner.tokenStart, tail !== null ? tail.loc.end.offset - this.locationMap.startOffset : this.scanner.tokenStart, this.filename ); } return null; }, error: function(message, offset) { var location = typeof offset !== 'undefined' && offset < this.scanner.source.length ? this.locationMap.getLocation(offset) : this.scanner.eof ? this.locationMap.getLocation(findWhiteSpaceStart(this.scanner.source, this.scanner.source.length - 1)) : this.locationMap.getLocation(this.scanner.tokenStart); throw new SyntaxError$2( message || 'Unexpected input', this.scanner.source, location.offset, location.line, location.column ); } }; config = processConfig(config || {}); for (var key in config) { parser[key] = config[key]; } return function(source, options) { options = options || {}; var context = options.context || 'default'; var onComment = options.onComment; var ast; tokenize$1(source, parser.scanner); parser.locationMap.setSource( source, options.offset, options.line, options.column ); parser.filename = options.filename || '<unknown>'; parser.needPositions = Boolean(options.positions); parser.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop$1; parser.onParseErrorThrow = false; parser.parseAtrulePrelude = 'parseAtrulePrelude' in options ? Boolean(options.parseAtrulePrelude) : true; parser.parseRulePrelude = 'parseRulePrelude' in options ? Boolean(options.parseRulePrelude) : true; parser.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true; parser.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false; if (!parser.context.hasOwnProperty(context)) { throw new Error('Unknown context `' + context + '`'); } if (typeof onComment === 'function') { parser.scanner.forEachToken((type, start, end) => { if (type === COMMENT$7) { const loc = parser.getLocation(start, end); const value = cmpStr$2(source, end - 2, end, '*/') ? source.slice(start + 2, end - 2) : source.slice(start + 2, end); onComment(value, loc); } }); } ast = parser.context[context].call(parser, options); if (!parser.scanner.eof) { parser.error(); } return ast; }; }; var sourceMapGenerator = {}; var base64Vlq = {}; var base64$1 = {}; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); /** * Encode an integer in the range of 0 to 63 to a single base 64 digit. */ base64$1.encode = function (number) { if (0 <= number && number < intToCharMap.length) { return intToCharMap[number]; } throw new TypeError("Must be between 0 and 63: " + number); }; /** * Decode a single base 64 character code digit to an integer. Returns -1 on * failure. */ base64$1.decode = function (charCode) { var bigA = 65; // 'A' var bigZ = 90; // 'Z' var littleA = 97; // 'a' var littleZ = 122; // 'z' var zero = 48; // '0' var nine = 57; // '9' var plus = 43; // '+' var slash = 47; // '/' var littleOffset = 26; var numberOffset = 52; // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ if (bigA <= charCode && charCode <= bigZ) { return (charCode - bigA); } // 26 - 51: abcdefghijklmnopqrstuvwxyz if (littleA <= charCode && charCode <= littleZ) { return (charCode - littleA + littleOffset); } // 52 - 61: 0123456789 if (zero <= charCode && charCode <= nine) { return (charCode - zero + numberOffset); } // 62: + if (charCode == plus) { return 62; } // 63: / if (charCode == slash) { return 63; } // Invalid base64 digit. return -1; }; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause * * Based on the Base 64 VLQ implementation in Closure Compiler: * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java * * Copyright 2011 The Closure Compiler Authors. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ var base64 = base64$1; // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, // the next four bits are the actual value, and the 6th bit is the // continuation bit. The continuation bit tells us whether there are more // digits in this value following this digit. // // Continuation // | Sign // | | // V V // 101011 var VLQ_BASE_SHIFT = 5; // binary: 100000 var VLQ_BASE = 1 << VLQ_BASE_SHIFT; // binary: 011111 var VLQ_BASE_MASK = VLQ_BASE - 1; // binary: 100000 var VLQ_CONTINUATION_BIT = VLQ_BASE; /** * Converts from a two-complement value to a value where the sign bit is * placed in the least significant bit. For example, as decimals: * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) */ function toVLQSigned(aValue) { return aValue < 0 ? ((-aValue) << 1) + 1 : (aValue << 1) + 0; } /** * Converts to a two-complement value from a value where the sign bit is * placed in the least significant bit. For example, as decimals: * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 */ function fromVLQSigned(aValue) { var isNegative = (aValue & 1) === 1; var shifted = aValue >> 1; return isNegative ? -shifted : shifted; } /** * Returns the base 64 VLQ encoded value. */ base64Vlq.encode = function base64VLQ_encode(aValue) { var encoded = ""; var digit; var vlq = toVLQSigned(aValue); do { digit = vlq & VLQ_BASE_MASK; vlq >>>= VLQ_BASE_SHIFT; if (vlq > 0) { // There are still more digits in this value, so we must make sure the // continuation bit is marked. digit |= VLQ_CONTINUATION_BIT; } encoded += base64.encode(digit); } while (vlq > 0); return encoded; }; /** * Decodes the next base 64 VLQ value from the given string and returns the * value and the rest of the string via the out parameter. */ base64Vlq.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { var strLen = aStr.length; var result = 0; var shift = 0; var continuation, digit; do { if (aIndex >= strLen) { throw new Error("Expected more digits in base 64 VLQ value."); } digit = base64.decode(aStr.charCodeAt(aIndex++)); if (digit === -1) { throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); } continuation = !!(digit & VLQ_CONTINUATION_BIT); digit &= VLQ_BASE_MASK; result = result + (digit << shift); shift += VLQ_BASE_SHIFT; } while (continuation); aOutParam.value = fromVLQSigned(result); aOutParam.rest = aIndex; }; var util$3 = {}; /* -*- Mode: js; js-indent-level: 2; -*- */ (function (exports) { /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ /** * This is a helper function for getting values from parameter/options * objects. * * @param args The object we are extracting values from * @param name The name of the property we are getting. * @param defaultValue An optional value to return if the property is missing * from the object. If this is not specified and the property is missing, an * error will be thrown. */ function getArg(aArgs, aName, aDefaultValue) { if (aName in aArgs) { return aArgs[aName]; } else if (arguments.length === 3) { return aDefaultValue; } else { throw new Error('"' + aName + '" is a required argument.'); } } exports.getArg = getArg; var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.-]*)(?::(\d+))?(.*)$/; var dataUrlRegexp = /^data:.+\,.+$/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); if (!match) { return null; } return { scheme: match[1], auth: match[2], host: match[3], port: match[4], path: match[5] }; } exports.urlParse = urlParse; function urlGenerate(aParsedUrl) { var url = ''; if (aParsedUrl.scheme) { url += aParsedUrl.scheme + ':'; } url += '//'; if (aParsedUrl.auth) { url += aParsedUrl.auth + '@'; } if (aParsedUrl.host) { url += aParsedUrl.host; } if (aParsedUrl.port) { url += ":" + aParsedUrl.port; } if (aParsedUrl.path) { url += aParsedUrl.path; } return url; } exports.urlGenerate = urlGenerate; /** * Normalizes a path, or the path portion of a URL: * * - Replaces consecutive slashes with one slash. * - Removes unnecessary '.' parts. * - Removes unnecessary '<dir>/..' parts. * * Based on code in the Node.js 'path' core module. * * @param aPath The path or url to normalize. */ function normalize(aPath) { var path = aPath; var url = urlParse(aPath); if (url) { if (!url.path) { return aPath; } path = url.path; } var isAbsolute = exports.isAbsolute(path); var parts = path.split(/\/+/); for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { part = parts[i]; if (part === '.') { parts.splice(i, 1); } else if (part === '..') { up++; } else if (up > 0) { if (part === '') { // The first part is blank if the path is absolute. Trying to go // above the root is a no-op. Therefore we can remove all '..' parts // directly after the root. parts.splice(i + 1, up); up = 0; } else { parts.splice(i, 2); up--; } } } path = parts.join('/'); if (path === '') { path = isAbsolute ? '/' : '.'; } if (url) { url.path = path; return urlGenerate(url); } return path; } exports.normalize = normalize; /** * Joins two paths/URLs. * * @param aRoot The root path or URL. * @param aPath The path or URL to be joined with the root. * * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a * scheme-relative URL: Then the scheme of aRoot, if any, is prepended * first. * - Otherwise aPath is a path. If aRoot is a URL, then its path portion * is updated with the result and aRoot is returned. Otherwise the result * is returned. * - If aPath is absolute, the result is aPath. * - Otherwise the two paths are joined with a slash. * - Joining for example 'http://' and 'www.example.com' is also supported. */ function join(aRoot, aPath) { if (aRoot === "") { aRoot = "."; } if (aPath === "") { aPath = "."; } var aPathUrl = urlParse(aPath); var aRootUrl = urlParse(aRoot); if (aRootUrl) { aRoot = aRootUrl.path || '/'; } // `join(foo, '//www.example.org')` if (aPathUrl && !aPathUrl.scheme) { if (aRootUrl) { aPathUrl.scheme = aRootUrl.scheme; } return urlGenerate(aPathUrl); } if (aPathUrl || aPath.match(dataUrlRegexp)) { return aPath; } // `join('http://', 'www.example.com')` if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { aRootUrl.host = aPath; return urlGenerate(aRootUrl); } var joined = aPath.charAt(0) === '/' ? aPath : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); if (aRootUrl) { aRootUrl.path = joined; return urlGenerate(aRootUrl); } return joined; } exports.join = join; exports.isAbsolute = function (aPath) { return aPath.charAt(0) === '/' || urlRegexp.test(aPath); }; /** * Make a path relative to a URL or another path. * * @param aRoot The root path or URL. * @param aPath The path or URL to be made relative to aRoot. */ function relative(aRoot, aPath) { if (aRoot === "") { aRoot = "."; } aRoot = aRoot.replace(/\/$/, ''); // It is possible for the path to be above the root. In this case, simply // checking whether the root is a prefix of the path won't work. Instead, we // need to remove components from the root one by one, until either we find // a prefix that fits, or we run out of components to remove. var level = 0; while (aPath.indexOf(aRoot + '/') !== 0) { var index = aRoot.lastIndexOf("/"); if (index < 0) { return aPath; } // If the only part of the root that is left is the scheme (i.e. http://, // file:///, etc.), one or more slashes (/), or simply nothing at all, we // have exhausted all components, so the path is not relative to the root. aRoot = aRoot.slice(0, index); if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { return aPath; } ++level; } // Make sure we add a "../" for each component we removed from the root. return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); } exports.relative = relative; var supportsNullProto = (function () { var obj = Object.create(null); return !('__proto__' in obj); }()); function identity (s) { return s; } /** * Because behavior goes wacky when you set `__proto__` on objects, we * have to prefix all the strings in our set with an arbitrary character. * * See https://github.com/mozilla/source-map/pull/31 and * https://github.com/mozilla/source-map/issues/30 * * @param String aStr */ function toSetString(aStr) { if (isProtoString(aStr)) { return '$' + aStr; } return aStr; } exports.toSetString = supportsNullProto ? identity : toSetString; function fromSetString(aStr) { if (isProtoString(aStr)) { return aStr.slice(1); } return aStr; } exports.fromSetString = supportsNullProto ? identity : fromSetString; function isProtoString(s) { if (!s) { return false; } var length = s.length; if (length < 9 /* "__proto__".length */) { return false; } if (s.charCodeAt(length - 1) !== 95 /* '_' */ || s.charCodeAt(length - 2) !== 95 /* '_' */ || s.charCodeAt(length - 3) !== 111 /* 'o' */ || s.charCodeAt(length - 4) !== 116 /* 't' */ || s.charCodeAt(length - 5) !== 111 /* 'o' */ || s.charCodeAt(length - 6) !== 114 /* 'r' */ || s.charCodeAt(length - 7) !== 112 /* 'p' */ || s.charCodeAt(length - 8) !== 95 /* '_' */ || s.charCodeAt(length - 9) !== 95 /* '_' */) { return false; } for (var i = length - 10; i >= 0; i--) { if (s.charCodeAt(i) !== 36 /* '$' */) { return false; } } return true; } /** * Comparator between two mappings where the original positions are compared. * * Optionally pass in `true` as `onlyCompareGenerated` to consider two * mappings with the same original source/line/column, but different generated * line and column the same. Useful when searching for a mapping with a * stubbed out mapping. */ function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { var cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0 || onlyCompareOriginal) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByOriginalPositions = compareByOriginalPositions; /** * Comparator between two mappings with deflated source and name indices where * the generated positions are compared. * * Optionally pass in `true` as `onlyCompareGenerated` to consider two * mappings with the same generated line and column, but different * source/name/original line and column the same. Useful when searching for a * mapping with a stubbed out mapping. */ function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { var cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0 || onlyCompareGenerated) { return cmp; } cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; function strcmp(aStr1, aStr2) { if (aStr1 === aStr2) { return 0; } if (aStr1 === null) { return 1; // aStr2 !== null } if (aStr2 === null) { return -1; // aStr1 !== null } if (aStr1 > aStr2) { return 1; } return -1; } /** * Comparator between two mappings with inflated source and name strings where * the generated positions are compared. */ function compareByGeneratedPositionsInflated(mappingA, mappingB) { var cmp = mappingA.generatedLine - mappingB.generatedLine; if (cmp !== 0) { return cmp; } cmp = mappingA.generatedColumn - mappingB.generatedColumn; if (cmp !== 0) { return cmp; } cmp = strcmp(mappingA.source, mappingB.source); if (cmp !== 0) { return cmp; } cmp = mappingA.originalLine - mappingB.originalLine; if (cmp !== 0) { return cmp; } cmp = mappingA.originalColumn - mappingB.originalColumn; if (cmp !== 0) { return cmp; } return strcmp(mappingA.name, mappingB.name); } exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; /** * Strip any JSON XSSI avoidance prefix from the string (as documented * in the source maps specification), and then parse the string as * JSON. */ function parseSourceMapInput(str) { return JSON.parse(str.replace(/^\)]}'[^\n]*\n/, '')); } exports.parseSourceMapInput = parseSourceMapInput; /** * Compute the URL of a source given the the source root, the source's * URL, and the source map's URL. */ function computeSourceURL(sourceRoot, sourceURL, sourceMapURL) { sourceURL = sourceURL || ''; if (sourceRoot) { // This follows what Chrome does. if (sourceRoot[sourceRoot.length - 1] !== '/' && sourceURL[0] !== '/') { sourceRoot += '/'; } // The spec says: // Line 4: An optional source root, useful for relocating source // files on a server or removing repeated values in the // “sources” entry. This value is prepended to the individual // entries in the “source” field. sourceURL = sourceRoot + sourceURL; } // Historically, SourceMapConsumer did not take the sourceMapURL as // a parameter. This mode is still somewhat supported, which is why // this code block is conditional. However, it's preferable to pass // the source map URL to SourceMapConsumer, so that this function // can implement the source URL resolution algorithm as outlined in // the spec. This block is basically the equivalent of: // new URL(sourceURL, sourceMapURL).toString() // ... except it avoids using URL, which wasn't available in the // older releases of node still supported by this library. // // The spec says: // If the sources are not absolute URLs after prepending of the // “sourceRoot”, the sources are resolved relative to the // SourceMap (like resolving script src in a html document). if (sourceMapURL) { var parsed = urlParse(sourceMapURL); if (!parsed) { throw new Error("sourceMapURL could not be parsed"); } if (parsed.path) { // Strip the last path component, but keep the "/". var index = parsed.path.lastIndexOf('/'); if (index >= 0) { parsed.path = parsed.path.substring(0, index + 1); } } sourceURL = join(urlGenerate(parsed), sourceURL); } return normalize(sourceURL); } exports.computeSourceURL = computeSourceURL; }(util$3)); var arraySet = {}; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var util$2 = util$3; var has$1 = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; /** * A data structure which is a combination of an array and a set. Adding a new * member is O(1), testing for membership is O(1), and finding the index of an * element is O(1). Removing elements from the set is not supported. Only * strings are supported for membership. */ function ArraySet$1() { this._array = []; this._set = hasNativeMap ? new Map() : Object.create(null); } /** * Static method for creating ArraySet instances from an existing array. */ ArraySet$1.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { var set = new ArraySet$1(); for (var i = 0, len = aArray.length; i < len; i++) { set.add(aArray[i], aAllowDuplicates); } return set; }; /** * Return how many unique items are in this ArraySet. If duplicates have been * added, than those do not count towards the size. * * @returns Number */ ArraySet$1.prototype.size = function ArraySet_size() { return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; }; /** * Add the given string to this set. * * @param String aStr */ ArraySet$1.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { var sStr = hasNativeMap ? aStr : util$2.toSetString(aStr); var isDuplicate = hasNativeMap ? this.has(aStr) : has$1.call(this._set, sStr); var idx = this._array.length; if (!isDuplicate || aAllowDuplicates) { this._array.push(aStr); } if (!isDuplicate) { if (hasNativeMap) { this._set.set(aStr, idx); } else { this._set[sStr] = idx; } } }; /** * Is the given string a member of this set? * * @param String aStr */ ArraySet$1.prototype.has = function ArraySet_has(aStr) { if (hasNativeMap) { return this._set.has(aStr); } else { var sStr = util$2.toSetString(aStr); return has$1.call(this._set, sStr); } }; /** * What is the index of the given string in the array? * * @param String aStr */ ArraySet$1.prototype.indexOf = function ArraySet_indexOf(aStr) { if (hasNativeMap) { var idx = this._set.get(aStr); if (idx >= 0) { return idx; } } else { var sStr = util$2.toSetString(aStr); if (has$1.call(this._set, sStr)) { return this._set[sStr]; } } throw new Error('"' + aStr + '" is not in the set.'); }; /** * What is the element at the given index? * * @param Number aIdx */ ArraySet$1.prototype.at = function ArraySet_at(aIdx) { if (aIdx >= 0 && aIdx < this._array.length) { return this._array[aIdx]; } throw new Error('No element indexed by ' + aIdx); }; /** * Returns the array representation of this set (which has the proper indices * indicated by indexOf). Note that this is a copy of the internal array used * for storing the members so that no one can mess with internal state. */ ArraySet$1.prototype.toArray = function ArraySet_toArray() { return this._array.slice(); }; arraySet.ArraySet = ArraySet$1; var mappingList = {}; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2014 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var util$1 = util$3; /** * Determine whether mappingB is after mappingA with respect to generated * position. */ function generatedPositionAfter(mappingA, mappingB) { // Optimized for most common case var lineA = mappingA.generatedLine; var lineB = mappingB.generatedLine; var columnA = mappingA.generatedColumn; var columnB = mappingB.generatedColumn; return lineB > lineA || lineB == lineA && columnB >= columnA || util$1.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; } /** * A data structure to provide a sorted view of accumulated mappings in a * performance conscious manner. It trades a neglibable overhead in general * case for a large speedup in case of mappings being added in order. */ function MappingList$1() { this._array = []; this._sorted = true; // Serves as infimum this._last = {generatedLine: -1, generatedColumn: 0}; } /** * Iterate through internal items. This method takes the same arguments that * `Array.prototype.forEach` takes. * * NOTE: The order of the mappings is NOT guaranteed. */ MappingList$1.prototype.unsortedForEach = function MappingList_forEach(aCallback, aThisArg) { this._array.forEach(aCallback, aThisArg); }; /** * Add the given source mapping. * * @param Object aMapping */ MappingList$1.prototype.add = function MappingList_add(aMapping) { if (generatedPositionAfter(this._last, aMapping)) { this._last = aMapping; this._array.push(aMapping); } else { this._sorted = false; this._array.push(aMapping); } }; /** * Returns the flat, sorted array of mappings. The mappings are sorted by * generated position. * * WARNING: This method returns internal data without copying, for * performance. The return value must NOT be mutated, and should be treated as * an immutable borrow. If you want to take ownership, you must make your own * copy. */ MappingList$1.prototype.toArray = function MappingList_toArray() { if (!this._sorted) { this._array.sort(util$1.compareByGeneratedPositionsInflated); this._sorted = true; } return this._array; }; mappingList.MappingList = MappingList$1; /* -*- Mode: js; js-indent-level: 2; -*- */ /* * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause */ var base64VLQ = base64Vlq; var util = util$3; var ArraySet = arraySet.ArraySet; var MappingList = mappingList.MappingList; /** * An instance of the SourceMapGenerator represents a source map which is * being built incrementally. You may pass an object with the following * properties: * * - file: The filename of the generated source. * - sourceRoot: A root for all relative URLs in this source map. */ function SourceMapGenerator$1(aArgs) { if (!aArgs) { aArgs = {}; } this._file = util.getArg(aArgs, 'file', null); this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); this._skipValidation = util.getArg(aArgs, 'skipValidation', false); this._sources = new ArraySet(); this._names = new ArraySet(); this._mappings = new MappingList(); this._sourcesContents = null; } SourceMapGenerator$1.prototype._version = 3; /** * Creates a new SourceMapGenerator based on a SourceMapConsumer * * @param aSourceMapConsumer The SourceMap. */ SourceMapGenerator$1.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { var sourceRoot = aSourceMapConsumer.sourceRoot; var generator = new SourceMapGenerator$1({ file: aSourceMapConsumer.file, sourceRoot: sourceRoot }); aSourceMapConsumer.eachMapping(function (mapping) { var newMapping = { generated: { line: mapping.generatedLine, column: mapping.generatedColumn } }; if (mapping.source != null) { newMapping.source = mapping.source; if (sourceRoot != null) { newMapping.source = util.relative(sourceRoot, newMapping.source); } newMapping.original = { line: mapping.originalLine, column: mapping.originalColumn }; if (mapping.name != null) { newMapping.name = mapping.name; } } generator.addMapping(newMapping); }); aSourceMapConsumer.sources.forEach(function (sourceFile) { var sourceRelative = sourceFile; if (sourceRoot !== null) { sourceRelative = util.relative(sourceRoot, sourceFile); } if (!generator._sources.has(sourceRelative)) { generator._sources.add(sourceRelative); } var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { generator.setSourceContent(sourceFile, content); } }); return generator; }; /** * Add a single mapping from original source line and column to the generated * source's line and column for this source map being created. The mapping * object should have the following properties: * * - generated: An object with the generated line and column positions. * - original: An object with the original line and column positions. * - source: The original source file (relative to the sourceRoot). * - name: An optional original token name for this mapping. */ SourceMapGenerator$1.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { var generated = util.getArg(aArgs, 'generated'); var original = util.getArg(aArgs, 'original', null); var source = util.getArg(aArgs, 'source', null); var name = util.getArg(aArgs, 'name', null); if (!this._skipValidation) { this._validateMapping(generated, original, source, name); } if (source != null) { source = String(source); if (!this._sources.has(source)) { this._sources.add(source); } } if (name != null) { name = String(name); if (!this._names.has(name)) { this._names.add(name); } } this._mappings.add({ generatedLine: generated.line, generatedColumn: generated.column, originalLine: original != null && original.line, originalColumn: original != null && original.column, source: source, name: name }); }; /** * Set the source content for a source file. */ SourceMapGenerator$1.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { var source = aSourceFile; if (this._sourceRoot != null) { source = util.relative(this._sourceRoot, source); } if (aSourceContent != null) { // Add the source content to the _sourcesContents map. // Create a new _sourcesContents map if the property is null. if (!this._sourcesContents) { this._sourcesContents = Object.create(null); } this._sourcesContents[util.toSetString(source)] = aSourceContent; } else if (this._sourcesContents) { // Remove the source file from the _sourcesContents map. // If the _sourcesContents map is empty, set the property to null. delete this._sourcesContents[util.toSetString(source)]; if (Object.keys(this._sourcesContents).length === 0) { this._sourcesContents = null; } } }; /** * Applies the mappings of a sub-source-map for a specific source file to the * source map being generated. Each mapping to the supplied source file is * rewritten using the supplied source map. Note: The resolution for the * resulting mappings is the minimium of this map and the supplied map. * * @param aSourceMapConsumer The source map to be applied. * @param aSourceFile Optional. The filename of the source file. * If omitted, SourceMapConsumer's file property will be used. * @param aSourceMapPath Optional. The dirname of the path to the source map * to be applied. If relative, it is relative to the SourceMapConsumer. * This parameter is needed when the two source maps aren't in the same * directory, and the source map to be applied contains relative source * paths. If so, those relative source paths need to be rewritten * relative to the SourceMapGenerator. */ SourceMapGenerator$1.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { var sourceFile = aSourceFile; // If aSourceFile is omitted, we will use the file property of the SourceMap if (aSourceFile == null) { if (aSourceMapConsumer.file == null) { throw new Error( 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + 'or the source map\'s "file" property. Both were omitted.' ); } sourceFile = aSourceMapConsumer.file; } var sourceRoot = this._sourceRoot; // Make "sourceFile" relative if an absolute Url is passed. if (sourceRoot != null) { sourceFile = util.relative(sourceRoot, sourceFile); } // Applying the SourceMap can add and remove items from the sources and // the names array. var newSources = new ArraySet(); var newNames = new ArraySet(); // Find mappings for the "sourceFile" this._mappings.unsortedForEach(function (mapping) { if (mapping.source === sourceFile && mapping.originalLine != null) { // Check if it can be mapped by the source map, then update the mapping. var original = aSourceMapConsumer.originalPositionFor({ line: mapping.originalLine, column: mapping.originalColumn }); if (original.source != null) { // Copy mapping mapping.source = original.source; if (aSourceMapPath != null) { mapping.source = util.join(aSourceMapPath, mapping.source); } if (sourceRoot != null) { mapping.source = util.relative(sourceRoot, mapping.source); } mapping.originalLine = original.line; mapping.originalColumn = original.column; if (original.name != null) { mapping.name = original.name; } } } var source = mapping.source; if (source != null && !newSources.has(source)) { newSources.add(source); } var name = mapping.name; if (name != null && !newNames.has(name)) { newNames.add(name); } }, this); this._sources = newSources; this._names = newNames; // Copy sourcesContents of applied map. aSourceMapConsumer.sources.forEach(function (sourceFile) { var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content != null) { if (aSourceMapPath != null) { sourceFile = util.join(aSourceMapPath, sourceFile); } if (sourceRoot != null) { sourceFile = util.relative(sourceRoot, sourceFile); } this.setSourceContent(sourceFile, content); } }, this); }; /** * A mapping can have one of the three levels of data: * * 1. Just the generated position. * 2. The Generated position, original position, and original source. * 3. Generated and original position, original source, as well as a name * token. * * To maintain consistency, we validate that any new mapping being added falls * in to one of these categories. */ SourceMapGenerator$1.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { // When aOriginal is truthy but has empty values for .line and .column, // it is most likely a programmer error. In this case we throw a very // specific error message to try to guide them the right way. // For example: https://github.com/Polymer/polymer-bundler/pull/519 if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { throw new Error( 'original.line and original.column are not numbers -- you probably meant to omit ' + 'the original mapping entirely and only map the generated position. If so, pass ' + 'null for the original mapping instead of an object with empty or null values.' ); } if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { // Case 1. return; } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { // Cases 2 and 3. return; } else { throw new Error('Invalid mapping: ' + JSON.stringify({ generated: aGenerated, source: aSource, original: aOriginal, name: aName })); } }; /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. */ SourceMapGenerator$1.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { var previousGeneratedColumn = 0; var previousGeneratedLine = 1; var previousOriginalColumn = 0; var previousOriginalLine = 0; var previousName = 0; var previousSource = 0; var result = ''; var next; var mapping; var nameIdx; var sourceIdx; var mappings = this._mappings.toArray(); for (var i = 0, len = mappings.length; i < len; i++) { mapping = mappings[i]; next = ''; if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; while (mapping.generatedLine !== previousGeneratedLine) { next += ';'; previousGeneratedLine++; } } else { if (i > 0) { if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { continue; } next += ','; } } next += base64VLQ.encode(mapping.generatedColumn - previousGeneratedColumn); previousGeneratedColumn = mapping.generatedColumn; if (mapping.source != null) { sourceIdx = this._sources.indexOf(mapping.source); next += base64VLQ.encode(sourceIdx - previousSource); previousSource = sourceIdx; // lines are stored 0-based in SourceMap spec version 3 next += base64VLQ.encode(mapping.originalLine - 1 - previousOriginalLine); previousOriginalLine = mapping.originalLine - 1; next += base64VLQ.encode(mapping.originalColumn - previousOriginalColumn); previousOriginalColumn = mapping.originalColumn; if (mapping.name != null) { nameIdx = this._names.indexOf(mapping.name); next += base64VLQ.encode(nameIdx - previousName); previousName = nameIdx; } } result += next; } return result; }; SourceMapGenerator$1.prototype._generateSourcesContent = function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { return aSources.map(function (source) { if (!this._sourcesContents) { return null; } if (aSourceRoot != null) { source = util.relative(aSourceRoot, source); } var key = util.toSetString(source); return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) ? this._sourcesContents[key] : null; }, this); }; /** * Externalize the source map. */ SourceMapGenerator$1.prototype.toJSON = function SourceMapGenerator_toJSON() { var map = { version: this._version, sources: this._sources.toArray(), names: this._names.toArray(), mappings: this._serializeMappings() }; if (this._file != null) { map.file = this._file; } if (this._sourceRoot != null) { map.sourceRoot = this._sourceRoot; } if (this._sourcesContents) { map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); } return map; }; /** * Render the source map being generated to a string. */ SourceMapGenerator$1.prototype.toString = function SourceMapGenerator_toString() { return JSON.stringify(this.toJSON()); }; sourceMapGenerator.SourceMapGenerator = SourceMapGenerator$1; var SourceMapGenerator = sourceMapGenerator.SourceMapGenerator; var trackNodes = { Atrule: true, Selector: true, Declaration: true }; var sourceMap$1 = function generateSourceMap(handlers) { var map = new SourceMapGenerator(); var line = 1; var column = 0; var generated = { line: 1, column: 0 }; var original = { line: 0, // should be zero to add first mapping column: 0 }; var sourceMappingActive = false; var activatedGenerated = { line: 1, column: 0 }; var activatedMapping = { generated: activatedGenerated }; var handlersNode = handlers.node; handlers.node = function(node) { if (node.loc && node.loc.start && trackNodes.hasOwnProperty(node.type)) { var nodeLine = node.loc.start.line; var nodeColumn = node.loc.start.column - 1; if (original.line !== nodeLine || original.column !== nodeColumn) { original.line = nodeLine; original.column = nodeColumn; generated.line = line; generated.column = column; if (sourceMappingActive) { sourceMappingActive = false; if (generated.line !== activatedGenerated.line || generated.column !== activatedGenerated.column) { map.addMapping(activatedMapping); } } sourceMappingActive = true; map.addMapping({ source: node.loc.source, original: original, generated: generated }); } } handlersNode.call(this, node); if (sourceMappingActive && trackNodes.hasOwnProperty(node.type)) { activatedGenerated.line = line; activatedGenerated.column = column; } }; var handlersChunk = handlers.chunk; handlers.chunk = function(chunk) { for (var i = 0; i < chunk.length; i++) { if (chunk.charCodeAt(i) === 10) { // \n line++; column = 0; } else { column++; } } handlersChunk(chunk); }; var handlersResult = handlers.result; handlers.result = function() { if (sourceMappingActive) { map.addMapping(activatedMapping); } return { css: handlersResult(), map: map }; }; return handlers; }; var sourceMap = sourceMap$1; var hasOwnProperty$4 = Object.prototype.hasOwnProperty; function processChildren(node, delimeter) { var list = node.children; var prev = null; if (typeof delimeter !== 'function') { list.forEach(this.node, this); } else { list.forEach(function(node) { if (prev !== null) { delimeter.call(this, prev); } this.node(node); prev = node; }, this); } } var create$3 = function createGenerator(config) { function processNode(node) { if (hasOwnProperty$4.call(types, node.type)) { types[node.type].call(this, node); } else { throw new Error('Unknown node type: ' + node.type); } } var types = {}; if (config.node) { for (var name in config.node) { types[name] = config.node[name].generate; } } return function(node, options) { var buffer = ''; var handlers = { children: processChildren, node: processNode, chunk: function(chunk) { buffer += chunk; }, result: function() { return buffer; } }; if (options) { if (typeof options.decorator === 'function') { handlers = options.decorator(handlers); } if (options.sourceMap) { handlers = sourceMap(handlers); } } handlers.node(node); return handlers.result(); }; }; var List$2 = List_1; var create$2 = function createConvertors(walk) { return { fromPlainObject: function(ast) { walk(ast, { enter: function(node) { if (node.children && node.children instanceof List$2 === false) { node.children = new List$2().fromArray(node.children); } } }); return ast; }, toPlainObject: function(ast) { walk(ast, { leave: function(node) { if (node.children && node.children instanceof List$2) { node.children = node.children.toArray(); } } }); return ast; } }; }; var hasOwnProperty$3 = Object.prototype.hasOwnProperty; var noop = function() {}; function ensureFunction(value) { return typeof value === 'function' ? value : noop; } function invokeForType(fn, type) { return function(node, item, list) { if (node.type === type) { fn.call(this, node, item, list); } }; } function getWalkersFromStructure(name, nodeType) { var structure = nodeType.structure; var walkers = []; for (var key in structure) { if (hasOwnProperty$3.call(structure, key) === false) { continue; } var fieldTypes = structure[key]; var walker = { name: key, type: false, nullable: false }; if (!Array.isArray(structure[key])) { fieldTypes = [structure[key]]; } for (var i = 0; i < fieldTypes.length; i++) { var fieldType = fieldTypes[i]; if (fieldType === null) { walker.nullable = true; } else if (typeof fieldType === 'string') { walker.type = 'node'; } else if (Array.isArray(fieldType)) { walker.type = 'list'; } } if (walker.type) { walkers.push(walker); } } if (walkers.length) { return { context: nodeType.walkContext, fields: walkers }; } return null; } function getTypesFromConfig(config) { var types = {}; for (var name in config.node) { if (hasOwnProperty$3.call(config.node, name)) { var nodeType = config.node[name]; if (!nodeType.structure) { throw new Error('Missed `structure` field in `' + name + '` node type definition'); } types[name] = getWalkersFromStructure(name, nodeType); } } return types; } function createTypeIterator(config, reverse) { var fields = config.fields.slice(); var contextName = config.context; var useContext = typeof contextName === 'string'; if (reverse) { fields.reverse(); } return function(node, context, walk, walkReducer) { var prevContextValue; if (useContext) { prevContextValue = context[contextName]; context[contextName] = node; } for (var i = 0; i < fields.length; i++) { var field = fields[i]; var ref = node[field.name]; if (!field.nullable || ref) { if (field.type === 'list') { var breakWalk = reverse ? ref.reduceRight(walkReducer, false) : ref.reduce(walkReducer, false); if (breakWalk) { return true; } } else if (walk(ref)) { return true; } } } if (useContext) { context[contextName] = prevContextValue; } }; } function createFastTraveralMap(iterators) { return { Atrule: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block }, Rule: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block }, Declaration: { StyleSheet: iterators.StyleSheet, Atrule: iterators.Atrule, Rule: iterators.Rule, Block: iterators.Block, DeclarationList: iterators.DeclarationList } }; } var create$1 = function createWalker(config) { var types = getTypesFromConfig(config); var iteratorsNatural = {}; var iteratorsReverse = {}; var breakWalk = Symbol('break-walk'); var skipNode = Symbol('skip-node'); for (var name in types) { if (hasOwnProperty$3.call(types, name) && types[name] !== null) { iteratorsNatural[name] = createTypeIterator(types[name], false); iteratorsReverse[name] = createTypeIterator(types[name], true); } } var fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural); var fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse); var walk = function(root, options) { function walkNode(node, item, list) { var enterRet = enter.call(context, node, item, list); if (enterRet === breakWalk) { debugger; return true; } if (enterRet === skipNode) { return false; } if (iterators.hasOwnProperty(node.type)) { if (iterators[node.type](node, context, walkNode, walkReducer)) { return true; } } if (leave.call(context, node, item, list) === breakWalk) { return true; } return false; } var walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list); var enter = noop; var leave = noop; var iterators = iteratorsNatural; var context = { break: breakWalk, skip: skipNode, root: root, stylesheet: null, atrule: null, atrulePrelude: null, rule: null, selector: null, block: null, declaration: null, function: null }; if (typeof options === 'function') { enter = options; } else if (options) { enter = ensureFunction(options.enter); leave = ensureFunction(options.leave); if (options.reverse) { iterators = iteratorsReverse; } if (options.visit) { if (fastTraversalIteratorsNatural.hasOwnProperty(options.visit)) { iterators = options.reverse ? fastTraversalIteratorsReverse[options.visit] : fastTraversalIteratorsNatural[options.visit]; } else if (!types.hasOwnProperty(options.visit)) { throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).join(', ') + ')'); } enter = invokeForType(enter, options.visit); leave = invokeForType(leave, options.visit); } } if (enter === noop && leave === noop) { throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function'); } walkNode(root); }; walk.break = breakWalk; walk.skip = skipNode; walk.find = function(ast, fn) { var found = null; walk(ast, function(node, item, list) { if (fn.call(this, node, item, list)) { found = node; return breakWalk; } }); return found; }; walk.findLast = function(ast, fn) { var found = null; walk(ast, { reverse: true, enter: function(node, item, list) { if (fn.call(this, node, item, list)) { found = node; return breakWalk; } } }); return found; }; walk.findAll = function(ast, fn) { var found = []; walk(ast, function(node, item, list) { if (fn.call(this, node, item, list)) { found.push(node); } }); return found; }; return walk; }; var List$1 = List_1; var clone$1 = function clone(node) { var result = {}; for (var key in node) { var value = node[key]; if (value) { if (Array.isArray(value) || value instanceof List$1) { value = value.map(clone); } else if (value.constructor === Object) { value = clone(value); } } result[key] = value; } return result; }; const hasOwnProperty$2 = Object.prototype.hasOwnProperty; const shape$1 = { generic: true, types: appendOrAssign, atrules: { prelude: appendOrAssignOrNull, descriptors: appendOrAssignOrNull }, properties: appendOrAssign, parseContext: assign, scope: deepAssign, atrule: ['parse'], pseudo: ['parse'], node: ['name', 'structure', 'parse', 'generate', 'walkContext'] }; function isObject$2(value) { return value && value.constructor === Object; } function copy(value) { return isObject$2(value) ? Object.assign({}, value) : value; } function assign(dest, src) { return Object.assign(dest, src); } function deepAssign(dest, src) { for (const key in src) { if (hasOwnProperty$2.call(src, key)) { if (isObject$2(dest[key])) { deepAssign(dest[key], copy(src[key])); } else { dest[key] = copy(src[key]); } } } return dest; } function append(a, b) { if (typeof b === 'string' && /^\s*\|/.test(b)) { return typeof a === 'string' ? a + b : b.replace(/^\s*\|\s*/, ''); } return b || null; } function appendOrAssign(a, b) { if (typeof b === 'string') { return append(a, b); } const result = Object.assign({}, a); for (let key in b) { if (hasOwnProperty$2.call(b, key)) { result[key] = append(hasOwnProperty$2.call(a, key) ? a[key] : undefined, b[key]); } } return result; } function appendOrAssignOrNull(a, b) { const result = appendOrAssign(a, b); return !isObject$2(result) || Object.keys(result).length ? result : null; } function mix$1(dest, src, shape) { for (const key in shape) { if (hasOwnProperty$2.call(shape, key) === false) { continue; } if (shape[key] === true) { if (key in src) { if (hasOwnProperty$2.call(src, key)) { dest[key] = copy(src[key]); } } } else if (shape[key]) { if (typeof shape[key] === 'function') { const fn = shape[key]; dest[key] = fn({}, dest[key]); dest[key] = fn(dest[key] || {}, src[key]); } else if (isObject$2(shape[key])) { const result = {}; for (let name in dest[key]) { result[name] = mix$1({}, dest[key][name], shape[key]); } for (let name in src[key]) { result[name] = mix$1(result[name] || {}, src[key][name], shape[key]); } dest[key] = result; } else if (Array.isArray(shape[key])) { const res = {}; const innerShape = shape[key].reduce(function(s, k) { s[k] = true; return s; }, {}); for (const [name, value] of Object.entries(dest[key] || {})) { res[name] = {}; if (value) { mix$1(res[name], value, innerShape); } } for (const name in src[key]) { if (hasOwnProperty$2.call(src[key], name)) { if (!res[name]) { res[name] = {}; } if (src[key] && src[key][name]) { mix$1(res[name], src[key][name], innerShape); } } } dest[key] = res; } } } return dest; } var mix_1 = (dest, src) => mix$1(dest, src, shape$1); var List = List_1; var SyntaxError$1 = _SyntaxError$1; var TokenStream = TokenStream_1; var Lexer = Lexer_1; var definitionSyntax = definitionSyntax$1; var tokenize = tokenizer$3; var createParser = create$4; var createGenerator = create$3; var createConvertor = create$2; var createWalker = create$1; var clone = clone$1; var names = names$2; var mix = mix_1; function createSyntax(config) { var parse = createParser(config); var walk = createWalker(config); var generate = createGenerator(config); var convert = createConvertor(walk); var syntax = { List: List, SyntaxError: SyntaxError$1, TokenStream: TokenStream, Lexer: Lexer, vendorPrefix: names.vendorPrefix, keyword: names.keyword, property: names.property, isCustomProperty: names.isCustomProperty, definitionSyntax: definitionSyntax, lexer: null, createLexer: function(config) { return new Lexer(config, syntax, syntax.lexer.structure); }, tokenize: tokenize, parse: parse, walk: walk, generate: generate, find: walk.find, findLast: walk.findLast, findAll: walk.findAll, clone: clone, fromPlainObject: convert.fromPlainObject, toPlainObject: convert.toPlainObject, createSyntax: function(config) { return createSyntax(mix({}, config)); }, fork: function(extension) { var base = mix({}, config); // copy of config return createSyntax( typeof extension === 'function' ? extension(base, Object.assign) : mix(base, extension) ); } }; syntax.lexer = new Lexer({ generic: true, types: config.types, atrules: config.atrules, properties: config.properties, node: config.node }, syntax); return syntax; } create$5.create = function(config) { return createSyntax(mix({}, config)); }; var require$$0 = { "@charset": { syntax: "@charset \"<charset>\";", groups: [ "CSS Charsets" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@charset" }, "@counter-style": { syntax: "@counter-style <counter-style-name> {\n [ system: <counter-system>; ] ||\n [ symbols: <counter-symbols>; ] ||\n [ additive-symbols: <additive-symbols>; ] ||\n [ negative: <negative-symbol>; ] ||\n [ prefix: <prefix>; ] ||\n [ suffix: <suffix>; ] ||\n [ range: <range>; ] ||\n [ pad: <padding>; ] ||\n [ speak-as: <speak-as>; ] ||\n [ fallback: <counter-style-name>; ]\n}", interfaces: [ "CSSCounterStyleRule" ], groups: [ "CSS Counter Styles" ], descriptors: { "additive-symbols": { syntax: "[ <integer> && <symbol> ]#", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, fallback: { syntax: "<counter-style-name>", media: "all", initial: "decimal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, negative: { syntax: "<symbol> <symbol>?", media: "all", initial: "\"-\" hyphen-minus", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, pad: { syntax: "<integer> && <symbol>", media: "all", initial: "0 \"\"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, prefix: { syntax: "<symbol>", media: "all", initial: "\"\"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, range: { syntax: "[ [ <integer> | infinite ]{2} ]# | auto", media: "all", initial: "auto", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "speak-as": { syntax: "auto | bullets | numbers | words | spell-out | <counter-style-name>", media: "all", initial: "auto", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, suffix: { syntax: "<symbol>", media: "all", initial: "\". \"", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, symbols: { syntax: "<symbol>+", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, system: { syntax: "cyclic | numeric | alphabetic | symbolic | additive | [ fixed <integer>? ] | [ extends <counter-style-name> ]", media: "all", initial: "symbolic", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@counter-style" }, "@document": { syntax: "@document [ <url> | url-prefix(<string>) | domain(<string>) | media-document(<string>) | regexp(<string>) ]# {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule" ], groups: [ "CSS Conditional Rules" ], status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@document" }, "@font-face": { syntax: "@font-face {\n [ font-family: <family-name>; ] ||\n [ src: <src>; ] ||\n [ unicode-range: <unicode-range>; ] ||\n [ font-variant: <font-variant>; ] ||\n [ font-feature-settings: <font-feature-settings>; ] ||\n [ font-variation-settings: <font-variation-settings>; ] ||\n [ font-stretch: <font-stretch>; ] ||\n [ font-weight: <font-weight>; ] ||\n [ font-style: <font-style>; ]\n}", interfaces: [ "CSSFontFaceRule" ], groups: [ "CSS Fonts" ], descriptors: { "font-display": { syntax: "[ auto | block | swap | fallback | optional ]", media: "visual", percentages: "no", initial: "auto", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, "font-family": { syntax: "<family-name>", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-feature-settings": { syntax: "normal | <feature-tag-value>#", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "font-variation-settings": { syntax: "normal | [ <string> <number> ]#", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "font-stretch": { syntax: "<font-stretch-absolute>{1,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-style": { syntax: "normal | italic | oblique <angle>{0,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-weight": { syntax: "<font-weight-absolute>{1,2}", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "font-variant": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> || stylistic(<feature-value-name>) || historical-forms || styleset(<feature-value-name>#) || character-variant(<feature-value-name>#) || swash(<feature-value-name>) || ornaments(<feature-value-name>) || annotation(<feature-value-name>) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero || <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "all", initial: "normal", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, src: { syntax: "[ <url> [ format( <string># ) ]? | local( <family-name> ) ]#", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, "unicode-range": { syntax: "<unicode-range>#", media: "all", initial: "U+0-10FFFF", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@font-face" }, "@font-feature-values": { syntax: "@font-feature-values <family-name># {\n <feature-value-block-list>\n}", interfaces: [ "CSSFontFeatureValuesRule" ], groups: [ "CSS Fonts" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@font-feature-values" }, "@import": { syntax: "@import [ <string> | <url> ] [ <media-query-list> ]?;", groups: [ "Media Queries" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@import" }, "@keyframes": { syntax: "@keyframes <keyframes-name> {\n <keyframe-block-list>\n}", interfaces: [ "CSSKeyframeRule", "CSSKeyframesRule" ], groups: [ "CSS Animations" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@keyframes" }, "@media": { syntax: "@media <media-query-list> {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule", "CSSMediaRule", "CSSCustomMediaRule" ], groups: [ "CSS Conditional Rules", "Media Queries" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@media" }, "@namespace": { syntax: "@namespace <namespace-prefix>? [ <string> | <url> ];", groups: [ "CSS Namespaces" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@namespace" }, "@page": { syntax: "@page <page-selector-list> {\n <page-body>\n}", interfaces: [ "CSSPageRule" ], groups: [ "CSS Pages" ], descriptors: { bleed: { syntax: "auto | <length>", media: [ "visual", "paged" ], initial: "auto", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, marks: { syntax: "none | [ crop || cross ]", media: [ "visual", "paged" ], initial: "none", percentages: "no", computed: "asSpecified", order: "orderOfAppearance", status: "standard" }, size: { syntax: "<length>{1,2} | auto | [ <page-size> || [ portrait | landscape ] ]", media: [ "visual", "paged" ], initial: "auto", percentages: "no", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "orderOfAppearance", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@page" }, "@property": { syntax: "@property <custom-property-name> {\n <declaration-list>\n}", interfaces: [ "CSS", "CSSPropertyRule" ], groups: [ "CSS Houdini" ], descriptors: { syntax: { syntax: "<string>", media: "all", percentages: "no", initial: "n/a (required)", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, inherits: { syntax: "true | false", media: "all", percentages: "no", initial: "auto", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, "initial-value": { syntax: "<string>", media: "all", initial: "n/a (required)", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "experimental" } }, status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@property" }, "@supports": { syntax: "@supports <supports-condition> {\n <group-rule-body>\n}", interfaces: [ "CSSGroupingRule", "CSSConditionRule", "CSSSupportsRule" ], groups: [ "CSS Conditional Rules" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@supports" }, "@viewport": { syntax: "@viewport {\n <group-rule-body>\n}", interfaces: [ "CSSViewportRule" ], groups: [ "CSS Device Adaptation" ], descriptors: { height: { syntax: "<viewport-length>{1,2}", media: [ "visual", "continuous" ], initial: [ "min-height", "max-height" ], percentages: [ "min-height", "max-height" ], computed: [ "min-height", "max-height" ], order: "orderOfAppearance", status: "standard" }, "max-height": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToHeightOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "max-width": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToWidthOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "max-zoom": { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" }, "min-height": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToHeightOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "min-width": { syntax: "<viewport-length>", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToWidthOfInitialViewport", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard" }, "min-zoom": { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" }, orientation: { syntax: "auto | portrait | landscape", media: [ "visual", "continuous" ], initial: "auto", percentages: "referToSizeOfBoundingBox", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "user-zoom": { syntax: "zoom | fixed", media: [ "visual", "continuous" ], initial: "zoom", percentages: "referToSizeOfBoundingBox", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, "viewport-fit": { syntax: "auto | contain | cover", media: [ "visual", "continuous" ], initial: "auto", percentages: "no", computed: "asSpecified", order: "uniqueOrder", status: "standard" }, width: { syntax: "<viewport-length>{1,2}", media: [ "visual", "continuous" ], initial: [ "min-width", "max-width" ], percentages: [ "min-width", "max-width" ], computed: [ "min-width", "max-width" ], order: "orderOfAppearance", status: "standard" }, zoom: { syntax: "auto | <number> | <percentage>", media: [ "visual", "continuous" ], initial: "auto", percentages: "the zoom factor itself", computed: "autoNonNegativeOrPercentage", order: "uniqueOrder", status: "standard" } }, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/@viewport" } }; var all = { syntax: "initial | inherit | unset | revert", media: "noPracticalMedia", inherited: false, animationType: "eachOfShorthandPropertiesExceptUnicodeBiDiAndDirection", percentages: "no", groups: [ "CSS Miscellaneous" ], initial: "noPracticalInitialValue", appliesto: "allElements", computed: "asSpecifiedAppliesToEachProperty", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/all" }; var animation = { syntax: "<single-animation>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-iteration-count", "animation-direction", "animation-fill-mode", "animation-play-state" ], appliesto: "allElementsAndPseudos", computed: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-direction", "animation-iteration-count", "animation-fill-mode", "animation-play-state" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation" }; var appearance = { syntax: "none | auto | textfield | menulist-button | <compat-auto>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/appearance" }; var azimuth = { syntax: "<angle> | [ [ left-side | far-left | left | center-left | center | center-right | right | far-right | right-side ] || behind ] | leftwards | rightwards", media: "aural", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Speech" ], initial: "center", appliesto: "allElements", computed: "normalizedAngle", order: "orderOfAppearance", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/azimuth" }; var background = { syntax: "[ <bg-layer> , ]* <final-bg-layer>", media: "visual", inherited: false, animationType: [ "background-color", "background-image", "background-clip", "background-position", "background-size", "background-repeat", "background-attachment" ], percentages: [ "background-position", "background-size" ], groups: [ "CSS Backgrounds and Borders" ], initial: [ "background-image", "background-position", "background-size", "background-repeat", "background-origin", "background-clip", "background-attachment", "background-color" ], appliesto: "allElements", computed: [ "background-image", "background-position", "background-size", "background-repeat", "background-origin", "background-clip", "background-attachment", "background-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background" }; var border = { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-color", "border-style", "border-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-width", "border-style", "border-color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border" }; var bottom = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToContainingBlockHeight", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/bottom" }; var clear = { syntax: "none | left | right | both | inline-start | inline-end", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "none", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clear" }; var clip = { syntax: "<shape> | auto", media: "visual", inherited: false, animationType: "rectangle", percentages: "no", groups: [ "CSS Masking" ], initial: "auto", appliesto: "absolutelyPositionedElements", computed: "autoOrRectangle", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clip" }; var color$1 = { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Color" ], initial: "variesFromBrowserToBrowser", appliesto: "allElements", computed: "translucentValuesRGBAOtherwiseRGB", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/color" }; var columns = { syntax: "<'column-width'> || <'column-count'>", media: "visual", inherited: false, animationType: [ "column-width", "column-count" ], percentages: "no", groups: [ "CSS Columns" ], initial: [ "column-width", "column-count" ], appliesto: "blockContainersExceptTableWrappers", computed: [ "column-width", "column-count" ], order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/columns" }; var contain = { syntax: "none | strict | content | [ size || layout || style || paint ]", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Containment" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/contain" }; var content = { syntax: "normal | none | [ <content-replacement> | <content-list> ] [/ <string> ]?", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Generated Content" ], initial: "normal", appliesto: "beforeAndAfterPseudos", computed: "normalOnElementsForPseudosNoneAbsoluteURIStringOrAsSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/content" }; var cursor = { syntax: "[ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing ] ]", media: [ "visual", "interactive" ], inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/cursor" }; var direction = { syntax: "ltr | rtl", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "ltr", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/direction" }; var display = { syntax: "[ <display-outside> || <display-inside> ] | <display-listitem> | <display-internal> | <display-box> | <display-legacy>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Display" ], initial: "inline", appliesto: "allElements", computed: "asSpecifiedExceptPositionedFloatingAndRootElementsKeywordMaybeDifferent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/display" }; var filter = { syntax: "none | <filter-function-list>", media: "visual", inherited: false, animationType: "filterList", percentages: "no", groups: [ "Filter Effects" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/filter" }; var flex = { syntax: "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]", media: "visual", inherited: false, animationType: [ "flex-grow", "flex-shrink", "flex-basis" ], percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: [ "flex-grow", "flex-shrink", "flex-basis" ], appliesto: "flexItemsAndInFlowPseudos", computed: [ "flex-grow", "flex-shrink", "flex-basis" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex" }; var float = { syntax: "left | right | none | inline-start | inline-end", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "none", appliesto: "allElementsNoEffectIfDisplayNone", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/float" }; var font = { syntax: "[ [ <'font-style'> || <font-variant-css21> || <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar", media: "visual", inherited: true, animationType: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], percentages: [ "font-size", "line-height" ], groups: [ "CSS Fonts" ], initial: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], appliesto: "allElements", computed: [ "font-style", "font-variant", "font-weight", "font-stretch", "font-size", "line-height", "font-family" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font" }; var gap = { syntax: "<'row-gap'> <'column-gap'>?", media: "visual", inherited: false, animationType: [ "row-gap", "column-gap" ], percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "row-gap", "column-gap" ], appliesto: "multiColumnElementsFlexContainersGridContainers", computed: [ "row-gap", "column-gap" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/gap" }; var grid = { syntax: "<'grid-template'> | <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? | [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>", media: "visual", inherited: false, animationType: "discrete", percentages: [ "grid-template-rows", "grid-template-columns", "grid-auto-rows", "grid-auto-columns" ], groups: [ "CSS Grid Layout" ], initial: [ "grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-rows", "grid-auto-columns", "grid-auto-flow", "grid-column-gap", "grid-row-gap", "column-gap", "row-gap" ], appliesto: "gridContainers", computed: [ "grid-template-rows", "grid-template-columns", "grid-template-areas", "grid-auto-rows", "grid-auto-columns", "grid-auto-flow", "grid-column-gap", "grid-row-gap", "column-gap", "row-gap" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid" }; var height = { syntax: "auto | <length> | <percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentagesRelativeToContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAutoOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/height" }; var hyphens = { syntax: "none | manual | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "manual", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/hyphens" }; var inset = { syntax: "<'top'>{1,4}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset" }; var isolation = { syntax: "auto | isolate", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "auto", appliesto: "allElementsSVGContainerGraphicsAndGraphicsReferencingElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/isolation" }; var left = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/left" }; var margin = { syntax: "[ <length> | <percentage> | auto ]{1,4}", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: [ "margin-bottom", "margin-left", "margin-right", "margin-top" ], appliesto: "allElementsExceptTableDisplayTypes", computed: [ "margin-bottom", "margin-left", "margin-right", "margin-top" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin" }; var mask = { syntax: "<mask-layer>#", media: "visual", inherited: false, animationType: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], percentages: [ "mask-position" ], groups: [ "CSS Masking" ], initial: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], appliesto: "allElementsSVGContainerElements", computed: [ "mask-image", "mask-mode", "mask-repeat", "mask-position", "mask-clip", "mask-origin", "mask-size", "mask-composite" ], order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask" }; var offset = { syntax: "[ <'offset-position'>? [ <'offset-path'> [ <'offset-distance'> || <'offset-rotate'> ]? ]? ]! [ / <'offset-anchor'> ]?", media: "visual", inherited: false, animationType: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], percentages: [ "offset-position", "offset-distance", "offset-anchor" ], groups: [ "CSS Motion Path" ], initial: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], appliesto: "transformableElements", computed: [ "offset-position", "offset-path", "offset-distance", "offset-anchor", "offset-rotate" ], order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset" }; var opacity = { syntax: "<alpha-value>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Color" ], initial: "1.0", appliesto: "allElements", computed: "specifiedValueClipped0To1", order: "uniqueOrder", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/opacity" }; var order = { syntax: "<integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "0", appliesto: "flexItemsGridItemsAbsolutelyPositionedContainerChildren", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/order" }; var orphans = { syntax: "<integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "2", appliesto: "blockContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/orphans" }; var outline = { syntax: "[ <'outline-color'> || <'outline-style'> || <'outline-width'> ]", media: [ "visual", "interactive" ], inherited: false, animationType: [ "outline-color", "outline-width", "outline-style" ], percentages: "no", groups: [ "CSS Basic User Interface" ], initial: [ "outline-color", "outline-style", "outline-width" ], appliesto: "allElements", computed: [ "outline-color", "outline-width", "outline-style" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline" }; var overflow = { syntax: "[ visible | hidden | clip | scroll | auto ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: [ "overflow-x", "overflow-y" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow" }; var padding = { syntax: "[ <length> | <percentage> ]{1,4}", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: [ "padding-bottom", "padding-left", "padding-right", "padding-top" ], appliesto: "allElementsExceptInternalTableDisplayTypes", computed: [ "padding-bottom", "padding-left", "padding-right", "padding-top" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding" }; var perspective = { syntax: "none | <length>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "absoluteLengthOrNone", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/perspective" }; var position$1 = { syntax: "static | relative | absolute | sticky | fixed", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Positioning" ], initial: "static", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/position" }; var quotes = { syntax: "none | auto | [ <string> <string> ]+", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Generated Content" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/quotes" }; var resize = { syntax: "none | both | horizontal | vertical | block | inline", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "none", appliesto: "elementsWithOverflowNotVisibleAndReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/resize" }; var right = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/right" }; var rotate = { syntax: "none | <angle> | [ x | y | z | <number>{3} ] && <angle>", media: "visual", inherited: false, animationType: "transform", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/rotate" }; var scale = { syntax: "none | <number>{1,3}", media: "visual", inherited: false, animationType: "transform", percentages: "no", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scale" }; var top = { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "lpc", percentages: "referToContainingBlockHeight", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/top" }; var transform = { syntax: "none | <transform-list>", media: "visual", inherited: false, animationType: "transform", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform" }; var transition = { syntax: "<single-transition>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: [ "transition-delay", "transition-duration", "transition-property", "transition-timing-function" ], appliesto: "allElementsAndPseudos", computed: [ "transition-delay", "transition-duration", "transition-property", "transition-timing-function" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition" }; var translate = { syntax: "none | <length-percentage> [ <length-percentage> <length>? ]?", media: "visual", inherited: false, animationType: "transform", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "none", appliesto: "transformableElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/translate" }; var visibility = { syntax: "visible | hidden | collapse", media: "visual", inherited: true, animationType: "visibility", percentages: "no", groups: [ "CSS Box Model" ], initial: "visible", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/visibility" }; var widows = { syntax: "<integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "2", appliesto: "blockContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/widows" }; var width = { syntax: "auto | <length> | <percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAutoOrAbsoluteLength", order: "lengthOrPercentageBeforeKeywordIfBothPresent", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/width" }; var zoom = { syntax: "normal | reset | <number> | <percentage>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/zoom" }; var require$$1 = { "--*": { syntax: "<declaration-value>", media: "all", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Variables" ], initial: "seeProse", appliesto: "allElements", computed: "asSpecifiedWithVarsSubstituted", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/--*" }, "-ms-accelerator": { syntax: "false | true", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "false", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-accelerator" }, "-ms-block-progression": { syntax: "tb | rl | bt | lr", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "tb", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-block-progression" }, "-ms-content-zoom-chaining": { syntax: "none | chained", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-chaining" }, "-ms-content-zooming": { syntax: "none | zoom", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "zoomForTheTopLevelNoneForTheRest", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zooming" }, "-ms-content-zoom-limit": { syntax: "<'-ms-content-zoom-limit-min'> <'-ms-content-zoom-limit-max'>", media: "interactive", inherited: false, animationType: "discrete", percentages: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], groups: [ "Microsoft Extensions" ], initial: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-content-zoom-limit-max", "-ms-content-zoom-limit-min" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit" }, "-ms-content-zoom-limit-max": { syntax: "<percentage>", media: "interactive", inherited: false, animationType: "discrete", percentages: "maxZoomFactor", groups: [ "Microsoft Extensions" ], initial: "400%", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit-max" }, "-ms-content-zoom-limit-min": { syntax: "<percentage>", media: "interactive", inherited: false, animationType: "discrete", percentages: "minZoomFactor", groups: [ "Microsoft Extensions" ], initial: "100%", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-limit-min" }, "-ms-content-zoom-snap": { syntax: "<'-ms-content-zoom-snap-type'> || <'-ms-content-zoom-snap-points'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-content-zoom-snap-type", "-ms-content-zoom-snap-points" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-content-zoom-snap-type", "-ms-content-zoom-snap-points" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap" }, "-ms-content-zoom-snap-points": { syntax: "snapInterval( <percentage>, <percentage> ) | snapList( <percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0%, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap-points" }, "-ms-content-zoom-snap-type": { syntax: "none | proximity | mandatory", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-content-zoom-snap-type" }, "-ms-filter": { syntax: "<string>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "\"\"", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-filter" }, "-ms-flow-from": { syntax: "[ none | <custom-ident> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-flow-from" }, "-ms-flow-into": { syntax: "[ none | <custom-ident> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "iframeElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-flow-into" }, "-ms-grid-columns": { syntax: "none | <track-list> | <auto-track-list>", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-grid-columns" }, "-ms-grid-rows": { syntax: "none | <track-list> | <auto-track-list>", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-grid-rows" }, "-ms-high-contrast-adjust": { syntax: "auto | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-high-contrast-adjust" }, "-ms-hyphenate-limit-chars": { syntax: "auto | <integer>{1,3}", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-chars" }, "-ms-hyphenate-limit-lines": { syntax: "no-limit | <integer>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "no-limit", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-lines" }, "-ms-hyphenate-limit-zone": { syntax: "<percentage> | <length>", media: "visual", inherited: true, animationType: "discrete", percentages: "referToLineBoxWidth", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-hyphenate-limit-zone" }, "-ms-ime-align": { syntax: "auto | after", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-ime-align" }, "-ms-overflow-style": { syntax: "auto | none | scrollbar | -ms-autohiding-scrollbar", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-overflow-style" }, "-ms-scrollbar-3dlight-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-3dlight-color" }, "-ms-scrollbar-arrow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ButtonText", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-arrow-color" }, "-ms-scrollbar-base-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-base-color" }, "-ms-scrollbar-darkshadow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDDarkShadow", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-darkshadow-color" }, "-ms-scrollbar-face-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDFace", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-face-color" }, "-ms-scrollbar-highlight-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDHighlight", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-highlight-color" }, "-ms-scrollbar-shadow-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "ThreeDDarkShadow", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-shadow-color" }, "-ms-scrollbar-track-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "Scrollbar", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scrollbar-track-color" }, "-ms-scroll-chaining": { syntax: "chained | none", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "chained", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-chaining" }, "-ms-scroll-limit": { syntax: "<'-ms-scroll-limit-x-min'> <'-ms-scroll-limit-y-min'> <'-ms-scroll-limit-x-max'> <'-ms-scroll-limit-y-max'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-limit-x-min", "-ms-scroll-limit-y-min", "-ms-scroll-limit-x-max", "-ms-scroll-limit-y-max" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-limit-x-min", "-ms-scroll-limit-y-min", "-ms-scroll-limit-x-max", "-ms-scroll-limit-y-max" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit" }, "-ms-scroll-limit-x-max": { syntax: "auto | <length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-x-max" }, "-ms-scroll-limit-x-min": { syntax: "<length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-x-min" }, "-ms-scroll-limit-y-max": { syntax: "auto | <length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-y-max" }, "-ms-scroll-limit-y-min": { syntax: "<length>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-limit-y-min" }, "-ms-scroll-rails": { syntax: "none | railed", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "railed", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-rails" }, "-ms-scroll-snap-points-x": { syntax: "snapInterval( <length-percentage>, <length-percentage> ) | snapList( <length-percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0px, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-points-x" }, "-ms-scroll-snap-points-y": { syntax: "snapInterval( <length-percentage>, <length-percentage> ) | snapList( <length-percentage># )", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "snapInterval(0px, 100%)", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-points-y" }, "-ms-scroll-snap-type": { syntax: "none | proximity | mandatory", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-type" }, "-ms-scroll-snap-x": { syntax: "<'-ms-scroll-snap-type'> <'-ms-scroll-snap-points-x'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-x" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-x" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-x" }, "-ms-scroll-snap-y": { syntax: "<'-ms-scroll-snap-type'> <'-ms-scroll-snap-points-y'>", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-y" ], appliesto: "nonReplacedBlockAndInlineBlockElements", computed: [ "-ms-scroll-snap-type", "-ms-scroll-snap-points-y" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-snap-y" }, "-ms-scroll-translation": { syntax: "none | vertical-to-horizontal", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-scroll-translation" }, "-ms-text-autospace": { syntax: "none | ideograph-alpha | ideograph-numeric | ideograph-parenthesis | ideograph-space", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-text-autospace" }, "-ms-touch-select": { syntax: "grippers | none", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "grippers", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-touch-select" }, "-ms-user-select": { syntax: "none | element | text", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "text", appliesto: "nonReplacedElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-user-select" }, "-ms-wrap-flow": { syntax: "auto | both | start | end | maximum | clear", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-flow" }, "-ms-wrap-margin": { syntax: "<length>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "0", appliesto: "exclusionElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-margin" }, "-ms-wrap-through": { syntax: "wrap | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Microsoft Extensions" ], initial: "wrap", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-ms-wrap-through" }, "-moz-appearance": { syntax: "none | button | button-arrow-down | button-arrow-next | button-arrow-previous | button-arrow-up | button-bevel | button-focus | caret | checkbox | checkbox-container | checkbox-label | checkmenuitem | dualbutton | groupbox | listbox | listitem | menuarrow | menubar | menucheckbox | menuimage | menuitem | menuitemtext | menulist | menulist-button | menulist-text | menulist-textfield | menupopup | menuradio | menuseparator | meterbar | meterchunk | progressbar | progressbar-vertical | progresschunk | progresschunk-vertical | radio | radio-container | radio-label | radiomenuitem | range | range-thumb | resizer | resizerpanel | scale-horizontal | scalethumbend | scalethumb-horizontal | scalethumbstart | scalethumbtick | scalethumb-vertical | scale-vertical | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical | searchfield | separator | sheet | spinner | spinner-downbutton | spinner-textfield | spinner-upbutton | splitter | statusbar | statusbarpanel | tab | tabpanel | tabpanels | tab-scroll-arrow-back | tab-scroll-arrow-forward | textfield | textfield-multiline | toolbar | toolbarbutton | toolbarbutton-dropdown | toolbargripper | toolbox | tooltip | treeheader | treeheadercell | treeheadersortarrow | treeitem | treeline | treetwisty | treetwistyopen | treeview | -moz-mac-unified-toolbar | -moz-win-borderless-glass | -moz-win-browsertabbar-toolbox | -moz-win-communicationstext | -moz-win-communications-toolbox | -moz-win-exclude-glass | -moz-win-glass | -moz-win-mediatext | -moz-win-media-toolbox | -moz-window-button-box | -moz-window-button-box-maximized | -moz-window-button-close | -moz-window-button-maximize | -moz-window-button-minimize | -moz-window-button-restore | -moz-window-frame-bottom | -moz-window-frame-left | -moz-window-frame-right | -moz-window-titlebar | -moz-window-titlebar-maximized", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "noneButOverriddenInUserAgentCSS", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/appearance" }, "-moz-binding": { syntax: "<url> | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElementsExceptGeneratedContentOrPseudoElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-binding" }, "-moz-border-bottom-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-bottom-colors" }, "-moz-border-left-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-left-colors" }, "-moz-border-right-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-right-colors" }, "-moz-border-top-colors": { syntax: "<color>+ | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-border-top-colors" }, "-moz-context-properties": { syntax: "none | [ fill | fill-opacity | stroke | stroke-opacity ]#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElementsThatCanReferenceImages", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-context-properties" }, "-moz-float-edge": { syntax: "border-box | content-box | margin-box | padding-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "content-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-float-edge" }, "-moz-force-broken-image-icon": { syntax: "<integer [0,1]>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "images", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-force-broken-image-icon" }, "-moz-image-region": { syntax: "<shape> | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "auto", appliesto: "xulImageElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-image-region" }, "-moz-orient": { syntax: "inline | block | horizontal | vertical", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "inline", appliesto: "anyElementEffectOnProgressAndMeter", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-orient" }, "-moz-outline-radius": { syntax: "<outline-radius>{1,4} [ / <outline-radius>{1,4} ]?", media: "visual", inherited: false, animationType: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], percentages: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], groups: [ "Mozilla Extensions" ], initial: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], appliesto: "allElements", computed: [ "-moz-outline-radius-topleft", "-moz-outline-radius-topright", "-moz-outline-radius-bottomright", "-moz-outline-radius-bottomleft" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius" }, "-moz-outline-radius-bottomleft": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-bottomleft" }, "-moz-outline-radius-bottomright": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-bottomright" }, "-moz-outline-radius-topleft": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-topleft" }, "-moz-outline-radius-topright": { syntax: "<outline-radius>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "Mozilla Extensions" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-outline-radius-topright" }, "-moz-stack-sizing": { syntax: "ignore | stretch-to-fit", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "stretch-to-fit", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-stack-sizing" }, "-moz-text-blink": { syntax: "none | blink", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-text-blink" }, "-moz-user-focus": { syntax: "ignore | normal | select-after | select-before | select-menu | select-same | select-all | none", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-focus" }, "-moz-user-input": { syntax: "auto | none | enabled | disabled", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input" }, "-moz-user-modify": { syntax: "read-only | read-write | write-only", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "read-only", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-modify" }, "-moz-window-dragging": { syntax: "drag | no-drag", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "drag", appliesto: "allElementsCreatingNativeWindows", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-window-dragging" }, "-moz-window-shadow": { syntax: "default | menu | tooltip | sheet | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "default", appliesto: "allElementsCreatingNativeWindows", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-moz-window-shadow" }, "-webkit-appearance": { syntax: "none | button | button-bevel | caret | checkbox | default-button | inner-spin-button | listbox | listitem | media-controls-background | media-controls-fullscreen-background | media-current-time-display | media-enter-fullscreen-button | media-exit-fullscreen-button | media-fullscreen-button | media-mute-button | media-overlay-play-button | media-play-button | media-seek-back-button | media-seek-forward-button | media-slider | media-sliderthumb | media-time-remaining-display | media-toggle-closed-captions-button | media-volume-slider | media-volume-slider-container | media-volume-sliderthumb | menulist | menulist-button | menulist-text | menulist-textfield | meter | progress-bar | progress-bar-value | push-button | radio | searchfield | searchfield-cancel-button | searchfield-decoration | searchfield-results-button | searchfield-results-decoration | slider-horizontal | slider-vertical | sliderthumb-horizontal | sliderthumb-vertical | square-button | textarea | textfield | -apple-pay-button", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "noneButOverriddenInUserAgentCSS", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/appearance" }, "-webkit-border-before": { syntax: "<'border-width'> || <'border-style'> || <'color'>", media: "visual", inherited: true, animationType: "discrete", percentages: [ "-webkit-border-before-width" ], groups: [ "WebKit Extensions" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "color" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-border-before" }, "-webkit-border-before-color": { syntax: "<'color'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard" }, "-webkit-border-before-style": { syntax: "<'border-style'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard" }, "-webkit-border-before-width": { syntax: "<'border-width'>", media: "visual", inherited: true, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "WebKit Extensions" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "nonstandard" }, "-webkit-box-reflect": { syntax: "[ above | below | right | left ]? <length>? <image>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-box-reflect" }, "-webkit-line-clamp": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "WebKit Extensions", "CSS Overflow" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-line-clamp" }, "-webkit-mask": { syntax: "[ <mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> || [ <box> | border | padding | content | text ] || [ <box> | border | padding | content ] ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: [ "-webkit-mask-image", "-webkit-mask-repeat", "-webkit-mask-attachment", "-webkit-mask-position", "-webkit-mask-origin", "-webkit-mask-clip" ], appliesto: "allElements", computed: [ "-webkit-mask-image", "-webkit-mask-repeat", "-webkit-mask-attachment", "-webkit-mask-position", "-webkit-mask-origin", "-webkit-mask-clip" ], order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask" }, "-webkit-mask-attachment": { syntax: "<attachment>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "scroll", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-attachment" }, "-webkit-mask-clip": { syntax: "[ <box> | border | padding | content | text ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "border", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-clip" }, "-webkit-mask-composite": { syntax: "<composite-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "source-over", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-composite" }, "-webkit-mask-image": { syntax: "<mask-reference>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "none", appliesto: "allElements", computed: "absoluteURIOrNone", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-image" }, "-webkit-mask-origin": { syntax: "[ <box> | border | padding | content ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "padding", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-origin" }, "-webkit-mask-position": { syntax: "<position>#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0% 0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-position" }, "-webkit-mask-position-x": { syntax: "[ <length-percentage> | left | center | right ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-position-x" }, "-webkit-mask-position-y": { syntax: "[ <length-percentage> | top | center | bottom ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfElement", groups: [ "WebKit Extensions" ], initial: "0%", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-position-y" }, "-webkit-mask-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-repeat" }, "-webkit-mask-repeat-x": { syntax: "repeat | no-repeat | space | round", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-repeat-x" }, "-webkit-mask-repeat-y": { syntax: "repeat | no-repeat | space | round", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "repeat", appliesto: "allElements", computed: "absoluteLengthOrPercentage", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-mask-repeat-y" }, "-webkit-mask-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "discrete", percentages: "relativeToBackgroundPositioningArea", groups: [ "WebKit Extensions" ], initial: "auto auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-size" }, "-webkit-overflow-scrolling": { syntax: "auto | touch", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "orderOfAppearance", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-overflow-scrolling" }, "-webkit-tap-highlight-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "black", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-tap-highlight-color" }, "-webkit-text-fill-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-fill-color" }, "-webkit-text-stroke": { syntax: "<length> || <color>", media: "visual", inherited: true, animationType: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], percentages: "no", groups: [ "WebKit Extensions" ], initial: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], appliesto: "allElements", computed: [ "-webkit-text-stroke-width", "-webkit-text-stroke-color" ], order: "canonicalOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke" }, "-webkit-text-stroke-color": { syntax: "<color>", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "WebKit Extensions" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke-color" }, "-webkit-text-stroke-width": { syntax: "<length>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "0", appliesto: "allElements", computed: "absoluteLength", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-text-stroke-width" }, "-webkit-touch-callout": { syntax: "default | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "default", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/-webkit-touch-callout" }, "-webkit-user-modify": { syntax: "read-only | read-write | read-write-plaintext-only", media: "interactive", inherited: true, animationType: "discrete", percentages: "no", groups: [ "WebKit Extensions" ], initial: "read-only", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard" }, "align-content": { syntax: "normal | <baseline-position> | <content-distribution> | <overflow-position>? <content-position>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multilineFlexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-content" }, "align-items": { syntax: "normal | stretch | <baseline-position> | [ <overflow-position>? <self-position> ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-items" }, "align-self": { syntax: "auto | normal | stretch | <baseline-position> | <overflow-position>? <self-position>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "auto", appliesto: "flexItemsGridItemsAndAbsolutelyPositionedBoxes", computed: "autoOnAbsolutelyPositionedElementsValueOfAlignItemsOnParent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-self" }, "align-tracks": { syntax: "[ normal | <baseline-position> | <content-distribution> | <overflow-position>? <content-position> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "normal", appliesto: "gridContainersWithMasonryLayoutInTheirBlockAxis", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/align-tracks" }, all: all, animation: animation, "animation-delay": { syntax: "<time>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-delay" }, "animation-direction": { syntax: "<single-animation-direction>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "normal", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-direction" }, "animation-duration": { syntax: "<time>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-duration" }, "animation-fill-mode": { syntax: "<single-animation-fill-mode>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "none", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-fill-mode" }, "animation-iteration-count": { syntax: "<single-animation-iteration-count>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "1", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-iteration-count" }, "animation-name": { syntax: "[ none | <keyframes-name> ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "none", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-name" }, "animation-play-state": { syntax: "<single-animation-play-state>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "running", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-play-state" }, "animation-timing-function": { syntax: "<timing-function>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Animations" ], initial: "ease", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/animation-timing-function" }, appearance: appearance, "aspect-ratio": { syntax: "auto | <ratio>", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElementsExceptInlineBoxesAndInternalRubyOrTableBoxes", computed: "asSpecified", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/aspect-ratio" }, azimuth: azimuth, "backdrop-filter": { syntax: "none | <filter-function-list>", media: "visual", inherited: false, animationType: "filterList", percentages: "no", groups: [ "Filter Effects" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/backdrop-filter" }, "backface-visibility": { syntax: "visible | hidden", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "visible", appliesto: "transformableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/backface-visibility" }, background: background, "background-attachment": { syntax: "<attachment>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "scroll", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-attachment" }, "background-blend-mode": { syntax: "<blend-mode>#", media: "none", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "normal", appliesto: "allElementsSVGContainerGraphicsAndGraphicsReferencingElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-blend-mode" }, "background-clip": { syntax: "<box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "border-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-clip" }, "background-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "transparent", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-color" }, "background-image": { syntax: "<bg-image>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-image" }, "background-origin": { syntax: "<box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "padding-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-origin" }, "background-position": { syntax: "<bg-position>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToSizeOfBackgroundPositioningAreaMinusBackgroundImageSize", groups: [ "CSS Backgrounds and Borders" ], initial: "0% 0%", appliesto: "allElements", computed: "listEachItemTwoKeywordsOriginOffsets", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position" }, "background-position-x": { syntax: "[ center | [ [ left | right | x-start | x-end ]? <length-percentage>? ]! ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToWidthOfBackgroundPositioningAreaMinusBackgroundImageHeight", groups: [ "CSS Backgrounds and Borders" ], initial: "left", appliesto: "allElements", computed: "listEachItemConsistingOfAbsoluteLengthPercentageAndOrigin", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position-x" }, "background-position-y": { syntax: "[ center | [ [ top | bottom | y-start | y-end ]? <length-percentage>? ]! ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "referToHeightOfBackgroundPositioningAreaMinusBackgroundImageHeight", groups: [ "CSS Backgrounds and Borders" ], initial: "top", appliesto: "allElements", computed: "listEachItemConsistingOfAbsoluteLengthPercentageAndOrigin", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-position-y" }, "background-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "repeat", appliesto: "allElements", computed: "listEachItemHasTwoKeywordsOnePerDimension", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-repeat" }, "background-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "relativeToBackgroundPositioningArea", groups: [ "CSS Backgrounds and Borders" ], initial: "auto auto", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/background-size" }, "block-overflow": { syntax: "clip | ellipsis | <string>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "clip", appliesto: "blockContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "block-size": { syntax: "<'width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "sameAsWidthAndHeight", computed: "sameAsWidthAndHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/block-size" }, border: border, "border-block": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block" }, "border-block-color": { syntax: "<'border-top-color'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-color" }, "border-block-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-style" }, "border-block-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-width" }, "border-block-end": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: [ "border-block-end-color", "border-block-end-style", "border-block-end-width" ], percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end" }, "border-block-end-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-color" }, "border-block-end-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-style" }, "border-block-end-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-end-width" }, "border-block-start": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: [ "border-block-start-color", "border-block-start-style", "border-block-start-width" ], percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-block-start-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start" }, "border-block-start-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-color" }, "border-block-start-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-style" }, "border-block-start-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-block-start-width" }, "border-bottom": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-bottom-color", "border-bottom-style", "border-bottom-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-bottom-width", "border-bottom-style", "border-bottom-color" ], appliesto: "allElements", computed: [ "border-bottom-width", "border-bottom-style", "border-bottom-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom" }, "border-bottom-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-color" }, "border-bottom-left-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-left-radius" }, "border-bottom-right-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-right-radius" }, "border-bottom-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-style" }, "border-bottom-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderBottomStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-bottom-width" }, "border-collapse": { syntax: "collapse | separate", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "separate", appliesto: "tableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-collapse" }, "border-color": { syntax: "<color>{1,4}", media: "visual", inherited: false, animationType: [ "border-bottom-color", "border-left-color", "border-right-color", "border-top-color" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-color", "border-right-color", "border-bottom-color", "border-left-color" ], appliesto: "allElements", computed: [ "border-bottom-color", "border-left-color", "border-right-color", "border-top-color" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-color" }, "border-end-end-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-end-end-radius" }, "border-end-start-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-end-start-radius" }, "border-image": { syntax: "<'border-image-source'> || <'border-image-slice'> [ / <'border-image-width'> | / <'border-image-width'>? / <'border-image-outset'> ]? || <'border-image-repeat'>", media: "visual", inherited: false, animationType: "discrete", percentages: [ "border-image-slice", "border-image-width" ], groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-image-source", "border-image-slice", "border-image-width", "border-image-outset", "border-image-repeat" ], appliesto: "allElementsExceptTableElementsWhenCollapse", computed: [ "border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source", "border-image-width" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image" }, "border-image-outset": { syntax: "[ <length> | <number> ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-outset" }, "border-image-repeat": { syntax: "[ stretch | repeat | round | space ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "stretch", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-repeat" }, "border-image-slice": { syntax: "<number-percentage>{1,4} && fill?", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "referToSizeOfBorderImage", groups: [ "CSS Backgrounds and Borders" ], initial: "100%", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "oneToFourPercentagesOrAbsoluteLengthsPlusFill", order: "percentagesOrLengthsFollowedByFill", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-slice" }, "border-image-source": { syntax: "none | <image>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "noneOrImageWithAbsoluteURI", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-source" }, "border-image-width": { syntax: "[ <length-percentage> | <number> | auto ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "referToWidthOrHeightOfBorderImageArea", groups: [ "CSS Backgrounds and Borders" ], initial: "1", appliesto: "allElementsExceptTableElementsWhenCollapse", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-image-width" }, "border-inline": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline" }, "border-inline-end": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: [ "border-inline-end-color", "border-inline-end-style", "border-inline-end-width" ], percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-inline-end-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end" }, "border-inline-color": { syntax: "<'border-top-color'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-color" }, "border-inline-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-style" }, "border-inline-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-width" }, "border-inline-end-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-color" }, "border-inline-end-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-style" }, "border-inline-end-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-end-width" }, "border-inline-start": { syntax: "<'border-top-width'> || <'border-top-style'> || <'color'>", media: "visual", inherited: false, animationType: [ "border-inline-start-color", "border-inline-start-style", "border-inline-start-width" ], percentages: "no", groups: [ "CSS Logical Properties" ], initial: [ "border-width", "border-style", "color" ], appliesto: "allElements", computed: [ "border-width", "border-style", "border-inline-start-color" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start" }, "border-inline-start-color": { syntax: "<'border-top-color'>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-color" }, "border-inline-start-style": { syntax: "<'border-top-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Logical Properties" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-style" }, "border-inline-start-width": { syntax: "<'border-top-width'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthZeroIfBorderStyleNoneOrHidden", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-inline-start-width" }, "border-left": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-left-color", "border-left-style", "border-left-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-left-width", "border-left-style", "border-left-color" ], appliesto: "allElements", computed: [ "border-left-width", "border-left-style", "border-left-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left" }, "border-left-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-color" }, "border-left-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-style" }, "border-left-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderLeftStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-left-width" }, "border-radius": { syntax: "<length-percentage>{1,4} [ / <length-percentage>{1,4} ]?", media: "visual", inherited: false, animationType: [ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius" ], percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius" ], appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: [ "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-radius" }, "border-right": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-right-color", "border-right-style", "border-right-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-right-width", "border-right-style", "border-right-color" ], appliesto: "allElements", computed: [ "border-right-width", "border-right-style", "border-right-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right" }, "border-right-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-color" }, "border-right-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-style" }, "border-right-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderRightStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-right-width" }, "border-spacing": { syntax: "<length> <length>?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "0", appliesto: "tableElements", computed: "twoAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-spacing" }, "border-start-end-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-start-end-radius" }, "border-start-start-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-start-start-radius" }, "border-style": { syntax: "<line-style>{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-style", "border-right-style", "border-bottom-style", "border-left-style" ], appliesto: "allElements", computed: [ "border-bottom-style", "border-left-style", "border-right-style", "border-top-style" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-style" }, "border-top": { syntax: "<line-width> || <line-style> || <color>", media: "visual", inherited: false, animationType: [ "border-top-color", "border-top-style", "border-top-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-width", "border-top-style", "border-top-color" ], appliesto: "allElements", computed: [ "border-top-width", "border-top-style", "border-top-color" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top" }, "border-top-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-color" }, "border-top-left-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-left-radius" }, "border-top-right-radius": { syntax: "<length-percentage>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfBorderBox", groups: [ "CSS Backgrounds and Borders" ], initial: "0", appliesto: "allElementsUAsNotRequiredWhenCollapse", computed: "twoAbsoluteLengthOrPercentages", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-right-radius" }, "border-top-style": { syntax: "<line-style>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-style" }, "border-top-width": { syntax: "<line-width>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "medium", appliesto: "allElements", computed: "absoluteLengthOr0IfBorderTopStyleNoneOrHidden", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-top-width" }, "border-width": { syntax: "<line-width>{1,4}", media: "visual", inherited: false, animationType: [ "border-bottom-width", "border-left-width", "border-right-width", "border-top-width" ], percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: [ "border-top-width", "border-right-width", "border-bottom-width", "border-left-width" ], appliesto: "allElements", computed: [ "border-bottom-width", "border-left-width", "border-right-width", "border-top-width" ], order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/border-width" }, bottom: bottom, "box-align": { syntax: "start | center | end | baseline | stretch", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "stretch", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-align" }, "box-decoration-break": { syntax: "slice | clone", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "slice", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-decoration-break" }, "box-direction": { syntax: "normal | reverse | inherit", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "normal", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-direction" }, "box-flex": { syntax: "<number>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "0", appliesto: "directChildrenOfElementsWithDisplayMozBoxMozInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-flex" }, "box-flex-group": { syntax: "<integer>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "1", appliesto: "inFlowChildrenOfBoxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-flex-group" }, "box-lines": { syntax: "single | multiple", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "single", appliesto: "boxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-lines" }, "box-ordinal-group": { syntax: "<integer>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "1", appliesto: "childrenOfBoxElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-ordinal-group" }, "box-orient": { syntax: "horizontal | vertical | inline-axis | block-axis | inherit", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "inlineAxisHorizontalInXUL", appliesto: "elementsWithDisplayBoxOrInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-orient" }, "box-pack": { syntax: "start | center | end | justify", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions", "WebKit Extensions" ], initial: "start", appliesto: "elementsWithDisplayMozBoxMozInlineBox", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-pack" }, "box-shadow": { syntax: "none | <shadow>#", media: "visual", inherited: false, animationType: "shadowList", percentages: "no", groups: [ "CSS Backgrounds and Borders" ], initial: "none", appliesto: "allElements", computed: "absoluteLengthsSpecifiedColorAsSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-shadow" }, "box-sizing": { syntax: "content-box | border-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "content-box", appliesto: "allElementsAcceptingWidthOrHeight", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/box-sizing" }, "break-after": { syntax: "auto | avoid | always | all | avoid-page | page | left | right | recto | verso | avoid-column | column | avoid-region | region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-after" }, "break-before": { syntax: "auto | avoid | always | all | avoid-page | page | left | right | recto | verso | avoid-column | column | avoid-region | region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-before" }, "break-inside": { syntax: "auto | avoid | avoid-page | avoid-column | avoid-region", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Fragmentation" ], initial: "auto", appliesto: "blockLevelElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/break-inside" }, "caption-side": { syntax: "top | bottom | block-start | block-end | inline-start | inline-end", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "top", appliesto: "tableCaptionElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/caption-side" }, "caret-color": { syntax: "auto | <color>", media: "interactive", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asAutoOrColor", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/caret-color" }, clear: clear, clip: clip, "clip-path": { syntax: "<clip-source> | [ <basic-shape> || <geometry-box> ] | none", media: "visual", inherited: false, animationType: "basicShapeOtherwiseNo", percentages: "referToReferenceBoxWhenSpecifiedOtherwiseBorderBox", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/clip-path" }, color: color$1, "color-adjust": { syntax: "economy | exact", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Color" ], initial: "economy", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/color-adjust" }, "column-count": { syntax: "<integer> | auto", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Columns" ], initial: "auto", appliesto: "blockContainersExceptTableWrappers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-count" }, "column-fill": { syntax: "auto | balance | balance-all", media: "visualInContinuousMediaNoEffectInOverflowColumns", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "balance", appliesto: "multicolElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-fill" }, "column-gap": { syntax: "normal | <length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multiColumnElementsFlexContainersGridContainers", computed: "asSpecifiedWithLengthsAbsoluteAndNormalComputingToZeroExceptMultiColumn", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-gap" }, "column-rule": { syntax: "<'column-rule-width'> || <'column-rule-style'> || <'column-rule-color'>", media: "visual", inherited: false, animationType: [ "column-rule-color", "column-rule-style", "column-rule-width" ], percentages: "no", groups: [ "CSS Columns" ], initial: [ "column-rule-width", "column-rule-style", "column-rule-color" ], appliesto: "multicolElements", computed: [ "column-rule-color", "column-rule-style", "column-rule-width" ], order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule" }, "column-rule-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Columns" ], initial: "currentcolor", appliesto: "multicolElements", computed: "computedColor", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-color" }, "column-rule-style": { syntax: "<'border-style'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "none", appliesto: "multicolElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-style" }, "column-rule-width": { syntax: "<'border-width'>", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Columns" ], initial: "medium", appliesto: "multicolElements", computed: "absoluteLength0IfColumnRuleStyleNoneOrHidden", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-rule-width" }, "column-span": { syntax: "none | all", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Columns" ], initial: "none", appliesto: "inFlowBlockLevelElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-span" }, "column-width": { syntax: "<length> | auto", media: "visual", inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Columns" ], initial: "auto", appliesto: "blockContainersExceptTableWrappers", computed: "absoluteLengthZeroOrLarger", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-width" }, columns: columns, contain: contain, content: content, "counter-increment": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-increment" }, "counter-reset": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-reset" }, "counter-set": { syntax: "[ <custom-ident> <integer>? ]+ | none", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Counter Styles" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/counter-set" }, cursor: cursor, direction: direction, display: display, "empty-cells": { syntax: "show | hide", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "show", appliesto: "tableCellElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/empty-cells" }, filter: filter, flex: flex, "flex-basis": { syntax: "content | <'width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToFlexContainersInnerMainSize", groups: [ "CSS Flexible Box Layout" ], initial: "auto", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "lengthOrPercentageBeforeKeywordIfBothPresent", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-basis" }, "flex-direction": { syntax: "row | row-reverse | column | column-reverse", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "row", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-direction" }, "flex-flow": { syntax: "<'flex-direction'> || <'flex-wrap'>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: [ "flex-direction", "flex-wrap" ], appliesto: "flexContainers", computed: [ "flex-direction", "flex-wrap" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-flow" }, "flex-grow": { syntax: "<number>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "0", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-grow" }, "flex-shrink": { syntax: "<number>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "1", appliesto: "flexItemsAndInFlowPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-shrink" }, "flex-wrap": { syntax: "nowrap | wrap | wrap-reverse", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Flexible Box Layout" ], initial: "nowrap", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/flex-wrap" }, float: float, font: font, "font-family": { syntax: "[ <family-name> | <generic-family> ]#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "dependsOnUserAgent", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-family" }, "font-feature-settings": { syntax: "normal | <feature-tag-value>#", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-feature-settings" }, "font-kerning": { syntax: "auto | normal | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-kerning" }, "font-language-override": { syntax: "normal | <string>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-language-override" }, "font-optical-sizing": { syntax: "auto | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-optical-sizing" }, "font-variation-settings": { syntax: "normal | [ <string> <number> ]#", media: "visual", inherited: true, animationType: "transform", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variation-settings" }, "font-size": { syntax: "<absolute-size> | <relative-size> | <length-percentage>", media: "visual", inherited: true, animationType: "length", percentages: "referToParentElementsFontSize", groups: [ "CSS Fonts" ], initial: "medium", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-size" }, "font-size-adjust": { syntax: "none | <number>", media: "visual", inherited: true, animationType: "number", percentages: "no", groups: [ "CSS Fonts" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-size-adjust" }, "font-smooth": { syntax: "auto | never | always | <absolute-size> | <length>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-smooth" }, "font-stretch": { syntax: "<font-stretch-absolute>", media: "visual", inherited: true, animationType: "fontStretch", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-stretch" }, "font-style": { syntax: "normal | italic | oblique <angle>?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-style" }, "font-synthesis": { syntax: "none | [ weight || style ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "weight style", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-synthesis" }, "font-variant": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> || stylistic( <feature-value-name> ) || historical-forms || styleset( <feature-value-name># ) || character-variant( <feature-value-name># ) || swash( <feature-value-name> ) || ornaments( <feature-value-name> ) || annotation( <feature-value-name> ) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero || <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant" }, "font-variant-alternates": { syntax: "normal | [ stylistic( <feature-value-name> ) || historical-forms || styleset( <feature-value-name># ) || character-variant( <feature-value-name># ) || swash( <feature-value-name> ) || ornaments( <feature-value-name> ) || annotation( <feature-value-name> ) ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-alternates" }, "font-variant-caps": { syntax: "normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-caps" }, "font-variant-east-asian": { syntax: "normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-east-asian" }, "font-variant-ligatures": { syntax: "normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-ligatures" }, "font-variant-numeric": { syntax: "normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-numeric" }, "font-variant-position": { syntax: "normal | sub | super", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-variant-position" }, "font-weight": { syntax: "<font-weight-absolute> | bolder | lighter", media: "visual", inherited: true, animationType: "fontWeight", percentages: "no", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "keywordOrNumericalValueBolderLighterTransformedToRealValue", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/font-weight" }, gap: gap, grid: grid, "grid-area": { syntax: "<grid-line> [ / <grid-line> ]{0,3}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-start", "grid-column-start", "grid-row-end", "grid-column-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-row-start", "grid-column-start", "grid-row-end", "grid-column-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-area" }, "grid-auto-columns": { syntax: "<track-size>+", media: "visual", inherited: false, animationType: "discrete", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-columns" }, "grid-auto-flow": { syntax: "[ row | column ] || dense", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "row", appliesto: "gridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-flow" }, "grid-auto-rows": { syntax: "<track-size>+", media: "visual", inherited: false, animationType: "discrete", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-auto-rows" }, "grid-column": { syntax: "<grid-line> [ / <grid-line> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-column-start", "grid-column-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-column-start", "grid-column-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column" }, "grid-column-end": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column-end" }, "grid-column-gap": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "0", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/column-gap" }, "grid-column-start": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-column-start" }, "grid-gap": { syntax: "<'grid-row-gap'> <'grid-column-gap'>?", media: "visual", inherited: false, animationType: [ "grid-row-gap", "grid-column-gap" ], percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-gap", "grid-column-gap" ], appliesto: "gridContainers", computed: [ "grid-row-gap", "grid-column-gap" ], order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/gap" }, "grid-row": { syntax: "<grid-line> [ / <grid-line> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: [ "grid-row-start", "grid-row-end" ], appliesto: "gridItemsAndBoxesWithinGridContainer", computed: [ "grid-row-start", "grid-row-end" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row" }, "grid-row-end": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row-end" }, "grid-row-gap": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "0", appliesto: "gridContainers", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/row-gap" }, "grid-row-start": { syntax: "<grid-line>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "auto", appliesto: "gridItemsAndBoxesWithinGridContainer", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-row-start" }, "grid-template": { syntax: "none | [ <'grid-template-rows'> / <'grid-template-columns'> ] | [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?", media: "visual", inherited: false, animationType: "discrete", percentages: [ "grid-template-columns", "grid-template-rows" ], groups: [ "CSS Grid Layout" ], initial: [ "grid-template-columns", "grid-template-rows", "grid-template-areas" ], appliesto: "gridContainers", computed: [ "grid-template-columns", "grid-template-rows", "grid-template-areas" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template" }, "grid-template-areas": { syntax: "none | <string>+", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-areas" }, "grid-template-columns": { syntax: "none | <track-list> | <auto-track-list> | subgrid <line-name-list>?", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-columns" }, "grid-template-rows": { syntax: "none | <track-list> | <auto-track-list> | subgrid <line-name-list>?", media: "visual", inherited: false, animationType: "simpleListOfLpcDifferenceLpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Grid Layout" ], initial: "none", appliesto: "gridContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/grid-template-rows" }, "hanging-punctuation": { syntax: "none | [ first || [ force-end | allow-end ] || last ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/hanging-punctuation" }, height: height, hyphens: hyphens, "image-orientation": { syntax: "from-image | <angle> | [ <angle>? flip ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "from-image", appliesto: "allElements", computed: "angleRoundedToNextQuarter", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/image-orientation" }, "image-rendering": { syntax: "auto | crisp-edges | pixelated", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/image-rendering" }, "image-resolution": { syntax: "[ from-image || <resolution> ] && snap?", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "1dppx", appliesto: "allElements", computed: "asSpecifiedWithExceptionOfResolution", order: "uniqueOrder", status: "experimental" }, "ime-mode": { syntax: "auto | normal | active | inactive | disabled", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "textFields", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ime-mode" }, "initial-letter": { syntax: "normal | [ <number> <integer>? ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Inline" ], initial: "normal", appliesto: "firstLetterPseudoElementsAndInlineLevelFirstChildren", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/initial-letter" }, "initial-letter-align": { syntax: "[ auto | alphabetic | hanging | ideographic ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Inline" ], initial: "auto", appliesto: "firstLetterPseudoElementsAndInlineLevelFirstChildren", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/initial-letter-align" }, "inline-size": { syntax: "<'width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "sameAsWidthAndHeight", computed: "sameAsWidthAndHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inline-size" }, inset: inset, "inset-block": { syntax: "<'top'>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block" }, "inset-block-end": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block-end" }, "inset-block-start": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalHeightOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-block-start" }, "inset-inline": { syntax: "<'top'>{1,2}", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline" }, "inset-inline-end": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline-end" }, "inset-inline-start": { syntax: "<'top'>", media: "visual", inherited: false, animationType: "lpc", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "auto", appliesto: "positionedElements", computed: "sameAsBoxOffsets", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/inset-inline-start" }, isolation: isolation, "justify-content": { syntax: "normal | <content-distribution> | <overflow-position>? [ <content-position> | left | right ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "flexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-content" }, "justify-items": { syntax: "normal | stretch | <baseline-position> | <overflow-position>? [ <self-position> | left | right ] | legacy | legacy && [ left | right | center ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "legacy", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-items" }, "justify-self": { syntax: "auto | normal | stretch | <baseline-position> | <overflow-position>? [ <self-position> | left | right ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "auto", appliesto: "blockLevelBoxesAndAbsolutelyPositionedBoxesAndGridItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-self" }, "justify-tracks": { syntax: "[ normal | <content-distribution> | <overflow-position>? [ <content-position> | left | right ] ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "normal", appliesto: "gridContainersWithMasonryLayoutInTheirInlineAxis", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/justify-tracks" }, left: left, "letter-spacing": { syntax: "normal | <length>", media: "visual", inherited: true, animationType: "length", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "optimumValueOfAbsoluteLengthOrNormal", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/letter-spacing" }, "line-break": { syntax: "auto | loose | normal | strict | anywhere", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-break" }, "line-clamp": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Overflow" ], initial: "none", appliesto: "blockContainersExceptMultiColumnContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "line-height": { syntax: "normal | <number> | <length> | <percentage>", media: "visual", inherited: true, animationType: "numberOrLength", percentages: "referToElementFontSize", groups: [ "CSS Fonts" ], initial: "normal", appliesto: "allElements", computed: "absoluteLengthOrAsSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-height" }, "line-height-step": { syntax: "<length>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Fonts" ], initial: "0", appliesto: "blockContainers", computed: "absoluteLength", order: "perGrammar", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/line-height-step" }, "list-style": { syntax: "<'list-style-type'> || <'list-style-position'> || <'list-style-image'>", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: [ "list-style-type", "list-style-position", "list-style-image" ], appliesto: "listItems", computed: [ "list-style-image", "list-style-position", "list-style-type" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style" }, "list-style-image": { syntax: "<url> | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "none", appliesto: "listItems", computed: "noneOrImageWithAbsoluteURI", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-image" }, "list-style-position": { syntax: "inside | outside", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "outside", appliesto: "listItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-position" }, "list-style-type": { syntax: "<counter-style> | <string> | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Lists and Counters" ], initial: "disc", appliesto: "listItems", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/list-style-type" }, margin: margin, "margin-block": { syntax: "<'margin-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block" }, "margin-block-end": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "length", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block-end" }, "margin-block-start": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "length", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-block-start" }, "margin-bottom": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-bottom" }, "margin-inline": { syntax: "<'margin-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline" }, "margin-inline-end": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "length", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline-end" }, "margin-inline-start": { syntax: "<'margin-left'>", media: "visual", inherited: false, animationType: "length", percentages: "dependsOnLayoutModel", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsMargin", computed: "lengthAbsolutePercentageAsSpecifiedOtherwiseAuto", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-inline-start" }, "margin-left": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-left" }, "margin-right": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-right" }, "margin-top": { syntax: "<length> | <percentage> | auto", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-top" }, "margin-trim": { syntax: "none | in-flow | all", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "none", appliesto: "blockContainersAndMultiColumnContainers", computed: "asSpecified", order: "perGrammar", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/margin-trim" }, mask: mask, "mask-border": { syntax: "<'mask-border-source'> || <'mask-border-slice'> [ / <'mask-border-width'>? [ / <'mask-border-outset'> ]? ]? || <'mask-border-repeat'> || <'mask-border-mode'>", media: "visual", inherited: false, animationType: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], percentages: [ "mask-border-slice", "mask-border-width" ], groups: [ "CSS Masking" ], initial: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], appliesto: "allElementsSVGContainerElements", computed: [ "mask-border-mode", "mask-border-outset", "mask-border-repeat", "mask-border-slice", "mask-border-source", "mask-border-width" ], order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border" }, "mask-border-mode": { syntax: "luminance | alpha", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "alpha", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-mode" }, "mask-border-outset": { syntax: "[ <length> | <number> ]{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "0", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-outset" }, "mask-border-repeat": { syntax: "[ stretch | repeat | round | space ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "stretch", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-repeat" }, "mask-border-slice": { syntax: "<number-percentage>{1,4} fill?", media: "visual", inherited: false, animationType: "discrete", percentages: "referToSizeOfMaskBorderImage", groups: [ "CSS Masking" ], initial: "0", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-slice" }, "mask-border-source": { syntax: "none | <image>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-source" }, "mask-border-width": { syntax: "[ <length-percentage> | <number> | auto ]{1,4}", media: "visual", inherited: false, animationType: "discrete", percentages: "relativeToMaskBorderImageArea", groups: [ "CSS Masking" ], initial: "auto", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-border-width" }, "mask-clip": { syntax: "[ <geometry-box> | no-clip ]#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "border-box", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-clip" }, "mask-composite": { syntax: "<compositing-operator>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "add", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-composite" }, "mask-image": { syntax: "<mask-reference>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "none", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedURLsAbsolute", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-image" }, "mask-mode": { syntax: "<masking-mode>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "match-source", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-mode" }, "mask-origin": { syntax: "<geometry-box>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "border-box", appliesto: "allElementsSVGContainerElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-origin" }, "mask-position": { syntax: "<position>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToSizeOfMaskPaintingArea", groups: [ "CSS Masking" ], initial: "center", appliesto: "allElementsSVGContainerElements", computed: "consistsOfTwoKeywordsForOriginAndOffsets", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-position" }, "mask-repeat": { syntax: "<repeat-style>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "no-repeat", appliesto: "allElementsSVGContainerElements", computed: "consistsOfTwoDimensionKeywords", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-repeat" }, "mask-size": { syntax: "<bg-size>#", media: "visual", inherited: false, animationType: "repeatableListOfSimpleListOfLpc", percentages: "no", groups: [ "CSS Masking" ], initial: "auto", appliesto: "allElementsSVGContainerElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-size" }, "mask-type": { syntax: "luminance | alpha", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Masking" ], initial: "luminance", appliesto: "maskElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mask-type" }, "masonry-auto-flow": { syntax: "[ pack | next ] || [ definite-first | ordered ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Grid Layout" ], initial: "pack", appliesto: "gridContainersWithMasonryLayout", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/masonry-auto-flow" }, "math-style": { syntax: "normal | compact", media: "visual", inherited: true, animationType: "notAnimatable", percentages: "no", groups: [ "MathML" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/math-style" }, "max-block-size": { syntax: "<'max-width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMaxWidthAndMaxHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-block-size" }, "max-height": { syntax: "none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentagesNone", groups: [ "CSS Box Model" ], initial: "none", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAsSpecifiedAbsoluteLengthOrNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-height" }, "max-inline-size": { syntax: "<'max-width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMaxWidthAndMaxHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-inline-size" }, "max-lines": { syntax: "none | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Overflow" ], initial: "none", appliesto: "blockContainersExceptMultiColumnContainers", computed: "asSpecified", order: "perGrammar", status: "experimental" }, "max-width": { syntax: "none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "none", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAsSpecifiedAbsoluteLengthOrNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/max-width" }, "min-block-size": { syntax: "<'min-width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "blockSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMinWidthAndMinHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-block-size" }, "min-height": { syntax: "auto | <length> | <percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "regardingHeightOfGeneratedBoxContainingBlockPercentages0", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableColumns", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-height" }, "min-inline-size": { syntax: "<'min-width'>", media: "visual", inherited: false, animationType: "lpc", percentages: "inlineSizeOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "sameAsWidthAndHeight", computed: "sameAsMinWidthAndMinHeight", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-inline-size" }, "min-width": { syntax: "auto | <length> | <percentage> | min-content | max-content | fit-content(<length-percentage>)", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "allElementsButNonReplacedAndTableRows", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/min-width" }, "mix-blend-mode": { syntax: "<blend-mode>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Compositing and Blending" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/mix-blend-mode" }, "object-fit": { syntax: "fill | contain | cover | none | scale-down", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Images" ], initial: "fill", appliesto: "replacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/object-fit" }, "object-position": { syntax: "<position>", media: "visual", inherited: true, animationType: "repeatableListOfSimpleListOfLpc", percentages: "referToWidthAndHeightOfElement", groups: [ "CSS Images" ], initial: "50% 50%", appliesto: "replacedElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/object-position" }, offset: offset, "offset-anchor": { syntax: "auto | <position>", media: "visual", inherited: false, animationType: "position", percentages: "relativeToWidthAndHeight", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "standard" }, "offset-distance": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToTotalPathLength", groups: [ "CSS Motion Path" ], initial: "0", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-distance" }, "offset-path": { syntax: "none | ray( [ <angle> && <size> && contain? ] ) | <path()> | <url> | [ <basic-shape> || <geometry-box> ]", media: "visual", inherited: false, animationType: "angleOrBasicShapeOrPath", percentages: "no", groups: [ "CSS Motion Path" ], initial: "none", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-path" }, "offset-position": { syntax: "auto | <position>", media: "visual", inherited: false, animationType: "position", percentages: "referToSizeOfContainingBlock", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "perGrammar", status: "experimental" }, "offset-rotate": { syntax: "[ auto | reverse ] || <angle>", media: "visual", inherited: false, animationType: "angleOrBasicShapeOrPath", percentages: "no", groups: [ "CSS Motion Path" ], initial: "auto", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/offset-rotate" }, opacity: opacity, order: order, orphans: orphans, outline: outline, "outline-color": { syntax: "<color> | invert", media: [ "visual", "interactive" ], inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "invertOrCurrentColor", appliesto: "allElements", computed: "invertForTranslucentColorRGBAOtherwiseRGB", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-color" }, "outline-offset": { syntax: "<length>", media: [ "visual", "interactive" ], inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "0", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-offset" }, "outline-style": { syntax: "auto | <'border-style'>", media: [ "visual", "interactive" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-style" }, "outline-width": { syntax: "<line-width>", media: [ "visual", "interactive" ], inherited: false, animationType: "length", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "medium", appliesto: "allElements", computed: "absoluteLength0ForNone", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/outline-width" }, overflow: overflow, "overflow-anchor": { syntax: "auto | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Anchoring" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard" }, "overflow-block": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "auto", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecifiedButVisibleOrClipReplacedToAutoOrHiddenIfOtherValueDifferent", order: "perGrammar", status: "standard" }, "overflow-clip-box": { syntax: "padding-box | content-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Mozilla Extensions" ], initial: "padding-box", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Mozilla/CSS/overflow-clip-box" }, "overflow-inline": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "auto", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecifiedButVisibleOrClipReplacedToAutoOrHiddenIfOtherValueDifferent", order: "perGrammar", status: "standard" }, "overflow-wrap": { syntax: "normal | break-word | anywhere", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "nonReplacedInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-wrap" }, "overflow-x": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecifiedButVisibleOrClipReplacedToAutoOrHiddenIfOtherValueDifferent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-x" }, "overflow-y": { syntax: "visible | hidden | clip | scroll | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "visible", appliesto: "blockContainersFlexContainersGridContainers", computed: "asSpecifiedButVisibleOrClipReplacedToAutoOrHiddenIfOtherValueDifferent", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-y" }, "overscroll-behavior": { syntax: "[ contain | none | auto ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior" }, "overscroll-behavior-block": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-block" }, "overscroll-behavior-inline": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-inline" }, "overscroll-behavior-x": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-x" }, "overscroll-behavior-y": { syntax: "contain | none | auto", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Model" ], initial: "auto", appliesto: "nonReplacedBlockAndInlineBlockElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overscroll-behavior-y" }, padding: padding, "padding-block": { syntax: "<'padding-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block" }, "padding-block-end": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block-end" }, "padding-block-start": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-block-start" }, "padding-bottom": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-bottom" }, "padding-inline": { syntax: "<'padding-left'>{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline" }, "padding-inline-end": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline-end" }, "padding-inline-start": { syntax: "<'padding-left'>", media: "visual", inherited: false, animationType: "length", percentages: "logicalWidthOfContainingBlock", groups: [ "CSS Logical Properties" ], initial: "0", appliesto: "allElements", computed: "asLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-inline-start" }, "padding-left": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-left" }, "padding-right": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-right" }, "padding-top": { syntax: "<length> | <percentage>", media: "visual", inherited: false, animationType: "length", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Box Model" ], initial: "0", appliesto: "allElementsExceptInternalTableDisplayTypes", computed: "percentageAsSpecifiedOrAbsoluteLength", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/padding-top" }, "page-break-after": { syntax: "auto | always | avoid | left | right | recto | verso", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-after" }, "page-break-before": { syntax: "auto | always | avoid | left | right | recto | verso", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-before" }, "page-break-inside": { syntax: "auto | avoid", media: [ "visual", "paged" ], inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Pages" ], initial: "auto", appliesto: "blockElementsInNormalFlow", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/page-break-inside" }, "paint-order": { syntax: "normal | [ fill || stroke || markers ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "textElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/paint-order" }, perspective: perspective, "perspective-origin": { syntax: "<position>", media: "visual", inherited: false, animationType: "simpleListOfLpc", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "50% 50%", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "oneOrTwoValuesLengthAbsoluteKeywordsPercentages", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/perspective-origin" }, "place-content": { syntax: "<'align-content'> <'justify-content'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multilineFlexContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-content" }, "place-items": { syntax: "<'align-items'> <'justify-items'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "align-items", "justify-items" ], appliesto: "allElements", computed: [ "align-items", "justify-items" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-items" }, "place-self": { syntax: "<'align-self'> <'justify-self'>?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Box Alignment" ], initial: [ "align-self", "justify-self" ], appliesto: "blockLevelBoxesAndAbsolutelyPositionedBoxesAndGridItems", computed: [ "align-self", "justify-self" ], order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/place-self" }, "pointer-events": { syntax: "auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "Pointer Events" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/pointer-events" }, position: position$1, quotes: quotes, resize: resize, right: right, rotate: rotate, "row-gap": { syntax: "normal | <length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToDimensionOfContentArea", groups: [ "CSS Box Alignment" ], initial: "normal", appliesto: "multiColumnElementsFlexContainersGridContainers", computed: "asSpecifiedWithLengthsAbsoluteAndNormalComputingToZeroExceptMultiColumn", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/row-gap" }, "ruby-align": { syntax: "start | center | space-between | space-around", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "space-around", appliesto: "rubyBasesAnnotationsBaseAnnotationContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align" }, "ruby-merge": { syntax: "separate | collapse | auto", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "separate", appliesto: "rubyAnnotationsContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental" }, "ruby-position": { syntax: "over | under | inter-character", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Ruby" ], initial: "over", appliesto: "rubyAnnotationsContainers", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/ruby-position" }, scale: scale, "scrollbar-color": { syntax: "auto | dark | light | <color>{2}", media: "visual", inherited: true, animationType: "color", percentages: "no", groups: [ "CSS Scrollbars" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-color" }, "scrollbar-gutter": { syntax: "auto | [ stable | always ] && both? && force?", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Overflow" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-gutter" }, "scrollbar-width": { syntax: "auto | thin | none", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scrollbars" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width" }, "scroll-behavior": { syntax: "auto | smooth", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSSOM View" ], initial: "auto", appliesto: "scrollingBoxes", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-behavior" }, "scroll-margin": { syntax: "<length>{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin" }, "scroll-margin-block": { syntax: "<length>{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block" }, "scroll-margin-block-start": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block-start" }, "scroll-margin-block-end": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-block-end" }, "scroll-margin-bottom": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-bottom" }, "scroll-margin-inline": { syntax: "<length>{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline" }, "scroll-margin-inline-start": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline-start" }, "scroll-margin-inline-end": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-inline-end" }, "scroll-margin-left": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-left" }, "scroll-margin-right": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-right" }, "scroll-margin-top": { syntax: "<length>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "0", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-margin-top" }, "scroll-padding": { syntax: "[ auto | <length-percentage> ]{1,4}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding" }, "scroll-padding-block": { syntax: "[ auto | <length-percentage> ]{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block" }, "scroll-padding-block-start": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block-start" }, "scroll-padding-block-end": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-block-end" }, "scroll-padding-bottom": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-bottom" }, "scroll-padding-inline": { syntax: "[ auto | <length-percentage> ]{1,2}", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline" }, "scroll-padding-inline-start": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline-start" }, "scroll-padding-inline-end": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-inline-end" }, "scroll-padding-left": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-left" }, "scroll-padding-right": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-right" }, "scroll-padding-top": { syntax: "auto | <length-percentage>", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "relativeToTheScrollContainersScrollport", groups: [ "CSS Scroll Snap" ], initial: "auto", appliesto: "scrollContainers", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-padding-top" }, "scroll-snap-align": { syntax: "[ none | start | end | center ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-align" }, "scroll-snap-coordinate": { syntax: "none | <position>#", media: "interactive", inherited: false, animationType: "position", percentages: "referToBorderBox", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-coordinate" }, "scroll-snap-destination": { syntax: "<position>", media: "interactive", inherited: false, animationType: "position", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "0px 0px", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-destination" }, "scroll-snap-points-x": { syntax: "none | repeat( <length-percentage> )", media: "interactive", inherited: false, animationType: "discrete", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-points-x" }, "scroll-snap-points-y": { syntax: "none | repeat( <length-percentage> )", media: "interactive", inherited: false, animationType: "discrete", percentages: "relativeToScrollContainerPaddingBoxAxis", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-points-y" }, "scroll-snap-stop": { syntax: "normal | always", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-stop" }, "scroll-snap-type": { syntax: "none | [ x | y | block | inline | both ] [ mandatory | proximity ]?", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type" }, "scroll-snap-type-x": { syntax: "none | mandatory | proximity", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type-x" }, "scroll-snap-type-y": { syntax: "none | mandatory | proximity", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Scroll Snap" ], initial: "none", appliesto: "scrollContainers", computed: "asSpecified", order: "uniqueOrder", status: "obsolete", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/scroll-snap-type-y" }, "shape-image-threshold": { syntax: "<alpha-value>", media: "visual", inherited: false, animationType: "number", percentages: "no", groups: [ "CSS Shapes" ], initial: "0.0", appliesto: "floats", computed: "specifiedValueNumberClipped0To1", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-image-threshold" }, "shape-margin": { syntax: "<length-percentage>", media: "visual", inherited: false, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Shapes" ], initial: "0", appliesto: "floats", computed: "asSpecifiedRelativeToAbsoluteLengths", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-margin" }, "shape-outside": { syntax: "none | <shape-box> || <basic-shape> | <image>", media: "visual", inherited: false, animationType: "basicShapeOtherwiseNo", percentages: "no", groups: [ "CSS Shapes" ], initial: "none", appliesto: "floats", computed: "asDefinedForBasicShapeWithAbsoluteURIOtherwiseAsSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/shape-outside" }, "tab-size": { syntax: "<integer> | <length>", media: "visual", inherited: true, animationType: "length", percentages: "no", groups: [ "CSS Text" ], initial: "8", appliesto: "blockContainers", computed: "specifiedIntegerOrAbsoluteLength", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/tab-size" }, "table-layout": { syntax: "auto | fixed", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Table" ], initial: "auto", appliesto: "tableElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/table-layout" }, "text-align": { syntax: "start | end | left | right | center | justify | match-parent", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "startOrNamelessValueIfLTRRightIfRTL", appliesto: "blockContainers", computed: "asSpecifiedExceptMatchParent", order: "orderOfAppearance", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-align" }, "text-align-last": { syntax: "auto | start | end | left | right | center | justify", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "blockContainers", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-align-last" }, "text-combine-upright": { syntax: "none | all | [ digits <integer>? ]", media: "visual", inherited: true, animationType: "notAnimatable", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "none", appliesto: "nonReplacedInlineElements", computed: "keywordPlusIntegerIfDigits", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-combine-upright" }, "text-decoration": { syntax: "<'text-decoration-line'> || <'text-decoration-style'> || <'text-decoration-color'> || <'text-decoration-thickness'>", media: "visual", inherited: false, animationType: [ "text-decoration-color", "text-decoration-style", "text-decoration-line", "text-decoration-thickness" ], percentages: "no", groups: [ "CSS Text Decoration" ], initial: [ "text-decoration-color", "text-decoration-style", "text-decoration-line" ], appliesto: "allElements", computed: [ "text-decoration-line", "text-decoration-style", "text-decoration-color", "text-decoration-thickness" ], order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration" }, "text-decoration-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-color" }, "text-decoration-line": { syntax: "none | [ underline || overline || line-through || blink ] | spelling-error | grammar-error", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-line" }, "text-decoration-skip": { syntax: "none | [ objects || [ spaces | [ leading-spaces || trailing-spaces ] ] || edges || box-decoration ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "objects", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-skip" }, "text-decoration-skip-ink": { syntax: "auto | all | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-skip-ink" }, "text-decoration-style": { syntax: "solid | double | dotted | dashed | wavy", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "solid", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-style" }, "text-decoration-thickness": { syntax: "auto | from-font | <length> | <percentage> ", media: "visual", inherited: false, animationType: "byComputedValueType", percentages: "referToElementFontSize", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-decoration-thickness" }, "text-emphasis": { syntax: "<'text-emphasis-style'> || <'text-emphasis-color'>", media: "visual", inherited: false, animationType: [ "text-emphasis-color", "text-emphasis-style" ], percentages: "no", groups: [ "CSS Text Decoration" ], initial: [ "text-emphasis-style", "text-emphasis-color" ], appliesto: "allElements", computed: [ "text-emphasis-style", "text-emphasis-color" ], order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis" }, "text-emphasis-color": { syntax: "<color>", media: "visual", inherited: false, animationType: "color", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "currentcolor", appliesto: "allElements", computed: "computedColor", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-color" }, "text-emphasis-position": { syntax: "[ over | under ] && [ right | left ]", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "over right", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-position" }, "text-emphasis-style": { syntax: "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | <string>", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-emphasis-style" }, "text-indent": { syntax: "<length-percentage> && hanging? && each-line?", media: "visual", inherited: true, animationType: "lpc", percentages: "referToWidthOfContainingBlock", groups: [ "CSS Text" ], initial: "0", appliesto: "blockContainers", computed: "percentageOrAbsoluteLengthPlusKeywords", order: "lengthOrPercentageBeforeKeywords", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-indent" }, "text-justify": { syntax: "auto | inter-character | inter-word | none", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "auto", appliesto: "inlineLevelAndTableCellElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-justify" }, "text-orientation": { syntax: "mixed | upright | sideways", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "mixed", appliesto: "allElementsExceptTableRowGroupsRowsColumnGroupsAndColumns", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-orientation" }, "text-overflow": { syntax: "[ clip | ellipsis | <string> ]{1,2}", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "clip", appliesto: "blockContainerElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-overflow" }, "text-rendering": { syntax: "auto | optimizeSpeed | optimizeLegibility | geometricPrecision", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Miscellaneous" ], initial: "auto", appliesto: "textElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-rendering" }, "text-shadow": { syntax: "none | <shadow-t>#", media: "visual", inherited: true, animationType: "shadowList", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "none", appliesto: "allElements", computed: "colorPlusThreeAbsoluteLengths", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-shadow" }, "text-size-adjust": { syntax: "none | auto | <percentage>", media: "visual", inherited: true, animationType: "discrete", percentages: "referToSizeOfFont", groups: [ "CSS Text" ], initial: "autoForSmartphoneBrowsersSupportingInflation", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "experimental", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-size-adjust" }, "text-transform": { syntax: "none | capitalize | uppercase | lowercase | full-width | full-size-kana", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "none", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-transform" }, "text-underline-offset": { syntax: "auto | <length> | <percentage> ", media: "visual", inherited: true, animationType: "byComputedValueType", percentages: "referToElementFontSize", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-underline-offset" }, "text-underline-position": { syntax: "auto | from-font | [ under || [ left | right ] ]", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text Decoration" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "orderOfAppearance", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/text-underline-position" }, top: top, "touch-action": { syntax: "auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] || pinch-zoom ] | manipulation", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "Pointer Events" ], initial: "auto", appliesto: "allElementsExceptNonReplacedInlineElementsTableRowsColumnsRowColumnGroups", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/touch-action" }, transform: transform, "transform-box": { syntax: "content-box | border-box | fill-box | stroke-box | view-box", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "view-box", appliesto: "transformableElements", computed: "asSpecified", order: "perGrammar", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-box" }, "transform-origin": { syntax: "[ <length-percentage> | left | center | right | top | bottom ] | [ [ <length-percentage> | left | center | right ] && [ <length-percentage> | top | center | bottom ] ] <length>?", media: "visual", inherited: false, animationType: "simpleListOfLpc", percentages: "referToSizeOfBoundingBox", groups: [ "CSS Transforms" ], initial: "50% 50% 0", appliesto: "transformableElements", computed: "forLengthAbsoluteValueOtherwisePercentage", order: "oneOrTwoValuesLengthAbsoluteKeywordsPercentages", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-origin" }, "transform-style": { syntax: "flat | preserve-3d", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transforms" ], initial: "flat", appliesto: "transformableElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transform-style" }, transition: transition, "transition-delay": { syntax: "<time>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-delay" }, "transition-duration": { syntax: "<time>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "0s", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-duration" }, "transition-property": { syntax: "none | <single-transition-property>#", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "all", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-property" }, "transition-timing-function": { syntax: "<timing-function>#", media: "interactive", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Transitions" ], initial: "ease", appliesto: "allElementsAndPseudos", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/transition-timing-function" }, translate: translate, "unicode-bidi": { syntax: "normal | embed | isolate | bidi-override | isolate-override | plaintext", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "normal", appliesto: "allElementsSomeValuesNoEffectOnNonInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/unicode-bidi" }, "user-select": { syntax: "auto | text | none | contain | all", media: "visual", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Basic User Interface" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "nonstandard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/user-select" }, "vertical-align": { syntax: "baseline | sub | super | text-top | text-bottom | middle | top | bottom | <percentage> | <length>", media: "visual", inherited: false, animationType: "length", percentages: "referToLineHeight", groups: [ "CSS Table" ], initial: "baseline", appliesto: "inlineLevelAndTableCellElements", computed: "absoluteLengthOrKeyword", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/vertical-align" }, visibility: visibility, "white-space": { syntax: "normal | pre | nowrap | pre-wrap | pre-line | break-spaces", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/white-space" }, widows: widows, width: width, "will-change": { syntax: "auto | <animateable-feature>#", media: "all", inherited: false, animationType: "discrete", percentages: "no", groups: [ "CSS Will Change" ], initial: "auto", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/will-change" }, "word-break": { syntax: "normal | break-all | keep-all | break-word", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/word-break" }, "word-spacing": { syntax: "normal | <length-percentage>", media: "visual", inherited: true, animationType: "length", percentages: "referToWidthOfAffectedGlyph", groups: [ "CSS Text" ], initial: "normal", appliesto: "allElements", computed: "optimumMinAndMaxValueOfAbsoluteLengthPercentageOrNormal", order: "uniqueOrder", alsoAppliesTo: [ "::first-letter", "::first-line", "::placeholder" ], status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/word-spacing" }, "word-wrap": { syntax: "normal | break-word", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Text" ], initial: "normal", appliesto: "nonReplacedInlineElements", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/overflow-wrap" }, "writing-mode": { syntax: "horizontal-tb | vertical-rl | vertical-lr | sideways-rl | sideways-lr", media: "visual", inherited: true, animationType: "discrete", percentages: "no", groups: [ "CSS Writing Modes" ], initial: "horizontal-tb", appliesto: "allElementsExceptTableRowColumnGroupsTableRowsColumns", computed: "asSpecified", order: "uniqueOrder", status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/writing-mode" }, "z-index": { syntax: "auto | <integer>", media: "visual", inherited: false, animationType: "integer", percentages: "no", groups: [ "CSS Positioning" ], initial: "auto", appliesto: "positionedElements", computed: "asSpecified", order: "uniqueOrder", stacking: true, status: "standard", mdn_url: "https://developer.mozilla.org/docs/Web/CSS/z-index" }, zoom: zoom }; var attachment = { syntax: "scroll | fixed | local" }; var box = { syntax: "border-box | padding-box | content-box" }; var color = { syntax: "<rgb()> | <rgba()> | <hsl()> | <hsla()> | <hex-color> | <named-color> | currentcolor | <deprecated-system-color>" }; var combinator = { syntax: "'>' | '+' | '~' | [ '||' ]" }; var gradient = { syntax: "<linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()> | <conic-gradient()>" }; var hue = { syntax: "<number> | <angle>" }; var image = { syntax: "<url> | <image()> | <image-set()> | <element()> | <paint()> | <cross-fade()> | <gradient>" }; var nth$1 = { syntax: "<an-plus-b> | even | odd" }; var position = { syntax: "[ [ left | center | right ] || [ top | center | bottom ] | [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]? | [ [ left | right ] <length-percentage> ] && [ [ top | bottom ] <length-percentage> ] ]" }; var quote = { syntax: "open-quote | close-quote | no-open-quote | no-close-quote" }; var shadow = { syntax: "inset? && <length>{2,4} && <color>?" }; var shape = { syntax: "rect(<top>, <right>, <bottom>, <left>)" }; var size = { syntax: "closest-side | farthest-side | closest-corner | farthest-corner | <length> | <length-percentage>{2}" }; var symbol = { syntax: "<string> | <image> | <custom-ident>" }; var target = { syntax: "<target-counter()> | <target-counters()> | <target-text()>" }; var require$$2 = { "absolute-size": { syntax: "xx-small | x-small | small | medium | large | x-large | xx-large | xxx-large" }, "alpha-value": { syntax: "<number> | <percentage>" }, "angle-percentage": { syntax: "<angle> | <percentage>" }, "angular-color-hint": { syntax: "<angle-percentage>" }, "angular-color-stop": { syntax: "<color> && <color-stop-angle>?" }, "angular-color-stop-list": { syntax: "[ <angular-color-stop> [, <angular-color-hint>]? ]# , <angular-color-stop>" }, "animateable-feature": { syntax: "scroll-position | contents | <custom-ident>" }, attachment: attachment, "attr()": { syntax: "attr( <attr-name> <type-or-unit>? [, <attr-fallback> ]? )" }, "attr-matcher": { syntax: "[ '~' | '|' | '^' | '$' | '*' ]? '='" }, "attr-modifier": { syntax: "i | s" }, "attribute-selector": { syntax: "'[' <wq-name> ']' | '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'" }, "auto-repeat": { syntax: "repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )" }, "auto-track-list": { syntax: "[ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>? <auto-repeat>\n[ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?" }, "baseline-position": { syntax: "[ first | last ]? baseline" }, "basic-shape": { syntax: "<inset()> | <circle()> | <ellipse()> | <polygon()> | <path()>" }, "bg-image": { syntax: "none | <image>" }, "bg-layer": { syntax: "<bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>" }, "bg-position": { syntax: "[ [ left | center | right | top | bottom | <length-percentage> ] | [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ] | [ center | [ left | right ] <length-percentage>? ] && [ center | [ top | bottom ] <length-percentage>? ] ]" }, "bg-size": { syntax: "[ <length-percentage> | auto ]{1,2} | cover | contain" }, "blur()": { syntax: "blur( <length> )" }, "blend-mode": { syntax: "normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity" }, box: box, "brightness()": { syntax: "brightness( <number-percentage> )" }, "calc()": { syntax: "calc( <calc-sum> )" }, "calc-sum": { syntax: "<calc-product> [ [ '+' | '-' ] <calc-product> ]*" }, "calc-product": { syntax: "<calc-value> [ '*' <calc-value> | '/' <number> ]*" }, "calc-value": { syntax: "<number> | <dimension> | <percentage> | ( <calc-sum> )" }, "cf-final-image": { syntax: "<image> | <color>" }, "cf-mixing-image": { syntax: "<percentage>? && <image>" }, "circle()": { syntax: "circle( [ <shape-radius> ]? [ at <position> ]? )" }, "clamp()": { syntax: "clamp( <calc-sum>#{3} )" }, "class-selector": { syntax: "'.' <ident-token>" }, "clip-source": { syntax: "<url>" }, color: color, "color-stop": { syntax: "<color-stop-length> | <color-stop-angle>" }, "color-stop-angle": { syntax: "<angle-percentage>{1,2}" }, "color-stop-length": { syntax: "<length-percentage>{1,2}" }, "color-stop-list": { syntax: "[ <linear-color-stop> [, <linear-color-hint>]? ]# , <linear-color-stop>" }, combinator: combinator, "common-lig-values": { syntax: "[ common-ligatures | no-common-ligatures ]" }, "compat-auto": { syntax: "searchfield | textarea | push-button | slider-horizontal | checkbox | radio | square-button | menulist | listbox | meter | progress-bar | button" }, "composite-style": { syntax: "clear | copy | source-over | source-in | source-out | source-atop | destination-over | destination-in | destination-out | destination-atop | xor" }, "compositing-operator": { syntax: "add | subtract | intersect | exclude" }, "compound-selector": { syntax: "[ <type-selector>? <subclass-selector>* [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!" }, "compound-selector-list": { syntax: "<compound-selector>#" }, "complex-selector": { syntax: "<compound-selector> [ <combinator>? <compound-selector> ]*" }, "complex-selector-list": { syntax: "<complex-selector>#" }, "conic-gradient()": { syntax: "conic-gradient( [ from <angle> ]? [ at <position> ]?, <angular-color-stop-list> )" }, "contextual-alt-values": { syntax: "[ contextual | no-contextual ]" }, "content-distribution": { syntax: "space-between | space-around | space-evenly | stretch" }, "content-list": { syntax: "[ <string> | contents | <image> | <quote> | <target> | <leader()> ]+" }, "content-position": { syntax: "center | start | end | flex-start | flex-end" }, "content-replacement": { syntax: "<image>" }, "contrast()": { syntax: "contrast( [ <number-percentage> ] )" }, "counter()": { syntax: "counter( <custom-ident>, <counter-style>? )" }, "counter-style": { syntax: "<counter-style-name> | symbols()" }, "counter-style-name": { syntax: "<custom-ident>" }, "counters()": { syntax: "counters( <custom-ident>, <string>, <counter-style>? )" }, "cross-fade()": { syntax: "cross-fade( <cf-mixing-image> , <cf-final-image>? )" }, "cubic-bezier-timing-function": { syntax: "ease | ease-in | ease-out | ease-in-out | cubic-bezier(<number [0,1]>, <number>, <number [0,1]>, <number>)" }, "deprecated-system-color": { syntax: "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonFace | ButtonHighlight | ButtonShadow | ButtonText | CaptionText | GrayText | Highlight | HighlightText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, "discretionary-lig-values": { syntax: "[ discretionary-ligatures | no-discretionary-ligatures ]" }, "display-box": { syntax: "contents | none" }, "display-inside": { syntax: "flow | flow-root | table | flex | grid | ruby" }, "display-internal": { syntax: "table-row-group | table-header-group | table-footer-group | table-row | table-cell | table-column-group | table-column | table-caption | ruby-base | ruby-text | ruby-base-container | ruby-text-container" }, "display-legacy": { syntax: "inline-block | inline-list-item | inline-table | inline-flex | inline-grid" }, "display-listitem": { syntax: "<display-outside>? && [ flow | flow-root ]? && list-item" }, "display-outside": { syntax: "block | inline | run-in" }, "drop-shadow()": { syntax: "drop-shadow( <length>{2,3} <color>? )" }, "east-asian-variant-values": { syntax: "[ jis78 | jis83 | jis90 | jis04 | simplified | traditional ]" }, "east-asian-width-values": { syntax: "[ full-width | proportional-width ]" }, "element()": { syntax: "element( <id-selector> )" }, "ellipse()": { syntax: "ellipse( [ <shape-radius>{2} ]? [ at <position> ]? )" }, "ending-shape": { syntax: "circle | ellipse" }, "env()": { syntax: "env( <custom-ident> , <declaration-value>? )" }, "explicit-track-list": { syntax: "[ <line-names>? <track-size> ]+ <line-names>?" }, "family-name": { syntax: "<string> | <custom-ident>+" }, "feature-tag-value": { syntax: "<string> [ <integer> | on | off ]?" }, "feature-type": { syntax: "@stylistic | @historical-forms | @styleset | @character-variant | @swash | @ornaments | @annotation" }, "feature-value-block": { syntax: "<feature-type> '{' <feature-value-declaration-list> '}'" }, "feature-value-block-list": { syntax: "<feature-value-block>+" }, "feature-value-declaration": { syntax: "<custom-ident>: <integer>+;" }, "feature-value-declaration-list": { syntax: "<feature-value-declaration>" }, "feature-value-name": { syntax: "<custom-ident>" }, "fill-rule": { syntax: "nonzero | evenodd" }, "filter-function": { syntax: "<blur()> | <brightness()> | <contrast()> | <drop-shadow()> | <grayscale()> | <hue-rotate()> | <invert()> | <opacity()> | <saturate()> | <sepia()>" }, "filter-function-list": { syntax: "[ <filter-function> | <url> ]+" }, "final-bg-layer": { syntax: "<'background-color'> || <bg-image> || <bg-position> [ / <bg-size> ]? || <repeat-style> || <attachment> || <box> || <box>" }, "fit-content()": { syntax: "fit-content( [ <length> | <percentage> ] )" }, "fixed-breadth": { syntax: "<length-percentage>" }, "fixed-repeat": { syntax: "repeat( [ <positive-integer> ] , [ <line-names>? <fixed-size> ]+ <line-names>? )" }, "fixed-size": { syntax: "<fixed-breadth> | minmax( <fixed-breadth> , <track-breadth> ) | minmax( <inflexible-breadth> , <fixed-breadth> )" }, "font-stretch-absolute": { syntax: "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | <percentage>" }, "font-variant-css21": { syntax: "[ normal | small-caps ]" }, "font-weight-absolute": { syntax: "normal | bold | <number [1,1000]>" }, "frequency-percentage": { syntax: "<frequency> | <percentage>" }, "general-enclosed": { syntax: "[ <function-token> <any-value> ) ] | ( <ident> <any-value> )" }, "generic-family": { syntax: "serif | sans-serif | cursive | fantasy | monospace" }, "generic-name": { syntax: "serif | sans-serif | cursive | fantasy | monospace" }, "geometry-box": { syntax: "<shape-box> | fill-box | stroke-box | view-box" }, gradient: gradient, "grayscale()": { syntax: "grayscale( <number-percentage> )" }, "grid-line": { syntax: "auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]" }, "historical-lig-values": { syntax: "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { syntax: "hsl( <hue> <percentage> <percentage> [ / <alpha-value> ]? ) | hsl( <hue>, <percentage>, <percentage>, <alpha-value>? )" }, "hsla()": { syntax: "hsla( <hue> <percentage> <percentage> [ / <alpha-value> ]? ) | hsla( <hue>, <percentage>, <percentage>, <alpha-value>? )" }, hue: hue, "hue-rotate()": { syntax: "hue-rotate( <angle> )" }, "id-selector": { syntax: "<hash-token>" }, image: image, "image()": { syntax: "image( <image-tags>? [ <image-src>? , <color>? ]! )" }, "image-set()": { syntax: "image-set( <image-set-option># )" }, "image-set-option": { syntax: "[ <image> | <string> ] <resolution>" }, "image-src": { syntax: "<url> | <string>" }, "image-tags": { syntax: "ltr | rtl" }, "inflexible-breadth": { syntax: "<length> | <percentage> | min-content | max-content | auto" }, "inset()": { syntax: "inset( <length-percentage>{1,4} [ round <'border-radius'> ]? )" }, "invert()": { syntax: "invert( <number-percentage> )" }, "keyframes-name": { syntax: "<custom-ident> | <string>" }, "keyframe-block": { syntax: "<keyframe-selector># {\n <declaration-list>\n}" }, "keyframe-block-list": { syntax: "<keyframe-block>+" }, "keyframe-selector": { syntax: "from | to | <percentage>" }, "leader()": { syntax: "leader( <leader-type> )" }, "leader-type": { syntax: "dotted | solid | space | <string>" }, "length-percentage": { syntax: "<length> | <percentage>" }, "line-names": { syntax: "'[' <custom-ident>* ']'" }, "line-name-list": { syntax: "[ <line-names> | <name-repeat> ]+" }, "line-style": { syntax: "none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset" }, "line-width": { syntax: "<length> | thin | medium | thick" }, "linear-color-hint": { syntax: "<length-percentage>" }, "linear-color-stop": { syntax: "<color> <color-stop-length>?" }, "linear-gradient()": { syntax: "linear-gradient( [ <angle> | to <side-or-corner> ]? , <color-stop-list> )" }, "mask-layer": { syntax: "<mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> || <geometry-box> || [ <geometry-box> | no-clip ] || <compositing-operator> || <masking-mode>" }, "mask-position": { syntax: "[ <length-percentage> | left | center | right ] [ <length-percentage> | top | center | bottom ]?" }, "mask-reference": { syntax: "none | <image> | <mask-source>" }, "mask-source": { syntax: "<url>" }, "masking-mode": { syntax: "alpha | luminance | match-source" }, "matrix()": { syntax: "matrix( <number>#{6} )" }, "matrix3d()": { syntax: "matrix3d( <number>#{16} )" }, "max()": { syntax: "max( <calc-sum># )" }, "media-and": { syntax: "<media-in-parens> [ and <media-in-parens> ]+" }, "media-condition": { syntax: "<media-not> | <media-and> | <media-or> | <media-in-parens>" }, "media-condition-without-or": { syntax: "<media-not> | <media-and> | <media-in-parens>" }, "media-feature": { syntax: "( [ <mf-plain> | <mf-boolean> | <mf-range> ] )" }, "media-in-parens": { syntax: "( <media-condition> ) | <media-feature> | <general-enclosed>" }, "media-not": { syntax: "not <media-in-parens>" }, "media-or": { syntax: "<media-in-parens> [ or <media-in-parens> ]+" }, "media-query": { syntax: "<media-condition> | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?" }, "media-query-list": { syntax: "<media-query>#" }, "media-type": { syntax: "<ident>" }, "mf-boolean": { syntax: "<mf-name>" }, "mf-name": { syntax: "<ident>" }, "mf-plain": { syntax: "<mf-name> : <mf-value>" }, "mf-range": { syntax: "<mf-name> [ '<' | '>' ]? '='? <mf-value>\n| <mf-value> [ '<' | '>' ]? '='? <mf-name>\n| <mf-value> '<' '='? <mf-name> '<' '='? <mf-value>\n| <mf-value> '>' '='? <mf-name> '>' '='? <mf-value>" }, "mf-value": { syntax: "<number> | <dimension> | <ident> | <ratio>" }, "min()": { syntax: "min( <calc-sum># )" }, "minmax()": { syntax: "minmax( [ <length> | <percentage> | min-content | max-content | auto ] , [ <length> | <percentage> | <flex> | min-content | max-content | auto ] )" }, "named-color": { syntax: "transparent | aliceblue | antiquewhite | aqua | aquamarine | azure | beige | bisque | black | blanchedalmond | blue | blueviolet | brown | burlywood | cadetblue | chartreuse | chocolate | coral | cornflowerblue | cornsilk | crimson | cyan | darkblue | darkcyan | darkgoldenrod | darkgray | darkgreen | darkgrey | darkkhaki | darkmagenta | darkolivegreen | darkorange | darkorchid | darkred | darksalmon | darkseagreen | darkslateblue | darkslategray | darkslategrey | darkturquoise | darkviolet | deeppink | deepskyblue | dimgray | dimgrey | dodgerblue | firebrick | floralwhite | forestgreen | fuchsia | gainsboro | ghostwhite | gold | goldenrod | gray | green | greenyellow | grey | honeydew | hotpink | indianred | indigo | ivory | khaki | lavender | lavenderblush | lawngreen | lemonchiffon | lightblue | lightcoral | lightcyan | lightgoldenrodyellow | lightgray | lightgreen | lightgrey | lightpink | lightsalmon | lightseagreen | lightskyblue | lightslategray | lightslategrey | lightsteelblue | lightyellow | lime | limegreen | linen | magenta | maroon | mediumaquamarine | mediumblue | mediumorchid | mediumpurple | mediumseagreen | mediumslateblue | mediumspringgreen | mediumturquoise | mediumvioletred | midnightblue | mintcream | mistyrose | moccasin | navajowhite | navy | oldlace | olive | olivedrab | orange | orangered | orchid | palegoldenrod | palegreen | paleturquoise | palevioletred | papayawhip | peachpuff | peru | pink | plum | powderblue | purple | rebeccapurple | red | rosybrown | royalblue | saddlebrown | salmon | sandybrown | seagreen | seashell | sienna | silver | skyblue | slateblue | slategray | slategrey | snow | springgreen | steelblue | tan | teal | thistle | tomato | turquoise | violet | wheat | white | whitesmoke | yellow | yellowgreen" }, "namespace-prefix": { syntax: "<ident>" }, "ns-prefix": { syntax: "[ <ident-token> | '*' ]? '|'" }, "number-percentage": { syntax: "<number> | <percentage>" }, "numeric-figure-values": { syntax: "[ lining-nums | oldstyle-nums ]" }, "numeric-fraction-values": { syntax: "[ diagonal-fractions | stacked-fractions ]" }, "numeric-spacing-values": { syntax: "[ proportional-nums | tabular-nums ]" }, nth: nth$1, "opacity()": { syntax: "opacity( [ <number-percentage> ] )" }, "overflow-position": { syntax: "unsafe | safe" }, "outline-radius": { syntax: "<length> | <percentage>" }, "page-body": { syntax: "<declaration>? [ ; <page-body> ]? | <page-margin-box> <page-body>" }, "page-margin-box": { syntax: "<page-margin-box-type> '{' <declaration-list> '}'" }, "page-margin-box-type": { syntax: "@top-left-corner | @top-left | @top-center | @top-right | @top-right-corner | @bottom-left-corner | @bottom-left | @bottom-center | @bottom-right | @bottom-right-corner | @left-top | @left-middle | @left-bottom | @right-top | @right-middle | @right-bottom" }, "page-selector-list": { syntax: "[ <page-selector># ]?" }, "page-selector": { syntax: "<pseudo-page>+ | <ident> <pseudo-page>*" }, "path()": { syntax: "path( [ <fill-rule>, ]? <string> )" }, "paint()": { syntax: "paint( <ident>, <declaration-value>? )" }, "perspective()": { syntax: "perspective( <length> )" }, "polygon()": { syntax: "polygon( <fill-rule>? , [ <length-percentage> <length-percentage> ]# )" }, position: position, "pseudo-class-selector": { syntax: "':' <ident-token> | ':' <function-token> <any-value> ')'" }, "pseudo-element-selector": { syntax: "':' <pseudo-class-selector>" }, "pseudo-page": { syntax: ": [ left | right | first | blank ]" }, quote: quote, "radial-gradient()": { syntax: "radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )" }, "relative-selector": { syntax: "<combinator>? <complex-selector>" }, "relative-selector-list": { syntax: "<relative-selector>#" }, "relative-size": { syntax: "larger | smaller" }, "repeat-style": { syntax: "repeat-x | repeat-y | [ repeat | space | round | no-repeat ]{1,2}" }, "repeating-linear-gradient()": { syntax: "repeating-linear-gradient( [ <angle> | to <side-or-corner> ]? , <color-stop-list> )" }, "repeating-radial-gradient()": { syntax: "repeating-radial-gradient( [ <ending-shape> || <size> ]? [ at <position> ]? , <color-stop-list> )" }, "rgb()": { syntax: "rgb( <percentage>{3} [ / <alpha-value> ]? ) | rgb( <number>{3} [ / <alpha-value> ]? ) | rgb( <percentage>#{3} , <alpha-value>? ) | rgb( <number>#{3} , <alpha-value>? )" }, "rgba()": { syntax: "rgba( <percentage>{3} [ / <alpha-value> ]? ) | rgba( <number>{3} [ / <alpha-value> ]? ) | rgba( <percentage>#{3} , <alpha-value>? ) | rgba( <number>#{3} , <alpha-value>? )" }, "rotate()": { syntax: "rotate( [ <angle> | <zero> ] )" }, "rotate3d()": { syntax: "rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )" }, "rotateX()": { syntax: "rotateX( [ <angle> | <zero> ] )" }, "rotateY()": { syntax: "rotateY( [ <angle> | <zero> ] )" }, "rotateZ()": { syntax: "rotateZ( [ <angle> | <zero> ] )" }, "saturate()": { syntax: "saturate( <number-percentage> )" }, "scale()": { syntax: "scale( <number> , <number>? )" }, "scale3d()": { syntax: "scale3d( <number> , <number> , <number> )" }, "scaleX()": { syntax: "scaleX( <number> )" }, "scaleY()": { syntax: "scaleY( <number> )" }, "scaleZ()": { syntax: "scaleZ( <number> )" }, "self-position": { syntax: "center | start | end | self-start | self-end | flex-start | flex-end" }, "shape-radius": { syntax: "<length-percentage> | closest-side | farthest-side" }, "skew()": { syntax: "skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )" }, "skewX()": { syntax: "skewX( [ <angle> | <zero> ] )" }, "skewY()": { syntax: "skewY( [ <angle> | <zero> ] )" }, "sepia()": { syntax: "sepia( <number-percentage> )" }, shadow: shadow, "shadow-t": { syntax: "[ <length>{2,3} && <color>? ]" }, shape: shape, "shape-box": { syntax: "<box> | margin-box" }, "side-or-corner": { syntax: "[ left | right ] || [ top | bottom ]" }, "single-animation": { syntax: "<time> || <timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ]" }, "single-animation-direction": { syntax: "normal | reverse | alternate | alternate-reverse" }, "single-animation-fill-mode": { syntax: "none | forwards | backwards | both" }, "single-animation-iteration-count": { syntax: "infinite | <number>" }, "single-animation-play-state": { syntax: "running | paused" }, "single-transition": { syntax: "[ none | <single-transition-property> ] || <time> || <timing-function> || <time>" }, "single-transition-property": { syntax: "all | <custom-ident>" }, size: size, "step-position": { syntax: "jump-start | jump-end | jump-none | jump-both | start | end" }, "step-timing-function": { syntax: "step-start | step-end | steps(<integer>[, <step-position>]?)" }, "subclass-selector": { syntax: "<id-selector> | <class-selector> | <attribute-selector> | <pseudo-class-selector>" }, "supports-condition": { syntax: "not <supports-in-parens> | <supports-in-parens> [ and <supports-in-parens> ]* | <supports-in-parens> [ or <supports-in-parens> ]*" }, "supports-in-parens": { syntax: "( <supports-condition> ) | <supports-feature> | <general-enclosed>" }, "supports-feature": { syntax: "<supports-decl> | <supports-selector-fn>" }, "supports-decl": { syntax: "( <declaration> )" }, "supports-selector-fn": { syntax: "selector( <complex-selector> )" }, symbol: symbol, target: target, "target-counter()": { syntax: "target-counter( [ <string> | <url> ] , <custom-ident> , <counter-style>? )" }, "target-counters()": { syntax: "target-counters( [ <string> | <url> ] , <custom-ident> , <string> , <counter-style>? )" }, "target-text()": { syntax: "target-text( [ <string> | <url> ] , [ content | before | after | first-letter ]? )" }, "time-percentage": { syntax: "<time> | <percentage>" }, "timing-function": { syntax: "linear | <cubic-bezier-timing-function> | <step-timing-function>" }, "track-breadth": { syntax: "<length-percentage> | <flex> | min-content | max-content | auto" }, "track-list": { syntax: "[ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?" }, "track-repeat": { syntax: "repeat( [ <positive-integer> ] , [ <line-names>? <track-size> ]+ <line-names>? )" }, "track-size": { syntax: "<track-breadth> | minmax( <inflexible-breadth> , <track-breadth> ) | fit-content( [ <length> | <percentage> ] )" }, "transform-function": { syntax: "<matrix()> | <translate()> | <translateX()> | <translateY()> | <scale()> | <scaleX()> | <scaleY()> | <rotate()> | <skew()> | <skewX()> | <skewY()> | <matrix3d()> | <translate3d()> | <translateZ()> | <scale3d()> | <scaleZ()> | <rotate3d()> | <rotateX()> | <rotateY()> | <rotateZ()> | <perspective()>" }, "transform-list": { syntax: "<transform-function>+" }, "translate()": { syntax: "translate( <length-percentage> , <length-percentage>? )" }, "translate3d()": { syntax: "translate3d( <length-percentage> , <length-percentage> , <length> )" }, "translateX()": { syntax: "translateX( <length-percentage> )" }, "translateY()": { syntax: "translateY( <length-percentage> )" }, "translateZ()": { syntax: "translateZ( <length> )" }, "type-or-unit": { syntax: "string | color | url | integer | number | length | angle | time | frequency | cap | ch | em | ex | ic | lh | rlh | rem | vb | vi | vw | vh | vmin | vmax | mm | Q | cm | in | pt | pc | px | deg | grad | rad | turn | ms | s | Hz | kHz | %" }, "type-selector": { syntax: "<wq-name> | <ns-prefix>? '*'" }, "var()": { syntax: "var( <custom-property-name> , <declaration-value>? )" }, "viewport-length": { syntax: "auto | <length-percentage>" }, "wq-name": { syntax: "<ns-prefix>? <ident-token>" } }; var atrules = { charset: { prelude: "<string>" }, "font-face": { descriptors: { "unicode-range": { comment: "replaces <unicode-range>, an old production name", syntax: "<urange>#" } } } }; var properties = { "-moz-background-clip": { comment: "deprecated syntax in old Firefox, https://developer.mozilla.org/en/docs/Web/CSS/background-clip", syntax: "padding | border" }, "-moz-border-radius-bottomleft": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-left-radius", syntax: "<'border-bottom-left-radius'>" }, "-moz-border-radius-bottomright": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius", syntax: "<'border-bottom-right-radius'>" }, "-moz-border-radius-topleft": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-left-radius", syntax: "<'border-top-left-radius'>" }, "-moz-border-radius-topright": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius", syntax: "<'border-bottom-right-radius'>" }, "-moz-control-character-visibility": { comment: "firefox specific keywords, https://bugzilla.mozilla.org/show_bug.cgi?id=947588", syntax: "visible | hidden" }, "-moz-osx-font-smoothing": { comment: "misssed old syntax https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth", syntax: "auto | grayscale" }, "-moz-user-select": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/user-select", syntax: "none | text | all | -moz-none" }, "-ms-flex-align": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align", syntax: "start | end | center | baseline | stretch" }, "-ms-flex-item-align": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align", syntax: "auto | start | end | center | baseline | stretch" }, "-ms-flex-line-pack": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack", syntax: "start | end | center | justify | distribute | stretch" }, "-ms-flex-negative": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-shrink'>" }, "-ms-flex-pack": { comment: "misssed old syntax implemented in IE, https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack", syntax: "start | end | center | justify | distribute" }, "-ms-flex-order": { comment: "misssed old syntax implemented in IE; https://msdn.microsoft.com/en-us/library/jj127303(v=vs.85).aspx", syntax: "<integer>" }, "-ms-flex-positive": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-grow'>" }, "-ms-flex-preferred-size": { comment: "misssed old syntax implemented in IE; TODO: find references for comfirmation", syntax: "<'flex-basis'>" }, "-ms-interpolation-mode": { comment: "https://msdn.microsoft.com/en-us/library/ff521095(v=vs.85).aspx", syntax: "nearest-neighbor | bicubic" }, "-ms-grid-column-align": { comment: "add this property first since it uses as fallback for flexbox, https://msdn.microsoft.com/en-us/library/windows/apps/hh466338.aspx", syntax: "start | end | center | stretch" }, "-ms-grid-row-align": { comment: "add this property first since it uses as fallback for flexbox, https://msdn.microsoft.com/en-us/library/windows/apps/hh466348.aspx", syntax: "start | end | center | stretch" }, "-ms-hyphenate-limit-last": { comment: "misssed old syntax implemented in IE; https://www.w3.org/TR/css-text-4/#hyphenate-line-limits", syntax: "none | always | column | page | spread" }, "-webkit-appearance": { comment: "webkit specific keywords", references: [ "http://css-infos.net/property/-webkit-appearance" ], syntax: "none | button | button-bevel | caps-lock-indicator | caret | checkbox | default-button | inner-spin-button | listbox | listitem | media-controls-background | media-controls-fullscreen-background | media-current-time-display | media-enter-fullscreen-button | media-exit-fullscreen-button | media-fullscreen-button | media-mute-button | media-overlay-play-button | media-play-button | media-seek-back-button | media-seek-forward-button | media-slider | media-sliderthumb | media-time-remaining-display | media-toggle-closed-captions-button | media-volume-slider | media-volume-slider-container | media-volume-sliderthumb | menulist | menulist-button | menulist-text | menulist-textfield | meter | progress-bar | progress-bar-value | push-button | radio | scrollbarbutton-down | scrollbarbutton-left | scrollbarbutton-right | scrollbarbutton-up | scrollbargripper-horizontal | scrollbargripper-vertical | scrollbarthumb-horizontal | scrollbarthumb-vertical | scrollbartrack-horizontal | scrollbartrack-vertical | searchfield | searchfield-cancel-button | searchfield-decoration | searchfield-results-button | searchfield-results-decoration | slider-horizontal | slider-vertical | sliderthumb-horizontal | sliderthumb-vertical | square-button | textarea | textfield | -apple-pay-button" }, "-webkit-background-clip": { comment: "https://developer.mozilla.org/en/docs/Web/CSS/background-clip", syntax: "[ <box> | border | padding | content | text ]#" }, "-webkit-column-break-after": { comment: "added, http://help.dottoro.com/lcrthhhv.php", syntax: "always | auto | avoid" }, "-webkit-column-break-before": { comment: "added, http://help.dottoro.com/lcxquvkf.php", syntax: "always | auto | avoid" }, "-webkit-column-break-inside": { comment: "added, http://help.dottoro.com/lclhnthl.php", syntax: "always | auto | avoid" }, "-webkit-font-smoothing": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth", syntax: "auto | none | antialiased | subpixel-antialiased" }, "-webkit-mask-box-image": { comment: "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-box-image", syntax: "[ <url> | <gradient> | none ] [ <length-percentage>{4} <-webkit-mask-box-repeat>{2} ]?" }, "-webkit-print-color-adjust": { comment: "missed", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/-webkit-print-color-adjust" ], syntax: "economy | exact" }, "-webkit-text-security": { comment: "missed; http://help.dottoro.com/lcbkewgt.php", syntax: "none | circle | disc | square" }, "-webkit-user-drag": { comment: "missed; http://help.dottoro.com/lcbixvwm.php", syntax: "none | element | auto" }, "-webkit-user-select": { comment: "auto is supported by old webkit, https://developer.mozilla.org/en-US/docs/Web/CSS/user-select", syntax: "auto | none | text | all" }, "alignment-baseline": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#AlignmentBaselineProperty" ], syntax: "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical" }, "baseline-shift": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#BaselineShiftProperty" ], syntax: "baseline | sub | super | <svg-length>" }, behavior: { comment: "added old IE property https://msdn.microsoft.com/en-us/library/ms530723(v=vs.85).aspx", syntax: "<url>+" }, "clip-rule": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/masking.html#ClipRuleProperty" ], syntax: "nonzero | evenodd" }, cue: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'cue-before'> <'cue-after'>?" }, "cue-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<url> <decibel>? | none" }, "cue-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<url> <decibel>? | none" }, cursor: { comment: "added legacy keywords: hand, -webkit-grab. -webkit-grabbing, -webkit-zoom-in, -webkit-zoom-out, -moz-grab, -moz-grabbing, -moz-zoom-in, -moz-zoom-out", references: [ "https://www.sitepoint.com/css3-cursor-styles/" ], syntax: "[ [ <url> [ <x> <y> ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]" }, display: { comment: "extended with -ms-flexbox", syntax: "| <-non-standard-display>" }, position: { comment: "extended with -webkit-sticky", syntax: "| -webkit-sticky" }, "dominant-baseline": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#DominantBaselineProperty" ], syntax: "auto | use-script | no-change | reset-size | ideographic | alphabetic | hanging | mathematical | central | middle | text-after-edge | text-before-edge" }, "image-rendering": { comment: "extended with <-non-standard-image-rendering>, added SVG keywords optimizeSpeed and optimizeQuality", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/image-rendering", "https://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty" ], syntax: "| optimizeSpeed | optimizeQuality | <-non-standard-image-rendering>" }, fill: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "<paint>" }, "fill-opacity": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "<number-zero-one>" }, "fill-rule": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#FillProperty" ], syntax: "nonzero | evenodd" }, filter: { comment: "extend with IE legacy syntaxes", syntax: "| <-ms-filter-function-list>" }, "glyph-orientation-horizontal": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#GlyphOrientationHorizontalProperty" ], syntax: "<angle>" }, "glyph-orientation-vertical": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#GlyphOrientationVerticalProperty" ], syntax: "<angle>" }, kerning: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#KerningProperty" ], syntax: "auto | <svg-length>" }, "letter-spacing": { comment: "fix syntax <length> -> <length-percentage>", references: [ "https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing" ], syntax: "normal | <length-percentage>" }, marker: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-end": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-mid": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "marker-start": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#MarkerProperties" ], syntax: "none | <url>" }, "max-width": { comment: "fix auto -> none (https://github.com/mdn/data/pull/431); extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/max-width", syntax: "none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>) | <-non-standard-width>" }, width: { comment: "per spec fit-content should be a function, however browsers are supporting it as a keyword (https://github.com/csstree/stylelint-validator/issues/29)", syntax: "| fit-content | -moz-fit-content | -webkit-fit-content" }, "min-width": { comment: "extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width", syntax: "auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>) | <-non-standard-width>" }, overflow: { comment: "extend by vendor keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow", syntax: "| <-non-standard-overflow>" }, pause: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'pause-before'> <'pause-after'>?" }, "pause-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "pause-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, rest: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<'rest-before'> <'rest-after'>?" }, "rest-after": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "rest-before": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<time> | none | x-weak | weak | medium | strong | x-strong" }, "shape-rendering": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#ShapeRenderingPropert" ], syntax: "auto | optimizeSpeed | crispEdges | geometricPrecision" }, src: { comment: "added @font-face's src property https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src", syntax: "[ <url> [ format( <string># ) ]? | local( <family-name> ) ]#" }, speak: { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "auto | none | normal" }, "speak-as": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "normal | spell-out || digits || [ literal-punctuation | no-punctuation ]" }, stroke: { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<paint>" }, "stroke-dasharray": { comment: "added SVG property; a list of comma and/or white space separated <length>s and <percentage>s", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "none | [ <svg-length>+ ]#" }, "stroke-dashoffset": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<svg-length>" }, "stroke-linecap": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "butt | round | square" }, "stroke-linejoin": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "miter | round | bevel" }, "stroke-miterlimit": { comment: "added SVG property (<miterlimit> = <number-one-or-greater>) ", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<number-one-or-greater>" }, "stroke-opacity": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<number-zero-one>" }, "stroke-width": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/painting.html#StrokeProperties" ], syntax: "<svg-length>" }, "text-anchor": { comment: "added SVG property", references: [ "https://www.w3.org/TR/SVG/text.html#TextAlignmentProperties" ], syntax: "start | middle | end" }, "unicode-bidi": { comment: "added prefixed keywords https://developer.mozilla.org/en-US/docs/Web/CSS/unicode-bidi", syntax: "| -moz-isolate | -moz-isolate-override | -moz-plaintext | -webkit-isolate | -webkit-isolate-override | -webkit-plaintext" }, "unicode-range": { comment: "added missed property https://developer.mozilla.org/en-US/docs/Web/CSS/%40font-face/unicode-range", syntax: "<urange>#" }, "voice-balance": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<number> | left | center | right | leftwards | rightwards" }, "voice-duration": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "auto | <time>" }, "voice-family": { comment: "<name> -> <family-name>, https://www.w3.org/TR/css3-speech/#property-index", syntax: "[ [ <family-name> | <generic-voice> ] , ]* [ <family-name> | <generic-voice> ] | preserve" }, "voice-pitch": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<frequency> && absolute | [ [ x-low | low | medium | high | x-high ] || [ <frequency> | <semitones> | <percentage> ] ]" }, "voice-range": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "<frequency> && absolute | [ [ x-low | low | medium | high | x-high ] || [ <frequency> | <semitones> | <percentage> ] ]" }, "voice-rate": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "[ normal | x-slow | slow | medium | fast | x-fast ] || <percentage>" }, "voice-stress": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "normal | strong | moderate | none | reduced" }, "voice-volume": { comment: "https://www.w3.org/TR/css3-speech/#property-index", syntax: "silent | [ [ x-soft | soft | medium | loud | x-loud ] || <decibel> ]" }, "writing-mode": { comment: "extend with SVG keywords", syntax: "| <svg-writing-mode>" } }; var syntaxes = { "-legacy-gradient": { comment: "added collection of legacy gradient syntaxes", syntax: "<-webkit-gradient()> | <-legacy-linear-gradient> | <-legacy-repeating-linear-gradient> | <-legacy-radial-gradient> | <-legacy-repeating-radial-gradient>" }, "-legacy-linear-gradient": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "-moz-linear-gradient( <-legacy-linear-gradient-arguments> ) | -webkit-linear-gradient( <-legacy-linear-gradient-arguments> ) | -o-linear-gradient( <-legacy-linear-gradient-arguments> )" }, "-legacy-repeating-linear-gradient": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "-moz-repeating-linear-gradient( <-legacy-linear-gradient-arguments> ) | -webkit-repeating-linear-gradient( <-legacy-linear-gradient-arguments> ) | -o-repeating-linear-gradient( <-legacy-linear-gradient-arguments> )" }, "-legacy-linear-gradient-arguments": { comment: "like standard syntax but w/o `to` keyword https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient", syntax: "[ <angle> | <side-or-corner> ]? , <color-stop-list>" }, "-legacy-radial-gradient": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "-moz-radial-gradient( <-legacy-radial-gradient-arguments> ) | -webkit-radial-gradient( <-legacy-radial-gradient-arguments> ) | -o-radial-gradient( <-legacy-radial-gradient-arguments> )" }, "-legacy-repeating-radial-gradient": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "-moz-repeating-radial-gradient( <-legacy-radial-gradient-arguments> ) | -webkit-repeating-radial-gradient( <-legacy-radial-gradient-arguments> ) | -o-repeating-radial-gradient( <-legacy-radial-gradient-arguments> )" }, "-legacy-radial-gradient-arguments": { comment: "deprecated syntax that implemented by some browsers https://www.w3.org/TR/2011/WD-css3-images-20110908/#radial-gradients", syntax: "[ <position> , ]? [ [ [ <-legacy-radial-gradient-shape> || <-legacy-radial-gradient-size> ] | [ <length> | <percentage> ]{2} ] , ]? <color-stop-list>" }, "-legacy-radial-gradient-size": { comment: "before a standard it contains 2 extra keywords (`contain` and `cover`) https://www.w3.org/TR/2011/WD-css3-images-20110908/#ltsize", syntax: "closest-side | closest-corner | farthest-side | farthest-corner | contain | cover" }, "-legacy-radial-gradient-shape": { comment: "define to double sure it doesn't extends in future https://www.w3.org/TR/2011/WD-css3-images-20110908/#ltshape", syntax: "circle | ellipse" }, "-non-standard-font": { comment: "non standard fonts", references: [ "https://webkit.org/blog/3709/using-the-system-font-in-web-content/" ], syntax: "-apple-system-body | -apple-system-headline | -apple-system-subheadline | -apple-system-caption1 | -apple-system-caption2 | -apple-system-footnote | -apple-system-short-body | -apple-system-short-headline | -apple-system-short-subheadline | -apple-system-short-caption1 | -apple-system-short-footnote | -apple-system-tall-body" }, "-non-standard-color": { comment: "non standard colors", references: [ "http://cssdot.ru/%D0%A1%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%87%D0%BD%D0%B8%D0%BA_CSS/color-i305.html", "https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Mozilla_Color_Preference_Extensions" ], syntax: "-moz-ButtonDefault | -moz-ButtonHoverFace | -moz-ButtonHoverText | -moz-CellHighlight | -moz-CellHighlightText | -moz-Combobox | -moz-ComboboxText | -moz-Dialog | -moz-DialogText | -moz-dragtargetzone | -moz-EvenTreeRow | -moz-Field | -moz-FieldText | -moz-html-CellHighlight | -moz-html-CellHighlightText | -moz-mac-accentdarkestshadow | -moz-mac-accentdarkshadow | -moz-mac-accentface | -moz-mac-accentlightesthighlight | -moz-mac-accentlightshadow | -moz-mac-accentregularhighlight | -moz-mac-accentregularshadow | -moz-mac-chrome-active | -moz-mac-chrome-inactive | -moz-mac-focusring | -moz-mac-menuselect | -moz-mac-menushadow | -moz-mac-menutextselect | -moz-MenuHover | -moz-MenuHoverText | -moz-MenuBarText | -moz-MenuBarHoverText | -moz-nativehyperlinktext | -moz-OddTreeRow | -moz-win-communicationstext | -moz-win-mediatext | -moz-activehyperlinktext | -moz-default-background-color | -moz-default-color | -moz-hyperlinktext | -moz-visitedhyperlinktext | -webkit-activelink | -webkit-focus-ring-color | -webkit-link | -webkit-text" }, "-non-standard-image-rendering": { comment: "non-standard keywords http://phrogz.net/tmp/canvas_image_zoom.html", syntax: "optimize-contrast | -moz-crisp-edges | -o-crisp-edges | -webkit-optimize-contrast" }, "-non-standard-overflow": { comment: "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow", syntax: "-moz-scrollbars-none | -moz-scrollbars-horizontal | -moz-scrollbars-vertical | -moz-hidden-unscrollable" }, "-non-standard-width": { comment: "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width", syntax: "fill-available | min-intrinsic | intrinsic | -moz-available | -moz-fit-content | -moz-min-content | -moz-max-content | -webkit-min-content | -webkit-max-content" }, "-webkit-gradient()": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/ - TODO: simplify when after match algorithm improvement ( [, point, radius | , point] -> [, radius]? , point )", syntax: "-webkit-gradient( <-webkit-gradient-type>, <-webkit-gradient-point> [, <-webkit-gradient-point> | , <-webkit-gradient-radius>, <-webkit-gradient-point> ] [, <-webkit-gradient-radius>]? [, <-webkit-gradient-color-stop>]* )" }, "-webkit-gradient-color-stop": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "from( <color> ) | color-stop( [ <number-zero-one> | <percentage> ] , <color> ) | to( <color> )" }, "-webkit-gradient-point": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "[ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]" }, "-webkit-gradient-radius": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "<length> | <percentage>" }, "-webkit-gradient-type": { comment: "first Apple proposal gradient syntax https://webkit.org/blog/175/introducing-css-gradients/", syntax: "linear | radial" }, "-webkit-mask-box-repeat": { comment: "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-box-image", syntax: "repeat | stretch | round" }, "-webkit-mask-clip-style": { comment: "missed; there is no enough information about `-webkit-mask-clip` property, but looks like all those keywords are working", syntax: "border | border-box | padding | padding-box | content | content-box | text" }, "-ms-filter-function-list": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<-ms-filter-function>+" }, "-ms-filter-function": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<-ms-filter-function-progid> | <-ms-filter-function-legacy>" }, "-ms-filter-function-progid": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "'progid:' [ <ident-token> '.' ]* [ <ident-token> | <function-token> <any-value>? ) ]" }, "-ms-filter-function-legacy": { comment: "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter", syntax: "<ident-token> | <function-token> <any-value>? )" }, "-ms-filter": { syntax: "<string>" }, age: { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "child | young | old" }, "attr-name": { syntax: "<wq-name>" }, "attr-fallback": { syntax: "<any-value>" }, "border-radius": { comment: "missed, https://drafts.csswg.org/css-backgrounds-3/#the-border-radius", syntax: "<length-percentage>{1,2}" }, bottom: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "content-list": { comment: "missed -> https://drafts.csswg.org/css-content/#typedef-content-list (document-url, <target> and leader() is omitted util stabilization)", syntax: "[ <string> | contents | <image> | <quote> | <target> | <leader()> | <attr()> | counter( <ident>, <'list-style-type'>? ) ]+" }, "element()": { comment: "https://drafts.csswg.org/css-gcpm/#element-syntax & https://drafts.csswg.org/css-images-4/#element-notation", syntax: "element( <custom-ident> , [ first | start | last | first-except ]? ) | element( <id-selector> )" }, "generic-voice": { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "[ <age>? <gender> <integer>? ]" }, gender: { comment: "https://www.w3.org/TR/css3-speech/#voice-family", syntax: "male | female | neutral" }, "generic-family": { comment: "added -apple-system", references: [ "https://webkit.org/blog/3709/using-the-system-font-in-web-content/" ], syntax: "| -apple-system" }, gradient: { comment: "added legacy syntaxes support", syntax: "| <-legacy-gradient>" }, left: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "mask-image": { comment: "missed; https://drafts.fxtf.org/css-masking-1/#the-mask-image", syntax: "<mask-reference>#" }, "name-repeat": { comment: "missed, and looks like obsolete, keep it as is since other property syntaxes should be changed too; https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-name-repeat", syntax: "repeat( [ <positive-integer> | auto-fill ], <line-names>+)" }, "named-color": { comment: "added non standard color names", syntax: "| <-non-standard-color>" }, paint: { comment: "used by SVG https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint", syntax: "none | <color> | <url> [ none | <color> ]? | context-fill | context-stroke" }, "page-size": { comment: "https://www.w3.org/TR/css-page-3/#typedef-page-size-page-size", syntax: "A5 | A4 | A3 | B5 | B4 | JIS-B5 | JIS-B4 | letter | legal | ledger" }, ratio: { comment: "missed, https://drafts.csswg.org/mediaqueries-4/#typedef-ratio", syntax: "<integer> / <integer>" }, right: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, shape: { comment: "missed spaces in function body and add backwards compatible syntax", syntax: "rect( <top>, <right>, <bottom>, <left> ) | rect( <top> <right> <bottom> <left> )" }, "svg-length": { comment: "All coordinates and lengths in SVG can be specified with or without a unit identifier", references: [ "https://www.w3.org/TR/SVG11/coords.html#Units" ], syntax: "<percentage> | <length> | <number>" }, "svg-writing-mode": { comment: "SVG specific keywords (deprecated for CSS)", references: [ "https://developer.mozilla.org/en/docs/Web/CSS/writing-mode", "https://www.w3.org/TR/SVG/text.html#WritingModeProperty" ], syntax: "lr-tb | rl-tb | tb-rl | lr | rl | tb" }, top: { comment: "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect", syntax: "<length> | auto" }, "track-group": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "'(' [ <string>* <track-minmax> <string>* ]+ ')' [ '[' <positive-integer> ']' ]? | <track-minmax>" }, "track-list-v0": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "[ <string>* <track-group> <string>* ]+ | none" }, "track-minmax": { comment: "used by old grid-columns and grid-rows syntax v0", syntax: "minmax( <track-breadth> , <track-breadth> ) | auto | <track-breadth> | fit-content" }, x: { comment: "missed; not sure we should add it, but no others except `cursor` is using it so it's ok for now; https://drafts.csswg.org/css-ui-3/#cursor", syntax: "<number>" }, y: { comment: "missed; not sure we should add it, but no others except `cursor` is using so it's ok for now; https://drafts.csswg.org/css-ui-3/#cursor", syntax: "<number>" }, declaration: { comment: "missed, restored by https://drafts.csswg.org/css-syntax", syntax: "<ident-token> : <declaration-value>? [ '!' important ]?" }, "declaration-list": { comment: "missed, restored by https://drafts.csswg.org/css-syntax", syntax: "[ <declaration>? ';' ]* <declaration>?" }, url: { comment: "https://drafts.csswg.org/css-values-4/#urls", syntax: "url( <string> <url-modifier>* ) | <url-token>" }, "url-modifier": { comment: "https://drafts.csswg.org/css-values-4/#typedef-url-modifier", syntax: "<ident> | <function-token> <any-value> )" }, "number-zero-one": { syntax: "<number [0,1]>" }, "number-one-or-greater": { syntax: "<number [1,∞]>" }, "positive-integer": { syntax: "<integer [0,∞]>" }, "-non-standard-display": { syntax: "-ms-inline-flexbox | -ms-grid | -ms-inline-grid | -webkit-flex | -webkit-inline-flex | -webkit-box | -webkit-inline-box | -moz-inline-stack | -moz-box | -moz-inline-box" } }; var require$$3 = { atrules: atrules, properties: properties, syntaxes: syntaxes }; const mdnAtrules = require$$0; const mdnProperties = require$$1; const mdnSyntaxes = require$$2; const patch = require$$3; const extendSyntax = /^\s*\|\s*/; function preprocessAtrules(dict) { const result = Object.create(null); for (const atruleName in dict) { const atrule = dict[atruleName]; let descriptors = null; if (atrule.descriptors) { descriptors = Object.create(null); for (const descriptor in atrule.descriptors) { descriptors[descriptor] = atrule.descriptors[descriptor].syntax; } } result[atruleName.substr(1)] = { prelude: atrule.syntax.trim().match(/^@\S+\s+([^;\{]*)/)[1].trim() || null, descriptors }; } return result; } function patchDictionary(dict, patchDict) { const result = {}; // copy all syntaxes for an original dict for (const key in dict) { result[key] = dict[key].syntax || dict[key]; } // apply a patch for (const key in patchDict) { if (key in dict) { if (patchDict[key].syntax) { result[key] = extendSyntax.test(patchDict[key].syntax) ? result[key] + ' ' + patchDict[key].syntax.trim() : patchDict[key].syntax; } else { delete result[key]; } } else { if (patchDict[key].syntax) { result[key] = patchDict[key].syntax.replace(extendSyntax, ''); } } } return result; } function unpackSyntaxes(dict) { const result = {}; for (const key in dict) { result[key] = dict[key].syntax; } return result; } function patchAtrules(dict, patchDict) { const result = {}; // copy all syntaxes for an original dict for (const key in dict) { const patchDescriptors = (patchDict[key] && patchDict[key].descriptors) || null; result[key] = { prelude: key in patchDict && 'prelude' in patchDict[key] ? patchDict[key].prelude : dict[key].prelude || null, descriptors: dict[key].descriptors ? patchDictionary(dict[key].descriptors, patchDescriptors || {}) : patchDescriptors && unpackSyntaxes(patchDescriptors) }; } // apply a patch for (const key in patchDict) { if (!hasOwnProperty.call(dict, key)) { result[key] = { prelude: patchDict[key].prelude || null, descriptors: patchDict[key].descriptors && unpackSyntaxes(patchDict[key].descriptors) }; } } return result; } var data$1 = { types: patchDictionary(mdnSyntaxes, patch.syntaxes), atrules: patchAtrules(preprocessAtrules(mdnAtrules), patch.atrules), properties: patchDictionary(mdnProperties, patch.properties) }; var cmpChar$2 = tokenizer$3.cmpChar; var isDigit$1 = tokenizer$3.isDigit; var TYPE$y = tokenizer$3.TYPE; var WHITESPACE$8 = TYPE$y.WhiteSpace; var COMMENT$6 = TYPE$y.Comment; var IDENT$f = TYPE$y.Ident; var NUMBER$6 = TYPE$y.Number; var DIMENSION$5 = TYPE$y.Dimension; var PLUSSIGN$5 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$2 = 0x002D; // U+002D HYPHEN-MINUS (-) var N = 0x006E; // U+006E LATIN SMALL LETTER N (n) var DISALLOW_SIGN = true; var ALLOW_SIGN = false; function checkInteger(offset, disallowSign) { var pos = this.scanner.tokenStart + offset; var code = this.scanner.source.charCodeAt(pos); if (code === PLUSSIGN$5 || code === HYPHENMINUS$2) { if (disallowSign) { this.error('Number sign is not allowed'); } pos++; } for (; pos < this.scanner.tokenEnd; pos++) { if (!isDigit$1(this.scanner.source.charCodeAt(pos))) { this.error('Integer is expected', pos); } } } function checkTokenIsInteger(disallowSign) { return checkInteger.call(this, 0, disallowSign); } function expectCharCode(offset, code) { if (!cmpChar$2(this.scanner.source, this.scanner.tokenStart + offset, code)) { var msg = ''; switch (code) { case N: msg = 'N is expected'; break; case HYPHENMINUS$2: msg = 'HyphenMinus is expected'; break; } this.error(msg, this.scanner.tokenStart + offset); } } // ... <signed-integer> // ... ['+' | '-'] <signless-integer> function consumeB() { var offset = 0; var sign = 0; var type = this.scanner.tokenType; while (type === WHITESPACE$8 || type === COMMENT$6) { type = this.scanner.lookupType(++offset); } if (type !== NUMBER$6) { if (this.scanner.isDelim(PLUSSIGN$5, offset) || this.scanner.isDelim(HYPHENMINUS$2, offset)) { sign = this.scanner.isDelim(PLUSSIGN$5, offset) ? PLUSSIGN$5 : HYPHENMINUS$2; do { type = this.scanner.lookupType(++offset); } while (type === WHITESPACE$8 || type === COMMENT$6); if (type !== NUMBER$6) { this.scanner.skip(offset); checkTokenIsInteger.call(this, DISALLOW_SIGN); } } else { return null; } } if (offset > 0) { this.scanner.skip(offset); } if (sign === 0) { type = this.scanner.source.charCodeAt(this.scanner.tokenStart); if (type !== PLUSSIGN$5 && type !== HYPHENMINUS$2) { this.error('Number sign is expected'); } } checkTokenIsInteger.call(this, sign !== 0); return sign === HYPHENMINUS$2 ? '-' + this.consume(NUMBER$6) : this.consume(NUMBER$6); } // An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb var AnPlusB = { name: 'AnPlusB', structure: { a: [String, null], b: [String, null] }, parse: function() { /* eslint-disable brace-style*/ var start = this.scanner.tokenStart; var a = null; var b = null; // <integer> if (this.scanner.tokenType === NUMBER$6) { checkTokenIsInteger.call(this, ALLOW_SIGN); b = this.consume(NUMBER$6); } // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> // -n- <signless-integer> // <dashndashdigit-ident> else if (this.scanner.tokenType === IDENT$f && cmpChar$2(this.scanner.source, this.scanner.tokenStart, HYPHENMINUS$2)) { a = '-1'; expectCharCode.call(this, 1, N); switch (this.scanner.getTokenLength()) { // -n // -n <signed-integer> // -n ['+' | '-'] <signless-integer> case 2: this.scanner.next(); b = consumeB.call(this); break; // -n- <signless-integer> case 3: expectCharCode.call(this, 2, HYPHENMINUS$2); this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN); b = '-' + this.consume(NUMBER$6); break; // <dashndashdigit-ident> default: expectCharCode.call(this, 2, HYPHENMINUS$2); checkInteger.call(this, 3, DISALLOW_SIGN); this.scanner.next(); b = this.scanner.substrToCursor(start + 2); } } // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> // '+'? n- <signless-integer> // '+'? <ndashdigit-ident> else if (this.scanner.tokenType === IDENT$f || (this.scanner.isDelim(PLUSSIGN$5) && this.scanner.lookupType(1) === IDENT$f)) { var sign = 0; a = '1'; // just ignore a plus if (this.scanner.isDelim(PLUSSIGN$5)) { sign = 1; this.scanner.next(); } expectCharCode.call(this, 0, N); switch (this.scanner.getTokenLength()) { // '+'? n // '+'? n <signed-integer> // '+'? n ['+' | '-'] <signless-integer> case 1: this.scanner.next(); b = consumeB.call(this); break; // '+'? n- <signless-integer> case 2: expectCharCode.call(this, 1, HYPHENMINUS$2); this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN); b = '-' + this.consume(NUMBER$6); break; // '+'? <ndashdigit-ident> default: expectCharCode.call(this, 1, HYPHENMINUS$2); checkInteger.call(this, 2, DISALLOW_SIGN); this.scanner.next(); b = this.scanner.substrToCursor(start + sign + 1); } } // <ndashdigit-dimension> // <ndash-dimension> <signless-integer> // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> else if (this.scanner.tokenType === DIMENSION$5) { var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); var sign = code === PLUSSIGN$5 || code === HYPHENMINUS$2; for (var i = this.scanner.tokenStart + sign; i < this.scanner.tokenEnd; i++) { if (!isDigit$1(this.scanner.source.charCodeAt(i))) { break; } } if (i === this.scanner.tokenStart + sign) { this.error('Integer is expected', this.scanner.tokenStart + sign); } expectCharCode.call(this, i - this.scanner.tokenStart, N); a = this.scanner.source.substring(start, i); // <n-dimension> // <n-dimension> <signed-integer> // <n-dimension> ['+' | '-'] <signless-integer> if (i + 1 === this.scanner.tokenEnd) { this.scanner.next(); b = consumeB.call(this); } else { expectCharCode.call(this, i - this.scanner.tokenStart + 1, HYPHENMINUS$2); // <ndash-dimension> <signless-integer> if (i + 2 === this.scanner.tokenEnd) { this.scanner.next(); this.scanner.skipSC(); checkTokenIsInteger.call(this, DISALLOW_SIGN); b = '-' + this.consume(NUMBER$6); } // <ndashdigit-dimension> else { checkInteger.call(this, i - this.scanner.tokenStart + 2, DISALLOW_SIGN); this.scanner.next(); b = this.scanner.substrToCursor(i + 1); } } } else { this.error(); } if (a !== null && a.charCodeAt(0) === PLUSSIGN$5) { a = a.substr(1); } if (b !== null && b.charCodeAt(0) === PLUSSIGN$5) { b = b.substr(1); } return { type: 'AnPlusB', loc: this.getLocation(start, this.scanner.tokenStart), a: a, b: b }; }, generate: function(node) { var a = node.a !== null && node.a !== undefined; var b = node.b !== null && node.b !== undefined; if (a) { this.chunk( node.a === '+1' ? '+n' : // eslint-disable-line operator-linebreak, indent node.a === '1' ? 'n' : // eslint-disable-line operator-linebreak, indent node.a === '-1' ? '-n' : // eslint-disable-line operator-linebreak, indent node.a + 'n' // eslint-disable-line operator-linebreak, indent ); if (b) { b = String(node.b); if (b.charAt(0) === '-' || b.charAt(0) === '+') { this.chunk(b.charAt(0)); this.chunk(b.substr(1)); } else { this.chunk('+'); this.chunk(b); } } } else { this.chunk(String(node.b)); } } }; var tokenizer = tokenizer$3; var TYPE$x = tokenizer.TYPE; var WhiteSpace$1 = TYPE$x.WhiteSpace; var Semicolon = TYPE$x.Semicolon; var LeftCurlyBracket = TYPE$x.LeftCurlyBracket; var Delim = TYPE$x.Delim; var EXCLAMATIONMARK$2 = 0x0021; // U+0021 EXCLAMATION MARK (!) function getOffsetExcludeWS() { if (this.scanner.tokenIndex > 0) { if (this.scanner.lookupType(-1) === WhiteSpace$1) { return this.scanner.tokenIndex > 1 ? this.scanner.getTokenStart(this.scanner.tokenIndex - 1) : this.scanner.firstCharOffset; } } return this.scanner.tokenStart; } // 0, 0, false function balanceEnd() { return 0; } // LEFTCURLYBRACKET, 0, false function leftCurlyBracket(tokenType) { return tokenType === LeftCurlyBracket ? 1 : 0; } // LEFTCURLYBRACKET, SEMICOLON, false function leftCurlyBracketOrSemicolon(tokenType) { return tokenType === LeftCurlyBracket || tokenType === Semicolon ? 1 : 0; } // EXCLAMATIONMARK, SEMICOLON, false function exclamationMarkOrSemicolon(tokenType, source, offset) { if (tokenType === Delim && source.charCodeAt(offset) === EXCLAMATIONMARK$2) { return 1; } return tokenType === Semicolon ? 1 : 0; } // 0, SEMICOLON, true function semicolonIncluded(tokenType) { return tokenType === Semicolon ? 2 : 0; } var Raw = { name: 'Raw', structure: { value: String }, parse: function(startToken, mode, excludeWhiteSpace) { var startOffset = this.scanner.getTokenStart(startToken); var endOffset; this.scanner.skip( this.scanner.getRawLength(startToken, mode || balanceEnd) ); if (excludeWhiteSpace && this.scanner.tokenStart > startOffset) { endOffset = getOffsetExcludeWS.call(this); } else { endOffset = this.scanner.tokenStart; } return { type: 'Raw', loc: this.getLocation(startOffset, endOffset), value: this.scanner.source.substring(startOffset, endOffset) }; }, generate: function(node) { this.chunk(node.value); }, mode: { default: balanceEnd, leftCurlyBracket: leftCurlyBracket, leftCurlyBracketOrSemicolon: leftCurlyBracketOrSemicolon, exclamationMarkOrSemicolon: exclamationMarkOrSemicolon, semicolonIncluded: semicolonIncluded } }; var TYPE$w = tokenizer$3.TYPE; var rawMode$5 = Raw.mode; var ATKEYWORD$2 = TYPE$w.AtKeyword; var SEMICOLON$4 = TYPE$w.Semicolon; var LEFTCURLYBRACKET$3 = TYPE$w.LeftCurlyBracket; var RIGHTCURLYBRACKET$1 = TYPE$w.RightCurlyBracket; function consumeRaw$5(startToken) { return this.Raw(startToken, rawMode$5.leftCurlyBracketOrSemicolon, true); } function isDeclarationBlockAtrule() { for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) { if (type === RIGHTCURLYBRACKET$1) { return true; } if (type === LEFTCURLYBRACKET$3 || type === ATKEYWORD$2) { return false; } } return false; } var Atrule = { name: 'Atrule', structure: { name: String, prelude: ['AtrulePrelude', 'Raw', null], block: ['Block', null] }, parse: function() { var start = this.scanner.tokenStart; var name; var nameLowerCase; var prelude = null; var block = null; this.eat(ATKEYWORD$2); name = this.scanner.substrToCursor(start + 1); nameLowerCase = name.toLowerCase(); this.scanner.skipSC(); // parse prelude if (this.scanner.eof === false && this.scanner.tokenType !== LEFTCURLYBRACKET$3 && this.scanner.tokenType !== SEMICOLON$4) { if (this.parseAtrulePrelude) { prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw$5); // turn empty AtrulePrelude into null if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) { prelude = null; } } else { prelude = consumeRaw$5.call(this, this.scanner.tokenIndex); } this.scanner.skipSC(); } switch (this.scanner.tokenType) { case SEMICOLON$4: this.scanner.next(); break; case LEFTCURLYBRACKET$3: if (this.atrule.hasOwnProperty(nameLowerCase) && typeof this.atrule[nameLowerCase].block === 'function') { block = this.atrule[nameLowerCase].block.call(this); } else { // TODO: should consume block content as Raw? block = this.Block(isDeclarationBlockAtrule.call(this)); } break; } return { type: 'Atrule', loc: this.getLocation(start, this.scanner.tokenStart), name: name, prelude: prelude, block: block }; }, generate: function(node) { this.chunk('@'); this.chunk(node.name); if (node.prelude !== null) { this.chunk(' '); this.node(node.prelude); } if (node.block) { this.node(node.block); } else { this.chunk(';'); } }, walkContext: 'atrule' }; var TYPE$v = tokenizer$3.TYPE; var SEMICOLON$3 = TYPE$v.Semicolon; var LEFTCURLYBRACKET$2 = TYPE$v.LeftCurlyBracket; var AtrulePrelude = { name: 'AtrulePrelude', structure: { children: [[]] }, parse: function(name) { var children = null; if (name !== null) { name = name.toLowerCase(); } this.scanner.skipSC(); if (this.atrule.hasOwnProperty(name) && typeof this.atrule[name].prelude === 'function') { // custom consumer children = this.atrule[name].prelude.call(this); } else { // default consumer children = this.readSequence(this.scope.AtrulePrelude); } this.scanner.skipSC(); if (this.scanner.eof !== true && this.scanner.tokenType !== LEFTCURLYBRACKET$2 && this.scanner.tokenType !== SEMICOLON$3) { this.error('Semicolon or block is expected'); } if (children === null) { children = this.createList(); } return { type: 'AtrulePrelude', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); }, walkContext: 'atrulePrelude' }; var TYPE$u = tokenizer$3.TYPE; var IDENT$e = TYPE$u.Ident; var STRING$3 = TYPE$u.String; var COLON$6 = TYPE$u.Colon; var LEFTSQUAREBRACKET$3 = TYPE$u.LeftSquareBracket; var RIGHTSQUAREBRACKET$1 = TYPE$u.RightSquareBracket; var DOLLARSIGN$1 = 0x0024; // U+0024 DOLLAR SIGN ($) var ASTERISK$5 = 0x002A; // U+002A ASTERISK (*) var EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=) var CIRCUMFLEXACCENT = 0x005E; // U+005E (^) var VERTICALLINE$2 = 0x007C; // U+007C VERTICAL LINE (|) var TILDE$2 = 0x007E; // U+007E TILDE (~) function getAttributeName() { if (this.scanner.eof) { this.error('Unexpected end of input'); } var start = this.scanner.tokenStart; var expectIdent = false; var checkColon = true; if (this.scanner.isDelim(ASTERISK$5)) { expectIdent = true; checkColon = false; this.scanner.next(); } else if (!this.scanner.isDelim(VERTICALLINE$2)) { this.eat(IDENT$e); } if (this.scanner.isDelim(VERTICALLINE$2)) { if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 1) !== EQUALSSIGN) { this.scanner.next(); this.eat(IDENT$e); } else if (expectIdent) { this.error('Identifier is expected', this.scanner.tokenEnd); } } else if (expectIdent) { this.error('Vertical line is expected'); } if (checkColon && this.scanner.tokenType === COLON$6) { this.scanner.next(); this.eat(IDENT$e); } return { type: 'Identifier', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; } function getOperator() { var start = this.scanner.tokenStart; var code = this.scanner.source.charCodeAt(start); if (code !== EQUALSSIGN && // = code !== TILDE$2 && // ~= code !== CIRCUMFLEXACCENT && // ^= code !== DOLLARSIGN$1 && // $= code !== ASTERISK$5 && // *= code !== VERTICALLINE$2 // |= ) { this.error('Attribute selector (=, ~=, ^=, $=, *=, |=) is expected'); } this.scanner.next(); if (code !== EQUALSSIGN) { if (!this.scanner.isDelim(EQUALSSIGN)) { this.error('Equal sign is expected'); } this.scanner.next(); } return this.scanner.substrToCursor(start); } // '[' <wq-name> ']' // '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']' var AttributeSelector = { name: 'AttributeSelector', structure: { name: 'Identifier', matcher: [String, null], value: ['String', 'Identifier', null], flags: [String, null] }, parse: function() { var start = this.scanner.tokenStart; var name; var matcher = null; var value = null; var flags = null; this.eat(LEFTSQUAREBRACKET$3); this.scanner.skipSC(); name = getAttributeName.call(this); this.scanner.skipSC(); if (this.scanner.tokenType !== RIGHTSQUAREBRACKET$1) { // avoid case `[name i]` if (this.scanner.tokenType !== IDENT$e) { matcher = getOperator.call(this); this.scanner.skipSC(); value = this.scanner.tokenType === STRING$3 ? this.String() : this.Identifier(); this.scanner.skipSC(); } // attribute flags if (this.scanner.tokenType === IDENT$e) { flags = this.scanner.getTokenValue(); this.scanner.next(); this.scanner.skipSC(); } } this.eat(RIGHTSQUAREBRACKET$1); return { type: 'AttributeSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, matcher: matcher, value: value, flags: flags }; }, generate: function(node) { var flagsPrefix = ' '; this.chunk('['); this.node(node.name); if (node.matcher !== null) { this.chunk(node.matcher); if (node.value !== null) { this.node(node.value); // space between string and flags is not required if (node.value.type === 'String') { flagsPrefix = ''; } } } if (node.flags !== null) { this.chunk(flagsPrefix); this.chunk(node.flags); } this.chunk(']'); } }; var TYPE$t = tokenizer$3.TYPE; var rawMode$4 = Raw.mode; var WHITESPACE$7 = TYPE$t.WhiteSpace; var COMMENT$5 = TYPE$t.Comment; var SEMICOLON$2 = TYPE$t.Semicolon; var ATKEYWORD$1 = TYPE$t.AtKeyword; var LEFTCURLYBRACKET$1 = TYPE$t.LeftCurlyBracket; var RIGHTCURLYBRACKET = TYPE$t.RightCurlyBracket; function consumeRaw$4(startToken) { return this.Raw(startToken, null, true); } function consumeRule() { return this.parseWithFallback(this.Rule, consumeRaw$4); } function consumeRawDeclaration(startToken) { return this.Raw(startToken, rawMode$4.semicolonIncluded, true); } function consumeDeclaration() { if (this.scanner.tokenType === SEMICOLON$2) { return consumeRawDeclaration.call(this, this.scanner.tokenIndex); } var node = this.parseWithFallback(this.Declaration, consumeRawDeclaration); if (this.scanner.tokenType === SEMICOLON$2) { this.scanner.next(); } return node; } var Block = { name: 'Block', structure: { children: [[ 'Atrule', 'Rule', 'Declaration' ]] }, parse: function(isDeclaration) { var consumer = isDeclaration ? consumeDeclaration : consumeRule; var start = this.scanner.tokenStart; var children = this.createList(); this.eat(LEFTCURLYBRACKET$1); scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case RIGHTCURLYBRACKET: break scan; case WHITESPACE$7: case COMMENT$5: this.scanner.next(); break; case ATKEYWORD$1: children.push(this.parseWithFallback(this.Atrule, consumeRaw$4)); break; default: children.push(consumer.call(this)); } } if (!this.scanner.eof) { this.eat(RIGHTCURLYBRACKET); } return { type: 'Block', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('{'); this.children(node, function(prev) { if (prev.type === 'Declaration') { this.chunk(';'); } }); this.chunk('}'); }, walkContext: 'block' }; var TYPE$s = tokenizer$3.TYPE; var LEFTSQUAREBRACKET$2 = TYPE$s.LeftSquareBracket; var RIGHTSQUAREBRACKET = TYPE$s.RightSquareBracket; var Brackets = { name: 'Brackets', structure: { children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var children = null; this.eat(LEFTSQUAREBRACKET$2); children = readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTSQUAREBRACKET); } return { type: 'Brackets', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('['); this.children(node); this.chunk(']'); } }; var CDC$1 = tokenizer$3.TYPE.CDC; var CDC_1 = { name: 'CDC', structure: [], parse: function() { var start = this.scanner.tokenStart; this.eat(CDC$1); // --> return { type: 'CDC', loc: this.getLocation(start, this.scanner.tokenStart) }; }, generate: function() { this.chunk('-->'); } }; var CDO$1 = tokenizer$3.TYPE.CDO; var CDO_1 = { name: 'CDO', structure: [], parse: function() { var start = this.scanner.tokenStart; this.eat(CDO$1); // <!-- return { type: 'CDO', loc: this.getLocation(start, this.scanner.tokenStart) }; }, generate: function() { this.chunk('<!--'); } }; var TYPE$r = tokenizer$3.TYPE; var IDENT$d = TYPE$r.Ident; var FULLSTOP$2 = 0x002E; // U+002E FULL STOP (.) // '.' ident var ClassSelector = { name: 'ClassSelector', structure: { name: String }, parse: function() { if (!this.scanner.isDelim(FULLSTOP$2)) { this.error('Full stop is expected'); } this.scanner.next(); return { type: 'ClassSelector', loc: this.getLocation(this.scanner.tokenStart - 1, this.scanner.tokenEnd), name: this.consume(IDENT$d) }; }, generate: function(node) { this.chunk('.'); this.chunk(node.name); } }; var TYPE$q = tokenizer$3.TYPE; var IDENT$c = TYPE$q.Ident; var PLUSSIGN$4 = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS$5 = 0x002F; // U+002F SOLIDUS (/) var GREATERTHANSIGN$1 = 0x003E; // U+003E GREATER-THAN SIGN (>) var TILDE$1 = 0x007E; // U+007E TILDE (~) // + | > | ~ | /deep/ var Combinator = { name: 'Combinator', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); switch (code) { case GREATERTHANSIGN$1: case PLUSSIGN$4: case TILDE$1: this.scanner.next(); break; case SOLIDUS$5: this.scanner.next(); if (this.scanner.tokenType !== IDENT$c || this.scanner.lookupValue(0, 'deep') === false) { this.error('Identifier `deep` is expected'); } this.scanner.next(); if (!this.scanner.isDelim(SOLIDUS$5)) { this.error('Solidus is expected'); } this.scanner.next(); break; default: this.error('Combinator is expected'); } return { type: 'Combinator', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.name); } }; var TYPE$p = tokenizer$3.TYPE; var COMMENT$4 = TYPE$p.Comment; var ASTERISK$4 = 0x002A; // U+002A ASTERISK (*) var SOLIDUS$4 = 0x002F; // U+002F SOLIDUS (/) // '/*' .* '*/' var Comment = { name: 'Comment', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; var end = this.scanner.tokenEnd; this.eat(COMMENT$4); if ((end - start + 2) >= 2 && this.scanner.source.charCodeAt(end - 2) === ASTERISK$4 && this.scanner.source.charCodeAt(end - 1) === SOLIDUS$4) { end -= 2; } return { type: 'Comment', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start + 2, end) }; }, generate: function(node) { this.chunk('/*'); this.chunk(node.value); this.chunk('*/'); } }; var isCustomProperty = names$2.isCustomProperty; var TYPE$o = tokenizer$3.TYPE; var rawMode$3 = Raw.mode; var IDENT$b = TYPE$o.Ident; var HASH$4 = TYPE$o.Hash; var COLON$5 = TYPE$o.Colon; var SEMICOLON$1 = TYPE$o.Semicolon; var DELIM$4 = TYPE$o.Delim; var WHITESPACE$6 = TYPE$o.WhiteSpace; var EXCLAMATIONMARK$1 = 0x0021; // U+0021 EXCLAMATION MARK (!) var NUMBERSIGN$2 = 0x0023; // U+0023 NUMBER SIGN (#) var DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($) var AMPERSAND = 0x0026; // U+0026 ANPERSAND (&) var ASTERISK$3 = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN$3 = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS$3 = 0x002F; // U+002F SOLIDUS (/) function consumeValueRaw(startToken) { return this.Raw(startToken, rawMode$3.exclamationMarkOrSemicolon, true); } function consumeCustomPropertyRaw(startToken) { return this.Raw(startToken, rawMode$3.exclamationMarkOrSemicolon, false); } function consumeValue() { var startValueToken = this.scanner.tokenIndex; var value = this.Value(); if (value.type !== 'Raw' && this.scanner.eof === false && this.scanner.tokenType !== SEMICOLON$1 && this.scanner.isDelim(EXCLAMATIONMARK$1) === false && this.scanner.isBalanceEdge(startValueToken) === false) { this.error(); } return value; } var Declaration = { name: 'Declaration', structure: { important: [Boolean, String], property: String, value: ['Value', 'Raw'] }, parse: function() { var start = this.scanner.tokenStart; var startToken = this.scanner.tokenIndex; var property = readProperty.call(this); var customProperty = isCustomProperty(property); var parseValue = customProperty ? this.parseCustomProperty : this.parseValue; var consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw; var important = false; var value; this.scanner.skipSC(); this.eat(COLON$5); const valueStart = this.scanner.tokenIndex; if (!customProperty) { this.scanner.skipSC(); } if (parseValue) { value = this.parseWithFallback(consumeValue, consumeRaw); } else { value = consumeRaw.call(this, this.scanner.tokenIndex); } if (customProperty && value.type === 'Value' && value.children.isEmpty()) { for (let offset = valueStart - this.scanner.tokenIndex; offset <= 0; offset++) { if (this.scanner.lookupType(offset) === WHITESPACE$6) { value.children.appendData({ type: 'WhiteSpace', loc: null, value: ' ' }); break; } } } if (this.scanner.isDelim(EXCLAMATIONMARK$1)) { important = getImportant.call(this); this.scanner.skipSC(); } // Do not include semicolon to range per spec // https://drafts.csswg.org/css-syntax/#declaration-diagram if (this.scanner.eof === false && this.scanner.tokenType !== SEMICOLON$1 && this.scanner.isBalanceEdge(startToken) === false) { this.error(); } return { type: 'Declaration', loc: this.getLocation(start, this.scanner.tokenStart), important: important, property: property, value: value }; }, generate: function(node) { this.chunk(node.property); this.chunk(':'); this.node(node.value); if (node.important) { this.chunk(node.important === true ? '!important' : '!' + node.important); } }, walkContext: 'declaration' }; function readProperty() { var start = this.scanner.tokenStart; // hacks if (this.scanner.tokenType === DELIM$4) { switch (this.scanner.source.charCodeAt(this.scanner.tokenStart)) { case ASTERISK$3: case DOLLARSIGN: case PLUSSIGN$3: case NUMBERSIGN$2: case AMPERSAND: this.scanner.next(); break; // TODO: not sure we should support this hack case SOLIDUS$3: this.scanner.next(); if (this.scanner.isDelim(SOLIDUS$3)) { this.scanner.next(); } break; } } if (this.scanner.tokenType === HASH$4) { this.eat(HASH$4); } else { this.eat(IDENT$b); } return this.scanner.substrToCursor(start); } // ! ws* important function getImportant() { this.eat(DELIM$4); this.scanner.skipSC(); var important = this.consume(IDENT$b); // store original value in case it differ from `important` // for better original source restoring and hacks like `!ie` support return important === 'important' ? true : important; } var TYPE$n = tokenizer$3.TYPE; var rawMode$2 = Raw.mode; var WHITESPACE$5 = TYPE$n.WhiteSpace; var COMMENT$3 = TYPE$n.Comment; var SEMICOLON = TYPE$n.Semicolon; function consumeRaw$3(startToken) { return this.Raw(startToken, rawMode$2.semicolonIncluded, true); } var DeclarationList = { name: 'DeclarationList', structure: { children: [[ 'Declaration' ]] }, parse: function() { var children = this.createList(); while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE$5: case COMMENT$3: case SEMICOLON: this.scanner.next(); break; default: children.push(this.parseWithFallback(this.Declaration, consumeRaw$3)); } } return { type: 'DeclarationList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function(prev) { if (prev.type === 'Declaration') { this.chunk(';'); } }); } }; var consumeNumber$2 = utils$2.consumeNumber; var TYPE$m = tokenizer$3.TYPE; var DIMENSION$4 = TYPE$m.Dimension; var Dimension = { name: 'Dimension', structure: { value: String, unit: String }, parse: function() { var start = this.scanner.tokenStart; var numberEnd = consumeNumber$2(this.scanner.source, start); this.eat(DIMENSION$4); return { type: 'Dimension', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start, numberEnd), unit: this.scanner.source.substring(numberEnd, this.scanner.tokenStart) }; }, generate: function(node) { this.chunk(node.value); this.chunk(node.unit); } }; var TYPE$l = tokenizer$3.TYPE; var RIGHTPARENTHESIS$5 = TYPE$l.RightParenthesis; // <function-token> <sequence> ) var _Function = { name: 'Function', structure: { name: String, children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var name = this.consumeFunctionName(); var nameLowerCase = name.toLowerCase(); var children; children = recognizer.hasOwnProperty(nameLowerCase) ? recognizer[nameLowerCase].call(this, recognizer) : readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTPARENTHESIS$5); } return { type: 'Function', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk(node.name); this.chunk('('); this.children(node); this.chunk(')'); }, walkContext: 'function' }; var TYPE$k = tokenizer$3.TYPE; var HASH$3 = TYPE$k.Hash; // '#' ident var Hash = { name: 'Hash', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; this.eat(HASH$3); return { type: 'Hash', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start + 1) }; }, generate: function(node) { this.chunk('#'); this.chunk(node.value); } }; var TYPE$j = tokenizer$3.TYPE; var IDENT$a = TYPE$j.Ident; var Identifier = { name: 'Identifier', structure: { name: String }, parse: function() { return { type: 'Identifier', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), name: this.consume(IDENT$a) }; }, generate: function(node) { this.chunk(node.name); } }; var TYPE$i = tokenizer$3.TYPE; var HASH$2 = TYPE$i.Hash; // <hash-token> var IdSelector = { name: 'IdSelector', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; // TODO: check value is an ident this.eat(HASH$2); return { type: 'IdSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start + 1) }; }, generate: function(node) { this.chunk('#'); this.chunk(node.name); } }; var TYPE$h = tokenizer$3.TYPE; var IDENT$9 = TYPE$h.Ident; var NUMBER$5 = TYPE$h.Number; var DIMENSION$3 = TYPE$h.Dimension; var LEFTPARENTHESIS$5 = TYPE$h.LeftParenthesis; var RIGHTPARENTHESIS$4 = TYPE$h.RightParenthesis; var COLON$4 = TYPE$h.Colon; var DELIM$3 = TYPE$h.Delim; var MediaFeature = { name: 'MediaFeature', structure: { name: String, value: ['Identifier', 'Number', 'Dimension', 'Ratio', null] }, parse: function() { var start = this.scanner.tokenStart; var name; var value = null; this.eat(LEFTPARENTHESIS$5); this.scanner.skipSC(); name = this.consume(IDENT$9); this.scanner.skipSC(); if (this.scanner.tokenType !== RIGHTPARENTHESIS$4) { this.eat(COLON$4); this.scanner.skipSC(); switch (this.scanner.tokenType) { case NUMBER$5: if (this.lookupNonWSType(1) === DELIM$3) { value = this.Ratio(); } else { value = this.Number(); } break; case DIMENSION$3: value = this.Dimension(); break; case IDENT$9: value = this.Identifier(); break; default: this.error('Number, dimension, ratio or identifier is expected'); } this.scanner.skipSC(); } this.eat(RIGHTPARENTHESIS$4); return { type: 'MediaFeature', loc: this.getLocation(start, this.scanner.tokenStart), name: name, value: value }; }, generate: function(node) { this.chunk('('); this.chunk(node.name); if (node.value !== null) { this.chunk(':'); this.node(node.value); } this.chunk(')'); } }; var TYPE$g = tokenizer$3.TYPE; var WHITESPACE$4 = TYPE$g.WhiteSpace; var COMMENT$2 = TYPE$g.Comment; var IDENT$8 = TYPE$g.Ident; var LEFTPARENTHESIS$4 = TYPE$g.LeftParenthesis; var MediaQuery = { name: 'MediaQuery', structure: { children: [[ 'Identifier', 'MediaFeature', 'WhiteSpace' ]] }, parse: function() { this.scanner.skipSC(); var children = this.createList(); var child = null; var space = null; scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case COMMENT$2: this.scanner.next(); continue; case WHITESPACE$4: space = this.WhiteSpace(); continue; case IDENT$8: child = this.Identifier(); break; case LEFTPARENTHESIS$4: child = this.MediaFeature(); break; default: break scan; } if (space !== null) { children.push(space); space = null; } children.push(child); } if (child === null) { this.error('Identifier or parenthesis is expected'); } return { type: 'MediaQuery', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); } }; var COMMA$3 = tokenizer$3.TYPE.Comma; var MediaQueryList = { name: 'MediaQueryList', structure: { children: [[ 'MediaQuery' ]] }, parse: function(relative) { var children = this.createList(); this.scanner.skipSC(); while (!this.scanner.eof) { children.push(this.MediaQuery(relative)); if (this.scanner.tokenType !== COMMA$3) { break; } this.scanner.next(); } return { type: 'MediaQueryList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function() { this.chunk(','); }); } }; var Nth = { name: 'Nth', structure: { nth: ['AnPlusB', 'Identifier'], selector: ['SelectorList', null] }, parse: function(allowOfClause) { this.scanner.skipSC(); var start = this.scanner.tokenStart; var end = start; var selector = null; var query; if (this.scanner.lookupValue(0, 'odd') || this.scanner.lookupValue(0, 'even')) { query = this.Identifier(); } else { query = this.AnPlusB(); } this.scanner.skipSC(); if (allowOfClause && this.scanner.lookupValue(0, 'of')) { this.scanner.next(); selector = this.SelectorList(); if (this.needPositions) { end = this.getLastListNode(selector.children).loc.end.offset; } } else { if (this.needPositions) { end = query.loc.end.offset; } } return { type: 'Nth', loc: this.getLocation(start, end), nth: query, selector: selector }; }, generate: function(node) { this.node(node.nth); if (node.selector !== null) { this.chunk(' of '); this.node(node.selector); } } }; var NUMBER$4 = tokenizer$3.TYPE.Number; var _Number = { name: 'Number', structure: { value: String }, parse: function() { return { type: 'Number', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), value: this.consume(NUMBER$4) }; }, generate: function(node) { this.chunk(node.value); } }; // '/' | '*' | ',' | ':' | '+' | '-' var Operator = { name: 'Operator', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; this.scanner.next(); return { type: 'Operator', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.value); } }; var TYPE$f = tokenizer$3.TYPE; var LEFTPARENTHESIS$3 = TYPE$f.LeftParenthesis; var RIGHTPARENTHESIS$3 = TYPE$f.RightParenthesis; var Parentheses = { name: 'Parentheses', structure: { children: [[]] }, parse: function(readSequence, recognizer) { var start = this.scanner.tokenStart; var children = null; this.eat(LEFTPARENTHESIS$3); children = readSequence.call(this, recognizer); if (!this.scanner.eof) { this.eat(RIGHTPARENTHESIS$3); } return { type: 'Parentheses', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.chunk('('); this.children(node); this.chunk(')'); } }; var consumeNumber$1 = utils$2.consumeNumber; var TYPE$e = tokenizer$3.TYPE; var PERCENTAGE$2 = TYPE$e.Percentage; var Percentage = { name: 'Percentage', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; var numberEnd = consumeNumber$1(this.scanner.source, start); this.eat(PERCENTAGE$2); return { type: 'Percentage', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.source.substring(start, numberEnd) }; }, generate: function(node) { this.chunk(node.value); this.chunk('%'); } }; var TYPE$d = tokenizer$3.TYPE; var IDENT$7 = TYPE$d.Ident; var FUNCTION$5 = TYPE$d.Function; var COLON$3 = TYPE$d.Colon; var RIGHTPARENTHESIS$2 = TYPE$d.RightParenthesis; // : [ <ident> | <function-token> <any-value>? ) ] var PseudoClassSelector = { name: 'PseudoClassSelector', structure: { name: String, children: [['Raw'], null] }, parse: function() { var start = this.scanner.tokenStart; var children = null; var name; var nameLowerCase; this.eat(COLON$3); if (this.scanner.tokenType === FUNCTION$5) { name = this.consumeFunctionName(); nameLowerCase = name.toLowerCase(); if (this.pseudo.hasOwnProperty(nameLowerCase)) { this.scanner.skipSC(); children = this.pseudo[nameLowerCase].call(this); this.scanner.skipSC(); } else { children = this.createList(); children.push( this.Raw(this.scanner.tokenIndex, null, false) ); } this.eat(RIGHTPARENTHESIS$2); } else { name = this.consume(IDENT$7); } return { type: 'PseudoClassSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk(':'); this.chunk(node.name); if (node.children !== null) { this.chunk('('); this.children(node); this.chunk(')'); } }, walkContext: 'function' }; var TYPE$c = tokenizer$3.TYPE; var IDENT$6 = TYPE$c.Ident; var FUNCTION$4 = TYPE$c.Function; var COLON$2 = TYPE$c.Colon; var RIGHTPARENTHESIS$1 = TYPE$c.RightParenthesis; // :: [ <ident> | <function-token> <any-value>? ) ] var PseudoElementSelector = { name: 'PseudoElementSelector', structure: { name: String, children: [['Raw'], null] }, parse: function() { var start = this.scanner.tokenStart; var children = null; var name; var nameLowerCase; this.eat(COLON$2); this.eat(COLON$2); if (this.scanner.tokenType === FUNCTION$4) { name = this.consumeFunctionName(); nameLowerCase = name.toLowerCase(); if (this.pseudo.hasOwnProperty(nameLowerCase)) { this.scanner.skipSC(); children = this.pseudo[nameLowerCase].call(this); this.scanner.skipSC(); } else { children = this.createList(); children.push( this.Raw(this.scanner.tokenIndex, null, false) ); } this.eat(RIGHTPARENTHESIS$1); } else { name = this.consume(IDENT$6); } return { type: 'PseudoElementSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: name, children: children }; }, generate: function(node) { this.chunk('::'); this.chunk(node.name); if (node.children !== null) { this.chunk('('); this.children(node); this.chunk(')'); } }, walkContext: 'function' }; var isDigit = tokenizer$3.isDigit; var TYPE$b = tokenizer$3.TYPE; var NUMBER$3 = TYPE$b.Number; var DELIM$2 = TYPE$b.Delim; var SOLIDUS$2 = 0x002F; // U+002F SOLIDUS (/) var FULLSTOP$1 = 0x002E; // U+002E FULL STOP (.) // Terms of <ratio> should be a positive numbers (not zero or negative) // (see https://drafts.csswg.org/mediaqueries-3/#values) // However, -o-min-device-pixel-ratio takes fractional values as a ratio's term // and this is using by various sites. Therefore we relax checking on parse // to test a term is unsigned number without an exponent part. // Additional checking may be applied on lexer validation. function consumeNumber() { this.scanner.skipWS(); var value = this.consume(NUMBER$3); for (var i = 0; i < value.length; i++) { var code = value.charCodeAt(i); if (!isDigit(code) && code !== FULLSTOP$1) { this.error('Unsigned number is expected', this.scanner.tokenStart - value.length + i); } } if (Number(value) === 0) { this.error('Zero number is not allowed', this.scanner.tokenStart - value.length); } return value; } // <positive-integer> S* '/' S* <positive-integer> var Ratio = { name: 'Ratio', structure: { left: String, right: String }, parse: function() { var start = this.scanner.tokenStart; var left = consumeNumber.call(this); var right; this.scanner.skipWS(); if (!this.scanner.isDelim(SOLIDUS$2)) { this.error('Solidus is expected'); } this.eat(DELIM$2); right = consumeNumber.call(this); return { type: 'Ratio', loc: this.getLocation(start, this.scanner.tokenStart), left: left, right: right }; }, generate: function(node) { this.chunk(node.left); this.chunk('/'); this.chunk(node.right); } }; var TYPE$a = tokenizer$3.TYPE; var rawMode$1 = Raw.mode; var LEFTCURLYBRACKET = TYPE$a.LeftCurlyBracket; function consumeRaw$2(startToken) { return this.Raw(startToken, rawMode$1.leftCurlyBracket, true); } function consumePrelude() { var prelude = this.SelectorList(); if (prelude.type !== 'Raw' && this.scanner.eof === false && this.scanner.tokenType !== LEFTCURLYBRACKET) { this.error(); } return prelude; } var Rule = { name: 'Rule', structure: { prelude: ['SelectorList', 'Raw'], block: ['Block'] }, parse: function() { var startToken = this.scanner.tokenIndex; var startOffset = this.scanner.tokenStart; var prelude; var block; if (this.parseRulePrelude) { prelude = this.parseWithFallback(consumePrelude, consumeRaw$2); } else { prelude = consumeRaw$2.call(this, startToken); } block = this.Block(true); return { type: 'Rule', loc: this.getLocation(startOffset, this.scanner.tokenStart), prelude: prelude, block: block }; }, generate: function(node) { this.node(node.prelude); this.node(node.block); }, walkContext: 'rule' }; var Selector = { name: 'Selector', structure: { children: [[ 'TypeSelector', 'IdSelector', 'ClassSelector', 'AttributeSelector', 'PseudoClassSelector', 'PseudoElementSelector', 'Combinator', 'WhiteSpace' ]] }, parse: function() { var children = this.readSequence(this.scope.Selector); // nothing were consumed if (this.getFirstListNode(children) === null) { this.error('Selector is expected'); } return { type: 'Selector', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node); } }; var TYPE$9 = tokenizer$3.TYPE; var COMMA$2 = TYPE$9.Comma; var SelectorList = { name: 'SelectorList', structure: { children: [[ 'Selector', 'Raw' ]] }, parse: function() { var children = this.createList(); while (!this.scanner.eof) { children.push(this.Selector()); if (this.scanner.tokenType === COMMA$2) { this.scanner.next(); continue; } break; } return { type: 'SelectorList', loc: this.getLocationFromList(children), children: children }; }, generate: function(node) { this.children(node, function() { this.chunk(','); }); }, walkContext: 'selector' }; var STRING$2 = tokenizer$3.TYPE.String; var _String = { name: 'String', structure: { value: String }, parse: function() { return { type: 'String', loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), value: this.consume(STRING$2) }; }, generate: function(node) { this.chunk(node.value); } }; var TYPE$8 = tokenizer$3.TYPE; var WHITESPACE$3 = TYPE$8.WhiteSpace; var COMMENT$1 = TYPE$8.Comment; var ATKEYWORD = TYPE$8.AtKeyword; var CDO = TYPE$8.CDO; var CDC = TYPE$8.CDC; var EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!) function consumeRaw$1(startToken) { return this.Raw(startToken, null, false); } var StyleSheet = { name: 'StyleSheet', structure: { children: [[ 'Comment', 'CDO', 'CDC', 'Atrule', 'Rule', 'Raw' ]] }, parse: function() { var start = this.scanner.tokenStart; var children = this.createList(); var child; while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE$3: this.scanner.next(); continue; case COMMENT$1: // ignore comments except exclamation comments (i.e. /*! .. */) on top level if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 2) !== EXCLAMATIONMARK) { this.scanner.next(); continue; } child = this.Comment(); break; case CDO: // <!-- child = this.CDO(); break; case CDC: // --> child = this.CDC(); break; // CSS Syntax Module Level 3 // §2.2 Error handling // At the "top level" of a stylesheet, an <at-keyword-token> starts an at-rule. case ATKEYWORD: child = this.parseWithFallback(this.Atrule, consumeRaw$1); break; // Anything else starts a qualified rule ... default: child = this.parseWithFallback(this.Rule, consumeRaw$1); } children.push(child); } return { type: 'StyleSheet', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.children(node); }, walkContext: 'stylesheet' }; var TYPE$7 = tokenizer$3.TYPE; var IDENT$5 = TYPE$7.Ident; var ASTERISK$2 = 0x002A; // U+002A ASTERISK (*) var VERTICALLINE$1 = 0x007C; // U+007C VERTICAL LINE (|) function eatIdentifierOrAsterisk() { if (this.scanner.tokenType !== IDENT$5 && this.scanner.isDelim(ASTERISK$2) === false) { this.error('Identifier or asterisk is expected'); } this.scanner.next(); } // ident // ident|ident // ident|* // * // *|ident // *|* // |ident // |* var TypeSelector = { name: 'TypeSelector', structure: { name: String }, parse: function() { var start = this.scanner.tokenStart; if (this.scanner.isDelim(VERTICALLINE$1)) { this.scanner.next(); eatIdentifierOrAsterisk.call(this); } else { eatIdentifierOrAsterisk.call(this); if (this.scanner.isDelim(VERTICALLINE$1)) { this.scanner.next(); eatIdentifierOrAsterisk.call(this); } } return { type: 'TypeSelector', loc: this.getLocation(start, this.scanner.tokenStart), name: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.name); } }; var isHexDigit = tokenizer$3.isHexDigit; var cmpChar$1 = tokenizer$3.cmpChar; var TYPE$6 = tokenizer$3.TYPE; var NAME = tokenizer$3.NAME; var IDENT$4 = TYPE$6.Ident; var NUMBER$2 = TYPE$6.Number; var DIMENSION$2 = TYPE$6.Dimension; var PLUSSIGN$2 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS$1 = 0x002D; // U+002D HYPHEN-MINUS (-) var QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?) var U$1 = 0x0075; // U+0075 LATIN SMALL LETTER U (u) function eatHexSequence(offset, allowDash) { for (var pos = this.scanner.tokenStart + offset, len = 0; pos < this.scanner.tokenEnd; pos++) { var code = this.scanner.source.charCodeAt(pos); if (code === HYPHENMINUS$1 && allowDash && len !== 0) { if (eatHexSequence.call(this, offset + len + 1, false) === 0) { this.error(); } return -1; } if (!isHexDigit(code)) { this.error( allowDash && len !== 0 ? 'HyphenMinus' + (len < 6 ? ' or hex digit' : '') + ' is expected' : (len < 6 ? 'Hex digit is expected' : 'Unexpected input'), pos ); } if (++len > 6) { this.error('Too many hex digits', pos); } } this.scanner.next(); return len; } function eatQuestionMarkSequence(max) { var count = 0; while (this.scanner.isDelim(QUESTIONMARK)) { if (++count > max) { this.error('Too many question marks'); } this.scanner.next(); } } function startsWith(code) { if (this.scanner.source.charCodeAt(this.scanner.tokenStart) !== code) { this.error(NAME[code] + ' is expected'); } } // https://drafts.csswg.org/css-syntax/#urange // Informally, the <urange> production has three forms: // U+0001 // Defines a range consisting of a single code point, in this case the code point "1". // U+0001-00ff // Defines a range of codepoints between the first and the second value, in this case // the range between "1" and "ff" (255 in decimal) inclusive. // U+00?? // Defines a range of codepoints where the "?" characters range over all hex digits, // in this case defining the same as the value U+0000-00ff. // In each form, a maximum of 6 digits is allowed for each hexadecimal number (if you treat "?" as a hexadecimal digit). // // <urange> = // u '+' <ident-token> '?'* | // u <dimension-token> '?'* | // u <number-token> '?'* | // u <number-token> <dimension-token> | // u <number-token> <number-token> | // u '+' '?'+ function scanUnicodeRange() { var hexLength = 0; // u '+' <ident-token> '?'* // u '+' '?'+ if (this.scanner.isDelim(PLUSSIGN$2)) { this.scanner.next(); if (this.scanner.tokenType === IDENT$4) { hexLength = eatHexSequence.call(this, 0, true); if (hexLength > 0) { eatQuestionMarkSequence.call(this, 6 - hexLength); } return; } if (this.scanner.isDelim(QUESTIONMARK)) { this.scanner.next(); eatQuestionMarkSequence.call(this, 5); return; } this.error('Hex digit or question mark is expected'); return; } // u <number-token> '?'* // u <number-token> <dimension-token> // u <number-token> <number-token> if (this.scanner.tokenType === NUMBER$2) { startsWith.call(this, PLUSSIGN$2); hexLength = eatHexSequence.call(this, 1, true); if (this.scanner.isDelim(QUESTIONMARK)) { eatQuestionMarkSequence.call(this, 6 - hexLength); return; } if (this.scanner.tokenType === DIMENSION$2 || this.scanner.tokenType === NUMBER$2) { startsWith.call(this, HYPHENMINUS$1); eatHexSequence.call(this, 1, false); return; } return; } // u <dimension-token> '?'* if (this.scanner.tokenType === DIMENSION$2) { startsWith.call(this, PLUSSIGN$2); hexLength = eatHexSequence.call(this, 1, true); if (hexLength > 0) { eatQuestionMarkSequence.call(this, 6 - hexLength); } return; } this.error(); } var UnicodeRange = { name: 'UnicodeRange', structure: { value: String }, parse: function() { var start = this.scanner.tokenStart; // U or u if (!cmpChar$1(this.scanner.source, start, U$1)) { this.error('U is expected'); } if (!cmpChar$1(this.scanner.source, start + 1, PLUSSIGN$2)) { this.error('Plus sign is expected'); } this.scanner.next(); scanUnicodeRange.call(this); return { type: 'UnicodeRange', loc: this.getLocation(start, this.scanner.tokenStart), value: this.scanner.substrToCursor(start) }; }, generate: function(node) { this.chunk(node.value); } }; var isWhiteSpace = tokenizer$3.isWhiteSpace; var cmpStr$1 = tokenizer$3.cmpStr; var TYPE$5 = tokenizer$3.TYPE; var FUNCTION$3 = TYPE$5.Function; var URL$3 = TYPE$5.Url; var RIGHTPARENTHESIS = TYPE$5.RightParenthesis; // <url-token> | <function-token> <string> ) var Url = { name: 'Url', structure: { value: ['String', 'Raw'] }, parse: function() { var start = this.scanner.tokenStart; var value; switch (this.scanner.tokenType) { case URL$3: var rawStart = start + 4; var rawEnd = this.scanner.tokenEnd - 1; while (rawStart < rawEnd && isWhiteSpace(this.scanner.source.charCodeAt(rawStart))) { rawStart++; } while (rawStart < rawEnd && isWhiteSpace(this.scanner.source.charCodeAt(rawEnd - 1))) { rawEnd--; } value = { type: 'Raw', loc: this.getLocation(rawStart, rawEnd), value: this.scanner.source.substring(rawStart, rawEnd) }; this.eat(URL$3); break; case FUNCTION$3: if (!cmpStr$1(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(')) { this.error('Function name must be `url`'); } this.eat(FUNCTION$3); this.scanner.skipSC(); value = this.String(); this.scanner.skipSC(); this.eat(RIGHTPARENTHESIS); break; default: this.error('Url or Function is expected'); } return { type: 'Url', loc: this.getLocation(start, this.scanner.tokenStart), value: value }; }, generate: function(node) { this.chunk('url'); this.chunk('('); this.node(node.value); this.chunk(')'); } }; var Value = { name: 'Value', structure: { children: [[]] }, parse: function() { var start = this.scanner.tokenStart; var children = this.readSequence(this.scope.Value); return { type: 'Value', loc: this.getLocation(start, this.scanner.tokenStart), children: children }; }, generate: function(node) { this.children(node); } }; var WHITESPACE$2 = tokenizer$3.TYPE.WhiteSpace; var SPACE = Object.freeze({ type: 'WhiteSpace', loc: null, value: ' ' }); var WhiteSpace = { name: 'WhiteSpace', structure: { value: String }, parse: function() { this.eat(WHITESPACE$2); return SPACE; // return { // type: 'WhiteSpace', // loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd), // value: this.consume(WHITESPACE) // }; }, generate: function(node) { this.chunk(node.value); } }; var node = { AnPlusB: AnPlusB, Atrule: Atrule, AtrulePrelude: AtrulePrelude, AttributeSelector: AttributeSelector, Block: Block, Brackets: Brackets, CDC: CDC_1, CDO: CDO_1, ClassSelector: ClassSelector, Combinator: Combinator, Comment: Comment, Declaration: Declaration, DeclarationList: DeclarationList, Dimension: Dimension, Function: _Function, Hash: Hash, Identifier: Identifier, IdSelector: IdSelector, MediaFeature: MediaFeature, MediaQuery: MediaQuery, MediaQueryList: MediaQueryList, Nth: Nth, Number: _Number, Operator: Operator, Parentheses: Parentheses, Percentage: Percentage, PseudoClassSelector: PseudoClassSelector, PseudoElementSelector: PseudoElementSelector, Ratio: Ratio, Raw: Raw, Rule: Rule, Selector: Selector, SelectorList: SelectorList, String: _String, StyleSheet: StyleSheet, TypeSelector: TypeSelector, UnicodeRange: UnicodeRange, Url: Url, Value: Value, WhiteSpace: WhiteSpace }; var data = data$1; var lexer = { generic: true, types: data.types, atrules: data.atrules, properties: data.properties, node: node }; var cmpChar = tokenizer$3.cmpChar; var cmpStr = tokenizer$3.cmpStr; var TYPE$4 = tokenizer$3.TYPE; var IDENT$3 = TYPE$4.Ident; var STRING$1 = TYPE$4.String; var NUMBER$1 = TYPE$4.Number; var FUNCTION$2 = TYPE$4.Function; var URL$2 = TYPE$4.Url; var HASH$1 = TYPE$4.Hash; var DIMENSION$1 = TYPE$4.Dimension; var PERCENTAGE$1 = TYPE$4.Percentage; var LEFTPARENTHESIS$2 = TYPE$4.LeftParenthesis; var LEFTSQUAREBRACKET$1 = TYPE$4.LeftSquareBracket; var COMMA$1 = TYPE$4.Comma; var DELIM$1 = TYPE$4.Delim; var NUMBERSIGN$1 = 0x0023; // U+0023 NUMBER SIGN (#) var ASTERISK$1 = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN$1 = 0x002B; // U+002B PLUS SIGN (+) var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-) var SOLIDUS$1 = 0x002F; // U+002F SOLIDUS (/) var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u) var _default = function defaultRecognizer(context) { switch (this.scanner.tokenType) { case HASH$1: return this.Hash(); case COMMA$1: context.space = null; context.ignoreWSAfter = true; return this.Operator(); case LEFTPARENTHESIS$2: return this.Parentheses(this.readSequence, context.recognizer); case LEFTSQUAREBRACKET$1: return this.Brackets(this.readSequence, context.recognizer); case STRING$1: return this.String(); case DIMENSION$1: return this.Dimension(); case PERCENTAGE$1: return this.Percentage(); case NUMBER$1: return this.Number(); case FUNCTION$2: return cmpStr(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(') ? this.Url() : this.Function(this.readSequence, context.recognizer); case URL$2: return this.Url(); case IDENT$3: // check for unicode range, it should start with u+ or U+ if (cmpChar(this.scanner.source, this.scanner.tokenStart, U) && cmpChar(this.scanner.source, this.scanner.tokenStart + 1, PLUSSIGN$1)) { return this.UnicodeRange(); } else { return this.Identifier(); } case DELIM$1: var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); if (code === SOLIDUS$1 || code === ASTERISK$1 || code === PLUSSIGN$1 || code === HYPHENMINUS) { return this.Operator(); // TODO: replace with Delim } // TODO: produce a node with Delim node type if (code === NUMBERSIGN$1) { this.error('Hex or identifier is expected', this.scanner.tokenStart + 1); } break; } }; var atrulePrelude = { getNode: _default }; var TYPE$3 = tokenizer$3.TYPE; var DELIM = TYPE$3.Delim; var IDENT$2 = TYPE$3.Ident; var DIMENSION = TYPE$3.Dimension; var PERCENTAGE = TYPE$3.Percentage; var NUMBER = TYPE$3.Number; var HASH = TYPE$3.Hash; var COLON$1 = TYPE$3.Colon; var LEFTSQUAREBRACKET = TYPE$3.LeftSquareBracket; var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#) var ASTERISK = 0x002A; // U+002A ASTERISK (*) var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+) var SOLIDUS = 0x002F; // U+002F SOLIDUS (/) var FULLSTOP = 0x002E; // U+002E FULL STOP (.) var GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>) var VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|) var TILDE = 0x007E; // U+007E TILDE (~) function getNode(context) { switch (this.scanner.tokenType) { case LEFTSQUAREBRACKET: return this.AttributeSelector(); case HASH: return this.IdSelector(); case COLON$1: if (this.scanner.lookupType(1) === COLON$1) { return this.PseudoElementSelector(); } else { return this.PseudoClassSelector(); } case IDENT$2: return this.TypeSelector(); case NUMBER: case PERCENTAGE: return this.Percentage(); case DIMENSION: // throws when .123ident if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === FULLSTOP) { this.error('Identifier is expected', this.scanner.tokenStart + 1); } break; case DELIM: var code = this.scanner.source.charCodeAt(this.scanner.tokenStart); switch (code) { case PLUSSIGN: case GREATERTHANSIGN: case TILDE: context.space = null; context.ignoreWSAfter = true; return this.Combinator(); case SOLIDUS: // /deep/ return this.Combinator(); case FULLSTOP: return this.ClassSelector(); case ASTERISK: case VERTICALLINE: return this.TypeSelector(); case NUMBERSIGN: return this.IdSelector(); } break; } } var selector = { getNode: getNode }; // legacy IE function // expression( <any-value> ) var expression = function() { return this.createSingleNodeList( this.Raw(this.scanner.tokenIndex, null, false) ); }; var TYPE$2 = tokenizer$3.TYPE; var rawMode = Raw.mode; var COMMA = TYPE$2.Comma; var WHITESPACE$1 = TYPE$2.WhiteSpace; // var( <ident> , <value>? ) var _var = function() { var children = this.createList(); this.scanner.skipSC(); // NOTE: Don't check more than a first argument is an ident, rest checks are for lexer children.push(this.Identifier()); this.scanner.skipSC(); if (this.scanner.tokenType === COMMA) { children.push(this.Operator()); const startIndex = this.scanner.tokenIndex; const value = this.parseCustomProperty ? this.Value(null) : this.Raw(this.scanner.tokenIndex, rawMode.exclamationMarkOrSemicolon, false); if (value.type === 'Value' && value.children.isEmpty()) { for (let offset = startIndex - this.scanner.tokenIndex; offset <= 0; offset++) { if (this.scanner.lookupType(offset) === WHITESPACE$1) { value.children.appendData({ type: 'WhiteSpace', loc: null, value: ' ' }); break; } } } children.push(value); } return children; }; var value$2 = { getNode: _default, 'expression': expression, 'var': _var }; var scope = { AtrulePrelude: atrulePrelude, Selector: selector, Value: value$2 }; var fontFace = { parse: { prelude: null, block: function() { return this.Block(true); } } }; var TYPE$1 = tokenizer$3.TYPE; var STRING = TYPE$1.String; var IDENT$1 = TYPE$1.Ident; var URL$1 = TYPE$1.Url; var FUNCTION$1 = TYPE$1.Function; var LEFTPARENTHESIS$1 = TYPE$1.LeftParenthesis; var _import = { parse: { prelude: function() { var children = this.createList(); this.scanner.skipSC(); switch (this.scanner.tokenType) { case STRING: children.push(this.String()); break; case URL$1: case FUNCTION$1: children.push(this.Url()); break; default: this.error('String or url() is expected'); } if (this.lookupNonWSType(0) === IDENT$1 || this.lookupNonWSType(0) === LEFTPARENTHESIS$1) { children.push(this.WhiteSpace()); children.push(this.MediaQueryList()); } return children; }, block: null } }; var media = { parse: { prelude: function() { return this.createSingleNodeList( this.MediaQueryList() ); }, block: function() { return this.Block(false); } } }; var page = { parse: { prelude: function() { return this.createSingleNodeList( this.SelectorList() ); }, block: function() { return this.Block(true); } } }; var TYPE = tokenizer$3.TYPE; var WHITESPACE = TYPE.WhiteSpace; var COMMENT = TYPE.Comment; var IDENT = TYPE.Ident; var FUNCTION = TYPE.Function; var COLON = TYPE.Colon; var LEFTPARENTHESIS = TYPE.LeftParenthesis; function consumeRaw() { return this.createSingleNodeList( this.Raw(this.scanner.tokenIndex, null, false) ); } function parentheses() { this.scanner.skipSC(); if (this.scanner.tokenType === IDENT && this.lookupNonWSType(1) === COLON) { return this.createSingleNodeList( this.Declaration() ); } return readSequence.call(this); } function readSequence() { var children = this.createList(); var space = null; var child; this.scanner.skipSC(); scan: while (!this.scanner.eof) { switch (this.scanner.tokenType) { case WHITESPACE: space = this.WhiteSpace(); continue; case COMMENT: this.scanner.next(); continue; case FUNCTION: child = this.Function(consumeRaw, this.scope.AtrulePrelude); break; case IDENT: child = this.Identifier(); break; case LEFTPARENTHESIS: child = this.Parentheses(parentheses, this.scope.AtrulePrelude); break; default: break scan; } if (space !== null) { children.push(space); space = null; } children.push(child); } return children; } var supports = { parse: { prelude: function() { var children = readSequence.call(this); if (this.getFirstListNode(children) === null) { this.error('Condition is expected'); } return children; }, block: function() { return this.Block(false); } } }; var atrule = { 'font-face': fontFace, 'import': _import, 'media': media, 'page': page, 'supports': supports }; var dir = { parse: function() { return this.createSingleNodeList( this.Identifier() ); } }; var has = { parse: function() { return this.createSingleNodeList( this.SelectorList() ); } }; var lang = { parse: function() { return this.createSingleNodeList( this.Identifier() ); } }; var selectorList = { parse: function selectorList() { return this.createSingleNodeList( this.SelectorList() ); } }; var matches = selectorList; var not = selectorList; var ALLOW_OF_CLAUSE = true; var nthWithOfClause = { parse: function nthWithOfClause() { return this.createSingleNodeList( this.Nth(ALLOW_OF_CLAUSE) ); } }; var nthChild = nthWithOfClause; var nthLastChild = nthWithOfClause; var DISALLOW_OF_CLAUSE = false; var nth = { parse: function nth() { return this.createSingleNodeList( this.Nth(DISALLOW_OF_CLAUSE) ); } }; var nthLastOfType = nth; var nthOfType = nth; var slotted = { parse: function compoundSelector() { return this.createSingleNodeList( this.Selector() ); } }; var pseudo = { 'dir': dir, 'has': has, 'lang': lang, 'matches': matches, 'not': not, 'nth-child': nthChild, 'nth-last-child': nthLastChild, 'nth-last-of-type': nthLastOfType, 'nth-of-type': nthOfType, 'slotted': slotted }; var parser = { parseContext: { default: 'StyleSheet', stylesheet: 'StyleSheet', atrule: 'Atrule', atrulePrelude: function(options) { return this.AtrulePrelude(options.atrule ? String(options.atrule) : null); }, mediaQueryList: 'MediaQueryList', mediaQuery: 'MediaQuery', rule: 'Rule', selectorList: 'SelectorList', selector: 'Selector', block: function() { return this.Block(true); }, declarationList: 'DeclarationList', declaration: 'Declaration', value: 'Value' }, scope: scope, atrule: atrule, pseudo: pseudo, node: node }; var walker = { node: node }; var _args = [ [ "css-tree@1.1.3", "/home/gitlab-runner/builds/BQJy2NwB/0/pagedjs/pagedjs" ] ]; var _from = "css-tree@1.1.3"; var _id = "css-tree@1.1.3"; var _inBundle = false; var _integrity = "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q=="; var _location = "/css-tree"; var _phantomChildren = { }; var _requested = { type: "version", registry: true, raw: "css-tree@1.1.3", name: "css-tree", escapedName: "css-tree", rawSpec: "1.1.3", saveSpec: null, fetchSpec: "1.1.3" }; var _requiredBy = [ "/" ]; var _resolved = "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz"; var _spec = "1.1.3"; var _where = "/home/gitlab-runner/builds/BQJy2NwB/0/pagedjs/pagedjs"; var author = { name: "Roman Dvornov", email: "rdvornov@gmail.com", url: "https://github.com/lahmatiy" }; var bugs = { url: "https://github.com/csstree/csstree/issues" }; var dependencies = { "mdn-data": "2.0.14", "source-map": "^0.6.1" }; var description = "A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations"; var devDependencies = { "@rollup/plugin-commonjs": "^11.0.2", "@rollup/plugin-json": "^4.0.2", "@rollup/plugin-node-resolve": "^7.1.1", coveralls: "^3.0.9", eslint: "^6.8.0", "json-to-ast": "^2.1.0", mocha: "^6.2.3", nyc: "^14.1.1", rollup: "^1.32.1", "rollup-plugin-terser": "^5.3.0" }; var engines = { node: ">=8.0.0" }; var files = [ "data", "dist", "lib" ]; var homepage = "https://github.com/csstree/csstree#readme"; var jsdelivr = "dist/csstree.min.js"; var keywords = [ "css", "ast", "tokenizer", "parser", "walker", "lexer", "generator", "utils", "syntax", "validation" ]; var license = "MIT"; var main = "lib/index.js"; var name = "css-tree"; var repository = { type: "git", url: "git+https://github.com/csstree/csstree.git" }; var scripts = { build: "rollup --config", coverage: "nyc npm test", coveralls: "nyc report --reporter=text-lcov | coveralls", hydrogen: "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/parse --stat -o /dev/null", lint: "eslint data lib scripts test && node scripts/review-syntax-patch --lint && node scripts/update-docs --lint", "lint-and-test": "npm run lint && npm test", prepublishOnly: "npm run build", "review:syntax-patch": "node scripts/review-syntax-patch", test: "mocha --reporter progress", travis: "nyc npm run lint-and-test && npm run coveralls", "update:docs": "node scripts/update-docs" }; var unpkg = "dist/csstree.min.js"; var version = "1.1.3"; var require$$4 = { _args: _args, _from: _from, _id: _id, _inBundle: _inBundle, _integrity: _integrity, _location: _location, _phantomChildren: _phantomChildren, _requested: _requested, _requiredBy: _requiredBy, _resolved: _resolved, _spec: _spec, _where: _where, author: author, bugs: bugs, dependencies: dependencies, description: description, devDependencies: devDependencies, engines: engines, files: files, homepage: homepage, jsdelivr: jsdelivr, keywords: keywords, license: license, main: main, name: name, repository: repository, scripts: scripts, unpkg: unpkg, version: version }; function merge() { var dest = {}; for (var i = 0; i < arguments.length; i++) { var src = arguments[i]; for (var key in src) { dest[key] = src[key]; } } return dest; } syntax.exports = create$5.create( merge( lexer, parser, walker ) ); syntax.exports.version = require$$4.version; var lib = syntax.exports; class Sheet { constructor(url, hooks) { if (hooks) { this.hooks = hooks; } else { this.hooks = {}; this.hooks.onUrl = new Hook(this); this.hooks.onAtPage = new Hook(this); this.hooks.onAtMedia = new Hook(this); this.hooks.onRule = new Hook(this); this.hooks.onDeclaration = new Hook(this); this.hooks.onSelector = new Hook(this); this.hooks.onPseudoSelector = new Hook(this); this.hooks.onContent = new Hook(this); this.hooks.onImport = new Hook(this); this.hooks.beforeTreeParse = new Hook(this); this.hooks.beforeTreeWalk = new Hook(this); this.hooks.afterTreeWalk = new Hook(this); } try { this.url = new URL(url, window.location.href); } catch (e) { this.url = new URL(window.location.href); } } // parse async parse(text) { this.text = text; await this.hooks.beforeTreeParse.trigger(this.text, this); // send to csstree this.ast = lib.parse(this._text); await this.hooks.beforeTreeWalk.trigger(this.ast); // Replace urls this.replaceUrls(this.ast); // Scope this.id = UUID(); // this.addScope(this.ast, this.uuid); // Replace IDs with data-id this.replaceIds(this.ast); this.imported = []; // Trigger Hooks this.urls(this.ast); this.rules(this.ast); this.atrules(this.ast); await this.hooks.afterTreeWalk.trigger(this.ast, this); // return ast return this.ast; } insertRule(rule) { let inserted = this.ast.children.appendData(rule); this.declarations(rule); return inserted; } urls(ast) { lib.walk(ast, { visit: "Url", enter: (node, item, list) => { this.hooks.onUrl.trigger(node, item, list); } }); } atrules(ast) { lib.walk(ast, { visit: "Atrule", enter: (node, item, list) => { const basename = lib.keyword(node.name).basename; if (basename === "page") { this.hooks.onAtPage.trigger(node, item, list); this.declarations(node, item, list); } if (basename === "media") { this.hooks.onAtMedia.trigger(node, item, list); this.declarations(node, item, list); } if (basename === "import") { this.hooks.onImport.trigger(node, item, list); this.imports(node, item, list); } } }); } rules(ast) { lib.walk(ast, { visit: "Rule", enter: (ruleNode, ruleItem, rulelist) => { this.hooks.onRule.trigger(ruleNode, ruleItem, rulelist); this.declarations(ruleNode, ruleItem, rulelist); this.onSelector(ruleNode, ruleItem, rulelist); } }); } declarations(ruleNode, ruleItem, rulelist) { lib.walk(ruleNode, { visit: "Declaration", enter: (declarationNode, dItem, dList) => { this.hooks.onDeclaration.trigger(declarationNode, dItem, dList, {ruleNode, ruleItem, rulelist}); if (declarationNode.property === "content") { lib.walk(declarationNode, { visit: "Function", enter: (funcNode, fItem, fList) => { this.hooks.onContent.trigger(funcNode, fItem, fList, {declarationNode, dItem, dList}, {ruleNode, ruleItem, rulelist}); } }); } } }); } // add pseudo elements to parser onSelector(ruleNode, ruleItem, rulelist) { lib.walk(ruleNode, { visit: "Selector", enter: (selectNode, selectItem, selectList) => { this.hooks.onSelector.trigger(selectNode, selectItem, selectList, {ruleNode, ruleItem, rulelist}); if (selectNode.children.forEach(node => {if (node.type === "PseudoElementSelector") { lib.walk(node, { visit: "PseudoElementSelector", enter: (pseudoNode, pItem, pList) => { this.hooks.onPseudoSelector.trigger(pseudoNode, pItem, pList, {selectNode, selectItem, selectList}, {ruleNode, ruleItem, rulelist}); } }); }})); } }); } replaceUrls(ast) { lib.walk(ast, { visit: "Url", enter: (node, item, list) => { let content = node.value.value; if ((node.value.type === "Raw" && content.startsWith("data:")) || (node.value.type === "String" && (content.startsWith("\"data:") || content.startsWith("'data:")))) ; else { let href = content.replace(/["']/g, ""); let url = new URL(href, this.url); node.value.value = url.toString(); } } }); } addScope(ast, id) { // Get all selector lists // add an id lib.walk(ast, { visit: "Selector", enter: (node, item, list) => { let children = node.children; children.prepend(children.createItem({ type: "WhiteSpace", value: " " })); children.prepend(children.createItem({ type: "IdSelector", name: id, loc: null, children: null })); } }); } getNamedPageSelectors(ast) { let namedPageSelectors = {}; lib.walk(ast, { visit: "Rule", enter: (node, item, list) => { lib.walk(node, { visit: "Declaration", enter: (declaration, dItem, dList) => { if (declaration.property === "page") { let value = declaration.value.children.first(); let name = value.name; let selector = lib.generate(node.prelude); namedPageSelectors[name] = { name: name, selector: selector }; // dList.remove(dItem); // Add in page break declaration.property = "break-before"; value.type = "Identifier"; value.name = "always"; } } }); } }); return namedPageSelectors; } replaceIds(ast) { lib.walk(ast, { visit: "Rule", enter: (node, item, list) => { lib.walk(node, { visit: "IdSelector", enter: (idNode, idItem, idList) => { let name = idNode.name; idNode.flags = null; idNode.matcher = "="; idNode.name = {type: "Identifier", loc: null, name: "data-id"}; idNode.type = "AttributeSelector"; idNode.value = {type: "String", loc: null, value: `"${name}"`}; } }); } }); } imports(node, item, list) { // console.log("import", node, item, list); let queries = []; lib.walk(node, { visit: "MediaQuery", enter: (mqNode, mqItem, mqList) => { lib.walk(mqNode, { visit: "Identifier", enter: (identNode, identItem, identList) => { queries.push(identNode.name); } }); } }); // Just basic media query support for now let shouldNotApply = queries.some((query, index) => { let q = query; if (q === "not") { q = queries[index + 1]; return !(q === "screen" || q === "speech"); } else { return (q === "screen" || q === "speech"); } }); if (shouldNotApply) { return; } lib.walk(node, { visit: "String", enter: (urlNode, urlItem, urlList) => { let href = urlNode.value.replace(/["']/g, ""); let url = new URL(href, this.url); let value = url.toString(); this.imported.push(value); // Remove the original list.remove(item); } }); } set text(t) { this._text = t; } get text() { return this._text; } // generate string toString(ast) { return lib.generate(ast || this.ast); } } var baseStyles = ` :root { --pagedjs-width: 8.5in; --pagedjs-height: 11in; --pagedjs-width-right: 8.5in; --pagedjs-height-right: 11in; --pagedjs-width-left: 8.5in; --pagedjs-height-left: 11in; --pagedjs-pagebox-width: 8.5in; --pagedjs-pagebox-height: 11in; --pagedjs-footnotes-height: 0mm; --pagedjs-margin-top: 1in; --pagedjs-margin-right: 1in; --pagedjs-margin-bottom: 1in; --pagedjs-margin-left: 1in; --pagedjs-padding-top: 0mm; --pagedjs-padding-right: 0mm; --pagedjs-padding-bottom: 0mm; --pagedjs-padding-left: 0mm; --pagedjs-border-top: 0mm; --pagedjs-border-right: 0mm; --pagedjs-border-bottom: 0mm; --pagedjs-border-left: 0mm; --pagedjs-bleed-top: 0mm; --pagedjs-bleed-right: 0mm; --pagedjs-bleed-bottom: 0mm; --pagedjs-bleed-left: 0mm; --pagedjs-bleed-right-top: 0mm; --pagedjs-bleed-right-right: 0mm; --pagedjs-bleed-right-bottom: 0mm; --pagedjs-bleed-right-left: 0mm; --pagedjs-bleed-left-top: 0mm; --pagedjs-bleed-left-right: 0mm; --pagedjs-bleed-left-bottom: 0mm; --pagedjs-bleed-left-left: 0mm; --pagedjs-crop-color: black; --pagedjs-crop-shadow: white; --pagedjs-crop-offset: 2mm; --pagedjs-crop-stroke: 1px; --pagedjs-cross-size: 5mm; --pagedjs-mark-cross-display: none; --pagedjs-mark-crop-display: none; --pagedjs-page-count: 0; --pagedjs-page-counter-increment: 1; --pagedjs-footnotes-count: 0; --pagedjs-column-gap-offset: 1000px; } @page { size: letter; margin: 0; } .pagedjs_sheet { box-sizing: border-box; width: var(--pagedjs-width); height: var(--pagedjs-height); overflow: hidden; position: relative; display: grid; grid-template-columns: [bleed-left] var(--pagedjs-bleed-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-left) - var(--pagedjs-bleed-right)) [bleed-right] var(--pagedjs-bleed-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-top) - var(--pagedjs-bleed-bottom)) [bleed-bottom] var(--pagedjs-bleed-bottom); } .pagedjs_right_page .pagedjs_sheet { width: var(--pagedjs-width-right); height: var(--pagedjs-height-right); grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-right-left) - var(--pagedjs-bleed-right-right)) [bleed-right] var(--pagedjs-bleed-right-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-right-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-right-top) - var(--pagedjs-bleed-right-bottom)) [bleed-bottom] var(--pagedjs-bleed-right-bottom); } .pagedjs_left_page .pagedjs_sheet { width: var(--pagedjs-width-left); height: var(--pagedjs-height-left); grid-template-columns: [bleed-left] var(--pagedjs-bleed-left-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-left-left) - var(--pagedjs-bleed-left-right)) [bleed-right] var(--pagedjs-bleed-left-right); grid-template-rows: [bleed-top] var(--pagedjs-bleed-left-top) [sheet-middle] calc(var(--pagedjs-height) - var(--pagedjs-bleed-left-top) - var(--pagedjs-bleed-left-bottom)) [bleed-bottom] var(--pagedjs-bleed-left-bottom); } .pagedjs_bleed { display: flex; align-items: center; justify-content: center; flex-wrap: nowrap; overflow: hidden; } .pagedjs_bleed-top { grid-column: bleed-left / -1; grid-row: bleed-top; flex-direction: row; } .pagedjs_bleed-bottom { grid-column: bleed-left / -1; grid-row: bleed-bottom; flex-direction: row; } .pagedjs_bleed-left { grid-column: bleed-left; grid-row: bleed-top / -1; flex-direction: column; } .pagedjs_bleed-right { grid-column: bleed-right; grid-row: bleed-top / -1; flex-direction: column; } .pagedjs_marks-crop { display: var(--pagedjs-mark-crop-display); flex-grow: 0; flex-shrink: 0; z-index: 9999999999; } .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-left) - var(--pagedjs-crop-stroke)); border-right: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); box-shadow: 1px 0px 0px 0px var(--pagedjs-crop-shadow); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-right-left) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1), .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1) { width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-right) - var(--pagedjs-crop-stroke)); border-left: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); box-shadow: -1px 0px 0px 0px var(--pagedjs-crop-shadow); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-right-right) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(3), .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(3) { width: calc(var(--pagedjs-bleed-left-right) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-top .pagedjs_marks-crop { align-self: flex-start; height: calc(var(--pagedjs-bleed-top) - var(--pagedjs-crop-offset)); } .pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-right-top) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-top .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-left-top) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-bottom .pagedjs_marks-crop { align-self: flex-end; height: calc(var(--pagedjs-bleed-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-right-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-bottom .pagedjs_marks-crop { height: calc(var(--pagedjs-bleed-left-bottom) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-top) - var(--pagedjs-crop-stroke)); border-bottom: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); box-shadow: 0px 1px 0px 0px var(--pagedjs-crop-shadow); } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-right-top) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1), .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(1) { height: calc(var(--pagedjs-bleed-left-top) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-bottom) - var(--pagedjs-crop-stroke)); border-top: var(--pagedjs-crop-stroke) solid var(--pagedjs-crop-color); box-shadow: 0px -1px 0px 0px var(--pagedjs-crop-shadow); } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-right-bottom) - var(--pagedjs-crop-stroke)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3), .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop:nth-child(3) { height: calc(var(--pagedjs-bleed-left-bottom) - var(--pagedjs-crop-stroke)); } .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left) - var(--pagedjs-crop-offset)); align-self: flex-start; } .pagedjs_right_page .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right-left) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-left .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-offset)); } .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right) - var(--pagedjs-crop-offset)); align-self: flex-end; } .pagedjs_right_page .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-right-right) - var(--pagedjs-crop-offset)); } .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop { width: calc(var(--pagedjs-bleed-left-right) - var(--pagedjs-crop-offset)); } .pagedjs_marks-middle { display: flex; flex-grow: 1; flex-shrink: 0; align-items: center; justify-content: center; } .pagedjs_marks-cross { display: var(--pagedjs-mark-cross-display); background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIzMi41MzdweCIgaGVpZ2h0PSIzMi41MzdweCIgdmlld0JveD0iMC4xMDQgMC4xMDQgMzIuNTM3IDMyLjUzNyIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwLjEwNCAwLjEwNCAzMi41MzcgMzIuNTM3IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMy4zODkzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIGQ9Ik0yOS45MzEsMTYuMzczYzAsNy40ODktNi4wNjgsMTMuNTYtMTMuNTU4LDEzLjU2Yy03LjQ4MywwLTEzLjU1Ny02LjA3Mi0xMy41NTctMTMuNTZjMC03LjQ4Niw2LjA3NC0xMy41NTQsMTMuNTU3LTEzLjU1NEMyMy44NjIsMi44MTksMjkuOTMxLDguODg3LDI5LjkzMSwxNi4zNzN6Ii8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjMuMzg5MyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMC4xMDQiIHkxPSIxNi4zNzMiIHgyPSIzMi42NDIiIHkyPSIxNi4zNzMiLz48bGluZSBmaWxsPSJub25lIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMy4zODkzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHgxPSIxNi4zNzMiIHkxPSIwLjEwNCIgeDI9IjE2LjM3MyIgeTI9IjMyLjY0MiIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIzLjM4OTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgZD0iTTI0LjUwOCwxNi4zNzNjMCw0LjQ5Ni0zLjYzOCw4LjEzNS04LjEzNSw4LjEzNWMtNC40OTEsMC04LjEzNS0zLjYzOC04LjEzNS04LjEzNWMwLTQuNDg5LDMuNjQ0LTguMTM1LDguMTM1LTguMTM1QzIwLjg2OSw4LjIzOSwyNC41MDgsMTEuODg0LDI0LjUwOCwxNi4zNzN6Ii8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBkPSJNMjkuOTMxLDE2LjM3M2MwLDcuNDg5LTYuMDY4LDEzLjU2LTEzLjU1OCwxMy41NmMtNy40ODMsMC0xMy41NTctNi4wNzItMTMuNTU3LTEzLjU2YzAtNy40ODYsNi4wNzQtMTMuNTU0LDEzLjU1Ny0xMy41NTRDMjMuODYyLDIuODE5LDI5LjkzMSw4Ljg4NywyOS45MzEsMTYuMzczeiIvPjxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSIwLjY3NzgiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjAuMTA0IiB5MT0iMTYuMzczIiB4Mj0iMzIuNjQyIiB5Mj0iMTYuMzczIi8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMTYuMzczIiB5MT0iMC4xMDQiIHgyPSIxNi4zNzMiIHkyPSIzMi42NDIiLz48cGF0aCBkPSJNMjQuNTA4LDE2LjM3M2MwLDQuNDk2LTMuNjM4LDguMTM1LTguMTM1LDguMTM1Yy00LjQ5MSwwLTguMTM1LTMuNjM4LTguMTM1LTguMTM1YzAtNC40ODksMy42NDQtOC4xMzUsOC4xMzUtOC4xMzVDMjAuODY5LDguMjM5LDI0LjUwOCwxMS44ODQsMjQuNTA4LDE2LjM3MyIvPjxsaW5lIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIwLjY3NzgiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgeDE9IjguMjM5IiB5MT0iMTYuMzczIiB4Mj0iMjQuNTA4IiB5Mj0iMTYuMzczIi8+PGxpbmUgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2Utd2lkdGg9IjAuNjc3OCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiB4MT0iMTYuMzczIiB5MT0iOC4yMzkiIHgyPSIxNi4zNzMiIHkyPSIyNC41MDgiLz48L3N2Zz4=); background-repeat: no-repeat; background-position: 50% 50%; background-size: var(--pagedjs-cross-size); z-index: 2147483647; width: var(--pagedjs-cross-size); height: var(--pagedjs-cross-size); } .pagedjs_pagebox { box-sizing: border-box; width: var(--pagedjs-pagebox-width); height: var(--pagedjs-pagebox-height); position: relative; display: grid; grid-template-columns: [left] var(--pagedjs-margin-left) [center] calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)) [right] var(--pagedjs-margin-right); grid-template-rows: [header] var(--pagedjs-margin-top) [page] calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)) [footer] var(--pagedjs-margin-bottom); grid-column: sheet-center; grid-row: sheet-middle; } .pagedjs_pagebox * { box-sizing: border-box; } .pagedjs_margin-top { width: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)); height: var(--pagedjs-margin-top); grid-column: center; grid-row: header; flex-wrap: nowrap; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 100%; } .pagedjs_margin-top-left-corner-holder { width: var(--pagedjs-margin-left); height: var(--pagedjs-margin-top); display: flex; grid-column: left; grid-row: header; } .pagedjs_margin-top-right-corner-holder { width: var(--pagedjs-margin-right); height: var(--pagedjs-margin-top); display: flex; grid-column: right; grid-row: header; } .pagedjs_margin-top-left-corner { width: var(--pagedjs-margin-left); } .pagedjs_margin-top-right-corner { width: var(--pagedjs-margin-right); } .pagedjs_margin-right { height: calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)); width: var(--pagedjs-margin-right); right: 0; grid-column: right; grid-row: page; display: grid; grid-template-rows: repeat(3, 33.3333%); grid-template-columns: 100%; } .pagedjs_margin-bottom { width: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right)); height: var(--pagedjs-margin-bottom); grid-column: center; grid-row: footer; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 100%; } .pagedjs_margin-bottom-left-corner-holder { width: var(--pagedjs-margin-left); height: var(--pagedjs-margin-bottom); display: flex; grid-column: left; grid-row: footer; } .pagedjs_margin-bottom-right-corner-holder { width: var(--pagedjs-margin-right); height: var(--pagedjs-margin-bottom); display: flex; grid-column: right; grid-row: footer; } .pagedjs_margin-bottom-left-corner { width: var(--pagedjs-margin-left); } .pagedjs_margin-bottom-right-corner { width: var(--pagedjs-margin-right); } .pagedjs_margin-left { height: calc(var(--pagedjs-pagebox-height) - var(--pagedjs-margin-top) - var(--pagedjs-margin-bottom)); width: var(--pagedjs-margin-left); grid-column: left; grid-row: page; display: grid; grid-template-rows: repeat(3, 33.33333%); grid-template-columns: 100%; } .pagedjs_pages .pagedjs_pagebox .pagedjs_margin:not(.hasContent) { visibility: hidden; } .pagedjs_pagebox > .pagedjs_area { grid-column: center; grid-row: page; width: 100%; height: 100%; padding: var(--pagedjs-padding-top) var(--pagedjs-padding-right) var(--pagedjs-padding-bottom) var(--pagedjs-padding-left); border-top: var(--pagedjs-border-top); border-right: var(--pagedjs-border-right); border-bottom: var(--pagedjs-border-bottom); border-left: var(--pagedjs-border-left); } .pagedjs_pagebox > .pagedjs_area > .pagedjs_page_content { width: 100%; height: calc(100% - var(--pagedjs-footnotes-height)); position: relative; column-fill: auto; } .pagedjs_pagebox > .pagedjs_area > .pagedjs_page_content > div { height: inherit; } .pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area { position: relative; overflow: hidden; height: var(--pagedjs-footnotes-height); display: flex; justify-content: flex-end; flex-flow: column; } .pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_content { overflow: hidden; } .pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_inner_content { overflow: hidden; } .pagedjs_area [data-footnote-call] { all: unset; counter-increment: footnote; } .pagedjs_area [data-split-from] { counter-increment: unset; counter-reset: unset; } [data-footnote-call]::after { vertical-align: super; font-size: 65%; line-height: normal; content: counter(footnote); } @supports ( font-variant-position: super ) { [data-footnote-call]::after { vertical-align: baseline; font-size: 100%; line-height: inherit; font-variant-position: super; } } .pagedjs_footnote_empty { display: none; } .pagedjs_area [data-split-from] { counter-increment: unset; counter-reset: unset; } [data-footnote-marker] { text-indent: 0; display: list-item; list-style-position: inside; } [data-footnote-marker][data-split-from] { list-style: none; } [data-footnote-marker]:not([data-split-from]) { counter-increment: footnote-marker; } [data-footnote-marker]::marker { content: counter(footnote-marker) ". "; } [data-footnote-marker][data-split-from]::marker { content: unset; } .pagedjs_area .pagedjs_footnote_inner_content [data-note-display="inline"] { display: inline; } .pagedjs_page { counter-increment: page var(--pagedjs-page-counter-increment); width: var(--pagedjs-width); height: var(--pagedjs-height); } .pagedjs_page.pagedjs_right_page { width: var(--pagedjs-width-right); height: var(--pagedjs-height-right); } .pagedjs_page.pagedjs_left_page { width: var(--pagedjs-width-left); height: var(--pagedjs-height-left); } .pagedjs_pages { counter-reset: pages var(--pagedjs-page-count) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-count); } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner, .pagedjs_pagebox .pagedjs_margin-top-left, .pagedjs_pagebox .pagedjs_margin-top-right, .pagedjs_pagebox .pagedjs_margin-bottom-left, .pagedjs_pagebox .pagedjs_margin-bottom-right, .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_margin-right-middle, .pagedjs_margin-left-middle { display: flex; align-items: center; } .pagedjs_margin-right-top, .pagedjs_margin-left-top { display: flex; align-items: flex-top; } .pagedjs_margin-right-bottom, .pagedjs_margin-left-bottom { display: flex; align-items: flex-end; } /* .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center { height: 100%; display: none; align-items: center; flex: 1 0 33%; margin: 0 auto; } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner { display: none; align-items: center; } .pagedjs_pagebox .pagedjs_margin-left-top, .pagedjs_pagebox .pagedjs_margin-right-top { display: none; align-items: flex-start; } .pagedjs_pagebox .pagedjs_margin-right-middle, .pagedjs_pagebox .pagedjs_margin-left-middle { display: none; align-items: center; } .pagedjs_pagebox .pagedjs_margin-left-bottom, .pagedjs_pagebox .pagedjs_margin-right-bottom { display: none; align-items: flex-end; } */ .pagedjs_pagebox .pagedjs_margin-top-left, .pagedjs_pagebox .pagedjs_margin-top-right-corner, .pagedjs_pagebox .pagedjs_margin-bottom-left, .pagedjs_pagebox .pagedjs_margin-bottom-right-corner { text-align: left; } .pagedjs_pagebox .pagedjs_margin-top-left-corner, .pagedjs_pagebox .pagedjs_margin-top-right, .pagedjs_pagebox .pagedjs_margin-bottom-left-corner, .pagedjs_pagebox .pagedjs_margin-bottom-right { text-align: right; } .pagedjs_pagebox .pagedjs_margin-top-center, .pagedjs_pagebox .pagedjs_margin-bottom-center, .pagedjs_pagebox .pagedjs_margin-left-top, .pagedjs_pagebox .pagedjs_margin-left-middle, .pagedjs_pagebox .pagedjs_margin-left-bottom, .pagedjs_pagebox .pagedjs_margin-right-top, .pagedjs_pagebox .pagedjs_margin-right-middle, .pagedjs_pagebox .pagedjs_margin-right-bottom { text-align: center; } .pagedjs_pages .pagedjs_margin .pagedjs_margin-content { width: 100%; } .pagedjs_pages .pagedjs_margin-left .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-top .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-right .pagedjs_margin-content::after, .pagedjs_pages .pagedjs_margin-bottom .pagedjs_margin-content::after { display: block; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to] { margin-bottom: unset; padding-bottom: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from] { text-indent: unset; margin-top: unset; padding-top: unset; initial-letter: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from] > *::first-letter, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]::first-letter { color: unset; font-size: unset; font-weight: unset; font-family: unset; color: unset; line-height: unset; float: unset; padding: unset; margin: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:not([data-footnote-call]):after, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:not([data-footnote-call])::after { content: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call]):before, .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call])::before { content: unset; } .pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div li[data-split-from]:first-of-type { list-style: none; } /* [data-page]:not([data-split-from]), [data-break-before="page"]:not([data-split-from]), [data-break-before="always"]:not([data-split-from]), [data-break-before="left"]:not([data-split-from]), [data-break-before="right"]:not([data-split-from]), [data-break-before="recto"]:not([data-split-from]), [data-break-before="verso"]:not([data-split-from]) { break-before: column; } [data-page]:not([data-split-to]), [data-break-after="page"]:not([data-split-to]), [data-break-after="always"]:not([data-split-to]), [data-break-after="left"]:not([data-split-to]), [data-break-after="right"]:not([data-split-to]), [data-break-after="recto"]:not([data-split-to]), [data-break-after="verso"]:not([data-split-to]) { break-after: column; } */ .pagedjs_clear-after::after { content: none !important; } [data-align-last-split-element='justify'] { text-align-last: justify; } @media print { html { width: 100%; height: 100%; -webkit-print-color-adjust: exact; print-color-adjust: exact; } body { margin: 0; padding: 0; width: 100% !important; height: 100% !important; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; } .pagedjs_pages { width: auto; display: block !important; transform: none !important; height: 100% !important; min-height: 100%; max-height: 100%; overflow: visible; } .pagedjs_page { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; page-break-after: always; break-after: page; } .pagedjs_sheet { margin: 0; padding: 0; max-height: 100%; min-height: 100%; height: 100% !important; } } `; async function request(url, options={}) { return new Promise(function(resolve, reject) { let request = new XMLHttpRequest(); request.open(options.method || "get", url, true); for (let i in options.headers) { request.setRequestHeader(i, options.headers[i]); } request.withCredentials = options.credentials === "include"; request.onload = () => { // Chrome returns a status code of 0 for local files const status = request.status === 0 && url.startsWith("file://") ? 200 : request.status; resolve(new Response(request.responseText, {status})); }; request.onerror = reject; request.send(options.body || null); }); } class Polisher { constructor(setup) { this.sheets = []; this.inserted = []; this.hooks = {}; this.hooks.onUrl = new Hook(this); this.hooks.onAtPage = new Hook(this); this.hooks.onAtMedia = new Hook(this); this.hooks.onRule = new Hook(this); this.hooks.onDeclaration = new Hook(this); this.hooks.onContent = new Hook(this); this.hooks.onSelector = new Hook(this); this.hooks.onPseudoSelector = new Hook(this); this.hooks.onImport = new Hook(this); this.hooks.beforeTreeParse = new Hook(this); this.hooks.beforeTreeWalk = new Hook(this); this.hooks.afterTreeWalk = new Hook(this); if (setup !== false) { this.setup(); } } setup() { this.base = this.insert(baseStyles); this.styleEl = document.createElement("style"); document.head.appendChild(this.styleEl); this.styleSheet = this.styleEl.sheet; return this.styleSheet; } async add() { let fetched = []; let urls = []; for (var i = 0; i < arguments.length; i++) { let f; if (typeof arguments[i] === "object") { for (let url in arguments[i]) { let obj = arguments[i]; f = new Promise(function(resolve, reject) { urls.push(url); resolve(obj[url]); }); } } else { urls.push(arguments[i]); f = request(arguments[i]).then((response) => { return response.text(); }); } fetched.push(f); } return await Promise.all(fetched) .then(async (originals) => { let text = ""; for (let index = 0; index < originals.length; index++) { text = await this.convertViaSheet(originals[index], urls[index]); this.insert(text); } return text; }); } async convertViaSheet(cssStr, href) { let sheet = new Sheet(href, this.hooks); await sheet.parse(cssStr); // Insert the imported sheets first for (let url of sheet.imported) { let str = await request(url).then((response) => { return response.text(); }); let text = await this.convertViaSheet(str, url); this.insert(text); } this.sheets.push(sheet); if (typeof sheet.width !== "undefined") { this.width = sheet.width; } if (typeof sheet.height !== "undefined") { this.height = sheet.height; } if (typeof sheet.orientation !== "undefined") { this.orientation = sheet.orientation; } return sheet.toString(); } insert(text){ let head = document.querySelector("head"); let style = document.createElement("style"); style.setAttribute("data-pagedjs-inserted-styles", "true"); style.appendChild(document.createTextNode(text)); head.appendChild(style); this.inserted.push(style); return style; } destroy() { this.styleEl.remove(); this.inserted.forEach((s) => { s.remove(); }); this.sheets = []; } } class Handler { constructor(chunker, polisher, caller) { let hooks = Object.assign({}, chunker && chunker.hooks, polisher && polisher.hooks, caller && caller.hooks); this.chunker = chunker; this.polisher = polisher; this.caller = caller; for (let name in hooks) { if (name in this) { let hook = hooks[name]; hook.register(this[name].bind(this)); } } } } EventEmitter(Handler.prototype); // https://www.w3.org/TR/css3-page/#page-size-prop var pageSizes = { "A0": { width: { value: 841, unit: "mm" }, height: { value: 1189, unit: "mm" } }, "A1": { width: { value: 594, unit: "mm" }, height: { value: 841, unit: "mm" } }, "A2": { width: { value: 420, unit: "mm" }, height: { value: 594, unit: "mm" } }, "A3": { width: { value: 297, unit: "mm" }, height: { value: 420, unit: "mm" } }, "A4": { width: { value: 210, unit: "mm" }, height: { value: 297, unit: "mm" } }, "A5": { width: { value: 148, unit: "mm" }, height: { value: 210, unit: "mm" } }, "A6": { width: { value: 105, unit: "mm" }, height: { value: 148, unit: "mm" } }, "A7": { width: { value: 74, unit: "mm" }, height: { value: 105, unit: "mm" } }, "A8": { width: { value: 52, unit: "mm" }, height: { value: 74, unit: "mm" } }, "A9": { width: { value: 37, unit: "mm" }, height: { value: 52, unit: "mm" } }, "A10": { width: { value: 26, unit: "mm" }, height: { value: 37, unit: "mm" } }, "B4": { width: { value: 250, unit: "mm" }, height: { value: 353, unit: "mm" } }, "B5": { width: { value: 176, unit: "mm" }, height: { value: 250, unit: "mm" } }, "letter": { width: { value: 8.5, unit: "in" }, height: { value: 11, unit: "in" } }, "legal": { width: { value: 8.5, unit: "in" }, height: { value: 14, unit: "in" } }, "ledger": { width: { value: 11, unit: "in" }, height: { value: 17, unit: "in" } } }; class AtPage extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.pages = {}; this.width = undefined; this.height = undefined; this.orientation = undefined; this.marginalia = {}; } pageModel(selector) { return { selector: selector, name: undefined, psuedo: undefined, nth: undefined, marginalia: {}, width: undefined, height: undefined, orientation: undefined, margin: { top: {}, right: {}, left: {}, bottom: {} }, padding: { top: {}, right: {}, left: {}, bottom: {} }, border: { top: {}, right: {}, left: {}, bottom: {} }, backgroundOrigin: undefined, block: {}, marks: undefined, notes: undefined, added: false }; } // Find and Remove @page rules onAtPage(node, item, list) { let page, marginalia; let selector = ""; let named, psuedo, nth; let needsMerge = false; if (node.prelude) { named = this.getTypeSelector(node); psuedo = this.getPsuedoSelector(node); nth = this.getNthSelector(node); selector = lib.generate(node.prelude); } else { selector = "*"; } if (selector in this.pages) { // this.pages[selector] = Object.assign(this.pages[selector], page); // console.log("after", selector, this.pages[selector]); // this.pages[selector].added = false; page = this.pages[selector]; marginalia = this.replaceMarginalia(node); needsMerge = true; // Mark page for getting classes added again page.added = false; } else { page = this.pageModel(selector); marginalia = this.replaceMarginalia(node); this.pages[selector] = page; } page.name = named; page.psuedo = psuedo; page.nth = nth; if (needsMerge) { page.marginalia = Object.assign(page.marginalia, marginalia); } else { page.marginalia = marginalia; } let notes = this.replaceNotes(node); page.notes = notes; let declarations = this.replaceDeclarations(node); if (declarations.size) { page.size = declarations.size; page.width = declarations.size.width; page.height = declarations.size.height; page.orientation = declarations.size.orientation; page.format = declarations.size.format; } if (declarations.bleed && declarations.bleed[0] != "auto") { switch (declarations.bleed.length) { case 4: // top right bottom left page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[2], left: declarations.bleed[3] }; break; case 3: // top right bottom right page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[2], left: declarations.bleed[1] }; break; case 2: // top right top right page.bleed = { top: declarations.bleed[0], right: declarations.bleed[1], bottom: declarations.bleed[0], left: declarations.bleed[1] }; break; default: page.bleed = { top: declarations.bleed[0], right: declarations.bleed[0], bottom: declarations.bleed[0], left: declarations.bleed[0] }; } } if (declarations.marks) { if (!declarations.bleed || declarations.bleed && declarations.bleed[0] === "auto") { // Spec say 6pt, but needs more space for marks page.bleed = { top: { value: 6, unit: "mm" }, right: { value: 6, unit: "mm" }, bottom: { value: 6, unit: "mm" }, left: { value: 6, unit: "mm" } }; } page.marks = declarations.marks; } if (declarations.margin) { page.margin = declarations.margin; } if (declarations.padding) { page.padding = declarations.padding; } if (declarations.border) { page.border = declarations.border; } if (declarations.marks) { page.marks = declarations.marks; } if (needsMerge) { page.block.children.appendList(node.block.children); } else { page.block = node.block; } // Remove the rule list.remove(item); } /* Handled in breaks */ /* afterParsed(parsed) { for (let b in this.named) { // Find elements let elements = parsed.querySelectorAll(b); // Add break data for (var i = 0; i < elements.length; i++) { elements[i].setAttribute("data-page", this.named[b]); } } } */ afterTreeWalk(ast, sheet) { let dirtyPage = "*" in this.pages && this.pages["*"].added === false; this.addPageClasses(this.pages, ast, sheet); if (dirtyPage) { let width = this.pages["*"].width; let height = this.pages["*"].height; let format = this.pages["*"].format; let orientation = this.pages["*"].orientation; let bleed = this.pages["*"].bleed; let marks = this.pages["*"].marks; let bleedverso = undefined; let bleedrecto = undefined; if (":left" in this.pages) { bleedverso = this.pages[":left"].bleed; } if (":right" in this.pages) { bleedrecto = this.pages[":right"].bleed; } if ((width && height) && (this.width !== width || this.height !== height)) { this.width = width; this.height = height; this.format = format; this.orientation = orientation; this.addRootVars(ast, width, height, orientation, bleed, bleedrecto, bleedverso, marks); this.addRootPage(ast, this.pages["*"].size, bleed, bleedrecto, bleedverso); this.emit("size", { width, height, orientation, format, bleed }); this.emit("atpages", this.pages); } } } getTypeSelector(ast) { // Find page name let name; lib.walk(ast, { visit: "TypeSelector", enter: (node, item, list) => { name = node.name; } }); return name; } getPsuedoSelector(ast) { // Find if it has :left & :right & :black & :first let name; lib.walk(ast, { visit: "PseudoClassSelector", enter: (node, item, list) => { if (node.name !== "nth") { name = node.name; } } }); return name; } getNthSelector(ast) { // Find if it has :nth let nth; lib.walk(ast, { visit: "PseudoClassSelector", enter: (node, item, list) => { if (node.name === "nth" && node.children) { let raw = node.children.first(); nth = raw.value; } } }); return nth; } replaceMarginalia(ast) { let parsed = {}; const MARGINS = [ "top-left-corner", "top-left", "top", "top-center", "top-right", "top-right-corner", "bottom-left-corner", "bottom-left", "bottom", "bottom-center", "bottom-right", "bottom-right-corner", "left-top", "left-middle", "left", "left-bottom", "top-right-corner", "right-top", "right-middle", "right", "right-bottom", "right-right-corner" ]; lib.walk(ast.block, { visit: "Atrule", enter: (node, item, list) => { let name = node.name; if (MARGINS.includes(name)) { if (name === "top") { name = "top-center"; } if (name === "right") { name = "right-middle"; } if (name === "left") { name = "left-middle"; } if (name === "bottom") { name = "bottom-center"; } parsed[name] = node.block; list.remove(item); } } }); return parsed; } replaceNotes(ast) { let parsed = {}; lib.walk(ast.block, { visit: "Atrule", enter: (node, item, list) => { let name = node.name; if (name === "footnote") { parsed[name] = node.block; list.remove(item); } } }); return parsed; } replaceDeclarations(ast) { let parsed = {}; lib.walk(ast.block, { visit: "Declaration", enter: (declaration, dItem, dList) => { let prop = lib.property(declaration.property).name; // let value = declaration.value; if (prop === "marks") { parsed.marks = []; lib.walk(declaration, { visit: "Identifier", enter: (ident) => { parsed.marks.push(ident.name); } }); dList.remove(dItem); } else if (prop === "margin") { parsed.margin = this.getMargins(declaration); dList.remove(dItem); } else if (prop.indexOf("margin-") === 0) { let m = prop.substring("margin-".length); if (!parsed.margin) { parsed.margin = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.margin[m] = declaration.value.children.first(); dList.remove(dItem); } else if (prop === "padding") { parsed.padding = this.getPaddings(declaration.value); dList.remove(dItem); } else if (prop.indexOf("padding-") === 0) { let p = prop.substring("padding-".length); if (!parsed.padding) { parsed.padding = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.padding[p] = declaration.value.children.first(); dList.remove(dItem); } else if (prop === "border") { if (!parsed.border) { parsed.border = { top: {}, right: {}, left: {}, bottom: {} }; } parsed.border.top = lib.generate(declaration.value); parsed.border.right = lib.generate(declaration.value); parsed.border.left = lib.generate(declaration.value); parsed.border.bottom = lib.generate(declaration.value); dList.remove(dItem); } else if (prop.indexOf("border-") === 0) { if (!parsed.border) { parsed.border = { top: {}, right: {}, left: {}, bottom: {} }; } let p = prop.substring("border-".length); parsed.border[p] = lib.generate(declaration.value); dList.remove(dItem); } else if (prop === "size") { parsed.size = this.getSize(declaration); dList.remove(dItem); } else if (prop === "bleed") { parsed.bleed = []; lib.walk(declaration, { enter: (subNode) => { switch (subNode.type) { case "String": // bleed: "auto" if (subNode.value.indexOf("auto") > -1) { parsed.bleed.push("auto"); } break; case "Dimension": // bleed: 1in 2in, bleed: 20px ect. parsed.bleed.push({ value: subNode.value, unit: subNode.unit }); break; case "Number": parsed.bleed.push({ value: subNode.value, unit: "px" }); break; // ignore } } }); dList.remove(dItem); } } }); return parsed; } getSize(declaration) { let width, height, orientation, format; // Get size: Xmm Ymm lib.walk(declaration, { visit: "Dimension", enter: (node, item, list) => { let { value, unit } = node; if (typeof width === "undefined") { width = { value, unit }; } else if (typeof height === "undefined") { height = { value, unit }; } } }); // Get size: "A4" lib.walk(declaration, { visit: "String", enter: (node, item, list) => { let name = node.value.replace(/["|']/g, ""); let s = pageSizes[name]; if (s) { width = s.width; height = s.height; } } }); // Get Format or Landscape or Portrait lib.walk(declaration, { visit: "Identifier", enter: (node, item, list) => { let name = node.name; if (name === "landscape" || name === "portrait") { orientation = node.name; } else if (name !== "auto") { let s = pageSizes[name]; if (s) { width = s.width; height = s.height; } format = name; } } }); return { width, height, orientation, format }; } getMargins(declaration) { let margins = []; let margin = { top: {}, right: {}, left: {}, bottom: {} }; lib.walk(declaration, { enter: (node) => { switch (node.type) { case "Dimension": // margin: 1in 2in, margin: 20px, etc... margins.push(node); break; case "Number": // margin: 0 margins.push({value: node.value, unit: "px"}); break; // ignore } } }); if (margins.length === 1) { for (let m in margin) { margin[m] = margins[0]; } } else if (margins.length === 2) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[0]; margin.left = margins[1]; } else if (margins.length === 3) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[2]; margin.left = margins[1]; } else if (margins.length === 4) { margin.top = margins[0]; margin.right = margins[1]; margin.bottom = margins[2]; margin.left = margins[3]; } return margin; } getPaddings(declaration) { let paddings = []; let padding = { top: {}, right: {}, left: {}, bottom: {} }; lib.walk(declaration, { enter: (node) => { switch (node.type) { case "Dimension": // padding: 1in 2in, padding: 20px, etc... paddings.push(node); break; case "Number": // padding: 0 paddings.push({value: node.value, unit: "px"}); break; // ignore } } }); if (paddings.length === 1) { for (let p in padding) { padding[p] = paddings[0]; } } else if (paddings.length === 2) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[0]; padding.left = paddings[1]; } else if (paddings.length === 3) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[2]; padding.left = paddings[1]; } else if (paddings.length === 4) { padding.top = paddings[0]; padding.right = paddings[1]; padding.bottom = paddings[2]; padding.left = paddings[3]; } return padding; } // get values for the border on the @page to pass them to the element with the .pagedjs_area class getBorders(declaration) { let border = { top: {}, right: {}, left: {}, bottom: {} }; if (declaration.prop == "border") { border.top = lib.generate(declaration.value); border.right = lib.generate(declaration.value); border.bottom = lib.generate(declaration.value); border.left = lib.generate(declaration.value); } else if (declaration.prop == "border-top") { border.top = lib.generate(declaration.value); } else if (declaration.prop == "border-right") { border.right = lib.generate(declaration.value); } else if (declaration.prop == "border-bottom") { border.bottom = lib.generate(declaration.value); } else if (declaration.prop == "border-left") { border.left = lib.generate(declaration.value); } return border; } addPageClasses(pages, ast, sheet) { // First add * page if ("*" in pages && pages["*"].added === false) { let p = this.createPage(pages["*"], ast.children, sheet); sheet.insertRule(p); pages["*"].added = true; } // Add :left & :right if (":left" in pages && pages[":left"].added === false) { let left = this.createPage(pages[":left"], ast.children, sheet); sheet.insertRule(left); pages[":left"].added = true; } if (":right" in pages && pages[":right"].added === false) { let right = this.createPage(pages[":right"], ast.children, sheet); sheet.insertRule(right); pages[":right"].added = true; } // Add :first & :blank if (":first" in pages && pages[":first"].added === false) { let first = this.createPage(pages[":first"], ast.children, sheet); sheet.insertRule(first); pages[":first"].added = true; } if (":blank" in pages && pages[":blank"].added === false) { let blank = this.createPage(pages[":blank"], ast.children, sheet); sheet.insertRule(blank); pages[":blank"].added = true; } // Add nth pages for (let pg in pages) { if (pages[pg].nth && pages[pg].added === false) { let nth = this.createPage(pages[pg], ast.children, sheet); sheet.insertRule(nth); pages[pg].added = true; } } // Add named pages for (let pg in pages) { if (pages[pg].name && pages[pg].added === false) { let named = this.createPage(pages[pg], ast.children, sheet); sheet.insertRule(named); pages[pg].added = true; } } } createPage(page, ruleList, sheet) { let selectors = this.selectorsForPage(page); let children = page.block.children.copy(); let block = { type: "Block", loc: 0, children: children }; let rule = this.createRule(selectors, block); this.addMarginVars(page.margin, children, children.first()); this.addPaddingVars(page.padding, children, children.first()); this.addBorderVars(page.border, children, children.first()); if (page.width) { this.addDimensions(page.width, page.height, page.orientation, children, children.first()); } if (page.marginalia) { this.addMarginaliaStyles(page, ruleList, rule, sheet); this.addMarginaliaContent(page, ruleList, rule, sheet); } if(page.notes) { this.addNotesStyles(page.notes, page, ruleList, rule, sheet); } return rule; } addMarginVars(margin, list, item) { // variables for margins for (let m in margin) { if (typeof margin[m].value !== "undefined") { let value = margin[m].value + (margin[m].unit || ""); let mVar = list.createItem({ type: "Declaration", property: "--pagedjs-margin-" + m, value: { type: "Raw", value: value } }); list.append(mVar, item); } } } addPaddingVars(padding, list, item) { // variables for padding for (let p in padding) { if (typeof padding[p].value !== "undefined") { let value = padding[p].value + (padding[p].unit || ""); let pVar = list.createItem({ type: "Declaration", property: "--pagedjs-padding-" + p, value: { type: "Raw", value: value } }); list.append(pVar, item); } } } addBorderVars(border, list, item) { // variables for borders for (const name of Object.keys(border)) { const value = border[name]; // value is an empty object when undefined if (typeof value === "string") { const borderItem = list.createItem({ type: "Declaration", property: "--pagedjs-border-" + name, value: { type: "Raw", value: value } }); list.append(borderItem, item); } } } addDimensions(width, height, orientation, list, item) { let widthString, heightString; widthString = CSSValueToString(width); heightString = CSSValueToString(height); if (orientation && orientation !== "portrait") { // reverse for orientation [widthString, heightString] = [heightString, widthString]; } // width variable let wVar = this.createVariable("--pagedjs-pagebox-width", widthString); list.appendData(wVar); // height variable let hVar = this.createVariable("--pagedjs-pagebox-height", heightString); list.appendData(hVar); // let w = this.createDimension("width", width); // let h = this.createDimension("height", height); // list.appendData(w); // list.appendData(h); } addMarginaliaStyles(page, list, item, sheet) { for (let loc in page.marginalia) { let block = lib.clone(page.marginalia[loc]); let hasContent = false; if (block.children.isEmpty()) { continue; } lib.walk(block, { visit: "Declaration", enter: (node, item, list) => { if (node.property === "content") { if (node.value.children && node.value.children.first().name === "none") { hasContent = false; } else { hasContent = true; } list.remove(item); } if (node.property === "vertical-align") { lib.walk(node, { visit: "Identifier", enter: (identNode, identItem, identlist) => { let name = identNode.name; if (name === "top") { identNode.name = "flex-start"; } else if (name === "middle") { identNode.name = "center"; } else if (name === "bottom") { identNode.name = "flex-end"; } } }); node.property = "align-items"; } if (node.property === "width" && (loc === "top-left" || loc === "top-center" || loc === "top-right" || loc === "bottom-left" || loc === "bottom-center" || loc === "bottom-right")) { let c = lib.clone(node); c.property = "max-width"; list.appendData(c); } if (node.property === "height" && (loc === "left-top" || loc === "left-middle" || loc === "left-bottom" || loc === "right-top" || loc === "right-middle" || loc === "right-bottom")) { let c = lib.clone(node); c.property = "max-height"; list.appendData(c); } } }); let marginSelectors = this.selectorsForPageMargin(page, loc); let marginRule = this.createRule(marginSelectors, block); list.appendData(marginRule); let sel = lib.generate({ type: "Selector", children: marginSelectors }); this.marginalia[sel] = { page: page, selector: sel, block: page.marginalia[loc], hasContent: hasContent }; } } addMarginaliaContent(page, list, item, sheet) { let displayNone; // Just content for (let loc in page.marginalia) { let content = lib.clone(page.marginalia[loc]); lib.walk(content, { visit: "Declaration", enter: (node, item, list) => { if (node.property !== "content") { list.remove(item); } if (node.value.children && node.value.children.first().name === "none") { displayNone = true; } } }); if (content.children.isEmpty()) { continue; } let displaySelectors = this.selectorsForPageMargin(page, loc); let displayDeclaration; displaySelectors.insertData({ type: "Combinator", name: ">" }); displaySelectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-content" }); displaySelectors.insertData({ type: "Combinator", name: ">" }); displaySelectors.insertData({ type: "TypeSelector", name: "*" }); if (displayNone) { displayDeclaration = this.createDeclaration("display", "none"); } else { displayDeclaration = this.createDeclaration("display", "block"); } let displayRule = this.createRule(displaySelectors, [displayDeclaration]); sheet.insertRule(displayRule); // insert content rule let contentSelectors = this.selectorsForPageMargin(page, loc); contentSelectors.insertData({ type: "Combinator", name: ">" }); contentSelectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-content" }); contentSelectors.insertData({ type: "PseudoElementSelector", name: "after", children: null }); let contentRule = this.createRule(contentSelectors, content); sheet.insertRule(contentRule); } } addRootVars(ast, width, height, orientation, bleed, bleedrecto, bleedverso, marks) { let rules = []; let selectors = new lib.List(); selectors.insertData({ type: "PseudoClassSelector", name: "root", children: null }); let widthString, heightString; let widthStringRight, heightStringRight; let widthStringLeft, heightStringLeft; if (!bleed) { widthString = CSSValueToString(width); heightString = CSSValueToString(height); widthStringRight = CSSValueToString(width); heightStringRight = CSSValueToString(height); widthStringLeft = CSSValueToString(width); heightStringLeft = CSSValueToString(height); } else { widthString = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightString = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; widthStringRight = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightStringRight = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; widthStringLeft = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleed.left)} + ${CSSValueToString(bleed.right)} )`; heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleed.top)} + ${CSSValueToString(bleed.bottom)} )`; let bleedTop = this.createVariable("--pagedjs-bleed-top", CSSValueToString(bleed.top)); let bleedRight = this.createVariable("--pagedjs-bleed-right", CSSValueToString(bleed.right)); let bleedBottom = this.createVariable("--pagedjs-bleed-bottom", CSSValueToString(bleed.bottom)); let bleedLeft = this.createVariable("--pagedjs-bleed-left", CSSValueToString(bleed.left)); let bleedTopRecto = this.createVariable("--pagedjs-bleed-right-top", CSSValueToString(bleed.top)); let bleedRightRecto = this.createVariable("--pagedjs-bleed-right-right", CSSValueToString(bleed.right)); let bleedBottomRecto = this.createVariable("--pagedjs-bleed-right-bottom", CSSValueToString(bleed.bottom)); let bleedLeftRecto = this.createVariable("--pagedjs-bleed-right-left", CSSValueToString(bleed.left)); let bleedTopVerso = this.createVariable("--pagedjs-bleed-left-top", CSSValueToString(bleed.top)); let bleedRightVerso = this.createVariable("--pagedjs-bleed-left-right", CSSValueToString(bleed.right)); let bleedBottomVerso = this.createVariable("--pagedjs-bleed-left-bottom", CSSValueToString(bleed.bottom)); let bleedLeftVerso = this.createVariable("--pagedjs-bleed-left-left", CSSValueToString(bleed.left)); if (bleedrecto) { bleedTopRecto = this.createVariable("--pagedjs-bleed-right-top", CSSValueToString(bleedrecto.top)); bleedRightRecto = this.createVariable("--pagedjs-bleed-right-right", CSSValueToString(bleedrecto.right)); bleedBottomRecto = this.createVariable("--pagedjs-bleed-right-bottom", CSSValueToString(bleedrecto.bottom)); bleedLeftRecto = this.createVariable("--pagedjs-bleed-right-left", CSSValueToString(bleedrecto.left)); widthStringRight = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleedrecto.left)} + ${CSSValueToString(bleedrecto.right)} )`; heightStringRight = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedrecto.top)} + ${CSSValueToString(bleedrecto.bottom)} )`; } if (bleedverso) { bleedTopVerso = this.createVariable("--pagedjs-bleed-left-top", CSSValueToString(bleedverso.top)); bleedRightVerso = this.createVariable("--pagedjs-bleed-left-right", CSSValueToString(bleedverso.right)); bleedBottomVerso = this.createVariable("--pagedjs-bleed-left-bottom", CSSValueToString(bleedverso.bottom)); bleedLeftVerso = this.createVariable("--pagedjs-bleed-left-left", CSSValueToString(bleedverso.left)); widthStringLeft = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleedverso.left)} + ${CSSValueToString(bleedverso.right)} )`; heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedverso.top)} + ${CSSValueToString(bleedverso.bottom)} )`; } let pageWidthVar = this.createVariable("--pagedjs-width", CSSValueToString(width)); let pageHeightVar = this.createVariable("--pagedjs-height", CSSValueToString(height)); rules.push( bleedTop, bleedRight, bleedBottom, bleedLeft, bleedTopRecto, bleedRightRecto, bleedBottomRecto, bleedLeftRecto, bleedTopVerso, bleedRightVerso, bleedBottomVerso, bleedLeftVerso, pageWidthVar, pageHeightVar ); } if (marks) { marks.forEach((mark) => { let markDisplay = this.createVariable("--pagedjs-mark-" + mark + "-display", "block"); rules.push(markDisplay); }); } // orientation variable if (orientation) { let oVar = this.createVariable("--pagedjs-orientation", orientation); rules.push(oVar); if (orientation !== "portrait") { // reverse for orientation [widthString, heightString] = [heightString, widthString]; [widthStringRight, heightStringRight] = [heightStringRight, widthStringRight]; [widthStringLeft, heightStringLeft] = [heightStringLeft, widthStringLeft]; } } let wVar = this.createVariable("--pagedjs-width", widthString); let hVar = this.createVariable("--pagedjs-height", heightString); let wVarR = this.createVariable("--pagedjs-width-right", widthStringRight); let hVarR = this.createVariable("--pagedjs-height-right", heightStringRight); let wVarL = this.createVariable("--pagedjs-width-left", widthStringLeft); let hVarL = this.createVariable("--pagedjs-height-left", heightStringLeft); rules.push(wVar, hVar, wVarR, hVarR, wVarL, hVarL); let rule = this.createRule(selectors, rules); ast.children.appendData(rule); } addNotesStyles(notes, page, list, item, sheet) { for (const note in notes) { let selectors = this.selectorsForPage(page); selectors.insertData({ type: "Combinator", name: " " }); selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + note + "_content" }); let notesRule = this.createRule(selectors, notes[note]); list.appendData(notesRule); } } /* @page { size: var(--pagedjs-width) var(--pagedjs-height); margin: 0; padding: 0; } */ addRootPage(ast, size, bleed, bleedrecto, bleedverso) { let { width, height, orientation, format } = size; let children = new lib.List(); let childrenLeft = new lib.List(); let childrenRight = new lib.List(); let dimensions = new lib.List(); let dimensionsLeft = new lib.List(); let dimensionsRight = new lib.List(); if (bleed) { let widthCalculations = new lib.List(); let heightCalculations = new lib.List(); // width widthCalculations.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Operator", value: "+" }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Dimension", unit: bleed.left.unit, value: bleed.left.value }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Operator", value: "+" }); widthCalculations.appendData({ type: "WhiteSpace", value: " " }); widthCalculations.appendData({ type: "Dimension", unit: bleed.right.unit, value: bleed.right.value }); // height heightCalculations.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Operator", value: "+" }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Dimension", unit: bleed.top.unit, value: bleed.top.value }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Operator", value: "+" }); heightCalculations.appendData({ type: "WhiteSpace", value: " " }); heightCalculations.appendData({ type: "Dimension", unit: bleed.bottom.unit, value: bleed.bottom.value }); dimensions.appendData({ type: "Function", name: "calc", children: widthCalculations }); dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Function", name: "calc", children: heightCalculations }); } else if (format) { dimensions.appendData({ type: "Identifier", name: format }); if (orientation) { dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Identifier", name: orientation }); } } else { dimensions.appendData({ type: "Dimension", unit: width.unit, value: width.value }); dimensions.appendData({ type: "WhiteSpace", value: " " }); dimensions.appendData({ type: "Dimension", unit: height.unit, value: height.value }); } children.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensions } }); children.appendData({ type: "Declaration", property: "margin", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); children.appendData({ type: "Declaration", property: "padding", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); children.appendData({ type: "Declaration", property: "padding", loc: null, value: { type: "Value", children: [{ type: "Dimension", unit: "px", value: 0 }] } }); let rule = ast.children.createItem({ type: "Atrule", prelude: null, name: "page", block: { type: "Block", loc: null, children: children } }); ast.children.append(rule); if (bleedverso) { let widthCalculationsLeft = new lib.List(); let heightCalculationsLeft = new lib.List(); // width widthCalculationsLeft.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Operator", value: "+" }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.left.unit, value: bleedverso.left.value }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Operator", value: "+" }); widthCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.right.unit, value: bleedverso.right.value }); // height heightCalculationsLeft.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Operator", value: "+" }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.top.unit, value: bleedverso.top.value }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Operator", value: "+" }); heightCalculationsLeft.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsLeft.appendData({ type: "Dimension", unit: bleedverso.bottom.unit, value: bleedverso.bottom.value }); dimensionsLeft.appendData({ type: "Function", name: "calc", children: widthCalculationsLeft }); dimensionsLeft.appendData({ type: "WhiteSpace", value: " " }); dimensionsLeft.appendData({ type: "Function", name: "calc", children: heightCalculationsLeft }); childrenLeft.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensionsLeft } }); let ruleLeft = ast.children.createItem({ type: "Atrule", prelude: null, name: "page :left", block: { type: "Block", loc: null, children: childrenLeft } }); ast.children.append(ruleLeft); } if (bleedrecto) { let widthCalculationsRight = new lib.List(); let heightCalculationsRight = new lib.List(); // width widthCalculationsRight.appendData({ type: "Dimension", unit: width.unit, value: width.value }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Operator", value: "+" }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.left.unit, value: bleedrecto.left.value }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Operator", value: "+" }); widthCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); widthCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.right.unit, value: bleedrecto.right.value }); // height heightCalculationsRight.appendData({ type: "Dimension", unit: height.unit, value: height.value }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Operator", value: "+" }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.top.unit, value: bleedrecto.top.value }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Operator", value: "+" }); heightCalculationsRight.appendData({ type: "WhiteSpace", value: " " }); heightCalculationsRight.appendData({ type: "Dimension", unit: bleedrecto.bottom.unit, value: bleedrecto.bottom.value }); dimensionsRight.appendData({ type: "Function", name: "calc", children: widthCalculationsRight }); dimensionsRight.appendData({ type: "WhiteSpace", value: " " }); dimensionsRight.appendData({ type: "Function", name: "calc", children: heightCalculationsRight }); childrenRight.appendData({ type: "Declaration", property: "size", loc: null, value: { type: "Value", children: dimensionsRight } }); let ruleRight = ast.children.createItem({ type: "Atrule", prelude: null, name: "page :right", block: { type: "Block", loc: null, children: childrenRight } }); ast.children.append(ruleRight); } } getNth(nth) { let n = nth.indexOf("n"); let plus = nth.indexOf("+"); let splitN = nth.split("n"); let splitP = nth.split("+"); let a = null; let b = null; if (n > -1) { a = splitN[0]; if (plus > -1) { b = splitP[1]; } } else { b = nth; } return { type: "Nth", loc: null, selector: null, nth: { type: "AnPlusB", loc: null, a: a, b: b } }; } addPageAttributes(page, start, pages) { let namedPages = [start.dataset.page]; if (namedPages && namedPages.length) { for (const named of namedPages) { if (!named) { continue; } page.name = named; page.element.classList.add("pagedjs_named_page"); page.element.classList.add("pagedjs_" + named + "_page"); if (!start.dataset.splitFrom) { page.element.classList.add("pagedjs_" + named + "_first_page"); } } } } getStartElement(content, breakToken) { let node = breakToken && breakToken.node; if (!content && !breakToken) { return; } // No break if (!node) { return content.children[0]; } // Top level element if (node.nodeType === 1 && node.parentNode.nodeType === 11) { return node; } // Named page if (node.nodeType === 1 && node.dataset.page) { return node; } // Get top level Named parent let fragment = rebuildAncestors(node); let pages = fragment.querySelectorAll("[data-page]"); if (pages.length) { return pages[pages.length - 1]; } else { return fragment.children[0]; } } beforePageLayout(page, contents, breakToken, chunker) { let start = this.getStartElement(contents, breakToken); if (start) { this.addPageAttributes(page, start, chunker.pages); } // page.element.querySelector('.paged_area').style.color = red; } finalizePage(fragment, page, breakToken, chunker) { for (let m in this.marginalia) { let margin = this.marginalia[m]; let sels = m.split(" "); let content; if (page.element.matches(sels[0]) && margin.hasContent) { content = page.element.querySelector(sels[1]); content.classList.add("hasContent"); } } // check center ["top", "bottom"].forEach((loc) => { let marginGroup = page.element.querySelector(".pagedjs_margin-" + loc); let center = page.element.querySelector(".pagedjs_margin-" + loc + "-center"); let left = page.element.querySelector(".pagedjs_margin-" + loc + "-left"); let right = page.element.querySelector(".pagedjs_margin-" + loc + "-right"); let centerContent = center.classList.contains("hasContent"); let leftContent = left.classList.contains("hasContent"); let rightContent = right.classList.contains("hasContent"); let centerWidth, leftWidth, rightWidth; if (leftContent) { leftWidth = window.getComputedStyle(left)["max-width"]; } if (rightContent) { rightWidth = window.getComputedStyle(right)["max-width"]; } if (centerContent) { centerWidth = window.getComputedStyle(center)["max-width"]; if (centerWidth === "none" || centerWidth === "auto") { if (!leftContent && !rightContent) { marginGroup.style["grid-template-columns"] = "0 1fr 0"; } else if (leftContent) { if (!rightContent) { if (leftWidth !== "none" && leftWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + leftWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; left.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let centerOuterWidth = center.offsetWidth; let outerwidths = leftOuterWidth + centerOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; left.style["white-space"] = "normal"; center.style["white-space"] = "normal"; } } else { if (leftWidth !== "none" && leftWidth !== "auto") { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + leftWidth; } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = rightWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; left.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; right.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let centerOuterWidth = center.offsetWidth; let rightOuterWidth = right.offsetWidth; let outerwidths = leftOuterWidth + centerOuterWidth + rightOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; if (newcenterWidth > 40) { marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; } else { marginGroup.style["grid-template-columns"] = "repeat(3, 1fr)"; } left.style["white-space"] = "normal"; center.style["white-space"] = "normal"; right.style["white-space"] = "normal"; } } } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = rightWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto auto 1fr"; right.style["white-space"] = "nowrap"; center.style["white-space"] = "nowrap"; let rightOuterWidth = right.offsetWidth; let centerOuterWidth = center.offsetWidth; let outerwidths = rightOuterWidth + centerOuterWidth; let newcenterWidth = centerOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, 1fr) minmax(33%, " + newcenterWidth + "%) minmax(16.66%, 1fr)"; right.style["white-space"] = "normal"; center.style["white-space"] = "normal"; } } } else if (centerWidth !== "none" && centerWidth !== "auto") { if (leftContent && leftWidth !== "none" && leftWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " " + centerWidth + " 1fr"; } else if (rightContent && rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr " + centerWidth + " " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "1fr " + centerWidth + " 1fr"; } } } else { if (leftContent) { if (!rightContent) { marginGroup.style["grid-template-columns"] = "1fr 0 0"; } else { if (leftWidth !== "none" && leftWidth !== "auto") { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = leftWidth + " 1fr " + rightWidth; } else { marginGroup.style["grid-template-columns"] = leftWidth + " 0 1fr"; } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr 0 " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "auto 1fr auto"; left.style["white-space"] = "nowrap"; right.style["white-space"] = "nowrap"; let leftOuterWidth = left.offsetWidth; let rightOuterWidth = right.offsetWidth; let outerwidths = leftOuterWidth + rightOuterWidth; let newLeftWidth = leftOuterWidth * 100 / outerwidths; marginGroup.style["grid-template-columns"] = "minmax(16.66%, " + newLeftWidth + "%) 0 1fr"; left.style["white-space"] = "normal"; right.style["white-space"] = "normal"; } } } } else { if (rightWidth !== "none" && rightWidth !== "auto") { marginGroup.style["grid-template-columns"] = "1fr 0 " + rightWidth; } else { marginGroup.style["grid-template-columns"] = "0 0 1fr"; } } } }); // check middle ["left", "right"].forEach((loc) => { let middle = page.element.querySelector(".pagedjs_margin-" + loc + "-middle.hasContent"); let marginGroup = page.element.querySelector(".pagedjs_margin-" + loc); let top = page.element.querySelector(".pagedjs_margin-" + loc + "-top"); let bottom = page.element.querySelector(".pagedjs_margin-" + loc + "-bottom"); let topContent = top.classList.contains("hasContent"); let bottomContent = bottom.classList.contains("hasContent"); let middleHeight, topHeight, bottomHeight; if (topContent) { topHeight = window.getComputedStyle(top)["max-height"]; } if (bottomContent) { bottomHeight = window.getComputedStyle(bottom)["max-height"]; } if (middle) { middleHeight = window.getComputedStyle(middle)["max-height"]; if (middleHeight === "none" || middleHeight === "auto") { if (!topContent && !bottomContent) { marginGroup.style["grid-template-rows"] = "0 1fr 0"; } else if (topContent) { if (!bottomContent) { if (topHeight !== "none" && topHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + "*2) " + topHeight; } } else { if (topHeight !== "none" && topHeight !== "auto") { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + " - " + bottomHeight + ") " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = topHeight + " calc(100% - " + topHeight + "*2) " + topHeight; } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = bottomHeight + " calc(100% - " + bottomHeight + "*2) " + bottomHeight; } } } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = bottomHeight + " calc(100% - " + bottomHeight + "*2) " + bottomHeight; } } } else { if (topContent && topHeight !== "none" && topHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " " + middleHeight + " calc(100% - (" + topHeight + " + " + middleHeight + "))"; } else if (bottomContent && bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr " + middleHeight + " " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "calc((100% - " + middleHeight + ")/2) " + middleHeight + " calc((100% - " + middleHeight + ")/2)"; } } } else { if (topContent) { if (!bottomContent) { marginGroup.style["grid-template-rows"] = "1fr 0 0"; } else { if (topHeight !== "none" && topHeight !== "auto") { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = topHeight + " 1fr " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = topHeight + " 0 1fr"; } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr 0 " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "1fr 0 1fr"; } } } } else { if (bottomHeight !== "none" && bottomHeight !== "auto") { marginGroup.style["grid-template-rows"] = "1fr 0 " + bottomHeight; } else { marginGroup.style["grid-template-rows"] = "0 0 1fr"; } } } }); } // CSS Tree Helpers selectorsForPage(page) { let nthlist; let nth; let selectors = new lib.List(); selectors.insertData({ type: "ClassSelector", name: "pagedjs_page" }); // Named page if (page.name) { selectors.insertData({ type: "ClassSelector", name: "pagedjs_named_page" }); selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.name + "_page" }); } // PsuedoSelector if (page.psuedo && !(page.name && page.psuedo === "first")) { selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.psuedo + "_page" }); } if (page.name && page.psuedo === "first") { selectors.insertData({ type: "ClassSelector", name: "pagedjs_" + page.name + "_" + page.psuedo + "_page" }); } // Nth if (page.nth) { nthlist = new lib.List(); nth = this.getNth(page.nth); nthlist.insertData(nth); selectors.insertData({ type: "PseudoClassSelector", name: "nth-of-type", children: nthlist }); } return selectors; } selectorsForPageMargin(page, margin) { let selectors = this.selectorsForPage(page); selectors.insertData({ type: "Combinator", name: " " }); selectors.insertData({ type: "ClassSelector", name: "pagedjs_margin-" + margin }); return selectors; } createDeclaration(property, value, important) { let children = new lib.List(); children.insertData({ type: "Identifier", loc: null, name: value }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createVariable(property, value) { return { type: "Declaration", loc: null, property: property, value: { type: "Raw", value: value } }; } createCalculatedDimension(property, items, important, operator = "+") { let children = new lib.List(); let calculations = new lib.List(); items.forEach((item, index) => { calculations.appendData({ type: "Dimension", unit: item.unit, value: item.value }); calculations.appendData({ type: "WhiteSpace", value: " " }); if (index + 1 < items.length) { calculations.appendData({ type: "Operator", value: operator }); calculations.appendData({ type: "WhiteSpace", value: " " }); } }); children.insertData({ type: "Function", loc: null, name: "calc", children: calculations }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createDimension(property, cssValue, important) { let children = new lib.List(); children.insertData({ type: "Dimension", loc: null, value: cssValue.value, unit: cssValue.unit }); return { type: "Declaration", loc: null, important: important, property: property, value: { type: "Value", loc: null, children: children } }; } createBlock(declarations) { let block = new lib.List(); declarations.forEach((declaration) => { block.insertData(declaration); }); return { type: "Block", loc: null, children: block }; } createRule(selectors, block) { let selectorList = new lib.List(); selectorList.insertData({ type: "Selector", children: selectors }); if (Array.isArray(block)) { block = this.createBlock(block); } return { type: "Rule", prelude: { type: "SelectorList", children: selectorList }, block: block }; } } class Breaks extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.breaks = {}; } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "page") { let children = declaration.value.children.first(); let value = children.name; let selector = lib.generate(rule.ruleNode.prelude); let name = value; let breaker = { property: property, value: value, selector: selector, name: name }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); dList.remove(dItem); } if (property === "break-before" || property === "break-after" || property === "page-break-before" || property === "page-break-after" ) { let child = declaration.value.children.first(); let value = child.name; let selector = lib.generate(rule.ruleNode.prelude); if (property === "page-break-before") { property = "break-before"; } else if (property === "page-break-after") { property = "break-after"; } let breaker = { property: property, value: value, selector: selector }; selector.split(",").forEach((s) => { if (!this.breaks[s]) { this.breaks[s] = [breaker]; } else { this.breaks[s].push(breaker); } }); // Remove from CSS -- handle right / left in module dList.remove(dItem); } } afterParsed(parsed) { this.processBreaks(parsed, this.breaks); } processBreaks(parsed, breaks) { for (let b in breaks) { // Find elements let elements = parsed.querySelectorAll(b); // Add break data for (var i = 0; i < elements.length; i++) { for (let prop of breaks[b]) { if (prop.property === "break-after") { let nodeAfter = displayedElementAfter(elements[i], parsed); elements[i].setAttribute("data-break-after", prop.value); if (nodeAfter) { nodeAfter.setAttribute("data-previous-break-after", prop.value); } } else if (prop.property === "break-before") { let nodeBefore = displayedElementBefore(elements[i], parsed); // Breaks are only allowed between siblings, not between a box and its container. // If we cannot find a node before we should not break! // https://drafts.csswg.org/css-break-3/#break-propagation if (nodeBefore) { if (prop.value === "page" && needsPageBreak(elements[i], nodeBefore)) { // we ignore this explicit page break because an implicit page break is already needed continue; } elements[i].setAttribute("data-break-before", prop.value); nodeBefore.setAttribute("data-next-break-before", prop.value); } } else if (prop.property === "page") { elements[i].setAttribute("data-page", prop.value); let nodeAfter = displayedElementAfter(elements[i], parsed); if (nodeAfter) { nodeAfter.setAttribute("data-after-page", prop.value); } } else { elements[i].setAttribute("data-" + prop.property, prop.value); } } } } } mergeBreaks(pageBreaks, newBreaks) { for (let b in newBreaks) { if (b in pageBreaks) { pageBreaks[b] = pageBreaks[b].concat(newBreaks[b]); } else { pageBreaks[b] = newBreaks[b]; } } return pageBreaks; } addBreakAttributes(pageElement, page) { let before = pageElement.querySelector("[data-break-before]"); let after = pageElement.querySelector("[data-break-after]"); let previousBreakAfter = pageElement.querySelector("[data-previous-break-after]"); if (before) { if (before.dataset.splitFrom) { page.splitFrom = before.dataset.splitFrom; pageElement.setAttribute("data-split-from", before.dataset.splitFrom); } else if (before.dataset.breakBefore && before.dataset.breakBefore !== "avoid") { page.breakBefore = before.dataset.breakBefore; pageElement.setAttribute("data-break-before", before.dataset.breakBefore); } } if (after && after.dataset) { if (after.dataset.splitTo) { page.splitTo = after.dataset.splitTo; pageElement.setAttribute("data-split-to", after.dataset.splitTo); } else if (after.dataset.breakAfter && after.dataset.breakAfter !== "avoid") { page.breakAfter = after.dataset.breakAfter; pageElement.setAttribute("data-break-after", after.dataset.breakAfter); } } if (previousBreakAfter && previousBreakAfter.dataset) { if (previousBreakAfter.dataset.previousBreakAfter && previousBreakAfter.dataset.previousBreakAfter !== "avoid") { page.previousBreakAfter = previousBreakAfter.dataset.previousBreakAfter; } } } afterPageLayout(pageElement, page) { this.addBreakAttributes(pageElement, page); } } class PrintMedia extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } onAtMedia(node, item, list) { let media = this.getMediaName(node); let rules; if (media.includes("print")) { rules = node.block.children; // Append rules to the end of main rules list // TODO: this isn't working right, needs to check what is in the prelude /* rules.forEach((selectList) => { if (selectList.prelude) { selectList.prelude.children.forEach((rule) => { rule.children.prependData({ type: "Combinator", name: " " }); rule.children.prependData({ type: "ClassSelector", name: "pagedjs_page" }); }); } }); list.insertList(rules, item); */ // Append rules to the end of main rules list list.appendList(rules); // Remove rules from the @media block list.remove(item); } else if (!media.includes("all") && !media.includes("pagedjs-ignore")) { list.remove(item); } } getMediaName(node) { let media = []; if (typeof node.prelude === "undefined" || node.prelude.type !== "AtrulePrelude" ) { return; } lib.walk(node.prelude, { visit: "Identifier", enter: (identNode, iItem, iList) => { media.push(identNode.name); } }); return media; } } class Splits extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } afterPageLayout(pageElement, page, breakToken, chunker) { let splits = Array.from(pageElement.querySelectorAll("[data-split-from]")); let pages = pageElement.parentNode; let index = Array.prototype.indexOf.call(pages.children, pageElement); let prevPage; if (index === 0) { return; } prevPage = pages.children[index - 1]; let from; // Capture the last from element splits.forEach((split) => { let ref = split.dataset.ref; from = prevPage.querySelector("[data-ref='"+ ref +"']:not([data-split-to])"); if (from) { from.dataset.splitTo = ref; if (!from.dataset.splitFrom) { from.dataset.splitOriginal = true; } } }); // Fix alignment on the deepest split element if (from) { this.handleAlignment(from); } } handleAlignment(node) { let styles = window.getComputedStyle(node); let align = styles["text-align"]; let alignLast = styles["text-align-last"]; node.dataset.lastSplitElement = "true"; if (align === "justify" && alignLast === "auto") { node.dataset.alignLastSplitElement = "justify"; } else { node.dataset.alignLastSplitElement = alignLast; } } } class Counters extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.counters = {}; this.resetCountersMap = new Map(); } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "counter-increment") { this.handleIncrement(declaration, rule); // clean up empty declaration let hasProperities = false; declaration.value.children.forEach((data) => { if (data.type && data.type !== "WhiteSpace") { hasProperities = true; } }); if (!hasProperities) { dList.remove(dItem); } } else if (property === "counter-reset") { this.handleReset(declaration, rule); // clean up empty declaration let hasProperities = false; declaration.value.children.forEach((data) => { if (data.type && data.type !== "WhiteSpace") { hasProperities = true; } }); if (!hasProperities) { dList.remove(dItem); } } } afterParsed(parsed) { this.processCounters(parsed, this.counters); this.scopeCounters(this.counters); } addCounter(name) { if (name in this.counters) { return this.counters[name]; } this.counters[name] = { name: name, increments: {}, resets: {} }; return this.counters[name]; } handleIncrement(declaration, rule) { let increments = []; let children = declaration.value.children; children.forEach((data, item) => { if (data.type && data.type === "Identifier") { let name = data.name; if (name === "page" || name.indexOf("target-counter-") === 0) { return; } let whitespace, number, value; if (item.next && item.next.data.type === "WhiteSpace") { whitespace = item.next; } if (whitespace && whitespace.next && whitespace.next.data.type === "Number") { number = whitespace.next; value = parseInt(number.data.value); } let selector = lib.generate(rule.ruleNode.prelude); let counter; if (!(name in this.counters)) { counter = this.addCounter(name); } else { counter = this.counters[name]; } let increment = { selector: selector, number: value || 1 }; counter.increments[selector] = increment; increments.push(increment); // Remove the parsed resets children.remove(item); if (whitespace) { children.remove(whitespace); } if (number) { children.remove(number); } } }); return increments; } handleReset(declaration, rule) { let resets = []; let children = declaration.value.children; children.forEach((data, item) => { if (data.type && data.type === "Identifier") { let name = data.name; let whitespace, number, value; if (item.next && item.next.data.type === "WhiteSpace") { whitespace = item.next; } if (whitespace && whitespace.next && whitespace.next.data.type === "Number") { number = whitespace.next; value = parseInt(number.data.value); } let counter; let selector; let prelude = rule.ruleNode.prelude; if (rule.ruleNode.type === "Atrule" && rule.ruleNode.name === "page") { selector = ".pagedjs_page"; } else { selector = lib.generate(prelude || rule.ruleNode); } if (name === "footnote") { this.addFootnoteMarkerCounter(declaration.value.children); } if (!(name in this.counters)) { counter = this.addCounter(name); } else { counter = this.counters[name]; } let reset = { selector: selector, number: value || 0 }; counter.resets[selector] = reset; resets.push(reset); if (selector !== ".pagedjs_page") { // Remove the parsed resets children.remove(item); if (whitespace) { children.remove(whitespace); } if (number) { children.remove(number); } } } }); return resets; } processCounters(parsed, counters) { let counter; for (let c in counters) { counter = this.counters[c]; this.processCounterIncrements(parsed, counter); this.processCounterResets(parsed, counter); if (c !== "page") { this.addCounterValues(parsed, counter); } } } scopeCounters(counters) { let countersArray = []; for (let c in counters) { if(c !== "page") { countersArray.push(`${counters[c].name} 0`); } } // Add to pages to allow cross page scope this.insertRule(`.pagedjs_pages { counter-reset: ${countersArray.join(" ")} page 0 pages var(--pagedjs-page-count) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-count)}`); } insertRule(rule) { this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } processCounterIncrements(parsed, counter) { let increment; for (let inc in counter.increments) { increment = counter.increments[inc]; // Find elements for increments let incrementElements = parsed.querySelectorAll(increment.selector); // Add counter data for (let i = 0; i < incrementElements.length; i++) { incrementElements[i].setAttribute("data-counter-"+ counter.name +"-increment", increment.number); if (incrementElements[i].getAttribute("data-counter-increment")) { incrementElements[i].setAttribute("data-counter-increment", incrementElements[i].getAttribute("data-counter-increment") + " " + counter.name); } else { incrementElements[i].setAttribute("data-counter-increment", counter.name); } } } } processCounterResets(parsed, counter) { let reset; for (let r in counter.resets) { reset = counter.resets[r]; // Find elements for resets let resetElements = parsed.querySelectorAll(reset.selector); // Add counter data for (var i = 0; i < resetElements.length; i++) { resetElements[i].setAttribute("data-counter-"+ counter.name +"-reset", reset.number); if (resetElements[i].getAttribute("data-counter-reset")) { resetElements[i].setAttribute("data-counter-reset", resetElements[i].getAttribute("data-counter-reset") + " " + counter.name); } else { resetElements[i].setAttribute("data-counter-reset", counter.name); } } } } addCounterValues(parsed, counter) { let counterName = counter.name; if (counterName === "page" || counterName === "footnote") { return; } let elements = parsed.querySelectorAll("[data-counter-"+ counterName +"-reset], [data-counter-"+ counterName +"-increment]"); let count = 0; let element; let increment, reset; let resetValue, incrementValue, resetDelta; let incrementArray; for (let i = 0; i < elements.length; i++) { element = elements[i]; resetDelta = 0; incrementArray = []; if (element.hasAttribute("data-counter-"+ counterName +"-reset")) { reset = element.getAttribute("data-counter-"+ counterName +"-reset"); resetValue = parseInt(reset); // Use negative increment value inplace of reset resetDelta = resetValue - count; incrementArray.push(`${counterName} ${resetDelta}`); count = resetValue; } if (element.hasAttribute("data-counter-"+ counterName +"-increment")) { increment = element.getAttribute("data-counter-"+ counterName +"-increment"); incrementValue = parseInt(increment); count += incrementValue; element.setAttribute("data-counter-"+counterName+"-value", count); incrementArray.push(`${counterName} ${incrementValue}`); } if (incrementArray.length > 0) { this.incrementCounterForElement(element, incrementArray); } } } addFootnoteMarkerCounter(list) { let markers = []; lib.walk(list, { visit: "Identifier", enter: (identNode, iItem, iList) => { markers.push(identNode.name); } }); // Already added if (markers.includes("footnote-maker")) { return; } list.insertData({ type: "WhiteSpace", value: " " }); list.insertData({ type: "Identifier", name: "footnote-marker" }); list.insertData({ type: "WhiteSpace", value: " " }); list.insertData({ type: "Number", value: 0 }); } incrementCounterForElement(element, incrementArray) { if (!element || !incrementArray || incrementArray.length === 0) return; const ref = element.dataset.ref; const prevIncrements = Array.from(this.styleSheet.cssRules).filter((rule) => { return rule.selectorText === `[data-ref="${element.dataset.ref}"]:not([data-split-from])` && rule.style[0] === "counter-increment"; }); const increments = []; for (let styleRule of prevIncrements) { let values = styleRule.style.counterIncrement.split(" "); for (let i = 0; i < values.length; i+=2) { increments.push(values[i] + " " + values[i+1]); } } Array.prototype.push.apply(increments, incrementArray); this.insertRule(`[data-ref="${ref}"]:not([data-split-from]) { counter-increment: ${increments.join(" ")} }`); } afterPageLayout(pageElement, page) { let resets = []; let pgreset = pageElement.querySelectorAll("[data-counter-page-reset]:not([data-split-from])"); pgreset.forEach((reset) => { const ref = reset.dataset && reset.dataset.ref; if (ref && this.resetCountersMap.has(ref)) ; else { if (ref) { this.resetCountersMap.set(ref, ""); } let value = reset.dataset.counterPageReset; resets.push(`page ${value}`); } }); let notereset = pageElement.querySelectorAll("[data-counter-footnote-reset]:not([data-split-from])"); notereset.forEach((reset) => { let value = reset.dataset.counterFootnoteReset; resets.push(`footnote ${value}`); resets.push(`footnote-marker ${value}`); }); if (resets.length) { this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] { counter-increment: none; counter-reset: ${resets.join(" ")} }`, this.styleSheet.cssRules.length); } } } class Lists extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } afterParsed(content) { const orderedLists = content.querySelectorAll("ol"); for (var list of orderedLists) { this.addDataNumbers(list); } } afterPageLayout(pageElement, page, breakToken, chunker) { var orderedLists = pageElement.getElementsByTagName("ol"); for (var list of orderedLists) { if (list.firstElementChild) { list.start = list.firstElementChild.dataset.itemNum; } } } addDataNumbers(list) { let start = 1; if (list.hasAttribute("start")) { start = parseInt(list.getAttribute("start"), 10); if (isNaN(start)) { start = 1; } } let items = list.children; for (var i = 0; i < items.length; i++) { items[i].setAttribute("data-item-num", i + start); } } } class PositionFixed extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.fixedElementsSelector = []; this.fixedElements = []; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "position" && declaration.value.children.first().name === "fixed") { let selector = lib.generate(rule.ruleNode.prelude); this.fixedElementsSelector.push(selector); dList.remove(dItem); } } afterParsed(fragment) { this.fixedElementsSelector.forEach(fixedEl => { fragment.querySelectorAll(`${fixedEl}`).forEach(el => { el.style.setProperty("position", "absolute"); this.fixedElements.push(el); el.remove(); }); }); } afterPageLayout(pageElement, page, breakToken) { this.fixedElements.forEach(el => { const clone = el.cloneNode(true); pageElement.querySelector(".pagedjs_pagebox").insertAdjacentElement("afterbegin", clone); }); } } class PageCounterIncrement extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.pageCounter = { name: "page", increments: {}, resets: {} }; } onDeclaration(declaration, dItem, dList, rule) { const property = declaration.property; if (property === "counter-increment") { let inc = this.handleIncrement(declaration, rule); if (inc) { dList.remove(dItem); } } } afterParsed(_) { for (const inc in this.pageCounter.increments) { const increment = this.pageCounter.increments[inc]; this.insertRule(`${increment.selector} { --pagedjs-page-counter-increment: ${increment.number} }`); } } handleIncrement(declaration, rule) { const identifier = declaration.value.children.first(); const number = declaration.value.children.getSize() > 1 ? declaration.value.children.last().value : 1; const name = identifier && identifier.name; if (name && name.indexOf("target-counter-") === 0) { return; } // A counter named page is automatically created and incremented by 1 on every page of the document, // unless the counter-increment property in the page context explicitly specifies a different increment for the page counter. // https://www.w3.org/TR/css-page-3/#page-based-counters if (name !== "page") { return; } // the counter-increment property is not defined on the page context (i.e. @page rule), ignoring... if (rule.ruleNode.name === "page" && rule.ruleNode.type === "Atrule") { return; } const selector = lib.generate(rule.ruleNode.prelude); return this.pageCounter.increments[selector] = { selector: selector, number }; } insertRule(rule) { this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } class NthOfType extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.selectors = {}; } onRule(ruleNode, ruleItem, rulelist) { let selector = lib.generate(ruleNode.prelude); if (selector.match(/:(first|last|nth)-of-type/)) { let declarations = lib.generate(ruleNode.block); declarations = declarations.replace(/[{}]/g,""); let uuid = "nth-of-type-" + UUID(); selector.split(",").forEach((s) => { if (!this.selectors[s]) { this.selectors[s] = [uuid, declarations]; } else { this.selectors[s][1] = `${this.selectors[s][1]};${declarations}` ; } }); rulelist.remove(ruleItem); } } afterParsed(parsed) { this.processSelectors(parsed, this.selectors); } processSelectors(parsed, selectors) { // add the new attributes to matching elements for (let s in selectors) { let elements = parsed.querySelectorAll(s); for (var i = 0; i < elements.length; i++) { let dataNthOfType = elements[i].getAttribute("data-nth-of-type"); if (dataNthOfType && dataNthOfType != "") { dataNthOfType = `${dataNthOfType},${selectors[s][0]}`; elements[i].setAttribute("data-nth-of-type", dataNthOfType); } else { elements[i].setAttribute("data-nth-of-type", selectors[s][0]); } } let rule = `*[data-nth-of-type*='${selectors[s][0]}'] { ${selectors[s][1]}; }`; this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } } class Following extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.selectors = {}; } onRule(ruleNode, ruleItem, rulelist) { let selector = lib.generate(ruleNode.prelude); if (selector.match(/\+/)) { let declarations = lib.generate(ruleNode.block); declarations = declarations.replace(/[{}]/g,""); let uuid = "following-" + UUID(); selector.split(",").forEach((s) => { if (!this.selectors[s]) { this.selectors[s] = [uuid, declarations]; } else { this.selectors[s][1] = `${this.selectors[s][1]};${declarations}` ; } }); rulelist.remove(ruleItem); } } afterParsed(parsed) { this.processSelectors(parsed, this.selectors); } processSelectors(parsed, selectors) { // add the new attributes to matching elements for (let s in selectors) { let elements = parsed.querySelectorAll(s); for (var i = 0; i < elements.length; i++) { let dataFollowing = elements[i].getAttribute("data-following"); if (dataFollowing && dataFollowing != "") { dataFollowing = `${dataFollowing},${selectors[s][0]}`; elements[i].setAttribute("data-following", dataFollowing); } else { elements[i].setAttribute("data-following", selectors[s][0]); } } let rule = `*[data-following*='${selectors[s][0]}'] { ${selectors[s][1]}; }`; this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length); } } } class Footnotes extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.footnotes = {}; this.needsLayout = []; } onDeclaration(declaration, dItem, dList, rule) { let property = declaration.property; if (property === "float") { let identifier = declaration.value.children && declaration.value.children.first(); let location = identifier && identifier.name; if (location === "footnote") { let selector = lib.generate(rule.ruleNode.prelude); this.footnotes[selector] = { selector: selector, policy: "auto", display: "block" }; dList.remove(dItem); } } if (property === "footnote-policy") { let identifier = declaration.value.children && declaration.value.children.first(); let policy = identifier && identifier.name; if (policy) { let selector = lib.generate(rule.ruleNode.prelude); let note = this.footnotes[selector]; if (note) { note.policy = policy; } } } if (property === "footnote-display") { let identifier = declaration.value.children && declaration.value.children.first(); let display = identifier && identifier.name; let selector = lib.generate(rule.ruleNode.prelude); if (display && this.footnotes[selector]) { let note = this.footnotes[selector]; if (note) { note.display = display; } } } } onPseudoSelector(pseudoNode, pItem, pList, selector, rule) { let name = pseudoNode.name; if (name === "footnote-marker") { // switch ::footnote-marker to [data-footnote-marker]::before let prelude = rule.ruleNode.prelude; let newPrelude = new lib.List(); // Can't get remove to work, so just copying everything else prelude.children.first().children.each((node) => { if (node.type !== "PseudoElementSelector") { newPrelude.appendData(node); } }); // Add our data call newPrelude.appendData({ type: "AttributeSelector", name: { type: "Identifier", name: "data-footnote-marker", }, flags: null, loc: null, matcher: null, value: null }); // Add new pseudo element newPrelude.appendData({ type: "PseudoElementSelector", name: "marker", loc: null, children: null }); prelude.children.first().children = newPrelude; } if (name === "footnote-call") { // switch ::footnote-call to [data-footnote-call]::after let prelude = rule.ruleNode.prelude; let newPrelude = new lib.List(); // Can't get remove to work, so just copying everything else prelude.children.first().children.each((node) => { if (node.type !== "PseudoElementSelector") { newPrelude.appendData(node); } }); // Add our data call newPrelude.appendData({ type: "AttributeSelector", name: { type: "Identifier", name: "data-footnote-call", }, flags: null, loc: null, matcher: null, value: null }); // Add new pseudo element newPrelude.appendData({ type: "PseudoElementSelector", name: "after", loc: null, children: null }); prelude.children.first().children = newPrelude; } } afterParsed(parsed) { this.processFootnotes(parsed, this.footnotes); } processFootnotes(parsed, notes) { for (let n in notes) { // Find elements let elements = parsed.querySelectorAll(n); let element; let note = notes[n]; for (var i = 0; i < elements.length; i++) { element = elements[i]; // Add note type element.setAttribute("data-note", "footnote"); element.setAttribute("data-break-before", "avoid"); element.setAttribute("data-note-policy", note.policy || "auto"); element.setAttribute("data-note-display", note.display || "block"); // Mark all parents this.processFootnoteContainer(element); } } } processFootnoteContainer(node) { // Find the container let element = node.parentElement; let prevElement = element; // Walk up the dom until we find a container element while (element) { if (isContainer(element)) { // Add flag to the previous non-container element that will render with children prevElement.setAttribute("data-has-notes", "true"); break; } prevElement = element; element = element.parentElement; // If no containers were found and there are no further parents flag the last element if (!element) { prevElement.setAttribute("data-has-notes", "true"); } } } renderNode(node) { if (node.nodeType == 1) { // Get all notes let notes; // Ingnore html element nodes, like mathml if (!node.dataset) { return; } if (node.dataset.note === "footnote") { notes = [node]; } else if (node.dataset.hasNotes || node.querySelectorAll("[data-note='footnote']")) { notes = node.querySelectorAll("[data-note='footnote']"); } if (notes && notes.length) { this.findVisibleFootnotes(notes, node); } } } findVisibleFootnotes(notes, node) { let area, size, right; area = node.closest(".pagedjs_page_content"); size = area.getBoundingClientRect(); right = size.left + size.width; for (let i = 0; i < notes.length; ++i) { let currentNote = notes[i]; let bounds = currentNote.getBoundingClientRect(); let left = bounds.left; if (left < right) { // Add call for the note this.moveFootnote(currentNote, node.closest(".pagedjs_area"), true); } } } moveFootnote(node, pageArea, needsNoteCall) { // let pageArea = node.closest(".pagedjs_area"); let noteArea = pageArea.querySelector(".pagedjs_footnote_area"); let noteContent = noteArea.querySelector(".pagedjs_footnote_content"); let noteInnerContent = noteContent.querySelector(".pagedjs_footnote_inner_content"); if (!isElement(node)) { return; } // Add call for the note let noteCall; if (needsNoteCall) { noteCall = this.createFootnoteCall(node); } // Remove the break before attribute for future layout node.removeAttribute("data-break-before"); // Check if note already exists for overflow let existing = noteInnerContent.querySelector(`[data-ref="${node.dataset.ref}"]`); if (existing) { // Remove the note from the flow but no need to render it again node.remove(); return; } // Add the note node noteInnerContent.appendChild(node); // Remove empty class if (noteContent.classList.contains("pagedjs_footnote_empty")) { noteContent.classList.remove("pagedjs_footnote_empty"); } // Add marker node.dataset.footnoteMarker = node.dataset.ref; // Add Id node.id = `note-${node.dataset.ref}`; // Get note content size let height = noteContent.scrollHeight; // Check the noteCall is still on screen let area = pageArea.querySelector(".pagedjs_page_content"); let size = area.getBoundingClientRect(); let right = size.left + size.width; // TODO: add a max height in CSS // Check element sizes let noteCallBounds = noteCall && noteCall.getBoundingClientRect(); let noteAreaBounds = noteArea.getBoundingClientRect(); // Get the @footnote margins let noteContentMargins = this.marginsHeight(noteContent); let noteContentPadding = this.paddingHeight(noteContent); let noteContentBorders = this.borderHeight(noteContent); let total = noteContentMargins + noteContentPadding + noteContentBorders; // Get the top of the @footnote area let notAreaTop = Math.floor(noteAreaBounds.top); // If the height isn't set yet, remove the margins from the top if (noteAreaBounds.height === 0) { notAreaTop -= this.marginsHeight(noteContent, false); notAreaTop -= this.paddingHeight(noteContent, false); notAreaTop -= this.borderHeight(noteContent, false); } // Determine the note call position and offset per policy let notePolicy = node.dataset.notePolicy; let noteCallPosition = 0; let noteCallOffset = 0; if (noteCall) { // Get the correct line bottom for super or sub styled callouts let prevSibling = noteCall.previousSibling; let range = new Range(); if (prevSibling) { range.setStartBefore(prevSibling); } else { range.setStartBefore(noteCall); } range.setEndAfter(noteCall); let rangeBounds = range.getBoundingClientRect(); noteCallPosition = rangeBounds.bottom; if (!notePolicy || notePolicy === "auto") { noteCallOffset = Math.ceil(rangeBounds.bottom); } else if (notePolicy === "line") { noteCallOffset = Math.ceil(rangeBounds.top); } else if (notePolicy === "block") { // Check that there is a previous element on the page let parentParagraph = noteCall.closest("p").previousElementSibling; if (parentParagraph) { noteCallOffset = Math.ceil( parentParagraph.getBoundingClientRect().bottom ); } else { noteCallOffset = Math.ceil(rangeBounds.bottom); } } } let contentDelta = height + total - noteAreaBounds.height; // Space between the top of the footnotes area and the bottom of the footnote call let noteDelta = noteCallPosition ? notAreaTop - noteCallPosition : 0; // Space needed for the force a break for the policy of the footnote let notePolicyDelta = noteCallPosition ? Math.floor(noteAreaBounds.top) - noteCallOffset : 0; let hasNotes = noteArea.querySelector("[data-note='footnote']"); if (needsNoteCall && noteCallBounds.left > right) { // Note is offscreen and will be chunked to the next page on overflow node.remove(); } else if (!hasNotes && needsNoteCall && total > noteDelta) { // No space to add even the footnote area pageArea.style.setProperty("--pagedjs-footnotes-height", "0px"); // Add a wrapper as this div is removed later let wrapperDiv = document.createElement("div"); wrapperDiv.appendChild(node); // Push to the layout queue for the next page this.needsLayout.push(wrapperDiv); } else if (!needsNoteCall) { // Call was previously added, force adding footnote pageArea.style.setProperty( "--pagedjs-footnotes-height", `${height + total}px` ); } else if (noteCallPosition < noteAreaBounds.top - contentDelta) { // the current note content will fit without pushing the call to the next page pageArea.style.setProperty( "--pagedjs-footnotes-height", `${height + noteContentMargins + noteContentBorders}px` ); } else { // set height to just before note call pageArea.style.setProperty( "--pagedjs-footnotes-height", `${noteAreaBounds.height + notePolicyDelta}px` ); noteInnerContent.style.height = noteAreaBounds.height + notePolicyDelta - total + "px"; } } createFootnoteCall(node) { let parentElement = node.parentElement; let footnoteCall = document.createElement("a"); for (const className of node.classList) { footnoteCall.classList.add(`${className}`); } footnoteCall.dataset.footnoteCall = node.dataset.ref; footnoteCall.dataset.ref = node.dataset.ref; // Increment for counters footnoteCall.dataset.dataCounterFootnoteIncrement = 1; // Add link footnoteCall.href = `#note-${node.dataset.ref}`; parentElement.insertBefore(footnoteCall, node); return footnoteCall; } afterPageLayout(pageElement, page, breakToken, chunker) { let pageArea = pageElement.querySelector(".pagedjs_area"); let noteArea = page.footnotesArea; let noteContent = noteArea.querySelector(".pagedjs_footnote_content"); let noteInnerContent = noteArea.querySelector(".pagedjs_footnote_inner_content"); let noteContentBounds = noteContent.getBoundingClientRect(); let { width } = noteContentBounds; noteInnerContent.style.columnWidth = Math.round(width) + "px"; noteInnerContent.style.columnGap = "calc(var(--pagedjs-margin-right) + var(--pagedjs-margin-left))"; // Get overflow let layout = new Layout(noteArea, undefined, chunker.settings); let overflow = layout.findOverflow(noteInnerContent, noteContentBounds); if (overflow) { let { startContainer, startOffset } = overflow; let startIsNode; if (isElement(startContainer)) { let start = startContainer.childNodes[startOffset]; startIsNode = isElement(start) && start.hasAttribute("data-footnote-marker"); } let extracted = overflow.extractContents(); if (!startIsNode) { let splitChild = extracted.firstElementChild; splitChild.dataset.splitFrom = splitChild.dataset.ref; this.handleAlignment(noteInnerContent.lastElementChild); } this.needsLayout.push(extracted); noteContent.style.removeProperty("height"); noteInnerContent.style.removeProperty("height"); let noteInnerContentBounds = noteInnerContent.getBoundingClientRect(); let { height } = noteInnerContentBounds; // Get the @footnote margins let noteContentMargins = this.marginsHeight(noteContent); let noteContentPadding = this.paddingHeight(noteContent); let noteContentBorders = this.borderHeight(noteContent); pageArea.style.setProperty( "--pagedjs-footnotes-height", `${height + noteContentMargins + noteContentBorders + noteContentPadding}px` ); // Hide footnote content if empty if (noteInnerContent.childNodes.length === 0) { noteContent.classList.add("pagedjs_footnote_empty"); } if (!breakToken) { chunker.clonePage(page); } else { let breakBefore, previousBreakAfter; if ( breakToken.node && typeof breakToken.node.dataset !== "undefined" && typeof breakToken.node.dataset.previousBreakAfter !== "undefined" ) { previousBreakAfter = breakToken.node.dataset.previousBreakAfter; } if ( breakToken.node && typeof breakToken.node.dataset !== "undefined" && typeof breakToken.node.dataset.breakBefore !== "undefined" ) { breakBefore = breakToken.node.dataset.breakBefore; } if (breakBefore || previousBreakAfter) { chunker.clonePage(page); } } } noteInnerContent.style.height = "auto"; } handleAlignment(node) { let styles = window.getComputedStyle(node); let alignLast = styles["text-align-last"]; node.dataset.lastSplitElement = "true"; if (alignLast === "auto") { node.dataset.alignLastSplitElement = "justify"; } else { node.dataset.alignLastSplitElement = alignLast; } } beforePageLayout(page) { while (this.needsLayout.length) { let fragment = this.needsLayout.shift(); Array.from(fragment.childNodes).forEach((node) => { this.moveFootnote( node, page.element.querySelector(".pagedjs_area"), false ); }); } } afterOverflowRemoved(removed, rendered) { // Find the page area let area = rendered.closest(".pagedjs_area"); // Get any rendered footnotes let notes = area.querySelectorAll(".pagedjs_footnote_area [data-note='footnote']"); for (let n = 0; n < notes.length; n++) { const note = notes[n]; // Check if the call for that footnote has been removed with the overflow let call = removed.querySelector(`[data-footnote-call="${note.dataset.ref}"]`); if (call) { note.remove(); } } // Hide footnote content if empty let noteInnerContent = area.querySelector(".pagedjs_footnote_inner_content"); if (noteInnerContent && noteInnerContent.childNodes.length === 0) { noteInnerContent.parentElement.classList.add("pagedjs_footnote_empty"); } } marginsHeight(element, total=true) { let styles = window.getComputedStyle(element); let marginTop = parseInt(styles.marginTop); let marginBottom = parseInt(styles.marginBottom); let margin = 0; if (marginTop) { margin += marginTop; } if (marginBottom && total) { margin += marginBottom; } return margin; } paddingHeight(element, total=true) { let styles = window.getComputedStyle(element); let paddingTop = parseInt(styles.paddingTop); let paddingBottom = parseInt(styles.paddingBottom); let padding = 0; if (paddingTop) { padding += paddingTop; } if (paddingBottom && total) { padding += paddingBottom; } return padding; } borderHeight(element, total=true) { let styles = window.getComputedStyle(element); let borderTop = parseInt(styles.borderTop); let borderBottom = parseInt(styles.borderBottom); let borders = 0; if (borderTop) { borders += borderTop; } if (borderBottom && total) { borders += borderBottom; } return borders; } } var pagedMediaHandlers = [ PrintMedia, AtPage, Breaks, Splits, Counters, Lists, PositionFixed, PageCounterIncrement, NthOfType, Following, Footnotes ]; class RunningHeaders extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.runningSelectors = {}; this.elements = {}; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "position") { let selector = lib.generate(rule.ruleNode.prelude); let identifier = declaration.value.children.first().name; if (identifier === "running") { let value; lib.walk(declaration, { visit: "Function", enter: (node, item, list) => { value = node.children.first().name; } }); this.runningSelectors[value] = { identifier: identifier, value: value, selector: selector }; } } if (declaration.property === "content") { lib.walk(declaration, { visit: "Function", enter: (funcNode, fItem, fList) => { if (funcNode.name.indexOf("element") > -1) { let selector = lib.generate(rule.ruleNode.prelude); let func = funcNode.name; let value = funcNode.children.first().name; let args = [value]; // we only handle first for now let style = "first"; selector.split(",").forEach((s) => { // remove before / after s = s.replace(/::after|::before/, ""); this.elements[s] = { func: func, args: args, value: value, style: style , selector: s, fullSelector: selector }; }); } } }); } } afterParsed(fragment) { for (let name of Object.keys(this.runningSelectors)) { let set = this.runningSelectors[name]; let selected = Array.from(fragment.querySelectorAll(set.selector)); if (set.identifier === "running") { for (let header of selected) { header.style.display = "none"; } } } } afterPageLayout(fragment) { for (let name of Object.keys(this.runningSelectors)) { let set = this.runningSelectors[name]; let selected = fragment.querySelector(set.selector); if (selected) { // let cssVar; if (set.identifier === "running") { // cssVar = selected.textContent.replace(/\\([\s\S])|(["|'])/g,"\\$1$2"); // this.styleSheet.insertRule(`:root { --string-${name}: "${cssVar}"; }`, this.styleSheet.cssRules.length); // fragment.style.setProperty(`--string-${name}`, `"${cssVar}"`); set.first = selected; } else { console.warn(set.value + "needs css replacement"); } } } // move elements if (!this.orderedSelectors) { this.orderedSelectors = this.orderSelectors(this.elements); } for (let selector of this.orderedSelectors) { if (selector) { let el = this.elements[selector]; let selected = fragment.querySelector(selector); if (selected) { let running = this.runningSelectors[el.args[0]]; if (running && running.first) { selected.innerHTML = ""; // Clear node // selected.classList.add("pagedjs_clear-after"); // Clear ::after let clone = running.first.cloneNode(true); clone.style.display = null; selected.appendChild(clone); } } } } } /** * Assign a weight to @page selector classes * 1) page * 2) left & right * 3) blank * 4) first & nth * 5) named page * 6) named left & right * 7) named first & nth * @param {string} [s] selector string * @return {int} weight */ pageWeight(s) { let weight = 1; let selector = s.split(" "); let parts = selector.length && selector[0].split("."); parts.shift(); // remove empty first part switch (parts.length) { case 4: if (/^pagedjs_[\w-]+_first_page$/.test(parts[3])) { weight = 7; } else if (parts[3] === "pagedjs_left_page" || parts[3] === "pagedjs_right_page") { weight = 6; } break; case 3: if (parts[1] === "pagedjs_named_page") { if (parts[2].indexOf(":nth-of-type") > -1) { weight = 7; } else { weight = 5; } } break; case 2: if (parts[1] === "pagedjs_first_page") { weight = 4; } else if (parts[1] === "pagedjs_blank_page") { weight = 3; } else if (parts[1] === "pagedjs_left_page" || parts[1] === "pagedjs_right_page") { weight = 2; } break; default: if (parts[0].indexOf(":nth-of-type") > -1) { weight = 4; } else { weight = 1; } } return weight; } /** * Orders the selectors based on weight * * Does not try to deduplicate base on specifity of the selector * Previous matched selector will just be overwritten * @param {obj} [obj] selectors object * @return {Array} orderedSelectors */ orderSelectors(obj) { let selectors = Object.keys(obj); let weighted = { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [] }; let orderedSelectors = []; for (let s of selectors) { let w = this.pageWeight(s); weighted[w].unshift(s); } for (var i = 1; i <= 7; i++) { orderedSelectors = orderedSelectors.concat(weighted[i]); } return orderedSelectors; } beforeTreeParse(text, sheet) { // element(x) is parsed as image element selector, so update element to element-ident sheet.text = text.replace(/element[\s]*\(([^|^#)]*)\)/g, "element-ident($1)"); } } function cleanPseudoContent(el, trim = "\"' ") { if(el == null) return; return el .replace(new RegExp(`^[${trim}]+`), "") .replace(new RegExp(`[${trim}]+$`), "") .replace(/["']/g, match => { return "\\" + match; }) .replace(/[\n]/g, match => { return "\\00000A"; }); } function cleanSelector(el) { if(el == null) return; return el .replace(new RegExp("::footnote-call", "g"), "") .replace(new RegExp("::footnote-marker", "g"), ""); } class StringSets extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.stringSetSelectors = {}; this.type; // pageLastString = last string variable defined on the page this.pageLastString; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "string-set") { let selector = lib.generate(rule.ruleNode.prelude); let identifiers = []; let functions = []; let values = []; declaration.value.children.forEach((child) => { if (child.type === "Identifier") { identifiers.push(child.name); } if (child.type === "Function") { functions.push(child.name); child.children.forEach((subchild) => { if (subchild.type === "Identifier") { values.push(subchild.name); } }); } }); identifiers.forEach((identifier, index) => { let func = functions[index]; let value = values[index]; this.stringSetSelectors[identifier] = { identifier, func, value, selector }; }); } } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "string") { let identifier = funcNode.children && funcNode.children.first().name; this.type = funcNode.children.last().name; funcNode.name = "var"; funcNode.children = new lib.List(); if(this.type === "first" || this.type === "last" || this.type === "start" || this.type === "first-except"){ funcNode.children.append( funcNode.children.createItem({ type: "Identifier", loc: null, name: "--pagedjs-string-" + this.type + "-" + identifier }) ); }else { funcNode.children.append( funcNode.children.createItem({ type: "Identifier", loc: null, name: "--pagedjs-string-first-" + identifier }) ); } } } afterPageLayout(fragment) { if ( this.pageLastString === undefined ) { this.pageLastString = {}; } for (let name of Object.keys(this.stringSetSelectors)) { let set = this.stringSetSelectors[name]; let value = set.value; let func = set.func; let selected = fragment.querySelectorAll(set.selector); // Get the last found string for the current identifier let stringPrevPage = ( name in this.pageLastString ) ? this.pageLastString[name] : ""; let varFirst, varLast, varStart, varFirstExcept; if(selected.length == 0){ // if there is no sel. on the page varFirst = stringPrevPage; varLast = stringPrevPage; varStart = stringPrevPage; varFirstExcept = stringPrevPage; }else { selected.forEach((sel) => { // push each content into the array to define in the variable the first and the last element of the page. if (func === "content") { this.pageLastString[name] = selected[selected.length - 1].textContent; } if (func === "attr") { this.pageLastString[name] = selected[selected.length - 1].getAttribute(value) || ""; } }); /* FIRST */ if (func === "content") { varFirst = selected[0].textContent; } if (func === "attr") { varFirst = selected[0].getAttribute(value) || ""; } /* LAST */ if (func === "content") { varLast = selected[selected.length - 1].textContent; } if (func === "attr") { varLast = selected[selected.length - 1].getAttribute(value) || ""; } /* START */ // Hack to find if the sel. is the first elem of the page / find a better way let selTop = selected[0].getBoundingClientRect().top; let pageContent = selected[0].closest(".pagedjs_page_content"); let pageContentTop = pageContent.getBoundingClientRect().top; if(selTop == pageContentTop){ varStart = varFirst; }else { varStart = stringPrevPage; } /* FIRST EXCEPT */ varFirstExcept = ""; } fragment.style.setProperty(`--pagedjs-string-first-${name}`, `"${cleanPseudoContent(varFirst)}`); fragment.style.setProperty(`--pagedjs-string-last-${name}`, `"${cleanPseudoContent(varLast)}`); fragment.style.setProperty(`--pagedjs-string-start-${name}`, `"${cleanPseudoContent(varStart)}`); fragment.style.setProperty(`--pagedjs-string-first-except-${name}`, `"${cleanPseudoContent(varFirstExcept)}`); } } } class TargetCounters extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.counterTargets = {}; } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "target-counter") { let selector = lib.generate(rule.ruleNode.prelude); let first = funcNode.children.first(); let func = first.name; let value = lib.generate(funcNode); let args = []; first.children.forEach((child) => { if (child.type === "Identifier") { args.push(child.name); } }); let counter; let style; let styleIdentifier; funcNode.children.forEach((child) => { if (child.type === "Identifier") { if (!counter) { counter = child.name; } else if (!style) { styleIdentifier = lib.clone(child); style = child.name; } } }); let variable = "target-counter-" + UUID(); selector.split(",").forEach((s) => { this.counterTargets[s] = { func: func, args: args, value: value, counter: counter, style: style, selector: s, fullSelector: selector, variable: variable }; }); // Replace with counter funcNode.name = "counter"; funcNode.children = new lib.List(); funcNode.children.appendData({ type: "Identifier", loc: 0, name: variable }); if (styleIdentifier) { funcNode.children.appendData({type: "Operator", loc: null, value: ","}); funcNode.children.appendData(styleIdentifier); } } } afterPageLayout(fragment, page, breakToken, chunker) { Object.keys(this.counterTargets).forEach((name) => { let target = this.counterTargets[name]; let split = target.selector.split(/::?/g); let query = split[0]; let queried = chunker.pagesArea.querySelectorAll(query + ":not([data-" + target.variable + "])"); queried.forEach((selected, index) => { // TODO: handle func other than attr if (target.func !== "attr") { return; } let val = attr(selected, target.args); let element = chunker.pagesArea.querySelector(querySelectorEscape(val)); if (element) { let selector = UUID(); selected.setAttribute("data-" + target.variable, selector); // TODO: handle other counter types (by query) let pseudo = ""; if (split.length > 1) { pseudo += "::" + split[1]; } if (target.counter === "page") { let pages = chunker.pagesArea.querySelectorAll(".pagedjs_page"); let pg = 0; for (let i = 0; i < pages.length; i++) { let page = pages[i]; let styles = window.getComputedStyle(page); let reset = styles["counter-reset"].replace("page", "").trim(); let increment = styles["counter-increment"].replace("page", "").trim(); if (reset !== "none") { pg = parseInt(reset); } if (increment !== "none") { pg += parseInt(increment); } if (page.contains(element)){ break; } } this.styleSheet.insertRule(`[data-${target.variable}="${selector}"]${pseudo} { counter-reset: ${target.variable} ${pg}; }`, this.styleSheet.cssRules.length); } else { let value = element.getAttribute(`data-counter-${target.counter}-value`); if (value) { this.styleSheet.insertRule(`[data-${target.variable}="${selector}"]${pseudo} { counter-reset: ${target.variable} ${target.variable} ${parseInt(value)}; }`, this.styleSheet.cssRules.length); } } // force redraw let el = document.querySelector(`[data-${target.variable}="${selector}"]`); if (el) { el.style.display = "none"; el.clientHeight; el.style.removeProperty("display"); } } }); }); } } // import { nodeAfter } from "../../utils/dom"; class TargetText extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.styleSheet = polisher.styleSheet; this.textTargets = {}; this.beforeContent = ""; this.afterContent = ""; this.selector = {}; } onContent(funcNode, fItem, fList, declaration, rule) { if (funcNode.name === "target-text") { this.selector = lib.generate(rule.ruleNode.prelude); let first = funcNode.children.first(); let last = funcNode.children.last(); let func = first.name; let value = lib.generate(funcNode); let args = []; first.children.forEach(child => { if (child.type === "Identifier") { args.push(child.name); } }); let style; if (last !== first) { style = last.name; } let variable = "--pagedjs-" + UUID(); this.selector.split(",").forEach(s => { this.textTargets[s] = { func: func, args: args, value: value, style: style || "content", selector: s, fullSelector: this.selector, variable: variable }; }); // Replace with variable funcNode.name = "var"; funcNode.children = new lib.List(); funcNode.children.appendData({ type: "Identifier", loc: 0, name: variable }); } } // parse this on the ONCONTENT : get all before and after and replace the value with a variable onPseudoSelector(pseudoNode, pItem, pList, selector, rule) { // console.log(pseudoNode); // console.log(rule); rule.ruleNode.block.children.forEach(properties => { if (pseudoNode.name === "before" && properties.property === "content") { // let beforeVariable = "--pagedjs-" + UUID(); let contenu = properties.value.children; contenu.forEach(prop => { if (prop.type === "String") { this.beforeContent = prop.value; } }); } else if (pseudoNode.name === "after" && properties.property === "content") { properties.value.children.forEach(prop => { if (prop.type === "String") { this.afterContent = prop.value; } }); } }); } afterParsed(fragment) { Object.keys(this.textTargets).forEach(name => { let target = this.textTargets[name]; let split = target.selector.split("::"); let query = split[0]; let queried = fragment.querySelectorAll(query); let textContent; queried.forEach((selected, index) => { let val = attr(selected, target.args); let element = fragment.querySelector(querySelectorEscape(val)); if (element) { // content & first-letter & before & after refactorized if (target.style) { this.selector = UUID(); selected.setAttribute("data-target-text", this.selector); let psuedo = ""; if (split.length > 1) { psuedo += "::" + split[1]; } if (target.style === "before" || target.style === "after") { const pseudoType = `${target.style}Content`; textContent = cleanPseudoContent(this[pseudoType]); } else { textContent = cleanPseudoContent(element.textContent, " "); } textContent = target.style === "first-letter" ? textContent.charAt(0) : textContent; this.styleSheet.insertRule(`[data-target-text="${this.selector}"]${psuedo} { ${target.variable}: "${textContent}" }`); } else { console.warn("missed target", val); } } }); }); } } var generatedContentHandlers = [ RunningHeaders, StringSets, TargetCounters, TargetText ]; class WhiteSpaceFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { filterTree(content, (node) => { return this.filterEmpty(node); }, NodeFilter.SHOW_TEXT); } filterEmpty(node) { if (node.textContent.length > 1 && isIgnorable(node)) { // Do not touch the content if text is pre-formatted let parent = node.parentNode; let pre = isElement(parent) && parent.closest("pre"); if (pre) { return NodeFilter.FILTER_REJECT; } const previousSibling = previousSignificantNode(node); const nextSibling = nextSignificantNode(node); if (nextSibling === null && previousSibling === null) { // we should not remove a Node that does not have any siblings. node.textContent = " "; return NodeFilter.FILTER_REJECT; } if (nextSibling === null) { // we can safely remove this node return NodeFilter.FILTER_ACCEPT; } if (previousSibling === null) { // we can safely remove this node return NodeFilter.FILTER_ACCEPT; } // replace the content with a single space node.textContent = " "; // TODO: we also need to preserve sequences of white spaces when the parent has "white-space" rule: // pre // Sequences of white space are preserved. Lines are only broken at newline characters in the source and at <br> elements. // // pre-wrap // Sequences of white space are preserved. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes. // // pre-line // Sequences of white space are collapsed. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes. // // break-spaces // The behavior is identical to that of pre-wrap, except that: // - Any sequence of preserved white space always takes up space, including at the end of the line. // - A line breaking opportunity exists after every preserved white space character, including between white space characters. // - Such preserved spaces take up space and do not hang, and thus affect the box’s intrinsic sizes (min-content size and max-content size). // // See: https://developer.mozilla.org/en-US/docs/Web/CSS/white-space#Values return NodeFilter.FILTER_REJECT; } else { return NodeFilter.FILTER_REJECT; } } } class CommentsFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { filterTree(content, null, NodeFilter.SHOW_COMMENT); } } class ScriptsFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } filter(content) { content.querySelectorAll("script").forEach( script => { script.remove(); }); } } var clearCut = {}; /** * Originally ported from https://github.com/keeganstreet/specificity/blob/866bf7ab4e7f62a7179c15b13a95af4e1c7b1afa/specificity.js * * Calculates the specificity of CSS selectors * http://www.w3.org/TR/css3-selectors/#specificity * * Returns a selector integer value */ (function (exports) { // The following regular expressions assume that selectors matching the preceding regular expressions have been removed var attributeRegex = /(\[[^\]]+\])/g; var idRegex = /(#[^\s\+>~\.\[:]+)/g; var classRegex = /(\.[^\s\+>~\.\[:]+)/g; var pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/g; var pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g; var elementRegex = /([^\s\+>~\.\[:]+)/g; var notRegex = /:not\(([^\)]*)\)/g; var ruleRegex = /\{[^]*/gm; var separatorRegex = /[\*\s\+>~]/g; var straysRegex = /[#\.]/g; // Find matches for a regular expression in a string and push their details to parts // Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements var findMatch = function(regex, type, types, selector) { var matches = selector.match(regex); if (matches) { for (var i = 0; i < matches.length; i++) { types[type]++; // Replace this simple selector with whitespace so it won't be counted in further simple selectors selector = selector.replace(matches[i], ' '); } } return selector; }; // Calculate the specificity for a selector by dividing it into simple selectors and counting them var calculate = function(selector) { var commaIndex = selector.indexOf(','); if (commaIndex !== -1) { selector = selector.substring(0, commaIndex); } var types = { a: 0, b: 0, c: 0 }; // Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument selector = selector.replace(notRegex, ' $1 '); // Remove anything after a left brace in case a user has pasted in a rule, not just a selector selector = selector.replace(ruleRegex, ' '); // Add attribute selectors to parts collection (type b) selector = findMatch(attributeRegex, 'b', types, selector); // Add ID selectors to parts collection (type a) selector = findMatch(idRegex, 'a', types, selector); // Add class selectors to parts collection (type b) selector = findMatch(classRegex, 'b', types, selector); // Add pseudo-element selectors to parts collection (type c) selector = findMatch(pseudoElementRegex, 'c', types, selector); // Add pseudo-class selectors to parts collection (type b) selector = findMatch(pseudoClassRegex, 'b', types, selector); // Remove universal selector and separator characters selector = selector.replace(separatorRegex, ' '); // Remove any stray dots or hashes which aren't attached to words // These may be present if the user is live-editing this selector selector = selector.replace(straysRegex, ' '); // The only things left should be element selectors (type c) findMatch(elementRegex, 'c', types, selector); return (types.a * 100) + (types.b * 10) + (types.c * 1); }; var specificityCache = {}; exports.calculateSpecificity = function(selector) { var specificity = specificityCache[selector]; if (specificity === undefined) { specificity = calculate(selector); specificityCache[selector] = specificity; } return specificity; }; var validSelectorCache = {}; var testSelectorElement = null; exports.isSelectorValid = function(selector) { var valid = validSelectorCache[selector]; if (valid === undefined) { if (testSelectorElement == null) { testSelectorElement = document.createElement('div'); } try { testSelectorElement.querySelector(selector); valid = true; } catch (error) { valid = false; } validSelectorCache[selector] = valid; } return valid; }; exports.validateSelector = function(selector) { if (!exports.isSelectorValid(selector)) { var error = new SyntaxError(selector + ' is not a valid selector'); error.code = 'EBADSELECTOR'; throw error; } }; }(clearCut)); class UndisplayedFilter extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); this.displayRules = {}; } onDeclaration(declaration, dItem, dList, rule) { if (declaration.property === "display") { let selector = lib.generate(rule.ruleNode.prelude); let value = declaration.value.children.first().name; selector.split(",").forEach((s) => { this.displayRules[s] = { value: value, selector: s, specificity: clearCut.calculateSpecificity(s), important: declaration.important }; }); } } filter(content) { let { matches, selectors } = this.sortDisplayedSelectors(content, this.displayRules); // Find matching elements that have display styles for (let i = 0; i < matches.length; i++) { let element = matches[i]; let selector = selectors[i]; let displayValue = selector[selector.length-1].value; if(this.removable(element) && displayValue === "none") { element.dataset.undisplayed = "undisplayed"; } } // Find elements that have inline styles let styledElements = content.querySelectorAll("[style]"); for (let i = 0; i < styledElements.length; i++) { let element = styledElements[i]; if (this.removable(element)) { element.dataset.undisplayed = "undisplayed"; } } } sorter(a, b) { if (a.important && !b.important) { return 1; } if (b.important && !a.important) { return -1; } return a.specificity - b.specificity; } sortDisplayedSelectors(content, displayRules=[]) { let matches = []; let selectors = []; for (let d in displayRules) { let displayItem = displayRules[d]; let selector = displayItem.selector; let query = []; try { try { query = content.querySelectorAll(selector); } catch (e) { query = content.querySelectorAll(cleanSelector(selector)); } } catch (e) { query = []; } let elements = Array.from(query); for (let e of elements) { if (matches.includes(e)) { let index = matches.indexOf(e); selectors[index].push(displayItem); selectors[index] = selectors[index].sort(this.sorter); } else { matches.push(e); selectors.push([displayItem]); } } } return { matches, selectors }; } removable(element) { if (element.style && element.style.display !== "" && element.style.display !== "none") { return false; } return true; } } var filters = [ WhiteSpaceFilter, CommentsFilter, ScriptsFilter, UndisplayedFilter ]; var isImplemented$3 = function () { var from = Array.from, arr, result; if (typeof from !== "function") return false; arr = ["raz", "dwa"]; result = from(arr); return Boolean(result && (result !== arr) && (result[1] === "dwa")); }; var validTypes = { object: true, symbol: true }; var isImplemented$2 = function () { var symbol; if (typeof Symbol !== 'function') return false; symbol = Symbol('test symbol'); try { String(symbol); } catch (e) { return false; } // Return 'true' also for polyfills if (!validTypes[typeof Symbol.iterator]) return false; if (!validTypes[typeof Symbol.toPrimitive]) return false; if (!validTypes[typeof Symbol.toStringTag]) return false; return true; }; var isSymbol$1 = function (x) { if (!x) return false; if (typeof x === 'symbol') return true; if (!x.constructor) return false; if (x.constructor.name !== 'Symbol') return false; return (x[x.constructor.toStringTag] === 'Symbol'); }; var isSymbol = isSymbol$1; var validateSymbol$1 = function (value) { if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); return value; }; var d$1 = d$3.exports , validateSymbol = validateSymbol$1 , create = Object.create, defineProperties = Object.defineProperties , defineProperty$2 = Object.defineProperty, objPrototype = Object.prototype , NativeSymbol, SymbolPolyfill, HiddenSymbol, globalSymbols = create(null) , isNativeSafe; if (typeof Symbol === 'function') { NativeSymbol = Symbol; try { String(NativeSymbol()); isNativeSafe = true; } catch (ignore) {} } var generateName = (function () { var created = create(null); return function (desc) { var postfix = 0, name, ie11BugWorkaround; while (created[desc + (postfix || '')]) ++postfix; desc += (postfix || ''); created[desc] = true; name = '@@' + desc; defineProperty$2(objPrototype, name, d$1.gs(null, function (value) { // For IE11 issue see: // https://connect.microsoft.com/IE/feedbackdetail/view/1928508/ // ie11-broken-getters-on-dom-objects // https://github.com/medikoo/es6-symbol/issues/12 if (ie11BugWorkaround) return; ie11BugWorkaround = true; defineProperty$2(this, name, d$1(value)); ie11BugWorkaround = false; })); return name; }; }()); // Internal constructor (not one exposed) for creating Symbol instances. // This one is used to ensure that `someSymbol instanceof Symbol` always return false HiddenSymbol = function Symbol(description) { if (this instanceof HiddenSymbol) throw new TypeError('Symbol is not a constructor'); return SymbolPolyfill(description); }; // Exposed `Symbol` constructor // (returns instances of HiddenSymbol) var polyfill = SymbolPolyfill = function Symbol(description) { var symbol; if (this instanceof Symbol) throw new TypeError('Symbol is not a constructor'); if (isNativeSafe) return NativeSymbol(description); symbol = create(HiddenSymbol.prototype); description = (description === undefined ? '' : String(description)); return defineProperties(symbol, { __description__: d$1('', description), __name__: d$1('', generateName(description)) }); }; defineProperties(SymbolPolyfill, { for: d$1(function (key) { if (globalSymbols[key]) return globalSymbols[key]; return (globalSymbols[key] = SymbolPolyfill(String(key))); }), keyFor: d$1(function (s) { var key; validateSymbol(s); for (key in globalSymbols) if (globalSymbols[key] === s) return key; }), // To ensure proper interoperability with other native functions (e.g. Array.from) // fallback to eventual native implementation of given symbol hasInstance: d$1('', (NativeSymbol && NativeSymbol.hasInstance) || SymbolPolyfill('hasInstance')), isConcatSpreadable: d$1('', (NativeSymbol && NativeSymbol.isConcatSpreadable) || SymbolPolyfill('isConcatSpreadable')), iterator: d$1('', (NativeSymbol && NativeSymbol.iterator) || SymbolPolyfill('iterator')), match: d$1('', (NativeSymbol && NativeSymbol.match) || SymbolPolyfill('match')), replace: d$1('', (NativeSymbol && NativeSymbol.replace) || SymbolPolyfill('replace')), search: d$1('', (NativeSymbol && NativeSymbol.search) || SymbolPolyfill('search')), species: d$1('', (NativeSymbol && NativeSymbol.species) || SymbolPolyfill('species')), split: d$1('', (NativeSymbol && NativeSymbol.split) || SymbolPolyfill('split')), toPrimitive: d$1('', (NativeSymbol && NativeSymbol.toPrimitive) || SymbolPolyfill('toPrimitive')), toStringTag: d$1('', (NativeSymbol && NativeSymbol.toStringTag) || SymbolPolyfill('toStringTag')), unscopables: d$1('', (NativeSymbol && NativeSymbol.unscopables) || SymbolPolyfill('unscopables')) }); // Internal tweaks for real symbol producer defineProperties(HiddenSymbol.prototype, { constructor: d$1(SymbolPolyfill), toString: d$1('', function () { return this.__name__; }) }); // Proper implementation of methods exposed on Symbol.prototype // They won't be accessible on produced symbol instances as they derive from HiddenSymbol.prototype defineProperties(SymbolPolyfill.prototype, { toString: d$1(function () { return 'Symbol (' + validateSymbol(this).__description__ + ')'; }), valueOf: d$1(function () { return validateSymbol(this); }) }); defineProperty$2(SymbolPolyfill.prototype, SymbolPolyfill.toPrimitive, d$1('', function () { var symbol = validateSymbol(this); if (typeof symbol === 'symbol') return symbol; return symbol.toString(); })); defineProperty$2(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d$1('c', 'Symbol')); // Proper implementaton of toPrimitive and toStringTag for returned symbol instances defineProperty$2(HiddenSymbol.prototype, SymbolPolyfill.toStringTag, d$1('c', SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])); // Note: It's important to define `toPrimitive` as last one, as some implementations // implement `toPrimitive` natively without implementing `toStringTag` (or other specified symbols) // And that may invoke error in definition flow: // See: https://github.com/medikoo/es6-symbol/issues/13#issuecomment-164146149 defineProperty$2(HiddenSymbol.prototype, SymbolPolyfill.toPrimitive, d$1('c', SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])); var es6Symbol = isImplemented$2() ? Symbol : polyfill; var objToString$2 = Object.prototype.toString , id$2 = objToString$2.call( (function () { return arguments; })() ); var isArguments$1 = function (value) { return objToString$2.call(value) === id$2; }; var objToString$1 = Object.prototype.toString, id$1 = objToString$1.call(noop$4); var isFunction$1 = function (value) { return typeof value === "function" && objToString$1.call(value) === id$1; }; var isImplemented$1 = function () { var sign = Math.sign; if (typeof sign !== "function") return false; return (sign(10) === 1) && (sign(-20) === -1); }; var shim$2 = function (value) { value = Number(value); if (isNaN(value) || (value === 0)) return value; return value > 0 ? 1 : -1; }; var sign$1 = isImplemented$1() ? Math.sign : shim$2; var sign = sign$1 , abs$1 = Math.abs, floor$1 = Math.floor; var toInteger$1 = function (value) { if (isNaN(value)) return 0; value = Number(value); if ((value === 0) || !isFinite(value)) return value; return sign(value) * floor$1(abs$1(value)); }; var toInteger = toInteger$1 , max = Math.max; var toPosInteger = function (value) { return max(0, toInteger(value)); }; var objToString = Object.prototype.toString, id = objToString.call(""); var isString$1 = function (value) { return ( typeof value === "string" || (value && typeof value === "object" && (value instanceof String || objToString.call(value) === id)) || false ); }; var iteratorSymbol = es6Symbol.iterator , isArguments = isArguments$1 , isFunction = isFunction$1 , toPosInt$1 = toPosInteger , callable = validCallable , validValue = validValue$1 , isValue$1 = isValue$5 , isString = isString$1 , isArray = Array.isArray , call = Function.prototype.call , desc = { configurable: true, enumerable: true, writable: true, value: null } , defineProperty$1 = Object.defineProperty; // eslint-disable-next-line complexity var shim$1 = function (arrayLike /*, mapFn, thisArg*/) { var mapFn = arguments[1] , thisArg = arguments[2] , Context , i , j , arr , length , code , iterator , result , getIterator , value; arrayLike = Object(validValue(arrayLike)); if (isValue$1(mapFn)) callable(mapFn); if (!this || this === Array || !isFunction(this)) { // Result: Plain array if (!mapFn) { if (isArguments(arrayLike)) { // Source: Arguments length = arrayLike.length; if (length !== 1) return Array.apply(null, arrayLike); arr = new Array(1); arr[0] = arrayLike[0]; return arr; } if (isArray(arrayLike)) { // Source: Array arr = new Array(length = arrayLike.length); for (i = 0; i < length; ++i) arr[i] = arrayLike[i]; return arr; } } arr = []; } else { // Result: Non plain array Context = this; } if (!isArray(arrayLike)) { if ((getIterator = arrayLike[iteratorSymbol]) !== undefined) { // Source: Iterator iterator = callable(getIterator).call(arrayLike); if (Context) arr = new Context(); result = iterator.next(); i = 0; while (!result.done) { value = mapFn ? call.call(mapFn, thisArg, result.value, i) : result.value; if (Context) { desc.value = value; defineProperty$1(arr, i, desc); } else { arr[i] = value; } result = iterator.next(); ++i; } length = i; } else if (isString(arrayLike)) { // Source: String length = arrayLike.length; if (Context) arr = new Context(); for (i = 0, j = 0; i < length; ++i) { value = arrayLike[i]; if (i + 1 < length) { code = value.charCodeAt(0); // eslint-disable-next-line max-depth if (code >= 0xd800 && code <= 0xdbff) value += arrayLike[++i]; } value = mapFn ? call.call(mapFn, thisArg, value, j) : value; if (Context) { desc.value = value; defineProperty$1(arr, j, desc); } else { arr[j] = value; } ++j; } length = j; } } if (length === undefined) { // Source: array or array-like length = toPosInt$1(arrayLike.length); if (Context) arr = new Context(length); for (i = 0; i < length; ++i) { value = mapFn ? call.call(mapFn, thisArg, arrayLike[i], i) : arrayLike[i]; if (Context) { desc.value = value; defineProperty$1(arr, i, desc); } else { arr[i] = value; } } } if (Context) { desc.value = null; arr.length = length; } return arr; }; var from = isImplemented$3() ? Array.from : shim$1; var isImplemented = function () { var numberIsNaN = Number.isNaN; if (typeof numberIsNaN !== "function") return false; return !numberIsNaN({}) && numberIsNaN(NaN) && !numberIsNaN(34); }; var shim = function (value) { // eslint-disable-next-line no-self-compare return value !== value; }; var isNan = isImplemented() ? Number.isNaN : shim; var numberIsNaN = isNan , toPosInt = toPosInteger , value$1 = validValue$1 , indexOf$1 = Array.prototype.indexOf , objHasOwnProperty = Object.prototype.hasOwnProperty , abs = Math.abs , floor = Math.floor; var eIndexOf = function (searchElement /*, fromIndex*/) { var i, length, fromIndex, val; if (!numberIsNaN(searchElement)) return indexOf$1.apply(this, arguments); length = toPosInt(value$1(this).length); fromIndex = arguments[1]; if (isNaN(fromIndex)) fromIndex = 0; else if (fromIndex >= 0) fromIndex = floor(fromIndex); else fromIndex = toPosInt(this.length) - floor(abs(fromIndex)); for (i = fromIndex; i < length; ++i) { if (objHasOwnProperty.call(this, i)) { val = this[i]; if (numberIsNaN(val)) return i; // Jslint: ignore } } return -1; }; var indexOf = eIndexOf , forEach = Array.prototype.forEach , splice = Array.prototype.splice; // eslint-disable-next-line no-unused-vars var remove$1 = function (itemToRemove /*, …item*/) { forEach.call( arguments, function (item) { var index = indexOf.call(this, item); if (index !== -1) splice.call(this, index, 1); }, this ); }; var isValue = isValue$5; var map = { function: true, object: true }; var isObject$1 = function (value) { return (isValue(value) && map[typeof value]) || false; }; var isObject = isObject$1; var validObject = function (value) { if (!isObject(value)) throw new TypeError(value + " is not an Object"); return value; }; var aFrom = from , remove = remove$1 , value = validObject , d = d$3.exports , emit = eventEmitter.exports.methods.emit , defineProperty = Object.defineProperty , hasOwnProperty$1 = Object.prototype.hasOwnProperty , getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; var pipe = function (e1, e2/*, name*/) { var pipes, pipe, desc, name; (value(e1) && value(e2)); name = arguments[2]; if (name === undefined) name = 'emit'; pipe = { close: function () { remove.call(pipes, e2); } }; if (hasOwnProperty$1.call(e1, '__eePipes__')) { (pipes = e1.__eePipes__).push(e2); return pipe; } defineProperty(e1, '__eePipes__', d('c', pipes = [e2])); desc = getOwnPropertyDescriptor(e1, name); if (!desc) { desc = d('c', undefined); } else { delete desc.get; delete desc.set; } desc.value = function () { var i, emitter, data = aFrom(pipes); emit.apply(this, arguments); for (i = 0; (emitter = data[i]); ++i) emit.apply(emitter, arguments); }; defineProperty(e1, name, desc); return pipe; }; let registeredHandlers = [...pagedMediaHandlers, ...generatedContentHandlers, ...filters]; class Handlers { constructor(chunker, polisher, caller) { registeredHandlers.forEach((Handler) => { let handler = new Handler(chunker, polisher, caller); pipe(handler, this); }); } } EventEmitter(Handlers.prototype); function registerHandlers() { for (var i = 0; i < arguments.length; i++) { registeredHandlers.push(arguments[i]); } } function initializeHandlers(chunker, polisher, caller) { let handlers = new Handlers(chunker, polisher, caller); return handlers; } class Previewer { constructor(options) { // this.preview = this.getParams("preview") !== "false"; this.settings = options || {}; // Process styles this.polisher = new Polisher(false); // Chunk contents this.chunker = new Chunker(undefined, undefined, this.settings); // Hooks this.hooks = {}; this.hooks.beforePreview = new Hook(this); this.hooks.afterPreview = new Hook(this); // default size this.size = { width: { value: 8.5, unit: "in" }, height: { value: 11, unit: "in" }, format: undefined, orientation: undefined }; this.chunker.on("page", (page) => { this.emit("page", page); }); this.chunker.on("rendering", () => { this.emit("rendering", this.chunker); }); } initializeHandlers() { let handlers = initializeHandlers(this.chunker, this.polisher, this); handlers.on("size", (size) => { this.size = size; this.emit("size", size); }); handlers.on("atpages", (pages) => { this.atpages = pages; this.emit("atpages", pages); }); return handlers; } registerHandlers() { return registerHandlers.apply(registerHandlers, arguments); } getParams(name) { let param; let url = new URL(window.location); let params = new URLSearchParams(url.search); for(var pair of params.entries()) { if(pair[0] === name) { param = pair[1]; } } return param; } wrapContent() { // Wrap body in template tag let body = document.querySelector("body"); // Check if a template exists let template; template = body.querySelector(":scope > template[data-ref='pagedjs-content']"); if (!template) { // Otherwise create one template = document.createElement("template"); template.dataset.ref = "pagedjs-content"; template.innerHTML = body.innerHTML; body.innerHTML = ""; body.appendChild(template); } return template.content; } removeStyles(doc=document) { // Get all stylesheets const stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']:not([data-pagedjs-ignore], [media~='screen'])")); // Get inline styles const inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles], [data-pagedjs-ignore], [media~='screen'])")); const elements = [...stylesheets, ...inlineStyles]; return elements // preserve order .sort(function (element1, element2) { const position = element1.compareDocumentPosition(element2); if (position === Node.DOCUMENT_POSITION_PRECEDING) { return 1; } else if (position === Node.DOCUMENT_POSITION_FOLLOWING) { return -1; } return 0; }) // extract the href .map((element) => { if (element.nodeName === "STYLE") { const obj = {}; obj[window.location.href] = element.textContent; element.remove(); return obj; } if (element.nodeName === "LINK") { element.remove(); return element.href; } // ignore console.warn(`Unable to process: ${element}, ignoring.`); }); } async preview(content, stylesheets, renderTo) { await this.hooks.beforePreview.trigger(content, renderTo); if (!content) { content = this.wrapContent(); } if (!stylesheets) { stylesheets = this.removeStyles(); } this.polisher.setup(); this.handlers = this.initializeHandlers(); await this.polisher.add(...stylesheets); let startTime = performance.now(); // Render flow let flow = await this.chunker.flow(content, renderTo); let endTime = performance.now(); flow.performance = (endTime - startTime); flow.size = this.size; this.emit("rendered", flow); await this.hooks.afterPreview.trigger(flow.pages); return flow; } } EventEmitter(Previewer.prototype); var Paged = /*#__PURE__*/Object.freeze({ __proto__: null, Chunker: Chunker, Polisher: Polisher, Previewer: Previewer, Handler: Handler, registeredHandlers: registeredHandlers, registerHandlers: registerHandlers, initializeHandlers: initializeHandlers }); window.Paged = Paged; let ready = new Promise(function(resolve, reject){ if (document.readyState === "interactive" || document.readyState === "complete") { resolve(document.readyState); return; } document.onreadystatechange = function ($) { if (document.readyState === "interactive") { resolve(document.readyState); } }; }); let config = window.PagedConfig || { auto: true, before: undefined, after: undefined, content: undefined, stylesheets: undefined, renderTo: undefined, settings: undefined }; let previewer = new Previewer(config.settings); ready.then(async function () { let done; if (config.before) { await config.before(); } if(config.auto !== false) { done = await previewer.preview(config.content, config.stylesheets, config.renderTo); } if (config.after) { await config.after(done); } }); return previewer; }));