leaflet.js 378 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563
  1. import {
  2. __commonJS
  3. } from "./chunk-Y2F7D3TJ.js";
  4. // ../../../../Work2/Orienteering/mobile_h5/actMgt/node_modules/leaflet/dist/leaflet-src.js
  5. var require_leaflet_src = __commonJS({
  6. "../../../../Work2/Orienteering/mobile_h5/actMgt/node_modules/leaflet/dist/leaflet-src.js"(exports, module) {
  7. (function(global, factory) {
  8. typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.leaflet = {}));
  9. })(exports, function(exports2) {
  10. "use strict";
  11. var version = "1.9.4";
  12. function extend(dest) {
  13. var i, j, len, src;
  14. for (j = 1, len = arguments.length; j < len; j++) {
  15. src = arguments[j];
  16. for (i in src) {
  17. dest[i] = src[i];
  18. }
  19. }
  20. return dest;
  21. }
  22. var create$2 = Object.create || /* @__PURE__ */ function() {
  23. function F() {
  24. }
  25. return function(proto) {
  26. F.prototype = proto;
  27. return new F();
  28. };
  29. }();
  30. function bind(fn, obj) {
  31. var slice = Array.prototype.slice;
  32. if (fn.bind) {
  33. return fn.bind.apply(fn, slice.call(arguments, 1));
  34. }
  35. var args = slice.call(arguments, 2);
  36. return function() {
  37. return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
  38. };
  39. }
  40. var lastId = 0;
  41. function stamp(obj) {
  42. if (!("_leaflet_id" in obj)) {
  43. obj["_leaflet_id"] = ++lastId;
  44. }
  45. return obj._leaflet_id;
  46. }
  47. function throttle(fn, time, context) {
  48. var lock, args, wrapperFn, later;
  49. later = function() {
  50. lock = false;
  51. if (args) {
  52. wrapperFn.apply(context, args);
  53. args = false;
  54. }
  55. };
  56. wrapperFn = function() {
  57. if (lock) {
  58. args = arguments;
  59. } else {
  60. fn.apply(context, arguments);
  61. setTimeout(later, time);
  62. lock = true;
  63. }
  64. };
  65. return wrapperFn;
  66. }
  67. function wrapNum(x, range, includeMax) {
  68. var max = range[1], min = range[0], d = max - min;
  69. return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
  70. }
  71. function falseFn() {
  72. return false;
  73. }
  74. function formatNum(num, precision) {
  75. if (precision === false) {
  76. return num;
  77. }
  78. var pow = Math.pow(10, precision === void 0 ? 6 : precision);
  79. return Math.round(num * pow) / pow;
  80. }
  81. function trim(str) {
  82. return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, "");
  83. }
  84. function splitWords(str) {
  85. return trim(str).split(/\s+/);
  86. }
  87. function setOptions(obj, options) {
  88. if (!Object.prototype.hasOwnProperty.call(obj, "options")) {
  89. obj.options = obj.options ? create$2(obj.options) : {};
  90. }
  91. for (var i in options) {
  92. obj.options[i] = options[i];
  93. }
  94. return obj.options;
  95. }
  96. function getParamString(obj, existingUrl, uppercase) {
  97. var params = [];
  98. for (var i in obj) {
  99. params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + "=" + encodeURIComponent(obj[i]));
  100. }
  101. return (!existingUrl || existingUrl.indexOf("?") === -1 ? "?" : "&") + params.join("&");
  102. }
  103. var templateRe = /\{ *([\w_ -]+) *\}/g;
  104. function template(str, data) {
  105. return str.replace(templateRe, function(str2, key) {
  106. var value = data[key];
  107. if (value === void 0) {
  108. throw new Error("No value provided for variable " + str2);
  109. } else if (typeof value === "function") {
  110. value = value(data);
  111. }
  112. return value;
  113. });
  114. }
  115. var isArray = Array.isArray || function(obj) {
  116. return Object.prototype.toString.call(obj) === "[object Array]";
  117. };
  118. function indexOf(array, el) {
  119. for (var i = 0; i < array.length; i++) {
  120. if (array[i] === el) {
  121. return i;
  122. }
  123. }
  124. return -1;
  125. }
  126. var emptyImageUrl = "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
  127. function getPrefixed(name) {
  128. return window["webkit" + name] || window["moz" + name] || window["ms" + name];
  129. }
  130. var lastTime = 0;
  131. function timeoutDefer(fn) {
  132. var time = +/* @__PURE__ */ new Date(), timeToCall = Math.max(0, 16 - (time - lastTime));
  133. lastTime = time + timeToCall;
  134. return window.setTimeout(fn, timeToCall);
  135. }
  136. var requestFn = window.requestAnimationFrame || getPrefixed("RequestAnimationFrame") || timeoutDefer;
  137. var cancelFn = window.cancelAnimationFrame || getPrefixed("CancelAnimationFrame") || getPrefixed("CancelRequestAnimationFrame") || function(id) {
  138. window.clearTimeout(id);
  139. };
  140. function requestAnimFrame(fn, context, immediate) {
  141. if (immediate && requestFn === timeoutDefer) {
  142. fn.call(context);
  143. } else {
  144. return requestFn.call(window, bind(fn, context));
  145. }
  146. }
  147. function cancelAnimFrame(id) {
  148. if (id) {
  149. cancelFn.call(window, id);
  150. }
  151. }
  152. var Util = {
  153. __proto__: null,
  154. extend,
  155. create: create$2,
  156. bind,
  157. get lastId() {
  158. return lastId;
  159. },
  160. stamp,
  161. throttle,
  162. wrapNum,
  163. falseFn,
  164. formatNum,
  165. trim,
  166. splitWords,
  167. setOptions,
  168. getParamString,
  169. template,
  170. isArray,
  171. indexOf,
  172. emptyImageUrl,
  173. requestFn,
  174. cancelFn,
  175. requestAnimFrame,
  176. cancelAnimFrame
  177. };
  178. function Class() {
  179. }
  180. Class.extend = function(props) {
  181. var NewClass = function() {
  182. setOptions(this);
  183. if (this.initialize) {
  184. this.initialize.apply(this, arguments);
  185. }
  186. this.callInitHooks();
  187. };
  188. var parentProto = NewClass.__super__ = this.prototype;
  189. var proto = create$2(parentProto);
  190. proto.constructor = NewClass;
  191. NewClass.prototype = proto;
  192. for (var i in this) {
  193. if (Object.prototype.hasOwnProperty.call(this, i) && i !== "prototype" && i !== "__super__") {
  194. NewClass[i] = this[i];
  195. }
  196. }
  197. if (props.statics) {
  198. extend(NewClass, props.statics);
  199. }
  200. if (props.includes) {
  201. checkDeprecatedMixinEvents(props.includes);
  202. extend.apply(null, [proto].concat(props.includes));
  203. }
  204. extend(proto, props);
  205. delete proto.statics;
  206. delete proto.includes;
  207. if (proto.options) {
  208. proto.options = parentProto.options ? create$2(parentProto.options) : {};
  209. extend(proto.options, props.options);
  210. }
  211. proto._initHooks = [];
  212. proto.callInitHooks = function() {
  213. if (this._initHooksCalled) {
  214. return;
  215. }
  216. if (parentProto.callInitHooks) {
  217. parentProto.callInitHooks.call(this);
  218. }
  219. this._initHooksCalled = true;
  220. for (var i2 = 0, len = proto._initHooks.length; i2 < len; i2++) {
  221. proto._initHooks[i2].call(this);
  222. }
  223. };
  224. return NewClass;
  225. };
  226. Class.include = function(props) {
  227. var parentOptions = this.prototype.options;
  228. extend(this.prototype, props);
  229. if (props.options) {
  230. this.prototype.options = parentOptions;
  231. this.mergeOptions(props.options);
  232. }
  233. return this;
  234. };
  235. Class.mergeOptions = function(options) {
  236. extend(this.prototype.options, options);
  237. return this;
  238. };
  239. Class.addInitHook = function(fn) {
  240. var args = Array.prototype.slice.call(arguments, 1);
  241. var init = typeof fn === "function" ? fn : function() {
  242. this[fn].apply(this, args);
  243. };
  244. this.prototype._initHooks = this.prototype._initHooks || [];
  245. this.prototype._initHooks.push(init);
  246. return this;
  247. };
  248. function checkDeprecatedMixinEvents(includes) {
  249. if (typeof L === "undefined" || !L || !L.Mixin) {
  250. return;
  251. }
  252. includes = isArray(includes) ? includes : [includes];
  253. for (var i = 0; i < includes.length; i++) {
  254. if (includes[i] === L.Mixin.Events) {
  255. 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);
  256. }
  257. }
  258. }
  259. var Events = {
  260. /* @method on(type: String, fn: Function, context?: Object): this
  261. * 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'`).
  262. *
  263. * @alternative
  264. * @method on(eventMap: Object): this
  265. * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
  266. */
  267. on: function(types, fn, context) {
  268. if (typeof types === "object") {
  269. for (var type in types) {
  270. this._on(type, types[type], fn);
  271. }
  272. } else {
  273. types = splitWords(types);
  274. for (var i = 0, len = types.length; i < len; i++) {
  275. this._on(types[i], fn, context);
  276. }
  277. }
  278. return this;
  279. },
  280. /* @method off(type: String, fn?: Function, context?: Object): this
  281. * 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.
  282. *
  283. * @alternative
  284. * @method off(eventMap: Object): this
  285. * Removes a set of type/listener pairs.
  286. *
  287. * @alternative
  288. * @method off: this
  289. * Removes all listeners to all events on the object. This includes implicitly attached events.
  290. */
  291. off: function(types, fn, context) {
  292. if (!arguments.length) {
  293. delete this._events;
  294. } else if (typeof types === "object") {
  295. for (var type in types) {
  296. this._off(type, types[type], fn);
  297. }
  298. } else {
  299. types = splitWords(types);
  300. var removeAll = arguments.length === 1;
  301. for (var i = 0, len = types.length; i < len; i++) {
  302. if (removeAll) {
  303. this._off(types[i]);
  304. } else {
  305. this._off(types[i], fn, context);
  306. }
  307. }
  308. }
  309. return this;
  310. },
  311. // attach listener (without syntactic sugar now)
  312. _on: function(type, fn, context, _once) {
  313. if (typeof fn !== "function") {
  314. console.warn("wrong listener type: " + typeof fn);
  315. return;
  316. }
  317. if (this._listens(type, fn, context) !== false) {
  318. return;
  319. }
  320. if (context === this) {
  321. context = void 0;
  322. }
  323. var newListener = { fn, ctx: context };
  324. if (_once) {
  325. newListener.once = true;
  326. }
  327. this._events = this._events || {};
  328. this._events[type] = this._events[type] || [];
  329. this._events[type].push(newListener);
  330. },
  331. _off: function(type, fn, context) {
  332. var listeners, i, len;
  333. if (!this._events) {
  334. return;
  335. }
  336. listeners = this._events[type];
  337. if (!listeners) {
  338. return;
  339. }
  340. if (arguments.length === 1) {
  341. if (this._firingCount) {
  342. for (i = 0, len = listeners.length; i < len; i++) {
  343. listeners[i].fn = falseFn;
  344. }
  345. }
  346. delete this._events[type];
  347. return;
  348. }
  349. if (typeof fn !== "function") {
  350. console.warn("wrong listener type: " + typeof fn);
  351. return;
  352. }
  353. var index2 = this._listens(type, fn, context);
  354. if (index2 !== false) {
  355. var listener = listeners[index2];
  356. if (this._firingCount) {
  357. listener.fn = falseFn;
  358. this._events[type] = listeners = listeners.slice();
  359. }
  360. listeners.splice(index2, 1);
  361. }
  362. },
  363. // @method fire(type: String, data?: Object, propagate?: Boolean): this
  364. // Fires an event of the specified type. You can optionally provide a data
  365. // object — the first argument of the listener function will contain its
  366. // properties. The event can optionally be propagated to event parents.
  367. fire: function(type, data, propagate) {
  368. if (!this.listens(type, propagate)) {
  369. return this;
  370. }
  371. var event = extend({}, data, {
  372. type,
  373. target: this,
  374. sourceTarget: data && data.sourceTarget || this
  375. });
  376. if (this._events) {
  377. var listeners = this._events[type];
  378. if (listeners) {
  379. this._firingCount = this._firingCount + 1 || 1;
  380. for (var i = 0, len = listeners.length; i < len; i++) {
  381. var l = listeners[i];
  382. var fn = l.fn;
  383. if (l.once) {
  384. this.off(type, fn, l.ctx);
  385. }
  386. fn.call(l.ctx || this, event);
  387. }
  388. this._firingCount--;
  389. }
  390. }
  391. if (propagate) {
  392. this._propagateEvent(event);
  393. }
  394. return this;
  395. },
  396. // @method listens(type: String, propagate?: Boolean): Boolean
  397. // @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean
  398. // Returns `true` if a particular event type has any listeners attached to it.
  399. // The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.
  400. listens: function(type, fn, context, propagate) {
  401. if (typeof type !== "string") {
  402. console.warn('"string" type argument expected');
  403. }
  404. var _fn = fn;
  405. if (typeof fn !== "function") {
  406. propagate = !!fn;
  407. _fn = void 0;
  408. context = void 0;
  409. }
  410. var listeners = this._events && this._events[type];
  411. if (listeners && listeners.length) {
  412. if (this._listens(type, _fn, context) !== false) {
  413. return true;
  414. }
  415. }
  416. if (propagate) {
  417. for (var id in this._eventParents) {
  418. if (this._eventParents[id].listens(type, fn, context, propagate)) {
  419. return true;
  420. }
  421. }
  422. }
  423. return false;
  424. },
  425. // returns the index (number) or false
  426. _listens: function(type, fn, context) {
  427. if (!this._events) {
  428. return false;
  429. }
  430. var listeners = this._events[type] || [];
  431. if (!fn) {
  432. return !!listeners.length;
  433. }
  434. if (context === this) {
  435. context = void 0;
  436. }
  437. for (var i = 0, len = listeners.length; i < len; i++) {
  438. if (listeners[i].fn === fn && listeners[i].ctx === context) {
  439. return i;
  440. }
  441. }
  442. return false;
  443. },
  444. // @method once(…): this
  445. // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
  446. once: function(types, fn, context) {
  447. if (typeof types === "object") {
  448. for (var type in types) {
  449. this._on(type, types[type], fn, true);
  450. }
  451. } else {
  452. types = splitWords(types);
  453. for (var i = 0, len = types.length; i < len; i++) {
  454. this._on(types[i], fn, context, true);
  455. }
  456. }
  457. return this;
  458. },
  459. // @method addEventParent(obj: Evented): this
  460. // Adds an event parent - an `Evented` that will receive propagated events
  461. addEventParent: function(obj) {
  462. this._eventParents = this._eventParents || {};
  463. this._eventParents[stamp(obj)] = obj;
  464. return this;
  465. },
  466. // @method removeEventParent(obj: Evented): this
  467. // Removes an event parent, so it will stop receiving propagated events
  468. removeEventParent: function(obj) {
  469. if (this._eventParents) {
  470. delete this._eventParents[stamp(obj)];
  471. }
  472. return this;
  473. },
  474. _propagateEvent: function(e) {
  475. for (var id in this._eventParents) {
  476. this._eventParents[id].fire(e.type, extend({
  477. layer: e.target,
  478. propagatedFrom: e.target
  479. }, e), true);
  480. }
  481. }
  482. };
  483. Events.addEventListener = Events.on;
  484. Events.removeEventListener = Events.clearAllEventListeners = Events.off;
  485. Events.addOneTimeEventListener = Events.once;
  486. Events.fireEvent = Events.fire;
  487. Events.hasEventListeners = Events.listens;
  488. var Evented = Class.extend(Events);
  489. function Point(x, y, round) {
  490. this.x = round ? Math.round(x) : x;
  491. this.y = round ? Math.round(y) : y;
  492. }
  493. var trunc = Math.trunc || function(v) {
  494. return v > 0 ? Math.floor(v) : Math.ceil(v);
  495. };
  496. Point.prototype = {
  497. // @method clone(): Point
  498. // Returns a copy of the current point.
  499. clone: function() {
  500. return new Point(this.x, this.y);
  501. },
  502. // @method add(otherPoint: Point): Point
  503. // Returns the result of addition of the current and the given points.
  504. add: function(point) {
  505. return this.clone()._add(toPoint(point));
  506. },
  507. _add: function(point) {
  508. this.x += point.x;
  509. this.y += point.y;
  510. return this;
  511. },
  512. // @method subtract(otherPoint: Point): Point
  513. // Returns the result of subtraction of the given point from the current.
  514. subtract: function(point) {
  515. return this.clone()._subtract(toPoint(point));
  516. },
  517. _subtract: function(point) {
  518. this.x -= point.x;
  519. this.y -= point.y;
  520. return this;
  521. },
  522. // @method divideBy(num: Number): Point
  523. // Returns the result of division of the current point by the given number.
  524. divideBy: function(num) {
  525. return this.clone()._divideBy(num);
  526. },
  527. _divideBy: function(num) {
  528. this.x /= num;
  529. this.y /= num;
  530. return this;
  531. },
  532. // @method multiplyBy(num: Number): Point
  533. // Returns the result of multiplication of the current point by the given number.
  534. multiplyBy: function(num) {
  535. return this.clone()._multiplyBy(num);
  536. },
  537. _multiplyBy: function(num) {
  538. this.x *= num;
  539. this.y *= num;
  540. return this;
  541. },
  542. // @method scaleBy(scale: Point): Point
  543. // Multiply each coordinate of the current point by each coordinate of
  544. // `scale`. In linear algebra terms, multiply the point by the
  545. // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
  546. // defined by `scale`.
  547. scaleBy: function(point) {
  548. return new Point(this.x * point.x, this.y * point.y);
  549. },
  550. // @method unscaleBy(scale: Point): Point
  551. // Inverse of `scaleBy`. Divide each coordinate of the current point by
  552. // each coordinate of `scale`.
  553. unscaleBy: function(point) {
  554. return new Point(this.x / point.x, this.y / point.y);
  555. },
  556. // @method round(): Point
  557. // Returns a copy of the current point with rounded coordinates.
  558. round: function() {
  559. return this.clone()._round();
  560. },
  561. _round: function() {
  562. this.x = Math.round(this.x);
  563. this.y = Math.round(this.y);
  564. return this;
  565. },
  566. // @method floor(): Point
  567. // Returns a copy of the current point with floored coordinates (rounded down).
  568. floor: function() {
  569. return this.clone()._floor();
  570. },
  571. _floor: function() {
  572. this.x = Math.floor(this.x);
  573. this.y = Math.floor(this.y);
  574. return this;
  575. },
  576. // @method ceil(): Point
  577. // Returns a copy of the current point with ceiled coordinates (rounded up).
  578. ceil: function() {
  579. return this.clone()._ceil();
  580. },
  581. _ceil: function() {
  582. this.x = Math.ceil(this.x);
  583. this.y = Math.ceil(this.y);
  584. return this;
  585. },
  586. // @method trunc(): Point
  587. // Returns a copy of the current point with truncated coordinates (rounded towards zero).
  588. trunc: function() {
  589. return this.clone()._trunc();
  590. },
  591. _trunc: function() {
  592. this.x = trunc(this.x);
  593. this.y = trunc(this.y);
  594. return this;
  595. },
  596. // @method distanceTo(otherPoint: Point): Number
  597. // Returns the cartesian distance between the current and the given points.
  598. distanceTo: function(point) {
  599. point = toPoint(point);
  600. var x = point.x - this.x, y = point.y - this.y;
  601. return Math.sqrt(x * x + y * y);
  602. },
  603. // @method equals(otherPoint: Point): Boolean
  604. // Returns `true` if the given point has the same coordinates.
  605. equals: function(point) {
  606. point = toPoint(point);
  607. return point.x === this.x && point.y === this.y;
  608. },
  609. // @method contains(otherPoint: Point): Boolean
  610. // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
  611. contains: function(point) {
  612. point = toPoint(point);
  613. return Math.abs(point.x) <= Math.abs(this.x) && Math.abs(point.y) <= Math.abs(this.y);
  614. },
  615. // @method toString(): String
  616. // Returns a string representation of the point for debugging purposes.
  617. toString: function() {
  618. return "Point(" + formatNum(this.x) + ", " + formatNum(this.y) + ")";
  619. }
  620. };
  621. function toPoint(x, y, round) {
  622. if (x instanceof Point) {
  623. return x;
  624. }
  625. if (isArray(x)) {
  626. return new Point(x[0], x[1]);
  627. }
  628. if (x === void 0 || x === null) {
  629. return x;
  630. }
  631. if (typeof x === "object" && "x" in x && "y" in x) {
  632. return new Point(x.x, x.y);
  633. }
  634. return new Point(x, y, round);
  635. }
  636. function Bounds(a, b) {
  637. if (!a) {
  638. return;
  639. }
  640. var points = b ? [a, b] : a;
  641. for (var i = 0, len = points.length; i < len; i++) {
  642. this.extend(points[i]);
  643. }
  644. }
  645. Bounds.prototype = {
  646. // @method extend(point: Point): this
  647. // Extends the bounds to contain the given point.
  648. // @alternative
  649. // @method extend(otherBounds: Bounds): this
  650. // Extend the bounds to contain the given bounds
  651. extend: function(obj) {
  652. var min2, max2;
  653. if (!obj) {
  654. return this;
  655. }
  656. if (obj instanceof Point || typeof obj[0] === "number" || "x" in obj) {
  657. min2 = max2 = toPoint(obj);
  658. } else {
  659. obj = toBounds(obj);
  660. min2 = obj.min;
  661. max2 = obj.max;
  662. if (!min2 || !max2) {
  663. return this;
  664. }
  665. }
  666. if (!this.min && !this.max) {
  667. this.min = min2.clone();
  668. this.max = max2.clone();
  669. } else {
  670. this.min.x = Math.min(min2.x, this.min.x);
  671. this.max.x = Math.max(max2.x, this.max.x);
  672. this.min.y = Math.min(min2.y, this.min.y);
  673. this.max.y = Math.max(max2.y, this.max.y);
  674. }
  675. return this;
  676. },
  677. // @method getCenter(round?: Boolean): Point
  678. // Returns the center point of the bounds.
  679. getCenter: function(round) {
  680. return toPoint(
  681. (this.min.x + this.max.x) / 2,
  682. (this.min.y + this.max.y) / 2,
  683. round
  684. );
  685. },
  686. // @method getBottomLeft(): Point
  687. // Returns the bottom-left point of the bounds.
  688. getBottomLeft: function() {
  689. return toPoint(this.min.x, this.max.y);
  690. },
  691. // @method getTopRight(): Point
  692. // Returns the top-right point of the bounds.
  693. getTopRight: function() {
  694. return toPoint(this.max.x, this.min.y);
  695. },
  696. // @method getTopLeft(): Point
  697. // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
  698. getTopLeft: function() {
  699. return this.min;
  700. },
  701. // @method getBottomRight(): Point
  702. // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
  703. getBottomRight: function() {
  704. return this.max;
  705. },
  706. // @method getSize(): Point
  707. // Returns the size of the given bounds
  708. getSize: function() {
  709. return this.max.subtract(this.min);
  710. },
  711. // @method contains(otherBounds: Bounds): Boolean
  712. // Returns `true` if the rectangle contains the given one.
  713. // @alternative
  714. // @method contains(point: Point): Boolean
  715. // Returns `true` if the rectangle contains the given point.
  716. contains: function(obj) {
  717. var min, max;
  718. if (typeof obj[0] === "number" || obj instanceof Point) {
  719. obj = toPoint(obj);
  720. } else {
  721. obj = toBounds(obj);
  722. }
  723. if (obj instanceof Bounds) {
  724. min = obj.min;
  725. max = obj.max;
  726. } else {
  727. min = max = obj;
  728. }
  729. return min.x >= this.min.x && max.x <= this.max.x && min.y >= this.min.y && max.y <= this.max.y;
  730. },
  731. // @method intersects(otherBounds: Bounds): Boolean
  732. // Returns `true` if the rectangle intersects the given bounds. Two bounds
  733. // intersect if they have at least one point in common.
  734. intersects: function(bounds) {
  735. bounds = toBounds(bounds);
  736. var min = this.min, max = this.max, min2 = bounds.min, max2 = bounds.max, xIntersects = max2.x >= min.x && min2.x <= max.x, yIntersects = max2.y >= min.y && min2.y <= max.y;
  737. return xIntersects && yIntersects;
  738. },
  739. // @method overlaps(otherBounds: Bounds): Boolean
  740. // Returns `true` if the rectangle overlaps the given bounds. Two bounds
  741. // overlap if their intersection is an area.
  742. overlaps: function(bounds) {
  743. bounds = toBounds(bounds);
  744. var min = this.min, max = this.max, min2 = bounds.min, max2 = bounds.max, xOverlaps = max2.x > min.x && min2.x < max.x, yOverlaps = max2.y > min.y && min2.y < max.y;
  745. return xOverlaps && yOverlaps;
  746. },
  747. // @method isValid(): Boolean
  748. // Returns `true` if the bounds are properly initialized.
  749. isValid: function() {
  750. return !!(this.min && this.max);
  751. },
  752. // @method pad(bufferRatio: Number): Bounds
  753. // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
  754. // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
  755. // Negative values will retract the bounds.
  756. pad: function(bufferRatio) {
  757. var min = this.min, max = this.max, heightBuffer = Math.abs(min.x - max.x) * bufferRatio, widthBuffer = Math.abs(min.y - max.y) * bufferRatio;
  758. return toBounds(
  759. toPoint(min.x - heightBuffer, min.y - widthBuffer),
  760. toPoint(max.x + heightBuffer, max.y + widthBuffer)
  761. );
  762. },
  763. // @method equals(otherBounds: Bounds): Boolean
  764. // Returns `true` if the rectangle is equivalent to the given bounds.
  765. equals: function(bounds) {
  766. if (!bounds) {
  767. return false;
  768. }
  769. bounds = toBounds(bounds);
  770. return this.min.equals(bounds.getTopLeft()) && this.max.equals(bounds.getBottomRight());
  771. }
  772. };
  773. function toBounds(a, b) {
  774. if (!a || a instanceof Bounds) {
  775. return a;
  776. }
  777. return new Bounds(a, b);
  778. }
  779. function LatLngBounds(corner1, corner2) {
  780. if (!corner1) {
  781. return;
  782. }
  783. var latlngs = corner2 ? [corner1, corner2] : corner1;
  784. for (var i = 0, len = latlngs.length; i < len; i++) {
  785. this.extend(latlngs[i]);
  786. }
  787. }
  788. LatLngBounds.prototype = {
  789. // @method extend(latlng: LatLng): this
  790. // Extend the bounds to contain the given point
  791. // @alternative
  792. // @method extend(otherBounds: LatLngBounds): this
  793. // Extend the bounds to contain the given bounds
  794. extend: function(obj) {
  795. var sw = this._southWest, ne = this._northEast, sw2, ne2;
  796. if (obj instanceof LatLng) {
  797. sw2 = obj;
  798. ne2 = obj;
  799. } else if (obj instanceof LatLngBounds) {
  800. sw2 = obj._southWest;
  801. ne2 = obj._northEast;
  802. if (!sw2 || !ne2) {
  803. return this;
  804. }
  805. } else {
  806. return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
  807. }
  808. if (!sw && !ne) {
  809. this._southWest = new LatLng(sw2.lat, sw2.lng);
  810. this._northEast = new LatLng(ne2.lat, ne2.lng);
  811. } else {
  812. sw.lat = Math.min(sw2.lat, sw.lat);
  813. sw.lng = Math.min(sw2.lng, sw.lng);
  814. ne.lat = Math.max(ne2.lat, ne.lat);
  815. ne.lng = Math.max(ne2.lng, ne.lng);
  816. }
  817. return this;
  818. },
  819. // @method pad(bufferRatio: Number): LatLngBounds
  820. // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
  821. // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
  822. // Negative values will retract the bounds.
  823. pad: function(bufferRatio) {
  824. var sw = this._southWest, ne = this._northEast, heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
  825. return new LatLngBounds(
  826. new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
  827. new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)
  828. );
  829. },
  830. // @method getCenter(): LatLng
  831. // Returns the center point of the bounds.
  832. getCenter: function() {
  833. return new LatLng(
  834. (this._southWest.lat + this._northEast.lat) / 2,
  835. (this._southWest.lng + this._northEast.lng) / 2
  836. );
  837. },
  838. // @method getSouthWest(): LatLng
  839. // Returns the south-west point of the bounds.
  840. getSouthWest: function() {
  841. return this._southWest;
  842. },
  843. // @method getNorthEast(): LatLng
  844. // Returns the north-east point of the bounds.
  845. getNorthEast: function() {
  846. return this._northEast;
  847. },
  848. // @method getNorthWest(): LatLng
  849. // Returns the north-west point of the bounds.
  850. getNorthWest: function() {
  851. return new LatLng(this.getNorth(), this.getWest());
  852. },
  853. // @method getSouthEast(): LatLng
  854. // Returns the south-east point of the bounds.
  855. getSouthEast: function() {
  856. return new LatLng(this.getSouth(), this.getEast());
  857. },
  858. // @method getWest(): Number
  859. // Returns the west longitude of the bounds
  860. getWest: function() {
  861. return this._southWest.lng;
  862. },
  863. // @method getSouth(): Number
  864. // Returns the south latitude of the bounds
  865. getSouth: function() {
  866. return this._southWest.lat;
  867. },
  868. // @method getEast(): Number
  869. // Returns the east longitude of the bounds
  870. getEast: function() {
  871. return this._northEast.lng;
  872. },
  873. // @method getNorth(): Number
  874. // Returns the north latitude of the bounds
  875. getNorth: function() {
  876. return this._northEast.lat;
  877. },
  878. // @method contains(otherBounds: LatLngBounds): Boolean
  879. // Returns `true` if the rectangle contains the given one.
  880. // @alternative
  881. // @method contains (latlng: LatLng): Boolean
  882. // Returns `true` if the rectangle contains the given point.
  883. contains: function(obj) {
  884. if (typeof obj[0] === "number" || obj instanceof LatLng || "lat" in obj) {
  885. obj = toLatLng(obj);
  886. } else {
  887. obj = toLatLngBounds(obj);
  888. }
  889. var sw = this._southWest, ne = this._northEast, sw2, ne2;
  890. if (obj instanceof LatLngBounds) {
  891. sw2 = obj.getSouthWest();
  892. ne2 = obj.getNorthEast();
  893. } else {
  894. sw2 = ne2 = obj;
  895. }
  896. return sw2.lat >= sw.lat && ne2.lat <= ne.lat && sw2.lng >= sw.lng && ne2.lng <= ne.lng;
  897. },
  898. // @method intersects(otherBounds: LatLngBounds): Boolean
  899. // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
  900. intersects: function(bounds) {
  901. bounds = toLatLngBounds(bounds);
  902. var sw = this._southWest, ne = this._northEast, sw2 = bounds.getSouthWest(), ne2 = bounds.getNorthEast(), latIntersects = ne2.lat >= sw.lat && sw2.lat <= ne.lat, lngIntersects = ne2.lng >= sw.lng && sw2.lng <= ne.lng;
  903. return latIntersects && lngIntersects;
  904. },
  905. // @method overlaps(otherBounds: LatLngBounds): Boolean
  906. // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
  907. overlaps: function(bounds) {
  908. bounds = toLatLngBounds(bounds);
  909. var sw = this._southWest, ne = this._northEast, sw2 = bounds.getSouthWest(), ne2 = bounds.getNorthEast(), latOverlaps = ne2.lat > sw.lat && sw2.lat < ne.lat, lngOverlaps = ne2.lng > sw.lng && sw2.lng < ne.lng;
  910. return latOverlaps && lngOverlaps;
  911. },
  912. // @method toBBoxString(): String
  913. // 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.
  914. toBBoxString: function() {
  915. return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(",");
  916. },
  917. // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
  918. // 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.
  919. equals: function(bounds, maxMargin) {
  920. if (!bounds) {
  921. return false;
  922. }
  923. bounds = toLatLngBounds(bounds);
  924. return this._southWest.equals(bounds.getSouthWest(), maxMargin) && this._northEast.equals(bounds.getNorthEast(), maxMargin);
  925. },
  926. // @method isValid(): Boolean
  927. // Returns `true` if the bounds are properly initialized.
  928. isValid: function() {
  929. return !!(this._southWest && this._northEast);
  930. }
  931. };
  932. function toLatLngBounds(a, b) {
  933. if (a instanceof LatLngBounds) {
  934. return a;
  935. }
  936. return new LatLngBounds(a, b);
  937. }
  938. function LatLng(lat, lng, alt) {
  939. if (isNaN(lat) || isNaN(lng)) {
  940. throw new Error("Invalid LatLng object: (" + lat + ", " + lng + ")");
  941. }
  942. this.lat = +lat;
  943. this.lng = +lng;
  944. if (alt !== void 0) {
  945. this.alt = +alt;
  946. }
  947. }
  948. LatLng.prototype = {
  949. // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
  950. // 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.
  951. equals: function(obj, maxMargin) {
  952. if (!obj) {
  953. return false;
  954. }
  955. obj = toLatLng(obj);
  956. var margin = Math.max(
  957. Math.abs(this.lat - obj.lat),
  958. Math.abs(this.lng - obj.lng)
  959. );
  960. return margin <= (maxMargin === void 0 ? 1e-9 : maxMargin);
  961. },
  962. // @method toString(): String
  963. // Returns a string representation of the point (for debugging purposes).
  964. toString: function(precision) {
  965. return "LatLng(" + formatNum(this.lat, precision) + ", " + formatNum(this.lng, precision) + ")";
  966. },
  967. // @method distanceTo(otherLatLng: LatLng): Number
  968. // 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).
  969. distanceTo: function(other) {
  970. return Earth.distance(this, toLatLng(other));
  971. },
  972. // @method wrap(): LatLng
  973. // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
  974. wrap: function() {
  975. return Earth.wrapLatLng(this);
  976. },
  977. // @method toBounds(sizeInMeters: Number): LatLngBounds
  978. // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
  979. toBounds: function(sizeInMeters) {
  980. var latAccuracy = 180 * sizeInMeters / 40075017, lngAccuracy = latAccuracy / Math.cos(Math.PI / 180 * this.lat);
  981. return toLatLngBounds(
  982. [this.lat - latAccuracy, this.lng - lngAccuracy],
  983. [this.lat + latAccuracy, this.lng + lngAccuracy]
  984. );
  985. },
  986. clone: function() {
  987. return new LatLng(this.lat, this.lng, this.alt);
  988. }
  989. };
  990. function toLatLng(a, b, c) {
  991. if (a instanceof LatLng) {
  992. return a;
  993. }
  994. if (isArray(a) && typeof a[0] !== "object") {
  995. if (a.length === 3) {
  996. return new LatLng(a[0], a[1], a[2]);
  997. }
  998. if (a.length === 2) {
  999. return new LatLng(a[0], a[1]);
  1000. }
  1001. return null;
  1002. }
  1003. if (a === void 0 || a === null) {
  1004. return a;
  1005. }
  1006. if (typeof a === "object" && "lat" in a) {
  1007. return new LatLng(a.lat, "lng" in a ? a.lng : a.lon, a.alt);
  1008. }
  1009. if (b === void 0) {
  1010. return null;
  1011. }
  1012. return new LatLng(a, b, c);
  1013. }
  1014. var CRS = {
  1015. // @method latLngToPoint(latlng: LatLng, zoom: Number): Point
  1016. // Projects geographical coordinates into pixel coordinates for a given zoom.
  1017. latLngToPoint: function(latlng, zoom2) {
  1018. var projectedPoint = this.projection.project(latlng), scale2 = this.scale(zoom2);
  1019. return this.transformation._transform(projectedPoint, scale2);
  1020. },
  1021. // @method pointToLatLng(point: Point, zoom: Number): LatLng
  1022. // The inverse of `latLngToPoint`. Projects pixel coordinates on a given
  1023. // zoom into geographical coordinates.
  1024. pointToLatLng: function(point, zoom2) {
  1025. var scale2 = this.scale(zoom2), untransformedPoint = this.transformation.untransform(point, scale2);
  1026. return this.projection.unproject(untransformedPoint);
  1027. },
  1028. // @method project(latlng: LatLng): Point
  1029. // Projects geographical coordinates into coordinates in units accepted for
  1030. // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
  1031. project: function(latlng) {
  1032. return this.projection.project(latlng);
  1033. },
  1034. // @method unproject(point: Point): LatLng
  1035. // Given a projected coordinate returns the corresponding LatLng.
  1036. // The inverse of `project`.
  1037. unproject: function(point) {
  1038. return this.projection.unproject(point);
  1039. },
  1040. // @method scale(zoom: Number): Number
  1041. // Returns the scale used when transforming projected coordinates into
  1042. // pixel coordinates for a particular zoom. For example, it returns
  1043. // `256 * 2^zoom` for Mercator-based CRS.
  1044. scale: function(zoom2) {
  1045. return 256 * Math.pow(2, zoom2);
  1046. },
  1047. // @method zoom(scale: Number): Number
  1048. // Inverse of `scale()`, returns the zoom level corresponding to a scale
  1049. // factor of `scale`.
  1050. zoom: function(scale2) {
  1051. return Math.log(scale2 / 256) / Math.LN2;
  1052. },
  1053. // @method getProjectedBounds(zoom: Number): Bounds
  1054. // Returns the projection's bounds scaled and transformed for the provided `zoom`.
  1055. getProjectedBounds: function(zoom2) {
  1056. if (this.infinite) {
  1057. return null;
  1058. }
  1059. var b = this.projection.bounds, s = this.scale(zoom2), min = this.transformation.transform(b.min, s), max = this.transformation.transform(b.max, s);
  1060. return new Bounds(min, max);
  1061. },
  1062. // @method distance(latlng1: LatLng, latlng2: LatLng): Number
  1063. // Returns the distance between two geographical coordinates.
  1064. // @property code: String
  1065. // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
  1066. //
  1067. // @property wrapLng: Number[]
  1068. // An array of two numbers defining whether the longitude (horizontal) coordinate
  1069. // axis wraps around a given range and how. Defaults to `[-180, 180]` in most
  1070. // geographical CRSs. If `undefined`, the longitude axis does not wrap around.
  1071. //
  1072. // @property wrapLat: Number[]
  1073. // Like `wrapLng`, but for the latitude (vertical) axis.
  1074. // wrapLng: [min, max],
  1075. // wrapLat: [min, max],
  1076. // @property infinite: Boolean
  1077. // If true, the coordinate space will be unbounded (infinite in both axes)
  1078. infinite: false,
  1079. // @method wrapLatLng(latlng: LatLng): LatLng
  1080. // Returns a `LatLng` where lat and lng has been wrapped according to the
  1081. // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
  1082. wrapLatLng: function(latlng) {
  1083. var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, alt = latlng.alt;
  1084. return new LatLng(lat, lng, alt);
  1085. },
  1086. // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
  1087. // Returns a `LatLngBounds` with the same size as the given one, ensuring
  1088. // that its center is within the CRS's bounds.
  1089. // Only accepts actual `L.LatLngBounds` instances, not arrays.
  1090. wrapLatLngBounds: function(bounds) {
  1091. var center = bounds.getCenter(), newCenter = this.wrapLatLng(center), latShift = center.lat - newCenter.lat, lngShift = center.lng - newCenter.lng;
  1092. if (latShift === 0 && lngShift === 0) {
  1093. return bounds;
  1094. }
  1095. var sw = bounds.getSouthWest(), ne = bounds.getNorthEast(), newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift), newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
  1096. return new LatLngBounds(newSw, newNe);
  1097. }
  1098. };
  1099. var Earth = extend({}, CRS, {
  1100. wrapLng: [-180, 180],
  1101. // Mean Earth Radius, as recommended for use by
  1102. // the International Union of Geodesy and Geophysics,
  1103. // see https://rosettacode.org/wiki/Haversine_formula
  1104. R: 6371e3,
  1105. // distance between two geographical points using spherical law of cosines approximation
  1106. distance: function(latlng1, latlng2) {
  1107. var rad = Math.PI / 180, lat1 = latlng1.lat * rad, lat2 = latlng2.lat * rad, sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2), sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2), a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  1108. return this.R * c;
  1109. }
  1110. });
  1111. var earthRadius = 6378137;
  1112. var SphericalMercator = {
  1113. R: earthRadius,
  1114. MAX_LATITUDE: 85.0511287798,
  1115. project: function(latlng) {
  1116. var d = Math.PI / 180, max = this.MAX_LATITUDE, lat = Math.max(Math.min(max, latlng.lat), -max), sin = Math.sin(lat * d);
  1117. return new Point(
  1118. this.R * latlng.lng * d,
  1119. this.R * Math.log((1 + sin) / (1 - sin)) / 2
  1120. );
  1121. },
  1122. unproject: function(point) {
  1123. var d = 180 / Math.PI;
  1124. return new LatLng(
  1125. (2 * Math.atan(Math.exp(point.y / this.R)) - Math.PI / 2) * d,
  1126. point.x * d / this.R
  1127. );
  1128. },
  1129. bounds: function() {
  1130. var d = earthRadius * Math.PI;
  1131. return new Bounds([-d, -d], [d, d]);
  1132. }()
  1133. };
  1134. function Transformation(a, b, c, d) {
  1135. if (isArray(a)) {
  1136. this._a = a[0];
  1137. this._b = a[1];
  1138. this._c = a[2];
  1139. this._d = a[3];
  1140. return;
  1141. }
  1142. this._a = a;
  1143. this._b = b;
  1144. this._c = c;
  1145. this._d = d;
  1146. }
  1147. Transformation.prototype = {
  1148. // @method transform(point: Point, scale?: Number): Point
  1149. // Returns a transformed point, optionally multiplied by the given scale.
  1150. // Only accepts actual `L.Point` instances, not arrays.
  1151. transform: function(point, scale2) {
  1152. return this._transform(point.clone(), scale2);
  1153. },
  1154. // destructive transform (faster)
  1155. _transform: function(point, scale2) {
  1156. scale2 = scale2 || 1;
  1157. point.x = scale2 * (this._a * point.x + this._b);
  1158. point.y = scale2 * (this._c * point.y + this._d);
  1159. return point;
  1160. },
  1161. // @method untransform(point: Point, scale?: Number): Point
  1162. // Returns the reverse transformation of the given point, optionally divided
  1163. // by the given scale. Only accepts actual `L.Point` instances, not arrays.
  1164. untransform: function(point, scale2) {
  1165. scale2 = scale2 || 1;
  1166. return new Point(
  1167. (point.x / scale2 - this._b) / this._a,
  1168. (point.y / scale2 - this._d) / this._c
  1169. );
  1170. }
  1171. };
  1172. function toTransformation(a, b, c, d) {
  1173. return new Transformation(a, b, c, d);
  1174. }
  1175. var EPSG3857 = extend({}, Earth, {
  1176. code: "EPSG:3857",
  1177. projection: SphericalMercator,
  1178. transformation: function() {
  1179. var scale2 = 0.5 / (Math.PI * SphericalMercator.R);
  1180. return toTransformation(scale2, 0.5, -scale2, 0.5);
  1181. }()
  1182. });
  1183. var EPSG900913 = extend({}, EPSG3857, {
  1184. code: "EPSG:900913"
  1185. });
  1186. function svgCreate(name) {
  1187. return document.createElementNS("http://www.w3.org/2000/svg", name);
  1188. }
  1189. function pointsToPath(rings, closed) {
  1190. var str = "", i, j, len, len2, points, p;
  1191. for (i = 0, len = rings.length; i < len; i++) {
  1192. points = rings[i];
  1193. for (j = 0, len2 = points.length; j < len2; j++) {
  1194. p = points[j];
  1195. str += (j ? "L" : "M") + p.x + " " + p.y;
  1196. }
  1197. str += closed ? Browser.svg ? "z" : "x" : "";
  1198. }
  1199. return str || "M0 0";
  1200. }
  1201. var style = document.documentElement.style;
  1202. var ie = "ActiveXObject" in window;
  1203. var ielt9 = ie && !document.addEventListener;
  1204. var edge = "msLaunchUri" in navigator && !("documentMode" in document);
  1205. var webkit = userAgentContains("webkit");
  1206. var android = userAgentContains("android");
  1207. var android23 = userAgentContains("android 2") || userAgentContains("android 3");
  1208. var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10);
  1209. var androidStock = android && userAgentContains("Google") && webkitVer < 537 && !("AudioNode" in window);
  1210. var opera = !!window.opera;
  1211. var chrome = !edge && userAgentContains("chrome");
  1212. var gecko = userAgentContains("gecko") && !webkit && !opera && !ie;
  1213. var safari = !chrome && userAgentContains("safari");
  1214. var phantom = userAgentContains("phantom");
  1215. var opera12 = "OTransition" in style;
  1216. var win = navigator.platform.indexOf("Win") === 0;
  1217. var ie3d = ie && "transition" in style;
  1218. var webkit3d = "WebKitCSSMatrix" in window && "m11" in new window.WebKitCSSMatrix() && !android23;
  1219. var gecko3d = "MozPerspective" in style;
  1220. var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
  1221. var mobile = typeof orientation !== "undefined" || userAgentContains("mobile");
  1222. var mobileWebkit = mobile && webkit;
  1223. var mobileWebkit3d = mobile && webkit3d;
  1224. var msPointer = !window.PointerEvent && window.MSPointerEvent;
  1225. var pointer = !!(window.PointerEvent || msPointer);
  1226. var touchNative = "ontouchstart" in window || !!window.TouchEvent;
  1227. var touch = !window.L_NO_TOUCH && (touchNative || pointer);
  1228. var mobileOpera = mobile && opera;
  1229. var mobileGecko = mobile && gecko;
  1230. var retina = (window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI) > 1;
  1231. var passiveEvents = function() {
  1232. var supportsPassiveOption = false;
  1233. try {
  1234. var opts = Object.defineProperty({}, "passive", {
  1235. get: function() {
  1236. supportsPassiveOption = true;
  1237. }
  1238. });
  1239. window.addEventListener("testPassiveEventSupport", falseFn, opts);
  1240. window.removeEventListener("testPassiveEventSupport", falseFn, opts);
  1241. } catch (e) {
  1242. }
  1243. return supportsPassiveOption;
  1244. }();
  1245. var canvas$1 = function() {
  1246. return !!document.createElement("canvas").getContext;
  1247. }();
  1248. var svg$1 = !!(document.createElementNS && svgCreate("svg").createSVGRect);
  1249. var inlineSvg = !!svg$1 && function() {
  1250. var div = document.createElement("div");
  1251. div.innerHTML = "<svg/>";
  1252. return (div.firstChild && div.firstChild.namespaceURI) === "http://www.w3.org/2000/svg";
  1253. }();
  1254. var vml = !svg$1 && function() {
  1255. try {
  1256. var div = document.createElement("div");
  1257. div.innerHTML = '<v:shape adj="1"/>';
  1258. var shape = div.firstChild;
  1259. shape.style.behavior = "url(#default#VML)";
  1260. return shape && typeof shape.adj === "object";
  1261. } catch (e) {
  1262. return false;
  1263. }
  1264. }();
  1265. var mac = navigator.platform.indexOf("Mac") === 0;
  1266. var linux = navigator.platform.indexOf("Linux") === 0;
  1267. function userAgentContains(str) {
  1268. return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
  1269. }
  1270. var Browser = {
  1271. ie,
  1272. ielt9,
  1273. edge,
  1274. webkit,
  1275. android,
  1276. android23,
  1277. androidStock,
  1278. opera,
  1279. chrome,
  1280. gecko,
  1281. safari,
  1282. phantom,
  1283. opera12,
  1284. win,
  1285. ie3d,
  1286. webkit3d,
  1287. gecko3d,
  1288. any3d,
  1289. mobile,
  1290. mobileWebkit,
  1291. mobileWebkit3d,
  1292. msPointer,
  1293. pointer,
  1294. touch,
  1295. touchNative,
  1296. mobileOpera,
  1297. mobileGecko,
  1298. retina,
  1299. passiveEvents,
  1300. canvas: canvas$1,
  1301. svg: svg$1,
  1302. vml,
  1303. inlineSvg,
  1304. mac,
  1305. linux
  1306. };
  1307. var POINTER_DOWN = Browser.msPointer ? "MSPointerDown" : "pointerdown";
  1308. var POINTER_MOVE = Browser.msPointer ? "MSPointerMove" : "pointermove";
  1309. var POINTER_UP = Browser.msPointer ? "MSPointerUp" : "pointerup";
  1310. var POINTER_CANCEL = Browser.msPointer ? "MSPointerCancel" : "pointercancel";
  1311. var pEvent = {
  1312. touchstart: POINTER_DOWN,
  1313. touchmove: POINTER_MOVE,
  1314. touchend: POINTER_UP,
  1315. touchcancel: POINTER_CANCEL
  1316. };
  1317. var handle = {
  1318. touchstart: _onPointerStart,
  1319. touchmove: _handlePointer,
  1320. touchend: _handlePointer,
  1321. touchcancel: _handlePointer
  1322. };
  1323. var _pointers = {};
  1324. var _pointerDocListener = false;
  1325. function addPointerListener(obj, type, handler) {
  1326. if (type === "touchstart") {
  1327. _addPointerDocListener();
  1328. }
  1329. if (!handle[type]) {
  1330. console.warn("wrong event specified:", type);
  1331. return falseFn;
  1332. }
  1333. handler = handle[type].bind(this, handler);
  1334. obj.addEventListener(pEvent[type], handler, false);
  1335. return handler;
  1336. }
  1337. function removePointerListener(obj, type, handler) {
  1338. if (!pEvent[type]) {
  1339. console.warn("wrong event specified:", type);
  1340. return;
  1341. }
  1342. obj.removeEventListener(pEvent[type], handler, false);
  1343. }
  1344. function _globalPointerDown(e) {
  1345. _pointers[e.pointerId] = e;
  1346. }
  1347. function _globalPointerMove(e) {
  1348. if (_pointers[e.pointerId]) {
  1349. _pointers[e.pointerId] = e;
  1350. }
  1351. }
  1352. function _globalPointerUp(e) {
  1353. delete _pointers[e.pointerId];
  1354. }
  1355. function _addPointerDocListener() {
  1356. if (!_pointerDocListener) {
  1357. document.addEventListener(POINTER_DOWN, _globalPointerDown, true);
  1358. document.addEventListener(POINTER_MOVE, _globalPointerMove, true);
  1359. document.addEventListener(POINTER_UP, _globalPointerUp, true);
  1360. document.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
  1361. _pointerDocListener = true;
  1362. }
  1363. }
  1364. function _handlePointer(handler, e) {
  1365. if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || "mouse")) {
  1366. return;
  1367. }
  1368. e.touches = [];
  1369. for (var i in _pointers) {
  1370. e.touches.push(_pointers[i]);
  1371. }
  1372. e.changedTouches = [e];
  1373. handler(e);
  1374. }
  1375. function _onPointerStart(handler, e) {
  1376. if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
  1377. preventDefault(e);
  1378. }
  1379. _handlePointer(handler, e);
  1380. }
  1381. function makeDblclick(event) {
  1382. var newEvent = {}, prop, i;
  1383. for (i in event) {
  1384. prop = event[i];
  1385. newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
  1386. }
  1387. event = newEvent;
  1388. newEvent.type = "dblclick";
  1389. newEvent.detail = 2;
  1390. newEvent.isTrusted = false;
  1391. newEvent._simulated = true;
  1392. return newEvent;
  1393. }
  1394. var delay = 200;
  1395. function addDoubleTapListener(obj, handler) {
  1396. obj.addEventListener("dblclick", handler);
  1397. var last = 0, detail;
  1398. function simDblclick(e) {
  1399. if (e.detail !== 1) {
  1400. detail = e.detail;
  1401. return;
  1402. }
  1403. if (e.pointerType === "mouse" || e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents) {
  1404. return;
  1405. }
  1406. var path = getPropagationPath(e);
  1407. if (path.some(function(el) {
  1408. return el instanceof HTMLLabelElement && el.attributes.for;
  1409. }) && !path.some(function(el) {
  1410. return el instanceof HTMLInputElement || el instanceof HTMLSelectElement;
  1411. })) {
  1412. return;
  1413. }
  1414. var now = Date.now();
  1415. if (now - last <= delay) {
  1416. detail++;
  1417. if (detail === 2) {
  1418. handler(makeDblclick(e));
  1419. }
  1420. } else {
  1421. detail = 1;
  1422. }
  1423. last = now;
  1424. }
  1425. obj.addEventListener("click", simDblclick);
  1426. return {
  1427. dblclick: handler,
  1428. simDblclick
  1429. };
  1430. }
  1431. function removeDoubleTapListener(obj, handlers) {
  1432. obj.removeEventListener("dblclick", handlers.dblclick);
  1433. obj.removeEventListener("click", handlers.simDblclick);
  1434. }
  1435. var TRANSFORM = testProp(
  1436. ["transform", "webkitTransform", "OTransform", "MozTransform", "msTransform"]
  1437. );
  1438. var TRANSITION = testProp(
  1439. ["webkitTransition", "transition", "OTransition", "MozTransition", "msTransition"]
  1440. );
  1441. var TRANSITION_END = TRANSITION === "webkitTransition" || TRANSITION === "OTransition" ? TRANSITION + "End" : "transitionend";
  1442. function get(id) {
  1443. return typeof id === "string" ? document.getElementById(id) : id;
  1444. }
  1445. function getStyle(el, style2) {
  1446. var value = el.style[style2] || el.currentStyle && el.currentStyle[style2];
  1447. if ((!value || value === "auto") && document.defaultView) {
  1448. var css = document.defaultView.getComputedStyle(el, null);
  1449. value = css ? css[style2] : null;
  1450. }
  1451. return value === "auto" ? null : value;
  1452. }
  1453. function create$1(tagName, className, container) {
  1454. var el = document.createElement(tagName);
  1455. el.className = className || "";
  1456. if (container) {
  1457. container.appendChild(el);
  1458. }
  1459. return el;
  1460. }
  1461. function remove(el) {
  1462. var parent = el.parentNode;
  1463. if (parent) {
  1464. parent.removeChild(el);
  1465. }
  1466. }
  1467. function empty(el) {
  1468. while (el.firstChild) {
  1469. el.removeChild(el.firstChild);
  1470. }
  1471. }
  1472. function toFront(el) {
  1473. var parent = el.parentNode;
  1474. if (parent && parent.lastChild !== el) {
  1475. parent.appendChild(el);
  1476. }
  1477. }
  1478. function toBack(el) {
  1479. var parent = el.parentNode;
  1480. if (parent && parent.firstChild !== el) {
  1481. parent.insertBefore(el, parent.firstChild);
  1482. }
  1483. }
  1484. function hasClass(el, name) {
  1485. if (el.classList !== void 0) {
  1486. return el.classList.contains(name);
  1487. }
  1488. var className = getClass(el);
  1489. return className.length > 0 && new RegExp("(^|\\s)" + name + "(\\s|$)").test(className);
  1490. }
  1491. function addClass(el, name) {
  1492. if (el.classList !== void 0) {
  1493. var classes = splitWords(name);
  1494. for (var i = 0, len = classes.length; i < len; i++) {
  1495. el.classList.add(classes[i]);
  1496. }
  1497. } else if (!hasClass(el, name)) {
  1498. var className = getClass(el);
  1499. setClass(el, (className ? className + " " : "") + name);
  1500. }
  1501. }
  1502. function removeClass(el, name) {
  1503. if (el.classList !== void 0) {
  1504. el.classList.remove(name);
  1505. } else {
  1506. setClass(el, trim((" " + getClass(el) + " ").replace(" " + name + " ", " ")));
  1507. }
  1508. }
  1509. function setClass(el, name) {
  1510. if (el.className.baseVal === void 0) {
  1511. el.className = name;
  1512. } else {
  1513. el.className.baseVal = name;
  1514. }
  1515. }
  1516. function getClass(el) {
  1517. if (el.correspondingElement) {
  1518. el = el.correspondingElement;
  1519. }
  1520. return el.className.baseVal === void 0 ? el.className : el.className.baseVal;
  1521. }
  1522. function setOpacity(el, value) {
  1523. if ("opacity" in el.style) {
  1524. el.style.opacity = value;
  1525. } else if ("filter" in el.style) {
  1526. _setOpacityIE(el, value);
  1527. }
  1528. }
  1529. function _setOpacityIE(el, value) {
  1530. var filter = false, filterName = "DXImageTransform.Microsoft.Alpha";
  1531. try {
  1532. filter = el.filters.item(filterName);
  1533. } catch (e) {
  1534. if (value === 1) {
  1535. return;
  1536. }
  1537. }
  1538. value = Math.round(value * 100);
  1539. if (filter) {
  1540. filter.Enabled = value !== 100;
  1541. filter.Opacity = value;
  1542. } else {
  1543. el.style.filter += " progid:" + filterName + "(opacity=" + value + ")";
  1544. }
  1545. }
  1546. function testProp(props) {
  1547. var style2 = document.documentElement.style;
  1548. for (var i = 0; i < props.length; i++) {
  1549. if (props[i] in style2) {
  1550. return props[i];
  1551. }
  1552. }
  1553. return false;
  1554. }
  1555. function setTransform(el, offset, scale2) {
  1556. var pos = offset || new Point(0, 0);
  1557. el.style[TRANSFORM] = (Browser.ie3d ? "translate(" + pos.x + "px," + pos.y + "px)" : "translate3d(" + pos.x + "px," + pos.y + "px,0)") + (scale2 ? " scale(" + scale2 + ")" : "");
  1558. }
  1559. function setPosition(el, point) {
  1560. el._leaflet_pos = point;
  1561. if (Browser.any3d) {
  1562. setTransform(el, point);
  1563. } else {
  1564. el.style.left = point.x + "px";
  1565. el.style.top = point.y + "px";
  1566. }
  1567. }
  1568. function getPosition(el) {
  1569. return el._leaflet_pos || new Point(0, 0);
  1570. }
  1571. var disableTextSelection;
  1572. var enableTextSelection;
  1573. var _userSelect;
  1574. if ("onselectstart" in document) {
  1575. disableTextSelection = function() {
  1576. on(window, "selectstart", preventDefault);
  1577. };
  1578. enableTextSelection = function() {
  1579. off(window, "selectstart", preventDefault);
  1580. };
  1581. } else {
  1582. var userSelectProperty = testProp(
  1583. ["userSelect", "WebkitUserSelect", "OUserSelect", "MozUserSelect", "msUserSelect"]
  1584. );
  1585. disableTextSelection = function() {
  1586. if (userSelectProperty) {
  1587. var style2 = document.documentElement.style;
  1588. _userSelect = style2[userSelectProperty];
  1589. style2[userSelectProperty] = "none";
  1590. }
  1591. };
  1592. enableTextSelection = function() {
  1593. if (userSelectProperty) {
  1594. document.documentElement.style[userSelectProperty] = _userSelect;
  1595. _userSelect = void 0;
  1596. }
  1597. };
  1598. }
  1599. function disableImageDrag() {
  1600. on(window, "dragstart", preventDefault);
  1601. }
  1602. function enableImageDrag() {
  1603. off(window, "dragstart", preventDefault);
  1604. }
  1605. var _outlineElement, _outlineStyle;
  1606. function preventOutline(element) {
  1607. while (element.tabIndex === -1) {
  1608. element = element.parentNode;
  1609. }
  1610. if (!element.style) {
  1611. return;
  1612. }
  1613. restoreOutline();
  1614. _outlineElement = element;
  1615. _outlineStyle = element.style.outlineStyle;
  1616. element.style.outlineStyle = "none";
  1617. on(window, "keydown", restoreOutline);
  1618. }
  1619. function restoreOutline() {
  1620. if (!_outlineElement) {
  1621. return;
  1622. }
  1623. _outlineElement.style.outlineStyle = _outlineStyle;
  1624. _outlineElement = void 0;
  1625. _outlineStyle = void 0;
  1626. off(window, "keydown", restoreOutline);
  1627. }
  1628. function getSizedParentNode(element) {
  1629. do {
  1630. element = element.parentNode;
  1631. } while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);
  1632. return element;
  1633. }
  1634. function getScale(element) {
  1635. var rect = element.getBoundingClientRect();
  1636. return {
  1637. x: rect.width / element.offsetWidth || 1,
  1638. y: rect.height / element.offsetHeight || 1,
  1639. boundingClientRect: rect
  1640. };
  1641. }
  1642. var DomUtil = {
  1643. __proto__: null,
  1644. TRANSFORM,
  1645. TRANSITION,
  1646. TRANSITION_END,
  1647. get,
  1648. getStyle,
  1649. create: create$1,
  1650. remove,
  1651. empty,
  1652. toFront,
  1653. toBack,
  1654. hasClass,
  1655. addClass,
  1656. removeClass,
  1657. setClass,
  1658. getClass,
  1659. setOpacity,
  1660. testProp,
  1661. setTransform,
  1662. setPosition,
  1663. getPosition,
  1664. get disableTextSelection() {
  1665. return disableTextSelection;
  1666. },
  1667. get enableTextSelection() {
  1668. return enableTextSelection;
  1669. },
  1670. disableImageDrag,
  1671. enableImageDrag,
  1672. preventOutline,
  1673. restoreOutline,
  1674. getSizedParentNode,
  1675. getScale
  1676. };
  1677. function on(obj, types, fn, context) {
  1678. if (types && typeof types === "object") {
  1679. for (var type in types) {
  1680. addOne(obj, type, types[type], fn);
  1681. }
  1682. } else {
  1683. types = splitWords(types);
  1684. for (var i = 0, len = types.length; i < len; i++) {
  1685. addOne(obj, types[i], fn, context);
  1686. }
  1687. }
  1688. return this;
  1689. }
  1690. var eventsKey = "_leaflet_events";
  1691. function off(obj, types, fn, context) {
  1692. if (arguments.length === 1) {
  1693. batchRemove(obj);
  1694. delete obj[eventsKey];
  1695. } else if (types && typeof types === "object") {
  1696. for (var type in types) {
  1697. removeOne(obj, type, types[type], fn);
  1698. }
  1699. } else {
  1700. types = splitWords(types);
  1701. if (arguments.length === 2) {
  1702. batchRemove(obj, function(type2) {
  1703. return indexOf(types, type2) !== -1;
  1704. });
  1705. } else {
  1706. for (var i = 0, len = types.length; i < len; i++) {
  1707. removeOne(obj, types[i], fn, context);
  1708. }
  1709. }
  1710. }
  1711. return this;
  1712. }
  1713. function batchRemove(obj, filterFn) {
  1714. for (var id in obj[eventsKey]) {
  1715. var type = id.split(/\d/)[0];
  1716. if (!filterFn || filterFn(type)) {
  1717. removeOne(obj, type, null, null, id);
  1718. }
  1719. }
  1720. }
  1721. var mouseSubst = {
  1722. mouseenter: "mouseover",
  1723. mouseleave: "mouseout",
  1724. wheel: !("onwheel" in window) && "mousewheel"
  1725. };
  1726. function addOne(obj, type, fn, context) {
  1727. var id = type + stamp(fn) + (context ? "_" + stamp(context) : "");
  1728. if (obj[eventsKey] && obj[eventsKey][id]) {
  1729. return this;
  1730. }
  1731. var handler = function(e) {
  1732. return fn.call(context || obj, e || window.event);
  1733. };
  1734. var originalHandler = handler;
  1735. if (!Browser.touchNative && Browser.pointer && type.indexOf("touch") === 0) {
  1736. handler = addPointerListener(obj, type, handler);
  1737. } else if (Browser.touch && type === "dblclick") {
  1738. handler = addDoubleTapListener(obj, handler);
  1739. } else if ("addEventListener" in obj) {
  1740. if (type === "touchstart" || type === "touchmove" || type === "wheel" || type === "mousewheel") {
  1741. obj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? { passive: false } : false);
  1742. } else if (type === "mouseenter" || type === "mouseleave") {
  1743. handler = function(e) {
  1744. e = e || window.event;
  1745. if (isExternalTarget(obj, e)) {
  1746. originalHandler(e);
  1747. }
  1748. };
  1749. obj.addEventListener(mouseSubst[type], handler, false);
  1750. } else {
  1751. obj.addEventListener(type, originalHandler, false);
  1752. }
  1753. } else {
  1754. obj.attachEvent("on" + type, handler);
  1755. }
  1756. obj[eventsKey] = obj[eventsKey] || {};
  1757. obj[eventsKey][id] = handler;
  1758. }
  1759. function removeOne(obj, type, fn, context, id) {
  1760. id = id || type + stamp(fn) + (context ? "_" + stamp(context) : "");
  1761. var handler = obj[eventsKey] && obj[eventsKey][id];
  1762. if (!handler) {
  1763. return this;
  1764. }
  1765. if (!Browser.touchNative && Browser.pointer && type.indexOf("touch") === 0) {
  1766. removePointerListener(obj, type, handler);
  1767. } else if (Browser.touch && type === "dblclick") {
  1768. removeDoubleTapListener(obj, handler);
  1769. } else if ("removeEventListener" in obj) {
  1770. obj.removeEventListener(mouseSubst[type] || type, handler, false);
  1771. } else {
  1772. obj.detachEvent("on" + type, handler);
  1773. }
  1774. obj[eventsKey][id] = null;
  1775. }
  1776. function stopPropagation(e) {
  1777. if (e.stopPropagation) {
  1778. e.stopPropagation();
  1779. } else if (e.originalEvent) {
  1780. e.originalEvent._stopped = true;
  1781. } else {
  1782. e.cancelBubble = true;
  1783. }
  1784. return this;
  1785. }
  1786. function disableScrollPropagation(el) {
  1787. addOne(el, "wheel", stopPropagation);
  1788. return this;
  1789. }
  1790. function disableClickPropagation(el) {
  1791. on(el, "mousedown touchstart dblclick contextmenu", stopPropagation);
  1792. el["_leaflet_disable_click"] = true;
  1793. return this;
  1794. }
  1795. function preventDefault(e) {
  1796. if (e.preventDefault) {
  1797. e.preventDefault();
  1798. } else {
  1799. e.returnValue = false;
  1800. }
  1801. return this;
  1802. }
  1803. function stop(e) {
  1804. preventDefault(e);
  1805. stopPropagation(e);
  1806. return this;
  1807. }
  1808. function getPropagationPath(ev) {
  1809. if (ev.composedPath) {
  1810. return ev.composedPath();
  1811. }
  1812. var path = [];
  1813. var el = ev.target;
  1814. while (el) {
  1815. path.push(el);
  1816. el = el.parentNode;
  1817. }
  1818. return path;
  1819. }
  1820. function getMousePosition(e, container) {
  1821. if (!container) {
  1822. return new Point(e.clientX, e.clientY);
  1823. }
  1824. var scale2 = getScale(container), offset = scale2.boundingClientRect;
  1825. return new Point(
  1826. // offset.left/top values are in page scale (like clientX/Y),
  1827. // whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
  1828. (e.clientX - offset.left) / scale2.x - container.clientLeft,
  1829. (e.clientY - offset.top) / scale2.y - container.clientTop
  1830. );
  1831. }
  1832. var wheelPxFactor = Browser.linux && Browser.chrome ? window.devicePixelRatio : Browser.mac ? window.devicePixelRatio * 3 : window.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1;
  1833. function getWheelDelta(e) {
  1834. return Browser.edge ? e.wheelDeltaY / 2 : (
  1835. // Don't trust window-geometry-based delta
  1836. e.deltaY && e.deltaMode === 0 ? -e.deltaY / wheelPxFactor : (
  1837. // Pixels
  1838. e.deltaY && e.deltaMode === 1 ? -e.deltaY * 20 : (
  1839. // Lines
  1840. e.deltaY && e.deltaMode === 2 ? -e.deltaY * 60 : (
  1841. // Pages
  1842. e.deltaX || e.deltaZ ? 0 : (
  1843. // Skip horizontal/depth wheel events
  1844. e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : (
  1845. // Legacy IE pixels
  1846. e.detail && Math.abs(e.detail) < 32765 ? -e.detail * 20 : (
  1847. // Legacy Moz lines
  1848. e.detail ? e.detail / -32765 * 60 : (
  1849. // Legacy Moz pages
  1850. 0
  1851. )
  1852. )
  1853. )
  1854. )
  1855. )
  1856. )
  1857. )
  1858. );
  1859. }
  1860. function isExternalTarget(el, e) {
  1861. var related = e.relatedTarget;
  1862. if (!related) {
  1863. return true;
  1864. }
  1865. try {
  1866. while (related && related !== el) {
  1867. related = related.parentNode;
  1868. }
  1869. } catch (err) {
  1870. return false;
  1871. }
  1872. return related !== el;
  1873. }
  1874. var DomEvent = {
  1875. __proto__: null,
  1876. on,
  1877. off,
  1878. stopPropagation,
  1879. disableScrollPropagation,
  1880. disableClickPropagation,
  1881. preventDefault,
  1882. stop,
  1883. getPropagationPath,
  1884. getMousePosition,
  1885. getWheelDelta,
  1886. isExternalTarget,
  1887. addListener: on,
  1888. removeListener: off
  1889. };
  1890. var PosAnimation = Evented.extend({
  1891. // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
  1892. // Run an animation of a given element to a new position, optionally setting
  1893. // duration in seconds (`0.25` by default) and easing linearity factor (3rd
  1894. // argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1),
  1895. // `0.5` by default).
  1896. run: function(el, newPos, duration, easeLinearity) {
  1897. this.stop();
  1898. this._el = el;
  1899. this._inProgress = true;
  1900. this._duration = duration || 0.25;
  1901. this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
  1902. this._startPos = getPosition(el);
  1903. this._offset = newPos.subtract(this._startPos);
  1904. this._startTime = +/* @__PURE__ */ new Date();
  1905. this.fire("start");
  1906. this._animate();
  1907. },
  1908. // @method stop()
  1909. // Stops the animation (if currently running).
  1910. stop: function() {
  1911. if (!this._inProgress) {
  1912. return;
  1913. }
  1914. this._step(true);
  1915. this._complete();
  1916. },
  1917. _animate: function() {
  1918. this._animId = requestAnimFrame(this._animate, this);
  1919. this._step();
  1920. },
  1921. _step: function(round) {
  1922. var elapsed = +/* @__PURE__ */ new Date() - this._startTime, duration = this._duration * 1e3;
  1923. if (elapsed < duration) {
  1924. this._runFrame(this._easeOut(elapsed / duration), round);
  1925. } else {
  1926. this._runFrame(1);
  1927. this._complete();
  1928. }
  1929. },
  1930. _runFrame: function(progress, round) {
  1931. var pos = this._startPos.add(this._offset.multiplyBy(progress));
  1932. if (round) {
  1933. pos._round();
  1934. }
  1935. setPosition(this._el, pos);
  1936. this.fire("step");
  1937. },
  1938. _complete: function() {
  1939. cancelAnimFrame(this._animId);
  1940. this._inProgress = false;
  1941. this.fire("end");
  1942. },
  1943. _easeOut: function(t) {
  1944. return 1 - Math.pow(1 - t, this._easeOutPower);
  1945. }
  1946. });
  1947. var Map = Evented.extend({
  1948. options: {
  1949. // @section Map State Options
  1950. // @option crs: CRS = L.CRS.EPSG3857
  1951. // The [Coordinate Reference System](#crs) to use. Don't change this if you're not
  1952. // sure what it means.
  1953. crs: EPSG3857,
  1954. // @option center: LatLng = undefined
  1955. // Initial geographic center of the map
  1956. center: void 0,
  1957. // @option zoom: Number = undefined
  1958. // Initial map zoom level
  1959. zoom: void 0,
  1960. // @option minZoom: Number = *
  1961. // Minimum zoom level of the map.
  1962. // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
  1963. // the lowest of their `minZoom` options will be used instead.
  1964. minZoom: void 0,
  1965. // @option maxZoom: Number = *
  1966. // Maximum zoom level of the map.
  1967. // If not specified and at least one `GridLayer` or `TileLayer` is in the map,
  1968. // the highest of their `maxZoom` options will be used instead.
  1969. maxZoom: void 0,
  1970. // @option layers: Layer[] = []
  1971. // Array of layers that will be added to the map initially
  1972. layers: [],
  1973. // @option maxBounds: LatLngBounds = null
  1974. // When this option is set, the map restricts the view to the given
  1975. // geographical bounds, bouncing the user back if the user tries to pan
  1976. // outside the view. To set the restriction dynamically, use
  1977. // [`setMaxBounds`](#map-setmaxbounds) method.
  1978. maxBounds: void 0,
  1979. // @option renderer: Renderer = *
  1980. // The default method for drawing vector layers on the map. `L.SVG`
  1981. // or `L.Canvas` by default depending on browser support.
  1982. renderer: void 0,
  1983. // @section Animation Options
  1984. // @option zoomAnimation: Boolean = true
  1985. // Whether the map zoom animation is enabled. By default it's enabled
  1986. // in all browsers that support CSS3 Transitions except Android.
  1987. zoomAnimation: true,
  1988. // @option zoomAnimationThreshold: Number = 4
  1989. // Won't animate zoom if the zoom difference exceeds this value.
  1990. zoomAnimationThreshold: 4,
  1991. // @option fadeAnimation: Boolean = true
  1992. // Whether the tile fade animation is enabled. By default it's enabled
  1993. // in all browsers that support CSS3 Transitions except Android.
  1994. fadeAnimation: true,
  1995. // @option markerZoomAnimation: Boolean = true
  1996. // Whether markers animate their zoom with the zoom animation, if disabled
  1997. // they will disappear for the length of the animation. By default it's
  1998. // enabled in all browsers that support CSS3 Transitions except Android.
  1999. markerZoomAnimation: true,
  2000. // @option transform3DLimit: Number = 2^23
  2001. // Defines the maximum size of a CSS translation transform. The default
  2002. // value should not be changed unless a web browser positions layers in
  2003. // the wrong place after doing a large `panBy`.
  2004. transform3DLimit: 8388608,
  2005. // Precision limit of a 32-bit float
  2006. // @section Interaction Options
  2007. // @option zoomSnap: Number = 1
  2008. // Forces the map's zoom level to always be a multiple of this, particularly
  2009. // right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
  2010. // By default, the zoom level snaps to the nearest integer; lower values
  2011. // (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
  2012. // means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
  2013. zoomSnap: 1,
  2014. // @option zoomDelta: Number = 1
  2015. // Controls how much the map's zoom level will change after a
  2016. // [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
  2017. // or `-` on the keyboard, or using the [zoom controls](#control-zoom).
  2018. // Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
  2019. zoomDelta: 1,
  2020. // @option trackResize: Boolean = true
  2021. // Whether the map automatically handles browser window resize to update itself.
  2022. trackResize: true
  2023. },
  2024. initialize: function(id, options) {
  2025. options = setOptions(this, options);
  2026. this._handlers = [];
  2027. this._layers = {};
  2028. this._zoomBoundLayers = {};
  2029. this._sizeChanged = true;
  2030. this._initContainer(id);
  2031. this._initLayout();
  2032. this._onResize = bind(this._onResize, this);
  2033. this._initEvents();
  2034. if (options.maxBounds) {
  2035. this.setMaxBounds(options.maxBounds);
  2036. }
  2037. if (options.zoom !== void 0) {
  2038. this._zoom = this._limitZoom(options.zoom);
  2039. }
  2040. if (options.center && options.zoom !== void 0) {
  2041. this.setView(toLatLng(options.center), options.zoom, { reset: true });
  2042. }
  2043. this.callInitHooks();
  2044. this._zoomAnimated = TRANSITION && Browser.any3d && !Browser.mobileOpera && this.options.zoomAnimation;
  2045. if (this._zoomAnimated) {
  2046. this._createAnimProxy();
  2047. on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
  2048. }
  2049. this._addLayers(this.options.layers);
  2050. },
  2051. // @section Methods for modifying map state
  2052. // @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
  2053. // Sets the view of the map (geographical center and zoom) with the given
  2054. // animation options.
  2055. setView: function(center, zoom2, options) {
  2056. zoom2 = zoom2 === void 0 ? this._zoom : this._limitZoom(zoom2);
  2057. center = this._limitCenter(toLatLng(center), zoom2, this.options.maxBounds);
  2058. options = options || {};
  2059. this._stop();
  2060. if (this._loaded && !options.reset && options !== true) {
  2061. if (options.animate !== void 0) {
  2062. options.zoom = extend({ animate: options.animate }, options.zoom);
  2063. options.pan = extend({ animate: options.animate, duration: options.duration }, options.pan);
  2064. }
  2065. var moved = this._zoom !== zoom2 ? this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom2, options.zoom) : this._tryAnimatedPan(center, options.pan);
  2066. if (moved) {
  2067. clearTimeout(this._sizeTimer);
  2068. return this;
  2069. }
  2070. }
  2071. this._resetView(center, zoom2, options.pan && options.pan.noMoveStart);
  2072. return this;
  2073. },
  2074. // @method setZoom(zoom: Number, options?: Zoom/pan options): this
  2075. // Sets the zoom of the map.
  2076. setZoom: function(zoom2, options) {
  2077. if (!this._loaded) {
  2078. this._zoom = zoom2;
  2079. return this;
  2080. }
  2081. return this.setView(this.getCenter(), zoom2, { zoom: options });
  2082. },
  2083. // @method zoomIn(delta?: Number, options?: Zoom options): this
  2084. // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
  2085. zoomIn: function(delta, options) {
  2086. delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
  2087. return this.setZoom(this._zoom + delta, options);
  2088. },
  2089. // @method zoomOut(delta?: Number, options?: Zoom options): this
  2090. // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
  2091. zoomOut: function(delta, options) {
  2092. delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
  2093. return this.setZoom(this._zoom - delta, options);
  2094. },
  2095. // @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
  2096. // Zooms the map while keeping a specified geographical point on the map
  2097. // stationary (e.g. used internally for scroll zoom and double-click zoom).
  2098. // @alternative
  2099. // @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
  2100. // Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
  2101. setZoomAround: function(latlng, zoom2, options) {
  2102. var scale2 = this.getZoomScale(zoom2), viewHalf = this.getSize().divideBy(2), containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng), centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale2), newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
  2103. return this.setView(newCenter, zoom2, { zoom: options });
  2104. },
  2105. _getBoundsCenterZoom: function(bounds, options) {
  2106. options = options || {};
  2107. bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
  2108. var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), zoom2 = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
  2109. zoom2 = typeof options.maxZoom === "number" ? Math.min(options.maxZoom, zoom2) : zoom2;
  2110. if (zoom2 === Infinity) {
  2111. return {
  2112. center: bounds.getCenter(),
  2113. zoom: zoom2
  2114. };
  2115. }
  2116. var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), swPoint = this.project(bounds.getSouthWest(), zoom2), nePoint = this.project(bounds.getNorthEast(), zoom2), center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom2);
  2117. return {
  2118. center,
  2119. zoom: zoom2
  2120. };
  2121. },
  2122. // @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
  2123. // Sets a map view that contains the given geographical bounds with the
  2124. // maximum zoom level possible.
  2125. fitBounds: function(bounds, options) {
  2126. bounds = toLatLngBounds(bounds);
  2127. if (!bounds.isValid()) {
  2128. throw new Error("Bounds are not valid.");
  2129. }
  2130. var target = this._getBoundsCenterZoom(bounds, options);
  2131. return this.setView(target.center, target.zoom, options);
  2132. },
  2133. // @method fitWorld(options?: fitBounds options): this
  2134. // Sets a map view that mostly contains the whole world with the maximum
  2135. // zoom level possible.
  2136. fitWorld: function(options) {
  2137. return this.fitBounds([[-90, -180], [90, 180]], options);
  2138. },
  2139. // @method panTo(latlng: LatLng, options?: Pan options): this
  2140. // Pans the map to a given center.
  2141. panTo: function(center, options) {
  2142. return this.setView(center, this._zoom, { pan: options });
  2143. },
  2144. // @method panBy(offset: Point, options?: Pan options): this
  2145. // Pans the map by a given number of pixels (animated).
  2146. panBy: function(offset, options) {
  2147. offset = toPoint(offset).round();
  2148. options = options || {};
  2149. if (!offset.x && !offset.y) {
  2150. return this.fire("moveend");
  2151. }
  2152. if (options.animate !== true && !this.getSize().contains(offset)) {
  2153. this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
  2154. return this;
  2155. }
  2156. if (!this._panAnim) {
  2157. this._panAnim = new PosAnimation();
  2158. this._panAnim.on({
  2159. "step": this._onPanTransitionStep,
  2160. "end": this._onPanTransitionEnd
  2161. }, this);
  2162. }
  2163. if (!options.noMoveStart) {
  2164. this.fire("movestart");
  2165. }
  2166. if (options.animate !== false) {
  2167. addClass(this._mapPane, "leaflet-pan-anim");
  2168. var newPos = this._getMapPanePos().subtract(offset).round();
  2169. this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
  2170. } else {
  2171. this._rawPanBy(offset);
  2172. this.fire("move").fire("moveend");
  2173. }
  2174. return this;
  2175. },
  2176. // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
  2177. // Sets the view of the map (geographical center and zoom) performing a smooth
  2178. // pan-zoom animation.
  2179. flyTo: function(targetCenter, targetZoom, options) {
  2180. options = options || {};
  2181. if (options.animate === false || !Browser.any3d) {
  2182. return this.setView(targetCenter, targetZoom, options);
  2183. }
  2184. this._stop();
  2185. var from = this.project(this.getCenter()), to = this.project(targetCenter), size = this.getSize(), startZoom = this._zoom;
  2186. targetCenter = toLatLng(targetCenter);
  2187. targetZoom = targetZoom === void 0 ? startZoom : targetZoom;
  2188. var w0 = Math.max(size.x, size.y), w1 = w0 * this.getZoomScale(startZoom, targetZoom), u1 = to.distanceTo(from) || 1, rho = 1.42, rho2 = rho * rho;
  2189. function r(i) {
  2190. var s1 = i ? -1 : 1, s2 = i ? w1 : w0, t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1, b1 = 2 * s2 * rho2 * u1, b = t1 / b1, sq = Math.sqrt(b * b + 1) - b;
  2191. var log = sq < 1e-9 ? -18 : Math.log(sq);
  2192. return log;
  2193. }
  2194. function sinh(n) {
  2195. return (Math.exp(n) - Math.exp(-n)) / 2;
  2196. }
  2197. function cosh(n) {
  2198. return (Math.exp(n) + Math.exp(-n)) / 2;
  2199. }
  2200. function tanh(n) {
  2201. return sinh(n) / cosh(n);
  2202. }
  2203. var r0 = r(0);
  2204. function w(s) {
  2205. return w0 * (cosh(r0) / cosh(r0 + rho * s));
  2206. }
  2207. function u(s) {
  2208. return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2;
  2209. }
  2210. function easeOut(t) {
  2211. return 1 - Math.pow(1 - t, 1.5);
  2212. }
  2213. var start = Date.now(), S = (r(1) - r0) / rho, duration = options.duration ? 1e3 * options.duration : 1e3 * S * 0.8;
  2214. function frame() {
  2215. var t = (Date.now() - start) / duration, s = easeOut(t) * S;
  2216. if (t <= 1) {
  2217. this._flyToFrame = requestAnimFrame(frame, this);
  2218. this._move(
  2219. this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
  2220. this.getScaleZoom(w0 / w(s), startZoom),
  2221. { flyTo: true }
  2222. );
  2223. } else {
  2224. this._move(targetCenter, targetZoom)._moveEnd(true);
  2225. }
  2226. }
  2227. this._moveStart(true, options.noMoveStart);
  2228. frame.call(this);
  2229. return this;
  2230. },
  2231. // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
  2232. // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
  2233. // but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
  2234. flyToBounds: function(bounds, options) {
  2235. var target = this._getBoundsCenterZoom(bounds, options);
  2236. return this.flyTo(target.center, target.zoom, options);
  2237. },
  2238. // @method setMaxBounds(bounds: LatLngBounds): this
  2239. // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
  2240. setMaxBounds: function(bounds) {
  2241. bounds = toLatLngBounds(bounds);
  2242. if (this.listens("moveend", this._panInsideMaxBounds)) {
  2243. this.off("moveend", this._panInsideMaxBounds);
  2244. }
  2245. if (!bounds.isValid()) {
  2246. this.options.maxBounds = null;
  2247. return this;
  2248. }
  2249. this.options.maxBounds = bounds;
  2250. if (this._loaded) {
  2251. this._panInsideMaxBounds();
  2252. }
  2253. return this.on("moveend", this._panInsideMaxBounds);
  2254. },
  2255. // @method setMinZoom(zoom: Number): this
  2256. // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
  2257. setMinZoom: function(zoom2) {
  2258. var oldZoom = this.options.minZoom;
  2259. this.options.minZoom = zoom2;
  2260. if (this._loaded && oldZoom !== zoom2) {
  2261. this.fire("zoomlevelschange");
  2262. if (this.getZoom() < this.options.minZoom) {
  2263. return this.setZoom(zoom2);
  2264. }
  2265. }
  2266. return this;
  2267. },
  2268. // @method setMaxZoom(zoom: Number): this
  2269. // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
  2270. setMaxZoom: function(zoom2) {
  2271. var oldZoom = this.options.maxZoom;
  2272. this.options.maxZoom = zoom2;
  2273. if (this._loaded && oldZoom !== zoom2) {
  2274. this.fire("zoomlevelschange");
  2275. if (this.getZoom() > this.options.maxZoom) {
  2276. return this.setZoom(zoom2);
  2277. }
  2278. }
  2279. return this;
  2280. },
  2281. // @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
  2282. // 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.
  2283. panInsideBounds: function(bounds, options) {
  2284. this._enforcingBounds = true;
  2285. var center = this.getCenter(), newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
  2286. if (!center.equals(newCenter)) {
  2287. this.panTo(newCenter, options);
  2288. }
  2289. this._enforcingBounds = false;
  2290. return this;
  2291. },
  2292. // @method panInside(latlng: LatLng, options?: padding options): this
  2293. // Pans the map the minimum amount to make the `latlng` visible. Use
  2294. // padding options to fit the display to more restricted bounds.
  2295. // If `latlng` is already within the (optionally padded) display bounds,
  2296. // the map will not be panned.
  2297. panInside: function(latlng, options) {
  2298. options = options || {};
  2299. var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), pixelCenter = this.project(this.getCenter()), pixelPoint = this.project(latlng), pixelBounds = this.getPixelBounds(), paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]), paddedSize = paddedBounds.getSize();
  2300. if (!paddedBounds.contains(pixelPoint)) {
  2301. this._enforcingBounds = true;
  2302. var centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
  2303. var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
  2304. pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
  2305. pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
  2306. this.panTo(this.unproject(pixelCenter), options);
  2307. this._enforcingBounds = false;
  2308. }
  2309. return this;
  2310. },
  2311. // @method invalidateSize(options: Zoom/pan options): this
  2312. // Checks if the map container size changed and updates the map if so —
  2313. // call it after you've changed the map size dynamically, also animating
  2314. // pan by default. If `options.pan` is `false`, panning will not occur.
  2315. // If `options.debounceMoveend` is `true`, it will delay `moveend` event so
  2316. // that it doesn't happen often even if the method is called many
  2317. // times in a row.
  2318. // @alternative
  2319. // @method invalidateSize(animate: Boolean): this
  2320. // Checks if the map container size changed and updates the map if so —
  2321. // call it after you've changed the map size dynamically, also animating
  2322. // pan by default.
  2323. invalidateSize: function(options) {
  2324. if (!this._loaded) {
  2325. return this;
  2326. }
  2327. options = extend({
  2328. animate: false,
  2329. pan: true
  2330. }, options === true ? { animate: true } : options);
  2331. var oldSize = this.getSize();
  2332. this._sizeChanged = true;
  2333. this._lastCenter = null;
  2334. var newSize = this.getSize(), oldCenter = oldSize.divideBy(2).round(), newCenter = newSize.divideBy(2).round(), offset = oldCenter.subtract(newCenter);
  2335. if (!offset.x && !offset.y) {
  2336. return this;
  2337. }
  2338. if (options.animate && options.pan) {
  2339. this.panBy(offset);
  2340. } else {
  2341. if (options.pan) {
  2342. this._rawPanBy(offset);
  2343. }
  2344. this.fire("move");
  2345. if (options.debounceMoveend) {
  2346. clearTimeout(this._sizeTimer);
  2347. this._sizeTimer = setTimeout(bind(this.fire, this, "moveend"), 200);
  2348. } else {
  2349. this.fire("moveend");
  2350. }
  2351. }
  2352. return this.fire("resize", {
  2353. oldSize,
  2354. newSize
  2355. });
  2356. },
  2357. // @section Methods for modifying map state
  2358. // @method stop(): this
  2359. // Stops the currently running `panTo` or `flyTo` animation, if any.
  2360. stop: function() {
  2361. this.setZoom(this._limitZoom(this._zoom));
  2362. if (!this.options.zoomSnap) {
  2363. this.fire("viewreset");
  2364. }
  2365. return this._stop();
  2366. },
  2367. // @section Geolocation methods
  2368. // @method locate(options?: Locate options): this
  2369. // Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
  2370. // event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
  2371. // and optionally sets the map view to the user's location with respect to
  2372. // detection accuracy (or to the world view if geolocation failed).
  2373. // Note that, if your page doesn't use HTTPS, this method will fail in
  2374. // modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
  2375. // See `Locate options` for more details.
  2376. locate: function(options) {
  2377. options = this._locateOptions = extend({
  2378. timeout: 1e4,
  2379. watch: false
  2380. // setView: false
  2381. // maxZoom: <Number>
  2382. // maximumAge: 0
  2383. // enableHighAccuracy: false
  2384. }, options);
  2385. if (!("geolocation" in navigator)) {
  2386. this._handleGeolocationError({
  2387. code: 0,
  2388. message: "Geolocation not supported."
  2389. });
  2390. return this;
  2391. }
  2392. var onResponse = bind(this._handleGeolocationResponse, this), onError = bind(this._handleGeolocationError, this);
  2393. if (options.watch) {
  2394. this._locationWatchId = navigator.geolocation.watchPosition(onResponse, onError, options);
  2395. } else {
  2396. navigator.geolocation.getCurrentPosition(onResponse, onError, options);
  2397. }
  2398. return this;
  2399. },
  2400. // @method stopLocate(): this
  2401. // Stops watching location previously initiated by `map.locate({watch: true})`
  2402. // and aborts resetting the map view if map.locate was called with
  2403. // `{setView: true}`.
  2404. stopLocate: function() {
  2405. if (navigator.geolocation && navigator.geolocation.clearWatch) {
  2406. navigator.geolocation.clearWatch(this._locationWatchId);
  2407. }
  2408. if (this._locateOptions) {
  2409. this._locateOptions.setView = false;
  2410. }
  2411. return this;
  2412. },
  2413. _handleGeolocationError: function(error) {
  2414. if (!this._container._leaflet_id) {
  2415. return;
  2416. }
  2417. var c = error.code, message = error.message || (c === 1 ? "permission denied" : c === 2 ? "position unavailable" : "timeout");
  2418. if (this._locateOptions.setView && !this._loaded) {
  2419. this.fitWorld();
  2420. }
  2421. this.fire("locationerror", {
  2422. code: c,
  2423. message: "Geolocation error: " + message + "."
  2424. });
  2425. },
  2426. _handleGeolocationResponse: function(pos) {
  2427. if (!this._container._leaflet_id) {
  2428. return;
  2429. }
  2430. var lat = pos.coords.latitude, lng = pos.coords.longitude, latlng = new LatLng(lat, lng), bounds = latlng.toBounds(pos.coords.accuracy * 2), options = this._locateOptions;
  2431. if (options.setView) {
  2432. var zoom2 = this.getBoundsZoom(bounds);
  2433. this.setView(latlng, options.maxZoom ? Math.min(zoom2, options.maxZoom) : zoom2);
  2434. }
  2435. var data = {
  2436. latlng,
  2437. bounds,
  2438. timestamp: pos.timestamp
  2439. };
  2440. for (var i in pos.coords) {
  2441. if (typeof pos.coords[i] === "number") {
  2442. data[i] = pos.coords[i];
  2443. }
  2444. }
  2445. this.fire("locationfound", data);
  2446. },
  2447. // TODO Appropriate docs section?
  2448. // @section Other Methods
  2449. // @method addHandler(name: String, HandlerClass: Function): this
  2450. // Adds a new `Handler` to the map, given its name and constructor function.
  2451. addHandler: function(name, HandlerClass) {
  2452. if (!HandlerClass) {
  2453. return this;
  2454. }
  2455. var handler = this[name] = new HandlerClass(this);
  2456. this._handlers.push(handler);
  2457. if (this.options[name]) {
  2458. handler.enable();
  2459. }
  2460. return this;
  2461. },
  2462. // @method remove(): this
  2463. // Destroys the map and clears all related event listeners.
  2464. remove: function() {
  2465. this._initEvents(true);
  2466. if (this.options.maxBounds) {
  2467. this.off("moveend", this._panInsideMaxBounds);
  2468. }
  2469. if (this._containerId !== this._container._leaflet_id) {
  2470. throw new Error("Map container is being reused by another instance");
  2471. }
  2472. try {
  2473. delete this._container._leaflet_id;
  2474. delete this._containerId;
  2475. } catch (e) {
  2476. this._container._leaflet_id = void 0;
  2477. this._containerId = void 0;
  2478. }
  2479. if (this._locationWatchId !== void 0) {
  2480. this.stopLocate();
  2481. }
  2482. this._stop();
  2483. remove(this._mapPane);
  2484. if (this._clearControlPos) {
  2485. this._clearControlPos();
  2486. }
  2487. if (this._resizeRequest) {
  2488. cancelAnimFrame(this._resizeRequest);
  2489. this._resizeRequest = null;
  2490. }
  2491. this._clearHandlers();
  2492. if (this._loaded) {
  2493. this.fire("unload");
  2494. }
  2495. var i;
  2496. for (i in this._layers) {
  2497. this._layers[i].remove();
  2498. }
  2499. for (i in this._panes) {
  2500. remove(this._panes[i]);
  2501. }
  2502. this._layers = [];
  2503. this._panes = [];
  2504. delete this._mapPane;
  2505. delete this._renderer;
  2506. return this;
  2507. },
  2508. // @section Other Methods
  2509. // @method createPane(name: String, container?: HTMLElement): HTMLElement
  2510. // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
  2511. // then returns it. The pane is created as a child of `container`, or
  2512. // as a child of the main map pane if not set.
  2513. createPane: function(name, container) {
  2514. var className = "leaflet-pane" + (name ? " leaflet-" + name.replace("Pane", "") + "-pane" : ""), pane = create$1("div", className, container || this._mapPane);
  2515. if (name) {
  2516. this._panes[name] = pane;
  2517. }
  2518. return pane;
  2519. },
  2520. // @section Methods for Getting Map State
  2521. // @method getCenter(): LatLng
  2522. // Returns the geographical center of the map view
  2523. getCenter: function() {
  2524. this._checkIfLoaded();
  2525. if (this._lastCenter && !this._moved()) {
  2526. return this._lastCenter.clone();
  2527. }
  2528. return this.layerPointToLatLng(this._getCenterLayerPoint());
  2529. },
  2530. // @method getZoom(): Number
  2531. // Returns the current zoom level of the map view
  2532. getZoom: function() {
  2533. return this._zoom;
  2534. },
  2535. // @method getBounds(): LatLngBounds
  2536. // Returns the geographical bounds visible in the current map view
  2537. getBounds: function() {
  2538. var bounds = this.getPixelBounds(), sw = this.unproject(bounds.getBottomLeft()), ne = this.unproject(bounds.getTopRight());
  2539. return new LatLngBounds(sw, ne);
  2540. },
  2541. // @method getMinZoom(): Number
  2542. // 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.
  2543. getMinZoom: function() {
  2544. return this.options.minZoom === void 0 ? this._layersMinZoom || 0 : this.options.minZoom;
  2545. },
  2546. // @method getMaxZoom(): Number
  2547. // Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
  2548. getMaxZoom: function() {
  2549. return this.options.maxZoom === void 0 ? this._layersMaxZoom === void 0 ? Infinity : this._layersMaxZoom : this.options.maxZoom;
  2550. },
  2551. // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number
  2552. // Returns the maximum zoom level on which the given bounds fit to the map
  2553. // view in its entirety. If `inside` (optional) is set to `true`, the method
  2554. // instead returns the minimum zoom level on which the map view fits into
  2555. // the given bounds in its entirety.
  2556. getBoundsZoom: function(bounds, inside, padding) {
  2557. bounds = toLatLngBounds(bounds);
  2558. padding = toPoint(padding || [0, 0]);
  2559. var zoom2 = this.getZoom() || 0, min = this.getMinZoom(), max = this.getMaxZoom(), nw = bounds.getNorthWest(), se = bounds.getSouthEast(), size = this.getSize().subtract(padding), boundsSize = toBounds(this.project(se, zoom2), this.project(nw, zoom2)).getSize(), snap = Browser.any3d ? this.options.zoomSnap : 1, scalex = size.x / boundsSize.x, scaley = size.y / boundsSize.y, scale2 = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
  2560. zoom2 = this.getScaleZoom(scale2, zoom2);
  2561. if (snap) {
  2562. zoom2 = Math.round(zoom2 / (snap / 100)) * (snap / 100);
  2563. zoom2 = inside ? Math.ceil(zoom2 / snap) * snap : Math.floor(zoom2 / snap) * snap;
  2564. }
  2565. return Math.max(min, Math.min(max, zoom2));
  2566. },
  2567. // @method getSize(): Point
  2568. // Returns the current size of the map container (in pixels).
  2569. getSize: function() {
  2570. if (!this._size || this._sizeChanged) {
  2571. this._size = new Point(
  2572. this._container.clientWidth || 0,
  2573. this._container.clientHeight || 0
  2574. );
  2575. this._sizeChanged = false;
  2576. }
  2577. return this._size.clone();
  2578. },
  2579. // @method getPixelBounds(): Bounds
  2580. // Returns the bounds of the current map view in projected pixel
  2581. // coordinates (sometimes useful in layer and overlay implementations).
  2582. getPixelBounds: function(center, zoom2) {
  2583. var topLeftPoint = this._getTopLeftPoint(center, zoom2);
  2584. return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
  2585. },
  2586. // TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
  2587. // the map pane? "left point of the map layer" can be confusing, specially
  2588. // since there can be negative offsets.
  2589. // @method getPixelOrigin(): Point
  2590. // Returns the projected pixel coordinates of the top left point of
  2591. // the map layer (useful in custom layer and overlay implementations).
  2592. getPixelOrigin: function() {
  2593. this._checkIfLoaded();
  2594. return this._pixelOrigin;
  2595. },
  2596. // @method getPixelWorldBounds(zoom?: Number): Bounds
  2597. // Returns the world's bounds in pixel coordinates for zoom level `zoom`.
  2598. // If `zoom` is omitted, the map's current zoom level is used.
  2599. getPixelWorldBounds: function(zoom2) {
  2600. return this.options.crs.getProjectedBounds(zoom2 === void 0 ? this.getZoom() : zoom2);
  2601. },
  2602. // @section Other Methods
  2603. // @method getPane(pane: String|HTMLElement): HTMLElement
  2604. // Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
  2605. getPane: function(pane) {
  2606. return typeof pane === "string" ? this._panes[pane] : pane;
  2607. },
  2608. // @method getPanes(): Object
  2609. // Returns a plain object containing the names of all [panes](#map-pane) as keys and
  2610. // the panes as values.
  2611. getPanes: function() {
  2612. return this._panes;
  2613. },
  2614. // @method getContainer: HTMLElement
  2615. // Returns the HTML element that contains the map.
  2616. getContainer: function() {
  2617. return this._container;
  2618. },
  2619. // @section Conversion Methods
  2620. // @method getZoomScale(toZoom: Number, fromZoom: Number): Number
  2621. // Returns the scale factor to be applied to a map transition from zoom level
  2622. // `fromZoom` to `toZoom`. Used internally to help with zoom animations.
  2623. getZoomScale: function(toZoom, fromZoom) {
  2624. var crs = this.options.crs;
  2625. fromZoom = fromZoom === void 0 ? this._zoom : fromZoom;
  2626. return crs.scale(toZoom) / crs.scale(fromZoom);
  2627. },
  2628. // @method getScaleZoom(scale: Number, fromZoom: Number): Number
  2629. // Returns the zoom level that the map would end up at, if it is at `fromZoom`
  2630. // level and everything is scaled by a factor of `scale`. Inverse of
  2631. // [`getZoomScale`](#map-getZoomScale).
  2632. getScaleZoom: function(scale2, fromZoom) {
  2633. var crs = this.options.crs;
  2634. fromZoom = fromZoom === void 0 ? this._zoom : fromZoom;
  2635. var zoom2 = crs.zoom(scale2 * crs.scale(fromZoom));
  2636. return isNaN(zoom2) ? Infinity : zoom2;
  2637. },
  2638. // @method project(latlng: LatLng, zoom: Number): Point
  2639. // Projects a geographical coordinate `LatLng` according to the projection
  2640. // of the map's CRS, then scales it according to `zoom` and the CRS's
  2641. // `Transformation`. The result is pixel coordinate relative to
  2642. // the CRS origin.
  2643. project: function(latlng, zoom2) {
  2644. zoom2 = zoom2 === void 0 ? this._zoom : zoom2;
  2645. return this.options.crs.latLngToPoint(toLatLng(latlng), zoom2);
  2646. },
  2647. // @method unproject(point: Point, zoom: Number): LatLng
  2648. // Inverse of [`project`](#map-project).
  2649. unproject: function(point, zoom2) {
  2650. zoom2 = zoom2 === void 0 ? this._zoom : zoom2;
  2651. return this.options.crs.pointToLatLng(toPoint(point), zoom2);
  2652. },
  2653. // @method layerPointToLatLng(point: Point): LatLng
  2654. // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
  2655. // returns the corresponding geographical coordinate (for the current zoom level).
  2656. layerPointToLatLng: function(point) {
  2657. var projectedPoint = toPoint(point).add(this.getPixelOrigin());
  2658. return this.unproject(projectedPoint);
  2659. },
  2660. // @method latLngToLayerPoint(latlng: LatLng): Point
  2661. // Given a geographical coordinate, returns the corresponding pixel coordinate
  2662. // relative to the [origin pixel](#map-getpixelorigin).
  2663. latLngToLayerPoint: function(latlng) {
  2664. var projectedPoint = this.project(toLatLng(latlng))._round();
  2665. return projectedPoint._subtract(this.getPixelOrigin());
  2666. },
  2667. // @method wrapLatLng(latlng: LatLng): LatLng
  2668. // Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
  2669. // map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
  2670. // CRS's bounds.
  2671. // By default this means longitude is wrapped around the dateline so its
  2672. // value is between -180 and +180 degrees.
  2673. wrapLatLng: function(latlng) {
  2674. return this.options.crs.wrapLatLng(toLatLng(latlng));
  2675. },
  2676. // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
  2677. // Returns a `LatLngBounds` with the same size as the given one, ensuring that
  2678. // its center is within the CRS's bounds.
  2679. // By default this means the center longitude is wrapped around the dateline so its
  2680. // value is between -180 and +180 degrees, and the majority of the bounds
  2681. // overlaps the CRS's bounds.
  2682. wrapLatLngBounds: function(latlng) {
  2683. return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
  2684. },
  2685. // @method distance(latlng1: LatLng, latlng2: LatLng): Number
  2686. // Returns the distance between two geographical coordinates according to
  2687. // the map's CRS. By default this measures distance in meters.
  2688. distance: function(latlng1, latlng2) {
  2689. return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
  2690. },
  2691. // @method containerPointToLayerPoint(point: Point): Point
  2692. // Given a pixel coordinate relative to the map container, returns the corresponding
  2693. // pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
  2694. containerPointToLayerPoint: function(point) {
  2695. return toPoint(point).subtract(this._getMapPanePos());
  2696. },
  2697. // @method layerPointToContainerPoint(point: Point): Point
  2698. // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
  2699. // returns the corresponding pixel coordinate relative to the map container.
  2700. layerPointToContainerPoint: function(point) {
  2701. return toPoint(point).add(this._getMapPanePos());
  2702. },
  2703. // @method containerPointToLatLng(point: Point): LatLng
  2704. // Given a pixel coordinate relative to the map container, returns
  2705. // the corresponding geographical coordinate (for the current zoom level).
  2706. containerPointToLatLng: function(point) {
  2707. var layerPoint = this.containerPointToLayerPoint(toPoint(point));
  2708. return this.layerPointToLatLng(layerPoint);
  2709. },
  2710. // @method latLngToContainerPoint(latlng: LatLng): Point
  2711. // Given a geographical coordinate, returns the corresponding pixel coordinate
  2712. // relative to the map container.
  2713. latLngToContainerPoint: function(latlng) {
  2714. return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
  2715. },
  2716. // @method mouseEventToContainerPoint(ev: MouseEvent): Point
  2717. // Given a MouseEvent object, returns the pixel coordinate relative to the
  2718. // map container where the event took place.
  2719. mouseEventToContainerPoint: function(e) {
  2720. return getMousePosition(e, this._container);
  2721. },
  2722. // @method mouseEventToLayerPoint(ev: MouseEvent): Point
  2723. // Given a MouseEvent object, returns the pixel coordinate relative to
  2724. // the [origin pixel](#map-getpixelorigin) where the event took place.
  2725. mouseEventToLayerPoint: function(e) {
  2726. return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
  2727. },
  2728. // @method mouseEventToLatLng(ev: MouseEvent): LatLng
  2729. // Given a MouseEvent object, returns geographical coordinate where the
  2730. // event took place.
  2731. mouseEventToLatLng: function(e) {
  2732. return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
  2733. },
  2734. // map initialization methods
  2735. _initContainer: function(id) {
  2736. var container = this._container = get(id);
  2737. if (!container) {
  2738. throw new Error("Map container not found.");
  2739. } else if (container._leaflet_id) {
  2740. throw new Error("Map container is already initialized.");
  2741. }
  2742. on(container, "scroll", this._onScroll, this);
  2743. this._containerId = stamp(container);
  2744. },
  2745. _initLayout: function() {
  2746. var container = this._container;
  2747. this._fadeAnimated = this.options.fadeAnimation && Browser.any3d;
  2748. addClass(container, "leaflet-container" + (Browser.touch ? " leaflet-touch" : "") + (Browser.retina ? " leaflet-retina" : "") + (Browser.ielt9 ? " leaflet-oldie" : "") + (Browser.safari ? " leaflet-safari" : "") + (this._fadeAnimated ? " leaflet-fade-anim" : ""));
  2749. var position = getStyle(container, "position");
  2750. if (position !== "absolute" && position !== "relative" && position !== "fixed" && position !== "sticky") {
  2751. container.style.position = "relative";
  2752. }
  2753. this._initPanes();
  2754. if (this._initControlPos) {
  2755. this._initControlPos();
  2756. }
  2757. },
  2758. _initPanes: function() {
  2759. var panes = this._panes = {};
  2760. this._paneRenderers = {};
  2761. this._mapPane = this.createPane("mapPane", this._container);
  2762. setPosition(this._mapPane, new Point(0, 0));
  2763. this.createPane("tilePane");
  2764. this.createPane("overlayPane");
  2765. this.createPane("shadowPane");
  2766. this.createPane("markerPane");
  2767. this.createPane("tooltipPane");
  2768. this.createPane("popupPane");
  2769. if (!this.options.markerZoomAnimation) {
  2770. addClass(panes.markerPane, "leaflet-zoom-hide");
  2771. addClass(panes.shadowPane, "leaflet-zoom-hide");
  2772. }
  2773. },
  2774. // private methods that modify map state
  2775. // @section Map state change events
  2776. _resetView: function(center, zoom2, noMoveStart) {
  2777. setPosition(this._mapPane, new Point(0, 0));
  2778. var loading = !this._loaded;
  2779. this._loaded = true;
  2780. zoom2 = this._limitZoom(zoom2);
  2781. this.fire("viewprereset");
  2782. var zoomChanged = this._zoom !== zoom2;
  2783. this._moveStart(zoomChanged, noMoveStart)._move(center, zoom2)._moveEnd(zoomChanged);
  2784. this.fire("viewreset");
  2785. if (loading) {
  2786. this.fire("load");
  2787. }
  2788. },
  2789. _moveStart: function(zoomChanged, noMoveStart) {
  2790. if (zoomChanged) {
  2791. this.fire("zoomstart");
  2792. }
  2793. if (!noMoveStart) {
  2794. this.fire("movestart");
  2795. }
  2796. return this;
  2797. },
  2798. _move: function(center, zoom2, data, supressEvent) {
  2799. if (zoom2 === void 0) {
  2800. zoom2 = this._zoom;
  2801. }
  2802. var zoomChanged = this._zoom !== zoom2;
  2803. this._zoom = zoom2;
  2804. this._lastCenter = center;
  2805. this._pixelOrigin = this._getNewPixelOrigin(center);
  2806. if (!supressEvent) {
  2807. if (zoomChanged || data && data.pinch) {
  2808. this.fire("zoom", data);
  2809. }
  2810. this.fire("move", data);
  2811. } else if (data && data.pinch) {
  2812. this.fire("zoom", data);
  2813. }
  2814. return this;
  2815. },
  2816. _moveEnd: function(zoomChanged) {
  2817. if (zoomChanged) {
  2818. this.fire("zoomend");
  2819. }
  2820. return this.fire("moveend");
  2821. },
  2822. _stop: function() {
  2823. cancelAnimFrame(this._flyToFrame);
  2824. if (this._panAnim) {
  2825. this._panAnim.stop();
  2826. }
  2827. return this;
  2828. },
  2829. _rawPanBy: function(offset) {
  2830. setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
  2831. },
  2832. _getZoomSpan: function() {
  2833. return this.getMaxZoom() - this.getMinZoom();
  2834. },
  2835. _panInsideMaxBounds: function() {
  2836. if (!this._enforcingBounds) {
  2837. this.panInsideBounds(this.options.maxBounds);
  2838. }
  2839. },
  2840. _checkIfLoaded: function() {
  2841. if (!this._loaded) {
  2842. throw new Error("Set map center and zoom first.");
  2843. }
  2844. },
  2845. // DOM event handling
  2846. // @section Interaction events
  2847. _initEvents: function(remove2) {
  2848. this._targets = {};
  2849. this._targets[stamp(this._container)] = this;
  2850. var onOff = remove2 ? off : on;
  2851. onOff(this._container, "click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup", this._handleDOMEvent, this);
  2852. if (this.options.trackResize) {
  2853. onOff(window, "resize", this._onResize, this);
  2854. }
  2855. if (Browser.any3d && this.options.transform3DLimit) {
  2856. (remove2 ? this.off : this.on).call(this, "moveend", this._onMoveEnd);
  2857. }
  2858. },
  2859. _onResize: function() {
  2860. cancelAnimFrame(this._resizeRequest);
  2861. this._resizeRequest = requestAnimFrame(
  2862. function() {
  2863. this.invalidateSize({ debounceMoveend: true });
  2864. },
  2865. this
  2866. );
  2867. },
  2868. _onScroll: function() {
  2869. this._container.scrollTop = 0;
  2870. this._container.scrollLeft = 0;
  2871. },
  2872. _onMoveEnd: function() {
  2873. var pos = this._getMapPanePos();
  2874. if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
  2875. this._resetView(this.getCenter(), this.getZoom());
  2876. }
  2877. },
  2878. _findEventTargets: function(e, type) {
  2879. var targets = [], target, isHover = type === "mouseout" || type === "mouseover", src = e.target || e.srcElement, dragging = false;
  2880. while (src) {
  2881. target = this._targets[stamp(src)];
  2882. if (target && (type === "click" || type === "preclick") && this._draggableMoved(target)) {
  2883. dragging = true;
  2884. break;
  2885. }
  2886. if (target && target.listens(type, true)) {
  2887. if (isHover && !isExternalTarget(src, e)) {
  2888. break;
  2889. }
  2890. targets.push(target);
  2891. if (isHover) {
  2892. break;
  2893. }
  2894. }
  2895. if (src === this._container) {
  2896. break;
  2897. }
  2898. src = src.parentNode;
  2899. }
  2900. if (!targets.length && !dragging && !isHover && this.listens(type, true)) {
  2901. targets = [this];
  2902. }
  2903. return targets;
  2904. },
  2905. _isClickDisabled: function(el) {
  2906. while (el && el !== this._container) {
  2907. if (el["_leaflet_disable_click"]) {
  2908. return true;
  2909. }
  2910. el = el.parentNode;
  2911. }
  2912. },
  2913. _handleDOMEvent: function(e) {
  2914. var el = e.target || e.srcElement;
  2915. if (!this._loaded || el["_leaflet_disable_events"] || e.type === "click" && this._isClickDisabled(el)) {
  2916. return;
  2917. }
  2918. var type = e.type;
  2919. if (type === "mousedown") {
  2920. preventOutline(el);
  2921. }
  2922. this._fireDOMEvent(e, type);
  2923. },
  2924. _mouseEvents: ["click", "dblclick", "mouseover", "mouseout", "contextmenu"],
  2925. _fireDOMEvent: function(e, type, canvasTargets) {
  2926. if (e.type === "click") {
  2927. var synth = extend({}, e);
  2928. synth.type = "preclick";
  2929. this._fireDOMEvent(synth, synth.type, canvasTargets);
  2930. }
  2931. var targets = this._findEventTargets(e, type);
  2932. if (canvasTargets) {
  2933. var filtered = [];
  2934. for (var i = 0; i < canvasTargets.length; i++) {
  2935. if (canvasTargets[i].listens(type, true)) {
  2936. filtered.push(canvasTargets[i]);
  2937. }
  2938. }
  2939. targets = filtered.concat(targets);
  2940. }
  2941. if (!targets.length) {
  2942. return;
  2943. }
  2944. if (type === "contextmenu") {
  2945. preventDefault(e);
  2946. }
  2947. var target = targets[0];
  2948. var data = {
  2949. originalEvent: e
  2950. };
  2951. if (e.type !== "keypress" && e.type !== "keydown" && e.type !== "keyup") {
  2952. var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
  2953. data.containerPoint = isMarker ? this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
  2954. data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
  2955. data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
  2956. }
  2957. for (i = 0; i < targets.length; i++) {
  2958. targets[i].fire(type, data, true);
  2959. if (data.originalEvent._stopped || targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1) {
  2960. return;
  2961. }
  2962. }
  2963. },
  2964. _draggableMoved: function(obj) {
  2965. obj = obj.dragging && obj.dragging.enabled() ? obj : this;
  2966. return obj.dragging && obj.dragging.moved() || this.boxZoom && this.boxZoom.moved();
  2967. },
  2968. _clearHandlers: function() {
  2969. for (var i = 0, len = this._handlers.length; i < len; i++) {
  2970. this._handlers[i].disable();
  2971. }
  2972. },
  2973. // @section Other Methods
  2974. // @method whenReady(fn: Function, context?: Object): this
  2975. // Runs the given function `fn` when the map gets initialized with
  2976. // a view (center and zoom) and at least one layer, or immediately
  2977. // if it's already initialized, optionally passing a function context.
  2978. whenReady: function(callback, context) {
  2979. if (this._loaded) {
  2980. callback.call(context || this, { target: this });
  2981. } else {
  2982. this.on("load", callback, context);
  2983. }
  2984. return this;
  2985. },
  2986. // private methods for getting map state
  2987. _getMapPanePos: function() {
  2988. return getPosition(this._mapPane) || new Point(0, 0);
  2989. },
  2990. _moved: function() {
  2991. var pos = this._getMapPanePos();
  2992. return pos && !pos.equals([0, 0]);
  2993. },
  2994. _getTopLeftPoint: function(center, zoom2) {
  2995. var pixelOrigin = center && zoom2 !== void 0 ? this._getNewPixelOrigin(center, zoom2) : this.getPixelOrigin();
  2996. return pixelOrigin.subtract(this._getMapPanePos());
  2997. },
  2998. _getNewPixelOrigin: function(center, zoom2) {
  2999. var viewHalf = this.getSize()._divideBy(2);
  3000. return this.project(center, zoom2)._subtract(viewHalf)._add(this._getMapPanePos())._round();
  3001. },
  3002. _latLngToNewLayerPoint: function(latlng, zoom2, center) {
  3003. var topLeft = this._getNewPixelOrigin(center, zoom2);
  3004. return this.project(latlng, zoom2)._subtract(topLeft);
  3005. },
  3006. _latLngBoundsToNewLayerBounds: function(latLngBounds, zoom2, center) {
  3007. var topLeft = this._getNewPixelOrigin(center, zoom2);
  3008. return toBounds([
  3009. this.project(latLngBounds.getSouthWest(), zoom2)._subtract(topLeft),
  3010. this.project(latLngBounds.getNorthWest(), zoom2)._subtract(topLeft),
  3011. this.project(latLngBounds.getSouthEast(), zoom2)._subtract(topLeft),
  3012. this.project(latLngBounds.getNorthEast(), zoom2)._subtract(topLeft)
  3013. ]);
  3014. },
  3015. // layer point of the current center
  3016. _getCenterLayerPoint: function() {
  3017. return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
  3018. },
  3019. // offset of the specified place to the current center in pixels
  3020. _getCenterOffset: function(latlng) {
  3021. return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
  3022. },
  3023. // adjust center for view to get inside bounds
  3024. _limitCenter: function(center, zoom2, bounds) {
  3025. if (!bounds) {
  3026. return center;
  3027. }
  3028. var centerPoint = this.project(center, zoom2), viewHalf = this.getSize().divideBy(2), viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)), offset = this._getBoundsOffset(viewBounds, bounds, zoom2);
  3029. if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
  3030. return center;
  3031. }
  3032. return this.unproject(centerPoint.add(offset), zoom2);
  3033. },
  3034. // adjust offset for view to get inside bounds
  3035. _limitOffset: function(offset, bounds) {
  3036. if (!bounds) {
  3037. return offset;
  3038. }
  3039. var viewBounds = this.getPixelBounds(), newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
  3040. return offset.add(this._getBoundsOffset(newBounds, bounds));
  3041. },
  3042. // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
  3043. _getBoundsOffset: function(pxBounds, maxBounds, zoom2) {
  3044. var projectedMaxBounds = toBounds(
  3045. this.project(maxBounds.getNorthEast(), zoom2),
  3046. this.project(maxBounds.getSouthWest(), zoom2)
  3047. ), minOffset = projectedMaxBounds.min.subtract(pxBounds.min), maxOffset = projectedMaxBounds.max.subtract(pxBounds.max), dx = this._rebound(minOffset.x, -maxOffset.x), dy = this._rebound(minOffset.y, -maxOffset.y);
  3048. return new Point(dx, dy);
  3049. },
  3050. _rebound: function(left, right) {
  3051. return left + right > 0 ? Math.round(left - right) / 2 : Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
  3052. },
  3053. _limitZoom: function(zoom2) {
  3054. var min = this.getMinZoom(), max = this.getMaxZoom(), snap = Browser.any3d ? this.options.zoomSnap : 1;
  3055. if (snap) {
  3056. zoom2 = Math.round(zoom2 / snap) * snap;
  3057. }
  3058. return Math.max(min, Math.min(max, zoom2));
  3059. },
  3060. _onPanTransitionStep: function() {
  3061. this.fire("move");
  3062. },
  3063. _onPanTransitionEnd: function() {
  3064. removeClass(this._mapPane, "leaflet-pan-anim");
  3065. this.fire("moveend");
  3066. },
  3067. _tryAnimatedPan: function(center, options) {
  3068. var offset = this._getCenterOffset(center)._trunc();
  3069. if ((options && options.animate) !== true && !this.getSize().contains(offset)) {
  3070. return false;
  3071. }
  3072. this.panBy(offset, options);
  3073. return true;
  3074. },
  3075. _createAnimProxy: function() {
  3076. var proxy = this._proxy = create$1("div", "leaflet-proxy leaflet-zoom-animated");
  3077. this._panes.mapPane.appendChild(proxy);
  3078. this.on("zoomanim", function(e) {
  3079. var prop = TRANSFORM, transform = this._proxy.style[prop];
  3080. setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
  3081. if (transform === this._proxy.style[prop] && this._animatingZoom) {
  3082. this._onZoomTransitionEnd();
  3083. }
  3084. }, this);
  3085. this.on("load moveend", this._animMoveEnd, this);
  3086. this._on("unload", this._destroyAnimProxy, this);
  3087. },
  3088. _destroyAnimProxy: function() {
  3089. remove(this._proxy);
  3090. this.off("load moveend", this._animMoveEnd, this);
  3091. delete this._proxy;
  3092. },
  3093. _animMoveEnd: function() {
  3094. var c = this.getCenter(), z = this.getZoom();
  3095. setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
  3096. },
  3097. _catchTransitionEnd: function(e) {
  3098. if (this._animatingZoom && e.propertyName.indexOf("transform") >= 0) {
  3099. this._onZoomTransitionEnd();
  3100. }
  3101. },
  3102. _nothingToAnimate: function() {
  3103. return !this._container.getElementsByClassName("leaflet-zoom-animated").length;
  3104. },
  3105. _tryAnimatedZoom: function(center, zoom2, options) {
  3106. if (this._animatingZoom) {
  3107. return true;
  3108. }
  3109. options = options || {};
  3110. if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() || Math.abs(zoom2 - this._zoom) > this.options.zoomAnimationThreshold) {
  3111. return false;
  3112. }
  3113. var scale2 = this.getZoomScale(zoom2), offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale2);
  3114. if (options.animate !== true && !this.getSize().contains(offset)) {
  3115. return false;
  3116. }
  3117. requestAnimFrame(function() {
  3118. this._moveStart(true, options.noMoveStart || false)._animateZoom(center, zoom2, true);
  3119. }, this);
  3120. return true;
  3121. },
  3122. _animateZoom: function(center, zoom2, startAnim, noUpdate) {
  3123. if (!this._mapPane) {
  3124. return;
  3125. }
  3126. if (startAnim) {
  3127. this._animatingZoom = true;
  3128. this._animateToCenter = center;
  3129. this._animateToZoom = zoom2;
  3130. addClass(this._mapPane, "leaflet-zoom-anim");
  3131. }
  3132. this.fire("zoomanim", {
  3133. center,
  3134. zoom: zoom2,
  3135. noUpdate
  3136. });
  3137. if (!this._tempFireZoomEvent) {
  3138. this._tempFireZoomEvent = this._zoom !== this._animateToZoom;
  3139. }
  3140. this._move(this._animateToCenter, this._animateToZoom, void 0, true);
  3141. setTimeout(bind(this._onZoomTransitionEnd, this), 250);
  3142. },
  3143. _onZoomTransitionEnd: function() {
  3144. if (!this._animatingZoom) {
  3145. return;
  3146. }
  3147. if (this._mapPane) {
  3148. removeClass(this._mapPane, "leaflet-zoom-anim");
  3149. }
  3150. this._animatingZoom = false;
  3151. this._move(this._animateToCenter, this._animateToZoom, void 0, true);
  3152. if (this._tempFireZoomEvent) {
  3153. this.fire("zoom");
  3154. }
  3155. delete this._tempFireZoomEvent;
  3156. this.fire("move");
  3157. this._moveEnd(true);
  3158. }
  3159. });
  3160. function createMap(id, options) {
  3161. return new Map(id, options);
  3162. }
  3163. var Control = Class.extend({
  3164. // @section
  3165. // @aka Control Options
  3166. options: {
  3167. // @option position: String = 'topright'
  3168. // The position of the control (one of the map corners). Possible values are `'topleft'`,
  3169. // `'topright'`, `'bottomleft'` or `'bottomright'`
  3170. position: "topright"
  3171. },
  3172. initialize: function(options) {
  3173. setOptions(this, options);
  3174. },
  3175. /* @section
  3176. * Classes extending L.Control will inherit the following methods:
  3177. *
  3178. * @method getPosition: string
  3179. * Returns the position of the control.
  3180. */
  3181. getPosition: function() {
  3182. return this.options.position;
  3183. },
  3184. // @method setPosition(position: string): this
  3185. // Sets the position of the control.
  3186. setPosition: function(position) {
  3187. var map = this._map;
  3188. if (map) {
  3189. map.removeControl(this);
  3190. }
  3191. this.options.position = position;
  3192. if (map) {
  3193. map.addControl(this);
  3194. }
  3195. return this;
  3196. },
  3197. // @method getContainer: HTMLElement
  3198. // Returns the HTMLElement that contains the control.
  3199. getContainer: function() {
  3200. return this._container;
  3201. },
  3202. // @method addTo(map: Map): this
  3203. // Adds the control to the given map.
  3204. addTo: function(map) {
  3205. this.remove();
  3206. this._map = map;
  3207. var container = this._container = this.onAdd(map), pos = this.getPosition(), corner = map._controlCorners[pos];
  3208. addClass(container, "leaflet-control");
  3209. if (pos.indexOf("bottom") !== -1) {
  3210. corner.insertBefore(container, corner.firstChild);
  3211. } else {
  3212. corner.appendChild(container);
  3213. }
  3214. this._map.on("unload", this.remove, this);
  3215. return this;
  3216. },
  3217. // @method remove: this
  3218. // Removes the control from the map it is currently active on.
  3219. remove: function() {
  3220. if (!this._map) {
  3221. return this;
  3222. }
  3223. remove(this._container);
  3224. if (this.onRemove) {
  3225. this.onRemove(this._map);
  3226. }
  3227. this._map.off("unload", this.remove, this);
  3228. this._map = null;
  3229. return this;
  3230. },
  3231. _refocusOnMap: function(e) {
  3232. if (this._map && e && e.screenX > 0 && e.screenY > 0) {
  3233. this._map.getContainer().focus();
  3234. }
  3235. }
  3236. });
  3237. var control = function(options) {
  3238. return new Control(options);
  3239. };
  3240. Map.include({
  3241. // @method addControl(control: Control): this
  3242. // Adds the given control to the map
  3243. addControl: function(control2) {
  3244. control2.addTo(this);
  3245. return this;
  3246. },
  3247. // @method removeControl(control: Control): this
  3248. // Removes the given control from the map
  3249. removeControl: function(control2) {
  3250. control2.remove();
  3251. return this;
  3252. },
  3253. _initControlPos: function() {
  3254. var corners = this._controlCorners = {}, l = "leaflet-", container = this._controlContainer = create$1("div", l + "control-container", this._container);
  3255. function createCorner(vSide, hSide) {
  3256. var className = l + vSide + " " + l + hSide;
  3257. corners[vSide + hSide] = create$1("div", className, container);
  3258. }
  3259. createCorner("top", "left");
  3260. createCorner("top", "right");
  3261. createCorner("bottom", "left");
  3262. createCorner("bottom", "right");
  3263. },
  3264. _clearControlPos: function() {
  3265. for (var i in this._controlCorners) {
  3266. remove(this._controlCorners[i]);
  3267. }
  3268. remove(this._controlContainer);
  3269. delete this._controlCorners;
  3270. delete this._controlContainer;
  3271. }
  3272. });
  3273. var Layers = Control.extend({
  3274. // @section
  3275. // @aka Control.Layers options
  3276. options: {
  3277. // @option collapsed: Boolean = true
  3278. // If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.
  3279. collapsed: true,
  3280. position: "topright",
  3281. // @option autoZIndex: Boolean = true
  3282. // 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.
  3283. autoZIndex: true,
  3284. // @option hideSingleBase: Boolean = false
  3285. // If `true`, the base layers in the control will be hidden when there is only one.
  3286. hideSingleBase: false,
  3287. // @option sortLayers: Boolean = false
  3288. // Whether to sort the layers. When `false`, layers will keep the order
  3289. // in which they were added to the control.
  3290. sortLayers: false,
  3291. // @option sortFunction: Function = *
  3292. // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
  3293. // that will be used for sorting the layers, when `sortLayers` is `true`.
  3294. // The function receives both the `L.Layer` instances and their names, as in
  3295. // `sortFunction(layerA, layerB, nameA, nameB)`.
  3296. // By default, it sorts layers alphabetically by their name.
  3297. sortFunction: function(layerA, layerB, nameA, nameB) {
  3298. return nameA < nameB ? -1 : nameB < nameA ? 1 : 0;
  3299. }
  3300. },
  3301. initialize: function(baseLayers, overlays, options) {
  3302. setOptions(this, options);
  3303. this._layerControlInputs = [];
  3304. this._layers = [];
  3305. this._lastZIndex = 0;
  3306. this._handlingClick = false;
  3307. this._preventClick = false;
  3308. for (var i in baseLayers) {
  3309. this._addLayer(baseLayers[i], i);
  3310. }
  3311. for (i in overlays) {
  3312. this._addLayer(overlays[i], i, true);
  3313. }
  3314. },
  3315. onAdd: function(map) {
  3316. this._initLayout();
  3317. this._update();
  3318. this._map = map;
  3319. map.on("zoomend", this._checkDisabledLayers, this);
  3320. for (var i = 0; i < this._layers.length; i++) {
  3321. this._layers[i].layer.on("add remove", this._onLayerChange, this);
  3322. }
  3323. return this._container;
  3324. },
  3325. addTo: function(map) {
  3326. Control.prototype.addTo.call(this, map);
  3327. return this._expandIfNotCollapsed();
  3328. },
  3329. onRemove: function() {
  3330. this._map.off("zoomend", this._checkDisabledLayers, this);
  3331. for (var i = 0; i < this._layers.length; i++) {
  3332. this._layers[i].layer.off("add remove", this._onLayerChange, this);
  3333. }
  3334. },
  3335. // @method addBaseLayer(layer: Layer, name: String): this
  3336. // Adds a base layer (radio button entry) with the given name to the control.
  3337. addBaseLayer: function(layer, name) {
  3338. this._addLayer(layer, name);
  3339. return this._map ? this._update() : this;
  3340. },
  3341. // @method addOverlay(layer: Layer, name: String): this
  3342. // Adds an overlay (checkbox entry) with the given name to the control.
  3343. addOverlay: function(layer, name) {
  3344. this._addLayer(layer, name, true);
  3345. return this._map ? this._update() : this;
  3346. },
  3347. // @method removeLayer(layer: Layer): this
  3348. // Remove the given layer from the control.
  3349. removeLayer: function(layer) {
  3350. layer.off("add remove", this._onLayerChange, this);
  3351. var obj = this._getLayer(stamp(layer));
  3352. if (obj) {
  3353. this._layers.splice(this._layers.indexOf(obj), 1);
  3354. }
  3355. return this._map ? this._update() : this;
  3356. },
  3357. // @method expand(): this
  3358. // Expand the control container if collapsed.
  3359. expand: function() {
  3360. addClass(this._container, "leaflet-control-layers-expanded");
  3361. this._section.style.height = null;
  3362. var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
  3363. if (acceptableHeight < this._section.clientHeight) {
  3364. addClass(this._section, "leaflet-control-layers-scrollbar");
  3365. this._section.style.height = acceptableHeight + "px";
  3366. } else {
  3367. removeClass(this._section, "leaflet-control-layers-scrollbar");
  3368. }
  3369. this._checkDisabledLayers();
  3370. return this;
  3371. },
  3372. // @method collapse(): this
  3373. // Collapse the control container if expanded.
  3374. collapse: function() {
  3375. removeClass(this._container, "leaflet-control-layers-expanded");
  3376. return this;
  3377. },
  3378. _initLayout: function() {
  3379. var className = "leaflet-control-layers", container = this._container = create$1("div", className), collapsed = this.options.collapsed;
  3380. container.setAttribute("aria-haspopup", true);
  3381. disableClickPropagation(container);
  3382. disableScrollPropagation(container);
  3383. var section = this._section = create$1("section", className + "-list");
  3384. if (collapsed) {
  3385. this._map.on("click", this.collapse, this);
  3386. on(container, {
  3387. mouseenter: this._expandSafely,
  3388. mouseleave: this.collapse
  3389. }, this);
  3390. }
  3391. var link = this._layersLink = create$1("a", className + "-toggle", container);
  3392. link.href = "#";
  3393. link.title = "Layers";
  3394. link.setAttribute("role", "button");
  3395. on(link, {
  3396. keydown: function(e) {
  3397. if (e.keyCode === 13) {
  3398. this._expandSafely();
  3399. }
  3400. },
  3401. // Certain screen readers intercept the key event and instead send a click event
  3402. click: function(e) {
  3403. preventDefault(e);
  3404. this._expandSafely();
  3405. }
  3406. }, this);
  3407. if (!collapsed) {
  3408. this.expand();
  3409. }
  3410. this._baseLayersList = create$1("div", className + "-base", section);
  3411. this._separator = create$1("div", className + "-separator", section);
  3412. this._overlaysList = create$1("div", className + "-overlays", section);
  3413. container.appendChild(section);
  3414. },
  3415. _getLayer: function(id) {
  3416. for (var i = 0; i < this._layers.length; i++) {
  3417. if (this._layers[i] && stamp(this._layers[i].layer) === id) {
  3418. return this._layers[i];
  3419. }
  3420. }
  3421. },
  3422. _addLayer: function(layer, name, overlay) {
  3423. if (this._map) {
  3424. layer.on("add remove", this._onLayerChange, this);
  3425. }
  3426. this._layers.push({
  3427. layer,
  3428. name,
  3429. overlay
  3430. });
  3431. if (this.options.sortLayers) {
  3432. this._layers.sort(bind(function(a, b) {
  3433. return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
  3434. }, this));
  3435. }
  3436. if (this.options.autoZIndex && layer.setZIndex) {
  3437. this._lastZIndex++;
  3438. layer.setZIndex(this._lastZIndex);
  3439. }
  3440. this._expandIfNotCollapsed();
  3441. },
  3442. _update: function() {
  3443. if (!this._container) {
  3444. return this;
  3445. }
  3446. empty(this._baseLayersList);
  3447. empty(this._overlaysList);
  3448. this._layerControlInputs = [];
  3449. var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
  3450. for (i = 0; i < this._layers.length; i++) {
  3451. obj = this._layers[i];
  3452. this._addItem(obj);
  3453. overlaysPresent = overlaysPresent || obj.overlay;
  3454. baseLayersPresent = baseLayersPresent || !obj.overlay;
  3455. baseLayersCount += !obj.overlay ? 1 : 0;
  3456. }
  3457. if (this.options.hideSingleBase) {
  3458. baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
  3459. this._baseLayersList.style.display = baseLayersPresent ? "" : "none";
  3460. }
  3461. this._separator.style.display = overlaysPresent && baseLayersPresent ? "" : "none";
  3462. return this;
  3463. },
  3464. _onLayerChange: function(e) {
  3465. if (!this._handlingClick) {
  3466. this._update();
  3467. }
  3468. var obj = this._getLayer(stamp(e.target));
  3469. var type = obj.overlay ? e.type === "add" ? "overlayadd" : "overlayremove" : e.type === "add" ? "baselayerchange" : null;
  3470. if (type) {
  3471. this._map.fire(type, obj);
  3472. }
  3473. },
  3474. // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)
  3475. _createRadioElement: function(name, checked) {
  3476. var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"' + (checked ? ' checked="checked"' : "") + "/>";
  3477. var radioFragment = document.createElement("div");
  3478. radioFragment.innerHTML = radioHtml;
  3479. return radioFragment.firstChild;
  3480. },
  3481. _addItem: function(obj) {
  3482. var label = document.createElement("label"), checked = this._map.hasLayer(obj.layer), input;
  3483. if (obj.overlay) {
  3484. input = document.createElement("input");
  3485. input.type = "checkbox";
  3486. input.className = "leaflet-control-layers-selector";
  3487. input.defaultChecked = checked;
  3488. } else {
  3489. input = this._createRadioElement("leaflet-base-layers_" + stamp(this), checked);
  3490. }
  3491. this._layerControlInputs.push(input);
  3492. input.layerId = stamp(obj.layer);
  3493. on(input, "click", this._onInputClick, this);
  3494. var name = document.createElement("span");
  3495. name.innerHTML = " " + obj.name;
  3496. var holder = document.createElement("span");
  3497. label.appendChild(holder);
  3498. holder.appendChild(input);
  3499. holder.appendChild(name);
  3500. var container = obj.overlay ? this._overlaysList : this._baseLayersList;
  3501. container.appendChild(label);
  3502. this._checkDisabledLayers();
  3503. return label;
  3504. },
  3505. _onInputClick: function() {
  3506. if (this._preventClick) {
  3507. return;
  3508. }
  3509. var inputs = this._layerControlInputs, input, layer;
  3510. var addedLayers = [], removedLayers = [];
  3511. this._handlingClick = true;
  3512. for (var i = inputs.length - 1; i >= 0; i--) {
  3513. input = inputs[i];
  3514. layer = this._getLayer(input.layerId).layer;
  3515. if (input.checked) {
  3516. addedLayers.push(layer);
  3517. } else if (!input.checked) {
  3518. removedLayers.push(layer);
  3519. }
  3520. }
  3521. for (i = 0; i < removedLayers.length; i++) {
  3522. if (this._map.hasLayer(removedLayers[i])) {
  3523. this._map.removeLayer(removedLayers[i]);
  3524. }
  3525. }
  3526. for (i = 0; i < addedLayers.length; i++) {
  3527. if (!this._map.hasLayer(addedLayers[i])) {
  3528. this._map.addLayer(addedLayers[i]);
  3529. }
  3530. }
  3531. this._handlingClick = false;
  3532. this._refocusOnMap();
  3533. },
  3534. _checkDisabledLayers: function() {
  3535. var inputs = this._layerControlInputs, input, layer, zoom2 = this._map.getZoom();
  3536. for (var i = inputs.length - 1; i >= 0; i--) {
  3537. input = inputs[i];
  3538. layer = this._getLayer(input.layerId).layer;
  3539. input.disabled = layer.options.minZoom !== void 0 && zoom2 < layer.options.minZoom || layer.options.maxZoom !== void 0 && zoom2 > layer.options.maxZoom;
  3540. }
  3541. },
  3542. _expandIfNotCollapsed: function() {
  3543. if (this._map && !this.options.collapsed) {
  3544. this.expand();
  3545. }
  3546. return this;
  3547. },
  3548. _expandSafely: function() {
  3549. var section = this._section;
  3550. this._preventClick = true;
  3551. on(section, "click", preventDefault);
  3552. this.expand();
  3553. var that = this;
  3554. setTimeout(function() {
  3555. off(section, "click", preventDefault);
  3556. that._preventClick = false;
  3557. });
  3558. }
  3559. });
  3560. var layers = function(baseLayers, overlays, options) {
  3561. return new Layers(baseLayers, overlays, options);
  3562. };
  3563. var Zoom = Control.extend({
  3564. // @section
  3565. // @aka Control.Zoom options
  3566. options: {
  3567. position: "topleft",
  3568. // @option zoomInText: String = '<span aria-hidden="true">+</span>'
  3569. // The text set on the 'zoom in' button.
  3570. zoomInText: '<span aria-hidden="true">+</span>',
  3571. // @option zoomInTitle: String = 'Zoom in'
  3572. // The title set on the 'zoom in' button.
  3573. zoomInTitle: "Zoom in",
  3574. // @option zoomOutText: String = '<span aria-hidden="true">&#x2212;</span>'
  3575. // The text set on the 'zoom out' button.
  3576. zoomOutText: '<span aria-hidden="true">&#x2212;</span>',
  3577. // @option zoomOutTitle: String = 'Zoom out'
  3578. // The title set on the 'zoom out' button.
  3579. zoomOutTitle: "Zoom out"
  3580. },
  3581. onAdd: function(map) {
  3582. var zoomName = "leaflet-control-zoom", container = create$1("div", zoomName + " leaflet-bar"), options = this.options;
  3583. this._zoomInButton = this._createButton(
  3584. options.zoomInText,
  3585. options.zoomInTitle,
  3586. zoomName + "-in",
  3587. container,
  3588. this._zoomIn
  3589. );
  3590. this._zoomOutButton = this._createButton(
  3591. options.zoomOutText,
  3592. options.zoomOutTitle,
  3593. zoomName + "-out",
  3594. container,
  3595. this._zoomOut
  3596. );
  3597. this._updateDisabled();
  3598. map.on("zoomend zoomlevelschange", this._updateDisabled, this);
  3599. return container;
  3600. },
  3601. onRemove: function(map) {
  3602. map.off("zoomend zoomlevelschange", this._updateDisabled, this);
  3603. },
  3604. disable: function() {
  3605. this._disabled = true;
  3606. this._updateDisabled();
  3607. return this;
  3608. },
  3609. enable: function() {
  3610. this._disabled = false;
  3611. this._updateDisabled();
  3612. return this;
  3613. },
  3614. _zoomIn: function(e) {
  3615. if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
  3616. this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
  3617. }
  3618. },
  3619. _zoomOut: function(e) {
  3620. if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
  3621. this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
  3622. }
  3623. },
  3624. _createButton: function(html, title, className, container, fn) {
  3625. var link = create$1("a", className, container);
  3626. link.innerHTML = html;
  3627. link.href = "#";
  3628. link.title = title;
  3629. link.setAttribute("role", "button");
  3630. link.setAttribute("aria-label", title);
  3631. disableClickPropagation(link);
  3632. on(link, "click", stop);
  3633. on(link, "click", fn, this);
  3634. on(link, "click", this._refocusOnMap, this);
  3635. return link;
  3636. },
  3637. _updateDisabled: function() {
  3638. var map = this._map, className = "leaflet-disabled";
  3639. removeClass(this._zoomInButton, className);
  3640. removeClass(this._zoomOutButton, className);
  3641. this._zoomInButton.setAttribute("aria-disabled", "false");
  3642. this._zoomOutButton.setAttribute("aria-disabled", "false");
  3643. if (this._disabled || map._zoom === map.getMinZoom()) {
  3644. addClass(this._zoomOutButton, className);
  3645. this._zoomOutButton.setAttribute("aria-disabled", "true");
  3646. }
  3647. if (this._disabled || map._zoom === map.getMaxZoom()) {
  3648. addClass(this._zoomInButton, className);
  3649. this._zoomInButton.setAttribute("aria-disabled", "true");
  3650. }
  3651. }
  3652. });
  3653. Map.mergeOptions({
  3654. zoomControl: true
  3655. });
  3656. Map.addInitHook(function() {
  3657. if (this.options.zoomControl) {
  3658. this.zoomControl = new Zoom();
  3659. this.addControl(this.zoomControl);
  3660. }
  3661. });
  3662. var zoom = function(options) {
  3663. return new Zoom(options);
  3664. };
  3665. var Scale = Control.extend({
  3666. // @section
  3667. // @aka Control.Scale options
  3668. options: {
  3669. position: "bottomleft",
  3670. // @option maxWidth: Number = 100
  3671. // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
  3672. maxWidth: 100,
  3673. // @option metric: Boolean = True
  3674. // Whether to show the metric scale line (m/km).
  3675. metric: true,
  3676. // @option imperial: Boolean = True
  3677. // Whether to show the imperial scale line (mi/ft).
  3678. imperial: true
  3679. // @option updateWhenIdle: Boolean = false
  3680. // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
  3681. },
  3682. onAdd: function(map) {
  3683. var className = "leaflet-control-scale", container = create$1("div", className), options = this.options;
  3684. this._addScales(options, className + "-line", container);
  3685. map.on(options.updateWhenIdle ? "moveend" : "move", this._update, this);
  3686. map.whenReady(this._update, this);
  3687. return container;
  3688. },
  3689. onRemove: function(map) {
  3690. map.off(this.options.updateWhenIdle ? "moveend" : "move", this._update, this);
  3691. },
  3692. _addScales: function(options, className, container) {
  3693. if (options.metric) {
  3694. this._mScale = create$1("div", className, container);
  3695. }
  3696. if (options.imperial) {
  3697. this._iScale = create$1("div", className, container);
  3698. }
  3699. },
  3700. _update: function() {
  3701. var map = this._map, y = map.getSize().y / 2;
  3702. var maxMeters = map.distance(
  3703. map.containerPointToLatLng([0, y]),
  3704. map.containerPointToLatLng([this.options.maxWidth, y])
  3705. );
  3706. this._updateScales(maxMeters);
  3707. },
  3708. _updateScales: function(maxMeters) {
  3709. if (this.options.metric && maxMeters) {
  3710. this._updateMetric(maxMeters);
  3711. }
  3712. if (this.options.imperial && maxMeters) {
  3713. this._updateImperial(maxMeters);
  3714. }
  3715. },
  3716. _updateMetric: function(maxMeters) {
  3717. var meters = this._getRoundNum(maxMeters), label = meters < 1e3 ? meters + " m" : meters / 1e3 + " km";
  3718. this._updateScale(this._mScale, label, meters / maxMeters);
  3719. },
  3720. _updateImperial: function(maxMeters) {
  3721. var maxFeet = maxMeters * 3.2808399, maxMiles, miles, feet;
  3722. if (maxFeet > 5280) {
  3723. maxMiles = maxFeet / 5280;
  3724. miles = this._getRoundNum(maxMiles);
  3725. this._updateScale(this._iScale, miles + " mi", miles / maxMiles);
  3726. } else {
  3727. feet = this._getRoundNum(maxFeet);
  3728. this._updateScale(this._iScale, feet + " ft", feet / maxFeet);
  3729. }
  3730. },
  3731. _updateScale: function(scale2, text, ratio) {
  3732. scale2.style.width = Math.round(this.options.maxWidth * ratio) + "px";
  3733. scale2.innerHTML = text;
  3734. },
  3735. _getRoundNum: function(num) {
  3736. var pow10 = Math.pow(10, (Math.floor(num) + "").length - 1), d = num / pow10;
  3737. d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;
  3738. return pow10 * d;
  3739. }
  3740. });
  3741. var scale = function(options) {
  3742. return new Scale(options);
  3743. };
  3744. var 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>';
  3745. var Attribution = Control.extend({
  3746. // @section
  3747. // @aka Control.Attribution options
  3748. options: {
  3749. position: "bottomright",
  3750. // @option prefix: String|false = 'Leaflet'
  3751. // The HTML text shown before the attributions. Pass `false` to disable.
  3752. prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' + (Browser.inlineSvg ? ukrainianFlag + " " : "") + "Leaflet</a>"
  3753. },
  3754. initialize: function(options) {
  3755. setOptions(this, options);
  3756. this._attributions = {};
  3757. },
  3758. onAdd: function(map) {
  3759. map.attributionControl = this;
  3760. this._container = create$1("div", "leaflet-control-attribution");
  3761. disableClickPropagation(this._container);
  3762. for (var i in map._layers) {
  3763. if (map._layers[i].getAttribution) {
  3764. this.addAttribution(map._layers[i].getAttribution());
  3765. }
  3766. }
  3767. this._update();
  3768. map.on("layeradd", this._addAttribution, this);
  3769. return this._container;
  3770. },
  3771. onRemove: function(map) {
  3772. map.off("layeradd", this._addAttribution, this);
  3773. },
  3774. _addAttribution: function(ev) {
  3775. if (ev.layer.getAttribution) {
  3776. this.addAttribution(ev.layer.getAttribution());
  3777. ev.layer.once("remove", function() {
  3778. this.removeAttribution(ev.layer.getAttribution());
  3779. }, this);
  3780. }
  3781. },
  3782. // @method setPrefix(prefix: String|false): this
  3783. // The HTML text shown before the attributions. Pass `false` to disable.
  3784. setPrefix: function(prefix) {
  3785. this.options.prefix = prefix;
  3786. this._update();
  3787. return this;
  3788. },
  3789. // @method addAttribution(text: String): this
  3790. // Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).
  3791. addAttribution: function(text) {
  3792. if (!text) {
  3793. return this;
  3794. }
  3795. if (!this._attributions[text]) {
  3796. this._attributions[text] = 0;
  3797. }
  3798. this._attributions[text]++;
  3799. this._update();
  3800. return this;
  3801. },
  3802. // @method removeAttribution(text: String): this
  3803. // Removes an attribution text.
  3804. removeAttribution: function(text) {
  3805. if (!text) {
  3806. return this;
  3807. }
  3808. if (this._attributions[text]) {
  3809. this._attributions[text]--;
  3810. this._update();
  3811. }
  3812. return this;
  3813. },
  3814. _update: function() {
  3815. if (!this._map) {
  3816. return;
  3817. }
  3818. var attribs = [];
  3819. for (var i in this._attributions) {
  3820. if (this._attributions[i]) {
  3821. attribs.push(i);
  3822. }
  3823. }
  3824. var prefixAndAttribs = [];
  3825. if (this.options.prefix) {
  3826. prefixAndAttribs.push(this.options.prefix);
  3827. }
  3828. if (attribs.length) {
  3829. prefixAndAttribs.push(attribs.join(", "));
  3830. }
  3831. this._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden="true">|</span> ');
  3832. }
  3833. });
  3834. Map.mergeOptions({
  3835. attributionControl: true
  3836. });
  3837. Map.addInitHook(function() {
  3838. if (this.options.attributionControl) {
  3839. new Attribution().addTo(this);
  3840. }
  3841. });
  3842. var attribution = function(options) {
  3843. return new Attribution(options);
  3844. };
  3845. Control.Layers = Layers;
  3846. Control.Zoom = Zoom;
  3847. Control.Scale = Scale;
  3848. Control.Attribution = Attribution;
  3849. control.layers = layers;
  3850. control.zoom = zoom;
  3851. control.scale = scale;
  3852. control.attribution = attribution;
  3853. var Handler = Class.extend({
  3854. initialize: function(map) {
  3855. this._map = map;
  3856. },
  3857. // @method enable(): this
  3858. // Enables the handler
  3859. enable: function() {
  3860. if (this._enabled) {
  3861. return this;
  3862. }
  3863. this._enabled = true;
  3864. this.addHooks();
  3865. return this;
  3866. },
  3867. // @method disable(): this
  3868. // Disables the handler
  3869. disable: function() {
  3870. if (!this._enabled) {
  3871. return this;
  3872. }
  3873. this._enabled = false;
  3874. this.removeHooks();
  3875. return this;
  3876. },
  3877. // @method enabled(): Boolean
  3878. // Returns `true` if the handler is enabled
  3879. enabled: function() {
  3880. return !!this._enabled;
  3881. }
  3882. // @section Extension methods
  3883. // Classes inheriting from `Handler` must implement the two following methods:
  3884. // @method addHooks()
  3885. // Called when the handler is enabled, should add event hooks.
  3886. // @method removeHooks()
  3887. // Called when the handler is disabled, should remove the event hooks added previously.
  3888. });
  3889. Handler.addTo = function(map, name) {
  3890. map.addHandler(name, this);
  3891. return this;
  3892. };
  3893. var Mixin = { Events };
  3894. var START = Browser.touch ? "touchstart mousedown" : "mousedown";
  3895. var Draggable = Evented.extend({
  3896. options: {
  3897. // @section
  3898. // @aka Draggable options
  3899. // @option clickTolerance: Number = 3
  3900. // The max number of pixels a user can shift the mouse pointer during a click
  3901. // for it to be considered a valid click (as opposed to a mouse drag).
  3902. clickTolerance: 3
  3903. },
  3904. // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
  3905. // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
  3906. initialize: function(element, dragStartTarget, preventOutline2, options) {
  3907. setOptions(this, options);
  3908. this._element = element;
  3909. this._dragStartTarget = dragStartTarget || element;
  3910. this._preventOutline = preventOutline2;
  3911. },
  3912. // @method enable()
  3913. // Enables the dragging ability
  3914. enable: function() {
  3915. if (this._enabled) {
  3916. return;
  3917. }
  3918. on(this._dragStartTarget, START, this._onDown, this);
  3919. this._enabled = true;
  3920. },
  3921. // @method disable()
  3922. // Disables the dragging ability
  3923. disable: function() {
  3924. if (!this._enabled) {
  3925. return;
  3926. }
  3927. if (Draggable._dragging === this) {
  3928. this.finishDrag(true);
  3929. }
  3930. off(this._dragStartTarget, START, this._onDown, this);
  3931. this._enabled = false;
  3932. this._moved = false;
  3933. },
  3934. _onDown: function(e) {
  3935. if (!this._enabled) {
  3936. return;
  3937. }
  3938. this._moved = false;
  3939. if (hasClass(this._element, "leaflet-zoom-anim")) {
  3940. return;
  3941. }
  3942. if (e.touches && e.touches.length !== 1) {
  3943. if (Draggable._dragging === this) {
  3944. this.finishDrag();
  3945. }
  3946. return;
  3947. }
  3948. if (Draggable._dragging || e.shiftKey || e.which !== 1 && e.button !== 1 && !e.touches) {
  3949. return;
  3950. }
  3951. Draggable._dragging = this;
  3952. if (this._preventOutline) {
  3953. preventOutline(this._element);
  3954. }
  3955. disableImageDrag();
  3956. disableTextSelection();
  3957. if (this._moving) {
  3958. return;
  3959. }
  3960. this.fire("down");
  3961. var first = e.touches ? e.touches[0] : e, sizedParent = getSizedParentNode(this._element);
  3962. this._startPoint = new Point(first.clientX, first.clientY);
  3963. this._startPos = getPosition(this._element);
  3964. this._parentScale = getScale(sizedParent);
  3965. var mouseevent = e.type === "mousedown";
  3966. on(document, mouseevent ? "mousemove" : "touchmove", this._onMove, this);
  3967. on(document, mouseevent ? "mouseup" : "touchend touchcancel", this._onUp, this);
  3968. },
  3969. _onMove: function(e) {
  3970. if (!this._enabled) {
  3971. return;
  3972. }
  3973. if (e.touches && e.touches.length > 1) {
  3974. this._moved = true;
  3975. return;
  3976. }
  3977. var first = e.touches && e.touches.length === 1 ? e.touches[0] : e, offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);
  3978. if (!offset.x && !offset.y) {
  3979. return;
  3980. }
  3981. if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) {
  3982. return;
  3983. }
  3984. offset.x /= this._parentScale.x;
  3985. offset.y /= this._parentScale.y;
  3986. preventDefault(e);
  3987. if (!this._moved) {
  3988. this.fire("dragstart");
  3989. this._moved = true;
  3990. addClass(document.body, "leaflet-dragging");
  3991. this._lastTarget = e.target || e.srcElement;
  3992. if (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {
  3993. this._lastTarget = this._lastTarget.correspondingUseElement;
  3994. }
  3995. addClass(this._lastTarget, "leaflet-drag-target");
  3996. }
  3997. this._newPos = this._startPos.add(offset);
  3998. this._moving = true;
  3999. this._lastEvent = e;
  4000. this._updatePosition();
  4001. },
  4002. _updatePosition: function() {
  4003. var e = { originalEvent: this._lastEvent };
  4004. this.fire("predrag", e);
  4005. setPosition(this._element, this._newPos);
  4006. this.fire("drag", e);
  4007. },
  4008. _onUp: function() {
  4009. if (!this._enabled) {
  4010. return;
  4011. }
  4012. this.finishDrag();
  4013. },
  4014. finishDrag: function(noInertia) {
  4015. removeClass(document.body, "leaflet-dragging");
  4016. if (this._lastTarget) {
  4017. removeClass(this._lastTarget, "leaflet-drag-target");
  4018. this._lastTarget = null;
  4019. }
  4020. off(document, "mousemove touchmove", this._onMove, this);
  4021. off(document, "mouseup touchend touchcancel", this._onUp, this);
  4022. enableImageDrag();
  4023. enableTextSelection();
  4024. var fireDragend = this._moved && this._moving;
  4025. this._moving = false;
  4026. Draggable._dragging = false;
  4027. if (fireDragend) {
  4028. this.fire("dragend", {
  4029. noInertia,
  4030. distance: this._newPos.distanceTo(this._startPos)
  4031. });
  4032. }
  4033. }
  4034. });
  4035. function clipPolygon(points, bounds, round) {
  4036. var clippedPoints, edges = [1, 4, 2, 8], i, j, k, a, b, len, edge2, p;
  4037. for (i = 0, len = points.length; i < len; i++) {
  4038. points[i]._code = _getBitCode(points[i], bounds);
  4039. }
  4040. for (k = 0; k < 4; k++) {
  4041. edge2 = edges[k];
  4042. clippedPoints = [];
  4043. for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
  4044. a = points[i];
  4045. b = points[j];
  4046. if (!(a._code & edge2)) {
  4047. if (b._code & edge2) {
  4048. p = _getEdgeIntersection(b, a, edge2, bounds, round);
  4049. p._code = _getBitCode(p, bounds);
  4050. clippedPoints.push(p);
  4051. }
  4052. clippedPoints.push(a);
  4053. } else if (!(b._code & edge2)) {
  4054. p = _getEdgeIntersection(b, a, edge2, bounds, round);
  4055. p._code = _getBitCode(p, bounds);
  4056. clippedPoints.push(p);
  4057. }
  4058. }
  4059. points = clippedPoints;
  4060. }
  4061. return points;
  4062. }
  4063. function polygonCenter(latlngs, crs) {
  4064. var i, j, p1, p2, f, area, x, y, center;
  4065. if (!latlngs || latlngs.length === 0) {
  4066. throw new Error("latlngs not passed");
  4067. }
  4068. if (!isFlat(latlngs)) {
  4069. console.warn("latlngs are not flat! Only the first ring will be used");
  4070. latlngs = latlngs[0];
  4071. }
  4072. var centroidLatLng = toLatLng([0, 0]);
  4073. var bounds = toLatLngBounds(latlngs);
  4074. var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
  4075. if (areaBounds < 1700) {
  4076. centroidLatLng = centroid(latlngs);
  4077. }
  4078. var len = latlngs.length;
  4079. var points = [];
  4080. for (i = 0; i < len; i++) {
  4081. var latlng = toLatLng(latlngs[i]);
  4082. points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
  4083. }
  4084. area = x = y = 0;
  4085. for (i = 0, j = len - 1; i < len; j = i++) {
  4086. p1 = points[i];
  4087. p2 = points[j];
  4088. f = p1.y * p2.x - p2.y * p1.x;
  4089. x += (p1.x + p2.x) * f;
  4090. y += (p1.y + p2.y) * f;
  4091. area += f * 3;
  4092. }
  4093. if (area === 0) {
  4094. center = points[0];
  4095. } else {
  4096. center = [x / area, y / area];
  4097. }
  4098. var latlngCenter = crs.unproject(toPoint(center));
  4099. return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
  4100. }
  4101. function centroid(coords) {
  4102. var latSum = 0;
  4103. var lngSum = 0;
  4104. var len = 0;
  4105. for (var i = 0; i < coords.length; i++) {
  4106. var latlng = toLatLng(coords[i]);
  4107. latSum += latlng.lat;
  4108. lngSum += latlng.lng;
  4109. len++;
  4110. }
  4111. return toLatLng([latSum / len, lngSum / len]);
  4112. }
  4113. var PolyUtil = {
  4114. __proto__: null,
  4115. clipPolygon,
  4116. polygonCenter,
  4117. centroid
  4118. };
  4119. function simplify(points, tolerance) {
  4120. if (!tolerance || !points.length) {
  4121. return points.slice();
  4122. }
  4123. var sqTolerance = tolerance * tolerance;
  4124. points = _reducePoints(points, sqTolerance);
  4125. points = _simplifyDP(points, sqTolerance);
  4126. return points;
  4127. }
  4128. function pointToSegmentDistance(p, p1, p2) {
  4129. return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
  4130. }
  4131. function closestPointOnSegment(p, p1, p2) {
  4132. return _sqClosestPointOnSegment(p, p1, p2);
  4133. }
  4134. function _simplifyDP(points, sqTolerance) {
  4135. var len = points.length, ArrayConstructor = typeof Uint8Array !== "undefined" ? Uint8Array : Array, markers = new ArrayConstructor(len);
  4136. markers[0] = markers[len - 1] = 1;
  4137. _simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
  4138. var i, newPoints = [];
  4139. for (i = 0; i < len; i++) {
  4140. if (markers[i]) {
  4141. newPoints.push(points[i]);
  4142. }
  4143. }
  4144. return newPoints;
  4145. }
  4146. function _simplifyDPStep(points, markers, sqTolerance, first, last) {
  4147. var maxSqDist = 0, index2, i, sqDist;
  4148. for (i = first + 1; i <= last - 1; i++) {
  4149. sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
  4150. if (sqDist > maxSqDist) {
  4151. index2 = i;
  4152. maxSqDist = sqDist;
  4153. }
  4154. }
  4155. if (maxSqDist > sqTolerance) {
  4156. markers[index2] = 1;
  4157. _simplifyDPStep(points, markers, sqTolerance, first, index2);
  4158. _simplifyDPStep(points, markers, sqTolerance, index2, last);
  4159. }
  4160. }
  4161. function _reducePoints(points, sqTolerance) {
  4162. var reducedPoints = [points[0]];
  4163. for (var i = 1, prev = 0, len = points.length; i < len; i++) {
  4164. if (_sqDist(points[i], points[prev]) > sqTolerance) {
  4165. reducedPoints.push(points[i]);
  4166. prev = i;
  4167. }
  4168. }
  4169. if (prev < len - 1) {
  4170. reducedPoints.push(points[len - 1]);
  4171. }
  4172. return reducedPoints;
  4173. }
  4174. var _lastCode;
  4175. function clipSegment(a, b, bounds, useLastCode, round) {
  4176. var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds), codeB = _getBitCode(b, bounds), codeOut, p, newCode;
  4177. _lastCode = codeB;
  4178. while (true) {
  4179. if (!(codeA | codeB)) {
  4180. return [a, b];
  4181. }
  4182. if (codeA & codeB) {
  4183. return false;
  4184. }
  4185. codeOut = codeA || codeB;
  4186. p = _getEdgeIntersection(a, b, codeOut, bounds, round);
  4187. newCode = _getBitCode(p, bounds);
  4188. if (codeOut === codeA) {
  4189. a = p;
  4190. codeA = newCode;
  4191. } else {
  4192. b = p;
  4193. codeB = newCode;
  4194. }
  4195. }
  4196. }
  4197. function _getEdgeIntersection(a, b, code, bounds, round) {
  4198. var dx = b.x - a.x, dy = b.y - a.y, min = bounds.min, max = bounds.max, x, y;
  4199. if (code & 8) {
  4200. x = a.x + dx * (max.y - a.y) / dy;
  4201. y = max.y;
  4202. } else if (code & 4) {
  4203. x = a.x + dx * (min.y - a.y) / dy;
  4204. y = min.y;
  4205. } else if (code & 2) {
  4206. x = max.x;
  4207. y = a.y + dy * (max.x - a.x) / dx;
  4208. } else if (code & 1) {
  4209. x = min.x;
  4210. y = a.y + dy * (min.x - a.x) / dx;
  4211. }
  4212. return new Point(x, y, round);
  4213. }
  4214. function _getBitCode(p, bounds) {
  4215. var code = 0;
  4216. if (p.x < bounds.min.x) {
  4217. code |= 1;
  4218. } else if (p.x > bounds.max.x) {
  4219. code |= 2;
  4220. }
  4221. if (p.y < bounds.min.y) {
  4222. code |= 4;
  4223. } else if (p.y > bounds.max.y) {
  4224. code |= 8;
  4225. }
  4226. return code;
  4227. }
  4228. function _sqDist(p1, p2) {
  4229. var dx = p2.x - p1.x, dy = p2.y - p1.y;
  4230. return dx * dx + dy * dy;
  4231. }
  4232. function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
  4233. var x = p1.x, y = p1.y, dx = p2.x - x, dy = p2.y - y, dot = dx * dx + dy * dy, t;
  4234. if (dot > 0) {
  4235. t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
  4236. if (t > 1) {
  4237. x = p2.x;
  4238. y = p2.y;
  4239. } else if (t > 0) {
  4240. x += dx * t;
  4241. y += dy * t;
  4242. }
  4243. }
  4244. dx = p.x - x;
  4245. dy = p.y - y;
  4246. return sqDist ? dx * dx + dy * dy : new Point(x, y);
  4247. }
  4248. function isFlat(latlngs) {
  4249. return !isArray(latlngs[0]) || typeof latlngs[0][0] !== "object" && typeof latlngs[0][0] !== "undefined";
  4250. }
  4251. function _flat(latlngs) {
  4252. console.warn("Deprecated use of _flat, please use L.LineUtil.isFlat instead.");
  4253. return isFlat(latlngs);
  4254. }
  4255. function polylineCenter(latlngs, crs) {
  4256. var i, halfDist, segDist, dist, p1, p2, ratio, center;
  4257. if (!latlngs || latlngs.length === 0) {
  4258. throw new Error("latlngs not passed");
  4259. }
  4260. if (!isFlat(latlngs)) {
  4261. console.warn("latlngs are not flat! Only the first ring will be used");
  4262. latlngs = latlngs[0];
  4263. }
  4264. var centroidLatLng = toLatLng([0, 0]);
  4265. var bounds = toLatLngBounds(latlngs);
  4266. var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
  4267. if (areaBounds < 1700) {
  4268. centroidLatLng = centroid(latlngs);
  4269. }
  4270. var len = latlngs.length;
  4271. var points = [];
  4272. for (i = 0; i < len; i++) {
  4273. var latlng = toLatLng(latlngs[i]);
  4274. points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
  4275. }
  4276. for (i = 0, halfDist = 0; i < len - 1; i++) {
  4277. halfDist += points[i].distanceTo(points[i + 1]) / 2;
  4278. }
  4279. if (halfDist === 0) {
  4280. center = points[0];
  4281. } else {
  4282. for (i = 0, dist = 0; i < len - 1; i++) {
  4283. p1 = points[i];
  4284. p2 = points[i + 1];
  4285. segDist = p1.distanceTo(p2);
  4286. dist += segDist;
  4287. if (dist > halfDist) {
  4288. ratio = (dist - halfDist) / segDist;
  4289. center = [
  4290. p2.x - ratio * (p2.x - p1.x),
  4291. p2.y - ratio * (p2.y - p1.y)
  4292. ];
  4293. break;
  4294. }
  4295. }
  4296. }
  4297. var latlngCenter = crs.unproject(toPoint(center));
  4298. return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
  4299. }
  4300. var LineUtil = {
  4301. __proto__: null,
  4302. simplify,
  4303. pointToSegmentDistance,
  4304. closestPointOnSegment,
  4305. clipSegment,
  4306. _getEdgeIntersection,
  4307. _getBitCode,
  4308. _sqClosestPointOnSegment,
  4309. isFlat,
  4310. _flat,
  4311. polylineCenter
  4312. };
  4313. var LonLat = {
  4314. project: function(latlng) {
  4315. return new Point(latlng.lng, latlng.lat);
  4316. },
  4317. unproject: function(point) {
  4318. return new LatLng(point.y, point.x);
  4319. },
  4320. bounds: new Bounds([-180, -90], [180, 90])
  4321. };
  4322. var Mercator = {
  4323. R: 6378137,
  4324. R_MINOR: 6356752314245179e-9,
  4325. bounds: new Bounds([-2003750834279e-5, -1549657073972e-5], [2003750834279e-5, 1876465623138e-5]),
  4326. project: function(latlng) {
  4327. var d = Math.PI / 180, r = this.R, y = latlng.lat * d, tmp = this.R_MINOR / r, e = Math.sqrt(1 - tmp * tmp), con = e * Math.sin(y);
  4328. var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
  4329. y = -r * Math.log(Math.max(ts, 1e-10));
  4330. return new Point(latlng.lng * d * r, y);
  4331. },
  4332. unproject: function(point) {
  4333. var d = 180 / Math.PI, r = this.R, tmp = this.R_MINOR / r, e = Math.sqrt(1 - tmp * tmp), ts = Math.exp(-point.y / r), phi = Math.PI / 2 - 2 * Math.atan(ts);
  4334. for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
  4335. con = e * Math.sin(phi);
  4336. con = Math.pow((1 - con) / (1 + con), e / 2);
  4337. dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
  4338. phi += dphi;
  4339. }
  4340. return new LatLng(phi * d, point.x * d / r);
  4341. }
  4342. };
  4343. var index = {
  4344. __proto__: null,
  4345. LonLat,
  4346. Mercator,
  4347. SphericalMercator
  4348. };
  4349. var EPSG3395 = extend({}, Earth, {
  4350. code: "EPSG:3395",
  4351. projection: Mercator,
  4352. transformation: function() {
  4353. var scale2 = 0.5 / (Math.PI * Mercator.R);
  4354. return toTransformation(scale2, 0.5, -scale2, 0.5);
  4355. }()
  4356. });
  4357. var EPSG4326 = extend({}, Earth, {
  4358. code: "EPSG:4326",
  4359. projection: LonLat,
  4360. transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)
  4361. });
  4362. var Simple = extend({}, CRS, {
  4363. projection: LonLat,
  4364. transformation: toTransformation(1, 0, -1, 0),
  4365. scale: function(zoom2) {
  4366. return Math.pow(2, zoom2);
  4367. },
  4368. zoom: function(scale2) {
  4369. return Math.log(scale2) / Math.LN2;
  4370. },
  4371. distance: function(latlng1, latlng2) {
  4372. var dx = latlng2.lng - latlng1.lng, dy = latlng2.lat - latlng1.lat;
  4373. return Math.sqrt(dx * dx + dy * dy);
  4374. },
  4375. infinite: true
  4376. });
  4377. CRS.Earth = Earth;
  4378. CRS.EPSG3395 = EPSG3395;
  4379. CRS.EPSG3857 = EPSG3857;
  4380. CRS.EPSG900913 = EPSG900913;
  4381. CRS.EPSG4326 = EPSG4326;
  4382. CRS.Simple = Simple;
  4383. var Layer = Evented.extend({
  4384. // Classes extending `L.Layer` will inherit the following options:
  4385. options: {
  4386. // @option pane: String = 'overlayPane'
  4387. // 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.
  4388. pane: "overlayPane",
  4389. // @option attribution: String = null
  4390. // 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.
  4391. attribution: null,
  4392. bubblingMouseEvents: true
  4393. },
  4394. /* @section
  4395. * Classes extending `L.Layer` will inherit the following methods:
  4396. *
  4397. * @method addTo(map: Map|LayerGroup): this
  4398. * Adds the layer to the given map or layer group.
  4399. */
  4400. addTo: function(map) {
  4401. map.addLayer(this);
  4402. return this;
  4403. },
  4404. // @method remove: this
  4405. // Removes the layer from the map it is currently active on.
  4406. remove: function() {
  4407. return this.removeFrom(this._map || this._mapToAdd);
  4408. },
  4409. // @method removeFrom(map: Map): this
  4410. // Removes the layer from the given map
  4411. //
  4412. // @alternative
  4413. // @method removeFrom(group: LayerGroup): this
  4414. // Removes the layer from the given `LayerGroup`
  4415. removeFrom: function(obj) {
  4416. if (obj) {
  4417. obj.removeLayer(this);
  4418. }
  4419. return this;
  4420. },
  4421. // @method getPane(name? : String): HTMLElement
  4422. // Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
  4423. getPane: function(name) {
  4424. return this._map.getPane(name ? this.options[name] || name : this.options.pane);
  4425. },
  4426. addInteractiveTarget: function(targetEl) {
  4427. this._map._targets[stamp(targetEl)] = this;
  4428. return this;
  4429. },
  4430. removeInteractiveTarget: function(targetEl) {
  4431. delete this._map._targets[stamp(targetEl)];
  4432. return this;
  4433. },
  4434. // @method getAttribution: String
  4435. // Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
  4436. getAttribution: function() {
  4437. return this.options.attribution;
  4438. },
  4439. _layerAdd: function(e) {
  4440. var map = e.target;
  4441. if (!map.hasLayer(this)) {
  4442. return;
  4443. }
  4444. this._map = map;
  4445. this._zoomAnimated = map._zoomAnimated;
  4446. if (this.getEvents) {
  4447. var events = this.getEvents();
  4448. map.on(events, this);
  4449. this.once("remove", function() {
  4450. map.off(events, this);
  4451. }, this);
  4452. }
  4453. this.onAdd(map);
  4454. this.fire("add");
  4455. map.fire("layeradd", { layer: this });
  4456. }
  4457. });
  4458. Map.include({
  4459. // @method addLayer(layer: Layer): this
  4460. // Adds the given layer to the map
  4461. addLayer: function(layer) {
  4462. if (!layer._layerAdd) {
  4463. throw new Error("The provided object is not a Layer.");
  4464. }
  4465. var id = stamp(layer);
  4466. if (this._layers[id]) {
  4467. return this;
  4468. }
  4469. this._layers[id] = layer;
  4470. layer._mapToAdd = this;
  4471. if (layer.beforeAdd) {
  4472. layer.beforeAdd(this);
  4473. }
  4474. this.whenReady(layer._layerAdd, layer);
  4475. return this;
  4476. },
  4477. // @method removeLayer(layer: Layer): this
  4478. // Removes the given layer from the map.
  4479. removeLayer: function(layer) {
  4480. var id = stamp(layer);
  4481. if (!this._layers[id]) {
  4482. return this;
  4483. }
  4484. if (this._loaded) {
  4485. layer.onRemove(this);
  4486. }
  4487. delete this._layers[id];
  4488. if (this._loaded) {
  4489. this.fire("layerremove", { layer });
  4490. layer.fire("remove");
  4491. }
  4492. layer._map = layer._mapToAdd = null;
  4493. return this;
  4494. },
  4495. // @method hasLayer(layer: Layer): Boolean
  4496. // Returns `true` if the given layer is currently added to the map
  4497. hasLayer: function(layer) {
  4498. return stamp(layer) in this._layers;
  4499. },
  4500. /* @method eachLayer(fn: Function, context?: Object): this
  4501. * Iterates over the layers of the map, optionally specifying context of the iterator function.
  4502. * ```
  4503. * map.eachLayer(function(layer){
  4504. * layer.bindPopup('Hello');
  4505. * });
  4506. * ```
  4507. */
  4508. eachLayer: function(method, context) {
  4509. for (var i in this._layers) {
  4510. method.call(context, this._layers[i]);
  4511. }
  4512. return this;
  4513. },
  4514. _addLayers: function(layers2) {
  4515. layers2 = layers2 ? isArray(layers2) ? layers2 : [layers2] : [];
  4516. for (var i = 0, len = layers2.length; i < len; i++) {
  4517. this.addLayer(layers2[i]);
  4518. }
  4519. },
  4520. _addZoomLimit: function(layer) {
  4521. if (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
  4522. this._zoomBoundLayers[stamp(layer)] = layer;
  4523. this._updateZoomLevels();
  4524. }
  4525. },
  4526. _removeZoomLimit: function(layer) {
  4527. var id = stamp(layer);
  4528. if (this._zoomBoundLayers[id]) {
  4529. delete this._zoomBoundLayers[id];
  4530. this._updateZoomLevels();
  4531. }
  4532. },
  4533. _updateZoomLevels: function() {
  4534. var minZoom = Infinity, maxZoom = -Infinity, oldZoomSpan = this._getZoomSpan();
  4535. for (var i in this._zoomBoundLayers) {
  4536. var options = this._zoomBoundLayers[i].options;
  4537. minZoom = options.minZoom === void 0 ? minZoom : Math.min(minZoom, options.minZoom);
  4538. maxZoom = options.maxZoom === void 0 ? maxZoom : Math.max(maxZoom, options.maxZoom);
  4539. }
  4540. this._layersMaxZoom = maxZoom === -Infinity ? void 0 : maxZoom;
  4541. this._layersMinZoom = minZoom === Infinity ? void 0 : minZoom;
  4542. if (oldZoomSpan !== this._getZoomSpan()) {
  4543. this.fire("zoomlevelschange");
  4544. }
  4545. if (this.options.maxZoom === void 0 && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
  4546. this.setZoom(this._layersMaxZoom);
  4547. }
  4548. if (this.options.minZoom === void 0 && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
  4549. this.setZoom(this._layersMinZoom);
  4550. }
  4551. }
  4552. });
  4553. var LayerGroup = Layer.extend({
  4554. initialize: function(layers2, options) {
  4555. setOptions(this, options);
  4556. this._layers = {};
  4557. var i, len;
  4558. if (layers2) {
  4559. for (i = 0, len = layers2.length; i < len; i++) {
  4560. this.addLayer(layers2[i]);
  4561. }
  4562. }
  4563. },
  4564. // @method addLayer(layer: Layer): this
  4565. // Adds the given layer to the group.
  4566. addLayer: function(layer) {
  4567. var id = this.getLayerId(layer);
  4568. this._layers[id] = layer;
  4569. if (this._map) {
  4570. this._map.addLayer(layer);
  4571. }
  4572. return this;
  4573. },
  4574. // @method removeLayer(layer: Layer): this
  4575. // Removes the given layer from the group.
  4576. // @alternative
  4577. // @method removeLayer(id: Number): this
  4578. // Removes the layer with the given internal ID from the group.
  4579. removeLayer: function(layer) {
  4580. var id = layer in this._layers ? layer : this.getLayerId(layer);
  4581. if (this._map && this._layers[id]) {
  4582. this._map.removeLayer(this._layers[id]);
  4583. }
  4584. delete this._layers[id];
  4585. return this;
  4586. },
  4587. // @method hasLayer(layer: Layer): Boolean
  4588. // Returns `true` if the given layer is currently added to the group.
  4589. // @alternative
  4590. // @method hasLayer(id: Number): Boolean
  4591. // Returns `true` if the given internal ID is currently added to the group.
  4592. hasLayer: function(layer) {
  4593. var layerId = typeof layer === "number" ? layer : this.getLayerId(layer);
  4594. return layerId in this._layers;
  4595. },
  4596. // @method clearLayers(): this
  4597. // Removes all the layers from the group.
  4598. clearLayers: function() {
  4599. return this.eachLayer(this.removeLayer, this);
  4600. },
  4601. // @method invoke(methodName: String, …): this
  4602. // Calls `methodName` on every layer contained in this group, passing any
  4603. // additional parameters. Has no effect if the layers contained do not
  4604. // implement `methodName`.
  4605. invoke: function(methodName) {
  4606. var args = Array.prototype.slice.call(arguments, 1), i, layer;
  4607. for (i in this._layers) {
  4608. layer = this._layers[i];
  4609. if (layer[methodName]) {
  4610. layer[methodName].apply(layer, args);
  4611. }
  4612. }
  4613. return this;
  4614. },
  4615. onAdd: function(map) {
  4616. this.eachLayer(map.addLayer, map);
  4617. },
  4618. onRemove: function(map) {
  4619. this.eachLayer(map.removeLayer, map);
  4620. },
  4621. // @method eachLayer(fn: Function, context?: Object): this
  4622. // Iterates over the layers of the group, optionally specifying context of the iterator function.
  4623. // ```js
  4624. // group.eachLayer(function (layer) {
  4625. // layer.bindPopup('Hello');
  4626. // });
  4627. // ```
  4628. eachLayer: function(method, context) {
  4629. for (var i in this._layers) {
  4630. method.call(context, this._layers[i]);
  4631. }
  4632. return this;
  4633. },
  4634. // @method getLayer(id: Number): Layer
  4635. // Returns the layer with the given internal ID.
  4636. getLayer: function(id) {
  4637. return this._layers[id];
  4638. },
  4639. // @method getLayers(): Layer[]
  4640. // Returns an array of all the layers added to the group.
  4641. getLayers: function() {
  4642. var layers2 = [];
  4643. this.eachLayer(layers2.push, layers2);
  4644. return layers2;
  4645. },
  4646. // @method setZIndex(zIndex: Number): this
  4647. // Calls `setZIndex` on every layer contained in this group, passing the z-index.
  4648. setZIndex: function(zIndex) {
  4649. return this.invoke("setZIndex", zIndex);
  4650. },
  4651. // @method getLayerId(layer: Layer): Number
  4652. // Returns the internal ID for a layer
  4653. getLayerId: function(layer) {
  4654. return stamp(layer);
  4655. }
  4656. });
  4657. var layerGroup = function(layers2, options) {
  4658. return new LayerGroup(layers2, options);
  4659. };
  4660. var FeatureGroup = LayerGroup.extend({
  4661. addLayer: function(layer) {
  4662. if (this.hasLayer(layer)) {
  4663. return this;
  4664. }
  4665. layer.addEventParent(this);
  4666. LayerGroup.prototype.addLayer.call(this, layer);
  4667. return this.fire("layeradd", { layer });
  4668. },
  4669. removeLayer: function(layer) {
  4670. if (!this.hasLayer(layer)) {
  4671. return this;
  4672. }
  4673. if (layer in this._layers) {
  4674. layer = this._layers[layer];
  4675. }
  4676. layer.removeEventParent(this);
  4677. LayerGroup.prototype.removeLayer.call(this, layer);
  4678. return this.fire("layerremove", { layer });
  4679. },
  4680. // @method setStyle(style: Path options): this
  4681. // Sets the given path options to each layer of the group that has a `setStyle` method.
  4682. setStyle: function(style2) {
  4683. return this.invoke("setStyle", style2);
  4684. },
  4685. // @method bringToFront(): this
  4686. // Brings the layer group to the top of all other layers
  4687. bringToFront: function() {
  4688. return this.invoke("bringToFront");
  4689. },
  4690. // @method bringToBack(): this
  4691. // Brings the layer group to the back of all other layers
  4692. bringToBack: function() {
  4693. return this.invoke("bringToBack");
  4694. },
  4695. // @method getBounds(): LatLngBounds
  4696. // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
  4697. getBounds: function() {
  4698. var bounds = new LatLngBounds();
  4699. for (var id in this._layers) {
  4700. var layer = this._layers[id];
  4701. bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
  4702. }
  4703. return bounds;
  4704. }
  4705. });
  4706. var featureGroup = function(layers2, options) {
  4707. return new FeatureGroup(layers2, options);
  4708. };
  4709. var Icon = Class.extend({
  4710. /* @section
  4711. * @aka Icon options
  4712. *
  4713. * @option iconUrl: String = null
  4714. * **(required)** The URL to the icon image (absolute or relative to your script path).
  4715. *
  4716. * @option iconRetinaUrl: String = null
  4717. * The URL to a retina sized version of the icon image (absolute or relative to your
  4718. * script path). Used for Retina screen devices.
  4719. *
  4720. * @option iconSize: Point = null
  4721. * Size of the icon image in pixels.
  4722. *
  4723. * @option iconAnchor: Point = null
  4724. * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
  4725. * will be aligned so that this point is at the marker's geographical location. Centered
  4726. * by default if size is specified, also can be set in CSS with negative margins.
  4727. *
  4728. * @option popupAnchor: Point = [0, 0]
  4729. * The coordinates of the point from which popups will "open", relative to the icon anchor.
  4730. *
  4731. * @option tooltipAnchor: Point = [0, 0]
  4732. * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
  4733. *
  4734. * @option shadowUrl: String = null
  4735. * The URL to the icon shadow image. If not specified, no shadow image will be created.
  4736. *
  4737. * @option shadowRetinaUrl: String = null
  4738. *
  4739. * @option shadowSize: Point = null
  4740. * Size of the shadow image in pixels.
  4741. *
  4742. * @option shadowAnchor: Point = null
  4743. * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
  4744. * as iconAnchor if not specified).
  4745. *
  4746. * @option className: String = ''
  4747. * A custom class name to assign to both icon and shadow images. Empty by default.
  4748. */
  4749. options: {
  4750. popupAnchor: [0, 0],
  4751. tooltipAnchor: [0, 0],
  4752. // @option crossOrigin: Boolean|String = false
  4753. // Whether the crossOrigin attribute will be added to the tiles.
  4754. // 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.
  4755. // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
  4756. crossOrigin: false
  4757. },
  4758. initialize: function(options) {
  4759. setOptions(this, options);
  4760. },
  4761. // @method createIcon(oldIcon?: HTMLElement): HTMLElement
  4762. // Called internally when the icon has to be shown, returns a `<img>` HTML element
  4763. // styled according to the options.
  4764. createIcon: function(oldIcon) {
  4765. return this._createIcon("icon", oldIcon);
  4766. },
  4767. // @method createShadow(oldIcon?: HTMLElement): HTMLElement
  4768. // As `createIcon`, but for the shadow beneath it.
  4769. createShadow: function(oldIcon) {
  4770. return this._createIcon("shadow", oldIcon);
  4771. },
  4772. _createIcon: function(name, oldIcon) {
  4773. var src = this._getIconUrl(name);
  4774. if (!src) {
  4775. if (name === "icon") {
  4776. throw new Error("iconUrl not set in Icon options (see the docs).");
  4777. }
  4778. return null;
  4779. }
  4780. var img = this._createImg(src, oldIcon && oldIcon.tagName === "IMG" ? oldIcon : null);
  4781. this._setIconStyles(img, name);
  4782. if (this.options.crossOrigin || this.options.crossOrigin === "") {
  4783. img.crossOrigin = this.options.crossOrigin === true ? "" : this.options.crossOrigin;
  4784. }
  4785. return img;
  4786. },
  4787. _setIconStyles: function(img, name) {
  4788. var options = this.options;
  4789. var sizeOption = options[name + "Size"];
  4790. if (typeof sizeOption === "number") {
  4791. sizeOption = [sizeOption, sizeOption];
  4792. }
  4793. var size = toPoint(sizeOption), anchor = toPoint(name === "shadow" && options.shadowAnchor || options.iconAnchor || size && size.divideBy(2, true));
  4794. img.className = "leaflet-marker-" + name + " " + (options.className || "");
  4795. if (anchor) {
  4796. img.style.marginLeft = -anchor.x + "px";
  4797. img.style.marginTop = -anchor.y + "px";
  4798. }
  4799. if (size) {
  4800. img.style.width = size.x + "px";
  4801. img.style.height = size.y + "px";
  4802. }
  4803. },
  4804. _createImg: function(src, el) {
  4805. el = el || document.createElement("img");
  4806. el.src = src;
  4807. return el;
  4808. },
  4809. _getIconUrl: function(name) {
  4810. return Browser.retina && this.options[name + "RetinaUrl"] || this.options[name + "Url"];
  4811. }
  4812. });
  4813. function icon(options) {
  4814. return new Icon(options);
  4815. }
  4816. var IconDefault = Icon.extend({
  4817. options: {
  4818. iconUrl: "marker-icon.png",
  4819. iconRetinaUrl: "marker-icon-2x.png",
  4820. shadowUrl: "marker-shadow.png",
  4821. iconSize: [25, 41],
  4822. iconAnchor: [12, 41],
  4823. popupAnchor: [1, -34],
  4824. tooltipAnchor: [16, -28],
  4825. shadowSize: [41, 41]
  4826. },
  4827. _getIconUrl: function(name) {
  4828. if (typeof IconDefault.imagePath !== "string") {
  4829. IconDefault.imagePath = this._detectIconPath();
  4830. }
  4831. return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
  4832. },
  4833. _stripUrl: function(path) {
  4834. var strip = function(str, re, idx) {
  4835. var match = re.exec(str);
  4836. return match && match[idx];
  4837. };
  4838. path = strip(path, /^url\((['"])?(.+)\1\)$/, 2);
  4839. return path && strip(path, /^(.*)marker-icon\.png$/, 1);
  4840. },
  4841. _detectIconPath: function() {
  4842. var el = create$1("div", "leaflet-default-icon-path", document.body);
  4843. var path = getStyle(el, "background-image") || getStyle(el, "backgroundImage");
  4844. document.body.removeChild(el);
  4845. path = this._stripUrl(path);
  4846. if (path) {
  4847. return path;
  4848. }
  4849. var link = document.querySelector('link[href$="leaflet.css"]');
  4850. if (!link) {
  4851. return "";
  4852. }
  4853. return link.href.substring(0, link.href.length - "leaflet.css".length - 1);
  4854. }
  4855. });
  4856. var MarkerDrag = Handler.extend({
  4857. initialize: function(marker2) {
  4858. this._marker = marker2;
  4859. },
  4860. addHooks: function() {
  4861. var icon2 = this._marker._icon;
  4862. if (!this._draggable) {
  4863. this._draggable = new Draggable(icon2, icon2, true);
  4864. }
  4865. this._draggable.on({
  4866. dragstart: this._onDragStart,
  4867. predrag: this._onPreDrag,
  4868. drag: this._onDrag,
  4869. dragend: this._onDragEnd
  4870. }, this).enable();
  4871. addClass(icon2, "leaflet-marker-draggable");
  4872. },
  4873. removeHooks: function() {
  4874. this._draggable.off({
  4875. dragstart: this._onDragStart,
  4876. predrag: this._onPreDrag,
  4877. drag: this._onDrag,
  4878. dragend: this._onDragEnd
  4879. }, this).disable();
  4880. if (this._marker._icon) {
  4881. removeClass(this._marker._icon, "leaflet-marker-draggable");
  4882. }
  4883. },
  4884. moved: function() {
  4885. return this._draggable && this._draggable._moved;
  4886. },
  4887. _adjustPan: function(e) {
  4888. var marker2 = this._marker, map = marker2._map, speed = this._marker.options.autoPanSpeed, padding = this._marker.options.autoPanPadding, iconPos = getPosition(marker2._icon), bounds = map.getPixelBounds(), origin = map.getPixelOrigin();
  4889. var panBounds = toBounds(
  4890. bounds.min._subtract(origin).add(padding),
  4891. bounds.max._subtract(origin).subtract(padding)
  4892. );
  4893. if (!panBounds.contains(iconPos)) {
  4894. var movement = toPoint(
  4895. (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) - (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
  4896. (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) - (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
  4897. ).multiplyBy(speed);
  4898. map.panBy(movement, { animate: false });
  4899. this._draggable._newPos._add(movement);
  4900. this._draggable._startPos._add(movement);
  4901. setPosition(marker2._icon, this._draggable._newPos);
  4902. this._onDrag(e);
  4903. this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
  4904. }
  4905. },
  4906. _onDragStart: function() {
  4907. this._oldLatLng = this._marker.getLatLng();
  4908. this._marker.closePopup && this._marker.closePopup();
  4909. this._marker.fire("movestart").fire("dragstart");
  4910. },
  4911. _onPreDrag: function(e) {
  4912. if (this._marker.options.autoPan) {
  4913. cancelAnimFrame(this._panRequest);
  4914. this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
  4915. }
  4916. },
  4917. _onDrag: function(e) {
  4918. var marker2 = this._marker, shadow = marker2._shadow, iconPos = getPosition(marker2._icon), latlng = marker2._map.layerPointToLatLng(iconPos);
  4919. if (shadow) {
  4920. setPosition(shadow, iconPos);
  4921. }
  4922. marker2._latlng = latlng;
  4923. e.latlng = latlng;
  4924. e.oldLatLng = this._oldLatLng;
  4925. marker2.fire("move", e).fire("drag", e);
  4926. },
  4927. _onDragEnd: function(e) {
  4928. cancelAnimFrame(this._panRequest);
  4929. delete this._oldLatLng;
  4930. this._marker.fire("moveend").fire("dragend", e);
  4931. }
  4932. });
  4933. var Marker = Layer.extend({
  4934. // @section
  4935. // @aka Marker options
  4936. options: {
  4937. // @option icon: Icon = *
  4938. // Icon instance to use for rendering the marker.
  4939. // See [Icon documentation](#L.Icon) for details on how to customize the marker icon.
  4940. // If not specified, a common instance of `L.Icon.Default` is used.
  4941. icon: new IconDefault(),
  4942. // Option inherited from "Interactive layer" abstract class
  4943. interactive: true,
  4944. // @option keyboard: Boolean = true
  4945. // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
  4946. keyboard: true,
  4947. // @option title: String = ''
  4948. // Text for the browser tooltip that appear on marker hover (no tooltip by default).
  4949. // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
  4950. title: "",
  4951. // @option alt: String = 'Marker'
  4952. // Text for the `alt` attribute of the icon image.
  4953. // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
  4954. alt: "Marker",
  4955. // @option zIndexOffset: Number = 0
  4956. // 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).
  4957. zIndexOffset: 0,
  4958. // @option opacity: Number = 1.0
  4959. // The opacity of the marker.
  4960. opacity: 1,
  4961. // @option riseOnHover: Boolean = false
  4962. // If `true`, the marker will get on top of others when you hover the mouse over it.
  4963. riseOnHover: false,
  4964. // @option riseOffset: Number = 250
  4965. // The z-index offset used for the `riseOnHover` feature.
  4966. riseOffset: 250,
  4967. // @option pane: String = 'markerPane'
  4968. // `Map pane` where the markers icon will be added.
  4969. pane: "markerPane",
  4970. // @option shadowPane: String = 'shadowPane'
  4971. // `Map pane` where the markers shadow will be added.
  4972. shadowPane: "shadowPane",
  4973. // @option bubblingMouseEvents: Boolean = false
  4974. // When `true`, a mouse event on this marker will trigger the same event on the map
  4975. // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
  4976. bubblingMouseEvents: false,
  4977. // @option autoPanOnFocus: Boolean = true
  4978. // When `true`, the map will pan whenever the marker is focused (via
  4979. // e.g. pressing `tab` on the keyboard) to ensure the marker is
  4980. // visible within the map's bounds
  4981. autoPanOnFocus: true,
  4982. // @section Draggable marker options
  4983. // @option draggable: Boolean = false
  4984. // Whether the marker is draggable with mouse/touch or not.
  4985. draggable: false,
  4986. // @option autoPan: Boolean = false
  4987. // Whether to pan the map when dragging this marker near its edge or not.
  4988. autoPan: false,
  4989. // @option autoPanPadding: Point = Point(50, 50)
  4990. // Distance (in pixels to the left/right and to the top/bottom) of the
  4991. // map edge to start panning the map.
  4992. autoPanPadding: [50, 50],
  4993. // @option autoPanSpeed: Number = 10
  4994. // Number of pixels the map should pan by.
  4995. autoPanSpeed: 10
  4996. },
  4997. /* @section
  4998. *
  4999. * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
  5000. */
  5001. initialize: function(latlng, options) {
  5002. setOptions(this, options);
  5003. this._latlng = toLatLng(latlng);
  5004. },
  5005. onAdd: function(map) {
  5006. this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
  5007. if (this._zoomAnimated) {
  5008. map.on("zoomanim", this._animateZoom, this);
  5009. }
  5010. this._initIcon();
  5011. this.update();
  5012. },
  5013. onRemove: function(map) {
  5014. if (this.dragging && this.dragging.enabled()) {
  5015. this.options.draggable = true;
  5016. this.dragging.removeHooks();
  5017. }
  5018. delete this.dragging;
  5019. if (this._zoomAnimated) {
  5020. map.off("zoomanim", this._animateZoom, this);
  5021. }
  5022. this._removeIcon();
  5023. this._removeShadow();
  5024. },
  5025. getEvents: function() {
  5026. return {
  5027. zoom: this.update,
  5028. viewreset: this.update
  5029. };
  5030. },
  5031. // @method getLatLng: LatLng
  5032. // Returns the current geographical position of the marker.
  5033. getLatLng: function() {
  5034. return this._latlng;
  5035. },
  5036. // @method setLatLng(latlng: LatLng): this
  5037. // Changes the marker position to the given point.
  5038. setLatLng: function(latlng) {
  5039. var oldLatLng = this._latlng;
  5040. this._latlng = toLatLng(latlng);
  5041. this.update();
  5042. return this.fire("move", { oldLatLng, latlng: this._latlng });
  5043. },
  5044. // @method setZIndexOffset(offset: Number): this
  5045. // Changes the [zIndex offset](#marker-zindexoffset) of the marker.
  5046. setZIndexOffset: function(offset) {
  5047. this.options.zIndexOffset = offset;
  5048. return this.update();
  5049. },
  5050. // @method getIcon: Icon
  5051. // Returns the current icon used by the marker
  5052. getIcon: function() {
  5053. return this.options.icon;
  5054. },
  5055. // @method setIcon(icon: Icon): this
  5056. // Changes the marker icon.
  5057. setIcon: function(icon2) {
  5058. this.options.icon = icon2;
  5059. if (this._map) {
  5060. this._initIcon();
  5061. this.update();
  5062. }
  5063. if (this._popup) {
  5064. this.bindPopup(this._popup, this._popup.options);
  5065. }
  5066. return this;
  5067. },
  5068. getElement: function() {
  5069. return this._icon;
  5070. },
  5071. update: function() {
  5072. if (this._icon && this._map) {
  5073. var pos = this._map.latLngToLayerPoint(this._latlng).round();
  5074. this._setPos(pos);
  5075. }
  5076. return this;
  5077. },
  5078. _initIcon: function() {
  5079. var options = this.options, classToAdd = "leaflet-zoom-" + (this._zoomAnimated ? "animated" : "hide");
  5080. var icon2 = options.icon.createIcon(this._icon), addIcon = false;
  5081. if (icon2 !== this._icon) {
  5082. if (this._icon) {
  5083. this._removeIcon();
  5084. }
  5085. addIcon = true;
  5086. if (options.title) {
  5087. icon2.title = options.title;
  5088. }
  5089. if (icon2.tagName === "IMG") {
  5090. icon2.alt = options.alt || "";
  5091. }
  5092. }
  5093. addClass(icon2, classToAdd);
  5094. if (options.keyboard) {
  5095. icon2.tabIndex = "0";
  5096. icon2.setAttribute("role", "button");
  5097. }
  5098. this._icon = icon2;
  5099. if (options.riseOnHover) {
  5100. this.on({
  5101. mouseover: this._bringToFront,
  5102. mouseout: this._resetZIndex
  5103. });
  5104. }
  5105. if (this.options.autoPanOnFocus) {
  5106. on(icon2, "focus", this._panOnFocus, this);
  5107. }
  5108. var newShadow = options.icon.createShadow(this._shadow), addShadow = false;
  5109. if (newShadow !== this._shadow) {
  5110. this._removeShadow();
  5111. addShadow = true;
  5112. }
  5113. if (newShadow) {
  5114. addClass(newShadow, classToAdd);
  5115. newShadow.alt = "";
  5116. }
  5117. this._shadow = newShadow;
  5118. if (options.opacity < 1) {
  5119. this._updateOpacity();
  5120. }
  5121. if (addIcon) {
  5122. this.getPane().appendChild(this._icon);
  5123. }
  5124. this._initInteraction();
  5125. if (newShadow && addShadow) {
  5126. this.getPane(options.shadowPane).appendChild(this._shadow);
  5127. }
  5128. },
  5129. _removeIcon: function() {
  5130. if (this.options.riseOnHover) {
  5131. this.off({
  5132. mouseover: this._bringToFront,
  5133. mouseout: this._resetZIndex
  5134. });
  5135. }
  5136. if (this.options.autoPanOnFocus) {
  5137. off(this._icon, "focus", this._panOnFocus, this);
  5138. }
  5139. remove(this._icon);
  5140. this.removeInteractiveTarget(this._icon);
  5141. this._icon = null;
  5142. },
  5143. _removeShadow: function() {
  5144. if (this._shadow) {
  5145. remove(this._shadow);
  5146. }
  5147. this._shadow = null;
  5148. },
  5149. _setPos: function(pos) {
  5150. if (this._icon) {
  5151. setPosition(this._icon, pos);
  5152. }
  5153. if (this._shadow) {
  5154. setPosition(this._shadow, pos);
  5155. }
  5156. this._zIndex = pos.y + this.options.zIndexOffset;
  5157. this._resetZIndex();
  5158. },
  5159. _updateZIndex: function(offset) {
  5160. if (this._icon) {
  5161. this._icon.style.zIndex = this._zIndex + offset;
  5162. }
  5163. },
  5164. _animateZoom: function(opt) {
  5165. var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
  5166. this._setPos(pos);
  5167. },
  5168. _initInteraction: function() {
  5169. if (!this.options.interactive) {
  5170. return;
  5171. }
  5172. addClass(this._icon, "leaflet-interactive");
  5173. this.addInteractiveTarget(this._icon);
  5174. if (MarkerDrag) {
  5175. var draggable = this.options.draggable;
  5176. if (this.dragging) {
  5177. draggable = this.dragging.enabled();
  5178. this.dragging.disable();
  5179. }
  5180. this.dragging = new MarkerDrag(this);
  5181. if (draggable) {
  5182. this.dragging.enable();
  5183. }
  5184. }
  5185. },
  5186. // @method setOpacity(opacity: Number): this
  5187. // Changes the opacity of the marker.
  5188. setOpacity: function(opacity) {
  5189. this.options.opacity = opacity;
  5190. if (this._map) {
  5191. this._updateOpacity();
  5192. }
  5193. return this;
  5194. },
  5195. _updateOpacity: function() {
  5196. var opacity = this.options.opacity;
  5197. if (this._icon) {
  5198. setOpacity(this._icon, opacity);
  5199. }
  5200. if (this._shadow) {
  5201. setOpacity(this._shadow, opacity);
  5202. }
  5203. },
  5204. _bringToFront: function() {
  5205. this._updateZIndex(this.options.riseOffset);
  5206. },
  5207. _resetZIndex: function() {
  5208. this._updateZIndex(0);
  5209. },
  5210. _panOnFocus: function() {
  5211. var map = this._map;
  5212. if (!map) {
  5213. return;
  5214. }
  5215. var iconOpts = this.options.icon.options;
  5216. var size = iconOpts.iconSize ? toPoint(iconOpts.iconSize) : toPoint(0, 0);
  5217. var anchor = iconOpts.iconAnchor ? toPoint(iconOpts.iconAnchor) : toPoint(0, 0);
  5218. map.panInside(this._latlng, {
  5219. paddingTopLeft: anchor,
  5220. paddingBottomRight: size.subtract(anchor)
  5221. });
  5222. },
  5223. _getPopupAnchor: function() {
  5224. return this.options.icon.options.popupAnchor;
  5225. },
  5226. _getTooltipAnchor: function() {
  5227. return this.options.icon.options.tooltipAnchor;
  5228. }
  5229. });
  5230. function marker(latlng, options) {
  5231. return new Marker(latlng, options);
  5232. }
  5233. var Path = Layer.extend({
  5234. // @section
  5235. // @aka Path options
  5236. options: {
  5237. // @option stroke: Boolean = true
  5238. // Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
  5239. stroke: true,
  5240. // @option color: String = '#3388ff'
  5241. // Stroke color
  5242. color: "#3388ff",
  5243. // @option weight: Number = 3
  5244. // Stroke width in pixels
  5245. weight: 3,
  5246. // @option opacity: Number = 1.0
  5247. // Stroke opacity
  5248. opacity: 1,
  5249. // @option lineCap: String= 'round'
  5250. // A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
  5251. lineCap: "round",
  5252. // @option lineJoin: String = 'round'
  5253. // A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
  5254. lineJoin: "round",
  5255. // @option dashArray: String = null
  5256. // 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).
  5257. dashArray: null,
  5258. // @option dashOffset: String = null
  5259. // 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).
  5260. dashOffset: null,
  5261. // @option fill: Boolean = depends
  5262. // Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
  5263. fill: false,
  5264. // @option fillColor: String = *
  5265. // Fill color. Defaults to the value of the [`color`](#path-color) option
  5266. fillColor: null,
  5267. // @option fillOpacity: Number = 0.2
  5268. // Fill opacity.
  5269. fillOpacity: 0.2,
  5270. // @option fillRule: String = 'evenodd'
  5271. // A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
  5272. fillRule: "evenodd",
  5273. // className: '',
  5274. // Option inherited from "Interactive layer" abstract class
  5275. interactive: true,
  5276. // @option bubblingMouseEvents: Boolean = true
  5277. // When `true`, a mouse event on this path will trigger the same event on the map
  5278. // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
  5279. bubblingMouseEvents: true
  5280. },
  5281. beforeAdd: function(map) {
  5282. this._renderer = map.getRenderer(this);
  5283. },
  5284. onAdd: function() {
  5285. this._renderer._initPath(this);
  5286. this._reset();
  5287. this._renderer._addPath(this);
  5288. },
  5289. onRemove: function() {
  5290. this._renderer._removePath(this);
  5291. },
  5292. // @method redraw(): this
  5293. // Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
  5294. redraw: function() {
  5295. if (this._map) {
  5296. this._renderer._updatePath(this);
  5297. }
  5298. return this;
  5299. },
  5300. // @method setStyle(style: Path options): this
  5301. // Changes the appearance of a Path based on the options in the `Path options` object.
  5302. setStyle: function(style2) {
  5303. setOptions(this, style2);
  5304. if (this._renderer) {
  5305. this._renderer._updateStyle(this);
  5306. if (this.options.stroke && style2 && Object.prototype.hasOwnProperty.call(style2, "weight")) {
  5307. this._updateBounds();
  5308. }
  5309. }
  5310. return this;
  5311. },
  5312. // @method bringToFront(): this
  5313. // Brings the layer to the top of all path layers.
  5314. bringToFront: function() {
  5315. if (this._renderer) {
  5316. this._renderer._bringToFront(this);
  5317. }
  5318. return this;
  5319. },
  5320. // @method bringToBack(): this
  5321. // Brings the layer to the bottom of all path layers.
  5322. bringToBack: function() {
  5323. if (this._renderer) {
  5324. this._renderer._bringToBack(this);
  5325. }
  5326. return this;
  5327. },
  5328. getElement: function() {
  5329. return this._path;
  5330. },
  5331. _reset: function() {
  5332. this._project();
  5333. this._update();
  5334. },
  5335. _clickTolerance: function() {
  5336. return (this.options.stroke ? this.options.weight / 2 : 0) + (this._renderer.options.tolerance || 0);
  5337. }
  5338. });
  5339. var CircleMarker = Path.extend({
  5340. // @section
  5341. // @aka CircleMarker options
  5342. options: {
  5343. fill: true,
  5344. // @option radius: Number = 10
  5345. // Radius of the circle marker, in pixels
  5346. radius: 10
  5347. },
  5348. initialize: function(latlng, options) {
  5349. setOptions(this, options);
  5350. this._latlng = toLatLng(latlng);
  5351. this._radius = this.options.radius;
  5352. },
  5353. // @method setLatLng(latLng: LatLng): this
  5354. // Sets the position of a circle marker to a new location.
  5355. setLatLng: function(latlng) {
  5356. var oldLatLng = this._latlng;
  5357. this._latlng = toLatLng(latlng);
  5358. this.redraw();
  5359. return this.fire("move", { oldLatLng, latlng: this._latlng });
  5360. },
  5361. // @method getLatLng(): LatLng
  5362. // Returns the current geographical position of the circle marker
  5363. getLatLng: function() {
  5364. return this._latlng;
  5365. },
  5366. // @method setRadius(radius: Number): this
  5367. // Sets the radius of a circle marker. Units are in pixels.
  5368. setRadius: function(radius) {
  5369. this.options.radius = this._radius = radius;
  5370. return this.redraw();
  5371. },
  5372. // @method getRadius(): Number
  5373. // Returns the current radius of the circle
  5374. getRadius: function() {
  5375. return this._radius;
  5376. },
  5377. setStyle: function(options) {
  5378. var radius = options && options.radius || this._radius;
  5379. Path.prototype.setStyle.call(this, options);
  5380. this.setRadius(radius);
  5381. return this;
  5382. },
  5383. _project: function() {
  5384. this._point = this._map.latLngToLayerPoint(this._latlng);
  5385. this._updateBounds();
  5386. },
  5387. _updateBounds: function() {
  5388. var r = this._radius, r2 = this._radiusY || r, w = this._clickTolerance(), p = [r + w, r2 + w];
  5389. this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
  5390. },
  5391. _update: function() {
  5392. if (this._map) {
  5393. this._updatePath();
  5394. }
  5395. },
  5396. _updatePath: function() {
  5397. this._renderer._updateCircle(this);
  5398. },
  5399. _empty: function() {
  5400. return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
  5401. },
  5402. // Needed by the `Canvas` renderer for interactivity
  5403. _containsPoint: function(p) {
  5404. return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
  5405. }
  5406. });
  5407. function circleMarker(latlng, options) {
  5408. return new CircleMarker(latlng, options);
  5409. }
  5410. var Circle = CircleMarker.extend({
  5411. initialize: function(latlng, options, legacyOptions) {
  5412. if (typeof options === "number") {
  5413. options = extend({}, legacyOptions, { radius: options });
  5414. }
  5415. setOptions(this, options);
  5416. this._latlng = toLatLng(latlng);
  5417. if (isNaN(this.options.radius)) {
  5418. throw new Error("Circle radius cannot be NaN");
  5419. }
  5420. this._mRadius = this.options.radius;
  5421. },
  5422. // @method setRadius(radius: Number): this
  5423. // Sets the radius of a circle. Units are in meters.
  5424. setRadius: function(radius) {
  5425. this._mRadius = radius;
  5426. return this.redraw();
  5427. },
  5428. // @method getRadius(): Number
  5429. // Returns the current radius of a circle. Units are in meters.
  5430. getRadius: function() {
  5431. return this._mRadius;
  5432. },
  5433. // @method getBounds(): LatLngBounds
  5434. // Returns the `LatLngBounds` of the path.
  5435. getBounds: function() {
  5436. var half = [this._radius, this._radiusY || this._radius];
  5437. return new LatLngBounds(
  5438. this._map.layerPointToLatLng(this._point.subtract(half)),
  5439. this._map.layerPointToLatLng(this._point.add(half))
  5440. );
  5441. },
  5442. setStyle: Path.prototype.setStyle,
  5443. _project: function() {
  5444. var lng = this._latlng.lng, lat = this._latlng.lat, map = this._map, crs = map.options.crs;
  5445. if (crs.distance === Earth.distance) {
  5446. var d = Math.PI / 180, latR = this._mRadius / Earth.R / d, top = map.project([lat + latR, lng]), bottom = map.project([lat - latR, lng]), p = top.add(bottom).divideBy(2), lat2 = map.unproject(p).lat, lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) / (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
  5447. if (isNaN(lngR) || lngR === 0) {
  5448. lngR = latR / Math.cos(Math.PI / 180 * lat);
  5449. }
  5450. this._point = p.subtract(map.getPixelOrigin());
  5451. this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
  5452. this._radiusY = p.y - top.y;
  5453. } else {
  5454. var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
  5455. this._point = map.latLngToLayerPoint(this._latlng);
  5456. this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
  5457. }
  5458. this._updateBounds();
  5459. }
  5460. });
  5461. function circle(latlng, options, legacyOptions) {
  5462. return new Circle(latlng, options, legacyOptions);
  5463. }
  5464. var Polyline = Path.extend({
  5465. // @section
  5466. // @aka Polyline options
  5467. options: {
  5468. // @option smoothFactor: Number = 1.0
  5469. // How much to simplify the polyline on each zoom level. More means
  5470. // better performance and smoother look, and less means more accurate representation.
  5471. smoothFactor: 1,
  5472. // @option noClip: Boolean = false
  5473. // Disable polyline clipping.
  5474. noClip: false
  5475. },
  5476. initialize: function(latlngs, options) {
  5477. setOptions(this, options);
  5478. this._setLatLngs(latlngs);
  5479. },
  5480. // @method getLatLngs(): LatLng[]
  5481. // Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
  5482. getLatLngs: function() {
  5483. return this._latlngs;
  5484. },
  5485. // @method setLatLngs(latlngs: LatLng[]): this
  5486. // Replaces all the points in the polyline with the given array of geographical points.
  5487. setLatLngs: function(latlngs) {
  5488. this._setLatLngs(latlngs);
  5489. return this.redraw();
  5490. },
  5491. // @method isEmpty(): Boolean
  5492. // Returns `true` if the Polyline has no LatLngs.
  5493. isEmpty: function() {
  5494. return !this._latlngs.length;
  5495. },
  5496. // @method closestLayerPoint(p: Point): Point
  5497. // Returns the point closest to `p` on the Polyline.
  5498. closestLayerPoint: function(p) {
  5499. var minDistance = Infinity, minPoint = null, closest = _sqClosestPointOnSegment, p1, p2;
  5500. for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
  5501. var points = this._parts[j];
  5502. for (var i = 1, len = points.length; i < len; i++) {
  5503. p1 = points[i - 1];
  5504. p2 = points[i];
  5505. var sqDist = closest(p, p1, p2, true);
  5506. if (sqDist < minDistance) {
  5507. minDistance = sqDist;
  5508. minPoint = closest(p, p1, p2);
  5509. }
  5510. }
  5511. }
  5512. if (minPoint) {
  5513. minPoint.distance = Math.sqrt(minDistance);
  5514. }
  5515. return minPoint;
  5516. },
  5517. // @method getCenter(): LatLng
  5518. // Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline.
  5519. getCenter: function() {
  5520. if (!this._map) {
  5521. throw new Error("Must add layer to map before using getCenter()");
  5522. }
  5523. return polylineCenter(this._defaultShape(), this._map.options.crs);
  5524. },
  5525. // @method getBounds(): LatLngBounds
  5526. // Returns the `LatLngBounds` of the path.
  5527. getBounds: function() {
  5528. return this._bounds;
  5529. },
  5530. // @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this
  5531. // Adds a given point to the polyline. By default, adds to the first ring of
  5532. // the polyline in case of a multi-polyline, but can be overridden by passing
  5533. // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
  5534. addLatLng: function(latlng, latlngs) {
  5535. latlngs = latlngs || this._defaultShape();
  5536. latlng = toLatLng(latlng);
  5537. latlngs.push(latlng);
  5538. this._bounds.extend(latlng);
  5539. return this.redraw();
  5540. },
  5541. _setLatLngs: function(latlngs) {
  5542. this._bounds = new LatLngBounds();
  5543. this._latlngs = this._convertLatLngs(latlngs);
  5544. },
  5545. _defaultShape: function() {
  5546. return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
  5547. },
  5548. // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
  5549. _convertLatLngs: function(latlngs) {
  5550. var result = [], flat = isFlat(latlngs);
  5551. for (var i = 0, len = latlngs.length; i < len; i++) {
  5552. if (flat) {
  5553. result[i] = toLatLng(latlngs[i]);
  5554. this._bounds.extend(result[i]);
  5555. } else {
  5556. result[i] = this._convertLatLngs(latlngs[i]);
  5557. }
  5558. }
  5559. return result;
  5560. },
  5561. _project: function() {
  5562. var pxBounds = new Bounds();
  5563. this._rings = [];
  5564. this._projectLatlngs(this._latlngs, this._rings, pxBounds);
  5565. if (this._bounds.isValid() && pxBounds.isValid()) {
  5566. this._rawPxBounds = pxBounds;
  5567. this._updateBounds();
  5568. }
  5569. },
  5570. _updateBounds: function() {
  5571. var w = this._clickTolerance(), p = new Point(w, w);
  5572. if (!this._rawPxBounds) {
  5573. return;
  5574. }
  5575. this._pxBounds = new Bounds([
  5576. this._rawPxBounds.min.subtract(p),
  5577. this._rawPxBounds.max.add(p)
  5578. ]);
  5579. },
  5580. // recursively turns latlngs into a set of rings with projected coordinates
  5581. _projectLatlngs: function(latlngs, result, projectedBounds) {
  5582. var flat = latlngs[0] instanceof LatLng, len = latlngs.length, i, ring;
  5583. if (flat) {
  5584. ring = [];
  5585. for (i = 0; i < len; i++) {
  5586. ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
  5587. projectedBounds.extend(ring[i]);
  5588. }
  5589. result.push(ring);
  5590. } else {
  5591. for (i = 0; i < len; i++) {
  5592. this._projectLatlngs(latlngs[i], result, projectedBounds);
  5593. }
  5594. }
  5595. },
  5596. // clip polyline by renderer bounds so that we have less to render for performance
  5597. _clipPoints: function() {
  5598. var bounds = this._renderer._bounds;
  5599. this._parts = [];
  5600. if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
  5601. return;
  5602. }
  5603. if (this.options.noClip) {
  5604. this._parts = this._rings;
  5605. return;
  5606. }
  5607. var parts = this._parts, i, j, k, len, len2, segment, points;
  5608. for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
  5609. points = this._rings[i];
  5610. for (j = 0, len2 = points.length; j < len2 - 1; j++) {
  5611. segment = clipSegment(points[j], points[j + 1], bounds, j, true);
  5612. if (!segment) {
  5613. continue;
  5614. }
  5615. parts[k] = parts[k] || [];
  5616. parts[k].push(segment[0]);
  5617. if (segment[1] !== points[j + 1] || j === len2 - 2) {
  5618. parts[k].push(segment[1]);
  5619. k++;
  5620. }
  5621. }
  5622. }
  5623. },
  5624. // simplify each clipped part of the polyline for performance
  5625. _simplifyPoints: function() {
  5626. var parts = this._parts, tolerance = this.options.smoothFactor;
  5627. for (var i = 0, len = parts.length; i < len; i++) {
  5628. parts[i] = simplify(parts[i], tolerance);
  5629. }
  5630. },
  5631. _update: function() {
  5632. if (!this._map) {
  5633. return;
  5634. }
  5635. this._clipPoints();
  5636. this._simplifyPoints();
  5637. this._updatePath();
  5638. },
  5639. _updatePath: function() {
  5640. this._renderer._updatePoly(this);
  5641. },
  5642. // Needed by the `Canvas` renderer for interactivity
  5643. _containsPoint: function(p, closed) {
  5644. var i, j, k, len, len2, part, w = this._clickTolerance();
  5645. if (!this._pxBounds || !this._pxBounds.contains(p)) {
  5646. return false;
  5647. }
  5648. for (i = 0, len = this._parts.length; i < len; i++) {
  5649. part = this._parts[i];
  5650. for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
  5651. if (!closed && j === 0) {
  5652. continue;
  5653. }
  5654. if (pointToSegmentDistance(p, part[k], part[j]) <= w) {
  5655. return true;
  5656. }
  5657. }
  5658. }
  5659. return false;
  5660. }
  5661. });
  5662. function polyline(latlngs, options) {
  5663. return new Polyline(latlngs, options);
  5664. }
  5665. Polyline._flat = _flat;
  5666. var Polygon = Polyline.extend({
  5667. options: {
  5668. fill: true
  5669. },
  5670. isEmpty: function() {
  5671. return !this._latlngs.length || !this._latlngs[0].length;
  5672. },
  5673. // @method getCenter(): LatLng
  5674. // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon.
  5675. getCenter: function() {
  5676. if (!this._map) {
  5677. throw new Error("Must add layer to map before using getCenter()");
  5678. }
  5679. return polygonCenter(this._defaultShape(), this._map.options.crs);
  5680. },
  5681. _convertLatLngs: function(latlngs) {
  5682. var result = Polyline.prototype._convertLatLngs.call(this, latlngs), len = result.length;
  5683. if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {
  5684. result.pop();
  5685. }
  5686. return result;
  5687. },
  5688. _setLatLngs: function(latlngs) {
  5689. Polyline.prototype._setLatLngs.call(this, latlngs);
  5690. if (isFlat(this._latlngs)) {
  5691. this._latlngs = [this._latlngs];
  5692. }
  5693. },
  5694. _defaultShape: function() {
  5695. return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
  5696. },
  5697. _clipPoints: function() {
  5698. var bounds = this._renderer._bounds, w = this.options.weight, p = new Point(w, w);
  5699. bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));
  5700. this._parts = [];
  5701. if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
  5702. return;
  5703. }
  5704. if (this.options.noClip) {
  5705. this._parts = this._rings;
  5706. return;
  5707. }
  5708. for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
  5709. clipped = clipPolygon(this._rings[i], bounds, true);
  5710. if (clipped.length) {
  5711. this._parts.push(clipped);
  5712. }
  5713. }
  5714. },
  5715. _updatePath: function() {
  5716. this._renderer._updatePoly(this, true);
  5717. },
  5718. // Needed by the `Canvas` renderer for interactivity
  5719. _containsPoint: function(p) {
  5720. var inside = false, part, p1, p2, i, j, k, len, len2;
  5721. if (!this._pxBounds || !this._pxBounds.contains(p)) {
  5722. return false;
  5723. }
  5724. for (i = 0, len = this._parts.length; i < len; i++) {
  5725. part = this._parts[i];
  5726. for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
  5727. p1 = part[j];
  5728. p2 = part[k];
  5729. if (p1.y > p.y !== p2.y > p.y && p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x) {
  5730. inside = !inside;
  5731. }
  5732. }
  5733. }
  5734. return inside || Polyline.prototype._containsPoint.call(this, p, true);
  5735. }
  5736. });
  5737. function polygon(latlngs, options) {
  5738. return new Polygon(latlngs, options);
  5739. }
  5740. var GeoJSON = FeatureGroup.extend({
  5741. /* @section
  5742. * @aka GeoJSON options
  5743. *
  5744. * @option pointToLayer: Function = *
  5745. * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
  5746. * called when data is added, passing the GeoJSON point feature and its `LatLng`.
  5747. * The default is to spawn a default `Marker`:
  5748. * ```js
  5749. * function(geoJsonPoint, latlng) {
  5750. * return L.marker(latlng);
  5751. * }
  5752. * ```
  5753. *
  5754. * @option style: Function = *
  5755. * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
  5756. * called internally when data is added.
  5757. * The default value is to not override any defaults:
  5758. * ```js
  5759. * function (geoJsonFeature) {
  5760. * return {}
  5761. * }
  5762. * ```
  5763. *
  5764. * @option onEachFeature: Function = *
  5765. * A `Function` that will be called once for each created `Feature`, after it has
  5766. * been created and styled. Useful for attaching events and popups to features.
  5767. * The default is to do nothing with the newly created layers:
  5768. * ```js
  5769. * function (feature, layer) {}
  5770. * ```
  5771. *
  5772. * @option filter: Function = *
  5773. * A `Function` that will be used to decide whether to include a feature or not.
  5774. * The default is to include all features:
  5775. * ```js
  5776. * function (geoJsonFeature) {
  5777. * return true;
  5778. * }
  5779. * ```
  5780. * Note: dynamically changing the `filter` option will have effect only on newly
  5781. * added data. It will _not_ re-evaluate already included features.
  5782. *
  5783. * @option coordsToLatLng: Function = *
  5784. * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
  5785. * The default is the `coordsToLatLng` static method.
  5786. *
  5787. * @option markersInheritOptions: Boolean = false
  5788. * Whether default Markers for "Point" type Features inherit from group options.
  5789. */
  5790. initialize: function(geojson, options) {
  5791. setOptions(this, options);
  5792. this._layers = {};
  5793. if (geojson) {
  5794. this.addData(geojson);
  5795. }
  5796. },
  5797. // @method addData( <GeoJSON> data ): this
  5798. // Adds a GeoJSON object to the layer.
  5799. addData: function(geojson) {
  5800. var features = isArray(geojson) ? geojson : geojson.features, i, len, feature;
  5801. if (features) {
  5802. for (i = 0, len = features.length; i < len; i++) {
  5803. feature = features[i];
  5804. if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
  5805. this.addData(feature);
  5806. }
  5807. }
  5808. return this;
  5809. }
  5810. var options = this.options;
  5811. if (options.filter && !options.filter(geojson)) {
  5812. return this;
  5813. }
  5814. var layer = geometryToLayer(geojson, options);
  5815. if (!layer) {
  5816. return this;
  5817. }
  5818. layer.feature = asFeature(geojson);
  5819. layer.defaultOptions = layer.options;
  5820. this.resetStyle(layer);
  5821. if (options.onEachFeature) {
  5822. options.onEachFeature(geojson, layer);
  5823. }
  5824. return this.addLayer(layer);
  5825. },
  5826. // @method resetStyle( <Path> layer? ): this
  5827. // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
  5828. // If `layer` is omitted, the style of all features in the current layer is reset.
  5829. resetStyle: function(layer) {
  5830. if (layer === void 0) {
  5831. return this.eachLayer(this.resetStyle, this);
  5832. }
  5833. layer.options = extend({}, layer.defaultOptions);
  5834. this._setLayerStyle(layer, this.options.style);
  5835. return this;
  5836. },
  5837. // @method setStyle( <Function> style ): this
  5838. // Changes styles of GeoJSON vector layers with the given style function.
  5839. setStyle: function(style2) {
  5840. return this.eachLayer(function(layer) {
  5841. this._setLayerStyle(layer, style2);
  5842. }, this);
  5843. },
  5844. _setLayerStyle: function(layer, style2) {
  5845. if (layer.setStyle) {
  5846. if (typeof style2 === "function") {
  5847. style2 = style2(layer.feature);
  5848. }
  5849. layer.setStyle(style2);
  5850. }
  5851. }
  5852. });
  5853. function geometryToLayer(geojson, options) {
  5854. var geometry = geojson.type === "Feature" ? geojson.geometry : geojson, coords = geometry ? geometry.coordinates : null, layers2 = [], pointToLayer = options && options.pointToLayer, _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng, latlng, latlngs, i, len;
  5855. if (!coords && !geometry) {
  5856. return null;
  5857. }
  5858. switch (geometry.type) {
  5859. case "Point":
  5860. latlng = _coordsToLatLng(coords);
  5861. return _pointToLayer(pointToLayer, geojson, latlng, options);
  5862. case "MultiPoint":
  5863. for (i = 0, len = coords.length; i < len; i++) {
  5864. latlng = _coordsToLatLng(coords[i]);
  5865. layers2.push(_pointToLayer(pointToLayer, geojson, latlng, options));
  5866. }
  5867. return new FeatureGroup(layers2);
  5868. case "LineString":
  5869. case "MultiLineString":
  5870. latlngs = coordsToLatLngs(coords, geometry.type === "LineString" ? 0 : 1, _coordsToLatLng);
  5871. return new Polyline(latlngs, options);
  5872. case "Polygon":
  5873. case "MultiPolygon":
  5874. latlngs = coordsToLatLngs(coords, geometry.type === "Polygon" ? 1 : 2, _coordsToLatLng);
  5875. return new Polygon(latlngs, options);
  5876. case "GeometryCollection":
  5877. for (i = 0, len = geometry.geometries.length; i < len; i++) {
  5878. var geoLayer = geometryToLayer({
  5879. geometry: geometry.geometries[i],
  5880. type: "Feature",
  5881. properties: geojson.properties
  5882. }, options);
  5883. if (geoLayer) {
  5884. layers2.push(geoLayer);
  5885. }
  5886. }
  5887. return new FeatureGroup(layers2);
  5888. case "FeatureCollection":
  5889. for (i = 0, len = geometry.features.length; i < len; i++) {
  5890. var featureLayer = geometryToLayer(geometry.features[i], options);
  5891. if (featureLayer) {
  5892. layers2.push(featureLayer);
  5893. }
  5894. }
  5895. return new FeatureGroup(layers2);
  5896. default:
  5897. throw new Error("Invalid GeoJSON object.");
  5898. }
  5899. }
  5900. function _pointToLayer(pointToLayerFn, geojson, latlng, options) {
  5901. return pointToLayerFn ? pointToLayerFn(geojson, latlng) : new Marker(latlng, options && options.markersInheritOptions && options);
  5902. }
  5903. function coordsToLatLng(coords) {
  5904. return new LatLng(coords[1], coords[0], coords[2]);
  5905. }
  5906. function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
  5907. var latlngs = [];
  5908. for (var i = 0, len = coords.length, latlng; i < len; i++) {
  5909. latlng = levelsDeep ? coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) : (_coordsToLatLng || coordsToLatLng)(coords[i]);
  5910. latlngs.push(latlng);
  5911. }
  5912. return latlngs;
  5913. }
  5914. function latLngToCoords(latlng, precision) {
  5915. latlng = toLatLng(latlng);
  5916. return latlng.alt !== void 0 ? [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] : [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
  5917. }
  5918. function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
  5919. var coords = [];
  5920. for (var i = 0, len = latlngs.length; i < len; i++) {
  5921. coords.push(levelsDeep ? latLngsToCoords(latlngs[i], isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) : latLngToCoords(latlngs[i], precision));
  5922. }
  5923. if (!levelsDeep && closed && coords.length > 0) {
  5924. coords.push(coords[0].slice());
  5925. }
  5926. return coords;
  5927. }
  5928. function getFeature(layer, newGeometry) {
  5929. return layer.feature ? extend({}, layer.feature, { geometry: newGeometry }) : asFeature(newGeometry);
  5930. }
  5931. function asFeature(geojson) {
  5932. if (geojson.type === "Feature" || geojson.type === "FeatureCollection") {
  5933. return geojson;
  5934. }
  5935. return {
  5936. type: "Feature",
  5937. properties: {},
  5938. geometry: geojson
  5939. };
  5940. }
  5941. var PointToGeoJSON = {
  5942. toGeoJSON: function(precision) {
  5943. return getFeature(this, {
  5944. type: "Point",
  5945. coordinates: latLngToCoords(this.getLatLng(), precision)
  5946. });
  5947. }
  5948. };
  5949. Marker.include(PointToGeoJSON);
  5950. Circle.include(PointToGeoJSON);
  5951. CircleMarker.include(PointToGeoJSON);
  5952. Polyline.include({
  5953. toGeoJSON: function(precision) {
  5954. var multi = !isFlat(this._latlngs);
  5955. var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
  5956. return getFeature(this, {
  5957. type: (multi ? "Multi" : "") + "LineString",
  5958. coordinates: coords
  5959. });
  5960. }
  5961. });
  5962. Polygon.include({
  5963. toGeoJSON: function(precision) {
  5964. var holes = !isFlat(this._latlngs), multi = holes && !isFlat(this._latlngs[0]);
  5965. var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
  5966. if (!holes) {
  5967. coords = [coords];
  5968. }
  5969. return getFeature(this, {
  5970. type: (multi ? "Multi" : "") + "Polygon",
  5971. coordinates: coords
  5972. });
  5973. }
  5974. });
  5975. LayerGroup.include({
  5976. toMultiPoint: function(precision) {
  5977. var coords = [];
  5978. this.eachLayer(function(layer) {
  5979. coords.push(layer.toGeoJSON(precision).geometry.coordinates);
  5980. });
  5981. return getFeature(this, {
  5982. type: "MultiPoint",
  5983. coordinates: coords
  5984. });
  5985. },
  5986. // @method toGeoJSON(precision?: Number|false): Object
  5987. // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
  5988. // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
  5989. toGeoJSON: function(precision) {
  5990. var type = this.feature && this.feature.geometry && this.feature.geometry.type;
  5991. if (type === "MultiPoint") {
  5992. return this.toMultiPoint(precision);
  5993. }
  5994. var isGeometryCollection = type === "GeometryCollection", jsons = [];
  5995. this.eachLayer(function(layer) {
  5996. if (layer.toGeoJSON) {
  5997. var json = layer.toGeoJSON(precision);
  5998. if (isGeometryCollection) {
  5999. jsons.push(json.geometry);
  6000. } else {
  6001. var feature = asFeature(json);
  6002. if (feature.type === "FeatureCollection") {
  6003. jsons.push.apply(jsons, feature.features);
  6004. } else {
  6005. jsons.push(feature);
  6006. }
  6007. }
  6008. }
  6009. });
  6010. if (isGeometryCollection) {
  6011. return getFeature(this, {
  6012. geometries: jsons,
  6013. type: "GeometryCollection"
  6014. });
  6015. }
  6016. return {
  6017. type: "FeatureCollection",
  6018. features: jsons
  6019. };
  6020. }
  6021. });
  6022. function geoJSON(geojson, options) {
  6023. return new GeoJSON(geojson, options);
  6024. }
  6025. var geoJson = geoJSON;
  6026. var ImageOverlay = Layer.extend({
  6027. // @section
  6028. // @aka ImageOverlay options
  6029. options: {
  6030. // @option opacity: Number = 1.0
  6031. // The opacity of the image overlay.
  6032. opacity: 1,
  6033. // @option alt: String = ''
  6034. // Text for the `alt` attribute of the image (useful for accessibility).
  6035. alt: "",
  6036. // @option interactive: Boolean = false
  6037. // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
  6038. interactive: false,
  6039. // @option crossOrigin: Boolean|String = false
  6040. // Whether the crossOrigin attribute will be added to the image.
  6041. // 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.
  6042. // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
  6043. crossOrigin: false,
  6044. // @option errorOverlayUrl: String = ''
  6045. // URL to the overlay image to show in place of the overlay that failed to load.
  6046. errorOverlayUrl: "",
  6047. // @option zIndex: Number = 1
  6048. // The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
  6049. zIndex: 1,
  6050. // @option className: String = ''
  6051. // A custom class name to assign to the image. Empty by default.
  6052. className: ""
  6053. },
  6054. initialize: function(url, bounds, options) {
  6055. this._url = url;
  6056. this._bounds = toLatLngBounds(bounds);
  6057. setOptions(this, options);
  6058. },
  6059. onAdd: function() {
  6060. if (!this._image) {
  6061. this._initImage();
  6062. if (this.options.opacity < 1) {
  6063. this._updateOpacity();
  6064. }
  6065. }
  6066. if (this.options.interactive) {
  6067. addClass(this._image, "leaflet-interactive");
  6068. this.addInteractiveTarget(this._image);
  6069. }
  6070. this.getPane().appendChild(this._image);
  6071. this._reset();
  6072. },
  6073. onRemove: function() {
  6074. remove(this._image);
  6075. if (this.options.interactive) {
  6076. this.removeInteractiveTarget(this._image);
  6077. }
  6078. },
  6079. // @method setOpacity(opacity: Number): this
  6080. // Sets the opacity of the overlay.
  6081. setOpacity: function(opacity) {
  6082. this.options.opacity = opacity;
  6083. if (this._image) {
  6084. this._updateOpacity();
  6085. }
  6086. return this;
  6087. },
  6088. setStyle: function(styleOpts) {
  6089. if (styleOpts.opacity) {
  6090. this.setOpacity(styleOpts.opacity);
  6091. }
  6092. return this;
  6093. },
  6094. // @method bringToFront(): this
  6095. // Brings the layer to the top of all overlays.
  6096. bringToFront: function() {
  6097. if (this._map) {
  6098. toFront(this._image);
  6099. }
  6100. return this;
  6101. },
  6102. // @method bringToBack(): this
  6103. // Brings the layer to the bottom of all overlays.
  6104. bringToBack: function() {
  6105. if (this._map) {
  6106. toBack(this._image);
  6107. }
  6108. return this;
  6109. },
  6110. // @method setUrl(url: String): this
  6111. // Changes the URL of the image.
  6112. setUrl: function(url) {
  6113. this._url = url;
  6114. if (this._image) {
  6115. this._image.src = url;
  6116. }
  6117. return this;
  6118. },
  6119. // @method setBounds(bounds: LatLngBounds): this
  6120. // Update the bounds that this ImageOverlay covers
  6121. setBounds: function(bounds) {
  6122. this._bounds = toLatLngBounds(bounds);
  6123. if (this._map) {
  6124. this._reset();
  6125. }
  6126. return this;
  6127. },
  6128. getEvents: function() {
  6129. var events = {
  6130. zoom: this._reset,
  6131. viewreset: this._reset
  6132. };
  6133. if (this._zoomAnimated) {
  6134. events.zoomanim = this._animateZoom;
  6135. }
  6136. return events;
  6137. },
  6138. // @method setZIndex(value: Number): this
  6139. // Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
  6140. setZIndex: function(value) {
  6141. this.options.zIndex = value;
  6142. this._updateZIndex();
  6143. return this;
  6144. },
  6145. // @method getBounds(): LatLngBounds
  6146. // Get the bounds that this ImageOverlay covers
  6147. getBounds: function() {
  6148. return this._bounds;
  6149. },
  6150. // @method getElement(): HTMLElement
  6151. // Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
  6152. // used by this overlay.
  6153. getElement: function() {
  6154. return this._image;
  6155. },
  6156. _initImage: function() {
  6157. var wasElementSupplied = this._url.tagName === "IMG";
  6158. var img = this._image = wasElementSupplied ? this._url : create$1("img");
  6159. addClass(img, "leaflet-image-layer");
  6160. if (this._zoomAnimated) {
  6161. addClass(img, "leaflet-zoom-animated");
  6162. }
  6163. if (this.options.className) {
  6164. addClass(img, this.options.className);
  6165. }
  6166. img.onselectstart = falseFn;
  6167. img.onmousemove = falseFn;
  6168. img.onload = bind(this.fire, this, "load");
  6169. img.onerror = bind(this._overlayOnError, this, "error");
  6170. if (this.options.crossOrigin || this.options.crossOrigin === "") {
  6171. img.crossOrigin = this.options.crossOrigin === true ? "" : this.options.crossOrigin;
  6172. }
  6173. if (this.options.zIndex) {
  6174. this._updateZIndex();
  6175. }
  6176. if (wasElementSupplied) {
  6177. this._url = img.src;
  6178. return;
  6179. }
  6180. img.src = this._url;
  6181. img.alt = this.options.alt;
  6182. },
  6183. _animateZoom: function(e) {
  6184. var scale2 = this._map.getZoomScale(e.zoom), offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
  6185. setTransform(this._image, offset, scale2);
  6186. },
  6187. _reset: function() {
  6188. var image = this._image, bounds = new Bounds(
  6189. this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
  6190. this._map.latLngToLayerPoint(this._bounds.getSouthEast())
  6191. ), size = bounds.getSize();
  6192. setPosition(image, bounds.min);
  6193. image.style.width = size.x + "px";
  6194. image.style.height = size.y + "px";
  6195. },
  6196. _updateOpacity: function() {
  6197. setOpacity(this._image, this.options.opacity);
  6198. },
  6199. _updateZIndex: function() {
  6200. if (this._image && this.options.zIndex !== void 0 && this.options.zIndex !== null) {
  6201. this._image.style.zIndex = this.options.zIndex;
  6202. }
  6203. },
  6204. _overlayOnError: function() {
  6205. this.fire("error");
  6206. var errorUrl = this.options.errorOverlayUrl;
  6207. if (errorUrl && this._url !== errorUrl) {
  6208. this._url = errorUrl;
  6209. this._image.src = errorUrl;
  6210. }
  6211. },
  6212. // @method getCenter(): LatLng
  6213. // Returns the center of the ImageOverlay.
  6214. getCenter: function() {
  6215. return this._bounds.getCenter();
  6216. }
  6217. });
  6218. var imageOverlay = function(url, bounds, options) {
  6219. return new ImageOverlay(url, bounds, options);
  6220. };
  6221. var VideoOverlay = ImageOverlay.extend({
  6222. // @section
  6223. // @aka VideoOverlay options
  6224. options: {
  6225. // @option autoplay: Boolean = true
  6226. // Whether the video starts playing automatically when loaded.
  6227. // On some browsers autoplay will only work with `muted: true`
  6228. autoplay: true,
  6229. // @option loop: Boolean = true
  6230. // Whether the video will loop back to the beginning when played.
  6231. loop: true,
  6232. // @option keepAspectRatio: Boolean = true
  6233. // Whether the video will save aspect ratio after the projection.
  6234. // Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
  6235. keepAspectRatio: true,
  6236. // @option muted: Boolean = false
  6237. // Whether the video starts on mute when loaded.
  6238. muted: false,
  6239. // @option playsInline: Boolean = true
  6240. // Mobile browsers will play the video right where it is instead of open it up in fullscreen mode.
  6241. playsInline: true
  6242. },
  6243. _initImage: function() {
  6244. var wasElementSupplied = this._url.tagName === "VIDEO";
  6245. var vid = this._image = wasElementSupplied ? this._url : create$1("video");
  6246. addClass(vid, "leaflet-image-layer");
  6247. if (this._zoomAnimated) {
  6248. addClass(vid, "leaflet-zoom-animated");
  6249. }
  6250. if (this.options.className) {
  6251. addClass(vid, this.options.className);
  6252. }
  6253. vid.onselectstart = falseFn;
  6254. vid.onmousemove = falseFn;
  6255. vid.onloadeddata = bind(this.fire, this, "load");
  6256. if (wasElementSupplied) {
  6257. var sourceElements = vid.getElementsByTagName("source");
  6258. var sources = [];
  6259. for (var j = 0; j < sourceElements.length; j++) {
  6260. sources.push(sourceElements[j].src);
  6261. }
  6262. this._url = sourceElements.length > 0 ? sources : [vid.src];
  6263. return;
  6264. }
  6265. if (!isArray(this._url)) {
  6266. this._url = [this._url];
  6267. }
  6268. if (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, "objectFit")) {
  6269. vid.style["objectFit"] = "fill";
  6270. }
  6271. vid.autoplay = !!this.options.autoplay;
  6272. vid.loop = !!this.options.loop;
  6273. vid.muted = !!this.options.muted;
  6274. vid.playsInline = !!this.options.playsInline;
  6275. for (var i = 0; i < this._url.length; i++) {
  6276. var source = create$1("source");
  6277. source.src = this._url[i];
  6278. vid.appendChild(source);
  6279. }
  6280. }
  6281. // @method getElement(): HTMLVideoElement
  6282. // Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
  6283. // used by this overlay.
  6284. });
  6285. function videoOverlay(video, bounds, options) {
  6286. return new VideoOverlay(video, bounds, options);
  6287. }
  6288. var SVGOverlay = ImageOverlay.extend({
  6289. _initImage: function() {
  6290. var el = this._image = this._url;
  6291. addClass(el, "leaflet-image-layer");
  6292. if (this._zoomAnimated) {
  6293. addClass(el, "leaflet-zoom-animated");
  6294. }
  6295. if (this.options.className) {
  6296. addClass(el, this.options.className);
  6297. }
  6298. el.onselectstart = falseFn;
  6299. el.onmousemove = falseFn;
  6300. }
  6301. // @method getElement(): SVGElement
  6302. // Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)
  6303. // used by this overlay.
  6304. });
  6305. function svgOverlay(el, bounds, options) {
  6306. return new SVGOverlay(el, bounds, options);
  6307. }
  6308. var DivOverlay = Layer.extend({
  6309. // @section
  6310. // @aka DivOverlay options
  6311. options: {
  6312. // @option interactive: Boolean = false
  6313. // If true, the popup/tooltip will listen to the mouse events.
  6314. interactive: false,
  6315. // @option offset: Point = Point(0, 0)
  6316. // The offset of the overlay position.
  6317. offset: [0, 0],
  6318. // @option className: String = ''
  6319. // A custom CSS class name to assign to the overlay.
  6320. className: "",
  6321. // @option pane: String = undefined
  6322. // `Map pane` where the overlay will be added.
  6323. pane: void 0,
  6324. // @option content: String|HTMLElement|Function = ''
  6325. // Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be
  6326. // passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay.
  6327. content: ""
  6328. },
  6329. initialize: function(options, source) {
  6330. if (options && (options instanceof LatLng || isArray(options))) {
  6331. this._latlng = toLatLng(options);
  6332. setOptions(this, source);
  6333. } else {
  6334. setOptions(this, options);
  6335. this._source = source;
  6336. }
  6337. if (this.options.content) {
  6338. this._content = this.options.content;
  6339. }
  6340. },
  6341. // @method openOn(map: Map): this
  6342. // Adds the overlay to the map.
  6343. // Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`.
  6344. openOn: function(map) {
  6345. map = arguments.length ? map : this._source._map;
  6346. if (!map.hasLayer(this)) {
  6347. map.addLayer(this);
  6348. }
  6349. return this;
  6350. },
  6351. // @method close(): this
  6352. // Closes the overlay.
  6353. // Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)`
  6354. // and `layer.closePopup()`/`.closeTooltip()`.
  6355. close: function() {
  6356. if (this._map) {
  6357. this._map.removeLayer(this);
  6358. }
  6359. return this;
  6360. },
  6361. // @method toggle(layer?: Layer): this
  6362. // Opens or closes the overlay bound to layer depending on its current state.
  6363. // Argument may be omitted only for overlay bound to layer.
  6364. // Alternative to `layer.togglePopup()`/`.toggleTooltip()`.
  6365. toggle: function(layer) {
  6366. if (this._map) {
  6367. this.close();
  6368. } else {
  6369. if (arguments.length) {
  6370. this._source = layer;
  6371. } else {
  6372. layer = this._source;
  6373. }
  6374. this._prepareOpen();
  6375. this.openOn(layer._map);
  6376. }
  6377. return this;
  6378. },
  6379. onAdd: function(map) {
  6380. this._zoomAnimated = map._zoomAnimated;
  6381. if (!this._container) {
  6382. this._initLayout();
  6383. }
  6384. if (map._fadeAnimated) {
  6385. setOpacity(this._container, 0);
  6386. }
  6387. clearTimeout(this._removeTimeout);
  6388. this.getPane().appendChild(this._container);
  6389. this.update();
  6390. if (map._fadeAnimated) {
  6391. setOpacity(this._container, 1);
  6392. }
  6393. this.bringToFront();
  6394. if (this.options.interactive) {
  6395. addClass(this._container, "leaflet-interactive");
  6396. this.addInteractiveTarget(this._container);
  6397. }
  6398. },
  6399. onRemove: function(map) {
  6400. if (map._fadeAnimated) {
  6401. setOpacity(this._container, 0);
  6402. this._removeTimeout = setTimeout(bind(remove, void 0, this._container), 200);
  6403. } else {
  6404. remove(this._container);
  6405. }
  6406. if (this.options.interactive) {
  6407. removeClass(this._container, "leaflet-interactive");
  6408. this.removeInteractiveTarget(this._container);
  6409. }
  6410. },
  6411. // @namespace DivOverlay
  6412. // @method getLatLng: LatLng
  6413. // Returns the geographical point of the overlay.
  6414. getLatLng: function() {
  6415. return this._latlng;
  6416. },
  6417. // @method setLatLng(latlng: LatLng): this
  6418. // Sets the geographical point where the overlay will open.
  6419. setLatLng: function(latlng) {
  6420. this._latlng = toLatLng(latlng);
  6421. if (this._map) {
  6422. this._updatePosition();
  6423. this._adjustPan();
  6424. }
  6425. return this;
  6426. },
  6427. // @method getContent: String|HTMLElement
  6428. // Returns the content of the overlay.
  6429. getContent: function() {
  6430. return this._content;
  6431. },
  6432. // @method setContent(htmlContent: String|HTMLElement|Function): this
  6433. // Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function.
  6434. // The function should return a `String` or `HTMLElement` to be used in the overlay.
  6435. setContent: function(content) {
  6436. this._content = content;
  6437. this.update();
  6438. return this;
  6439. },
  6440. // @method getElement: String|HTMLElement
  6441. // Returns the HTML container of the overlay.
  6442. getElement: function() {
  6443. return this._container;
  6444. },
  6445. // @method update: null
  6446. // Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded.
  6447. update: function() {
  6448. if (!this._map) {
  6449. return;
  6450. }
  6451. this._container.style.visibility = "hidden";
  6452. this._updateContent();
  6453. this._updateLayout();
  6454. this._updatePosition();
  6455. this._container.style.visibility = "";
  6456. this._adjustPan();
  6457. },
  6458. getEvents: function() {
  6459. var events = {
  6460. zoom: this._updatePosition,
  6461. viewreset: this._updatePosition
  6462. };
  6463. if (this._zoomAnimated) {
  6464. events.zoomanim = this._animateZoom;
  6465. }
  6466. return events;
  6467. },
  6468. // @method isOpen: Boolean
  6469. // Returns `true` when the overlay is visible on the map.
  6470. isOpen: function() {
  6471. return !!this._map && this._map.hasLayer(this);
  6472. },
  6473. // @method bringToFront: this
  6474. // Brings this overlay in front of other overlays (in the same map pane).
  6475. bringToFront: function() {
  6476. if (this._map) {
  6477. toFront(this._container);
  6478. }
  6479. return this;
  6480. },
  6481. // @method bringToBack: this
  6482. // Brings this overlay to the back of other overlays (in the same map pane).
  6483. bringToBack: function() {
  6484. if (this._map) {
  6485. toBack(this._container);
  6486. }
  6487. return this;
  6488. },
  6489. // prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)
  6490. _prepareOpen: function(latlng) {
  6491. var source = this._source;
  6492. if (!source._map) {
  6493. return false;
  6494. }
  6495. if (source instanceof FeatureGroup) {
  6496. source = null;
  6497. var layers2 = this._source._layers;
  6498. for (var id in layers2) {
  6499. if (layers2[id]._map) {
  6500. source = layers2[id];
  6501. break;
  6502. }
  6503. }
  6504. if (!source) {
  6505. return false;
  6506. }
  6507. this._source = source;
  6508. }
  6509. if (!latlng) {
  6510. if (source.getCenter) {
  6511. latlng = source.getCenter();
  6512. } else if (source.getLatLng) {
  6513. latlng = source.getLatLng();
  6514. } else if (source.getBounds) {
  6515. latlng = source.getBounds().getCenter();
  6516. } else {
  6517. throw new Error("Unable to get source layer LatLng.");
  6518. }
  6519. }
  6520. this.setLatLng(latlng);
  6521. if (this._map) {
  6522. this.update();
  6523. }
  6524. return true;
  6525. },
  6526. _updateContent: function() {
  6527. if (!this._content) {
  6528. return;
  6529. }
  6530. var node = this._contentNode;
  6531. var content = typeof this._content === "function" ? this._content(this._source || this) : this._content;
  6532. if (typeof content === "string") {
  6533. node.innerHTML = content;
  6534. } else {
  6535. while (node.hasChildNodes()) {
  6536. node.removeChild(node.firstChild);
  6537. }
  6538. node.appendChild(content);
  6539. }
  6540. this.fire("contentupdate");
  6541. },
  6542. _updatePosition: function() {
  6543. if (!this._map) {
  6544. return;
  6545. }
  6546. var pos = this._map.latLngToLayerPoint(this._latlng), offset = toPoint(this.options.offset), anchor = this._getAnchor();
  6547. if (this._zoomAnimated) {
  6548. setPosition(this._container, pos.add(anchor));
  6549. } else {
  6550. offset = offset.add(pos).add(anchor);
  6551. }
  6552. var bottom = this._containerBottom = -offset.y, left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
  6553. this._container.style.bottom = bottom + "px";
  6554. this._container.style.left = left + "px";
  6555. },
  6556. _getAnchor: function() {
  6557. return [0, 0];
  6558. }
  6559. });
  6560. Map.include({
  6561. _initOverlay: function(OverlayClass, content, latlng, options) {
  6562. var overlay = content;
  6563. if (!(overlay instanceof OverlayClass)) {
  6564. overlay = new OverlayClass(options).setContent(content);
  6565. }
  6566. if (latlng) {
  6567. overlay.setLatLng(latlng);
  6568. }
  6569. return overlay;
  6570. }
  6571. });
  6572. Layer.include({
  6573. _initOverlay: function(OverlayClass, old, content, options) {
  6574. var overlay = content;
  6575. if (overlay instanceof OverlayClass) {
  6576. setOptions(overlay, options);
  6577. overlay._source = this;
  6578. } else {
  6579. overlay = old && !options ? old : new OverlayClass(options, this);
  6580. overlay.setContent(content);
  6581. }
  6582. return overlay;
  6583. }
  6584. });
  6585. var Popup = DivOverlay.extend({
  6586. // @section
  6587. // @aka Popup options
  6588. options: {
  6589. // @option pane: String = 'popupPane'
  6590. // `Map pane` where the popup will be added.
  6591. pane: "popupPane",
  6592. // @option offset: Point = Point(0, 7)
  6593. // The offset of the popup position.
  6594. offset: [0, 7],
  6595. // @option maxWidth: Number = 300
  6596. // Max width of the popup, in pixels.
  6597. maxWidth: 300,
  6598. // @option minWidth: Number = 50
  6599. // Min width of the popup, in pixels.
  6600. minWidth: 50,
  6601. // @option maxHeight: Number = null
  6602. // If set, creates a scrollable container of the given height
  6603. // inside a popup if its content exceeds it.
  6604. // The scrollable container can be styled using the
  6605. // `leaflet-popup-scrolled` CSS class selector.
  6606. maxHeight: null,
  6607. // @option autoPan: Boolean = true
  6608. // Set it to `false` if you don't want the map to do panning animation
  6609. // to fit the opened popup.
  6610. autoPan: true,
  6611. // @option autoPanPaddingTopLeft: Point = null
  6612. // The margin between the popup and the top left corner of the map
  6613. // view after autopanning was performed.
  6614. autoPanPaddingTopLeft: null,
  6615. // @option autoPanPaddingBottomRight: Point = null
  6616. // The margin between the popup and the bottom right corner of the map
  6617. // view after autopanning was performed.
  6618. autoPanPaddingBottomRight: null,
  6619. // @option autoPanPadding: Point = Point(5, 5)
  6620. // Equivalent of setting both top left and bottom right autopan padding to the same value.
  6621. autoPanPadding: [5, 5],
  6622. // @option keepInView: Boolean = false
  6623. // Set it to `true` if you want to prevent users from panning the popup
  6624. // off of the screen while it is open.
  6625. keepInView: false,
  6626. // @option closeButton: Boolean = true
  6627. // Controls the presence of a close button in the popup.
  6628. closeButton: true,
  6629. // @option autoClose: Boolean = true
  6630. // Set it to `false` if you want to override the default behavior of
  6631. // the popup closing when another popup is opened.
  6632. autoClose: true,
  6633. // @option closeOnEscapeKey: Boolean = true
  6634. // Set it to `false` if you want to override the default behavior of
  6635. // the ESC key for closing of the popup.
  6636. closeOnEscapeKey: true,
  6637. // @option closeOnClick: Boolean = *
  6638. // Set it if you want to override the default behavior of the popup closing when user clicks
  6639. // on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
  6640. // @option className: String = ''
  6641. // A custom CSS class name to assign to the popup.
  6642. className: ""
  6643. },
  6644. // @namespace Popup
  6645. // @method openOn(map: Map): this
  6646. // Alternative to `map.openPopup(popup)`.
  6647. // Adds the popup to the map and closes the previous one.
  6648. openOn: function(map) {
  6649. map = arguments.length ? map : this._source._map;
  6650. if (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) {
  6651. map.removeLayer(map._popup);
  6652. }
  6653. map._popup = this;
  6654. return DivOverlay.prototype.openOn.call(this, map);
  6655. },
  6656. onAdd: function(map) {
  6657. DivOverlay.prototype.onAdd.call(this, map);
  6658. map.fire("popupopen", { popup: this });
  6659. if (this._source) {
  6660. this._source.fire("popupopen", { popup: this }, true);
  6661. if (!(this._source instanceof Path)) {
  6662. this._source.on("preclick", stopPropagation);
  6663. }
  6664. }
  6665. },
  6666. onRemove: function(map) {
  6667. DivOverlay.prototype.onRemove.call(this, map);
  6668. map.fire("popupclose", { popup: this });
  6669. if (this._source) {
  6670. this._source.fire("popupclose", { popup: this }, true);
  6671. if (!(this._source instanceof Path)) {
  6672. this._source.off("preclick", stopPropagation);
  6673. }
  6674. }
  6675. },
  6676. getEvents: function() {
  6677. var events = DivOverlay.prototype.getEvents.call(this);
  6678. if (this.options.closeOnClick !== void 0 ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
  6679. events.preclick = this.close;
  6680. }
  6681. if (this.options.keepInView) {
  6682. events.moveend = this._adjustPan;
  6683. }
  6684. return events;
  6685. },
  6686. _initLayout: function() {
  6687. var prefix = "leaflet-popup", container = this._container = create$1(
  6688. "div",
  6689. prefix + " " + (this.options.className || "") + " leaflet-zoom-animated"
  6690. );
  6691. var wrapper = this._wrapper = create$1("div", prefix + "-content-wrapper", container);
  6692. this._contentNode = create$1("div", prefix + "-content", wrapper);
  6693. disableClickPropagation(container);
  6694. disableScrollPropagation(this._contentNode);
  6695. on(container, "contextmenu", stopPropagation);
  6696. this._tipContainer = create$1("div", prefix + "-tip-container", container);
  6697. this._tip = create$1("div", prefix + "-tip", this._tipContainer);
  6698. if (this.options.closeButton) {
  6699. var closeButton = this._closeButton = create$1("a", prefix + "-close-button", container);
  6700. closeButton.setAttribute("role", "button");
  6701. closeButton.setAttribute("aria-label", "Close popup");
  6702. closeButton.href = "#close";
  6703. closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
  6704. on(closeButton, "click", function(ev) {
  6705. preventDefault(ev);
  6706. this.close();
  6707. }, this);
  6708. }
  6709. },
  6710. _updateLayout: function() {
  6711. var container = this._contentNode, style2 = container.style;
  6712. style2.width = "";
  6713. style2.whiteSpace = "nowrap";
  6714. var width = container.offsetWidth;
  6715. width = Math.min(width, this.options.maxWidth);
  6716. width = Math.max(width, this.options.minWidth);
  6717. style2.width = width + 1 + "px";
  6718. style2.whiteSpace = "";
  6719. style2.height = "";
  6720. var height = container.offsetHeight, maxHeight = this.options.maxHeight, scrolledClass = "leaflet-popup-scrolled";
  6721. if (maxHeight && height > maxHeight) {
  6722. style2.height = maxHeight + "px";
  6723. addClass(container, scrolledClass);
  6724. } else {
  6725. removeClass(container, scrolledClass);
  6726. }
  6727. this._containerWidth = this._container.offsetWidth;
  6728. },
  6729. _animateZoom: function(e) {
  6730. var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center), anchor = this._getAnchor();
  6731. setPosition(this._container, pos.add(anchor));
  6732. },
  6733. _adjustPan: function() {
  6734. if (!this.options.autoPan) {
  6735. return;
  6736. }
  6737. if (this._map._panAnim) {
  6738. this._map._panAnim.stop();
  6739. }
  6740. if (this._autopanning) {
  6741. this._autopanning = false;
  6742. return;
  6743. }
  6744. var map = this._map, marginBottom = parseInt(getStyle(this._container, "marginBottom"), 10) || 0, containerHeight = this._container.offsetHeight + marginBottom, containerWidth = this._containerWidth, layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);
  6745. layerPos._add(getPosition(this._container));
  6746. var containerPos = map.layerPointToContainerPoint(layerPos), padding = toPoint(this.options.autoPanPadding), paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding), paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding), size = map.getSize(), dx = 0, dy = 0;
  6747. if (containerPos.x + containerWidth + paddingBR.x > size.x) {
  6748. dx = containerPos.x + containerWidth - size.x + paddingBR.x;
  6749. }
  6750. if (containerPos.x - dx - paddingTL.x < 0) {
  6751. dx = containerPos.x - paddingTL.x;
  6752. }
  6753. if (containerPos.y + containerHeight + paddingBR.y > size.y) {
  6754. dy = containerPos.y + containerHeight - size.y + paddingBR.y;
  6755. }
  6756. if (containerPos.y - dy - paddingTL.y < 0) {
  6757. dy = containerPos.y - paddingTL.y;
  6758. }
  6759. if (dx || dy) {
  6760. if (this.options.keepInView) {
  6761. this._autopanning = true;
  6762. }
  6763. map.fire("autopanstart").panBy([dx, dy]);
  6764. }
  6765. },
  6766. _getAnchor: function() {
  6767. return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
  6768. }
  6769. });
  6770. var popup = function(options, source) {
  6771. return new Popup(options, source);
  6772. };
  6773. Map.mergeOptions({
  6774. closePopupOnClick: true
  6775. });
  6776. Map.include({
  6777. // @method openPopup(popup: Popup): this
  6778. // Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
  6779. // @alternative
  6780. // @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
  6781. // Creates a popup with the specified content and options and opens it in the given point on a map.
  6782. openPopup: function(popup2, latlng, options) {
  6783. this._initOverlay(Popup, popup2, latlng, options).openOn(this);
  6784. return this;
  6785. },
  6786. // @method closePopup(popup?: Popup): this
  6787. // Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
  6788. closePopup: function(popup2) {
  6789. popup2 = arguments.length ? popup2 : this._popup;
  6790. if (popup2) {
  6791. popup2.close();
  6792. }
  6793. return this;
  6794. }
  6795. });
  6796. Layer.include({
  6797. // @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
  6798. // Binds a popup to the layer with the passed `content` and sets up the
  6799. // necessary event listeners. If a `Function` is passed it will receive
  6800. // the layer as the first argument and should return a `String` or `HTMLElement`.
  6801. bindPopup: function(content, options) {
  6802. this._popup = this._initOverlay(Popup, this._popup, content, options);
  6803. if (!this._popupHandlersAdded) {
  6804. this.on({
  6805. click: this._openPopup,
  6806. keypress: this._onKeyPress,
  6807. remove: this.closePopup,
  6808. move: this._movePopup
  6809. });
  6810. this._popupHandlersAdded = true;
  6811. }
  6812. return this;
  6813. },
  6814. // @method unbindPopup(): this
  6815. // Removes the popup previously bound with `bindPopup`.
  6816. unbindPopup: function() {
  6817. if (this._popup) {
  6818. this.off({
  6819. click: this._openPopup,
  6820. keypress: this._onKeyPress,
  6821. remove: this.closePopup,
  6822. move: this._movePopup
  6823. });
  6824. this._popupHandlersAdded = false;
  6825. this._popup = null;
  6826. }
  6827. return this;
  6828. },
  6829. // @method openPopup(latlng?: LatLng): this
  6830. // Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
  6831. openPopup: function(latlng) {
  6832. if (this._popup) {
  6833. if (!(this instanceof FeatureGroup)) {
  6834. this._popup._source = this;
  6835. }
  6836. if (this._popup._prepareOpen(latlng || this._latlng)) {
  6837. this._popup.openOn(this._map);
  6838. }
  6839. }
  6840. return this;
  6841. },
  6842. // @method closePopup(): this
  6843. // Closes the popup bound to this layer if it is open.
  6844. closePopup: function() {
  6845. if (this._popup) {
  6846. this._popup.close();
  6847. }
  6848. return this;
  6849. },
  6850. // @method togglePopup(): this
  6851. // Opens or closes the popup bound to this layer depending on its current state.
  6852. togglePopup: function() {
  6853. if (this._popup) {
  6854. this._popup.toggle(this);
  6855. }
  6856. return this;
  6857. },
  6858. // @method isPopupOpen(): boolean
  6859. // Returns `true` if the popup bound to this layer is currently open.
  6860. isPopupOpen: function() {
  6861. return this._popup ? this._popup.isOpen() : false;
  6862. },
  6863. // @method setPopupContent(content: String|HTMLElement|Popup): this
  6864. // Sets the content of the popup bound to this layer.
  6865. setPopupContent: function(content) {
  6866. if (this._popup) {
  6867. this._popup.setContent(content);
  6868. }
  6869. return this;
  6870. },
  6871. // @method getPopup(): Popup
  6872. // Returns the popup bound to this layer.
  6873. getPopup: function() {
  6874. return this._popup;
  6875. },
  6876. _openPopup: function(e) {
  6877. if (!this._popup || !this._map) {
  6878. return;
  6879. }
  6880. stop(e);
  6881. var target = e.layer || e.target;
  6882. if (this._popup._source === target && !(target instanceof Path)) {
  6883. if (this._map.hasLayer(this._popup)) {
  6884. this.closePopup();
  6885. } else {
  6886. this.openPopup(e.latlng);
  6887. }
  6888. return;
  6889. }
  6890. this._popup._source = target;
  6891. this.openPopup(e.latlng);
  6892. },
  6893. _movePopup: function(e) {
  6894. this._popup.setLatLng(e.latlng);
  6895. },
  6896. _onKeyPress: function(e) {
  6897. if (e.originalEvent.keyCode === 13) {
  6898. this._openPopup(e);
  6899. }
  6900. }
  6901. });
  6902. var Tooltip = DivOverlay.extend({
  6903. // @section
  6904. // @aka Tooltip options
  6905. options: {
  6906. // @option pane: String = 'tooltipPane'
  6907. // `Map pane` where the tooltip will be added.
  6908. pane: "tooltipPane",
  6909. // @option offset: Point = Point(0, 0)
  6910. // Optional offset of the tooltip position.
  6911. offset: [0, 0],
  6912. // @option direction: String = 'auto'
  6913. // Direction where to open the tooltip. Possible values are: `right`, `left`,
  6914. // `top`, `bottom`, `center`, `auto`.
  6915. // `auto` will dynamically switch between `right` and `left` according to the tooltip
  6916. // position on the map.
  6917. direction: "auto",
  6918. // @option permanent: Boolean = false
  6919. // Whether to open the tooltip permanently or only on mouseover.
  6920. permanent: false,
  6921. // @option sticky: Boolean = false
  6922. // If true, the tooltip will follow the mouse instead of being fixed at the feature center.
  6923. sticky: false,
  6924. // @option opacity: Number = 0.9
  6925. // Tooltip container opacity.
  6926. opacity: 0.9
  6927. },
  6928. onAdd: function(map) {
  6929. DivOverlay.prototype.onAdd.call(this, map);
  6930. this.setOpacity(this.options.opacity);
  6931. map.fire("tooltipopen", { tooltip: this });
  6932. if (this._source) {
  6933. this.addEventParent(this._source);
  6934. this._source.fire("tooltipopen", { tooltip: this }, true);
  6935. }
  6936. },
  6937. onRemove: function(map) {
  6938. DivOverlay.prototype.onRemove.call(this, map);
  6939. map.fire("tooltipclose", { tooltip: this });
  6940. if (this._source) {
  6941. this.removeEventParent(this._source);
  6942. this._source.fire("tooltipclose", { tooltip: this }, true);
  6943. }
  6944. },
  6945. getEvents: function() {
  6946. var events = DivOverlay.prototype.getEvents.call(this);
  6947. if (!this.options.permanent) {
  6948. events.preclick = this.close;
  6949. }
  6950. return events;
  6951. },
  6952. _initLayout: function() {
  6953. var prefix = "leaflet-tooltip", className = prefix + " " + (this.options.className || "") + " leaflet-zoom-" + (this._zoomAnimated ? "animated" : "hide");
  6954. this._contentNode = this._container = create$1("div", className);
  6955. this._container.setAttribute("role", "tooltip");
  6956. this._container.setAttribute("id", "leaflet-tooltip-" + stamp(this));
  6957. },
  6958. _updateLayout: function() {
  6959. },
  6960. _adjustPan: function() {
  6961. },
  6962. _setPosition: function(pos) {
  6963. var subX, subY, map = this._map, container = this._container, centerPoint = map.latLngToContainerPoint(map.getCenter()), tooltipPoint = map.layerPointToContainerPoint(pos), direction = this.options.direction, tooltipWidth = container.offsetWidth, tooltipHeight = container.offsetHeight, offset = toPoint(this.options.offset), anchor = this._getAnchor();
  6964. if (direction === "top") {
  6965. subX = tooltipWidth / 2;
  6966. subY = tooltipHeight;
  6967. } else if (direction === "bottom") {
  6968. subX = tooltipWidth / 2;
  6969. subY = 0;
  6970. } else if (direction === "center") {
  6971. subX = tooltipWidth / 2;
  6972. subY = tooltipHeight / 2;
  6973. } else if (direction === "right") {
  6974. subX = 0;
  6975. subY = tooltipHeight / 2;
  6976. } else if (direction === "left") {
  6977. subX = tooltipWidth;
  6978. subY = tooltipHeight / 2;
  6979. } else if (tooltipPoint.x < centerPoint.x) {
  6980. direction = "right";
  6981. subX = 0;
  6982. subY = tooltipHeight / 2;
  6983. } else {
  6984. direction = "left";
  6985. subX = tooltipWidth + (offset.x + anchor.x) * 2;
  6986. subY = tooltipHeight / 2;
  6987. }
  6988. pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);
  6989. removeClass(container, "leaflet-tooltip-right");
  6990. removeClass(container, "leaflet-tooltip-left");
  6991. removeClass(container, "leaflet-tooltip-top");
  6992. removeClass(container, "leaflet-tooltip-bottom");
  6993. addClass(container, "leaflet-tooltip-" + direction);
  6994. setPosition(container, pos);
  6995. },
  6996. _updatePosition: function() {
  6997. var pos = this._map.latLngToLayerPoint(this._latlng);
  6998. this._setPosition(pos);
  6999. },
  7000. setOpacity: function(opacity) {
  7001. this.options.opacity = opacity;
  7002. if (this._container) {
  7003. setOpacity(this._container, opacity);
  7004. }
  7005. },
  7006. _animateZoom: function(e) {
  7007. var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
  7008. this._setPosition(pos);
  7009. },
  7010. _getAnchor: function() {
  7011. return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
  7012. }
  7013. });
  7014. var tooltip = function(options, source) {
  7015. return new Tooltip(options, source);
  7016. };
  7017. Map.include({
  7018. // @method openTooltip(tooltip: Tooltip): this
  7019. // Opens the specified tooltip.
  7020. // @alternative
  7021. // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
  7022. // Creates a tooltip with the specified content and options and open it.
  7023. openTooltip: function(tooltip2, latlng, options) {
  7024. this._initOverlay(Tooltip, tooltip2, latlng, options).openOn(this);
  7025. return this;
  7026. },
  7027. // @method closeTooltip(tooltip: Tooltip): this
  7028. // Closes the tooltip given as parameter.
  7029. closeTooltip: function(tooltip2) {
  7030. tooltip2.close();
  7031. return this;
  7032. }
  7033. });
  7034. Layer.include({
  7035. // @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
  7036. // Binds a tooltip to the layer with the passed `content` and sets up the
  7037. // necessary event listeners. If a `Function` is passed it will receive
  7038. // the layer as the first argument and should return a `String` or `HTMLElement`.
  7039. bindTooltip: function(content, options) {
  7040. if (this._tooltip && this.isTooltipOpen()) {
  7041. this.unbindTooltip();
  7042. }
  7043. this._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options);
  7044. this._initTooltipInteractions();
  7045. if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
  7046. this.openTooltip();
  7047. }
  7048. return this;
  7049. },
  7050. // @method unbindTooltip(): this
  7051. // Removes the tooltip previously bound with `bindTooltip`.
  7052. unbindTooltip: function() {
  7053. if (this._tooltip) {
  7054. this._initTooltipInteractions(true);
  7055. this.closeTooltip();
  7056. this._tooltip = null;
  7057. }
  7058. return this;
  7059. },
  7060. _initTooltipInteractions: function(remove2) {
  7061. if (!remove2 && this._tooltipHandlersAdded) {
  7062. return;
  7063. }
  7064. var onOff = remove2 ? "off" : "on", events = {
  7065. remove: this.closeTooltip,
  7066. move: this._moveTooltip
  7067. };
  7068. if (!this._tooltip.options.permanent) {
  7069. events.mouseover = this._openTooltip;
  7070. events.mouseout = this.closeTooltip;
  7071. events.click = this._openTooltip;
  7072. if (this._map) {
  7073. this._addFocusListeners();
  7074. } else {
  7075. events.add = this._addFocusListeners;
  7076. }
  7077. } else {
  7078. events.add = this._openTooltip;
  7079. }
  7080. if (this._tooltip.options.sticky) {
  7081. events.mousemove = this._moveTooltip;
  7082. }
  7083. this[onOff](events);
  7084. this._tooltipHandlersAdded = !remove2;
  7085. },
  7086. // @method openTooltip(latlng?: LatLng): this
  7087. // Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
  7088. openTooltip: function(latlng) {
  7089. if (this._tooltip) {
  7090. if (!(this instanceof FeatureGroup)) {
  7091. this._tooltip._source = this;
  7092. }
  7093. if (this._tooltip._prepareOpen(latlng)) {
  7094. this._tooltip.openOn(this._map);
  7095. if (this.getElement) {
  7096. this._setAriaDescribedByOnLayer(this);
  7097. } else if (this.eachLayer) {
  7098. this.eachLayer(this._setAriaDescribedByOnLayer, this);
  7099. }
  7100. }
  7101. }
  7102. return this;
  7103. },
  7104. // @method closeTooltip(): this
  7105. // Closes the tooltip bound to this layer if it is open.
  7106. closeTooltip: function() {
  7107. if (this._tooltip) {
  7108. return this._tooltip.close();
  7109. }
  7110. },
  7111. // @method toggleTooltip(): this
  7112. // Opens or closes the tooltip bound to this layer depending on its current state.
  7113. toggleTooltip: function() {
  7114. if (this._tooltip) {
  7115. this._tooltip.toggle(this);
  7116. }
  7117. return this;
  7118. },
  7119. // @method isTooltipOpen(): boolean
  7120. // Returns `true` if the tooltip bound to this layer is currently open.
  7121. isTooltipOpen: function() {
  7122. return this._tooltip.isOpen();
  7123. },
  7124. // @method setTooltipContent(content: String|HTMLElement|Tooltip): this
  7125. // Sets the content of the tooltip bound to this layer.
  7126. setTooltipContent: function(content) {
  7127. if (this._tooltip) {
  7128. this._tooltip.setContent(content);
  7129. }
  7130. return this;
  7131. },
  7132. // @method getTooltip(): Tooltip
  7133. // Returns the tooltip bound to this layer.
  7134. getTooltip: function() {
  7135. return this._tooltip;
  7136. },
  7137. _addFocusListeners: function() {
  7138. if (this.getElement) {
  7139. this._addFocusListenersOnLayer(this);
  7140. } else if (this.eachLayer) {
  7141. this.eachLayer(this._addFocusListenersOnLayer, this);
  7142. }
  7143. },
  7144. _addFocusListenersOnLayer: function(layer) {
  7145. var el = typeof layer.getElement === "function" && layer.getElement();
  7146. if (el) {
  7147. on(el, "focus", function() {
  7148. this._tooltip._source = layer;
  7149. this.openTooltip();
  7150. }, this);
  7151. on(el, "blur", this.closeTooltip, this);
  7152. }
  7153. },
  7154. _setAriaDescribedByOnLayer: function(layer) {
  7155. var el = typeof layer.getElement === "function" && layer.getElement();
  7156. if (el) {
  7157. el.setAttribute("aria-describedby", this._tooltip._container.id);
  7158. }
  7159. },
  7160. _openTooltip: function(e) {
  7161. if (!this._tooltip || !this._map) {
  7162. return;
  7163. }
  7164. if (this._map.dragging && this._map.dragging.moving() && !this._openOnceFlag) {
  7165. this._openOnceFlag = true;
  7166. var that = this;
  7167. this._map.once("moveend", function() {
  7168. that._openOnceFlag = false;
  7169. that._openTooltip(e);
  7170. });
  7171. return;
  7172. }
  7173. this._tooltip._source = e.layer || e.target;
  7174. this.openTooltip(this._tooltip.options.sticky ? e.latlng : void 0);
  7175. },
  7176. _moveTooltip: function(e) {
  7177. var latlng = e.latlng, containerPoint, layerPoint;
  7178. if (this._tooltip.options.sticky && e.originalEvent) {
  7179. containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
  7180. layerPoint = this._map.containerPointToLayerPoint(containerPoint);
  7181. latlng = this._map.layerPointToLatLng(layerPoint);
  7182. }
  7183. this._tooltip.setLatLng(latlng);
  7184. }
  7185. });
  7186. var DivIcon = Icon.extend({
  7187. options: {
  7188. // @section
  7189. // @aka DivIcon options
  7190. iconSize: [12, 12],
  7191. // also can be set through CSS
  7192. // iconAnchor: (Point),
  7193. // popupAnchor: (Point),
  7194. // @option html: String|HTMLElement = ''
  7195. // Custom HTML code to put inside the div element, empty by default. Alternatively,
  7196. // an instance of `HTMLElement`.
  7197. html: false,
  7198. // @option bgPos: Point = [0, 0]
  7199. // Optional relative position of the background, in pixels
  7200. bgPos: null,
  7201. className: "leaflet-div-icon"
  7202. },
  7203. createIcon: function(oldIcon) {
  7204. var div = oldIcon && oldIcon.tagName === "DIV" ? oldIcon : document.createElement("div"), options = this.options;
  7205. if (options.html instanceof Element) {
  7206. empty(div);
  7207. div.appendChild(options.html);
  7208. } else {
  7209. div.innerHTML = options.html !== false ? options.html : "";
  7210. }
  7211. if (options.bgPos) {
  7212. var bgPos = toPoint(options.bgPos);
  7213. div.style.backgroundPosition = -bgPos.x + "px " + -bgPos.y + "px";
  7214. }
  7215. this._setIconStyles(div, "icon");
  7216. return div;
  7217. },
  7218. createShadow: function() {
  7219. return null;
  7220. }
  7221. });
  7222. function divIcon(options) {
  7223. return new DivIcon(options);
  7224. }
  7225. Icon.Default = IconDefault;
  7226. var GridLayer = Layer.extend({
  7227. // @section
  7228. // @aka GridLayer options
  7229. options: {
  7230. // @option tileSize: Number|Point = 256
  7231. // Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
  7232. tileSize: 256,
  7233. // @option opacity: Number = 1.0
  7234. // Opacity of the tiles. Can be used in the `createTile()` function.
  7235. opacity: 1,
  7236. // @option updateWhenIdle: Boolean = (depends)
  7237. // Load new tiles only when panning ends.
  7238. // `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
  7239. // `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
  7240. // [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
  7241. updateWhenIdle: Browser.mobile,
  7242. // @option updateWhenZooming: Boolean = true
  7243. // 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.
  7244. updateWhenZooming: true,
  7245. // @option updateInterval: Number = 200
  7246. // Tiles will not update more than once every `updateInterval` milliseconds when panning.
  7247. updateInterval: 200,
  7248. // @option zIndex: Number = 1
  7249. // The explicit zIndex of the tile layer.
  7250. zIndex: 1,
  7251. // @option bounds: LatLngBounds = undefined
  7252. // If set, tiles will only be loaded inside the set `LatLngBounds`.
  7253. bounds: null,
  7254. // @option minZoom: Number = 0
  7255. // The minimum zoom level down to which this layer will be displayed (inclusive).
  7256. minZoom: 0,
  7257. // @option maxZoom: Number = undefined
  7258. // The maximum zoom level up to which this layer will be displayed (inclusive).
  7259. maxZoom: void 0,
  7260. // @option maxNativeZoom: Number = undefined
  7261. // Maximum zoom number the tile source has available. If it is specified,
  7262. // the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
  7263. // from `maxNativeZoom` level and auto-scaled.
  7264. maxNativeZoom: void 0,
  7265. // @option minNativeZoom: Number = undefined
  7266. // Minimum zoom number the tile source has available. If it is specified,
  7267. // the tiles on all zoom levels lower than `minNativeZoom` will be loaded
  7268. // from `minNativeZoom` level and auto-scaled.
  7269. minNativeZoom: void 0,
  7270. // @option noWrap: Boolean = false
  7271. // Whether the layer is wrapped around the antimeridian. If `true`, the
  7272. // GridLayer will only be displayed once at low zoom levels. Has no
  7273. // effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
  7274. // in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
  7275. // tiles outside the CRS limits.
  7276. noWrap: false,
  7277. // @option pane: String = 'tilePane'
  7278. // `Map pane` where the grid layer will be added.
  7279. pane: "tilePane",
  7280. // @option className: String = ''
  7281. // A custom class name to assign to the tile layer. Empty by default.
  7282. className: "",
  7283. // @option keepBuffer: Number = 2
  7284. // When panning the map, keep this many rows and columns of tiles before unloading them.
  7285. keepBuffer: 2
  7286. },
  7287. initialize: function(options) {
  7288. setOptions(this, options);
  7289. },
  7290. onAdd: function() {
  7291. this._initContainer();
  7292. this._levels = {};
  7293. this._tiles = {};
  7294. this._resetView();
  7295. },
  7296. beforeAdd: function(map) {
  7297. map._addZoomLimit(this);
  7298. },
  7299. onRemove: function(map) {
  7300. this._removeAllTiles();
  7301. remove(this._container);
  7302. map._removeZoomLimit(this);
  7303. this._container = null;
  7304. this._tileZoom = void 0;
  7305. },
  7306. // @method bringToFront: this
  7307. // Brings the tile layer to the top of all tile layers.
  7308. bringToFront: function() {
  7309. if (this._map) {
  7310. toFront(this._container);
  7311. this._setAutoZIndex(Math.max);
  7312. }
  7313. return this;
  7314. },
  7315. // @method bringToBack: this
  7316. // Brings the tile layer to the bottom of all tile layers.
  7317. bringToBack: function() {
  7318. if (this._map) {
  7319. toBack(this._container);
  7320. this._setAutoZIndex(Math.min);
  7321. }
  7322. return this;
  7323. },
  7324. // @method getContainer: HTMLElement
  7325. // Returns the HTML element that contains the tiles for this layer.
  7326. getContainer: function() {
  7327. return this._container;
  7328. },
  7329. // @method setOpacity(opacity: Number): this
  7330. // Changes the [opacity](#gridlayer-opacity) of the grid layer.
  7331. setOpacity: function(opacity) {
  7332. this.options.opacity = opacity;
  7333. this._updateOpacity();
  7334. return this;
  7335. },
  7336. // @method setZIndex(zIndex: Number): this
  7337. // Changes the [zIndex](#gridlayer-zindex) of the grid layer.
  7338. setZIndex: function(zIndex) {
  7339. this.options.zIndex = zIndex;
  7340. this._updateZIndex();
  7341. return this;
  7342. },
  7343. // @method isLoading: Boolean
  7344. // Returns `true` if any tile in the grid layer has not finished loading.
  7345. isLoading: function() {
  7346. return this._loading;
  7347. },
  7348. // @method redraw: this
  7349. // Causes the layer to clear all the tiles and request them again.
  7350. redraw: function() {
  7351. if (this._map) {
  7352. this._removeAllTiles();
  7353. var tileZoom = this._clampZoom(this._map.getZoom());
  7354. if (tileZoom !== this._tileZoom) {
  7355. this._tileZoom = tileZoom;
  7356. this._updateLevels();
  7357. }
  7358. this._update();
  7359. }
  7360. return this;
  7361. },
  7362. getEvents: function() {
  7363. var events = {
  7364. viewprereset: this._invalidateAll,
  7365. viewreset: this._resetView,
  7366. zoom: this._resetView,
  7367. moveend: this._onMoveEnd
  7368. };
  7369. if (!this.options.updateWhenIdle) {
  7370. if (!this._onMove) {
  7371. this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);
  7372. }
  7373. events.move = this._onMove;
  7374. }
  7375. if (this._zoomAnimated) {
  7376. events.zoomanim = this._animateZoom;
  7377. }
  7378. return events;
  7379. },
  7380. // @section Extension methods
  7381. // Layers extending `GridLayer` shall reimplement the following method.
  7382. // @method createTile(coords: Object, done?: Function): HTMLElement
  7383. // Called only internally, must be overridden by classes extending `GridLayer`.
  7384. // Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
  7385. // is specified, it must be called when the tile has finished loading and drawing.
  7386. createTile: function() {
  7387. return document.createElement("div");
  7388. },
  7389. // @section
  7390. // @method getTileSize: Point
  7391. // Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
  7392. getTileSize: function() {
  7393. var s = this.options.tileSize;
  7394. return s instanceof Point ? s : new Point(s, s);
  7395. },
  7396. _updateZIndex: function() {
  7397. if (this._container && this.options.zIndex !== void 0 && this.options.zIndex !== null) {
  7398. this._container.style.zIndex = this.options.zIndex;
  7399. }
  7400. },
  7401. _setAutoZIndex: function(compare) {
  7402. var layers2 = this.getPane().children, edgeZIndex = -compare(-Infinity, Infinity);
  7403. for (var i = 0, len = layers2.length, zIndex; i < len; i++) {
  7404. zIndex = layers2[i].style.zIndex;
  7405. if (layers2[i] !== this._container && zIndex) {
  7406. edgeZIndex = compare(edgeZIndex, +zIndex);
  7407. }
  7408. }
  7409. if (isFinite(edgeZIndex)) {
  7410. this.options.zIndex = edgeZIndex + compare(-1, 1);
  7411. this._updateZIndex();
  7412. }
  7413. },
  7414. _updateOpacity: function() {
  7415. if (!this._map) {
  7416. return;
  7417. }
  7418. if (Browser.ielt9) {
  7419. return;
  7420. }
  7421. setOpacity(this._container, this.options.opacity);
  7422. var now = +/* @__PURE__ */ new Date(), nextFrame = false, willPrune = false;
  7423. for (var key in this._tiles) {
  7424. var tile = this._tiles[key];
  7425. if (!tile.current || !tile.loaded) {
  7426. continue;
  7427. }
  7428. var fade = Math.min(1, (now - tile.loaded) / 200);
  7429. setOpacity(tile.el, fade);
  7430. if (fade < 1) {
  7431. nextFrame = true;
  7432. } else {
  7433. if (tile.active) {
  7434. willPrune = true;
  7435. } else {
  7436. this._onOpaqueTile(tile);
  7437. }
  7438. tile.active = true;
  7439. }
  7440. }
  7441. if (willPrune && !this._noPrune) {
  7442. this._pruneTiles();
  7443. }
  7444. if (nextFrame) {
  7445. cancelAnimFrame(this._fadeFrame);
  7446. this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
  7447. }
  7448. },
  7449. _onOpaqueTile: falseFn,
  7450. _initContainer: function() {
  7451. if (this._container) {
  7452. return;
  7453. }
  7454. this._container = create$1("div", "leaflet-layer " + (this.options.className || ""));
  7455. this._updateZIndex();
  7456. if (this.options.opacity < 1) {
  7457. this._updateOpacity();
  7458. }
  7459. this.getPane().appendChild(this._container);
  7460. },
  7461. _updateLevels: function() {
  7462. var zoom2 = this._tileZoom, maxZoom = this.options.maxZoom;
  7463. if (zoom2 === void 0) {
  7464. return void 0;
  7465. }
  7466. for (var z in this._levels) {
  7467. z = Number(z);
  7468. if (this._levels[z].el.children.length || z === zoom2) {
  7469. this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom2 - z);
  7470. this._onUpdateLevel(z);
  7471. } else {
  7472. remove(this._levels[z].el);
  7473. this._removeTilesAtZoom(z);
  7474. this._onRemoveLevel(z);
  7475. delete this._levels[z];
  7476. }
  7477. }
  7478. var level = this._levels[zoom2], map = this._map;
  7479. if (!level) {
  7480. level = this._levels[zoom2] = {};
  7481. level.el = create$1("div", "leaflet-tile-container leaflet-zoom-animated", this._container);
  7482. level.el.style.zIndex = maxZoom;
  7483. level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom2).round();
  7484. level.zoom = zoom2;
  7485. this._setZoomTransform(level, map.getCenter(), map.getZoom());
  7486. falseFn(level.el.offsetWidth);
  7487. this._onCreateLevel(level);
  7488. }
  7489. this._level = level;
  7490. return level;
  7491. },
  7492. _onUpdateLevel: falseFn,
  7493. _onRemoveLevel: falseFn,
  7494. _onCreateLevel: falseFn,
  7495. _pruneTiles: function() {
  7496. if (!this._map) {
  7497. return;
  7498. }
  7499. var key, tile;
  7500. var zoom2 = this._map.getZoom();
  7501. if (zoom2 > this.options.maxZoom || zoom2 < this.options.minZoom) {
  7502. this._removeAllTiles();
  7503. return;
  7504. }
  7505. for (key in this._tiles) {
  7506. tile = this._tiles[key];
  7507. tile.retain = tile.current;
  7508. }
  7509. for (key in this._tiles) {
  7510. tile = this._tiles[key];
  7511. if (tile.current && !tile.active) {
  7512. var coords = tile.coords;
  7513. if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
  7514. this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
  7515. }
  7516. }
  7517. }
  7518. for (key in this._tiles) {
  7519. if (!this._tiles[key].retain) {
  7520. this._removeTile(key);
  7521. }
  7522. }
  7523. },
  7524. _removeTilesAtZoom: function(zoom2) {
  7525. for (var key in this._tiles) {
  7526. if (this._tiles[key].coords.z !== zoom2) {
  7527. continue;
  7528. }
  7529. this._removeTile(key);
  7530. }
  7531. },
  7532. _removeAllTiles: function() {
  7533. for (var key in this._tiles) {
  7534. this._removeTile(key);
  7535. }
  7536. },
  7537. _invalidateAll: function() {
  7538. for (var z in this._levels) {
  7539. remove(this._levels[z].el);
  7540. this._onRemoveLevel(Number(z));
  7541. delete this._levels[z];
  7542. }
  7543. this._removeAllTiles();
  7544. this._tileZoom = void 0;
  7545. },
  7546. _retainParent: function(x, y, z, minZoom) {
  7547. var x2 = Math.floor(x / 2), y2 = Math.floor(y / 2), z2 = z - 1, coords2 = new Point(+x2, +y2);
  7548. coords2.z = +z2;
  7549. var key = this._tileCoordsToKey(coords2), tile = this._tiles[key];
  7550. if (tile && tile.active) {
  7551. tile.retain = true;
  7552. return true;
  7553. } else if (tile && tile.loaded) {
  7554. tile.retain = true;
  7555. }
  7556. if (z2 > minZoom) {
  7557. return this._retainParent(x2, y2, z2, minZoom);
  7558. }
  7559. return false;
  7560. },
  7561. _retainChildren: function(x, y, z, maxZoom) {
  7562. for (var i = 2 * x; i < 2 * x + 2; i++) {
  7563. for (var j = 2 * y; j < 2 * y + 2; j++) {
  7564. var coords = new Point(i, j);
  7565. coords.z = z + 1;
  7566. var key = this._tileCoordsToKey(coords), tile = this._tiles[key];
  7567. if (tile && tile.active) {
  7568. tile.retain = true;
  7569. continue;
  7570. } else if (tile && tile.loaded) {
  7571. tile.retain = true;
  7572. }
  7573. if (z + 1 < maxZoom) {
  7574. this._retainChildren(i, j, z + 1, maxZoom);
  7575. }
  7576. }
  7577. }
  7578. },
  7579. _resetView: function(e) {
  7580. var animating = e && (e.pinch || e.flyTo);
  7581. this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
  7582. },
  7583. _animateZoom: function(e) {
  7584. this._setView(e.center, e.zoom, true, e.noUpdate);
  7585. },
  7586. _clampZoom: function(zoom2) {
  7587. var options = this.options;
  7588. if (void 0 !== options.minNativeZoom && zoom2 < options.minNativeZoom) {
  7589. return options.minNativeZoom;
  7590. }
  7591. if (void 0 !== options.maxNativeZoom && options.maxNativeZoom < zoom2) {
  7592. return options.maxNativeZoom;
  7593. }
  7594. return zoom2;
  7595. },
  7596. _setView: function(center, zoom2, noPrune, noUpdate) {
  7597. var tileZoom = Math.round(zoom2);
  7598. if (this.options.maxZoom !== void 0 && tileZoom > this.options.maxZoom || this.options.minZoom !== void 0 && tileZoom < this.options.minZoom) {
  7599. tileZoom = void 0;
  7600. } else {
  7601. tileZoom = this._clampZoom(tileZoom);
  7602. }
  7603. var tileZoomChanged = this.options.updateWhenZooming && tileZoom !== this._tileZoom;
  7604. if (!noUpdate || tileZoomChanged) {
  7605. this._tileZoom = tileZoom;
  7606. if (this._abortLoading) {
  7607. this._abortLoading();
  7608. }
  7609. this._updateLevels();
  7610. this._resetGrid();
  7611. if (tileZoom !== void 0) {
  7612. this._update(center);
  7613. }
  7614. if (!noPrune) {
  7615. this._pruneTiles();
  7616. }
  7617. this._noPrune = !!noPrune;
  7618. }
  7619. this._setZoomTransforms(center, zoom2);
  7620. },
  7621. _setZoomTransforms: function(center, zoom2) {
  7622. for (var i in this._levels) {
  7623. this._setZoomTransform(this._levels[i], center, zoom2);
  7624. }
  7625. },
  7626. _setZoomTransform: function(level, center, zoom2) {
  7627. var scale2 = this._map.getZoomScale(zoom2, level.zoom), translate = level.origin.multiplyBy(scale2).subtract(this._map._getNewPixelOrigin(center, zoom2)).round();
  7628. if (Browser.any3d) {
  7629. setTransform(level.el, translate, scale2);
  7630. } else {
  7631. setPosition(level.el, translate);
  7632. }
  7633. },
  7634. _resetGrid: function() {
  7635. var map = this._map, crs = map.options.crs, tileSize = this._tileSize = this.getTileSize(), tileZoom = this._tileZoom;
  7636. var bounds = this._map.getPixelWorldBounds(this._tileZoom);
  7637. if (bounds) {
  7638. this._globalTileRange = this._pxBoundsToTileRange(bounds);
  7639. }
  7640. this._wrapX = crs.wrapLng && !this.options.noWrap && [
  7641. Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
  7642. Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
  7643. ];
  7644. this._wrapY = crs.wrapLat && !this.options.noWrap && [
  7645. Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
  7646. Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
  7647. ];
  7648. },
  7649. _onMoveEnd: function() {
  7650. if (!this._map || this._map._animatingZoom) {
  7651. return;
  7652. }
  7653. this._update();
  7654. },
  7655. _getTiledPixelBounds: function(center) {
  7656. var map = this._map, mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(), scale2 = map.getZoomScale(mapZoom, this._tileZoom), pixelCenter = map.project(center, this._tileZoom).floor(), halfSize = map.getSize().divideBy(scale2 * 2);
  7657. return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
  7658. },
  7659. // Private method to load tiles in the grid's active zoom level according to map bounds
  7660. _update: function(center) {
  7661. var map = this._map;
  7662. if (!map) {
  7663. return;
  7664. }
  7665. var zoom2 = this._clampZoom(map.getZoom());
  7666. if (center === void 0) {
  7667. center = map.getCenter();
  7668. }
  7669. if (this._tileZoom === void 0) {
  7670. return;
  7671. }
  7672. var pixelBounds = this._getTiledPixelBounds(center), tileRange = this._pxBoundsToTileRange(pixelBounds), tileCenter = tileRange.getCenter(), queue = [], margin = this.options.keepBuffer, noPruneRange = new Bounds(
  7673. tileRange.getBottomLeft().subtract([margin, -margin]),
  7674. tileRange.getTopRight().add([margin, -margin])
  7675. );
  7676. if (!(isFinite(tileRange.min.x) && isFinite(tileRange.min.y) && isFinite(tileRange.max.x) && isFinite(tileRange.max.y))) {
  7677. throw new Error("Attempted to load an infinite number of tiles");
  7678. }
  7679. for (var key in this._tiles) {
  7680. var c = this._tiles[key].coords;
  7681. if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
  7682. this._tiles[key].current = false;
  7683. }
  7684. }
  7685. if (Math.abs(zoom2 - this._tileZoom) > 1) {
  7686. this._setView(center, zoom2);
  7687. return;
  7688. }
  7689. for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
  7690. for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
  7691. var coords = new Point(i, j);
  7692. coords.z = this._tileZoom;
  7693. if (!this._isValidTile(coords)) {
  7694. continue;
  7695. }
  7696. var tile = this._tiles[this._tileCoordsToKey(coords)];
  7697. if (tile) {
  7698. tile.current = true;
  7699. } else {
  7700. queue.push(coords);
  7701. }
  7702. }
  7703. }
  7704. queue.sort(function(a, b) {
  7705. return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
  7706. });
  7707. if (queue.length !== 0) {
  7708. if (!this._loading) {
  7709. this._loading = true;
  7710. this.fire("loading");
  7711. }
  7712. var fragment = document.createDocumentFragment();
  7713. for (i = 0; i < queue.length; i++) {
  7714. this._addTile(queue[i], fragment);
  7715. }
  7716. this._level.el.appendChild(fragment);
  7717. }
  7718. },
  7719. _isValidTile: function(coords) {
  7720. var crs = this._map.options.crs;
  7721. if (!crs.infinite) {
  7722. var bounds = this._globalTileRange;
  7723. if (!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x) || !crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y)) {
  7724. return false;
  7725. }
  7726. }
  7727. if (!this.options.bounds) {
  7728. return true;
  7729. }
  7730. var tileBounds = this._tileCoordsToBounds(coords);
  7731. return toLatLngBounds(this.options.bounds).overlaps(tileBounds);
  7732. },
  7733. _keyToBounds: function(key) {
  7734. return this._tileCoordsToBounds(this._keyToTileCoords(key));
  7735. },
  7736. _tileCoordsToNwSe: function(coords) {
  7737. var map = this._map, tileSize = this.getTileSize(), nwPoint = coords.scaleBy(tileSize), sePoint = nwPoint.add(tileSize), nw = map.unproject(nwPoint, coords.z), se = map.unproject(sePoint, coords.z);
  7738. return [nw, se];
  7739. },
  7740. // converts tile coordinates to its geographical bounds
  7741. _tileCoordsToBounds: function(coords) {
  7742. var bp = this._tileCoordsToNwSe(coords), bounds = new LatLngBounds(bp[0], bp[1]);
  7743. if (!this.options.noWrap) {
  7744. bounds = this._map.wrapLatLngBounds(bounds);
  7745. }
  7746. return bounds;
  7747. },
  7748. // converts tile coordinates to key for the tile cache
  7749. _tileCoordsToKey: function(coords) {
  7750. return coords.x + ":" + coords.y + ":" + coords.z;
  7751. },
  7752. // converts tile cache key to coordinates
  7753. _keyToTileCoords: function(key) {
  7754. var k = key.split(":"), coords = new Point(+k[0], +k[1]);
  7755. coords.z = +k[2];
  7756. return coords;
  7757. },
  7758. _removeTile: function(key) {
  7759. var tile = this._tiles[key];
  7760. if (!tile) {
  7761. return;
  7762. }
  7763. remove(tile.el);
  7764. delete this._tiles[key];
  7765. this.fire("tileunload", {
  7766. tile: tile.el,
  7767. coords: this._keyToTileCoords(key)
  7768. });
  7769. },
  7770. _initTile: function(tile) {
  7771. addClass(tile, "leaflet-tile");
  7772. var tileSize = this.getTileSize();
  7773. tile.style.width = tileSize.x + "px";
  7774. tile.style.height = tileSize.y + "px";
  7775. tile.onselectstart = falseFn;
  7776. tile.onmousemove = falseFn;
  7777. if (Browser.ielt9 && this.options.opacity < 1) {
  7778. setOpacity(tile, this.options.opacity);
  7779. }
  7780. },
  7781. _addTile: function(coords, container) {
  7782. var tilePos = this._getTilePos(coords), key = this._tileCoordsToKey(coords);
  7783. var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));
  7784. this._initTile(tile);
  7785. if (this.createTile.length < 2) {
  7786. requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
  7787. }
  7788. setPosition(tile, tilePos);
  7789. this._tiles[key] = {
  7790. el: tile,
  7791. coords,
  7792. current: true
  7793. };
  7794. container.appendChild(tile);
  7795. this.fire("tileloadstart", {
  7796. tile,
  7797. coords
  7798. });
  7799. },
  7800. _tileReady: function(coords, err, tile) {
  7801. if (err) {
  7802. this.fire("tileerror", {
  7803. error: err,
  7804. tile,
  7805. coords
  7806. });
  7807. }
  7808. var key = this._tileCoordsToKey(coords);
  7809. tile = this._tiles[key];
  7810. if (!tile) {
  7811. return;
  7812. }
  7813. tile.loaded = +/* @__PURE__ */ new Date();
  7814. if (this._map._fadeAnimated) {
  7815. setOpacity(tile.el, 0);
  7816. cancelAnimFrame(this._fadeFrame);
  7817. this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
  7818. } else {
  7819. tile.active = true;
  7820. this._pruneTiles();
  7821. }
  7822. if (!err) {
  7823. addClass(tile.el, "leaflet-tile-loaded");
  7824. this.fire("tileload", {
  7825. tile: tile.el,
  7826. coords
  7827. });
  7828. }
  7829. if (this._noTilesToLoad()) {
  7830. this._loading = false;
  7831. this.fire("load");
  7832. if (Browser.ielt9 || !this._map._fadeAnimated) {
  7833. requestAnimFrame(this._pruneTiles, this);
  7834. } else {
  7835. setTimeout(bind(this._pruneTiles, this), 250);
  7836. }
  7837. }
  7838. },
  7839. _getTilePos: function(coords) {
  7840. return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
  7841. },
  7842. _wrapCoords: function(coords) {
  7843. var newCoords = new Point(
  7844. this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,
  7845. this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y
  7846. );
  7847. newCoords.z = coords.z;
  7848. return newCoords;
  7849. },
  7850. _pxBoundsToTileRange: function(bounds) {
  7851. var tileSize = this.getTileSize();
  7852. return new Bounds(
  7853. bounds.min.unscaleBy(tileSize).floor(),
  7854. bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1])
  7855. );
  7856. },
  7857. _noTilesToLoad: function() {
  7858. for (var key in this._tiles) {
  7859. if (!this._tiles[key].loaded) {
  7860. return false;
  7861. }
  7862. }
  7863. return true;
  7864. }
  7865. });
  7866. function gridLayer(options) {
  7867. return new GridLayer(options);
  7868. }
  7869. var TileLayer = GridLayer.extend({
  7870. // @section
  7871. // @aka TileLayer options
  7872. options: {
  7873. // @option minZoom: Number = 0
  7874. // The minimum zoom level down to which this layer will be displayed (inclusive).
  7875. minZoom: 0,
  7876. // @option maxZoom: Number = 18
  7877. // The maximum zoom level up to which this layer will be displayed (inclusive).
  7878. maxZoom: 18,
  7879. // @option subdomains: String|String[] = 'abc'
  7880. // 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.
  7881. subdomains: "abc",
  7882. // @option errorTileUrl: String = ''
  7883. // URL to the tile image to show in place of the tile that failed to load.
  7884. errorTileUrl: "",
  7885. // @option zoomOffset: Number = 0
  7886. // The zoom number used in tile URLs will be offset with this value.
  7887. zoomOffset: 0,
  7888. // @option tms: Boolean = false
  7889. // If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
  7890. tms: false,
  7891. // @option zoomReverse: Boolean = false
  7892. // If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
  7893. zoomReverse: false,
  7894. // @option detectRetina: Boolean = false
  7895. // 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.
  7896. detectRetina: false,
  7897. // @option crossOrigin: Boolean|String = false
  7898. // Whether the crossOrigin attribute will be added to the tiles.
  7899. // 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.
  7900. // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
  7901. crossOrigin: false,
  7902. // @option referrerPolicy: Boolean|String = false
  7903. // Whether the referrerPolicy attribute will be added to the tiles.
  7904. // If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.
  7905. // This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer
  7906. // (e.g. to validate an API token).
  7907. // Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.
  7908. referrerPolicy: false
  7909. },
  7910. initialize: function(url, options) {
  7911. this._url = url;
  7912. options = setOptions(this, options);
  7913. if (options.detectRetina && Browser.retina && options.maxZoom > 0) {
  7914. options.tileSize = Math.floor(options.tileSize / 2);
  7915. if (!options.zoomReverse) {
  7916. options.zoomOffset++;
  7917. options.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);
  7918. } else {
  7919. options.zoomOffset--;
  7920. options.minZoom = Math.min(options.maxZoom, options.minZoom + 1);
  7921. }
  7922. options.minZoom = Math.max(0, options.minZoom);
  7923. } else if (!options.zoomReverse) {
  7924. options.maxZoom = Math.max(options.minZoom, options.maxZoom);
  7925. } else {
  7926. options.minZoom = Math.min(options.maxZoom, options.minZoom);
  7927. }
  7928. if (typeof options.subdomains === "string") {
  7929. options.subdomains = options.subdomains.split("");
  7930. }
  7931. this.on("tileunload", this._onTileRemove);
  7932. },
  7933. // @method setUrl(url: String, noRedraw?: Boolean): this
  7934. // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
  7935. // If the URL does not change, the layer will not be redrawn unless
  7936. // the noRedraw parameter is set to false.
  7937. setUrl: function(url, noRedraw) {
  7938. if (this._url === url && noRedraw === void 0) {
  7939. noRedraw = true;
  7940. }
  7941. this._url = url;
  7942. if (!noRedraw) {
  7943. this.redraw();
  7944. }
  7945. return this;
  7946. },
  7947. // @method createTile(coords: Object, done?: Function): HTMLElement
  7948. // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
  7949. // to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
  7950. // callback is called when the tile has been loaded.
  7951. createTile: function(coords, done) {
  7952. var tile = document.createElement("img");
  7953. on(tile, "load", bind(this._tileOnLoad, this, done, tile));
  7954. on(tile, "error", bind(this._tileOnError, this, done, tile));
  7955. if (this.options.crossOrigin || this.options.crossOrigin === "") {
  7956. tile.crossOrigin = this.options.crossOrigin === true ? "" : this.options.crossOrigin;
  7957. }
  7958. if (typeof this.options.referrerPolicy === "string") {
  7959. tile.referrerPolicy = this.options.referrerPolicy;
  7960. }
  7961. tile.alt = "";
  7962. tile.src = this.getTileUrl(coords);
  7963. return tile;
  7964. },
  7965. // @section Extension methods
  7966. // @uninheritable
  7967. // Layers extending `TileLayer` might reimplement the following method.
  7968. // @method getTileUrl(coords: Object): String
  7969. // Called only internally, returns the URL for a tile given its coordinates.
  7970. // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
  7971. getTileUrl: function(coords) {
  7972. var data = {
  7973. r: Browser.retina ? "@2x" : "",
  7974. s: this._getSubdomain(coords),
  7975. x: coords.x,
  7976. y: coords.y,
  7977. z: this._getZoomForUrl()
  7978. };
  7979. if (this._map && !this._map.options.crs.infinite) {
  7980. var invertedY = this._globalTileRange.max.y - coords.y;
  7981. if (this.options.tms) {
  7982. data["y"] = invertedY;
  7983. }
  7984. data["-y"] = invertedY;
  7985. }
  7986. return template(this._url, extend(data, this.options));
  7987. },
  7988. _tileOnLoad: function(done, tile) {
  7989. if (Browser.ielt9) {
  7990. setTimeout(bind(done, this, null, tile), 0);
  7991. } else {
  7992. done(null, tile);
  7993. }
  7994. },
  7995. _tileOnError: function(done, tile, e) {
  7996. var errorUrl = this.options.errorTileUrl;
  7997. if (errorUrl && tile.getAttribute("src") !== errorUrl) {
  7998. tile.src = errorUrl;
  7999. }
  8000. done(e, tile);
  8001. },
  8002. _onTileRemove: function(e) {
  8003. e.tile.onload = null;
  8004. },
  8005. _getZoomForUrl: function() {
  8006. var zoom2 = this._tileZoom, maxZoom = this.options.maxZoom, zoomReverse = this.options.zoomReverse, zoomOffset = this.options.zoomOffset;
  8007. if (zoomReverse) {
  8008. zoom2 = maxZoom - zoom2;
  8009. }
  8010. return zoom2 + zoomOffset;
  8011. },
  8012. _getSubdomain: function(tilePoint) {
  8013. var index2 = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
  8014. return this.options.subdomains[index2];
  8015. },
  8016. // stops loading all tiles in the background layer
  8017. _abortLoading: function() {
  8018. var i, tile;
  8019. for (i in this._tiles) {
  8020. if (this._tiles[i].coords.z !== this._tileZoom) {
  8021. tile = this._tiles[i].el;
  8022. tile.onload = falseFn;
  8023. tile.onerror = falseFn;
  8024. if (!tile.complete) {
  8025. tile.src = emptyImageUrl;
  8026. var coords = this._tiles[i].coords;
  8027. remove(tile);
  8028. delete this._tiles[i];
  8029. this.fire("tileabort", {
  8030. tile,
  8031. coords
  8032. });
  8033. }
  8034. }
  8035. }
  8036. },
  8037. _removeTile: function(key) {
  8038. var tile = this._tiles[key];
  8039. if (!tile) {
  8040. return;
  8041. }
  8042. tile.el.setAttribute("src", emptyImageUrl);
  8043. return GridLayer.prototype._removeTile.call(this, key);
  8044. },
  8045. _tileReady: function(coords, err, tile) {
  8046. if (!this._map || tile && tile.getAttribute("src") === emptyImageUrl) {
  8047. return;
  8048. }
  8049. return GridLayer.prototype._tileReady.call(this, coords, err, tile);
  8050. }
  8051. });
  8052. function tileLayer(url, options) {
  8053. return new TileLayer(url, options);
  8054. }
  8055. var TileLayerWMS = TileLayer.extend({
  8056. // @section
  8057. // @aka TileLayer.WMS options
  8058. // If any custom options not documented here are used, they will be sent to the
  8059. // WMS server as extra parameters in each request URL. This can be useful for
  8060. // [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
  8061. defaultWmsParams: {
  8062. service: "WMS",
  8063. request: "GetMap",
  8064. // @option layers: String = ''
  8065. // **(required)** Comma-separated list of WMS layers to show.
  8066. layers: "",
  8067. // @option styles: String = ''
  8068. // Comma-separated list of WMS styles.
  8069. styles: "",
  8070. // @option format: String = 'image/jpeg'
  8071. // WMS image format (use `'image/png'` for layers with transparency).
  8072. format: "image/jpeg",
  8073. // @option transparent: Boolean = false
  8074. // If `true`, the WMS service will return images with transparency.
  8075. transparent: false,
  8076. // @option version: String = '1.1.1'
  8077. // Version of the WMS service to use
  8078. version: "1.1.1"
  8079. },
  8080. options: {
  8081. // @option crs: CRS = null
  8082. // Coordinate Reference System to use for the WMS requests, defaults to
  8083. // map CRS. Don't change this if you're not sure what it means.
  8084. crs: null,
  8085. // @option uppercase: Boolean = false
  8086. // If `true`, WMS request parameter keys will be uppercase.
  8087. uppercase: false
  8088. },
  8089. initialize: function(url, options) {
  8090. this._url = url;
  8091. var wmsParams = extend({}, this.defaultWmsParams);
  8092. for (var i in options) {
  8093. if (!(i in this.options)) {
  8094. wmsParams[i] = options[i];
  8095. }
  8096. }
  8097. options = setOptions(this, options);
  8098. var realRetina = options.detectRetina && Browser.retina ? 2 : 1;
  8099. var tileSize = this.getTileSize();
  8100. wmsParams.width = tileSize.x * realRetina;
  8101. wmsParams.height = tileSize.y * realRetina;
  8102. this.wmsParams = wmsParams;
  8103. },
  8104. onAdd: function(map) {
  8105. this._crs = this.options.crs || map.options.crs;
  8106. this._wmsVersion = parseFloat(this.wmsParams.version);
  8107. var projectionKey = this._wmsVersion >= 1.3 ? "crs" : "srs";
  8108. this.wmsParams[projectionKey] = this._crs.code;
  8109. TileLayer.prototype.onAdd.call(this, map);
  8110. },
  8111. getTileUrl: function(coords) {
  8112. var tileBounds = this._tileCoordsToNwSe(coords), crs = this._crs, bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])), min = bounds.min, max = bounds.max, bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ? [min.y, min.x, max.y, max.x] : [min.x, min.y, max.x, max.y]).join(","), url = TileLayer.prototype.getTileUrl.call(this, coords);
  8113. return url + getParamString(this.wmsParams, url, this.options.uppercase) + (this.options.uppercase ? "&BBOX=" : "&bbox=") + bbox;
  8114. },
  8115. // @method setParams(params: Object, noRedraw?: Boolean): this
  8116. // Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
  8117. setParams: function(params, noRedraw) {
  8118. extend(this.wmsParams, params);
  8119. if (!noRedraw) {
  8120. this.redraw();
  8121. }
  8122. return this;
  8123. }
  8124. });
  8125. function tileLayerWMS(url, options) {
  8126. return new TileLayerWMS(url, options);
  8127. }
  8128. TileLayer.WMS = TileLayerWMS;
  8129. tileLayer.wms = tileLayerWMS;
  8130. var Renderer = Layer.extend({
  8131. // @section
  8132. // @aka Renderer options
  8133. options: {
  8134. // @option padding: Number = 0.1
  8135. // How much to extend the clip area around the map view (relative to its size)
  8136. // e.g. 0.1 would be 10% of map view in each direction
  8137. padding: 0.1
  8138. },
  8139. initialize: function(options) {
  8140. setOptions(this, options);
  8141. stamp(this);
  8142. this._layers = this._layers || {};
  8143. },
  8144. onAdd: function() {
  8145. if (!this._container) {
  8146. this._initContainer();
  8147. addClass(this._container, "leaflet-zoom-animated");
  8148. }
  8149. this.getPane().appendChild(this._container);
  8150. this._update();
  8151. this.on("update", this._updatePaths, this);
  8152. },
  8153. onRemove: function() {
  8154. this.off("update", this._updatePaths, this);
  8155. this._destroyContainer();
  8156. },
  8157. getEvents: function() {
  8158. var events = {
  8159. viewreset: this._reset,
  8160. zoom: this._onZoom,
  8161. moveend: this._update,
  8162. zoomend: this._onZoomEnd
  8163. };
  8164. if (this._zoomAnimated) {
  8165. events.zoomanim = this._onAnimZoom;
  8166. }
  8167. return events;
  8168. },
  8169. _onAnimZoom: function(ev) {
  8170. this._updateTransform(ev.center, ev.zoom);
  8171. },
  8172. _onZoom: function() {
  8173. this._updateTransform(this._map.getCenter(), this._map.getZoom());
  8174. },
  8175. _updateTransform: function(center, zoom2) {
  8176. var scale2 = this._map.getZoomScale(zoom2, this._zoom), viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding), currentCenterPoint = this._map.project(this._center, zoom2), topLeftOffset = viewHalf.multiplyBy(-scale2).add(currentCenterPoint).subtract(this._map._getNewPixelOrigin(center, zoom2));
  8177. if (Browser.any3d) {
  8178. setTransform(this._container, topLeftOffset, scale2);
  8179. } else {
  8180. setPosition(this._container, topLeftOffset);
  8181. }
  8182. },
  8183. _reset: function() {
  8184. this._update();
  8185. this._updateTransform(this._center, this._zoom);
  8186. for (var id in this._layers) {
  8187. this._layers[id]._reset();
  8188. }
  8189. },
  8190. _onZoomEnd: function() {
  8191. for (var id in this._layers) {
  8192. this._layers[id]._project();
  8193. }
  8194. },
  8195. _updatePaths: function() {
  8196. for (var id in this._layers) {
  8197. this._layers[id]._update();
  8198. }
  8199. },
  8200. _update: function() {
  8201. var p = this.options.padding, size = this._map.getSize(), min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
  8202. this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
  8203. this._center = this._map.getCenter();
  8204. this._zoom = this._map.getZoom();
  8205. }
  8206. });
  8207. var Canvas = Renderer.extend({
  8208. // @section
  8209. // @aka Canvas options
  8210. options: {
  8211. // @option tolerance: Number = 0
  8212. // How much to extend the click tolerance around a path/object on the map.
  8213. tolerance: 0
  8214. },
  8215. getEvents: function() {
  8216. var events = Renderer.prototype.getEvents.call(this);
  8217. events.viewprereset = this._onViewPreReset;
  8218. return events;
  8219. },
  8220. _onViewPreReset: function() {
  8221. this._postponeUpdatePaths = true;
  8222. },
  8223. onAdd: function() {
  8224. Renderer.prototype.onAdd.call(this);
  8225. this._draw();
  8226. },
  8227. _initContainer: function() {
  8228. var container = this._container = document.createElement("canvas");
  8229. on(container, "mousemove", this._onMouseMove, this);
  8230. on(container, "click dblclick mousedown mouseup contextmenu", this._onClick, this);
  8231. on(container, "mouseout", this._handleMouseOut, this);
  8232. container["_leaflet_disable_events"] = true;
  8233. this._ctx = container.getContext("2d");
  8234. },
  8235. _destroyContainer: function() {
  8236. cancelAnimFrame(this._redrawRequest);
  8237. delete this._ctx;
  8238. remove(this._container);
  8239. off(this._container);
  8240. delete this._container;
  8241. },
  8242. _updatePaths: function() {
  8243. if (this._postponeUpdatePaths) {
  8244. return;
  8245. }
  8246. var layer;
  8247. this._redrawBounds = null;
  8248. for (var id in this._layers) {
  8249. layer = this._layers[id];
  8250. layer._update();
  8251. }
  8252. this._redraw();
  8253. },
  8254. _update: function() {
  8255. if (this._map._animatingZoom && this._bounds) {
  8256. return;
  8257. }
  8258. Renderer.prototype._update.call(this);
  8259. var b = this._bounds, container = this._container, size = b.getSize(), m = Browser.retina ? 2 : 1;
  8260. setPosition(container, b.min);
  8261. container.width = m * size.x;
  8262. container.height = m * size.y;
  8263. container.style.width = size.x + "px";
  8264. container.style.height = size.y + "px";
  8265. if (Browser.retina) {
  8266. this._ctx.scale(2, 2);
  8267. }
  8268. this._ctx.translate(-b.min.x, -b.min.y);
  8269. this.fire("update");
  8270. },
  8271. _reset: function() {
  8272. Renderer.prototype._reset.call(this);
  8273. if (this._postponeUpdatePaths) {
  8274. this._postponeUpdatePaths = false;
  8275. this._updatePaths();
  8276. }
  8277. },
  8278. _initPath: function(layer) {
  8279. this._updateDashArray(layer);
  8280. this._layers[stamp(layer)] = layer;
  8281. var order = layer._order = {
  8282. layer,
  8283. prev: this._drawLast,
  8284. next: null
  8285. };
  8286. if (this._drawLast) {
  8287. this._drawLast.next = order;
  8288. }
  8289. this._drawLast = order;
  8290. this._drawFirst = this._drawFirst || this._drawLast;
  8291. },
  8292. _addPath: function(layer) {
  8293. this._requestRedraw(layer);
  8294. },
  8295. _removePath: function(layer) {
  8296. var order = layer._order;
  8297. var next = order.next;
  8298. var prev = order.prev;
  8299. if (next) {
  8300. next.prev = prev;
  8301. } else {
  8302. this._drawLast = prev;
  8303. }
  8304. if (prev) {
  8305. prev.next = next;
  8306. } else {
  8307. this._drawFirst = next;
  8308. }
  8309. delete layer._order;
  8310. delete this._layers[stamp(layer)];
  8311. this._requestRedraw(layer);
  8312. },
  8313. _updatePath: function(layer) {
  8314. this._extendRedrawBounds(layer);
  8315. layer._project();
  8316. layer._update();
  8317. this._requestRedraw(layer);
  8318. },
  8319. _updateStyle: function(layer) {
  8320. this._updateDashArray(layer);
  8321. this._requestRedraw(layer);
  8322. },
  8323. _updateDashArray: function(layer) {
  8324. if (typeof layer.options.dashArray === "string") {
  8325. var parts = layer.options.dashArray.split(/[, ]+/), dashArray = [], dashValue, i;
  8326. for (i = 0; i < parts.length; i++) {
  8327. dashValue = Number(parts[i]);
  8328. if (isNaN(dashValue)) {
  8329. return;
  8330. }
  8331. dashArray.push(dashValue);
  8332. }
  8333. layer.options._dashArray = dashArray;
  8334. } else {
  8335. layer.options._dashArray = layer.options.dashArray;
  8336. }
  8337. },
  8338. _requestRedraw: function(layer) {
  8339. if (!this._map) {
  8340. return;
  8341. }
  8342. this._extendRedrawBounds(layer);
  8343. this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);
  8344. },
  8345. _extendRedrawBounds: function(layer) {
  8346. if (layer._pxBounds) {
  8347. var padding = (layer.options.weight || 0) + 1;
  8348. this._redrawBounds = this._redrawBounds || new Bounds();
  8349. this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
  8350. this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
  8351. }
  8352. },
  8353. _redraw: function() {
  8354. this._redrawRequest = null;
  8355. if (this._redrawBounds) {
  8356. this._redrawBounds.min._floor();
  8357. this._redrawBounds.max._ceil();
  8358. }
  8359. this._clear();
  8360. this._draw();
  8361. this._redrawBounds = null;
  8362. },
  8363. _clear: function() {
  8364. var bounds = this._redrawBounds;
  8365. if (bounds) {
  8366. var size = bounds.getSize();
  8367. this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
  8368. } else {
  8369. this._ctx.save();
  8370. this._ctx.setTransform(1, 0, 0, 1, 0, 0);
  8371. this._ctx.clearRect(0, 0, this._container.width, this._container.height);
  8372. this._ctx.restore();
  8373. }
  8374. },
  8375. _draw: function() {
  8376. var layer, bounds = this._redrawBounds;
  8377. this._ctx.save();
  8378. if (bounds) {
  8379. var size = bounds.getSize();
  8380. this._ctx.beginPath();
  8381. this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
  8382. this._ctx.clip();
  8383. }
  8384. this._drawing = true;
  8385. for (var order = this._drawFirst; order; order = order.next) {
  8386. layer = order.layer;
  8387. if (!bounds || layer._pxBounds && layer._pxBounds.intersects(bounds)) {
  8388. layer._updatePath();
  8389. }
  8390. }
  8391. this._drawing = false;
  8392. this._ctx.restore();
  8393. },
  8394. _updatePoly: function(layer, closed) {
  8395. if (!this._drawing) {
  8396. return;
  8397. }
  8398. var i, j, len2, p, parts = layer._parts, len = parts.length, ctx = this._ctx;
  8399. if (!len) {
  8400. return;
  8401. }
  8402. ctx.beginPath();
  8403. for (i = 0; i < len; i++) {
  8404. for (j = 0, len2 = parts[i].length; j < len2; j++) {
  8405. p = parts[i][j];
  8406. ctx[j ? "lineTo" : "moveTo"](p.x, p.y);
  8407. }
  8408. if (closed) {
  8409. ctx.closePath();
  8410. }
  8411. }
  8412. this._fillStroke(ctx, layer);
  8413. },
  8414. _updateCircle: function(layer) {
  8415. if (!this._drawing || layer._empty()) {
  8416. return;
  8417. }
  8418. var p = layer._point, ctx = this._ctx, r = Math.max(Math.round(layer._radius), 1), s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
  8419. if (s !== 1) {
  8420. ctx.save();
  8421. ctx.scale(1, s);
  8422. }
  8423. ctx.beginPath();
  8424. ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
  8425. if (s !== 1) {
  8426. ctx.restore();
  8427. }
  8428. this._fillStroke(ctx, layer);
  8429. },
  8430. _fillStroke: function(ctx, layer) {
  8431. var options = layer.options;
  8432. if (options.fill) {
  8433. ctx.globalAlpha = options.fillOpacity;
  8434. ctx.fillStyle = options.fillColor || options.color;
  8435. ctx.fill(options.fillRule || "evenodd");
  8436. }
  8437. if (options.stroke && options.weight !== 0) {
  8438. if (ctx.setLineDash) {
  8439. ctx.setLineDash(layer.options && layer.options._dashArray || []);
  8440. }
  8441. ctx.globalAlpha = options.opacity;
  8442. ctx.lineWidth = options.weight;
  8443. ctx.strokeStyle = options.color;
  8444. ctx.lineCap = options.lineCap;
  8445. ctx.lineJoin = options.lineJoin;
  8446. ctx.stroke();
  8447. }
  8448. },
  8449. // Canvas obviously doesn't have mouse events for individual drawn objects,
  8450. // so we emulate that by calculating what's under the mouse on mousemove/click manually
  8451. _onClick: function(e) {
  8452. var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
  8453. for (var order = this._drawFirst; order; order = order.next) {
  8454. layer = order.layer;
  8455. if (layer.options.interactive && layer._containsPoint(point)) {
  8456. if (!(e.type === "click" || e.type === "preclick") || !this._map._draggableMoved(layer)) {
  8457. clickedLayer = layer;
  8458. }
  8459. }
  8460. }
  8461. this._fireEvent(clickedLayer ? [clickedLayer] : false, e);
  8462. },
  8463. _onMouseMove: function(e) {
  8464. if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) {
  8465. return;
  8466. }
  8467. var point = this._map.mouseEventToLayerPoint(e);
  8468. this._handleMouseHover(e, point);
  8469. },
  8470. _handleMouseOut: function(e) {
  8471. var layer = this._hoveredLayer;
  8472. if (layer) {
  8473. removeClass(this._container, "leaflet-interactive");
  8474. this._fireEvent([layer], e, "mouseout");
  8475. this._hoveredLayer = null;
  8476. this._mouseHoverThrottled = false;
  8477. }
  8478. },
  8479. _handleMouseHover: function(e, point) {
  8480. if (this._mouseHoverThrottled) {
  8481. return;
  8482. }
  8483. var layer, candidateHoveredLayer;
  8484. for (var order = this._drawFirst; order; order = order.next) {
  8485. layer = order.layer;
  8486. if (layer.options.interactive && layer._containsPoint(point)) {
  8487. candidateHoveredLayer = layer;
  8488. }
  8489. }
  8490. if (candidateHoveredLayer !== this._hoveredLayer) {
  8491. this._handleMouseOut(e);
  8492. if (candidateHoveredLayer) {
  8493. addClass(this._container, "leaflet-interactive");
  8494. this._fireEvent([candidateHoveredLayer], e, "mouseover");
  8495. this._hoveredLayer = candidateHoveredLayer;
  8496. }
  8497. }
  8498. this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);
  8499. this._mouseHoverThrottled = true;
  8500. setTimeout(bind(function() {
  8501. this._mouseHoverThrottled = false;
  8502. }, this), 32);
  8503. },
  8504. _fireEvent: function(layers2, e, type) {
  8505. this._map._fireDOMEvent(e, type || e.type, layers2);
  8506. },
  8507. _bringToFront: function(layer) {
  8508. var order = layer._order;
  8509. if (!order) {
  8510. return;
  8511. }
  8512. var next = order.next;
  8513. var prev = order.prev;
  8514. if (next) {
  8515. next.prev = prev;
  8516. } else {
  8517. return;
  8518. }
  8519. if (prev) {
  8520. prev.next = next;
  8521. } else if (next) {
  8522. this._drawFirst = next;
  8523. }
  8524. order.prev = this._drawLast;
  8525. this._drawLast.next = order;
  8526. order.next = null;
  8527. this._drawLast = order;
  8528. this._requestRedraw(layer);
  8529. },
  8530. _bringToBack: function(layer) {
  8531. var order = layer._order;
  8532. if (!order) {
  8533. return;
  8534. }
  8535. var next = order.next;
  8536. var prev = order.prev;
  8537. if (prev) {
  8538. prev.next = next;
  8539. } else {
  8540. return;
  8541. }
  8542. if (next) {
  8543. next.prev = prev;
  8544. } else if (prev) {
  8545. this._drawLast = prev;
  8546. }
  8547. order.prev = null;
  8548. order.next = this._drawFirst;
  8549. this._drawFirst.prev = order;
  8550. this._drawFirst = order;
  8551. this._requestRedraw(layer);
  8552. }
  8553. });
  8554. function canvas(options) {
  8555. return Browser.canvas ? new Canvas(options) : null;
  8556. }
  8557. var vmlCreate = function() {
  8558. try {
  8559. document.namespaces.add("lvml", "urn:schemas-microsoft-com:vml");
  8560. return function(name) {
  8561. return document.createElement("<lvml:" + name + ' class="lvml">');
  8562. };
  8563. } catch (e) {
  8564. }
  8565. return function(name) {
  8566. return document.createElement("<" + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
  8567. };
  8568. }();
  8569. var vmlMixin = {
  8570. _initContainer: function() {
  8571. this._container = create$1("div", "leaflet-vml-container");
  8572. },
  8573. _update: function() {
  8574. if (this._map._animatingZoom) {
  8575. return;
  8576. }
  8577. Renderer.prototype._update.call(this);
  8578. this.fire("update");
  8579. },
  8580. _initPath: function(layer) {
  8581. var container = layer._container = vmlCreate("shape");
  8582. addClass(container, "leaflet-vml-shape " + (this.options.className || ""));
  8583. container.coordsize = "1 1";
  8584. layer._path = vmlCreate("path");
  8585. container.appendChild(layer._path);
  8586. this._updateStyle(layer);
  8587. this._layers[stamp(layer)] = layer;
  8588. },
  8589. _addPath: function(layer) {
  8590. var container = layer._container;
  8591. this._container.appendChild(container);
  8592. if (layer.options.interactive) {
  8593. layer.addInteractiveTarget(container);
  8594. }
  8595. },
  8596. _removePath: function(layer) {
  8597. var container = layer._container;
  8598. remove(container);
  8599. layer.removeInteractiveTarget(container);
  8600. delete this._layers[stamp(layer)];
  8601. },
  8602. _updateStyle: function(layer) {
  8603. var stroke = layer._stroke, fill = layer._fill, options = layer.options, container = layer._container;
  8604. container.stroked = !!options.stroke;
  8605. container.filled = !!options.fill;
  8606. if (options.stroke) {
  8607. if (!stroke) {
  8608. stroke = layer._stroke = vmlCreate("stroke");
  8609. }
  8610. container.appendChild(stroke);
  8611. stroke.weight = options.weight + "px";
  8612. stroke.color = options.color;
  8613. stroke.opacity = options.opacity;
  8614. if (options.dashArray) {
  8615. stroke.dashStyle = isArray(options.dashArray) ? options.dashArray.join(" ") : options.dashArray.replace(/( *, *)/g, " ");
  8616. } else {
  8617. stroke.dashStyle = "";
  8618. }
  8619. stroke.endcap = options.lineCap.replace("butt", "flat");
  8620. stroke.joinstyle = options.lineJoin;
  8621. } else if (stroke) {
  8622. container.removeChild(stroke);
  8623. layer._stroke = null;
  8624. }
  8625. if (options.fill) {
  8626. if (!fill) {
  8627. fill = layer._fill = vmlCreate("fill");
  8628. }
  8629. container.appendChild(fill);
  8630. fill.color = options.fillColor || options.color;
  8631. fill.opacity = options.fillOpacity;
  8632. } else if (fill) {
  8633. container.removeChild(fill);
  8634. layer._fill = null;
  8635. }
  8636. },
  8637. _updateCircle: function(layer) {
  8638. var p = layer._point.round(), r = Math.round(layer._radius), r2 = Math.round(layer._radiusY || r);
  8639. this._setPath(layer, layer._empty() ? "M0 0" : "AL " + p.x + "," + p.y + " " + r + "," + r2 + " 0," + 65535 * 360);
  8640. },
  8641. _setPath: function(layer, path) {
  8642. layer._path.v = path;
  8643. },
  8644. _bringToFront: function(layer) {
  8645. toFront(layer._container);
  8646. },
  8647. _bringToBack: function(layer) {
  8648. toBack(layer._container);
  8649. }
  8650. };
  8651. var create = Browser.vml ? vmlCreate : svgCreate;
  8652. var SVG = Renderer.extend({
  8653. _initContainer: function() {
  8654. this._container = create("svg");
  8655. this._container.setAttribute("pointer-events", "none");
  8656. this._rootGroup = create("g");
  8657. this._container.appendChild(this._rootGroup);
  8658. },
  8659. _destroyContainer: function() {
  8660. remove(this._container);
  8661. off(this._container);
  8662. delete this._container;
  8663. delete this._rootGroup;
  8664. delete this._svgSize;
  8665. },
  8666. _update: function() {
  8667. if (this._map._animatingZoom && this._bounds) {
  8668. return;
  8669. }
  8670. Renderer.prototype._update.call(this);
  8671. var b = this._bounds, size = b.getSize(), container = this._container;
  8672. if (!this._svgSize || !this._svgSize.equals(size)) {
  8673. this._svgSize = size;
  8674. container.setAttribute("width", size.x);
  8675. container.setAttribute("height", size.y);
  8676. }
  8677. setPosition(container, b.min);
  8678. container.setAttribute("viewBox", [b.min.x, b.min.y, size.x, size.y].join(" "));
  8679. this.fire("update");
  8680. },
  8681. // methods below are called by vector layers implementations
  8682. _initPath: function(layer) {
  8683. var path = layer._path = create("path");
  8684. if (layer.options.className) {
  8685. addClass(path, layer.options.className);
  8686. }
  8687. if (layer.options.interactive) {
  8688. addClass(path, "leaflet-interactive");
  8689. }
  8690. this._updateStyle(layer);
  8691. this._layers[stamp(layer)] = layer;
  8692. },
  8693. _addPath: function(layer) {
  8694. if (!this._rootGroup) {
  8695. this._initContainer();
  8696. }
  8697. this._rootGroup.appendChild(layer._path);
  8698. layer.addInteractiveTarget(layer._path);
  8699. },
  8700. _removePath: function(layer) {
  8701. remove(layer._path);
  8702. layer.removeInteractiveTarget(layer._path);
  8703. delete this._layers[stamp(layer)];
  8704. },
  8705. _updatePath: function(layer) {
  8706. layer._project();
  8707. layer._update();
  8708. },
  8709. _updateStyle: function(layer) {
  8710. var path = layer._path, options = layer.options;
  8711. if (!path) {
  8712. return;
  8713. }
  8714. if (options.stroke) {
  8715. path.setAttribute("stroke", options.color);
  8716. path.setAttribute("stroke-opacity", options.opacity);
  8717. path.setAttribute("stroke-width", options.weight);
  8718. path.setAttribute("stroke-linecap", options.lineCap);
  8719. path.setAttribute("stroke-linejoin", options.lineJoin);
  8720. if (options.dashArray) {
  8721. path.setAttribute("stroke-dasharray", options.dashArray);
  8722. } else {
  8723. path.removeAttribute("stroke-dasharray");
  8724. }
  8725. if (options.dashOffset) {
  8726. path.setAttribute("stroke-dashoffset", options.dashOffset);
  8727. } else {
  8728. path.removeAttribute("stroke-dashoffset");
  8729. }
  8730. } else {
  8731. path.setAttribute("stroke", "none");
  8732. }
  8733. if (options.fill) {
  8734. path.setAttribute("fill", options.fillColor || options.color);
  8735. path.setAttribute("fill-opacity", options.fillOpacity);
  8736. path.setAttribute("fill-rule", options.fillRule || "evenodd");
  8737. } else {
  8738. path.setAttribute("fill", "none");
  8739. }
  8740. },
  8741. _updatePoly: function(layer, closed) {
  8742. this._setPath(layer, pointsToPath(layer._parts, closed));
  8743. },
  8744. _updateCircle: function(layer) {
  8745. var p = layer._point, r = Math.max(Math.round(layer._radius), 1), r2 = Math.max(Math.round(layer._radiusY), 1) || r, arc = "a" + r + "," + r2 + " 0 1,0 ";
  8746. var d = layer._empty() ? "M0 0" : "M" + (p.x - r) + "," + p.y + arc + r * 2 + ",0 " + arc + -r * 2 + ",0 ";
  8747. this._setPath(layer, d);
  8748. },
  8749. _setPath: function(layer, path) {
  8750. layer._path.setAttribute("d", path);
  8751. },
  8752. // SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
  8753. _bringToFront: function(layer) {
  8754. toFront(layer._path);
  8755. },
  8756. _bringToBack: function(layer) {
  8757. toBack(layer._path);
  8758. }
  8759. });
  8760. if (Browser.vml) {
  8761. SVG.include(vmlMixin);
  8762. }
  8763. function svg(options) {
  8764. return Browser.svg || Browser.vml ? new SVG(options) : null;
  8765. }
  8766. Map.include({
  8767. // @namespace Map; @method getRenderer(layer: Path): Renderer
  8768. // Returns the instance of `Renderer` that should be used to render the given
  8769. // `Path`. It will ensure that the `renderer` options of the map and paths
  8770. // are respected, and that the renderers do exist on the map.
  8771. getRenderer: function(layer) {
  8772. var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
  8773. if (!renderer) {
  8774. renderer = this._renderer = this._createRenderer();
  8775. }
  8776. if (!this.hasLayer(renderer)) {
  8777. this.addLayer(renderer);
  8778. }
  8779. return renderer;
  8780. },
  8781. _getPaneRenderer: function(name) {
  8782. if (name === "overlayPane" || name === void 0) {
  8783. return false;
  8784. }
  8785. var renderer = this._paneRenderers[name];
  8786. if (renderer === void 0) {
  8787. renderer = this._createRenderer({ pane: name });
  8788. this._paneRenderers[name] = renderer;
  8789. }
  8790. return renderer;
  8791. },
  8792. _createRenderer: function(options) {
  8793. return this.options.preferCanvas && canvas(options) || svg(options);
  8794. }
  8795. });
  8796. var Rectangle = Polygon.extend({
  8797. initialize: function(latLngBounds, options) {
  8798. Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
  8799. },
  8800. // @method setBounds(latLngBounds: LatLngBounds): this
  8801. // Redraws the rectangle with the passed bounds.
  8802. setBounds: function(latLngBounds) {
  8803. return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
  8804. },
  8805. _boundsToLatLngs: function(latLngBounds) {
  8806. latLngBounds = toLatLngBounds(latLngBounds);
  8807. return [
  8808. latLngBounds.getSouthWest(),
  8809. latLngBounds.getNorthWest(),
  8810. latLngBounds.getNorthEast(),
  8811. latLngBounds.getSouthEast()
  8812. ];
  8813. }
  8814. });
  8815. function rectangle(latLngBounds, options) {
  8816. return new Rectangle(latLngBounds, options);
  8817. }
  8818. SVG.create = create;
  8819. SVG.pointsToPath = pointsToPath;
  8820. GeoJSON.geometryToLayer = geometryToLayer;
  8821. GeoJSON.coordsToLatLng = coordsToLatLng;
  8822. GeoJSON.coordsToLatLngs = coordsToLatLngs;
  8823. GeoJSON.latLngToCoords = latLngToCoords;
  8824. GeoJSON.latLngsToCoords = latLngsToCoords;
  8825. GeoJSON.getFeature = getFeature;
  8826. GeoJSON.asFeature = asFeature;
  8827. Map.mergeOptions({
  8828. // @option boxZoom: Boolean = true
  8829. // Whether the map can be zoomed to a rectangular area specified by
  8830. // dragging the mouse while pressing the shift key.
  8831. boxZoom: true
  8832. });
  8833. var BoxZoom = Handler.extend({
  8834. initialize: function(map) {
  8835. this._map = map;
  8836. this._container = map._container;
  8837. this._pane = map._panes.overlayPane;
  8838. this._resetStateTimeout = 0;
  8839. map.on("unload", this._destroy, this);
  8840. },
  8841. addHooks: function() {
  8842. on(this._container, "mousedown", this._onMouseDown, this);
  8843. },
  8844. removeHooks: function() {
  8845. off(this._container, "mousedown", this._onMouseDown, this);
  8846. },
  8847. moved: function() {
  8848. return this._moved;
  8849. },
  8850. _destroy: function() {
  8851. remove(this._pane);
  8852. delete this._pane;
  8853. },
  8854. _resetState: function() {
  8855. this._resetStateTimeout = 0;
  8856. this._moved = false;
  8857. },
  8858. _clearDeferredResetState: function() {
  8859. if (this._resetStateTimeout !== 0) {
  8860. clearTimeout(this._resetStateTimeout);
  8861. this._resetStateTimeout = 0;
  8862. }
  8863. },
  8864. _onMouseDown: function(e) {
  8865. if (!e.shiftKey || e.which !== 1 && e.button !== 1) {
  8866. return false;
  8867. }
  8868. this._clearDeferredResetState();
  8869. this._resetState();
  8870. disableTextSelection();
  8871. disableImageDrag();
  8872. this._startPoint = this._map.mouseEventToContainerPoint(e);
  8873. on(document, {
  8874. contextmenu: stop,
  8875. mousemove: this._onMouseMove,
  8876. mouseup: this._onMouseUp,
  8877. keydown: this._onKeyDown
  8878. }, this);
  8879. },
  8880. _onMouseMove: function(e) {
  8881. if (!this._moved) {
  8882. this._moved = true;
  8883. this._box = create$1("div", "leaflet-zoom-box", this._container);
  8884. addClass(this._container, "leaflet-crosshair");
  8885. this._map.fire("boxzoomstart");
  8886. }
  8887. this._point = this._map.mouseEventToContainerPoint(e);
  8888. var bounds = new Bounds(this._point, this._startPoint), size = bounds.getSize();
  8889. setPosition(this._box, bounds.min);
  8890. this._box.style.width = size.x + "px";
  8891. this._box.style.height = size.y + "px";
  8892. },
  8893. _finish: function() {
  8894. if (this._moved) {
  8895. remove(this._box);
  8896. removeClass(this._container, "leaflet-crosshair");
  8897. }
  8898. enableTextSelection();
  8899. enableImageDrag();
  8900. off(document, {
  8901. contextmenu: stop,
  8902. mousemove: this._onMouseMove,
  8903. mouseup: this._onMouseUp,
  8904. keydown: this._onKeyDown
  8905. }, this);
  8906. },
  8907. _onMouseUp: function(e) {
  8908. if (e.which !== 1 && e.button !== 1) {
  8909. return;
  8910. }
  8911. this._finish();
  8912. if (!this._moved) {
  8913. return;
  8914. }
  8915. this._clearDeferredResetState();
  8916. this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);
  8917. var bounds = new LatLngBounds(
  8918. this._map.containerPointToLatLng(this._startPoint),
  8919. this._map.containerPointToLatLng(this._point)
  8920. );
  8921. this._map.fitBounds(bounds).fire("boxzoomend", { boxZoomBounds: bounds });
  8922. },
  8923. _onKeyDown: function(e) {
  8924. if (e.keyCode === 27) {
  8925. this._finish();
  8926. this._clearDeferredResetState();
  8927. this._resetState();
  8928. }
  8929. }
  8930. });
  8931. Map.addInitHook("addHandler", "boxZoom", BoxZoom);
  8932. Map.mergeOptions({
  8933. // @option doubleClickZoom: Boolean|String = true
  8934. // Whether the map can be zoomed in by double clicking on it and
  8935. // zoomed out by double clicking while holding shift. If passed
  8936. // `'center'`, double-click zoom will zoom to the center of the
  8937. // view regardless of where the mouse was.
  8938. doubleClickZoom: true
  8939. });
  8940. var DoubleClickZoom = Handler.extend({
  8941. addHooks: function() {
  8942. this._map.on("dblclick", this._onDoubleClick, this);
  8943. },
  8944. removeHooks: function() {
  8945. this._map.off("dblclick", this._onDoubleClick, this);
  8946. },
  8947. _onDoubleClick: function(e) {
  8948. var map = this._map, oldZoom = map.getZoom(), delta = map.options.zoomDelta, zoom2 = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
  8949. if (map.options.doubleClickZoom === "center") {
  8950. map.setZoom(zoom2);
  8951. } else {
  8952. map.setZoomAround(e.containerPoint, zoom2);
  8953. }
  8954. }
  8955. });
  8956. Map.addInitHook("addHandler", "doubleClickZoom", DoubleClickZoom);
  8957. Map.mergeOptions({
  8958. // @option dragging: Boolean = true
  8959. // Whether the map is draggable with mouse/touch or not.
  8960. dragging: true,
  8961. // @section Panning Inertia Options
  8962. // @option inertia: Boolean = *
  8963. // If enabled, panning of the map will have an inertia effect where
  8964. // the map builds momentum while dragging and continues moving in
  8965. // the same direction for some time. Feels especially nice on touch
  8966. // devices. Enabled by default.
  8967. inertia: true,
  8968. // @option inertiaDeceleration: Number = 3000
  8969. // The rate with which the inertial movement slows down, in pixels/second².
  8970. inertiaDeceleration: 3400,
  8971. // px/s^2
  8972. // @option inertiaMaxSpeed: Number = Infinity
  8973. // Max speed of the inertial movement, in pixels/second.
  8974. inertiaMaxSpeed: Infinity,
  8975. // px/s
  8976. // @option easeLinearity: Number = 0.2
  8977. easeLinearity: 0.2,
  8978. // TODO refactor, move to CRS
  8979. // @option worldCopyJump: Boolean = false
  8980. // With this option enabled, the map tracks when you pan to another "copy"
  8981. // of the world and seamlessly jumps to the original one so that all overlays
  8982. // like markers and vector layers are still visible.
  8983. worldCopyJump: false,
  8984. // @option maxBoundsViscosity: Number = 0.0
  8985. // If `maxBounds` is set, this option will control how solid the bounds
  8986. // are when dragging the map around. The default value of `0.0` allows the
  8987. // user to drag outside the bounds at normal speed, higher values will
  8988. // slow down map dragging outside bounds, and `1.0` makes the bounds fully
  8989. // solid, preventing the user from dragging outside the bounds.
  8990. maxBoundsViscosity: 0
  8991. });
  8992. var Drag = Handler.extend({
  8993. addHooks: function() {
  8994. if (!this._draggable) {
  8995. var map = this._map;
  8996. this._draggable = new Draggable(map._mapPane, map._container);
  8997. this._draggable.on({
  8998. dragstart: this._onDragStart,
  8999. drag: this._onDrag,
  9000. dragend: this._onDragEnd
  9001. }, this);
  9002. this._draggable.on("predrag", this._onPreDragLimit, this);
  9003. if (map.options.worldCopyJump) {
  9004. this._draggable.on("predrag", this._onPreDragWrap, this);
  9005. map.on("zoomend", this._onZoomEnd, this);
  9006. map.whenReady(this._onZoomEnd, this);
  9007. }
  9008. }
  9009. addClass(this._map._container, "leaflet-grab leaflet-touch-drag");
  9010. this._draggable.enable();
  9011. this._positions = [];
  9012. this._times = [];
  9013. },
  9014. removeHooks: function() {
  9015. removeClass(this._map._container, "leaflet-grab");
  9016. removeClass(this._map._container, "leaflet-touch-drag");
  9017. this._draggable.disable();
  9018. },
  9019. moved: function() {
  9020. return this._draggable && this._draggable._moved;
  9021. },
  9022. moving: function() {
  9023. return this._draggable && this._draggable._moving;
  9024. },
  9025. _onDragStart: function() {
  9026. var map = this._map;
  9027. map._stop();
  9028. if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
  9029. var bounds = toLatLngBounds(this._map.options.maxBounds);
  9030. this._offsetLimit = toBounds(
  9031. this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
  9032. this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1).add(this._map.getSize())
  9033. );
  9034. this._viscosity = Math.min(1, Math.max(0, this._map.options.maxBoundsViscosity));
  9035. } else {
  9036. this._offsetLimit = null;
  9037. }
  9038. map.fire("movestart").fire("dragstart");
  9039. if (map.options.inertia) {
  9040. this._positions = [];
  9041. this._times = [];
  9042. }
  9043. },
  9044. _onDrag: function(e) {
  9045. if (this._map.options.inertia) {
  9046. var time = this._lastTime = +/* @__PURE__ */ new Date(), pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
  9047. this._positions.push(pos);
  9048. this._times.push(time);
  9049. this._prunePositions(time);
  9050. }
  9051. this._map.fire("move", e).fire("drag", e);
  9052. },
  9053. _prunePositions: function(time) {
  9054. while (this._positions.length > 1 && time - this._times[0] > 50) {
  9055. this._positions.shift();
  9056. this._times.shift();
  9057. }
  9058. },
  9059. _onZoomEnd: function() {
  9060. var pxCenter = this._map.getSize().divideBy(2), pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
  9061. this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
  9062. this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
  9063. },
  9064. _viscousLimit: function(value, threshold) {
  9065. return value - (value - threshold) * this._viscosity;
  9066. },
  9067. _onPreDragLimit: function() {
  9068. if (!this._viscosity || !this._offsetLimit) {
  9069. return;
  9070. }
  9071. var offset = this._draggable._newPos.subtract(this._draggable._startPos);
  9072. var limit = this._offsetLimit;
  9073. if (offset.x < limit.min.x) {
  9074. offset.x = this._viscousLimit(offset.x, limit.min.x);
  9075. }
  9076. if (offset.y < limit.min.y) {
  9077. offset.y = this._viscousLimit(offset.y, limit.min.y);
  9078. }
  9079. if (offset.x > limit.max.x) {
  9080. offset.x = this._viscousLimit(offset.x, limit.max.x);
  9081. }
  9082. if (offset.y > limit.max.y) {
  9083. offset.y = this._viscousLimit(offset.y, limit.max.y);
  9084. }
  9085. this._draggable._newPos = this._draggable._startPos.add(offset);
  9086. },
  9087. _onPreDragWrap: function() {
  9088. var worldWidth = this._worldWidth, halfWidth = Math.round(worldWidth / 2), dx = this._initialWorldOffset, x = this._draggable._newPos.x, newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx, newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx, newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
  9089. this._draggable._absPos = this._draggable._newPos.clone();
  9090. this._draggable._newPos.x = newX;
  9091. },
  9092. _onDragEnd: function(e) {
  9093. var map = this._map, options = map.options, noInertia = !options.inertia || e.noInertia || this._times.length < 2;
  9094. map.fire("dragend", e);
  9095. if (noInertia) {
  9096. map.fire("moveend");
  9097. } else {
  9098. this._prunePositions(+/* @__PURE__ */ new Date());
  9099. var direction = this._lastPos.subtract(this._positions[0]), duration = (this._lastTime - this._times[0]) / 1e3, ease = options.easeLinearity, speedVector = direction.multiplyBy(ease / duration), speed = speedVector.distanceTo([0, 0]), limitedSpeed = Math.min(options.inertiaMaxSpeed, speed), limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed), decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease), offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
  9100. if (!offset.x && !offset.y) {
  9101. map.fire("moveend");
  9102. } else {
  9103. offset = map._limitOffset(offset, map.options.maxBounds);
  9104. requestAnimFrame(function() {
  9105. map.panBy(offset, {
  9106. duration: decelerationDuration,
  9107. easeLinearity: ease,
  9108. noMoveStart: true,
  9109. animate: true
  9110. });
  9111. });
  9112. }
  9113. }
  9114. }
  9115. });
  9116. Map.addInitHook("addHandler", "dragging", Drag);
  9117. Map.mergeOptions({
  9118. // @option keyboard: Boolean = true
  9119. // Makes the map focusable and allows users to navigate the map with keyboard
  9120. // arrows and `+`/`-` keys.
  9121. keyboard: true,
  9122. // @option keyboardPanDelta: Number = 80
  9123. // Amount of pixels to pan when pressing an arrow key.
  9124. keyboardPanDelta: 80
  9125. });
  9126. var Keyboard = Handler.extend({
  9127. keyCodes: {
  9128. left: [37],
  9129. right: [39],
  9130. down: [40],
  9131. up: [38],
  9132. zoomIn: [187, 107, 61, 171],
  9133. zoomOut: [189, 109, 54, 173]
  9134. },
  9135. initialize: function(map) {
  9136. this._map = map;
  9137. this._setPanDelta(map.options.keyboardPanDelta);
  9138. this._setZoomDelta(map.options.zoomDelta);
  9139. },
  9140. addHooks: function() {
  9141. var container = this._map._container;
  9142. if (container.tabIndex <= 0) {
  9143. container.tabIndex = "0";
  9144. }
  9145. on(container, {
  9146. focus: this._onFocus,
  9147. blur: this._onBlur,
  9148. mousedown: this._onMouseDown
  9149. }, this);
  9150. this._map.on({
  9151. focus: this._addHooks,
  9152. blur: this._removeHooks
  9153. }, this);
  9154. },
  9155. removeHooks: function() {
  9156. this._removeHooks();
  9157. off(this._map._container, {
  9158. focus: this._onFocus,
  9159. blur: this._onBlur,
  9160. mousedown: this._onMouseDown
  9161. }, this);
  9162. this._map.off({
  9163. focus: this._addHooks,
  9164. blur: this._removeHooks
  9165. }, this);
  9166. },
  9167. _onMouseDown: function() {
  9168. if (this._focused) {
  9169. return;
  9170. }
  9171. var body = document.body, docEl = document.documentElement, top = body.scrollTop || docEl.scrollTop, left = body.scrollLeft || docEl.scrollLeft;
  9172. this._map._container.focus();
  9173. window.scrollTo(left, top);
  9174. },
  9175. _onFocus: function() {
  9176. this._focused = true;
  9177. this._map.fire("focus");
  9178. },
  9179. _onBlur: function() {
  9180. this._focused = false;
  9181. this._map.fire("blur");
  9182. },
  9183. _setPanDelta: function(panDelta) {
  9184. var keys = this._panKeys = {}, codes = this.keyCodes, i, len;
  9185. for (i = 0, len = codes.left.length; i < len; i++) {
  9186. keys[codes.left[i]] = [-1 * panDelta, 0];
  9187. }
  9188. for (i = 0, len = codes.right.length; i < len; i++) {
  9189. keys[codes.right[i]] = [panDelta, 0];
  9190. }
  9191. for (i = 0, len = codes.down.length; i < len; i++) {
  9192. keys[codes.down[i]] = [0, panDelta];
  9193. }
  9194. for (i = 0, len = codes.up.length; i < len; i++) {
  9195. keys[codes.up[i]] = [0, -1 * panDelta];
  9196. }
  9197. },
  9198. _setZoomDelta: function(zoomDelta) {
  9199. var keys = this._zoomKeys = {}, codes = this.keyCodes, i, len;
  9200. for (i = 0, len = codes.zoomIn.length; i < len; i++) {
  9201. keys[codes.zoomIn[i]] = zoomDelta;
  9202. }
  9203. for (i = 0, len = codes.zoomOut.length; i < len; i++) {
  9204. keys[codes.zoomOut[i]] = -zoomDelta;
  9205. }
  9206. },
  9207. _addHooks: function() {
  9208. on(document, "keydown", this._onKeyDown, this);
  9209. },
  9210. _removeHooks: function() {
  9211. off(document, "keydown", this._onKeyDown, this);
  9212. },
  9213. _onKeyDown: function(e) {
  9214. if (e.altKey || e.ctrlKey || e.metaKey) {
  9215. return;
  9216. }
  9217. var key = e.keyCode, map = this._map, offset;
  9218. if (key in this._panKeys) {
  9219. if (!map._panAnim || !map._panAnim._inProgress) {
  9220. offset = this._panKeys[key];
  9221. if (e.shiftKey) {
  9222. offset = toPoint(offset).multiplyBy(3);
  9223. }
  9224. if (map.options.maxBounds) {
  9225. offset = map._limitOffset(toPoint(offset), map.options.maxBounds);
  9226. }
  9227. if (map.options.worldCopyJump) {
  9228. var newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));
  9229. map.panTo(newLatLng);
  9230. } else {
  9231. map.panBy(offset);
  9232. }
  9233. }
  9234. } else if (key in this._zoomKeys) {
  9235. map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
  9236. } else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
  9237. map.closePopup();
  9238. } else {
  9239. return;
  9240. }
  9241. stop(e);
  9242. }
  9243. });
  9244. Map.addInitHook("addHandler", "keyboard", Keyboard);
  9245. Map.mergeOptions({
  9246. // @section Mouse wheel options
  9247. // @option scrollWheelZoom: Boolean|String = true
  9248. // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
  9249. // it will zoom to the center of the view regardless of where the mouse was.
  9250. scrollWheelZoom: true,
  9251. // @option wheelDebounceTime: Number = 40
  9252. // Limits the rate at which a wheel can fire (in milliseconds). By default
  9253. // user can't zoom via wheel more often than once per 40 ms.
  9254. wheelDebounceTime: 40,
  9255. // @option wheelPxPerZoomLevel: Number = 60
  9256. // How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
  9257. // mean a change of one full zoom level. Smaller values will make wheel-zooming
  9258. // faster (and vice versa).
  9259. wheelPxPerZoomLevel: 60
  9260. });
  9261. var ScrollWheelZoom = Handler.extend({
  9262. addHooks: function() {
  9263. on(this._map._container, "wheel", this._onWheelScroll, this);
  9264. this._delta = 0;
  9265. },
  9266. removeHooks: function() {
  9267. off(this._map._container, "wheel", this._onWheelScroll, this);
  9268. },
  9269. _onWheelScroll: function(e) {
  9270. var delta = getWheelDelta(e);
  9271. var debounce = this._map.options.wheelDebounceTime;
  9272. this._delta += delta;
  9273. this._lastMousePos = this._map.mouseEventToContainerPoint(e);
  9274. if (!this._startTime) {
  9275. this._startTime = +/* @__PURE__ */ new Date();
  9276. }
  9277. var left = Math.max(debounce - (+/* @__PURE__ */ new Date() - this._startTime), 0);
  9278. clearTimeout(this._timer);
  9279. this._timer = setTimeout(bind(this._performZoom, this), left);
  9280. stop(e);
  9281. },
  9282. _performZoom: function() {
  9283. var map = this._map, zoom2 = map.getZoom(), snap = this._map.options.zoomSnap || 0;
  9284. map._stop();
  9285. var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4), d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2, d4 = snap ? Math.ceil(d3 / snap) * snap : d3, delta = map._limitZoom(zoom2 + (this._delta > 0 ? d4 : -d4)) - zoom2;
  9286. this._delta = 0;
  9287. this._startTime = null;
  9288. if (!delta) {
  9289. return;
  9290. }
  9291. if (map.options.scrollWheelZoom === "center") {
  9292. map.setZoom(zoom2 + delta);
  9293. } else {
  9294. map.setZoomAround(this._lastMousePos, zoom2 + delta);
  9295. }
  9296. }
  9297. });
  9298. Map.addInitHook("addHandler", "scrollWheelZoom", ScrollWheelZoom);
  9299. var tapHoldDelay = 600;
  9300. Map.mergeOptions({
  9301. // @section Touch interaction options
  9302. // @option tapHold: Boolean
  9303. // Enables simulation of `contextmenu` event, default is `true` for mobile Safari.
  9304. tapHold: Browser.touchNative && Browser.safari && Browser.mobile,
  9305. // @option tapTolerance: Number = 15
  9306. // The max number of pixels a user can shift his finger during touch
  9307. // for it to be considered a valid tap.
  9308. tapTolerance: 15
  9309. });
  9310. var TapHold = Handler.extend({
  9311. addHooks: function() {
  9312. on(this._map._container, "touchstart", this._onDown, this);
  9313. },
  9314. removeHooks: function() {
  9315. off(this._map._container, "touchstart", this._onDown, this);
  9316. },
  9317. _onDown: function(e) {
  9318. clearTimeout(this._holdTimeout);
  9319. if (e.touches.length !== 1) {
  9320. return;
  9321. }
  9322. var first = e.touches[0];
  9323. this._startPos = this._newPos = new Point(first.clientX, first.clientY);
  9324. this._holdTimeout = setTimeout(bind(function() {
  9325. this._cancel();
  9326. if (!this._isTapValid()) {
  9327. return;
  9328. }
  9329. on(document, "touchend", preventDefault);
  9330. on(document, "touchend touchcancel", this._cancelClickPrevent);
  9331. this._simulateEvent("contextmenu", first);
  9332. }, this), tapHoldDelay);
  9333. on(document, "touchend touchcancel contextmenu", this._cancel, this);
  9334. on(document, "touchmove", this._onMove, this);
  9335. },
  9336. _cancelClickPrevent: function cancelClickPrevent() {
  9337. off(document, "touchend", preventDefault);
  9338. off(document, "touchend touchcancel", cancelClickPrevent);
  9339. },
  9340. _cancel: function() {
  9341. clearTimeout(this._holdTimeout);
  9342. off(document, "touchend touchcancel contextmenu", this._cancel, this);
  9343. off(document, "touchmove", this._onMove, this);
  9344. },
  9345. _onMove: function(e) {
  9346. var first = e.touches[0];
  9347. this._newPos = new Point(first.clientX, first.clientY);
  9348. },
  9349. _isTapValid: function() {
  9350. return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
  9351. },
  9352. _simulateEvent: function(type, e) {
  9353. var simulatedEvent = new MouseEvent(type, {
  9354. bubbles: true,
  9355. cancelable: true,
  9356. view: window,
  9357. // detail: 1,
  9358. screenX: e.screenX,
  9359. screenY: e.screenY,
  9360. clientX: e.clientX,
  9361. clientY: e.clientY
  9362. // button: 2,
  9363. // buttons: 2
  9364. });
  9365. simulatedEvent._simulated = true;
  9366. e.target.dispatchEvent(simulatedEvent);
  9367. }
  9368. });
  9369. Map.addInitHook("addHandler", "tapHold", TapHold);
  9370. Map.mergeOptions({
  9371. // @section Touch interaction options
  9372. // @option touchZoom: Boolean|String = *
  9373. // Whether the map can be zoomed by touch-dragging with two fingers. If
  9374. // passed `'center'`, it will zoom to the center of the view regardless of
  9375. // where the touch events (fingers) were. Enabled for touch-capable web
  9376. // browsers.
  9377. touchZoom: Browser.touch,
  9378. // @option bounceAtZoomLimits: Boolean = true
  9379. // Set it to false if you don't want the map to zoom beyond min/max zoom
  9380. // and then bounce back when pinch-zooming.
  9381. bounceAtZoomLimits: true
  9382. });
  9383. var TouchZoom = Handler.extend({
  9384. addHooks: function() {
  9385. addClass(this._map._container, "leaflet-touch-zoom");
  9386. on(this._map._container, "touchstart", this._onTouchStart, this);
  9387. },
  9388. removeHooks: function() {
  9389. removeClass(this._map._container, "leaflet-touch-zoom");
  9390. off(this._map._container, "touchstart", this._onTouchStart, this);
  9391. },
  9392. _onTouchStart: function(e) {
  9393. var map = this._map;
  9394. if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) {
  9395. return;
  9396. }
  9397. var p1 = map.mouseEventToContainerPoint(e.touches[0]), p2 = map.mouseEventToContainerPoint(e.touches[1]);
  9398. this._centerPoint = map.getSize()._divideBy(2);
  9399. this._startLatLng = map.containerPointToLatLng(this._centerPoint);
  9400. if (map.options.touchZoom !== "center") {
  9401. this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
  9402. }
  9403. this._startDist = p1.distanceTo(p2);
  9404. this._startZoom = map.getZoom();
  9405. this._moved = false;
  9406. this._zooming = true;
  9407. map._stop();
  9408. on(document, "touchmove", this._onTouchMove, this);
  9409. on(document, "touchend touchcancel", this._onTouchEnd, this);
  9410. preventDefault(e);
  9411. },
  9412. _onTouchMove: function(e) {
  9413. if (!e.touches || e.touches.length !== 2 || !this._zooming) {
  9414. return;
  9415. }
  9416. var map = this._map, p1 = map.mouseEventToContainerPoint(e.touches[0]), p2 = map.mouseEventToContainerPoint(e.touches[1]), scale2 = p1.distanceTo(p2) / this._startDist;
  9417. this._zoom = map.getScaleZoom(scale2, this._startZoom);
  9418. if (!map.options.bounceAtZoomLimits && (this._zoom < map.getMinZoom() && scale2 < 1 || this._zoom > map.getMaxZoom() && scale2 > 1)) {
  9419. this._zoom = map._limitZoom(this._zoom);
  9420. }
  9421. if (map.options.touchZoom === "center") {
  9422. this._center = this._startLatLng;
  9423. if (scale2 === 1) {
  9424. return;
  9425. }
  9426. } else {
  9427. var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
  9428. if (scale2 === 1 && delta.x === 0 && delta.y === 0) {
  9429. return;
  9430. }
  9431. this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
  9432. }
  9433. if (!this._moved) {
  9434. map._moveStart(true, false);
  9435. this._moved = true;
  9436. }
  9437. cancelAnimFrame(this._animRequest);
  9438. var moveFn = bind(map._move, map, this._center, this._zoom, { pinch: true, round: false }, void 0);
  9439. this._animRequest = requestAnimFrame(moveFn, this, true);
  9440. preventDefault(e);
  9441. },
  9442. _onTouchEnd: function() {
  9443. if (!this._moved || !this._zooming) {
  9444. this._zooming = false;
  9445. return;
  9446. }
  9447. this._zooming = false;
  9448. cancelAnimFrame(this._animRequest);
  9449. off(document, "touchmove", this._onTouchMove, this);
  9450. off(document, "touchend touchcancel", this._onTouchEnd, this);
  9451. if (this._map.options.zoomAnimation) {
  9452. this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
  9453. } else {
  9454. this._map._resetView(this._center, this._map._limitZoom(this._zoom));
  9455. }
  9456. }
  9457. });
  9458. Map.addInitHook("addHandler", "touchZoom", TouchZoom);
  9459. Map.BoxZoom = BoxZoom;
  9460. Map.DoubleClickZoom = DoubleClickZoom;
  9461. Map.Drag = Drag;
  9462. Map.Keyboard = Keyboard;
  9463. Map.ScrollWheelZoom = ScrollWheelZoom;
  9464. Map.TapHold = TapHold;
  9465. Map.TouchZoom = TouchZoom;
  9466. exports2.Bounds = Bounds;
  9467. exports2.Browser = Browser;
  9468. exports2.CRS = CRS;
  9469. exports2.Canvas = Canvas;
  9470. exports2.Circle = Circle;
  9471. exports2.CircleMarker = CircleMarker;
  9472. exports2.Class = Class;
  9473. exports2.Control = Control;
  9474. exports2.DivIcon = DivIcon;
  9475. exports2.DivOverlay = DivOverlay;
  9476. exports2.DomEvent = DomEvent;
  9477. exports2.DomUtil = DomUtil;
  9478. exports2.Draggable = Draggable;
  9479. exports2.Evented = Evented;
  9480. exports2.FeatureGroup = FeatureGroup;
  9481. exports2.GeoJSON = GeoJSON;
  9482. exports2.GridLayer = GridLayer;
  9483. exports2.Handler = Handler;
  9484. exports2.Icon = Icon;
  9485. exports2.ImageOverlay = ImageOverlay;
  9486. exports2.LatLng = LatLng;
  9487. exports2.LatLngBounds = LatLngBounds;
  9488. exports2.Layer = Layer;
  9489. exports2.LayerGroup = LayerGroup;
  9490. exports2.LineUtil = LineUtil;
  9491. exports2.Map = Map;
  9492. exports2.Marker = Marker;
  9493. exports2.Mixin = Mixin;
  9494. exports2.Path = Path;
  9495. exports2.Point = Point;
  9496. exports2.PolyUtil = PolyUtil;
  9497. exports2.Polygon = Polygon;
  9498. exports2.Polyline = Polyline;
  9499. exports2.Popup = Popup;
  9500. exports2.PosAnimation = PosAnimation;
  9501. exports2.Projection = index;
  9502. exports2.Rectangle = Rectangle;
  9503. exports2.Renderer = Renderer;
  9504. exports2.SVG = SVG;
  9505. exports2.SVGOverlay = SVGOverlay;
  9506. exports2.TileLayer = TileLayer;
  9507. exports2.Tooltip = Tooltip;
  9508. exports2.Transformation = Transformation;
  9509. exports2.Util = Util;
  9510. exports2.VideoOverlay = VideoOverlay;
  9511. exports2.bind = bind;
  9512. exports2.bounds = toBounds;
  9513. exports2.canvas = canvas;
  9514. exports2.circle = circle;
  9515. exports2.circleMarker = circleMarker;
  9516. exports2.control = control;
  9517. exports2.divIcon = divIcon;
  9518. exports2.extend = extend;
  9519. exports2.featureGroup = featureGroup;
  9520. exports2.geoJSON = geoJSON;
  9521. exports2.geoJson = geoJson;
  9522. exports2.gridLayer = gridLayer;
  9523. exports2.icon = icon;
  9524. exports2.imageOverlay = imageOverlay;
  9525. exports2.latLng = toLatLng;
  9526. exports2.latLngBounds = toLatLngBounds;
  9527. exports2.layerGroup = layerGroup;
  9528. exports2.map = createMap;
  9529. exports2.marker = marker;
  9530. exports2.point = toPoint;
  9531. exports2.polygon = polygon;
  9532. exports2.polyline = polyline;
  9533. exports2.popup = popup;
  9534. exports2.rectangle = rectangle;
  9535. exports2.setOptions = setOptions;
  9536. exports2.stamp = stamp;
  9537. exports2.svg = svg;
  9538. exports2.svgOverlay = svgOverlay;
  9539. exports2.tileLayer = tileLayer;
  9540. exports2.tooltip = tooltip;
  9541. exports2.transformation = toTransformation;
  9542. exports2.version = version;
  9543. exports2.videoOverlay = videoOverlay;
  9544. var oldL = window.L;
  9545. exports2.noConflict = function() {
  9546. window.L = oldL;
  9547. return this;
  9548. };
  9549. window.L = exports2;
  9550. });
  9551. }
  9552. });
  9553. export default require_leaflet_src();
  9554. /*! Bundled license information:
  9555. leaflet/dist/leaflet-src.js:
  9556. (* @preserve
  9557. * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
  9558. * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
  9559. *)
  9560. */
  9561. //# sourceMappingURL=leaflet.js.map