zrender.js 477 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (factory((global.zrender = {})));
  5. }(this, (function (exports) { 'use strict';
  6. /**
  7. * zrender: 生成唯一id
  8. *
  9. * @author errorrik (errorrik@gmail.com)
  10. */
  11. var idStart = 0x0907;
  12. var guid = function () {
  13. return idStart++;
  14. };
  15. /**
  16. * echarts设备环境识别
  17. *
  18. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  19. * @author firede[firede@firede.us]
  20. * @desc thanks zepto.
  21. */
  22. var env = {};
  23. if (typeof navigator === 'undefined') {
  24. // In node
  25. env = {
  26. browser: {},
  27. os: {},
  28. node: true,
  29. // Assume canvas is supported
  30. canvasSupported: true,
  31. svgSupported: true
  32. };
  33. }
  34. else {
  35. env = detect(navigator.userAgent);
  36. }
  37. var env$1 = env;
  38. // Zepto.js
  39. // (c) 2010-2013 Thomas Fuchs
  40. // Zepto.js may be freely distributed under the MIT license.
  41. function detect(ua) {
  42. var os = {};
  43. var browser = {};
  44. // var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/);
  45. // var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
  46. // var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
  47. // var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
  48. // var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);
  49. // var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/);
  50. // var touchpad = webos && ua.match(/TouchPad/);
  51. // var kindle = ua.match(/Kindle\/([\d.]+)/);
  52. // var silk = ua.match(/Silk\/([\d._]+)/);
  53. // var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/);
  54. // var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/);
  55. // var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/);
  56. // var playbook = ua.match(/PlayBook/);
  57. // var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/);
  58. var firefox = ua.match(/Firefox\/([\d.]+)/);
  59. // var safari = webkit && ua.match(/Mobile\//) && !chrome;
  60. // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;
  61. var ie = ua.match(/MSIE\s([\d.]+)/)
  62. // IE 11 Trident/7.0; rv:11.0
  63. || ua.match(/Trident\/.+?rv:(([\d.]+))/);
  64. var edge = ua.match(/Edge\/([\d.]+)/); // IE 12 and 12+
  65. var weChat = (/micromessenger/i).test(ua);
  66. // Todo: clean this up with a better OS/browser seperation:
  67. // - discern (more) between multiple browsers on android
  68. // - decide if kindle fire in silk mode is android or not
  69. // - Firefox on Android doesn't specify the Android version
  70. // - possibly devide in os, device and browser hashes
  71. // if (browser.webkit = !!webkit) browser.version = webkit[1];
  72. // if (android) os.android = true, os.version = android[2];
  73. // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');
  74. // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');
  75. // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
  76. // if (webos) os.webos = true, os.version = webos[2];
  77. // if (touchpad) os.touchpad = true;
  78. // if (blackberry) os.blackberry = true, os.version = blackberry[2];
  79. // if (bb10) os.bb10 = true, os.version = bb10[2];
  80. // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];
  81. // if (playbook) browser.playbook = true;
  82. // if (kindle) os.kindle = true, os.version = kindle[1];
  83. // if (silk) browser.silk = true, browser.version = silk[1];
  84. // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;
  85. // if (chrome) browser.chrome = true, browser.version = chrome[1];
  86. if (firefox) {
  87. browser.firefox = true;
  88. browser.version = firefox[1];
  89. }
  90. // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;
  91. // if (webview) browser.webview = true;
  92. if (ie) {
  93. browser.ie = true;
  94. browser.version = ie[1];
  95. }
  96. if (edge) {
  97. browser.edge = true;
  98. browser.version = edge[1];
  99. }
  100. // It is difficult to detect WeChat in Win Phone precisely, because ua can
  101. // not be set on win phone. So we do not consider Win Phone.
  102. if (weChat) {
  103. browser.weChat = true;
  104. }
  105. // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||
  106. // (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));
  107. // os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos ||
  108. // (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) ||
  109. // (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));
  110. return {
  111. browser: browser,
  112. os: os,
  113. node: false,
  114. // 原生canvas支持,改极端点了
  115. // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)
  116. canvasSupported: !!document.createElement('canvas').getContext,
  117. svgSupported: typeof SVGRect !== 'undefined',
  118. // @see <http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript>
  119. // works on most browsers
  120. // IE10/11 does not support touch event, and MS Edge supports them but not by
  121. // default, so we dont check navigator.maxTouchPoints for them here.
  122. touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,
  123. // <http://caniuse.com/#search=pointer%20event>.
  124. pointerEventsSupported: 'onpointerdown' in window
  125. // Firefox supports pointer but not by default, only MS browsers are reliable on pointer
  126. // events currently. So we dont use that on other browsers unless tested sufficiently.
  127. // Although IE 10 supports pointer event, it use old style and is different from the
  128. // standard. So we exclude that. (IE 10 is hardly used on touch device)
  129. && (browser.edge || (browser.ie && browser.version >= 11))
  130. };
  131. }
  132. /**
  133. * @module zrender/core/util
  134. */
  135. // 用于处理merge时无法遍历Date等对象的问题
  136. var BUILTIN_OBJECT = {
  137. '[object Function]': 1,
  138. '[object RegExp]': 1,
  139. '[object Date]': 1,
  140. '[object Error]': 1,
  141. '[object CanvasGradient]': 1,
  142. '[object CanvasPattern]': 1,
  143. // For node-canvas
  144. '[object Image]': 1,
  145. '[object Canvas]': 1
  146. };
  147. var TYPED_ARRAY = {
  148. '[object Int8Array]': 1,
  149. '[object Uint8Array]': 1,
  150. '[object Uint8ClampedArray]': 1,
  151. '[object Int16Array]': 1,
  152. '[object Uint16Array]': 1,
  153. '[object Int32Array]': 1,
  154. '[object Uint32Array]': 1,
  155. '[object Float32Array]': 1,
  156. '[object Float64Array]': 1
  157. };
  158. var objToString = Object.prototype.toString;
  159. var arrayProto = Array.prototype;
  160. var nativeForEach = arrayProto.forEach;
  161. var nativeFilter = arrayProto.filter;
  162. var nativeSlice = arrayProto.slice;
  163. var nativeMap = arrayProto.map;
  164. var nativeReduce = arrayProto.reduce;
  165. // Avoid assign to an exported variable, for transforming to cjs.
  166. var methods = {};
  167. function $override(name, fn) {
  168. methods[name] = fn;
  169. }
  170. /**
  171. * Those data types can be cloned:
  172. * Plain object, Array, TypedArray, number, string, null, undefined.
  173. * Those data types will be assgined using the orginal data:
  174. * BUILTIN_OBJECT
  175. * Instance of user defined class will be cloned to a plain object, without
  176. * properties in prototype.
  177. * Other data types is not supported (not sure what will happen).
  178. *
  179. * Caution: do not support clone Date, for performance consideration.
  180. * (There might be a large number of date in `series.data`).
  181. * So date should not be modified in and out of echarts.
  182. *
  183. * @param {*} source
  184. * @return {*} new
  185. */
  186. function clone(source) {
  187. if (source == null || typeof source != 'object') {
  188. return source;
  189. }
  190. var result = source;
  191. var typeStr = objToString.call(source);
  192. if (typeStr === '[object Array]') {
  193. result = [];
  194. for (var i = 0, len = source.length; i < len; i++) {
  195. result[i] = clone(source[i]);
  196. }
  197. }
  198. else if (TYPED_ARRAY[typeStr]) {
  199. var Ctor = source.constructor;
  200. if (source.constructor.from) {
  201. result = Ctor.from(source);
  202. }
  203. else {
  204. result = new Ctor(source.length);
  205. for (var i = 0, len = source.length; i < len; i++) {
  206. result[i] = clone(source[i]);
  207. }
  208. }
  209. }
  210. else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
  211. result = {};
  212. for (var key in source) {
  213. if (source.hasOwnProperty(key)) {
  214. result[key] = clone(source[key]);
  215. }
  216. }
  217. }
  218. return result;
  219. }
  220. /**
  221. * @memberOf module:zrender/core/util
  222. * @param {*} target
  223. * @param {*} source
  224. * @param {boolean} [overwrite=false]
  225. */
  226. function merge(target, source, overwrite) {
  227. // We should escapse that source is string
  228. // and enter for ... in ...
  229. if (!isObject(source) || !isObject(target)) {
  230. return overwrite ? clone(source) : target;
  231. }
  232. for (var key in source) {
  233. if (source.hasOwnProperty(key)) {
  234. var targetProp = target[key];
  235. var sourceProp = source[key];
  236. if (isObject(sourceProp)
  237. && isObject(targetProp)
  238. && !isArray(sourceProp)
  239. && !isArray(targetProp)
  240. && !isDom(sourceProp)
  241. && !isDom(targetProp)
  242. && !isBuiltInObject(sourceProp)
  243. && !isBuiltInObject(targetProp)
  244. && !isPrimitive(sourceProp)
  245. && !isPrimitive(targetProp)
  246. ) {
  247. // 如果需要递归覆盖,就递归调用merge
  248. merge(targetProp, sourceProp, overwrite);
  249. }
  250. else if (overwrite || !(key in target)) {
  251. // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况
  252. // NOTE,在 target[key] 不存在的时候也是直接覆盖
  253. target[key] = clone(source[key], true);
  254. }
  255. }
  256. }
  257. return target;
  258. }
  259. /**
  260. * @param {Array} targetAndSources The first item is target, and the rests are source.
  261. * @param {boolean} [overwrite=false]
  262. * @return {*} target
  263. */
  264. function mergeAll(targetAndSources, overwrite) {
  265. var result = targetAndSources[0];
  266. for (var i = 1, len = targetAndSources.length; i < len; i++) {
  267. result = merge(result, targetAndSources[i], overwrite);
  268. }
  269. return result;
  270. }
  271. /**
  272. * @param {*} target
  273. * @param {*} source
  274. * @memberOf module:zrender/core/util
  275. */
  276. function extend(target, source) {
  277. for (var key in source) {
  278. if (source.hasOwnProperty(key)) {
  279. target[key] = source[key];
  280. }
  281. }
  282. return target;
  283. }
  284. /**
  285. * @param {*} target
  286. * @param {*} source
  287. * @param {boolean} [overlay=false]
  288. * @memberOf module:zrender/core/util
  289. */
  290. function defaults(target, source, overlay) {
  291. for (var key in source) {
  292. if (source.hasOwnProperty(key)
  293. && (overlay ? source[key] != null : target[key] == null)
  294. ) {
  295. target[key] = source[key];
  296. }
  297. }
  298. return target;
  299. }
  300. var createCanvas = function () {
  301. return methods.createCanvas();
  302. };
  303. methods.createCanvas = function () {
  304. return document.createElement('canvas');
  305. };
  306. // FIXME
  307. var _ctx;
  308. function getContext() {
  309. if (!_ctx) {
  310. // Use util.createCanvas instead of createCanvas
  311. // because createCanvas may be overwritten in different environment
  312. _ctx = createCanvas().getContext('2d');
  313. }
  314. return _ctx;
  315. }
  316. /**
  317. * 查询数组中元素的index
  318. * @memberOf module:zrender/core/util
  319. */
  320. function indexOf(array, value) {
  321. if (array) {
  322. if (array.indexOf) {
  323. return array.indexOf(value);
  324. }
  325. for (var i = 0, len = array.length; i < len; i++) {
  326. if (array[i] === value) {
  327. return i;
  328. }
  329. }
  330. }
  331. return -1;
  332. }
  333. /**
  334. * 构造类继承关系
  335. *
  336. * @memberOf module:zrender/core/util
  337. * @param {Function} clazz 源类
  338. * @param {Function} baseClazz 基类
  339. */
  340. function inherits(clazz, baseClazz) {
  341. var clazzPrototype = clazz.prototype;
  342. function F() {}
  343. F.prototype = baseClazz.prototype;
  344. clazz.prototype = new F();
  345. for (var prop in clazzPrototype) {
  346. clazz.prototype[prop] = clazzPrototype[prop];
  347. }
  348. clazz.prototype.constructor = clazz;
  349. clazz.superClass = baseClazz;
  350. }
  351. /**
  352. * @memberOf module:zrender/core/util
  353. * @param {Object|Function} target
  354. * @param {Object|Function} sorce
  355. * @param {boolean} overlay
  356. */
  357. function mixin(target, source, overlay) {
  358. target = 'prototype' in target ? target.prototype : target;
  359. source = 'prototype' in source ? source.prototype : source;
  360. defaults(target, source, overlay);
  361. }
  362. /**
  363. * Consider typed array.
  364. * @param {Array|TypedArray} data
  365. */
  366. function isArrayLike(data) {
  367. if (! data) {
  368. return;
  369. }
  370. if (typeof data == 'string') {
  371. return false;
  372. }
  373. return typeof data.length == 'number';
  374. }
  375. /**
  376. * 数组或对象遍历
  377. * @memberOf module:zrender/core/util
  378. * @param {Object|Array} obj
  379. * @param {Function} cb
  380. * @param {*} [context]
  381. */
  382. function each(obj, cb, context) {
  383. if (!(obj && cb)) {
  384. return;
  385. }
  386. if (obj.forEach && obj.forEach === nativeForEach) {
  387. obj.forEach(cb, context);
  388. }
  389. else if (obj.length === +obj.length) {
  390. for (var i = 0, len = obj.length; i < len; i++) {
  391. cb.call(context, obj[i], i, obj);
  392. }
  393. }
  394. else {
  395. for (var key in obj) {
  396. if (obj.hasOwnProperty(key)) {
  397. cb.call(context, obj[key], key, obj);
  398. }
  399. }
  400. }
  401. }
  402. /**
  403. * 数组映射
  404. * @memberOf module:zrender/core/util
  405. * @param {Array} obj
  406. * @param {Function} cb
  407. * @param {*} [context]
  408. * @return {Array}
  409. */
  410. function map(obj, cb, context) {
  411. if (!(obj && cb)) {
  412. return;
  413. }
  414. if (obj.map && obj.map === nativeMap) {
  415. return obj.map(cb, context);
  416. }
  417. else {
  418. var result = [];
  419. for (var i = 0, len = obj.length; i < len; i++) {
  420. result.push(cb.call(context, obj[i], i, obj));
  421. }
  422. return result;
  423. }
  424. }
  425. /**
  426. * @memberOf module:zrender/core/util
  427. * @param {Array} obj
  428. * @param {Function} cb
  429. * @param {Object} [memo]
  430. * @param {*} [context]
  431. * @return {Array}
  432. */
  433. function reduce(obj, cb, memo, context) {
  434. if (!(obj && cb)) {
  435. return;
  436. }
  437. if (obj.reduce && obj.reduce === nativeReduce) {
  438. return obj.reduce(cb, memo, context);
  439. }
  440. else {
  441. for (var i = 0, len = obj.length; i < len; i++) {
  442. memo = cb.call(context, memo, obj[i], i, obj);
  443. }
  444. return memo;
  445. }
  446. }
  447. /**
  448. * 数组过滤
  449. * @memberOf module:zrender/core/util
  450. * @param {Array} obj
  451. * @param {Function} cb
  452. * @param {*} [context]
  453. * @return {Array}
  454. */
  455. function filter(obj, cb, context) {
  456. if (!(obj && cb)) {
  457. return;
  458. }
  459. if (obj.filter && obj.filter === nativeFilter) {
  460. return obj.filter(cb, context);
  461. }
  462. else {
  463. var result = [];
  464. for (var i = 0, len = obj.length; i < len; i++) {
  465. if (cb.call(context, obj[i], i, obj)) {
  466. result.push(obj[i]);
  467. }
  468. }
  469. return result;
  470. }
  471. }
  472. /**
  473. * 数组项查找
  474. * @memberOf module:zrender/core/util
  475. * @param {Array} obj
  476. * @param {Function} cb
  477. * @param {*} [context]
  478. * @return {*}
  479. */
  480. function find(obj, cb, context) {
  481. if (!(obj && cb)) {
  482. return;
  483. }
  484. for (var i = 0, len = obj.length; i < len; i++) {
  485. if (cb.call(context, obj[i], i, obj)) {
  486. return obj[i];
  487. }
  488. }
  489. }
  490. /**
  491. * @memberOf module:zrender/core/util
  492. * @param {Function} func
  493. * @param {*} context
  494. * @return {Function}
  495. */
  496. function bind(func, context) {
  497. var args = nativeSlice.call(arguments, 2);
  498. return function () {
  499. return func.apply(context, args.concat(nativeSlice.call(arguments)));
  500. };
  501. }
  502. /**
  503. * @memberOf module:zrender/core/util
  504. * @param {Function} func
  505. * @return {Function}
  506. */
  507. function curry(func) {
  508. var args = nativeSlice.call(arguments, 1);
  509. return function () {
  510. return func.apply(this, args.concat(nativeSlice.call(arguments)));
  511. };
  512. }
  513. /**
  514. * @memberOf module:zrender/core/util
  515. * @param {*} value
  516. * @return {boolean}
  517. */
  518. function isArray(value) {
  519. return objToString.call(value) === '[object Array]';
  520. }
  521. /**
  522. * @memberOf module:zrender/core/util
  523. * @param {*} value
  524. * @return {boolean}
  525. */
  526. function isFunction(value) {
  527. return typeof value === 'function';
  528. }
  529. /**
  530. * @memberOf module:zrender/core/util
  531. * @param {*} value
  532. * @return {boolean}
  533. */
  534. function isString(value) {
  535. return objToString.call(value) === '[object String]';
  536. }
  537. /**
  538. * @memberOf module:zrender/core/util
  539. * @param {*} value
  540. * @return {boolean}
  541. */
  542. function isObject(value) {
  543. // Avoid a V8 JIT bug in Chrome 19-20.
  544. // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
  545. var type = typeof value;
  546. return type === 'function' || (!!value && type == 'object');
  547. }
  548. /**
  549. * @memberOf module:zrender/core/util
  550. * @param {*} value
  551. * @return {boolean}
  552. */
  553. function isBuiltInObject(value) {
  554. return !!BUILTIN_OBJECT[objToString.call(value)];
  555. }
  556. /**
  557. * @memberOf module:zrender/core/util
  558. * @param {*} value
  559. * @return {boolean}
  560. */
  561. function isDom(value) {
  562. return typeof value === 'object'
  563. && typeof value.nodeType === 'number'
  564. && typeof value.ownerDocument === 'object';
  565. }
  566. /**
  567. * Whether is exactly NaN. Notice isNaN('a') returns true.
  568. * @param {*} value
  569. * @return {boolean}
  570. */
  571. function eqNaN(value) {
  572. return value !== value;
  573. }
  574. /**
  575. * If value1 is not null, then return value1, otherwise judget rest of values.
  576. * Low performance.
  577. * @memberOf module:zrender/core/util
  578. * @return {*} Final value
  579. */
  580. function retrieve(values) {
  581. for (var i = 0, len = arguments.length; i < len; i++) {
  582. if (arguments[i] != null) {
  583. return arguments[i];
  584. }
  585. }
  586. }
  587. function retrieve2(value0, value1) {
  588. return value0 != null
  589. ? value0
  590. : value1;
  591. }
  592. function retrieve3(value0, value1, value2) {
  593. return value0 != null
  594. ? value0
  595. : value1 != null
  596. ? value1
  597. : value2;
  598. }
  599. /**
  600. * @memberOf module:zrender/core/util
  601. * @param {Array} arr
  602. * @param {number} startIndex
  603. * @param {number} endIndex
  604. * @return {Array}
  605. */
  606. function slice() {
  607. return Function.call.apply(nativeSlice, arguments);
  608. }
  609. /**
  610. * Normalize css liked array configuration
  611. * e.g.
  612. * 3 => [3, 3, 3, 3]
  613. * [4, 2] => [4, 2, 4, 2]
  614. * [4, 3, 2] => [4, 3, 2, 3]
  615. * @param {number|Array.<number>} val
  616. * @return {Array.<number>}
  617. */
  618. function normalizeCssArray(val) {
  619. if (typeof (val) === 'number') {
  620. return [val, val, val, val];
  621. }
  622. var len = val.length;
  623. if (len === 2) {
  624. // vertical | horizontal
  625. return [val[0], val[1], val[0], val[1]];
  626. }
  627. else if (len === 3) {
  628. // top | horizontal | bottom
  629. return [val[0], val[1], val[2], val[1]];
  630. }
  631. return val;
  632. }
  633. /**
  634. * @memberOf module:zrender/core/util
  635. * @param {boolean} condition
  636. * @param {string} message
  637. */
  638. function assert(condition, message) {
  639. if (!condition) {
  640. throw new Error(message);
  641. }
  642. }
  643. var primitiveKey = '__ec_primitive__';
  644. /**
  645. * Set an object as primitive to be ignored traversing children in clone or merge
  646. */
  647. function setAsPrimitive(obj) {
  648. obj[primitiveKey] = true;
  649. }
  650. function isPrimitive(obj) {
  651. return obj[primitiveKey];
  652. }
  653. /**
  654. * @constructor
  655. * @param {Object} obj Only apply `ownProperty`.
  656. */
  657. function HashMap(obj) {
  658. obj && each(obj, function (value, key) {
  659. this.set(key, value);
  660. }, this);
  661. }
  662. // Add prefix to avoid conflict with Object.prototype.
  663. var HASH_MAP_PREFIX = '_ec_';
  664. var HASH_MAP_PREFIX_LENGTH = 4;
  665. HashMap.prototype = {
  666. constructor: HashMap,
  667. // Do not provide `has` method to avoid defining what is `has`.
  668. // (We usually treat `null` and `undefined` as the same, different
  669. // from ES6 Map).
  670. get: function (key) {
  671. return this[HASH_MAP_PREFIX + key];
  672. },
  673. set: function (key, value) {
  674. this[HASH_MAP_PREFIX + key] = value;
  675. // Comparing with invocation chaining, `return value` is more commonly
  676. // used in this case: `var someVal = map.set('a', genVal());`
  677. return value;
  678. },
  679. // Although util.each can be performed on this hashMap directly, user
  680. // should not use the exposed keys, who are prefixed.
  681. each: function (cb, context) {
  682. context !== void 0 && (cb = bind(cb, context));
  683. for (var prefixedKey in this) {
  684. this.hasOwnProperty(prefixedKey)
  685. && cb(this[prefixedKey], prefixedKey.slice(HASH_MAP_PREFIX_LENGTH));
  686. }
  687. },
  688. // Do not use this method if performance sensitive.
  689. removeKey: function (key) {
  690. delete this[HASH_MAP_PREFIX + key];
  691. }
  692. };
  693. function createHashMap(obj) {
  694. return new HashMap(obj);
  695. }
  696. function noop() {}
  697. var util = (Object.freeze || Object)({
  698. $override: $override,
  699. clone: clone,
  700. merge: merge,
  701. mergeAll: mergeAll,
  702. extend: extend,
  703. defaults: defaults,
  704. createCanvas: createCanvas,
  705. getContext: getContext,
  706. indexOf: indexOf,
  707. inherits: inherits,
  708. mixin: mixin,
  709. isArrayLike: isArrayLike,
  710. each: each,
  711. map: map,
  712. reduce: reduce,
  713. filter: filter,
  714. find: find,
  715. bind: bind,
  716. curry: curry,
  717. isArray: isArray,
  718. isFunction: isFunction,
  719. isString: isString,
  720. isObject: isObject,
  721. isBuiltInObject: isBuiltInObject,
  722. isDom: isDom,
  723. eqNaN: eqNaN,
  724. retrieve: retrieve,
  725. retrieve2: retrieve2,
  726. retrieve3: retrieve3,
  727. slice: slice,
  728. normalizeCssArray: normalizeCssArray,
  729. assert: assert,
  730. setAsPrimitive: setAsPrimitive,
  731. isPrimitive: isPrimitive,
  732. createHashMap: createHashMap,
  733. noop: noop
  734. });
  735. var ArrayCtor = typeof Float32Array === 'undefined'
  736. ? Array
  737. : Float32Array;
  738. /**
  739. * 创建一个向量
  740. * @param {number} [x=0]
  741. * @param {number} [y=0]
  742. * @return {Vector2}
  743. */
  744. function create(x, y) {
  745. var out = new ArrayCtor(2);
  746. if (x == null) {
  747. x = 0;
  748. }
  749. if (y == null) {
  750. y = 0;
  751. }
  752. out[0] = x;
  753. out[1] = y;
  754. return out;
  755. }
  756. /**
  757. * 复制向量数据
  758. * @param {Vector2} out
  759. * @param {Vector2} v
  760. * @return {Vector2}
  761. */
  762. function copy(out, v) {
  763. out[0] = v[0];
  764. out[1] = v[1];
  765. return out;
  766. }
  767. /**
  768. * 克隆一个向量
  769. * @param {Vector2} v
  770. * @return {Vector2}
  771. */
  772. function clone$1(v) {
  773. var out = new ArrayCtor(2);
  774. out[0] = v[0];
  775. out[1] = v[1];
  776. return out;
  777. }
  778. /**
  779. * 设置向量的两个项
  780. * @param {Vector2} out
  781. * @param {number} a
  782. * @param {number} b
  783. * @return {Vector2} 结果
  784. */
  785. function set(out, a, b) {
  786. out[0] = a;
  787. out[1] = b;
  788. return out;
  789. }
  790. /**
  791. * 向量相加
  792. * @param {Vector2} out
  793. * @param {Vector2} v1
  794. * @param {Vector2} v2
  795. */
  796. function add(out, v1, v2) {
  797. out[0] = v1[0] + v2[0];
  798. out[1] = v1[1] + v2[1];
  799. return out;
  800. }
  801. /**
  802. * 向量缩放后相加
  803. * @param {Vector2} out
  804. * @param {Vector2} v1
  805. * @param {Vector2} v2
  806. * @param {number} a
  807. */
  808. function scaleAndAdd(out, v1, v2, a) {
  809. out[0] = v1[0] + v2[0] * a;
  810. out[1] = v1[1] + v2[1] * a;
  811. return out;
  812. }
  813. /**
  814. * 向量相减
  815. * @param {Vector2} out
  816. * @param {Vector2} v1
  817. * @param {Vector2} v2
  818. */
  819. function sub(out, v1, v2) {
  820. out[0] = v1[0] - v2[0];
  821. out[1] = v1[1] - v2[1];
  822. return out;
  823. }
  824. /**
  825. * 向量长度
  826. * @param {Vector2} v
  827. * @return {number}
  828. */
  829. function len(v) {
  830. return Math.sqrt(lenSquare(v));
  831. }
  832. var length = len; // jshint ignore:line
  833. /**
  834. * 向量长度平方
  835. * @param {Vector2} v
  836. * @return {number}
  837. */
  838. function lenSquare(v) {
  839. return v[0] * v[0] + v[1] * v[1];
  840. }
  841. var lengthSquare = lenSquare;
  842. /**
  843. * 向量乘法
  844. * @param {Vector2} out
  845. * @param {Vector2} v1
  846. * @param {Vector2} v2
  847. */
  848. function mul(out, v1, v2) {
  849. out[0] = v1[0] * v2[0];
  850. out[1] = v1[1] * v2[1];
  851. return out;
  852. }
  853. /**
  854. * 向量除法
  855. * @param {Vector2} out
  856. * @param {Vector2} v1
  857. * @param {Vector2} v2
  858. */
  859. function div(out, v1, v2) {
  860. out[0] = v1[0] / v2[0];
  861. out[1] = v1[1] / v2[1];
  862. return out;
  863. }
  864. /**
  865. * 向量点乘
  866. * @param {Vector2} v1
  867. * @param {Vector2} v2
  868. * @return {number}
  869. */
  870. function dot(v1, v2) {
  871. return v1[0] * v2[0] + v1[1] * v2[1];
  872. }
  873. /**
  874. * 向量缩放
  875. * @param {Vector2} out
  876. * @param {Vector2} v
  877. * @param {number} s
  878. */
  879. function scale(out, v, s) {
  880. out[0] = v[0] * s;
  881. out[1] = v[1] * s;
  882. return out;
  883. }
  884. /**
  885. * 向量归一化
  886. * @param {Vector2} out
  887. * @param {Vector2} v
  888. */
  889. function normalize(out, v) {
  890. var d = len(v);
  891. if (d === 0) {
  892. out[0] = 0;
  893. out[1] = 0;
  894. }
  895. else {
  896. out[0] = v[0] / d;
  897. out[1] = v[1] / d;
  898. }
  899. return out;
  900. }
  901. /**
  902. * 计算向量间距离
  903. * @param {Vector2} v1
  904. * @param {Vector2} v2
  905. * @return {number}
  906. */
  907. function distance(v1, v2) {
  908. return Math.sqrt(
  909. (v1[0] - v2[0]) * (v1[0] - v2[0])
  910. + (v1[1] - v2[1]) * (v1[1] - v2[1])
  911. );
  912. }
  913. var dist = distance;
  914. /**
  915. * 向量距离平方
  916. * @param {Vector2} v1
  917. * @param {Vector2} v2
  918. * @return {number}
  919. */
  920. function distanceSquare(v1, v2) {
  921. return (v1[0] - v2[0]) * (v1[0] - v2[0])
  922. + (v1[1] - v2[1]) * (v1[1] - v2[1]);
  923. }
  924. var distSquare = distanceSquare;
  925. /**
  926. * 求负向量
  927. * @param {Vector2} out
  928. * @param {Vector2} v
  929. */
  930. function negate(out, v) {
  931. out[0] = -v[0];
  932. out[1] = -v[1];
  933. return out;
  934. }
  935. /**
  936. * 插值两个点
  937. * @param {Vector2} out
  938. * @param {Vector2} v1
  939. * @param {Vector2} v2
  940. * @param {number} t
  941. */
  942. function lerp(out, v1, v2, t) {
  943. out[0] = v1[0] + t * (v2[0] - v1[0]);
  944. out[1] = v1[1] + t * (v2[1] - v1[1]);
  945. return out;
  946. }
  947. /**
  948. * 矩阵左乘向量
  949. * @param {Vector2} out
  950. * @param {Vector2} v
  951. * @param {Vector2} m
  952. */
  953. function applyTransform(out, v, m) {
  954. var x = v[0];
  955. var y = v[1];
  956. out[0] = m[0] * x + m[2] * y + m[4];
  957. out[1] = m[1] * x + m[3] * y + m[5];
  958. return out;
  959. }
  960. /**
  961. * 求两个向量最小值
  962. * @param {Vector2} out
  963. * @param {Vector2} v1
  964. * @param {Vector2} v2
  965. */
  966. function min(out, v1, v2) {
  967. out[0] = Math.min(v1[0], v2[0]);
  968. out[1] = Math.min(v1[1], v2[1]);
  969. return out;
  970. }
  971. /**
  972. * 求两个向量最大值
  973. * @param {Vector2} out
  974. * @param {Vector2} v1
  975. * @param {Vector2} v2
  976. */
  977. function max(out, v1, v2) {
  978. out[0] = Math.max(v1[0], v2[0]);
  979. out[1] = Math.max(v1[1], v2[1]);
  980. return out;
  981. }
  982. var vector = (Object.freeze || Object)({
  983. create: create,
  984. copy: copy,
  985. clone: clone$1,
  986. set: set,
  987. add: add,
  988. scaleAndAdd: scaleAndAdd,
  989. sub: sub,
  990. len: len,
  991. length: length,
  992. lenSquare: lenSquare,
  993. lengthSquare: lengthSquare,
  994. mul: mul,
  995. div: div,
  996. dot: dot,
  997. scale: scale,
  998. normalize: normalize,
  999. distance: distance,
  1000. dist: dist,
  1001. distanceSquare: distanceSquare,
  1002. distSquare: distSquare,
  1003. negate: negate,
  1004. lerp: lerp,
  1005. applyTransform: applyTransform,
  1006. min: min,
  1007. max: max
  1008. });
  1009. // TODO Draggable for group
  1010. // FIXME Draggable on element which has parent rotation or scale
  1011. function Draggable() {
  1012. this.on('mousedown', this._dragStart, this);
  1013. this.on('mousemove', this._drag, this);
  1014. this.on('mouseup', this._dragEnd, this);
  1015. this.on('globalout', this._dragEnd, this);
  1016. // this._dropTarget = null;
  1017. // this._draggingTarget = null;
  1018. // this._x = 0;
  1019. // this._y = 0;
  1020. }
  1021. Draggable.prototype = {
  1022. constructor: Draggable,
  1023. _dragStart: function (e) {
  1024. var draggingTarget = e.target;
  1025. if (draggingTarget && draggingTarget.draggable) {
  1026. this._draggingTarget = draggingTarget;
  1027. draggingTarget.dragging = true;
  1028. this._x = e.offsetX;
  1029. this._y = e.offsetY;
  1030. this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);
  1031. }
  1032. },
  1033. _drag: function (e) {
  1034. var draggingTarget = this._draggingTarget;
  1035. if (draggingTarget) {
  1036. var x = e.offsetX;
  1037. var y = e.offsetY;
  1038. var dx = x - this._x;
  1039. var dy = y - this._y;
  1040. this._x = x;
  1041. this._y = y;
  1042. draggingTarget.drift(dx, dy, e);
  1043. this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);
  1044. var dropTarget = this.findHover(x, y, draggingTarget).target;
  1045. var lastDropTarget = this._dropTarget;
  1046. this._dropTarget = dropTarget;
  1047. if (draggingTarget !== dropTarget) {
  1048. if (lastDropTarget && dropTarget !== lastDropTarget) {
  1049. this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);
  1050. }
  1051. if (dropTarget && dropTarget !== lastDropTarget) {
  1052. this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);
  1053. }
  1054. }
  1055. }
  1056. },
  1057. _dragEnd: function (e) {
  1058. var draggingTarget = this._draggingTarget;
  1059. if (draggingTarget) {
  1060. draggingTarget.dragging = false;
  1061. }
  1062. this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);
  1063. if (this._dropTarget) {
  1064. this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);
  1065. }
  1066. this._draggingTarget = null;
  1067. this._dropTarget = null;
  1068. }
  1069. };
  1070. function param(target, e) {
  1071. return {target: target, topTarget: e && e.topTarget};
  1072. }
  1073. /**
  1074. * 事件扩展
  1075. * @module zrender/mixin/Eventful
  1076. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  1077. * pissang (https://www.github.com/pissang)
  1078. */
  1079. var arrySlice = Array.prototype.slice;
  1080. /**
  1081. * 事件分发器
  1082. * @alias module:zrender/mixin/Eventful
  1083. * @constructor
  1084. */
  1085. var Eventful = function () {
  1086. this._$handlers = {};
  1087. };
  1088. Eventful.prototype = {
  1089. constructor: Eventful,
  1090. /**
  1091. * 单次触发绑定,trigger后销毁
  1092. *
  1093. * @param {string} event 事件名
  1094. * @param {Function} handler 响应函数
  1095. * @param {Object} context
  1096. */
  1097. one: function (event, handler, context) {
  1098. var _h = this._$handlers;
  1099. if (!handler || !event) {
  1100. return this;
  1101. }
  1102. if (!_h[event]) {
  1103. _h[event] = [];
  1104. }
  1105. for (var i = 0; i < _h[event].length; i++) {
  1106. if (_h[event][i].h === handler) {
  1107. return this;
  1108. }
  1109. }
  1110. _h[event].push({
  1111. h: handler,
  1112. one: true,
  1113. ctx: context || this
  1114. });
  1115. return this;
  1116. },
  1117. /**
  1118. * 绑定事件
  1119. * @param {string} event 事件名
  1120. * @param {Function} handler 事件处理函数
  1121. * @param {Object} [context]
  1122. */
  1123. on: function (event, handler, context) {
  1124. var _h = this._$handlers;
  1125. if (!handler || !event) {
  1126. return this;
  1127. }
  1128. if (!_h[event]) {
  1129. _h[event] = [];
  1130. }
  1131. for (var i = 0; i < _h[event].length; i++) {
  1132. if (_h[event][i].h === handler) {
  1133. return this;
  1134. }
  1135. }
  1136. _h[event].push({
  1137. h: handler,
  1138. one: false,
  1139. ctx: context || this
  1140. });
  1141. return this;
  1142. },
  1143. /**
  1144. * 是否绑定了事件
  1145. * @param {string} event
  1146. * @return {boolean}
  1147. */
  1148. isSilent: function (event) {
  1149. var _h = this._$handlers;
  1150. return _h[event] && _h[event].length;
  1151. },
  1152. /**
  1153. * 解绑事件
  1154. * @param {string} event 事件名
  1155. * @param {Function} [handler] 事件处理函数
  1156. */
  1157. off: function (event, handler) {
  1158. var _h = this._$handlers;
  1159. if (!event) {
  1160. this._$handlers = {};
  1161. return this;
  1162. }
  1163. if (handler) {
  1164. if (_h[event]) {
  1165. var newList = [];
  1166. for (var i = 0, l = _h[event].length; i < l; i++) {
  1167. if (_h[event][i]['h'] != handler) {
  1168. newList.push(_h[event][i]);
  1169. }
  1170. }
  1171. _h[event] = newList;
  1172. }
  1173. if (_h[event] && _h[event].length === 0) {
  1174. delete _h[event];
  1175. }
  1176. }
  1177. else {
  1178. delete _h[event];
  1179. }
  1180. return this;
  1181. },
  1182. /**
  1183. * 事件分发
  1184. *
  1185. * @param {string} type 事件类型
  1186. */
  1187. trigger: function (type) {
  1188. if (this._$handlers[type]) {
  1189. var args = arguments;
  1190. var argLen = args.length;
  1191. if (argLen > 3) {
  1192. args = arrySlice.call(args, 1);
  1193. }
  1194. var _h = this._$handlers[type];
  1195. var len = _h.length;
  1196. for (var i = 0; i < len;) {
  1197. // Optimize advise from backbone
  1198. switch (argLen) {
  1199. case 1:
  1200. _h[i]['h'].call(_h[i]['ctx']);
  1201. break;
  1202. case 2:
  1203. _h[i]['h'].call(_h[i]['ctx'], args[1]);
  1204. break;
  1205. case 3:
  1206. _h[i]['h'].call(_h[i]['ctx'], args[1], args[2]);
  1207. break;
  1208. default:
  1209. // have more than 2 given arguments
  1210. _h[i]['h'].apply(_h[i]['ctx'], args);
  1211. break;
  1212. }
  1213. if (_h[i]['one']) {
  1214. _h.splice(i, 1);
  1215. len--;
  1216. }
  1217. else {
  1218. i++;
  1219. }
  1220. }
  1221. }
  1222. return this;
  1223. },
  1224. /**
  1225. * 带有context的事件分发, 最后一个参数是事件回调的context
  1226. * @param {string} type 事件类型
  1227. */
  1228. triggerWithContext: function (type) {
  1229. if (this._$handlers[type]) {
  1230. var args = arguments;
  1231. var argLen = args.length;
  1232. if (argLen > 4) {
  1233. args = arrySlice.call(args, 1, args.length - 1);
  1234. }
  1235. var ctx = args[args.length - 1];
  1236. var _h = this._$handlers[type];
  1237. var len = _h.length;
  1238. for (var i = 0; i < len;) {
  1239. // Optimize advise from backbone
  1240. switch (argLen) {
  1241. case 1:
  1242. _h[i]['h'].call(ctx);
  1243. break;
  1244. case 2:
  1245. _h[i]['h'].call(ctx, args[1]);
  1246. break;
  1247. case 3:
  1248. _h[i]['h'].call(ctx, args[1], args[2]);
  1249. break;
  1250. default:
  1251. // have more than 2 given arguments
  1252. _h[i]['h'].apply(ctx, args);
  1253. break;
  1254. }
  1255. if (_h[i]['one']) {
  1256. _h.splice(i, 1);
  1257. len--;
  1258. }
  1259. else {
  1260. i++;
  1261. }
  1262. }
  1263. }
  1264. return this;
  1265. }
  1266. };
  1267. /**
  1268. * Handler
  1269. * @module zrender/Handler
  1270. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  1271. * errorrik (errorrik@gmail.com)
  1272. * pissang (shenyi.914@gmail.com)
  1273. */
  1274. var SILENT = 'silent';
  1275. function makeEventPacket(eveType, targetInfo, event) {
  1276. return {
  1277. type: eveType,
  1278. event: event,
  1279. // target can only be an element that is not silent.
  1280. target: targetInfo.target,
  1281. // topTarget can be a silent element.
  1282. topTarget: targetInfo.topTarget,
  1283. cancelBubble: false,
  1284. offsetX: event.zrX,
  1285. offsetY: event.zrY,
  1286. gestureEvent: event.gestureEvent,
  1287. pinchX: event.pinchX,
  1288. pinchY: event.pinchY,
  1289. pinchScale: event.pinchScale,
  1290. wheelDelta: event.zrDelta,
  1291. zrByTouch: event.zrByTouch,
  1292. which: event.which
  1293. };
  1294. }
  1295. function EmptyProxy () {}
  1296. EmptyProxy.prototype.dispose = function () {};
  1297. var handlerNames = [
  1298. 'click', 'dblclick', 'mousewheel', 'mouseout',
  1299. 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
  1300. ];
  1301. /**
  1302. * @alias module:zrender/Handler
  1303. * @constructor
  1304. * @extends module:zrender/mixin/Eventful
  1305. * @param {module:zrender/Storage} storage Storage instance.
  1306. * @param {module:zrender/Painter} painter Painter instance.
  1307. * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.
  1308. * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).
  1309. */
  1310. var Handler = function(storage, painter, proxy, painterRoot) {
  1311. Eventful.call(this);
  1312. this.storage = storage;
  1313. this.painter = painter;
  1314. this.painterRoot = painterRoot;
  1315. proxy = proxy || new EmptyProxy();
  1316. /**
  1317. * Proxy of event. can be Dom, WebGLSurface, etc.
  1318. */
  1319. this.proxy = proxy;
  1320. // Attach handler
  1321. proxy.handler = this;
  1322. /**
  1323. * {target, topTarget, x, y}
  1324. * @private
  1325. * @type {Object}
  1326. */
  1327. this._hovered = {};
  1328. /**
  1329. * @private
  1330. * @type {Date}
  1331. */
  1332. this._lastTouchMoment;
  1333. /**
  1334. * @private
  1335. * @type {number}
  1336. */
  1337. this._lastX;
  1338. /**
  1339. * @private
  1340. * @type {number}
  1341. */
  1342. this._lastY;
  1343. Draggable.call(this);
  1344. each(handlerNames, function (name) {
  1345. proxy.on && proxy.on(name, this[name], this);
  1346. }, this);
  1347. };
  1348. Handler.prototype = {
  1349. constructor: Handler,
  1350. mousemove: function (event) {
  1351. var x = event.zrX;
  1352. var y = event.zrY;
  1353. var lastHovered = this._hovered;
  1354. var lastHoveredTarget = lastHovered.target;
  1355. // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call
  1356. // (like 'setOption' or 'dispatchAction') in event handlers, we should find
  1357. // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.
  1358. // See #6198.
  1359. if (lastHoveredTarget && !lastHoveredTarget.__zr) {
  1360. lastHovered = this.findHover(lastHovered.x, lastHovered.y);
  1361. lastHoveredTarget = lastHovered.target;
  1362. }
  1363. var hovered = this._hovered = this.findHover(x, y);
  1364. var hoveredTarget = hovered.target;
  1365. var proxy = this.proxy;
  1366. proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');
  1367. // Mouse out on previous hovered element
  1368. if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {
  1369. this.dispatchToElement(lastHovered, 'mouseout', event);
  1370. }
  1371. // Mouse moving on one element
  1372. this.dispatchToElement(hovered, 'mousemove', event);
  1373. // Mouse over on a new element
  1374. if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {
  1375. this.dispatchToElement(hovered, 'mouseover', event);
  1376. }
  1377. },
  1378. mouseout: function (event) {
  1379. this.dispatchToElement(this._hovered, 'mouseout', event);
  1380. // There might be some doms created by upper layer application
  1381. // at the same level of painter.getViewportRoot() (e.g., tooltip
  1382. // dom created by echarts), where 'globalout' event should not
  1383. // be triggered when mouse enters these doms. (But 'mouseout'
  1384. // should be triggered at the original hovered element as usual).
  1385. var element = event.toElement || event.relatedTarget;
  1386. var innerDom;
  1387. do {
  1388. element = element && element.parentNode;
  1389. }
  1390. while (element && element.nodeType != 9 && !(
  1391. innerDom = element === this.painterRoot
  1392. ));
  1393. !innerDom && this.trigger('globalout', {event: event});
  1394. },
  1395. /**
  1396. * Resize
  1397. */
  1398. resize: function (event) {
  1399. this._hovered = {};
  1400. },
  1401. /**
  1402. * Dispatch event
  1403. * @param {string} eventName
  1404. * @param {event=} eventArgs
  1405. */
  1406. dispatch: function (eventName, eventArgs) {
  1407. var handler = this[eventName];
  1408. handler && handler.call(this, eventArgs);
  1409. },
  1410. /**
  1411. * Dispose
  1412. */
  1413. dispose: function () {
  1414. this.proxy.dispose();
  1415. this.storage =
  1416. this.proxy =
  1417. this.painter = null;
  1418. },
  1419. /**
  1420. * 设置默认的cursor style
  1421. * @param {string} [cursorStyle='default'] 例如 crosshair
  1422. */
  1423. setCursorStyle: function (cursorStyle) {
  1424. var proxy = this.proxy;
  1425. proxy.setCursor && proxy.setCursor(cursorStyle);
  1426. },
  1427. /**
  1428. * 事件分发代理
  1429. *
  1430. * @private
  1431. * @param {Object} targetInfo {target, topTarget} 目标图形元素
  1432. * @param {string} eventName 事件名称
  1433. * @param {Object} event 事件对象
  1434. */
  1435. dispatchToElement: function (targetInfo, eventName, event) {
  1436. targetInfo = targetInfo || {};
  1437. var el = targetInfo.target;
  1438. if (el && el.silent) {
  1439. return;
  1440. }
  1441. var eventHandler = 'on' + eventName;
  1442. var eventPacket = makeEventPacket(eventName, targetInfo, event);
  1443. while (el) {
  1444. el[eventHandler]
  1445. && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));
  1446. el.trigger(eventName, eventPacket);
  1447. el = el.parent;
  1448. if (eventPacket.cancelBubble) {
  1449. break;
  1450. }
  1451. }
  1452. if (!eventPacket.cancelBubble) {
  1453. // 冒泡到顶级 zrender 对象
  1454. this.trigger(eventName, eventPacket);
  1455. // 分发事件到用户自定义层
  1456. // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在
  1457. this.painter && this.painter.eachOtherLayer(function (layer) {
  1458. if (typeof(layer[eventHandler]) == 'function') {
  1459. layer[eventHandler].call(layer, eventPacket);
  1460. }
  1461. if (layer.trigger) {
  1462. layer.trigger(eventName, eventPacket);
  1463. }
  1464. });
  1465. }
  1466. },
  1467. /**
  1468. * @private
  1469. * @param {number} x
  1470. * @param {number} y
  1471. * @param {module:zrender/graphic/Displayable} exclude
  1472. * @return {model:zrender/Element}
  1473. * @method
  1474. */
  1475. findHover: function(x, y, exclude) {
  1476. var list = this.storage.getDisplayList();
  1477. var out = {x: x, y: y};
  1478. for (var i = list.length - 1; i >= 0 ; i--) {
  1479. var hoverCheckResult;
  1480. if (list[i] !== exclude
  1481. // getDisplayList may include ignored item in VML mode
  1482. && !list[i].ignore
  1483. && (hoverCheckResult = isHover(list[i], x, y))
  1484. ) {
  1485. !out.topTarget && (out.topTarget = list[i]);
  1486. if (hoverCheckResult !== SILENT) {
  1487. out.target = list[i];
  1488. break;
  1489. }
  1490. }
  1491. }
  1492. return out;
  1493. }
  1494. };
  1495. // Common handlers
  1496. each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
  1497. Handler.prototype[name] = function (event) {
  1498. // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
  1499. var hovered = this.findHover(event.zrX, event.zrY);
  1500. var hoveredTarget = hovered.target;
  1501. if (name === 'mousedown') {
  1502. this._downEl = hoveredTarget;
  1503. this._downPoint = [event.zrX, event.zrY];
  1504. // In case click triggered before mouseup
  1505. this._upEl = hoveredTarget;
  1506. }
  1507. else if (name === 'mosueup') {
  1508. this._upEl = hoveredTarget;
  1509. }
  1510. else if (name === 'click') {
  1511. if (this._downEl !== this._upEl
  1512. // Original click event is triggered on the whole canvas element,
  1513. // including the case that `mousedown` - `mousemove` - `mouseup`,
  1514. // which should be filtered, otherwise it will bring trouble to
  1515. // pan and zoom.
  1516. || !this._downPoint
  1517. // Arbitrary value
  1518. || dist(this._downPoint, [event.zrX, event.zrY]) > 4
  1519. ) {
  1520. return;
  1521. }
  1522. this._downPoint = null;
  1523. }
  1524. this.dispatchToElement(hovered, name, event);
  1525. };
  1526. });
  1527. function isHover(displayable, x, y) {
  1528. if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
  1529. var el = displayable;
  1530. var isSilent;
  1531. while (el) {
  1532. // If clipped by ancestor.
  1533. // FIXME: If clipPath has neither stroke nor fill,
  1534. // el.clipPath.contain(x, y) will always return false.
  1535. if (el.clipPath && !el.clipPath.contain(x, y)) {
  1536. return false;
  1537. }
  1538. if (el.silent) {
  1539. isSilent = true;
  1540. }
  1541. el = el.parent;
  1542. }
  1543. return isSilent ? SILENT : true;
  1544. }
  1545. return false;
  1546. }
  1547. mixin(Handler, Eventful);
  1548. mixin(Handler, Draggable);
  1549. /**
  1550. * 3x2矩阵操作类
  1551. * @exports zrender/tool/matrix
  1552. */
  1553. var ArrayCtor$1 = typeof Float32Array === 'undefined'
  1554. ? Array
  1555. : Float32Array;
  1556. /**
  1557. * 创建一个单位矩阵
  1558. * @return {Float32Array|Array.<number>}
  1559. */
  1560. function create$1() {
  1561. var out = new ArrayCtor$1(6);
  1562. identity(out);
  1563. return out;
  1564. }
  1565. /**
  1566. * 设置矩阵为单位矩阵
  1567. * @param {Float32Array|Array.<number>} out
  1568. */
  1569. function identity(out) {
  1570. out[0] = 1;
  1571. out[1] = 0;
  1572. out[2] = 0;
  1573. out[3] = 1;
  1574. out[4] = 0;
  1575. out[5] = 0;
  1576. return out;
  1577. }
  1578. /**
  1579. * 复制矩阵
  1580. * @param {Float32Array|Array.<number>} out
  1581. * @param {Float32Array|Array.<number>} m
  1582. */
  1583. function copy$1(out, m) {
  1584. out[0] = m[0];
  1585. out[1] = m[1];
  1586. out[2] = m[2];
  1587. out[3] = m[3];
  1588. out[4] = m[4];
  1589. out[5] = m[5];
  1590. return out;
  1591. }
  1592. /**
  1593. * 矩阵相乘
  1594. * @param {Float32Array|Array.<number>} out
  1595. * @param {Float32Array|Array.<number>} m1
  1596. * @param {Float32Array|Array.<number>} m2
  1597. */
  1598. function mul$1(out, m1, m2) {
  1599. // Consider matrix.mul(m, m2, m);
  1600. // where out is the same as m2.
  1601. // So use temp variable to escape error.
  1602. var out0 = m1[0] * m2[0] + m1[2] * m2[1];
  1603. var out1 = m1[1] * m2[0] + m1[3] * m2[1];
  1604. var out2 = m1[0] * m2[2] + m1[2] * m2[3];
  1605. var out3 = m1[1] * m2[2] + m1[3] * m2[3];
  1606. var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
  1607. var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
  1608. out[0] = out0;
  1609. out[1] = out1;
  1610. out[2] = out2;
  1611. out[3] = out3;
  1612. out[4] = out4;
  1613. out[5] = out5;
  1614. return out;
  1615. }
  1616. /**
  1617. * 平移变换
  1618. * @param {Float32Array|Array.<number>} out
  1619. * @param {Float32Array|Array.<number>} a
  1620. * @param {Float32Array|Array.<number>} v
  1621. */
  1622. function translate(out, a, v) {
  1623. out[0] = a[0];
  1624. out[1] = a[1];
  1625. out[2] = a[2];
  1626. out[3] = a[3];
  1627. out[4] = a[4] + v[0];
  1628. out[5] = a[5] + v[1];
  1629. return out;
  1630. }
  1631. /**
  1632. * 旋转变换
  1633. * @param {Float32Array|Array.<number>} out
  1634. * @param {Float32Array|Array.<number>} a
  1635. * @param {number} rad
  1636. */
  1637. function rotate(out, a, rad) {
  1638. var aa = a[0];
  1639. var ac = a[2];
  1640. var atx = a[4];
  1641. var ab = a[1];
  1642. var ad = a[3];
  1643. var aty = a[5];
  1644. var st = Math.sin(rad);
  1645. var ct = Math.cos(rad);
  1646. out[0] = aa * ct + ab * st;
  1647. out[1] = -aa * st + ab * ct;
  1648. out[2] = ac * ct + ad * st;
  1649. out[3] = -ac * st + ct * ad;
  1650. out[4] = ct * atx + st * aty;
  1651. out[5] = ct * aty - st * atx;
  1652. return out;
  1653. }
  1654. /**
  1655. * 缩放变换
  1656. * @param {Float32Array|Array.<number>} out
  1657. * @param {Float32Array|Array.<number>} a
  1658. * @param {Float32Array|Array.<number>} v
  1659. */
  1660. function scale$1(out, a, v) {
  1661. var vx = v[0];
  1662. var vy = v[1];
  1663. out[0] = a[0] * vx;
  1664. out[1] = a[1] * vy;
  1665. out[2] = a[2] * vx;
  1666. out[3] = a[3] * vy;
  1667. out[4] = a[4] * vx;
  1668. out[5] = a[5] * vy;
  1669. return out;
  1670. }
  1671. /**
  1672. * 求逆矩阵
  1673. * @param {Float32Array|Array.<number>} out
  1674. * @param {Float32Array|Array.<number>} a
  1675. */
  1676. function invert(out, a) {
  1677. var aa = a[0];
  1678. var ac = a[2];
  1679. var atx = a[4];
  1680. var ab = a[1];
  1681. var ad = a[3];
  1682. var aty = a[5];
  1683. var det = aa * ad - ab * ac;
  1684. if (!det) {
  1685. return null;
  1686. }
  1687. det = 1.0 / det;
  1688. out[0] = ad * det;
  1689. out[1] = -ab * det;
  1690. out[2] = -ac * det;
  1691. out[3] = aa * det;
  1692. out[4] = (ac * aty - ad * atx) * det;
  1693. out[5] = (ab * atx - aa * aty) * det;
  1694. return out;
  1695. }
  1696. var matrix = (Object.freeze || Object)({
  1697. create: create$1,
  1698. identity: identity,
  1699. copy: copy$1,
  1700. mul: mul$1,
  1701. translate: translate,
  1702. rotate: rotate,
  1703. scale: scale$1,
  1704. invert: invert
  1705. });
  1706. /**
  1707. * 提供变换扩展
  1708. * @module zrender/mixin/Transformable
  1709. * @author pissang (https://www.github.com/pissang)
  1710. */
  1711. var mIdentity = identity;
  1712. var EPSILON = 5e-5;
  1713. function isNotAroundZero(val) {
  1714. return val > EPSILON || val < -EPSILON;
  1715. }
  1716. /**
  1717. * @alias module:zrender/mixin/Transformable
  1718. * @constructor
  1719. */
  1720. var Transformable = function (opts) {
  1721. opts = opts || {};
  1722. // If there are no given position, rotation, scale
  1723. if (!opts.position) {
  1724. /**
  1725. * 平移
  1726. * @type {Array.<number>}
  1727. * @default [0, 0]
  1728. */
  1729. this.position = [0, 0];
  1730. }
  1731. if (opts.rotation == null) {
  1732. /**
  1733. * 旋转
  1734. * @type {Array.<number>}
  1735. * @default 0
  1736. */
  1737. this.rotation = 0;
  1738. }
  1739. if (!opts.scale) {
  1740. /**
  1741. * 缩放
  1742. * @type {Array.<number>}
  1743. * @default [1, 1]
  1744. */
  1745. this.scale = [1, 1];
  1746. }
  1747. /**
  1748. * 旋转和缩放的原点
  1749. * @type {Array.<number>}
  1750. * @default null
  1751. */
  1752. this.origin = this.origin || null;
  1753. };
  1754. var transformableProto = Transformable.prototype;
  1755. transformableProto.transform = null;
  1756. /**
  1757. * 判断是否需要有坐标变换
  1758. * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵
  1759. */
  1760. transformableProto.needLocalTransform = function () {
  1761. return isNotAroundZero(this.rotation)
  1762. || isNotAroundZero(this.position[0])
  1763. || isNotAroundZero(this.position[1])
  1764. || isNotAroundZero(this.scale[0] - 1)
  1765. || isNotAroundZero(this.scale[1] - 1);
  1766. };
  1767. transformableProto.updateTransform = function () {
  1768. var parent = this.parent;
  1769. var parentHasTransform = parent && parent.transform;
  1770. var needLocalTransform = this.needLocalTransform();
  1771. var m = this.transform;
  1772. if (!(needLocalTransform || parentHasTransform)) {
  1773. m && mIdentity(m);
  1774. return;
  1775. }
  1776. m = m || create$1();
  1777. if (needLocalTransform) {
  1778. this.getLocalTransform(m);
  1779. }
  1780. else {
  1781. mIdentity(m);
  1782. }
  1783. // 应用父节点变换
  1784. if (parentHasTransform) {
  1785. if (needLocalTransform) {
  1786. mul$1(m, parent.transform, m);
  1787. }
  1788. else {
  1789. copy$1(m, parent.transform);
  1790. }
  1791. }
  1792. // 保存这个变换矩阵
  1793. this.transform = m;
  1794. this.invTransform = this.invTransform || create$1();
  1795. invert(this.invTransform, m);
  1796. };
  1797. transformableProto.getLocalTransform = function (m) {
  1798. return Transformable.getLocalTransform(this, m);
  1799. };
  1800. /**
  1801. * 将自己的transform应用到context上
  1802. * @param {CanvasRenderingContext2D} ctx
  1803. */
  1804. transformableProto.setTransform = function (ctx) {
  1805. var m = this.transform;
  1806. var dpr = ctx.dpr || 1;
  1807. if (m) {
  1808. ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
  1809. }
  1810. else {
  1811. ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
  1812. }
  1813. };
  1814. transformableProto.restoreTransform = function (ctx) {
  1815. var dpr = ctx.dpr || 1;
  1816. ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
  1817. };
  1818. var tmpTransform = [];
  1819. /**
  1820. * 分解`transform`矩阵到`position`, `rotation`, `scale`
  1821. */
  1822. transformableProto.decomposeTransform = function () {
  1823. if (!this.transform) {
  1824. return;
  1825. }
  1826. var parent = this.parent;
  1827. var m = this.transform;
  1828. if (parent && parent.transform) {
  1829. // Get local transform and decompose them to position, scale, rotation
  1830. mul$1(tmpTransform, parent.invTransform, m);
  1831. m = tmpTransform;
  1832. }
  1833. var sx = m[0] * m[0] + m[1] * m[1];
  1834. var sy = m[2] * m[2] + m[3] * m[3];
  1835. var position = this.position;
  1836. var scale$$1 = this.scale;
  1837. if (isNotAroundZero(sx - 1)) {
  1838. sx = Math.sqrt(sx);
  1839. }
  1840. if (isNotAroundZero(sy - 1)) {
  1841. sy = Math.sqrt(sy);
  1842. }
  1843. if (m[0] < 0) {
  1844. sx = -sx;
  1845. }
  1846. if (m[3] < 0) {
  1847. sy = -sy;
  1848. }
  1849. position[0] = m[4];
  1850. position[1] = m[5];
  1851. scale$$1[0] = sx;
  1852. scale$$1[1] = sy;
  1853. this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
  1854. };
  1855. /**
  1856. * Get global scale
  1857. * @return {Array.<number>}
  1858. */
  1859. transformableProto.getGlobalScale = function () {
  1860. var m = this.transform;
  1861. if (!m) {
  1862. return [1, 1];
  1863. }
  1864. var sx = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
  1865. var sy = Math.sqrt(m[2] * m[2] + m[3] * m[3]);
  1866. if (m[0] < 0) {
  1867. sx = -sx;
  1868. }
  1869. if (m[3] < 0) {
  1870. sy = -sy;
  1871. }
  1872. return [sx, sy];
  1873. };
  1874. /**
  1875. * 变换坐标位置到 shape 的局部坐标空间
  1876. * @method
  1877. * @param {number} x
  1878. * @param {number} y
  1879. * @return {Array.<number>}
  1880. */
  1881. transformableProto.transformCoordToLocal = function (x, y) {
  1882. var v2 = [x, y];
  1883. var invTransform = this.invTransform;
  1884. if (invTransform) {
  1885. applyTransform(v2, v2, invTransform);
  1886. }
  1887. return v2;
  1888. };
  1889. /**
  1890. * 变换局部坐标位置到全局坐标空间
  1891. * @method
  1892. * @param {number} x
  1893. * @param {number} y
  1894. * @return {Array.<number>}
  1895. */
  1896. transformableProto.transformCoordToGlobal = function (x, y) {
  1897. var v2 = [x, y];
  1898. var transform = this.transform;
  1899. if (transform) {
  1900. applyTransform(v2, v2, transform);
  1901. }
  1902. return v2;
  1903. };
  1904. /**
  1905. * @static
  1906. * @param {Object} target
  1907. * @param {Array.<number>} target.origin
  1908. * @param {number} target.rotation
  1909. * @param {Array.<number>} target.position
  1910. * @param {Array.<number>} [m]
  1911. */
  1912. Transformable.getLocalTransform = function (target, m) {
  1913. m = m || [];
  1914. mIdentity(m);
  1915. var origin = target.origin;
  1916. var scale$$1 = target.scale || [1, 1];
  1917. var rotation = target.rotation || 0;
  1918. var position = target.position || [0, 0];
  1919. if (origin) {
  1920. // Translate to origin
  1921. m[4] -= origin[0];
  1922. m[5] -= origin[1];
  1923. }
  1924. scale$1(m, m, scale$$1);
  1925. if (rotation) {
  1926. rotate(m, m, rotation);
  1927. }
  1928. if (origin) {
  1929. // Translate back from origin
  1930. m[4] += origin[0];
  1931. m[5] += origin[1];
  1932. }
  1933. m[4] += position[0];
  1934. m[5] += position[1];
  1935. return m;
  1936. };
  1937. /**
  1938. * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js
  1939. * @see http://sole.github.io/tween.js/examples/03_graphs.html
  1940. * @exports zrender/animation/easing
  1941. */
  1942. var easing = {
  1943. /**
  1944. * @param {number} k
  1945. * @return {number}
  1946. */
  1947. linear: function (k) {
  1948. return k;
  1949. },
  1950. /**
  1951. * @param {number} k
  1952. * @return {number}
  1953. */
  1954. quadraticIn: function (k) {
  1955. return k * k;
  1956. },
  1957. /**
  1958. * @param {number} k
  1959. * @return {number}
  1960. */
  1961. quadraticOut: function (k) {
  1962. return k * (2 - k);
  1963. },
  1964. /**
  1965. * @param {number} k
  1966. * @return {number}
  1967. */
  1968. quadraticInOut: function (k) {
  1969. if ((k *= 2) < 1) {
  1970. return 0.5 * k * k;
  1971. }
  1972. return -0.5 * (--k * (k - 2) - 1);
  1973. },
  1974. // 三次方的缓动(t^3)
  1975. /**
  1976. * @param {number} k
  1977. * @return {number}
  1978. */
  1979. cubicIn: function (k) {
  1980. return k * k * k;
  1981. },
  1982. /**
  1983. * @param {number} k
  1984. * @return {number}
  1985. */
  1986. cubicOut: function (k) {
  1987. return --k * k * k + 1;
  1988. },
  1989. /**
  1990. * @param {number} k
  1991. * @return {number}
  1992. */
  1993. cubicInOut: function (k) {
  1994. if ((k *= 2) < 1) {
  1995. return 0.5 * k * k * k;
  1996. }
  1997. return 0.5 * ((k -= 2) * k * k + 2);
  1998. },
  1999. // 四次方的缓动(t^4)
  2000. /**
  2001. * @param {number} k
  2002. * @return {number}
  2003. */
  2004. quarticIn: function (k) {
  2005. return k * k * k * k;
  2006. },
  2007. /**
  2008. * @param {number} k
  2009. * @return {number}
  2010. */
  2011. quarticOut: function (k) {
  2012. return 1 - (--k * k * k * k);
  2013. },
  2014. /**
  2015. * @param {number} k
  2016. * @return {number}
  2017. */
  2018. quarticInOut: function (k) {
  2019. if ((k *= 2) < 1) {
  2020. return 0.5 * k * k * k * k;
  2021. }
  2022. return -0.5 * ((k -= 2) * k * k * k - 2);
  2023. },
  2024. // 五次方的缓动(t^5)
  2025. /**
  2026. * @param {number} k
  2027. * @return {number}
  2028. */
  2029. quinticIn: function (k) {
  2030. return k * k * k * k * k;
  2031. },
  2032. /**
  2033. * @param {number} k
  2034. * @return {number}
  2035. */
  2036. quinticOut: function (k) {
  2037. return --k * k * k * k * k + 1;
  2038. },
  2039. /**
  2040. * @param {number} k
  2041. * @return {number}
  2042. */
  2043. quinticInOut: function (k) {
  2044. if ((k *= 2) < 1) {
  2045. return 0.5 * k * k * k * k * k;
  2046. }
  2047. return 0.5 * ((k -= 2) * k * k * k * k + 2);
  2048. },
  2049. // 正弦曲线的缓动(sin(t))
  2050. /**
  2051. * @param {number} k
  2052. * @return {number}
  2053. */
  2054. sinusoidalIn: function (k) {
  2055. return 1 - Math.cos(k * Math.PI / 2);
  2056. },
  2057. /**
  2058. * @param {number} k
  2059. * @return {number}
  2060. */
  2061. sinusoidalOut: function (k) {
  2062. return Math.sin(k * Math.PI / 2);
  2063. },
  2064. /**
  2065. * @param {number} k
  2066. * @return {number}
  2067. */
  2068. sinusoidalInOut: function (k) {
  2069. return 0.5 * (1 - Math.cos(Math.PI * k));
  2070. },
  2071. // 指数曲线的缓动(2^t)
  2072. /**
  2073. * @param {number} k
  2074. * @return {number}
  2075. */
  2076. exponentialIn: function (k) {
  2077. return k === 0 ? 0 : Math.pow(1024, k - 1);
  2078. },
  2079. /**
  2080. * @param {number} k
  2081. * @return {number}
  2082. */
  2083. exponentialOut: function (k) {
  2084. return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
  2085. },
  2086. /**
  2087. * @param {number} k
  2088. * @return {number}
  2089. */
  2090. exponentialInOut: function (k) {
  2091. if (k === 0) {
  2092. return 0;
  2093. }
  2094. if (k === 1) {
  2095. return 1;
  2096. }
  2097. if ((k *= 2) < 1) {
  2098. return 0.5 * Math.pow(1024, k - 1);
  2099. }
  2100. return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
  2101. },
  2102. // 圆形曲线的缓动(sqrt(1-t^2))
  2103. /**
  2104. * @param {number} k
  2105. * @return {number}
  2106. */
  2107. circularIn: function (k) {
  2108. return 1 - Math.sqrt(1 - k * k);
  2109. },
  2110. /**
  2111. * @param {number} k
  2112. * @return {number}
  2113. */
  2114. circularOut: function (k) {
  2115. return Math.sqrt(1 - (--k * k));
  2116. },
  2117. /**
  2118. * @param {number} k
  2119. * @return {number}
  2120. */
  2121. circularInOut: function (k) {
  2122. if ((k *= 2) < 1) {
  2123. return -0.5 * (Math.sqrt(1 - k * k) - 1);
  2124. }
  2125. return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
  2126. },
  2127. // 创建类似于弹簧在停止前来回振荡的动画
  2128. /**
  2129. * @param {number} k
  2130. * @return {number}
  2131. */
  2132. elasticIn: function (k) {
  2133. var s;
  2134. var a = 0.1;
  2135. var p = 0.4;
  2136. if (k === 0) {
  2137. return 0;
  2138. }
  2139. if (k === 1) {
  2140. return 1;
  2141. }
  2142. if (!a || a < 1) {
  2143. a = 1; s = p / 4;
  2144. }
  2145. else {
  2146. s = p * Math.asin(1 / a) / (2 * Math.PI);
  2147. }
  2148. return -(a * Math.pow(2, 10 * (k -= 1)) *
  2149. Math.sin((k - s) * (2 * Math.PI) / p));
  2150. },
  2151. /**
  2152. * @param {number} k
  2153. * @return {number}
  2154. */
  2155. elasticOut: function (k) {
  2156. var s;
  2157. var a = 0.1;
  2158. var p = 0.4;
  2159. if (k === 0) {
  2160. return 0;
  2161. }
  2162. if (k === 1) {
  2163. return 1;
  2164. }
  2165. if (!a || a < 1) {
  2166. a = 1; s = p / 4;
  2167. }
  2168. else {
  2169. s = p * Math.asin(1 / a) / (2 * Math.PI);
  2170. }
  2171. return (a * Math.pow(2, -10 * k) *
  2172. Math.sin((k - s) * (2 * Math.PI) / p) + 1);
  2173. },
  2174. /**
  2175. * @param {number} k
  2176. * @return {number}
  2177. */
  2178. elasticInOut: function (k) {
  2179. var s;
  2180. var a = 0.1;
  2181. var p = 0.4;
  2182. if (k === 0) {
  2183. return 0;
  2184. }
  2185. if (k === 1) {
  2186. return 1;
  2187. }
  2188. if (!a || a < 1) {
  2189. a = 1; s = p / 4;
  2190. }
  2191. else {
  2192. s = p * Math.asin(1 / a) / (2 * Math.PI);
  2193. }
  2194. if ((k *= 2) < 1) {
  2195. return -0.5 * (a * Math.pow(2, 10 * (k -= 1))
  2196. * Math.sin((k - s) * (2 * Math.PI) / p));
  2197. }
  2198. return a * Math.pow(2, -10 * (k -= 1))
  2199. * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
  2200. },
  2201. // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动
  2202. /**
  2203. * @param {number} k
  2204. * @return {number}
  2205. */
  2206. backIn: function (k) {
  2207. var s = 1.70158;
  2208. return k * k * ((s + 1) * k - s);
  2209. },
  2210. /**
  2211. * @param {number} k
  2212. * @return {number}
  2213. */
  2214. backOut: function (k) {
  2215. var s = 1.70158;
  2216. return --k * k * ((s + 1) * k + s) + 1;
  2217. },
  2218. /**
  2219. * @param {number} k
  2220. * @return {number}
  2221. */
  2222. backInOut: function (k) {
  2223. var s = 1.70158 * 1.525;
  2224. if ((k *= 2) < 1) {
  2225. return 0.5 * (k * k * ((s + 1) * k - s));
  2226. }
  2227. return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
  2228. },
  2229. // 创建弹跳效果
  2230. /**
  2231. * @param {number} k
  2232. * @return {number}
  2233. */
  2234. bounceIn: function (k) {
  2235. return 1 - easing.bounceOut(1 - k);
  2236. },
  2237. /**
  2238. * @param {number} k
  2239. * @return {number}
  2240. */
  2241. bounceOut: function (k) {
  2242. if (k < (1 / 2.75)) {
  2243. return 7.5625 * k * k;
  2244. }
  2245. else if (k < (2 / 2.75)) {
  2246. return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
  2247. }
  2248. else if (k < (2.5 / 2.75)) {
  2249. return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
  2250. }
  2251. else {
  2252. return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
  2253. }
  2254. },
  2255. /**
  2256. * @param {number} k
  2257. * @return {number}
  2258. */
  2259. bounceInOut: function (k) {
  2260. if (k < 0.5) {
  2261. return easing.bounceIn(k * 2) * 0.5;
  2262. }
  2263. return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
  2264. }
  2265. };
  2266. /**
  2267. * 动画主控制器
  2268. * @config target 动画对象,可以是数组,如果是数组的话会批量分发onframe等事件
  2269. * @config life(1000) 动画时长
  2270. * @config delay(0) 动画延迟时间
  2271. * @config loop(true)
  2272. * @config gap(0) 循环的间隔时间
  2273. * @config onframe
  2274. * @config easing(optional)
  2275. * @config ondestroy(optional)
  2276. * @config onrestart(optional)
  2277. *
  2278. * TODO pause
  2279. */
  2280. function Clip(options) {
  2281. this._target = options.target;
  2282. // 生命周期
  2283. this._life = options.life || 1000;
  2284. // 延时
  2285. this._delay = options.delay || 0;
  2286. // 开始时间
  2287. // this._startTime = new Date().getTime() + this._delay;// 单位毫秒
  2288. this._initialized = false;
  2289. // 是否循环
  2290. this.loop = options.loop == null ? false : options.loop;
  2291. this.gap = options.gap || 0;
  2292. this.easing = options.easing || 'Linear';
  2293. this.onframe = options.onframe;
  2294. this.ondestroy = options.ondestroy;
  2295. this.onrestart = options.onrestart;
  2296. this._pausedTime = 0;
  2297. this._paused = false;
  2298. }
  2299. Clip.prototype = {
  2300. constructor: Clip,
  2301. step: function (globalTime, deltaTime) {
  2302. // Set startTime on first step, or _startTime may has milleseconds different between clips
  2303. // PENDING
  2304. if (!this._initialized) {
  2305. this._startTime = globalTime + this._delay;
  2306. this._initialized = true;
  2307. }
  2308. if (this._paused) {
  2309. this._pausedTime += deltaTime;
  2310. return;
  2311. }
  2312. var percent = (globalTime - this._startTime - this._pausedTime) / this._life;
  2313. // 还没开始
  2314. if (percent < 0) {
  2315. return;
  2316. }
  2317. percent = Math.min(percent, 1);
  2318. var easing$$1 = this.easing;
  2319. var easingFunc = typeof easing$$1 == 'string' ? easing[easing$$1] : easing$$1;
  2320. var schedule = typeof easingFunc === 'function'
  2321. ? easingFunc(percent)
  2322. : percent;
  2323. this.fire('frame', schedule);
  2324. // 结束
  2325. if (percent == 1) {
  2326. if (this.loop) {
  2327. this.restart (globalTime);
  2328. // 重新开始周期
  2329. // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件
  2330. return 'restart';
  2331. }
  2332. // 动画完成将这个控制器标识为待删除
  2333. // 在Animation.update中进行批量删除
  2334. this._needsRemove = true;
  2335. return 'destroy';
  2336. }
  2337. return null;
  2338. },
  2339. restart: function (globalTime) {
  2340. var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
  2341. this._startTime = globalTime - remainder + this.gap;
  2342. this._pausedTime = 0;
  2343. this._needsRemove = false;
  2344. },
  2345. fire: function (eventType, arg) {
  2346. eventType = 'on' + eventType;
  2347. if (this[eventType]) {
  2348. this[eventType](this._target, arg);
  2349. }
  2350. },
  2351. pause: function () {
  2352. this._paused = true;
  2353. },
  2354. resume: function () {
  2355. this._paused = false;
  2356. }
  2357. };
  2358. // Simple LRU cache use doubly linked list
  2359. // @module zrender/core/LRU
  2360. /**
  2361. * Simple double linked list. Compared with array, it has O(1) remove operation.
  2362. * @constructor
  2363. */
  2364. var LinkedList = function () {
  2365. /**
  2366. * @type {module:zrender/core/LRU~Entry}
  2367. */
  2368. this.head = null;
  2369. /**
  2370. * @type {module:zrender/core/LRU~Entry}
  2371. */
  2372. this.tail = null;
  2373. this._len = 0;
  2374. };
  2375. var linkedListProto = LinkedList.prototype;
  2376. /**
  2377. * Insert a new value at the tail
  2378. * @param {} val
  2379. * @return {module:zrender/core/LRU~Entry}
  2380. */
  2381. linkedListProto.insert = function (val) {
  2382. var entry = new Entry(val);
  2383. this.insertEntry(entry);
  2384. return entry;
  2385. };
  2386. /**
  2387. * Insert an entry at the tail
  2388. * @param {module:zrender/core/LRU~Entry} entry
  2389. */
  2390. linkedListProto.insertEntry = function (entry) {
  2391. if (!this.head) {
  2392. this.head = this.tail = entry;
  2393. }
  2394. else {
  2395. this.tail.next = entry;
  2396. entry.prev = this.tail;
  2397. entry.next = null;
  2398. this.tail = entry;
  2399. }
  2400. this._len++;
  2401. };
  2402. /**
  2403. * Remove entry.
  2404. * @param {module:zrender/core/LRU~Entry} entry
  2405. */
  2406. linkedListProto.remove = function (entry) {
  2407. var prev = entry.prev;
  2408. var next = entry.next;
  2409. if (prev) {
  2410. prev.next = next;
  2411. }
  2412. else {
  2413. // Is head
  2414. this.head = next;
  2415. }
  2416. if (next) {
  2417. next.prev = prev;
  2418. }
  2419. else {
  2420. // Is tail
  2421. this.tail = prev;
  2422. }
  2423. entry.next = entry.prev = null;
  2424. this._len--;
  2425. };
  2426. /**
  2427. * @return {number}
  2428. */
  2429. linkedListProto.len = function () {
  2430. return this._len;
  2431. };
  2432. /**
  2433. * Clear list
  2434. */
  2435. linkedListProto.clear = function () {
  2436. this.head = this.tail = null;
  2437. this._len = 0;
  2438. };
  2439. /**
  2440. * @constructor
  2441. * @param {} val
  2442. */
  2443. var Entry = function (val) {
  2444. /**
  2445. * @type {}
  2446. */
  2447. this.value = val;
  2448. /**
  2449. * @type {module:zrender/core/LRU~Entry}
  2450. */
  2451. this.next;
  2452. /**
  2453. * @type {module:zrender/core/LRU~Entry}
  2454. */
  2455. this.prev;
  2456. };
  2457. /**
  2458. * LRU Cache
  2459. * @constructor
  2460. * @alias module:zrender/core/LRU
  2461. */
  2462. var LRU = function (maxSize) {
  2463. this._list = new LinkedList();
  2464. this._map = {};
  2465. this._maxSize = maxSize || 10;
  2466. this._lastRemovedEntry = null;
  2467. };
  2468. var LRUProto = LRU.prototype;
  2469. /**
  2470. * @param {string} key
  2471. * @param {} value
  2472. * @return {} Removed value
  2473. */
  2474. LRUProto.put = function (key, value) {
  2475. var list = this._list;
  2476. var map = this._map;
  2477. var removed = null;
  2478. if (map[key] == null) {
  2479. var len = list.len();
  2480. // Reuse last removed entry
  2481. var entry = this._lastRemovedEntry;
  2482. if (len >= this._maxSize && len > 0) {
  2483. // Remove the least recently used
  2484. var leastUsedEntry = list.head;
  2485. list.remove(leastUsedEntry);
  2486. delete map[leastUsedEntry.key];
  2487. removed = leastUsedEntry.value;
  2488. this._lastRemovedEntry = leastUsedEntry;
  2489. }
  2490. if (entry) {
  2491. entry.value = value;
  2492. }
  2493. else {
  2494. entry = new Entry(value);
  2495. }
  2496. entry.key = key;
  2497. list.insertEntry(entry);
  2498. map[key] = entry;
  2499. }
  2500. return removed;
  2501. };
  2502. /**
  2503. * @param {string} key
  2504. * @return {}
  2505. */
  2506. LRUProto.get = function (key) {
  2507. var entry = this._map[key];
  2508. var list = this._list;
  2509. if (entry != null) {
  2510. // Put the latest used entry in the tail
  2511. if (entry !== list.tail) {
  2512. list.remove(entry);
  2513. list.insertEntry(entry);
  2514. }
  2515. return entry.value;
  2516. }
  2517. };
  2518. /**
  2519. * Clear the cache
  2520. */
  2521. LRUProto.clear = function () {
  2522. this._list.clear();
  2523. this._map = {};
  2524. };
  2525. var kCSSColorTable = {
  2526. 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1],
  2527. 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1],
  2528. 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1],
  2529. 'beige': [245,245,220,1], 'bisque': [255,228,196,1],
  2530. 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1],
  2531. 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1],
  2532. 'brown': [165,42,42,1], 'burlywood': [222,184,135,1],
  2533. 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1],
  2534. 'chocolate': [210,105,30,1], 'coral': [255,127,80,1],
  2535. 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1],
  2536. 'crimson': [220,20,60,1], 'cyan': [0,255,255,1],
  2537. 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1],
  2538. 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1],
  2539. 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1],
  2540. 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1],
  2541. 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1],
  2542. 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1],
  2543. 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1],
  2544. 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1],
  2545. 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1],
  2546. 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1],
  2547. 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1],
  2548. 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1],
  2549. 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1],
  2550. 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1],
  2551. 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1],
  2552. 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1],
  2553. 'gray': [128,128,128,1], 'green': [0,128,0,1],
  2554. 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1],
  2555. 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1],
  2556. 'indianred': [205,92,92,1], 'indigo': [75,0,130,1],
  2557. 'ivory': [255,255,240,1], 'khaki': [240,230,140,1],
  2558. 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1],
  2559. 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1],
  2560. 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1],
  2561. 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1],
  2562. 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1],
  2563. 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1],
  2564. 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1],
  2565. 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1],
  2566. 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1],
  2567. 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1],
  2568. 'limegreen': [50,205,50,1], 'linen': [250,240,230,1],
  2569. 'magenta': [255,0,255,1], 'maroon': [128,0,0,1],
  2570. 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1],
  2571. 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1],
  2572. 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1],
  2573. 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1],
  2574. 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1],
  2575. 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1],
  2576. 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1],
  2577. 'navy': [0,0,128,1], 'oldlace': [253,245,230,1],
  2578. 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1],
  2579. 'orange': [255,165,0,1], 'orangered': [255,69,0,1],
  2580. 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1],
  2581. 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1],
  2582. 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1],
  2583. 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1],
  2584. 'pink': [255,192,203,1], 'plum': [221,160,221,1],
  2585. 'powderblue': [176,224,230,1], 'purple': [128,0,128,1],
  2586. 'red': [255,0,0,1], 'rosybrown': [188,143,143,1],
  2587. 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1],
  2588. 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1],
  2589. 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1],
  2590. 'sienna': [160,82,45,1], 'silver': [192,192,192,1],
  2591. 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1],
  2592. 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1],
  2593. 'snow': [255,250,250,1], 'springgreen': [0,255,127,1],
  2594. 'steelblue': [70,130,180,1], 'tan': [210,180,140,1],
  2595. 'teal': [0,128,128,1], 'thistle': [216,191,216,1],
  2596. 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1],
  2597. 'violet': [238,130,238,1], 'wheat': [245,222,179,1],
  2598. 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1],
  2599. 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1]
  2600. };
  2601. function clampCssByte(i) { // Clamp to integer 0 .. 255.
  2602. i = Math.round(i); // Seems to be what Chrome does (vs truncation).
  2603. return i < 0 ? 0 : i > 255 ? 255 : i;
  2604. }
  2605. function clampCssAngle(i) { // Clamp to integer 0 .. 360.
  2606. i = Math.round(i); // Seems to be what Chrome does (vs truncation).
  2607. return i < 0 ? 0 : i > 360 ? 360 : i;
  2608. }
  2609. function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0.
  2610. return f < 0 ? 0 : f > 1 ? 1 : f;
  2611. }
  2612. function parseCssInt(str) { // int or percentage.
  2613. if (str.length && str.charAt(str.length - 1) === '%') {
  2614. return clampCssByte(parseFloat(str) / 100 * 255);
  2615. }
  2616. return clampCssByte(parseInt(str, 10));
  2617. }
  2618. function parseCssFloat(str) { // float or percentage.
  2619. if (str.length && str.charAt(str.length - 1) === '%') {
  2620. return clampCssFloat(parseFloat(str) / 100);
  2621. }
  2622. return clampCssFloat(parseFloat(str));
  2623. }
  2624. function cssHueToRgb(m1, m2, h) {
  2625. if (h < 0) {
  2626. h += 1;
  2627. }
  2628. else if (h > 1) {
  2629. h -= 1;
  2630. }
  2631. if (h * 6 < 1) {
  2632. return m1 + (m2 - m1) * h * 6;
  2633. }
  2634. if (h * 2 < 1) {
  2635. return m2;
  2636. }
  2637. if (h * 3 < 2) {
  2638. return m1 + (m2 - m1) * (2/3 - h) * 6;
  2639. }
  2640. return m1;
  2641. }
  2642. function lerpNumber(a, b, p) {
  2643. return a + (b - a) * p;
  2644. }
  2645. function setRgba(out, r, g, b, a) {
  2646. out[0] = r; out[1] = g; out[2] = b; out[3] = a;
  2647. return out;
  2648. }
  2649. function copyRgba(out, a) {
  2650. out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];
  2651. return out;
  2652. }
  2653. var colorCache = new LRU(20);
  2654. var lastRemovedArr = null;
  2655. function putToCache(colorStr, rgbaArr) {
  2656. // Reuse removed array
  2657. if (lastRemovedArr) {
  2658. copyRgba(lastRemovedArr, rgbaArr);
  2659. }
  2660. lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));
  2661. }
  2662. /**
  2663. * @param {string} colorStr
  2664. * @param {Array.<number>} out
  2665. * @return {Array.<number>}
  2666. * @memberOf module:zrender/util/color
  2667. */
  2668. function parse(colorStr, rgbaArr) {
  2669. if (!colorStr) {
  2670. return;
  2671. }
  2672. rgbaArr = rgbaArr || [];
  2673. var cached = colorCache.get(colorStr);
  2674. if (cached) {
  2675. return copyRgba(rgbaArr, cached);
  2676. }
  2677. // colorStr may be not string
  2678. colorStr = colorStr + '';
  2679. // Remove all whitespace, not compliant, but should just be more accepting.
  2680. var str = colorStr.replace(/ /g, '').toLowerCase();
  2681. // Color keywords (and transparent) lookup.
  2682. if (str in kCSSColorTable) {
  2683. copyRgba(rgbaArr, kCSSColorTable[str]);
  2684. putToCache(colorStr, rgbaArr);
  2685. return rgbaArr;
  2686. }
  2687. // #abc and #abc123 syntax.
  2688. if (str.charAt(0) === '#') {
  2689. if (str.length === 4) {
  2690. var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
  2691. if (!(iv >= 0 && iv <= 0xfff)) {
  2692. setRgba(rgbaArr, 0, 0, 0, 1);
  2693. return; // Covers NaN.
  2694. }
  2695. setRgba(rgbaArr,
  2696. ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
  2697. (iv & 0xf0) | ((iv & 0xf0) >> 4),
  2698. (iv & 0xf) | ((iv & 0xf) << 4),
  2699. 1
  2700. );
  2701. putToCache(colorStr, rgbaArr);
  2702. return rgbaArr;
  2703. }
  2704. else if (str.length === 7) {
  2705. var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
  2706. if (!(iv >= 0 && iv <= 0xffffff)) {
  2707. setRgba(rgbaArr, 0, 0, 0, 1);
  2708. return; // Covers NaN.
  2709. }
  2710. setRgba(rgbaArr,
  2711. (iv & 0xff0000) >> 16,
  2712. (iv & 0xff00) >> 8,
  2713. iv & 0xff,
  2714. 1
  2715. );
  2716. putToCache(colorStr, rgbaArr);
  2717. return rgbaArr;
  2718. }
  2719. return;
  2720. }
  2721. var op = str.indexOf('('), ep = str.indexOf(')');
  2722. if (op !== -1 && ep + 1 === str.length) {
  2723. var fname = str.substr(0, op);
  2724. var params = str.substr(op + 1, ep - (op + 1)).split(',');
  2725. var alpha = 1; // To allow case fallthrough.
  2726. switch (fname) {
  2727. case 'rgba':
  2728. if (params.length !== 4) {
  2729. setRgba(rgbaArr, 0, 0, 0, 1);
  2730. return;
  2731. }
  2732. alpha = parseCssFloat(params.pop()); // jshint ignore:line
  2733. // Fall through.
  2734. case 'rgb':
  2735. if (params.length !== 3) {
  2736. setRgba(rgbaArr, 0, 0, 0, 1);
  2737. return;
  2738. }
  2739. setRgba(rgbaArr,
  2740. parseCssInt(params[0]),
  2741. parseCssInt(params[1]),
  2742. parseCssInt(params[2]),
  2743. alpha
  2744. );
  2745. putToCache(colorStr, rgbaArr);
  2746. return rgbaArr;
  2747. case 'hsla':
  2748. if (params.length !== 4) {
  2749. setRgba(rgbaArr, 0, 0, 0, 1);
  2750. return;
  2751. }
  2752. params[3] = parseCssFloat(params[3]);
  2753. hsla2rgba(params, rgbaArr);
  2754. putToCache(colorStr, rgbaArr);
  2755. return rgbaArr;
  2756. case 'hsl':
  2757. if (params.length !== 3) {
  2758. setRgba(rgbaArr, 0, 0, 0, 1);
  2759. return;
  2760. }
  2761. hsla2rgba(params, rgbaArr);
  2762. putToCache(colorStr, rgbaArr);
  2763. return rgbaArr;
  2764. default:
  2765. return;
  2766. }
  2767. }
  2768. setRgba(rgbaArr, 0, 0, 0, 1);
  2769. return;
  2770. }
  2771. /**
  2772. * @param {Array.<number>} hsla
  2773. * @param {Array.<number>} rgba
  2774. * @return {Array.<number>} rgba
  2775. */
  2776. function hsla2rgba(hsla, rgba) {
  2777. var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1
  2778. // NOTE(deanm): According to the CSS spec s/l should only be
  2779. // percentages, but we don't bother and let float or percentage.
  2780. var s = parseCssFloat(hsla[1]);
  2781. var l = parseCssFloat(hsla[2]);
  2782. var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
  2783. var m1 = l * 2 - m2;
  2784. rgba = rgba || [];
  2785. setRgba(rgba,
  2786. clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),
  2787. clampCssByte(cssHueToRgb(m1, m2, h) * 255),
  2788. clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),
  2789. 1
  2790. );
  2791. if (hsla.length === 4) {
  2792. rgba[3] = hsla[3];
  2793. }
  2794. return rgba;
  2795. }
  2796. /**
  2797. * @param {Array.<number>} rgba
  2798. * @return {Array.<number>} hsla
  2799. */
  2800. function rgba2hsla(rgba) {
  2801. if (!rgba) {
  2802. return;
  2803. }
  2804. // RGB from 0 to 255
  2805. var R = rgba[0] / 255;
  2806. var G = rgba[1] / 255;
  2807. var B = rgba[2] / 255;
  2808. var vMin = Math.min(R, G, B); // Min. value of RGB
  2809. var vMax = Math.max(R, G, B); // Max. value of RGB
  2810. var delta = vMax - vMin; // Delta RGB value
  2811. var L = (vMax + vMin) / 2;
  2812. var H;
  2813. var S;
  2814. // HSL results from 0 to 1
  2815. if (delta === 0) {
  2816. H = 0;
  2817. S = 0;
  2818. }
  2819. else {
  2820. if (L < 0.5) {
  2821. S = delta / (vMax + vMin);
  2822. }
  2823. else {
  2824. S = delta / (2 - vMax - vMin);
  2825. }
  2826. var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
  2827. var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
  2828. var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
  2829. if (R === vMax) {
  2830. H = deltaB - deltaG;
  2831. }
  2832. else if (G === vMax) {
  2833. H = (1 / 3) + deltaR - deltaB;
  2834. }
  2835. else if (B === vMax) {
  2836. H = (2 / 3) + deltaG - deltaR;
  2837. }
  2838. if (H < 0) {
  2839. H += 1;
  2840. }
  2841. if (H > 1) {
  2842. H -= 1;
  2843. }
  2844. }
  2845. var hsla = [H * 360, S, L];
  2846. if (rgba[3] != null) {
  2847. hsla.push(rgba[3]);
  2848. }
  2849. return hsla;
  2850. }
  2851. /**
  2852. * @param {string} color
  2853. * @param {number} level
  2854. * @return {string}
  2855. * @memberOf module:zrender/util/color
  2856. */
  2857. function lift(color, level) {
  2858. var colorArr = parse(color);
  2859. if (colorArr) {
  2860. for (var i = 0; i < 3; i++) {
  2861. if (level < 0) {
  2862. colorArr[i] = colorArr[i] * (1 - level) | 0;
  2863. }
  2864. else {
  2865. colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
  2866. }
  2867. }
  2868. return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
  2869. }
  2870. }
  2871. /**
  2872. * @param {string} color
  2873. * @return {string}
  2874. * @memberOf module:zrender/util/color
  2875. */
  2876. function toHex(color) {
  2877. var colorArr = parse(color);
  2878. if (colorArr) {
  2879. return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
  2880. }
  2881. }
  2882. /**
  2883. * Map value to color. Faster than lerp methods because color is represented by rgba array.
  2884. * @param {number} normalizedValue A float between 0 and 1.
  2885. * @param {Array.<Array.<number>>} colors List of rgba color array
  2886. * @param {Array.<number>} [out] Mapped gba color array
  2887. * @return {Array.<number>} will be null/undefined if input illegal.
  2888. */
  2889. function fastLerp(normalizedValue, colors, out) {
  2890. if (!(colors && colors.length)
  2891. || !(normalizedValue >= 0 && normalizedValue <= 1)
  2892. ) {
  2893. return;
  2894. }
  2895. out = out || [];
  2896. var value = normalizedValue * (colors.length - 1);
  2897. var leftIndex = Math.floor(value);
  2898. var rightIndex = Math.ceil(value);
  2899. var leftColor = colors[leftIndex];
  2900. var rightColor = colors[rightIndex];
  2901. var dv = value - leftIndex;
  2902. out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));
  2903. out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));
  2904. out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));
  2905. out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));
  2906. return out;
  2907. }
  2908. /**
  2909. * @deprecated
  2910. */
  2911. var fastMapToColor = fastLerp;
  2912. /**
  2913. * @param {number} normalizedValue A float between 0 and 1.
  2914. * @param {Array.<string>} colors Color list.
  2915. * @param {boolean=} fullOutput Default false.
  2916. * @return {(string|Object)} Result color. If fullOutput,
  2917. * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},
  2918. * @memberOf module:zrender/util/color
  2919. */
  2920. function lerp$1(normalizedValue, colors, fullOutput) {
  2921. if (!(colors && colors.length)
  2922. || !(normalizedValue >= 0 && normalizedValue <= 1)
  2923. ) {
  2924. return;
  2925. }
  2926. var value = normalizedValue * (colors.length - 1);
  2927. var leftIndex = Math.floor(value);
  2928. var rightIndex = Math.ceil(value);
  2929. var leftColor = parse(colors[leftIndex]);
  2930. var rightColor = parse(colors[rightIndex]);
  2931. var dv = value - leftIndex;
  2932. var color = stringify(
  2933. [
  2934. clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),
  2935. clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),
  2936. clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),
  2937. clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))
  2938. ],
  2939. 'rgba'
  2940. );
  2941. return fullOutput
  2942. ? {
  2943. color: color,
  2944. leftIndex: leftIndex,
  2945. rightIndex: rightIndex,
  2946. value: value
  2947. }
  2948. : color;
  2949. }
  2950. /**
  2951. * @deprecated
  2952. */
  2953. var mapToColor = lerp$1;
  2954. /**
  2955. * @param {string} color
  2956. * @param {number=} h 0 ~ 360, ignore when null.
  2957. * @param {number=} s 0 ~ 1, ignore when null.
  2958. * @param {number=} l 0 ~ 1, ignore when null.
  2959. * @return {string} Color string in rgba format.
  2960. * @memberOf module:zrender/util/color
  2961. */
  2962. function modifyHSL(color, h, s, l) {
  2963. color = parse(color);
  2964. if (color) {
  2965. color = rgba2hsla(color);
  2966. h != null && (color[0] = clampCssAngle(h));
  2967. s != null && (color[1] = parseCssFloat(s));
  2968. l != null && (color[2] = parseCssFloat(l));
  2969. return stringify(hsla2rgba(color), 'rgba');
  2970. }
  2971. }
  2972. /**
  2973. * @param {string} color
  2974. * @param {number=} alpha 0 ~ 1
  2975. * @return {string} Color string in rgba format.
  2976. * @memberOf module:zrender/util/color
  2977. */
  2978. function modifyAlpha(color, alpha) {
  2979. color = parse(color);
  2980. if (color && alpha != null) {
  2981. color[3] = clampCssFloat(alpha);
  2982. return stringify(color, 'rgba');
  2983. }
  2984. }
  2985. /**
  2986. * @param {Array.<number>} arrColor like [12,33,44,0.4]
  2987. * @param {string} type 'rgba', 'hsva', ...
  2988. * @return {string} Result color. (If input illegal, return undefined).
  2989. */
  2990. function stringify(arrColor, type) {
  2991. if (!arrColor || !arrColor.length) {
  2992. return;
  2993. }
  2994. var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
  2995. if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
  2996. colorStr += ',' + arrColor[3];
  2997. }
  2998. return type + '(' + colorStr + ')';
  2999. }
  3000. var color = (Object.freeze || Object)({
  3001. parse: parse,
  3002. lift: lift,
  3003. toHex: toHex,
  3004. fastLerp: fastLerp,
  3005. fastMapToColor: fastMapToColor,
  3006. lerp: lerp$1,
  3007. mapToColor: mapToColor,
  3008. modifyHSL: modifyHSL,
  3009. modifyAlpha: modifyAlpha,
  3010. stringify: stringify
  3011. });
  3012. /**
  3013. * @module echarts/animation/Animator
  3014. */
  3015. var arraySlice = Array.prototype.slice;
  3016. function defaultGetter(target, key) {
  3017. return target[key];
  3018. }
  3019. function defaultSetter(target, key, value) {
  3020. target[key] = value;
  3021. }
  3022. /**
  3023. * @param {number} p0
  3024. * @param {number} p1
  3025. * @param {number} percent
  3026. * @return {number}
  3027. */
  3028. function interpolateNumber(p0, p1, percent) {
  3029. return (p1 - p0) * percent + p0;
  3030. }
  3031. /**
  3032. * @param {string} p0
  3033. * @param {string} p1
  3034. * @param {number} percent
  3035. * @return {string}
  3036. */
  3037. function interpolateString(p0, p1, percent) {
  3038. return percent > 0.5 ? p1 : p0;
  3039. }
  3040. /**
  3041. * @param {Array} p0
  3042. * @param {Array} p1
  3043. * @param {number} percent
  3044. * @param {Array} out
  3045. * @param {number} arrDim
  3046. */
  3047. function interpolateArray(p0, p1, percent, out, arrDim) {
  3048. var len = p0.length;
  3049. if (arrDim == 1) {
  3050. for (var i = 0; i < len; i++) {
  3051. out[i] = interpolateNumber(p0[i], p1[i], percent);
  3052. }
  3053. }
  3054. else {
  3055. var len2 = len && p0[0].length;
  3056. for (var i = 0; i < len; i++) {
  3057. for (var j = 0; j < len2; j++) {
  3058. out[i][j] = interpolateNumber(
  3059. p0[i][j], p1[i][j], percent
  3060. );
  3061. }
  3062. }
  3063. }
  3064. }
  3065. // arr0 is source array, arr1 is target array.
  3066. // Do some preprocess to avoid error happened when interpolating from arr0 to arr1
  3067. function fillArr(arr0, arr1, arrDim) {
  3068. var arr0Len = arr0.length;
  3069. var arr1Len = arr1.length;
  3070. if (arr0Len !== arr1Len) {
  3071. // FIXME Not work for TypedArray
  3072. var isPreviousLarger = arr0Len > arr1Len;
  3073. if (isPreviousLarger) {
  3074. // Cut the previous
  3075. arr0.length = arr1Len;
  3076. }
  3077. else {
  3078. // Fill the previous
  3079. for (var i = arr0Len; i < arr1Len; i++) {
  3080. arr0.push(
  3081. arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])
  3082. );
  3083. }
  3084. }
  3085. }
  3086. // Handling NaN value
  3087. var len2 = arr0[0] && arr0[0].length;
  3088. for (var i = 0; i < arr0.length; i++) {
  3089. if (arrDim === 1) {
  3090. if (isNaN(arr0[i])) {
  3091. arr0[i] = arr1[i];
  3092. }
  3093. }
  3094. else {
  3095. for (var j = 0; j < len2; j++) {
  3096. if (isNaN(arr0[i][j])) {
  3097. arr0[i][j] = arr1[i][j];
  3098. }
  3099. }
  3100. }
  3101. }
  3102. }
  3103. /**
  3104. * @param {Array} arr0
  3105. * @param {Array} arr1
  3106. * @param {number} arrDim
  3107. * @return {boolean}
  3108. */
  3109. function isArraySame(arr0, arr1, arrDim) {
  3110. if (arr0 === arr1) {
  3111. return true;
  3112. }
  3113. var len = arr0.length;
  3114. if (len !== arr1.length) {
  3115. return false;
  3116. }
  3117. if (arrDim === 1) {
  3118. for (var i = 0; i < len; i++) {
  3119. if (arr0[i] !== arr1[i]) {
  3120. return false;
  3121. }
  3122. }
  3123. }
  3124. else {
  3125. var len2 = arr0[0].length;
  3126. for (var i = 0; i < len; i++) {
  3127. for (var j = 0; j < len2; j++) {
  3128. if (arr0[i][j] !== arr1[i][j]) {
  3129. return false;
  3130. }
  3131. }
  3132. }
  3133. }
  3134. return true;
  3135. }
  3136. /**
  3137. * Catmull Rom interpolate array
  3138. * @param {Array} p0
  3139. * @param {Array} p1
  3140. * @param {Array} p2
  3141. * @param {Array} p3
  3142. * @param {number} t
  3143. * @param {number} t2
  3144. * @param {number} t3
  3145. * @param {Array} out
  3146. * @param {number} arrDim
  3147. */
  3148. function catmullRomInterpolateArray(
  3149. p0, p1, p2, p3, t, t2, t3, out, arrDim
  3150. ) {
  3151. var len = p0.length;
  3152. if (arrDim == 1) {
  3153. for (var i = 0; i < len; i++) {
  3154. out[i] = catmullRomInterpolate(
  3155. p0[i], p1[i], p2[i], p3[i], t, t2, t3
  3156. );
  3157. }
  3158. }
  3159. else {
  3160. var len2 = p0[0].length;
  3161. for (var i = 0; i < len; i++) {
  3162. for (var j = 0; j < len2; j++) {
  3163. out[i][j] = catmullRomInterpolate(
  3164. p0[i][j], p1[i][j], p2[i][j], p3[i][j],
  3165. t, t2, t3
  3166. );
  3167. }
  3168. }
  3169. }
  3170. }
  3171. /**
  3172. * Catmull Rom interpolate number
  3173. * @param {number} p0
  3174. * @param {number} p1
  3175. * @param {number} p2
  3176. * @param {number} p3
  3177. * @param {number} t
  3178. * @param {number} t2
  3179. * @param {number} t3
  3180. * @return {number}
  3181. */
  3182. function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
  3183. var v0 = (p2 - p0) * 0.5;
  3184. var v1 = (p3 - p1) * 0.5;
  3185. return (2 * (p1 - p2) + v0 + v1) * t3
  3186. + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
  3187. + v0 * t + p1;
  3188. }
  3189. function cloneValue(value) {
  3190. if (isArrayLike(value)) {
  3191. var len = value.length;
  3192. if (isArrayLike(value[0])) {
  3193. var ret = [];
  3194. for (var i = 0; i < len; i++) {
  3195. ret.push(arraySlice.call(value[i]));
  3196. }
  3197. return ret;
  3198. }
  3199. return arraySlice.call(value);
  3200. }
  3201. return value;
  3202. }
  3203. function rgba2String(rgba) {
  3204. rgba[0] = Math.floor(rgba[0]);
  3205. rgba[1] = Math.floor(rgba[1]);
  3206. rgba[2] = Math.floor(rgba[2]);
  3207. return 'rgba(' + rgba.join(',') + ')';
  3208. }
  3209. function getArrayDim(keyframes) {
  3210. var lastValue = keyframes[keyframes.length - 1].value;
  3211. return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;
  3212. }
  3213. function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {
  3214. var getter = animator._getter;
  3215. var setter = animator._setter;
  3216. var useSpline = easing === 'spline';
  3217. var trackLen = keyframes.length;
  3218. if (!trackLen) {
  3219. return;
  3220. }
  3221. // Guess data type
  3222. var firstVal = keyframes[0].value;
  3223. var isValueArray = isArrayLike(firstVal);
  3224. var isValueColor = false;
  3225. var isValueString = false;
  3226. // For vertices morphing
  3227. var arrDim = isValueArray ? getArrayDim(keyframes) : 0;
  3228. var trackMaxTime;
  3229. // Sort keyframe as ascending
  3230. keyframes.sort(function(a, b) {
  3231. return a.time - b.time;
  3232. });
  3233. trackMaxTime = keyframes[trackLen - 1].time;
  3234. // Percents of each keyframe
  3235. var kfPercents = [];
  3236. // Value of each keyframe
  3237. var kfValues = [];
  3238. var prevValue = keyframes[0].value;
  3239. var isAllValueEqual = true;
  3240. for (var i = 0; i < trackLen; i++) {
  3241. kfPercents.push(keyframes[i].time / trackMaxTime);
  3242. // Assume value is a color when it is a string
  3243. var value = keyframes[i].value;
  3244. // Check if value is equal, deep check if value is array
  3245. if (!((isValueArray && isArraySame(value, prevValue, arrDim))
  3246. || (!isValueArray && value === prevValue))) {
  3247. isAllValueEqual = false;
  3248. }
  3249. prevValue = value;
  3250. // Try converting a string to a color array
  3251. if (typeof value == 'string') {
  3252. var colorArray = parse(value);
  3253. if (colorArray) {
  3254. value = colorArray;
  3255. isValueColor = true;
  3256. }
  3257. else {
  3258. isValueString = true;
  3259. }
  3260. }
  3261. kfValues.push(value);
  3262. }
  3263. if (!forceAnimate && isAllValueEqual) {
  3264. return;
  3265. }
  3266. var lastValue = kfValues[trackLen - 1];
  3267. // Polyfill array and NaN value
  3268. for (var i = 0; i < trackLen - 1; i++) {
  3269. if (isValueArray) {
  3270. fillArr(kfValues[i], lastValue, arrDim);
  3271. }
  3272. else {
  3273. if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {
  3274. kfValues[i] = lastValue;
  3275. }
  3276. }
  3277. }
  3278. isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);
  3279. // Cache the key of last frame to speed up when
  3280. // animation playback is sequency
  3281. var lastFrame = 0;
  3282. var lastFramePercent = 0;
  3283. var start;
  3284. var w;
  3285. var p0;
  3286. var p1;
  3287. var p2;
  3288. var p3;
  3289. if (isValueColor) {
  3290. var rgba = [0, 0, 0, 0];
  3291. }
  3292. var onframe = function (target, percent) {
  3293. // Find the range keyframes
  3294. // kf1-----kf2---------current--------kf3
  3295. // find kf2 and kf3 and do interpolation
  3296. var frame;
  3297. // In the easing function like elasticOut, percent may less than 0
  3298. if (percent < 0) {
  3299. frame = 0;
  3300. }
  3301. else if (percent < lastFramePercent) {
  3302. // Start from next key
  3303. // PENDING start from lastFrame ?
  3304. start = Math.min(lastFrame + 1, trackLen - 1);
  3305. for (frame = start; frame >= 0; frame--) {
  3306. if (kfPercents[frame] <= percent) {
  3307. break;
  3308. }
  3309. }
  3310. // PENDING really need to do this ?
  3311. frame = Math.min(frame, trackLen - 2);
  3312. }
  3313. else {
  3314. for (frame = lastFrame; frame < trackLen; frame++) {
  3315. if (kfPercents[frame] > percent) {
  3316. break;
  3317. }
  3318. }
  3319. frame = Math.min(frame - 1, trackLen - 2);
  3320. }
  3321. lastFrame = frame;
  3322. lastFramePercent = percent;
  3323. var range = (kfPercents[frame + 1] - kfPercents[frame]);
  3324. if (range === 0) {
  3325. return;
  3326. }
  3327. else {
  3328. w = (percent - kfPercents[frame]) / range;
  3329. }
  3330. if (useSpline) {
  3331. p1 = kfValues[frame];
  3332. p0 = kfValues[frame === 0 ? frame : frame - 1];
  3333. p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];
  3334. p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];
  3335. if (isValueArray) {
  3336. catmullRomInterpolateArray(
  3337. p0, p1, p2, p3, w, w * w, w * w * w,
  3338. getter(target, propName),
  3339. arrDim
  3340. );
  3341. }
  3342. else {
  3343. var value;
  3344. if (isValueColor) {
  3345. value = catmullRomInterpolateArray(
  3346. p0, p1, p2, p3, w, w * w, w * w * w,
  3347. rgba, 1
  3348. );
  3349. value = rgba2String(rgba);
  3350. }
  3351. else if (isValueString) {
  3352. // String is step(0.5)
  3353. return interpolateString(p1, p2, w);
  3354. }
  3355. else {
  3356. value = catmullRomInterpolate(
  3357. p0, p1, p2, p3, w, w * w, w * w * w
  3358. );
  3359. }
  3360. setter(
  3361. target,
  3362. propName,
  3363. value
  3364. );
  3365. }
  3366. }
  3367. else {
  3368. if (isValueArray) {
  3369. interpolateArray(
  3370. kfValues[frame], kfValues[frame + 1], w,
  3371. getter(target, propName),
  3372. arrDim
  3373. );
  3374. }
  3375. else {
  3376. var value;
  3377. if (isValueColor) {
  3378. interpolateArray(
  3379. kfValues[frame], kfValues[frame + 1], w,
  3380. rgba, 1
  3381. );
  3382. value = rgba2String(rgba);
  3383. }
  3384. else if (isValueString) {
  3385. // String is step(0.5)
  3386. return interpolateString(kfValues[frame], kfValues[frame + 1], w);
  3387. }
  3388. else {
  3389. value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);
  3390. }
  3391. setter(
  3392. target,
  3393. propName,
  3394. value
  3395. );
  3396. }
  3397. }
  3398. };
  3399. var clip = new Clip({
  3400. target: animator._target,
  3401. life: trackMaxTime,
  3402. loop: animator._loop,
  3403. delay: animator._delay,
  3404. onframe: onframe,
  3405. ondestroy: oneTrackDone
  3406. });
  3407. if (easing && easing !== 'spline') {
  3408. clip.easing = easing;
  3409. }
  3410. return clip;
  3411. }
  3412. /**
  3413. * @alias module:zrender/animation/Animator
  3414. * @constructor
  3415. * @param {Object} target
  3416. * @param {boolean} loop
  3417. * @param {Function} getter
  3418. * @param {Function} setter
  3419. */
  3420. var Animator = function(target, loop, getter, setter) {
  3421. this._tracks = {};
  3422. this._target = target;
  3423. this._loop = loop || false;
  3424. this._getter = getter || defaultGetter;
  3425. this._setter = setter || defaultSetter;
  3426. this._clipCount = 0;
  3427. this._delay = 0;
  3428. this._doneList = [];
  3429. this._onframeList = [];
  3430. this._clipList = [];
  3431. };
  3432. Animator.prototype = {
  3433. /**
  3434. * 设置动画关键帧
  3435. * @param {number} time 关键帧时间,单位是ms
  3436. * @param {Object} props 关键帧的属性值,key-value表示
  3437. * @return {module:zrender/animation/Animator}
  3438. */
  3439. when: function(time /* ms */, props) {
  3440. var tracks = this._tracks;
  3441. for (var propName in props) {
  3442. if (!props.hasOwnProperty(propName)) {
  3443. continue;
  3444. }
  3445. if (!tracks[propName]) {
  3446. tracks[propName] = [];
  3447. // Invalid value
  3448. var value = this._getter(this._target, propName);
  3449. if (value == null) {
  3450. // zrLog('Invalid property ' + propName);
  3451. continue;
  3452. }
  3453. // If time is 0
  3454. // Then props is given initialize value
  3455. // Else
  3456. // Initialize value from current prop value
  3457. if (time !== 0) {
  3458. tracks[propName].push({
  3459. time: 0,
  3460. value: cloneValue(value)
  3461. });
  3462. }
  3463. }
  3464. tracks[propName].push({
  3465. time: time,
  3466. value: props[propName]
  3467. });
  3468. }
  3469. return this;
  3470. },
  3471. /**
  3472. * 添加动画每一帧的回调函数
  3473. * @param {Function} callback
  3474. * @return {module:zrender/animation/Animator}
  3475. */
  3476. during: function (callback) {
  3477. this._onframeList.push(callback);
  3478. return this;
  3479. },
  3480. pause: function () {
  3481. for (var i = 0; i < this._clipList.length; i++) {
  3482. this._clipList[i].pause();
  3483. }
  3484. this._paused = true;
  3485. },
  3486. resume: function () {
  3487. for (var i = 0; i < this._clipList.length; i++) {
  3488. this._clipList[i].resume();
  3489. }
  3490. this._paused = false;
  3491. },
  3492. isPaused: function () {
  3493. return !!this._paused;
  3494. },
  3495. _doneCallback: function () {
  3496. // Clear all tracks
  3497. this._tracks = {};
  3498. // Clear all clips
  3499. this._clipList.length = 0;
  3500. var doneList = this._doneList;
  3501. var len = doneList.length;
  3502. for (var i = 0; i < len; i++) {
  3503. doneList[i].call(this);
  3504. }
  3505. },
  3506. /**
  3507. * 开始执行动画
  3508. * @param {string|Function} [easing]
  3509. * 动画缓动函数,详见{@link module:zrender/animation/easing}
  3510. * @param {boolean} forceAnimate
  3511. * @return {module:zrender/animation/Animator}
  3512. */
  3513. start: function (easing, forceAnimate) {
  3514. var self = this;
  3515. var clipCount = 0;
  3516. var oneTrackDone = function() {
  3517. clipCount--;
  3518. if (!clipCount) {
  3519. self._doneCallback();
  3520. }
  3521. };
  3522. var lastClip;
  3523. for (var propName in this._tracks) {
  3524. if (!this._tracks.hasOwnProperty(propName)) {
  3525. continue;
  3526. }
  3527. var clip = createTrackClip(
  3528. this, easing, oneTrackDone,
  3529. this._tracks[propName], propName, forceAnimate
  3530. );
  3531. if (clip) {
  3532. this._clipList.push(clip);
  3533. clipCount++;
  3534. // If start after added to animation
  3535. if (this.animation) {
  3536. this.animation.addClip(clip);
  3537. }
  3538. lastClip = clip;
  3539. }
  3540. }
  3541. // Add during callback on the last clip
  3542. if (lastClip) {
  3543. var oldOnFrame = lastClip.onframe;
  3544. lastClip.onframe = function (target, percent) {
  3545. oldOnFrame(target, percent);
  3546. for (var i = 0; i < self._onframeList.length; i++) {
  3547. self._onframeList[i](target, percent);
  3548. }
  3549. };
  3550. }
  3551. // This optimization will help the case that in the upper application
  3552. // the view may be refreshed frequently, where animation will be
  3553. // called repeatly but nothing changed.
  3554. if (!clipCount) {
  3555. this._doneCallback();
  3556. }
  3557. return this;
  3558. },
  3559. /**
  3560. * 停止动画
  3561. * @param {boolean} forwardToLast If move to last frame before stop
  3562. */
  3563. stop: function (forwardToLast) {
  3564. var clipList = this._clipList;
  3565. var animation = this.animation;
  3566. for (var i = 0; i < clipList.length; i++) {
  3567. var clip = clipList[i];
  3568. if (forwardToLast) {
  3569. // Move to last frame before stop
  3570. clip.onframe(this._target, 1);
  3571. }
  3572. animation && animation.removeClip(clip);
  3573. }
  3574. clipList.length = 0;
  3575. },
  3576. /**
  3577. * 设置动画延迟开始的时间
  3578. * @param {number} time 单位ms
  3579. * @return {module:zrender/animation/Animator}
  3580. */
  3581. delay: function (time) {
  3582. this._delay = time;
  3583. return this;
  3584. },
  3585. /**
  3586. * 添加动画结束的回调
  3587. * @param {Function} cb
  3588. * @return {module:zrender/animation/Animator}
  3589. */
  3590. done: function(cb) {
  3591. if (cb) {
  3592. this._doneList.push(cb);
  3593. }
  3594. return this;
  3595. },
  3596. /**
  3597. * @return {Array.<module:zrender/animation/Clip>}
  3598. */
  3599. getClips: function () {
  3600. return this._clipList;
  3601. }
  3602. };
  3603. var dpr = 1;
  3604. // If in browser environment
  3605. if (typeof window !== 'undefined') {
  3606. dpr = Math.max(window.devicePixelRatio || 1, 1);
  3607. }
  3608. /**
  3609. * config默认配置项
  3610. * @exports zrender/config
  3611. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  3612. */
  3613. /**
  3614. * debug日志选项:catchBrushException为true下有效
  3615. * 0 : 不生成debug数据,发布用
  3616. * 1 : 异常抛出,调试用
  3617. * 2 : 控制台输出,调试用
  3618. */
  3619. var debugMode = 0;
  3620. // retina 屏幕优化
  3621. var devicePixelRatio = dpr;
  3622. var log = function () {
  3623. };
  3624. if (debugMode === 1) {
  3625. log = function () {
  3626. for (var k in arguments) {
  3627. throw new Error(arguments[k]);
  3628. }
  3629. };
  3630. }
  3631. else if (debugMode > 1) {
  3632. log = function () {
  3633. for (var k in arguments) {
  3634. console.log(arguments[k]);
  3635. }
  3636. };
  3637. }
  3638. var zrLog = log;
  3639. /**
  3640. * @alias modue:zrender/mixin/Animatable
  3641. * @constructor
  3642. */
  3643. var Animatable = function () {
  3644. /**
  3645. * @type {Array.<module:zrender/animation/Animator>}
  3646. * @readOnly
  3647. */
  3648. this.animators = [];
  3649. };
  3650. Animatable.prototype = {
  3651. constructor: Animatable,
  3652. /**
  3653. * 动画
  3654. *
  3655. * @param {string} path The path to fetch value from object, like 'a.b.c'.
  3656. * @param {boolean} [loop] Whether to loop animation.
  3657. * @return {module:zrender/animation/Animator}
  3658. * @example:
  3659. * el.animate('style', false)
  3660. * .when(1000, {x: 10} )
  3661. * .done(function(){ // Animation done })
  3662. * .start()
  3663. */
  3664. animate: function (path, loop) {
  3665. var target;
  3666. var animatingShape = false;
  3667. var el = this;
  3668. var zr = this.__zr;
  3669. if (path) {
  3670. var pathSplitted = path.split('.');
  3671. var prop = el;
  3672. // If animating shape
  3673. animatingShape = pathSplitted[0] === 'shape';
  3674. for (var i = 0, l = pathSplitted.length; i < l; i++) {
  3675. if (!prop) {
  3676. continue;
  3677. }
  3678. prop = prop[pathSplitted[i]];
  3679. }
  3680. if (prop) {
  3681. target = prop;
  3682. }
  3683. }
  3684. else {
  3685. target = el;
  3686. }
  3687. if (!target) {
  3688. zrLog(
  3689. 'Property "'
  3690. + path
  3691. + '" is not existed in element '
  3692. + el.id
  3693. );
  3694. return;
  3695. }
  3696. var animators = el.animators;
  3697. var animator = new Animator(target, loop);
  3698. animator.during(function (target) {
  3699. el.dirty(animatingShape);
  3700. })
  3701. .done(function () {
  3702. // FIXME Animator will not be removed if use `Animator#stop` to stop animation
  3703. animators.splice(indexOf(animators, animator), 1);
  3704. });
  3705. animators.push(animator);
  3706. // If animate after added to the zrender
  3707. if (zr) {
  3708. zr.animation.addAnimator(animator);
  3709. }
  3710. return animator;
  3711. },
  3712. /**
  3713. * 停止动画
  3714. * @param {boolean} forwardToLast If move to last frame before stop
  3715. */
  3716. stopAnimation: function (forwardToLast) {
  3717. var animators = this.animators;
  3718. var len = animators.length;
  3719. for (var i = 0; i < len; i++) {
  3720. animators[i].stop(forwardToLast);
  3721. }
  3722. animators.length = 0;
  3723. return this;
  3724. },
  3725. /**
  3726. * Caution: this method will stop previous animation.
  3727. * So do not use this method to one element twice before
  3728. * animation starts, unless you know what you are doing.
  3729. * @param {Object} target
  3730. * @param {number} [time=500] Time in ms
  3731. * @param {string} [easing='linear']
  3732. * @param {number} [delay=0]
  3733. * @param {Function} [callback]
  3734. * @param {Function} [forceAnimate] Prevent stop animation and callback
  3735. * immediently when target values are the same as current values.
  3736. *
  3737. * @example
  3738. * // Animate position
  3739. * el.animateTo({
  3740. * position: [10, 10]
  3741. * }, function () { // done })
  3742. *
  3743. * // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing
  3744. * el.animateTo({
  3745. * shape: {
  3746. * width: 500
  3747. * },
  3748. * style: {
  3749. * fill: 'red'
  3750. * }
  3751. * position: [10, 10]
  3752. * }, 100, 100, 'cubicOut', function () { // done })
  3753. */
  3754. // TODO Return animation key
  3755. animateTo: function (target, time, delay, easing, callback, forceAnimate) {
  3756. // animateTo(target, time, easing, callback);
  3757. if (isString(delay)) {
  3758. callback = easing;
  3759. easing = delay;
  3760. delay = 0;
  3761. }
  3762. // animateTo(target, time, delay, callback);
  3763. else if (isFunction(easing)) {
  3764. callback = easing;
  3765. easing = 'linear';
  3766. delay = 0;
  3767. }
  3768. // animateTo(target, time, callback);
  3769. else if (isFunction(delay)) {
  3770. callback = delay;
  3771. delay = 0;
  3772. }
  3773. // animateTo(target, callback)
  3774. else if (isFunction(time)) {
  3775. callback = time;
  3776. time = 500;
  3777. }
  3778. // animateTo(target)
  3779. else if (!time) {
  3780. time = 500;
  3781. }
  3782. // Stop all previous animations
  3783. this.stopAnimation();
  3784. this._animateToShallow('', this, target, time, delay);
  3785. // Animators may be removed immediately after start
  3786. // if there is nothing to animate
  3787. var animators = this.animators.slice();
  3788. var count = animators.length;
  3789. function done() {
  3790. count--;
  3791. if (!count) {
  3792. callback && callback();
  3793. }
  3794. }
  3795. // No animators. This should be checked before animators[i].start(),
  3796. // because 'done' may be executed immediately if no need to animate.
  3797. if (!count) {
  3798. callback && callback();
  3799. }
  3800. // Start after all animators created
  3801. // Incase any animator is done immediately when all animation properties are not changed
  3802. for (var i = 0; i < animators.length; i++) {
  3803. animators[i]
  3804. .done(done)
  3805. .start(easing, forceAnimate);
  3806. }
  3807. },
  3808. /**
  3809. * @private
  3810. * @param {string} path=''
  3811. * @param {Object} source=this
  3812. * @param {Object} target
  3813. * @param {number} [time=500]
  3814. * @param {number} [delay=0]
  3815. *
  3816. * @example
  3817. * // Animate position
  3818. * el._animateToShallow({
  3819. * position: [10, 10]
  3820. * })
  3821. *
  3822. * // Animate shape, style and position in 100ms, delayed 100ms
  3823. * el._animateToShallow({
  3824. * shape: {
  3825. * width: 500
  3826. * },
  3827. * style: {
  3828. * fill: 'red'
  3829. * }
  3830. * position: [10, 10]
  3831. * }, 100, 100)
  3832. */
  3833. _animateToShallow: function (path, source, target, time, delay) {
  3834. var objShallow = {};
  3835. var propertyCount = 0;
  3836. for (var name in target) {
  3837. if (!target.hasOwnProperty(name)) {
  3838. continue;
  3839. }
  3840. if (source[name] != null) {
  3841. if (isObject(target[name]) && !isArrayLike(target[name])) {
  3842. this._animateToShallow(
  3843. path ? path + '.' + name : name,
  3844. source[name],
  3845. target[name],
  3846. time,
  3847. delay
  3848. );
  3849. }
  3850. else {
  3851. objShallow[name] = target[name];
  3852. propertyCount++;
  3853. }
  3854. }
  3855. else if (target[name] != null) {
  3856. // Attr directly if not has property
  3857. // FIXME, if some property not needed for element ?
  3858. if (!path) {
  3859. this.attr(name, target[name]);
  3860. }
  3861. else { // Shape or style
  3862. var props = {};
  3863. props[path] = {};
  3864. props[path][name] = target[name];
  3865. this.attr(props);
  3866. }
  3867. }
  3868. }
  3869. if (propertyCount > 0) {
  3870. this.animate(path, false)
  3871. .when(time == null ? 500 : time, objShallow)
  3872. .delay(delay || 0);
  3873. }
  3874. return this;
  3875. }
  3876. };
  3877. /**
  3878. * @alias module:zrender/Element
  3879. * @constructor
  3880. * @extends {module:zrender/mixin/Animatable}
  3881. * @extends {module:zrender/mixin/Transformable}
  3882. * @extends {module:zrender/mixin/Eventful}
  3883. */
  3884. var Element = function (opts) { // jshint ignore:line
  3885. Transformable.call(this, opts);
  3886. Eventful.call(this, opts);
  3887. Animatable.call(this, opts);
  3888. /**
  3889. * 画布元素ID
  3890. * @type {string}
  3891. */
  3892. this.id = opts.id || guid();
  3893. };
  3894. Element.prototype = {
  3895. /**
  3896. * 元素类型
  3897. * Element type
  3898. * @type {string}
  3899. */
  3900. type: 'element',
  3901. /**
  3902. * 元素名字
  3903. * Element name
  3904. * @type {string}
  3905. */
  3906. name: '',
  3907. /**
  3908. * ZRender 实例对象,会在 element 添加到 zrender 实例中后自动赋值
  3909. * ZRender instance will be assigned when element is associated with zrender
  3910. * @name module:/zrender/Element#__zr
  3911. * @type {module:zrender/ZRender}
  3912. */
  3913. __zr: null,
  3914. /**
  3915. * 图形是否忽略,为true时忽略图形的绘制以及事件触发
  3916. * If ignore drawing and events of the element object
  3917. * @name module:/zrender/Element#ignore
  3918. * @type {boolean}
  3919. * @default false
  3920. */
  3921. ignore: false,
  3922. /**
  3923. * 用于裁剪的路径(shape),所有 Group 内的路径在绘制时都会被这个路径裁剪
  3924. * 该路径会继承被裁减对象的变换
  3925. * @type {module:zrender/graphic/Path}
  3926. * @see http://www.w3.org/TR/2dcontext/#clipping-region
  3927. * @readOnly
  3928. */
  3929. clipPath: null,
  3930. /**
  3931. * Drift element
  3932. * @param {number} dx dx on the global space
  3933. * @param {number} dy dy on the global space
  3934. */
  3935. drift: function (dx, dy) {
  3936. switch (this.draggable) {
  3937. case 'horizontal':
  3938. dy = 0;
  3939. break;
  3940. case 'vertical':
  3941. dx = 0;
  3942. break;
  3943. }
  3944. var m = this.transform;
  3945. if (!m) {
  3946. m = this.transform = [1, 0, 0, 1, 0, 0];
  3947. }
  3948. m[4] += dx;
  3949. m[5] += dy;
  3950. this.decomposeTransform();
  3951. this.dirty(false);
  3952. },
  3953. /**
  3954. * Hook before update
  3955. */
  3956. beforeUpdate: function () {},
  3957. /**
  3958. * Hook after update
  3959. */
  3960. afterUpdate: function () {},
  3961. /**
  3962. * Update each frame
  3963. */
  3964. update: function () {
  3965. this.updateTransform();
  3966. },
  3967. /**
  3968. * @param {Function} cb
  3969. * @param {} context
  3970. */
  3971. traverse: function (cb, context) {},
  3972. /**
  3973. * @protected
  3974. */
  3975. attrKV: function (key, value) {
  3976. if (key === 'position' || key === 'scale' || key === 'origin') {
  3977. // Copy the array
  3978. if (value) {
  3979. var target = this[key];
  3980. if (!target) {
  3981. target = this[key] = [];
  3982. }
  3983. target[0] = value[0];
  3984. target[1] = value[1];
  3985. }
  3986. }
  3987. else {
  3988. this[key] = value;
  3989. }
  3990. },
  3991. /**
  3992. * Hide the element
  3993. */
  3994. hide: function () {
  3995. this.ignore = true;
  3996. this.__zr && this.__zr.refresh();
  3997. },
  3998. /**
  3999. * Show the element
  4000. */
  4001. show: function () {
  4002. this.ignore = false;
  4003. this.__zr && this.__zr.refresh();
  4004. },
  4005. /**
  4006. * @param {string|Object} key
  4007. * @param {*} value
  4008. */
  4009. attr: function (key, value) {
  4010. if (typeof key === 'string') {
  4011. this.attrKV(key, value);
  4012. }
  4013. else if (isObject(key)) {
  4014. for (var name in key) {
  4015. if (key.hasOwnProperty(name)) {
  4016. this.attrKV(name, key[name]);
  4017. }
  4018. }
  4019. }
  4020. this.dirty(false);
  4021. return this;
  4022. },
  4023. /**
  4024. * @param {module:zrender/graphic/Path} clipPath
  4025. */
  4026. setClipPath: function (clipPath) {
  4027. var zr = this.__zr;
  4028. if (zr) {
  4029. clipPath.addSelfToZr(zr);
  4030. }
  4031. // Remove previous clip path
  4032. if (this.clipPath && this.clipPath !== clipPath) {
  4033. this.removeClipPath();
  4034. }
  4035. this.clipPath = clipPath;
  4036. clipPath.__zr = zr;
  4037. clipPath.__clipTarget = this;
  4038. this.dirty(false);
  4039. },
  4040. /**
  4041. */
  4042. removeClipPath: function () {
  4043. var clipPath = this.clipPath;
  4044. if (clipPath) {
  4045. if (clipPath.__zr) {
  4046. clipPath.removeSelfFromZr(clipPath.__zr);
  4047. }
  4048. clipPath.__zr = null;
  4049. clipPath.__clipTarget = null;
  4050. this.clipPath = null;
  4051. this.dirty(false);
  4052. }
  4053. },
  4054. /**
  4055. * Add self from zrender instance.
  4056. * Not recursively because it will be invoked when element added to storage.
  4057. * @param {module:zrender/ZRender} zr
  4058. */
  4059. addSelfToZr: function (zr) {
  4060. this.__zr = zr;
  4061. // 添加动画
  4062. var animators = this.animators;
  4063. if (animators) {
  4064. for (var i = 0; i < animators.length; i++) {
  4065. zr.animation.addAnimator(animators[i]);
  4066. }
  4067. }
  4068. if (this.clipPath) {
  4069. this.clipPath.addSelfToZr(zr);
  4070. }
  4071. },
  4072. /**
  4073. * Remove self from zrender instance.
  4074. * Not recursively because it will be invoked when element added to storage.
  4075. * @param {module:zrender/ZRender} zr
  4076. */
  4077. removeSelfFromZr: function (zr) {
  4078. this.__zr = null;
  4079. // 移除动画
  4080. var animators = this.animators;
  4081. if (animators) {
  4082. for (var i = 0; i < animators.length; i++) {
  4083. zr.animation.removeAnimator(animators[i]);
  4084. }
  4085. }
  4086. if (this.clipPath) {
  4087. this.clipPath.removeSelfFromZr(zr);
  4088. }
  4089. }
  4090. };
  4091. mixin(Element, Animatable);
  4092. mixin(Element, Transformable);
  4093. mixin(Element, Eventful);
  4094. /**
  4095. * @module echarts/core/BoundingRect
  4096. */
  4097. var v2ApplyTransform = applyTransform;
  4098. var mathMin = Math.min;
  4099. var mathMax = Math.max;
  4100. /**
  4101. * @alias module:echarts/core/BoundingRect
  4102. */
  4103. function BoundingRect(x, y, width, height) {
  4104. if (width < 0) {
  4105. x = x + width;
  4106. width = -width;
  4107. }
  4108. if (height < 0) {
  4109. y = y + height;
  4110. height = -height;
  4111. }
  4112. /**
  4113. * @type {number}
  4114. */
  4115. this.x = x;
  4116. /**
  4117. * @type {number}
  4118. */
  4119. this.y = y;
  4120. /**
  4121. * @type {number}
  4122. */
  4123. this.width = width;
  4124. /**
  4125. * @type {number}
  4126. */
  4127. this.height = height;
  4128. }
  4129. BoundingRect.prototype = {
  4130. constructor: BoundingRect,
  4131. /**
  4132. * @param {module:echarts/core/BoundingRect} other
  4133. */
  4134. union: function (other) {
  4135. var x = mathMin(other.x, this.x);
  4136. var y = mathMin(other.y, this.y);
  4137. this.width = mathMax(
  4138. other.x + other.width,
  4139. this.x + this.width
  4140. ) - x;
  4141. this.height = mathMax(
  4142. other.y + other.height,
  4143. this.y + this.height
  4144. ) - y;
  4145. this.x = x;
  4146. this.y = y;
  4147. },
  4148. /**
  4149. * @param {Array.<number>} m
  4150. * @methods
  4151. */
  4152. applyTransform: (function () {
  4153. var lt = [];
  4154. var rb = [];
  4155. var lb = [];
  4156. var rt = [];
  4157. return function (m) {
  4158. // In case usage like this
  4159. // el.getBoundingRect().applyTransform(el.transform)
  4160. // And element has no transform
  4161. if (!m) {
  4162. return;
  4163. }
  4164. lt[0] = lb[0] = this.x;
  4165. lt[1] = rt[1] = this.y;
  4166. rb[0] = rt[0] = this.x + this.width;
  4167. rb[1] = lb[1] = this.y + this.height;
  4168. v2ApplyTransform(lt, lt, m);
  4169. v2ApplyTransform(rb, rb, m);
  4170. v2ApplyTransform(lb, lb, m);
  4171. v2ApplyTransform(rt, rt, m);
  4172. this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);
  4173. this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);
  4174. var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);
  4175. var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);
  4176. this.width = maxX - this.x;
  4177. this.height = maxY - this.y;
  4178. };
  4179. })(),
  4180. /**
  4181. * Calculate matrix of transforming from self to target rect
  4182. * @param {module:zrender/core/BoundingRect} b
  4183. * @return {Array.<number>}
  4184. */
  4185. calculateTransform: function (b) {
  4186. var a = this;
  4187. var sx = b.width / a.width;
  4188. var sy = b.height / a.height;
  4189. var m = create$1();
  4190. // 矩阵右乘
  4191. translate(m, m, [-a.x, -a.y]);
  4192. scale$1(m, m, [sx, sy]);
  4193. translate(m, m, [b.x, b.y]);
  4194. return m;
  4195. },
  4196. /**
  4197. * @param {(module:echarts/core/BoundingRect|Object)} b
  4198. * @return {boolean}
  4199. */
  4200. intersect: function (b) {
  4201. if (!b) {
  4202. return false;
  4203. }
  4204. if (!(b instanceof BoundingRect)) {
  4205. // Normalize negative width/height.
  4206. b = BoundingRect.create(b);
  4207. }
  4208. var a = this;
  4209. var ax0 = a.x;
  4210. var ax1 = a.x + a.width;
  4211. var ay0 = a.y;
  4212. var ay1 = a.y + a.height;
  4213. var bx0 = b.x;
  4214. var bx1 = b.x + b.width;
  4215. var by0 = b.y;
  4216. var by1 = b.y + b.height;
  4217. return ! (ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
  4218. },
  4219. contain: function (x, y) {
  4220. var rect = this;
  4221. return x >= rect.x
  4222. && x <= (rect.x + rect.width)
  4223. && y >= rect.y
  4224. && y <= (rect.y + rect.height);
  4225. },
  4226. /**
  4227. * @return {module:echarts/core/BoundingRect}
  4228. */
  4229. clone: function () {
  4230. return new BoundingRect(this.x, this.y, this.width, this.height);
  4231. },
  4232. /**
  4233. * Copy from another rect
  4234. */
  4235. copy: function (other) {
  4236. this.x = other.x;
  4237. this.y = other.y;
  4238. this.width = other.width;
  4239. this.height = other.height;
  4240. },
  4241. plain: function () {
  4242. return {
  4243. x: this.x,
  4244. y: this.y,
  4245. width: this.width,
  4246. height: this.height
  4247. };
  4248. }
  4249. };
  4250. /**
  4251. * @param {Object|module:zrender/core/BoundingRect} rect
  4252. * @param {number} rect.x
  4253. * @param {number} rect.y
  4254. * @param {number} rect.width
  4255. * @param {number} rect.height
  4256. * @return {module:zrender/core/BoundingRect}
  4257. */
  4258. BoundingRect.create = function (rect) {
  4259. return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
  4260. };
  4261. /**
  4262. * Group是一个容器,可以插入子节点,Group的变换也会被应用到子节点上
  4263. * @module zrender/graphic/Group
  4264. * @example
  4265. * var Group = require('zrender/container/Group');
  4266. * var Circle = require('zrender/graphic/shape/Circle');
  4267. * var g = new Group();
  4268. * g.position[0] = 100;
  4269. * g.position[1] = 100;
  4270. * g.add(new Circle({
  4271. * style: {
  4272. * x: 100,
  4273. * y: 100,
  4274. * r: 20,
  4275. * }
  4276. * }));
  4277. * zr.add(g);
  4278. */
  4279. /**
  4280. * @alias module:zrender/graphic/Group
  4281. * @constructor
  4282. * @extends module:zrender/mixin/Transformable
  4283. * @extends module:zrender/mixin/Eventful
  4284. */
  4285. var Group = function (opts) {
  4286. opts = opts || {};
  4287. Element.call(this, opts);
  4288. for (var key in opts) {
  4289. if (opts.hasOwnProperty(key)) {
  4290. this[key] = opts[key];
  4291. }
  4292. }
  4293. this._children = [];
  4294. this.__storage = null;
  4295. this.__dirty = true;
  4296. };
  4297. Group.prototype = {
  4298. constructor: Group,
  4299. isGroup: true,
  4300. /**
  4301. * @type {string}
  4302. */
  4303. type: 'group',
  4304. /**
  4305. * 所有子孙元素是否响应鼠标事件
  4306. * @name module:/zrender/container/Group#silent
  4307. * @type {boolean}
  4308. * @default false
  4309. */
  4310. silent: false,
  4311. /**
  4312. * @return {Array.<module:zrender/Element>}
  4313. */
  4314. children: function () {
  4315. return this._children.slice();
  4316. },
  4317. /**
  4318. * 获取指定 index 的儿子节点
  4319. * @param {number} idx
  4320. * @return {module:zrender/Element}
  4321. */
  4322. childAt: function (idx) {
  4323. return this._children[idx];
  4324. },
  4325. /**
  4326. * 获取指定名字的儿子节点
  4327. * @param {string} name
  4328. * @return {module:zrender/Element}
  4329. */
  4330. childOfName: function (name) {
  4331. var children = this._children;
  4332. for (var i = 0; i < children.length; i++) {
  4333. if (children[i].name === name) {
  4334. return children[i];
  4335. }
  4336. }
  4337. },
  4338. /**
  4339. * @return {number}
  4340. */
  4341. childCount: function () {
  4342. return this._children.length;
  4343. },
  4344. /**
  4345. * 添加子节点到最后
  4346. * @param {module:zrender/Element} child
  4347. */
  4348. add: function (child) {
  4349. if (child && child !== this && child.parent !== this) {
  4350. this._children.push(child);
  4351. this._doAdd(child);
  4352. }
  4353. return this;
  4354. },
  4355. /**
  4356. * 添加子节点在 nextSibling 之前
  4357. * @param {module:zrender/Element} child
  4358. * @param {module:zrender/Element} nextSibling
  4359. */
  4360. addBefore: function (child, nextSibling) {
  4361. if (child && child !== this && child.parent !== this
  4362. && nextSibling && nextSibling.parent === this) {
  4363. var children = this._children;
  4364. var idx = children.indexOf(nextSibling);
  4365. if (idx >= 0) {
  4366. children.splice(idx, 0, child);
  4367. this._doAdd(child);
  4368. }
  4369. }
  4370. return this;
  4371. },
  4372. _doAdd: function (child) {
  4373. if (child.parent) {
  4374. child.parent.remove(child);
  4375. }
  4376. child.parent = this;
  4377. var storage = this.__storage;
  4378. var zr = this.__zr;
  4379. if (storage && storage !== child.__storage) {
  4380. storage.addToStorage(child);
  4381. if (child instanceof Group) {
  4382. child.addChildrenToStorage(storage);
  4383. }
  4384. }
  4385. zr && zr.refresh();
  4386. },
  4387. /**
  4388. * 移除子节点
  4389. * @param {module:zrender/Element} child
  4390. */
  4391. remove: function (child) {
  4392. var zr = this.__zr;
  4393. var storage = this.__storage;
  4394. var children = this._children;
  4395. var idx = indexOf(children, child);
  4396. if (idx < 0) {
  4397. return this;
  4398. }
  4399. children.splice(idx, 1);
  4400. child.parent = null;
  4401. if (storage) {
  4402. storage.delFromStorage(child);
  4403. if (child instanceof Group) {
  4404. child.delChildrenFromStorage(storage);
  4405. }
  4406. }
  4407. zr && zr.refresh();
  4408. return this;
  4409. },
  4410. /**
  4411. * 移除所有子节点
  4412. */
  4413. removeAll: function () {
  4414. var children = this._children;
  4415. var storage = this.__storage;
  4416. var child;
  4417. var i;
  4418. for (i = 0; i < children.length; i++) {
  4419. child = children[i];
  4420. if (storage) {
  4421. storage.delFromStorage(child);
  4422. if (child instanceof Group) {
  4423. child.delChildrenFromStorage(storage);
  4424. }
  4425. }
  4426. child.parent = null;
  4427. }
  4428. children.length = 0;
  4429. return this;
  4430. },
  4431. /**
  4432. * 遍历所有子节点
  4433. * @param {Function} cb
  4434. * @param {} context
  4435. */
  4436. eachChild: function (cb, context) {
  4437. var children = this._children;
  4438. for (var i = 0; i < children.length; i++) {
  4439. var child = children[i];
  4440. cb.call(context, child, i);
  4441. }
  4442. return this;
  4443. },
  4444. /**
  4445. * 深度优先遍历所有子孙节点
  4446. * @param {Function} cb
  4447. * @param {} context
  4448. */
  4449. traverse: function (cb, context) {
  4450. for (var i = 0; i < this._children.length; i++) {
  4451. var child = this._children[i];
  4452. cb.call(context, child);
  4453. if (child.type === 'group') {
  4454. child.traverse(cb, context);
  4455. }
  4456. }
  4457. return this;
  4458. },
  4459. addChildrenToStorage: function (storage) {
  4460. for (var i = 0; i < this._children.length; i++) {
  4461. var child = this._children[i];
  4462. storage.addToStorage(child);
  4463. if (child instanceof Group) {
  4464. child.addChildrenToStorage(storage);
  4465. }
  4466. }
  4467. },
  4468. delChildrenFromStorage: function (storage) {
  4469. for (var i = 0; i < this._children.length; i++) {
  4470. var child = this._children[i];
  4471. storage.delFromStorage(child);
  4472. if (child instanceof Group) {
  4473. child.delChildrenFromStorage(storage);
  4474. }
  4475. }
  4476. },
  4477. dirty: function () {
  4478. this.__dirty = true;
  4479. this.__zr && this.__zr.refresh();
  4480. return this;
  4481. },
  4482. /**
  4483. * @return {module:zrender/core/BoundingRect}
  4484. */
  4485. getBoundingRect: function (includeChildren) {
  4486. // TODO Caching
  4487. var rect = null;
  4488. var tmpRect = new BoundingRect(0, 0, 0, 0);
  4489. var children = includeChildren || this._children;
  4490. var tmpMat = [];
  4491. for (var i = 0; i < children.length; i++) {
  4492. var child = children[i];
  4493. if (child.ignore || child.invisible) {
  4494. continue;
  4495. }
  4496. var childRect = child.getBoundingRect();
  4497. var transform = child.getLocalTransform(tmpMat);
  4498. // TODO
  4499. // The boundingRect cacluated by transforming original
  4500. // rect may be bigger than the actual bundingRect when rotation
  4501. // is used. (Consider a circle rotated aginst its center, where
  4502. // the actual boundingRect should be the same as that not be
  4503. // rotated.) But we can not find better approach to calculate
  4504. // actual boundingRect yet, considering performance.
  4505. if (transform) {
  4506. tmpRect.copy(childRect);
  4507. tmpRect.applyTransform(transform);
  4508. rect = rect || tmpRect.clone();
  4509. rect.union(tmpRect);
  4510. }
  4511. else {
  4512. rect = rect || childRect.clone();
  4513. rect.union(childRect);
  4514. }
  4515. }
  4516. return rect || tmpRect;
  4517. }
  4518. };
  4519. inherits(Group, Element);
  4520. // https://github.com/mziccard/node-timsort
  4521. var DEFAULT_MIN_MERGE = 32;
  4522. var DEFAULT_MIN_GALLOPING = 7;
  4523. function minRunLength(n) {
  4524. var r = 0;
  4525. while (n >= DEFAULT_MIN_MERGE) {
  4526. r |= n & 1;
  4527. n >>= 1;
  4528. }
  4529. return n + r;
  4530. }
  4531. function makeAscendingRun(array, lo, hi, compare) {
  4532. var runHi = lo + 1;
  4533. if (runHi === hi) {
  4534. return 1;
  4535. }
  4536. if (compare(array[runHi++], array[lo]) < 0) {
  4537. while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
  4538. runHi++;
  4539. }
  4540. reverseRun(array, lo, runHi);
  4541. }
  4542. else {
  4543. while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
  4544. runHi++;
  4545. }
  4546. }
  4547. return runHi - lo;
  4548. }
  4549. function reverseRun(array, lo, hi) {
  4550. hi--;
  4551. while (lo < hi) {
  4552. var t = array[lo];
  4553. array[lo++] = array[hi];
  4554. array[hi--] = t;
  4555. }
  4556. }
  4557. function binaryInsertionSort(array, lo, hi, start, compare) {
  4558. if (start === lo) {
  4559. start++;
  4560. }
  4561. for (; start < hi; start++) {
  4562. var pivot = array[start];
  4563. var left = lo;
  4564. var right = start;
  4565. var mid;
  4566. while (left < right) {
  4567. mid = left + right >>> 1;
  4568. if (compare(pivot, array[mid]) < 0) {
  4569. right = mid;
  4570. }
  4571. else {
  4572. left = mid + 1;
  4573. }
  4574. }
  4575. var n = start - left;
  4576. switch (n) {
  4577. case 3:
  4578. array[left + 3] = array[left + 2];
  4579. case 2:
  4580. array[left + 2] = array[left + 1];
  4581. case 1:
  4582. array[left + 1] = array[left];
  4583. break;
  4584. default:
  4585. while (n > 0) {
  4586. array[left + n] = array[left + n - 1];
  4587. n--;
  4588. }
  4589. }
  4590. array[left] = pivot;
  4591. }
  4592. }
  4593. function gallopLeft(value, array, start, length, hint, compare) {
  4594. var lastOffset = 0;
  4595. var maxOffset = 0;
  4596. var offset = 1;
  4597. if (compare(value, array[start + hint]) > 0) {
  4598. maxOffset = length - hint;
  4599. while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
  4600. lastOffset = offset;
  4601. offset = (offset << 1) + 1;
  4602. if (offset <= 0) {
  4603. offset = maxOffset;
  4604. }
  4605. }
  4606. if (offset > maxOffset) {
  4607. offset = maxOffset;
  4608. }
  4609. lastOffset += hint;
  4610. offset += hint;
  4611. }
  4612. else {
  4613. maxOffset = hint + 1;
  4614. while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
  4615. lastOffset = offset;
  4616. offset = (offset << 1) + 1;
  4617. if (offset <= 0) {
  4618. offset = maxOffset;
  4619. }
  4620. }
  4621. if (offset > maxOffset) {
  4622. offset = maxOffset;
  4623. }
  4624. var tmp = lastOffset;
  4625. lastOffset = hint - offset;
  4626. offset = hint - tmp;
  4627. }
  4628. lastOffset++;
  4629. while (lastOffset < offset) {
  4630. var m = lastOffset + (offset - lastOffset >>> 1);
  4631. if (compare(value, array[start + m]) > 0) {
  4632. lastOffset = m + 1;
  4633. }
  4634. else {
  4635. offset = m;
  4636. }
  4637. }
  4638. return offset;
  4639. }
  4640. function gallopRight(value, array, start, length, hint, compare) {
  4641. var lastOffset = 0;
  4642. var maxOffset = 0;
  4643. var offset = 1;
  4644. if (compare(value, array[start + hint]) < 0) {
  4645. maxOffset = hint + 1;
  4646. while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
  4647. lastOffset = offset;
  4648. offset = (offset << 1) + 1;
  4649. if (offset <= 0) {
  4650. offset = maxOffset;
  4651. }
  4652. }
  4653. if (offset > maxOffset) {
  4654. offset = maxOffset;
  4655. }
  4656. var tmp = lastOffset;
  4657. lastOffset = hint - offset;
  4658. offset = hint - tmp;
  4659. }
  4660. else {
  4661. maxOffset = length - hint;
  4662. while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
  4663. lastOffset = offset;
  4664. offset = (offset << 1) + 1;
  4665. if (offset <= 0) {
  4666. offset = maxOffset;
  4667. }
  4668. }
  4669. if (offset > maxOffset) {
  4670. offset = maxOffset;
  4671. }
  4672. lastOffset += hint;
  4673. offset += hint;
  4674. }
  4675. lastOffset++;
  4676. while (lastOffset < offset) {
  4677. var m = lastOffset + (offset - lastOffset >>> 1);
  4678. if (compare(value, array[start + m]) < 0) {
  4679. offset = m;
  4680. }
  4681. else {
  4682. lastOffset = m + 1;
  4683. }
  4684. }
  4685. return offset;
  4686. }
  4687. function TimSort(array, compare) {
  4688. var minGallop = DEFAULT_MIN_GALLOPING;
  4689. var runStart;
  4690. var runLength;
  4691. var stackSize = 0;
  4692. var tmp = [];
  4693. runStart = [];
  4694. runLength = [];
  4695. function pushRun(_runStart, _runLength) {
  4696. runStart[stackSize] = _runStart;
  4697. runLength[stackSize] = _runLength;
  4698. stackSize += 1;
  4699. }
  4700. function mergeRuns() {
  4701. while (stackSize > 1) {
  4702. var n = stackSize - 2;
  4703. if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {
  4704. if (runLength[n - 1] < runLength[n + 1]) {
  4705. n--;
  4706. }
  4707. }
  4708. else if (runLength[n] > runLength[n + 1]) {
  4709. break;
  4710. }
  4711. mergeAt(n);
  4712. }
  4713. }
  4714. function forceMergeRuns() {
  4715. while (stackSize > 1) {
  4716. var n = stackSize - 2;
  4717. if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
  4718. n--;
  4719. }
  4720. mergeAt(n);
  4721. }
  4722. }
  4723. function mergeAt(i) {
  4724. var start1 = runStart[i];
  4725. var length1 = runLength[i];
  4726. var start2 = runStart[i + 1];
  4727. var length2 = runLength[i + 1];
  4728. runLength[i] = length1 + length2;
  4729. if (i === stackSize - 3) {
  4730. runStart[i + 1] = runStart[i + 2];
  4731. runLength[i + 1] = runLength[i + 2];
  4732. }
  4733. stackSize--;
  4734. var k = gallopRight(array[start2], array, start1, length1, 0, compare);
  4735. start1 += k;
  4736. length1 -= k;
  4737. if (length1 === 0) {
  4738. return;
  4739. }
  4740. length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
  4741. if (length2 === 0) {
  4742. return;
  4743. }
  4744. if (length1 <= length2) {
  4745. mergeLow(start1, length1, start2, length2);
  4746. }
  4747. else {
  4748. mergeHigh(start1, length1, start2, length2);
  4749. }
  4750. }
  4751. function mergeLow(start1, length1, start2, length2) {
  4752. var i = 0;
  4753. for (i = 0; i < length1; i++) {
  4754. tmp[i] = array[start1 + i];
  4755. }
  4756. var cursor1 = 0;
  4757. var cursor2 = start2;
  4758. var dest = start1;
  4759. array[dest++] = array[cursor2++];
  4760. if (--length2 === 0) {
  4761. for (i = 0; i < length1; i++) {
  4762. array[dest + i] = tmp[cursor1 + i];
  4763. }
  4764. return;
  4765. }
  4766. if (length1 === 1) {
  4767. for (i = 0; i < length2; i++) {
  4768. array[dest + i] = array[cursor2 + i];
  4769. }
  4770. array[dest + length2] = tmp[cursor1];
  4771. return;
  4772. }
  4773. var _minGallop = minGallop;
  4774. var count1, count2, exit;
  4775. while (1) {
  4776. count1 = 0;
  4777. count2 = 0;
  4778. exit = false;
  4779. do {
  4780. if (compare(array[cursor2], tmp[cursor1]) < 0) {
  4781. array[dest++] = array[cursor2++];
  4782. count2++;
  4783. count1 = 0;
  4784. if (--length2 === 0) {
  4785. exit = true;
  4786. break;
  4787. }
  4788. }
  4789. else {
  4790. array[dest++] = tmp[cursor1++];
  4791. count1++;
  4792. count2 = 0;
  4793. if (--length1 === 1) {
  4794. exit = true;
  4795. break;
  4796. }
  4797. }
  4798. } while ((count1 | count2) < _minGallop);
  4799. if (exit) {
  4800. break;
  4801. }
  4802. do {
  4803. count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
  4804. if (count1 !== 0) {
  4805. for (i = 0; i < count1; i++) {
  4806. array[dest + i] = tmp[cursor1 + i];
  4807. }
  4808. dest += count1;
  4809. cursor1 += count1;
  4810. length1 -= count1;
  4811. if (length1 <= 1) {
  4812. exit = true;
  4813. break;
  4814. }
  4815. }
  4816. array[dest++] = array[cursor2++];
  4817. if (--length2 === 0) {
  4818. exit = true;
  4819. break;
  4820. }
  4821. count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
  4822. if (count2 !== 0) {
  4823. for (i = 0; i < count2; i++) {
  4824. array[dest + i] = array[cursor2 + i];
  4825. }
  4826. dest += count2;
  4827. cursor2 += count2;
  4828. length2 -= count2;
  4829. if (length2 === 0) {
  4830. exit = true;
  4831. break;
  4832. }
  4833. }
  4834. array[dest++] = tmp[cursor1++];
  4835. if (--length1 === 1) {
  4836. exit = true;
  4837. break;
  4838. }
  4839. _minGallop--;
  4840. } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
  4841. if (exit) {
  4842. break;
  4843. }
  4844. if (_minGallop < 0) {
  4845. _minGallop = 0;
  4846. }
  4847. _minGallop += 2;
  4848. }
  4849. minGallop = _minGallop;
  4850. minGallop < 1 && (minGallop = 1);
  4851. if (length1 === 1) {
  4852. for (i = 0; i < length2; i++) {
  4853. array[dest + i] = array[cursor2 + i];
  4854. }
  4855. array[dest + length2] = tmp[cursor1];
  4856. }
  4857. else if (length1 === 0) {
  4858. throw new Error();
  4859. // throw new Error('mergeLow preconditions were not respected');
  4860. }
  4861. else {
  4862. for (i = 0; i < length1; i++) {
  4863. array[dest + i] = tmp[cursor1 + i];
  4864. }
  4865. }
  4866. }
  4867. function mergeHigh (start1, length1, start2, length2) {
  4868. var i = 0;
  4869. for (i = 0; i < length2; i++) {
  4870. tmp[i] = array[start2 + i];
  4871. }
  4872. var cursor1 = start1 + length1 - 1;
  4873. var cursor2 = length2 - 1;
  4874. var dest = start2 + length2 - 1;
  4875. var customCursor = 0;
  4876. var customDest = 0;
  4877. array[dest--] = array[cursor1--];
  4878. if (--length1 === 0) {
  4879. customCursor = dest - (length2 - 1);
  4880. for (i = 0; i < length2; i++) {
  4881. array[customCursor + i] = tmp[i];
  4882. }
  4883. return;
  4884. }
  4885. if (length2 === 1) {
  4886. dest -= length1;
  4887. cursor1 -= length1;
  4888. customDest = dest + 1;
  4889. customCursor = cursor1 + 1;
  4890. for (i = length1 - 1; i >= 0; i--) {
  4891. array[customDest + i] = array[customCursor + i];
  4892. }
  4893. array[dest] = tmp[cursor2];
  4894. return;
  4895. }
  4896. var _minGallop = minGallop;
  4897. while (true) {
  4898. var count1 = 0;
  4899. var count2 = 0;
  4900. var exit = false;
  4901. do {
  4902. if (compare(tmp[cursor2], array[cursor1]) < 0) {
  4903. array[dest--] = array[cursor1--];
  4904. count1++;
  4905. count2 = 0;
  4906. if (--length1 === 0) {
  4907. exit = true;
  4908. break;
  4909. }
  4910. }
  4911. else {
  4912. array[dest--] = tmp[cursor2--];
  4913. count2++;
  4914. count1 = 0;
  4915. if (--length2 === 1) {
  4916. exit = true;
  4917. break;
  4918. }
  4919. }
  4920. } while ((count1 | count2) < _minGallop);
  4921. if (exit) {
  4922. break;
  4923. }
  4924. do {
  4925. count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
  4926. if (count1 !== 0) {
  4927. dest -= count1;
  4928. cursor1 -= count1;
  4929. length1 -= count1;
  4930. customDest = dest + 1;
  4931. customCursor = cursor1 + 1;
  4932. for (i = count1 - 1; i >= 0; i--) {
  4933. array[customDest + i] = array[customCursor + i];
  4934. }
  4935. if (length1 === 0) {
  4936. exit = true;
  4937. break;
  4938. }
  4939. }
  4940. array[dest--] = tmp[cursor2--];
  4941. if (--length2 === 1) {
  4942. exit = true;
  4943. break;
  4944. }
  4945. count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
  4946. if (count2 !== 0) {
  4947. dest -= count2;
  4948. cursor2 -= count2;
  4949. length2 -= count2;
  4950. customDest = dest + 1;
  4951. customCursor = cursor2 + 1;
  4952. for (i = 0; i < count2; i++) {
  4953. array[customDest + i] = tmp[customCursor + i];
  4954. }
  4955. if (length2 <= 1) {
  4956. exit = true;
  4957. break;
  4958. }
  4959. }
  4960. array[dest--] = array[cursor1--];
  4961. if (--length1 === 0) {
  4962. exit = true;
  4963. break;
  4964. }
  4965. _minGallop--;
  4966. } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
  4967. if (exit) {
  4968. break;
  4969. }
  4970. if (_minGallop < 0) {
  4971. _minGallop = 0;
  4972. }
  4973. _minGallop += 2;
  4974. }
  4975. minGallop = _minGallop;
  4976. if (minGallop < 1) {
  4977. minGallop = 1;
  4978. }
  4979. if (length2 === 1) {
  4980. dest -= length1;
  4981. cursor1 -= length1;
  4982. customDest = dest + 1;
  4983. customCursor = cursor1 + 1;
  4984. for (i = length1 - 1; i >= 0; i--) {
  4985. array[customDest + i] = array[customCursor + i];
  4986. }
  4987. array[dest] = tmp[cursor2];
  4988. }
  4989. else if (length2 === 0) {
  4990. throw new Error();
  4991. // throw new Error('mergeHigh preconditions were not respected');
  4992. }
  4993. else {
  4994. customCursor = dest - (length2 - 1);
  4995. for (i = 0; i < length2; i++) {
  4996. array[customCursor + i] = tmp[i];
  4997. }
  4998. }
  4999. }
  5000. this.mergeRuns = mergeRuns;
  5001. this.forceMergeRuns = forceMergeRuns;
  5002. this.pushRun = pushRun;
  5003. }
  5004. function sort(array, compare, lo, hi) {
  5005. if (!lo) {
  5006. lo = 0;
  5007. }
  5008. if (!hi) {
  5009. hi = array.length;
  5010. }
  5011. var remaining = hi - lo;
  5012. if (remaining < 2) {
  5013. return;
  5014. }
  5015. var runLength = 0;
  5016. if (remaining < DEFAULT_MIN_MERGE) {
  5017. runLength = makeAscendingRun(array, lo, hi, compare);
  5018. binaryInsertionSort(array, lo, hi, lo + runLength, compare);
  5019. return;
  5020. }
  5021. var ts = new TimSort(array, compare);
  5022. var minRun = minRunLength(remaining);
  5023. do {
  5024. runLength = makeAscendingRun(array, lo, hi, compare);
  5025. if (runLength < minRun) {
  5026. var force = remaining;
  5027. if (force > minRun) {
  5028. force = minRun;
  5029. }
  5030. binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
  5031. runLength = force;
  5032. }
  5033. ts.pushRun(lo, runLength);
  5034. ts.mergeRuns();
  5035. remaining -= runLength;
  5036. lo += runLength;
  5037. } while (remaining !== 0);
  5038. ts.forceMergeRuns();
  5039. }
  5040. /**
  5041. * Storage内容仓库模块
  5042. * @module zrender/Storage
  5043. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  5044. * @author errorrik (errorrik@gmail.com)
  5045. * @author pissang (https://github.com/pissang/)
  5046. */
  5047. // Use timsort because in most case elements are partially sorted
  5048. // https://jsfiddle.net/pissang/jr4x7mdm/8/
  5049. function shapeCompareFunc(a, b) {
  5050. if (a.zlevel === b.zlevel) {
  5051. if (a.z === b.z) {
  5052. // if (a.z2 === b.z2) {
  5053. // // FIXME Slow has renderidx compare
  5054. // // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement
  5055. // // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012
  5056. // return a.__renderidx - b.__renderidx;
  5057. // }
  5058. return a.z2 - b.z2;
  5059. }
  5060. return a.z - b.z;
  5061. }
  5062. return a.zlevel - b.zlevel;
  5063. }
  5064. /**
  5065. * 内容仓库 (M)
  5066. * @alias module:zrender/Storage
  5067. * @constructor
  5068. */
  5069. var Storage = function () { // jshint ignore:line
  5070. this._roots = [];
  5071. this._displayList = [];
  5072. this._displayListLen = 0;
  5073. };
  5074. Storage.prototype = {
  5075. constructor: Storage,
  5076. /**
  5077. * @param {Function} cb
  5078. *
  5079. */
  5080. traverse: function (cb, context) {
  5081. for (var i = 0; i < this._roots.length; i++) {
  5082. this._roots[i].traverse(cb, context);
  5083. }
  5084. },
  5085. /**
  5086. * 返回所有图形的绘制队列
  5087. * @param {boolean} [update=false] 是否在返回前更新该数组
  5088. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效
  5089. *
  5090. * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}
  5091. * @return {Array.<module:zrender/graphic/Displayable>}
  5092. */
  5093. getDisplayList: function (update, includeIgnore) {
  5094. includeIgnore = includeIgnore || false;
  5095. if (update) {
  5096. this.updateDisplayList(includeIgnore);
  5097. }
  5098. return this._displayList;
  5099. },
  5100. /**
  5101. * 更新图形的绘制队列。
  5102. * 每次绘制前都会调用,该方法会先深度优先遍历整个树,更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
  5103. * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
  5104. * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组
  5105. */
  5106. updateDisplayList: function (includeIgnore) {
  5107. this._displayListLen = 0;
  5108. var roots = this._roots;
  5109. var displayList = this._displayList;
  5110. for (var i = 0, len = roots.length; i < len; i++) {
  5111. this._updateAndAddDisplayable(roots[i], null, includeIgnore);
  5112. }
  5113. displayList.length = this._displayListLen;
  5114. // for (var i = 0, len = displayList.length; i < len; i++) {
  5115. // displayList[i].__renderidx = i;
  5116. // }
  5117. // displayList.sort(shapeCompareFunc);
  5118. env$1.canvasSupported && sort(displayList, shapeCompareFunc);
  5119. },
  5120. _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {
  5121. if (el.ignore && !includeIgnore) {
  5122. return;
  5123. }
  5124. el.beforeUpdate();
  5125. if (el.__dirty) {
  5126. el.update();
  5127. }
  5128. el.afterUpdate();
  5129. var userSetClipPath = el.clipPath;
  5130. if (userSetClipPath) {
  5131. // FIXME 效率影响
  5132. if (clipPaths) {
  5133. clipPaths = clipPaths.slice();
  5134. }
  5135. else {
  5136. clipPaths = [];
  5137. }
  5138. var currentClipPath = userSetClipPath;
  5139. var parentClipPath = el;
  5140. // Recursively add clip path
  5141. while (currentClipPath) {
  5142. // clipPath 的变换是基于使用这个 clipPath 的元素
  5143. currentClipPath.parent = parentClipPath;
  5144. currentClipPath.updateTransform();
  5145. clipPaths.push(currentClipPath);
  5146. parentClipPath = currentClipPath;
  5147. currentClipPath = currentClipPath.clipPath;
  5148. }
  5149. }
  5150. if (el.isGroup) {
  5151. var children = el._children;
  5152. for (var i = 0; i < children.length; i++) {
  5153. var child = children[i];
  5154. // Force to mark as dirty if group is dirty
  5155. // FIXME __dirtyPath ?
  5156. if (el.__dirty) {
  5157. child.__dirty = true;
  5158. }
  5159. this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
  5160. }
  5161. // Mark group clean here
  5162. el.__dirty = false;
  5163. }
  5164. else {
  5165. el.__clipPaths = clipPaths;
  5166. this._displayList[this._displayListLen++] = el;
  5167. }
  5168. },
  5169. /**
  5170. * 添加图形(Shape)或者组(Group)到根节点
  5171. * @param {module:zrender/Element} el
  5172. */
  5173. addRoot: function (el) {
  5174. if (el.__storage === this) {
  5175. return;
  5176. }
  5177. if (el instanceof Group) {
  5178. el.addChildrenToStorage(this);
  5179. }
  5180. this.addToStorage(el);
  5181. this._roots.push(el);
  5182. },
  5183. /**
  5184. * 删除指定的图形(Shape)或者组(Group)
  5185. * @param {string|Array.<string>} [el] 如果为空清空整个Storage
  5186. */
  5187. delRoot: function (el) {
  5188. if (el == null) {
  5189. // 不指定el清空
  5190. for (var i = 0; i < this._roots.length; i++) {
  5191. var root = this._roots[i];
  5192. if (root instanceof Group) {
  5193. root.delChildrenFromStorage(this);
  5194. }
  5195. }
  5196. this._roots = [];
  5197. this._displayList = [];
  5198. this._displayListLen = 0;
  5199. return;
  5200. }
  5201. if (el instanceof Array) {
  5202. for (var i = 0, l = el.length; i < l; i++) {
  5203. this.delRoot(el[i]);
  5204. }
  5205. return;
  5206. }
  5207. var idx = indexOf(this._roots, el);
  5208. if (idx >= 0) {
  5209. this.delFromStorage(el);
  5210. this._roots.splice(idx, 1);
  5211. if (el instanceof Group) {
  5212. el.delChildrenFromStorage(this);
  5213. }
  5214. }
  5215. },
  5216. addToStorage: function (el) {
  5217. el.__storage = this;
  5218. el.dirty(false);
  5219. return this;
  5220. },
  5221. delFromStorage: function (el) {
  5222. if (el) {
  5223. el.__storage = null;
  5224. }
  5225. return this;
  5226. },
  5227. /**
  5228. * 清空并且释放Storage
  5229. */
  5230. dispose: function () {
  5231. this._renderList =
  5232. this._roots = null;
  5233. },
  5234. displayableSortFunc: shapeCompareFunc
  5235. };
  5236. var STYLE_COMMON_PROPS = [
  5237. ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],
  5238. ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]
  5239. ];
  5240. // var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);
  5241. // var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);
  5242. var Style = function (opts, host) {
  5243. this.extendFrom(opts, false);
  5244. this.host = host;
  5245. };
  5246. function createLinearGradient(ctx, obj, rect) {
  5247. var x = obj.x == null ? 0 : obj.x;
  5248. var x2 = obj.x2 == null ? 1 : obj.x2;
  5249. var y = obj.y == null ? 0 : obj.y;
  5250. var y2 = obj.y2 == null ? 0 : obj.y2;
  5251. if (!obj.global) {
  5252. x = x * rect.width + rect.x;
  5253. x2 = x2 * rect.width + rect.x;
  5254. y = y * rect.height + rect.y;
  5255. y2 = y2 * rect.height + rect.y;
  5256. }
  5257. var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
  5258. return canvasGradient;
  5259. }
  5260. function createRadialGradient(ctx, obj, rect) {
  5261. var width = rect.width;
  5262. var height = rect.height;
  5263. var min = Math.min(width, height);
  5264. var x = obj.x == null ? 0.5 : obj.x;
  5265. var y = obj.y == null ? 0.5 : obj.y;
  5266. var r = obj.r == null ? 0.5 : obj.r;
  5267. if (!obj.global) {
  5268. x = x * width + rect.x;
  5269. y = y * height + rect.y;
  5270. r = r * min;
  5271. }
  5272. var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
  5273. return canvasGradient;
  5274. }
  5275. Style.prototype = {
  5276. constructor: Style,
  5277. /**
  5278. * @type {module:zrender/graphic/Displayable}
  5279. */
  5280. host: null,
  5281. /**
  5282. * @type {string}
  5283. */
  5284. fill: '#000',
  5285. /**
  5286. * @type {string}
  5287. */
  5288. stroke: null,
  5289. /**
  5290. * @type {number}
  5291. */
  5292. opacity: 1,
  5293. /**
  5294. * @type {Array.<number>}
  5295. */
  5296. lineDash: null,
  5297. /**
  5298. * @type {number}
  5299. */
  5300. lineDashOffset: 0,
  5301. /**
  5302. * @type {number}
  5303. */
  5304. shadowBlur: 0,
  5305. /**
  5306. * @type {number}
  5307. */
  5308. shadowOffsetX: 0,
  5309. /**
  5310. * @type {number}
  5311. */
  5312. shadowOffsetY: 0,
  5313. /**
  5314. * @type {number}
  5315. */
  5316. lineWidth: 1,
  5317. /**
  5318. * If stroke ignore scale
  5319. * @type {Boolean}
  5320. */
  5321. strokeNoScale: false,
  5322. // Bounding rect text configuration
  5323. // Not affected by element transform
  5324. /**
  5325. * @type {string}
  5326. */
  5327. text: null,
  5328. /**
  5329. * If `fontSize` or `fontFamily` exists, `font` will be reset by
  5330. * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.
  5331. * So do not visit it directly in upper application (like echarts),
  5332. * but use `contain/text#makeFont` instead.
  5333. * @type {string}
  5334. */
  5335. font: null,
  5336. /**
  5337. * The same as font. Use font please.
  5338. * @deprecated
  5339. * @type {string}
  5340. */
  5341. textFont: null,
  5342. /**
  5343. * It helps merging respectively, rather than parsing an entire font string.
  5344. * @type {string}
  5345. */
  5346. fontStyle: null,
  5347. /**
  5348. * It helps merging respectively, rather than parsing an entire font string.
  5349. * @type {string}
  5350. */
  5351. fontWeight: null,
  5352. /**
  5353. * It helps merging respectively, rather than parsing an entire font string.
  5354. * Should be 12 but not '12px'.
  5355. * @type {number}
  5356. */
  5357. fontSize: null,
  5358. /**
  5359. * It helps merging respectively, rather than parsing an entire font string.
  5360. * @type {string}
  5361. */
  5362. fontFamily: null,
  5363. /**
  5364. * Reserved for special functinality, like 'hr'.
  5365. * @type {string}
  5366. */
  5367. textTag: null,
  5368. /**
  5369. * @type {string}
  5370. */
  5371. textFill: '#000',
  5372. /**
  5373. * @type {string}
  5374. */
  5375. textStroke: null,
  5376. /**
  5377. * @type {number}
  5378. */
  5379. textWidth: null,
  5380. /**
  5381. * Only for textBackground.
  5382. * @type {number}
  5383. */
  5384. textHeight: null,
  5385. /**
  5386. * textStroke may be set as some color as a default
  5387. * value in upper applicaion, where the default value
  5388. * of textStrokeWidth should be 0 to make sure that
  5389. * user can choose to do not use text stroke.
  5390. * @type {number}
  5391. */
  5392. textStrokeWidth: 0,
  5393. /**
  5394. * @type {number}
  5395. */
  5396. textLineHeight: null,
  5397. /**
  5398. * 'inside', 'left', 'right', 'top', 'bottom'
  5399. * [x, y]
  5400. * Based on x, y of rect.
  5401. * @type {string|Array.<number>}
  5402. * @default 'inside'
  5403. */
  5404. textPosition: 'inside',
  5405. /**
  5406. * If not specified, use the boundingRect of a `displayable`.
  5407. * @type {Object}
  5408. */
  5409. textRect: null,
  5410. /**
  5411. * [x, y]
  5412. * @type {Array.<number>}
  5413. */
  5414. textOffset: null,
  5415. /**
  5416. * @type {string}
  5417. */
  5418. textAlign: null,
  5419. /**
  5420. * @type {string}
  5421. */
  5422. textVerticalAlign: null,
  5423. /**
  5424. * @type {number}
  5425. */
  5426. textDistance: 5,
  5427. /**
  5428. * @type {string}
  5429. */
  5430. textShadowColor: 'transparent',
  5431. /**
  5432. * @type {number}
  5433. */
  5434. textShadowBlur: 0,
  5435. /**
  5436. * @type {number}
  5437. */
  5438. textShadowOffsetX: 0,
  5439. /**
  5440. * @type {number}
  5441. */
  5442. textShadowOffsetY: 0,
  5443. /**
  5444. * @type {string}
  5445. */
  5446. textBoxShadowColor: 'transparent',
  5447. /**
  5448. * @type {number}
  5449. */
  5450. textBoxShadowBlur: 0,
  5451. /**
  5452. * @type {number}
  5453. */
  5454. textBoxShadowOffsetX: 0,
  5455. /**
  5456. * @type {number}
  5457. */
  5458. textBoxShadowOffsetY: 0,
  5459. /**
  5460. * Whether transform text.
  5461. * Only useful in Path and Image element
  5462. * @type {boolean}
  5463. */
  5464. transformText: false,
  5465. /**
  5466. * Text rotate around position of Path or Image
  5467. * Only useful in Path and Image element and transformText is false.
  5468. */
  5469. textRotation: 0,
  5470. /**
  5471. * Text origin of text rotation, like [10, 40].
  5472. * Based on x, y of rect.
  5473. * Useful in label rotation of circular symbol.
  5474. * By default, this origin is textPosition.
  5475. * Can be 'center'.
  5476. * @type {string|Array.<number>}
  5477. */
  5478. textOrigin: null,
  5479. /**
  5480. * @type {string}
  5481. */
  5482. textBackgroundColor: null,
  5483. /**
  5484. * @type {string}
  5485. */
  5486. textBorderColor: null,
  5487. /**
  5488. * @type {number}
  5489. */
  5490. textBorderWidth: 0,
  5491. /**
  5492. * @type {number}
  5493. */
  5494. textBorderRadius: 0,
  5495. /**
  5496. * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`
  5497. * @type {number|Array.<number>}
  5498. */
  5499. textPadding: null,
  5500. /**
  5501. * Text styles for rich text.
  5502. * @type {Object}
  5503. */
  5504. rich: null,
  5505. /**
  5506. * {outerWidth, outerHeight, ellipsis, placeholder}
  5507. * @type {Object}
  5508. */
  5509. truncate: null,
  5510. /**
  5511. * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
  5512. * @type {string}
  5513. */
  5514. blend: null,
  5515. /**
  5516. * @param {CanvasRenderingContext2D} ctx
  5517. */
  5518. bind: function (ctx, el, prevEl) {
  5519. var style = this;
  5520. var prevStyle = prevEl && prevEl.style;
  5521. var firstDraw = !prevStyle;
  5522. for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
  5523. var prop = STYLE_COMMON_PROPS[i];
  5524. var styleName = prop[0];
  5525. if (firstDraw || style[styleName] !== prevStyle[styleName]) {
  5526. // FIXME Invalid property value will cause style leak from previous element.
  5527. ctx[styleName] = style[styleName] || prop[1];
  5528. }
  5529. }
  5530. if ((firstDraw || style.fill !== prevStyle.fill)) {
  5531. ctx.fillStyle = style.fill;
  5532. }
  5533. if ((firstDraw || style.stroke !== prevStyle.stroke)) {
  5534. ctx.strokeStyle = style.stroke;
  5535. }
  5536. if ((firstDraw || style.opacity !== prevStyle.opacity)) {
  5537. ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;
  5538. }
  5539. if ((firstDraw || style.blend !== prevStyle.blend)) {
  5540. ctx.globalCompositeOperation = style.blend || 'source-over';
  5541. }
  5542. if (this.hasStroke()) {
  5543. var lineWidth = style.lineWidth;
  5544. ctx.lineWidth = lineWidth / (
  5545. (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1
  5546. );
  5547. }
  5548. },
  5549. hasFill: function () {
  5550. var fill = this.fill;
  5551. return fill != null && fill !== 'none';
  5552. },
  5553. hasStroke: function () {
  5554. var stroke = this.stroke;
  5555. return stroke != null && stroke !== 'none' && this.lineWidth > 0;
  5556. },
  5557. /**
  5558. * Extend from other style
  5559. * @param {zrender/graphic/Style} otherStyle
  5560. * @param {boolean} overwrite true: overwrirte any way.
  5561. * false: overwrite only when !target.hasOwnProperty
  5562. * others: overwrite when property is not null/undefined.
  5563. */
  5564. extendFrom: function (otherStyle, overwrite) {
  5565. if (otherStyle) {
  5566. for (var name in otherStyle) {
  5567. if (otherStyle.hasOwnProperty(name)
  5568. && (overwrite === true
  5569. || (
  5570. overwrite === false
  5571. ? !this.hasOwnProperty(name)
  5572. : otherStyle[name] != null
  5573. )
  5574. )
  5575. ) {
  5576. this[name] = otherStyle[name];
  5577. }
  5578. }
  5579. }
  5580. },
  5581. /**
  5582. * Batch setting style with a given object
  5583. * @param {Object|string} obj
  5584. * @param {*} [obj]
  5585. */
  5586. set: function (obj, value) {
  5587. if (typeof obj === 'string') {
  5588. this[obj] = value;
  5589. }
  5590. else {
  5591. this.extendFrom(obj, true);
  5592. }
  5593. },
  5594. /**
  5595. * Clone
  5596. * @return {zrender/graphic/Style} [description]
  5597. */
  5598. clone: function () {
  5599. var newStyle = new this.constructor();
  5600. newStyle.extendFrom(this, true);
  5601. return newStyle;
  5602. },
  5603. getGradient: function (ctx, obj, rect) {
  5604. var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;
  5605. var canvasGradient = method(ctx, obj, rect);
  5606. var colorStops = obj.colorStops;
  5607. for (var i = 0; i < colorStops.length; i++) {
  5608. canvasGradient.addColorStop(
  5609. colorStops[i].offset, colorStops[i].color
  5610. );
  5611. }
  5612. return canvasGradient;
  5613. }
  5614. };
  5615. var styleProto = Style.prototype;
  5616. for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {
  5617. var prop = STYLE_COMMON_PROPS[i];
  5618. if (!(prop[0] in styleProto)) {
  5619. styleProto[prop[0]] = prop[1];
  5620. }
  5621. }
  5622. // Provide for others
  5623. Style.getGradient = styleProto.getGradient;
  5624. var Pattern = function (image, repeat) {
  5625. // Should do nothing more in this constructor. Because gradient can be
  5626. // declard by `color: {image: ...}`, where this constructor will not be called.
  5627. this.image = image;
  5628. this.repeat = repeat;
  5629. // Can be cloned
  5630. this.type = 'pattern';
  5631. };
  5632. Pattern.prototype.getCanvasPattern = function (ctx) {
  5633. return ctx.createPattern(this.image, this.repeat || 'repeat');
  5634. };
  5635. /**
  5636. * @module zrender/Layer
  5637. * @author pissang(https://www.github.com/pissang)
  5638. */
  5639. function returnFalse() {
  5640. return false;
  5641. }
  5642. /**
  5643. * 创建dom
  5644. *
  5645. * @inner
  5646. * @param {string} id dom id 待用
  5647. * @param {Painter} painter painter instance
  5648. * @param {number} number
  5649. */
  5650. function createDom(id, painter, dpr) {
  5651. var newDom = createCanvas();
  5652. var width = painter.getWidth();
  5653. var height = painter.getHeight();
  5654. var newDomStyle = newDom.style;
  5655. // 没append呢,请原谅我这样写,清晰~
  5656. newDomStyle.position = 'absolute';
  5657. newDomStyle.left = 0;
  5658. newDomStyle.top = 0;
  5659. newDomStyle.width = width + 'px';
  5660. newDomStyle.height = height + 'px';
  5661. newDom.width = width * dpr;
  5662. newDom.height = height * dpr;
  5663. // id不作为索引用,避免可能造成的重名,定义为私有属性
  5664. newDom.setAttribute('data-zr-dom-id', id);
  5665. return newDom;
  5666. }
  5667. /**
  5668. * @alias module:zrender/Layer
  5669. * @constructor
  5670. * @extends module:zrender/mixin/Transformable
  5671. * @param {string} id
  5672. * @param {module:zrender/Painter} painter
  5673. * @param {number} [dpr]
  5674. */
  5675. var Layer = function(id, painter, dpr) {
  5676. var dom;
  5677. dpr = dpr || devicePixelRatio;
  5678. if (typeof id === 'string') {
  5679. dom = createDom(id, painter, dpr);
  5680. }
  5681. // Not using isDom because in node it will return false
  5682. else if (isObject(id)) {
  5683. dom = id;
  5684. id = dom.id;
  5685. }
  5686. this.id = id;
  5687. this.dom = dom;
  5688. var domStyle = dom.style;
  5689. if (domStyle) { // Not in node
  5690. dom.onselectstart = returnFalse; // 避免页面选中的尴尬
  5691. domStyle['-webkit-user-select'] = 'none';
  5692. domStyle['user-select'] = 'none';
  5693. domStyle['-webkit-touch-callout'] = 'none';
  5694. domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';
  5695. domStyle['padding'] = 0;
  5696. domStyle['margin'] = 0;
  5697. domStyle['border-width'] = 0;
  5698. }
  5699. this.domBack = null;
  5700. this.ctxBack = null;
  5701. this.painter = painter;
  5702. this.config = null;
  5703. // Configs
  5704. /**
  5705. * 每次清空画布的颜色
  5706. * @type {string}
  5707. * @default 0
  5708. */
  5709. this.clearColor = 0;
  5710. /**
  5711. * 是否开启动态模糊
  5712. * @type {boolean}
  5713. * @default false
  5714. */
  5715. this.motionBlur = false;
  5716. /**
  5717. * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
  5718. * @type {number}
  5719. * @default 0.7
  5720. */
  5721. this.lastFrameAlpha = 0.7;
  5722. /**
  5723. * Layer dpr
  5724. * @type {number}
  5725. */
  5726. this.dpr = dpr;
  5727. };
  5728. Layer.prototype = {
  5729. constructor: Layer,
  5730. elCount: 0,
  5731. __dirty: true,
  5732. initContext: function () {
  5733. this.ctx = this.dom.getContext('2d');
  5734. this.ctx.__currentValues = {};
  5735. this.ctx.dpr = this.dpr;
  5736. },
  5737. createBackBuffer: function () {
  5738. var dpr = this.dpr;
  5739. this.domBack = createDom('back-' + this.id, this.painter, dpr);
  5740. this.ctxBack = this.domBack.getContext('2d');
  5741. this.ctxBack.__currentValues = {};
  5742. if (dpr != 1) {
  5743. this.ctxBack.scale(dpr, dpr);
  5744. }
  5745. },
  5746. /**
  5747. * @param {number} width
  5748. * @param {number} height
  5749. */
  5750. resize: function (width, height) {
  5751. var dpr = this.dpr;
  5752. var dom = this.dom;
  5753. var domStyle = dom.style;
  5754. var domBack = this.domBack;
  5755. domStyle.width = width + 'px';
  5756. domStyle.height = height + 'px';
  5757. dom.width = width * dpr;
  5758. dom.height = height * dpr;
  5759. if (domBack) {
  5760. domBack.width = width * dpr;
  5761. domBack.height = height * dpr;
  5762. if (dpr != 1) {
  5763. this.ctxBack.scale(dpr, dpr);
  5764. }
  5765. }
  5766. },
  5767. /**
  5768. * 清空该层画布
  5769. * @param {boolean} clearAll Clear all with out motion blur
  5770. */
  5771. clear: function (clearAll) {
  5772. var dom = this.dom;
  5773. var ctx = this.ctx;
  5774. var width = dom.width;
  5775. var height = dom.height;
  5776. var clearColor = this.clearColor;
  5777. var haveMotionBLur = this.motionBlur && !clearAll;
  5778. var lastFrameAlpha = this.lastFrameAlpha;
  5779. var dpr = this.dpr;
  5780. if (haveMotionBLur) {
  5781. if (!this.domBack) {
  5782. this.createBackBuffer();
  5783. }
  5784. this.ctxBack.globalCompositeOperation = 'copy';
  5785. this.ctxBack.drawImage(
  5786. dom, 0, 0,
  5787. width / dpr,
  5788. height / dpr
  5789. );
  5790. }
  5791. ctx.clearRect(0, 0, width, height);
  5792. if (clearColor) {
  5793. var clearColorGradientOrPattern;
  5794. // Gradient
  5795. if (clearColor.colorStops) {
  5796. // Cache canvas gradient
  5797. clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {
  5798. x: 0,
  5799. y: 0,
  5800. width: width,
  5801. height: height
  5802. });
  5803. clearColor.__canvasGradient = clearColorGradientOrPattern;
  5804. }
  5805. // Pattern
  5806. else if (clearColor.image) {
  5807. clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);
  5808. }
  5809. ctx.save();
  5810. ctx.fillStyle = clearColorGradientOrPattern || clearColor;
  5811. ctx.fillRect(0, 0, width, height);
  5812. ctx.restore();
  5813. }
  5814. if (haveMotionBLur) {
  5815. var domBack = this.domBack;
  5816. ctx.save();
  5817. ctx.globalAlpha = lastFrameAlpha;
  5818. ctx.drawImage(domBack, 0, 0, width, height);
  5819. ctx.restore();
  5820. }
  5821. }
  5822. };
  5823. var requestAnimationFrame = (
  5824. typeof window !== 'undefined'
  5825. && (
  5826. (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))
  5827. // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809
  5828. || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))
  5829. || window.mozRequestAnimationFrame
  5830. || window.webkitRequestAnimationFrame
  5831. )
  5832. ) || function (func) {
  5833. setTimeout(func, 16);
  5834. };
  5835. var globalImageCache = new LRU(50);
  5836. /**
  5837. * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc
  5838. * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image
  5839. */
  5840. function findExistImage(newImageOrSrc) {
  5841. if (typeof newImageOrSrc === 'string') {
  5842. var cachedImgObj = globalImageCache.get(newImageOrSrc);
  5843. return cachedImgObj && cachedImgObj.image;
  5844. }
  5845. else {
  5846. return newImageOrSrc;
  5847. }
  5848. }
  5849. /**
  5850. * Caution: User should cache loaded images, but not just count on LRU.
  5851. * Consider if required images more than LRU size, will dead loop occur?
  5852. *
  5853. * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc
  5854. * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.
  5855. * @param {module:zrender/Element} [hostEl] For calling `dirty`.
  5856. * @param {Function} [cb] params: (image, cbPayload)
  5857. * @param {Object} [cbPayload] Payload on cb calling.
  5858. * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image
  5859. */
  5860. function createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {
  5861. if (!newImageOrSrc) {
  5862. return image;
  5863. }
  5864. else if (typeof newImageOrSrc === 'string') {
  5865. // Image should not be loaded repeatly.
  5866. if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {
  5867. return image;
  5868. }
  5869. // Only when there is no existent image or existent image src
  5870. // is different, this method is responsible for load.
  5871. var cachedImgObj = globalImageCache.get(newImageOrSrc);
  5872. var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};
  5873. if (cachedImgObj) {
  5874. image = cachedImgObj.image;
  5875. !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);
  5876. }
  5877. else {
  5878. !image && (image = new Image());
  5879. image.onload = imageOnLoad;
  5880. globalImageCache.put(
  5881. newImageOrSrc,
  5882. image.__cachedImgObj = {
  5883. image: image,
  5884. pending: [pendingWrap]
  5885. }
  5886. );
  5887. image.src = image.__zrImageSrc = newImageOrSrc;
  5888. }
  5889. return image;
  5890. }
  5891. // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas
  5892. else {
  5893. return newImageOrSrc;
  5894. }
  5895. }
  5896. function imageOnLoad() {
  5897. var cachedImgObj = this.__cachedImgObj;
  5898. this.onload = this.__cachedImgObj = null;
  5899. for (var i = 0; i < cachedImgObj.pending.length; i++) {
  5900. var pendingWrap = cachedImgObj.pending[i];
  5901. var cb = pendingWrap.cb;
  5902. cb && cb(this, pendingWrap.cbPayload);
  5903. pendingWrap.hostEl.dirty();
  5904. }
  5905. cachedImgObj.pending.length = 0;
  5906. }
  5907. function isImageReady(image) {
  5908. return image && image.width && image.height;
  5909. }
  5910. var textWidthCache = {};
  5911. var textWidthCacheCounter = 0;
  5912. var TEXT_CACHE_MAX = 5000;
  5913. var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;
  5914. var DEFAULT_FONT = '12px sans-serif';
  5915. // Avoid assign to an exported variable, for transforming to cjs.
  5916. var methods$1 = {};
  5917. function $override$1(name, fn) {
  5918. methods$1[name] = fn;
  5919. }
  5920. /**
  5921. * @public
  5922. * @param {string} text
  5923. * @param {string} font
  5924. * @return {number} width
  5925. */
  5926. function getWidth(text, font) {
  5927. font = font || DEFAULT_FONT;
  5928. var key = text + ':' + font;
  5929. if (textWidthCache[key]) {
  5930. return textWidthCache[key];
  5931. }
  5932. var textLines = (text + '').split('\n');
  5933. var width = 0;
  5934. for (var i = 0, l = textLines.length; i < l; i++) {
  5935. // textContain.measureText may be overrided in SVG or VML
  5936. width = Math.max(measureText(textLines[i], font).width, width);
  5937. }
  5938. if (textWidthCacheCounter > TEXT_CACHE_MAX) {
  5939. textWidthCacheCounter = 0;
  5940. textWidthCache = {};
  5941. }
  5942. textWidthCacheCounter++;
  5943. textWidthCache[key] = width;
  5944. return width;
  5945. }
  5946. /**
  5947. * @public
  5948. * @param {string} text
  5949. * @param {string} font
  5950. * @param {string} [textAlign='left']
  5951. * @param {string} [textVerticalAlign='top']
  5952. * @param {Array.<number>} [textPadding]
  5953. * @param {Object} [rich]
  5954. * @param {Object} [truncate]
  5955. * @return {Object} {x, y, width, height, lineHeight}
  5956. */
  5957. function getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, rich, truncate) {
  5958. return rich
  5959. ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, rich, truncate)
  5960. : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, truncate);
  5961. }
  5962. function getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, truncate) {
  5963. var contentBlock = parsePlainText(text, font, textPadding, truncate);
  5964. var outerWidth = getWidth(text, font);
  5965. if (textPadding) {
  5966. outerWidth += textPadding[1] + textPadding[3];
  5967. }
  5968. var outerHeight = contentBlock.outerHeight;
  5969. var x = adjustTextX(0, outerWidth, textAlign);
  5970. var y = adjustTextY(0, outerHeight, textVerticalAlign);
  5971. var rect = new BoundingRect(x, y, outerWidth, outerHeight);
  5972. rect.lineHeight = contentBlock.lineHeight;
  5973. return rect;
  5974. }
  5975. function getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, rich, truncate) {
  5976. var contentBlock = parseRichText(text, {
  5977. rich: rich,
  5978. truncate: truncate,
  5979. font: font,
  5980. textAlign: textAlign,
  5981. textPadding: textPadding
  5982. });
  5983. var outerWidth = contentBlock.outerWidth;
  5984. var outerHeight = contentBlock.outerHeight;
  5985. var x = adjustTextX(0, outerWidth, textAlign);
  5986. var y = adjustTextY(0, outerHeight, textVerticalAlign);
  5987. return new BoundingRect(x, y, outerWidth, outerHeight);
  5988. }
  5989. /**
  5990. * @public
  5991. * @param {number} x
  5992. * @param {number} width
  5993. * @param {string} [textAlign='left']
  5994. * @return {number} Adjusted x.
  5995. */
  5996. function adjustTextX(x, width, textAlign) {
  5997. // FIXME Right to left language
  5998. if (textAlign === 'right') {
  5999. x -= width;
  6000. }
  6001. else if (textAlign === 'center') {
  6002. x -= width / 2;
  6003. }
  6004. return x;
  6005. }
  6006. /**
  6007. * @public
  6008. * @param {number} y
  6009. * @param {number} height
  6010. * @param {string} [textVerticalAlign='top']
  6011. * @return {number} Adjusted y.
  6012. */
  6013. function adjustTextY(y, height, textVerticalAlign) {
  6014. if (textVerticalAlign === 'middle') {
  6015. y -= height / 2;
  6016. }
  6017. else if (textVerticalAlign === 'bottom') {
  6018. y -= height;
  6019. }
  6020. return y;
  6021. }
  6022. /**
  6023. * @public
  6024. * @param {stirng} textPosition
  6025. * @param {Object} rect {x, y, width, height}
  6026. * @param {number} distance
  6027. * @return {Object} {x, y, textAlign, textVerticalAlign}
  6028. */
  6029. function adjustTextPositionOnRect(textPosition, rect, distance) {
  6030. var x = rect.x;
  6031. var y = rect.y;
  6032. var height = rect.height;
  6033. var width = rect.width;
  6034. var halfHeight = height / 2;
  6035. var textAlign = 'left';
  6036. var textVerticalAlign = 'top';
  6037. switch (textPosition) {
  6038. case 'left':
  6039. x -= distance;
  6040. y += halfHeight;
  6041. textAlign = 'right';
  6042. textVerticalAlign = 'middle';
  6043. break;
  6044. case 'right':
  6045. x += distance + width;
  6046. y += halfHeight;
  6047. textVerticalAlign = 'middle';
  6048. break;
  6049. case 'top':
  6050. x += width / 2;
  6051. y -= distance;
  6052. textAlign = 'center';
  6053. textVerticalAlign = 'bottom';
  6054. break;
  6055. case 'bottom':
  6056. x += width / 2;
  6057. y += height + distance;
  6058. textAlign = 'center';
  6059. break;
  6060. case 'inside':
  6061. x += width / 2;
  6062. y += halfHeight;
  6063. textAlign = 'center';
  6064. textVerticalAlign = 'middle';
  6065. break;
  6066. case 'insideLeft':
  6067. x += distance;
  6068. y += halfHeight;
  6069. textVerticalAlign = 'middle';
  6070. break;
  6071. case 'insideRight':
  6072. x += width - distance;
  6073. y += halfHeight;
  6074. textAlign = 'right';
  6075. textVerticalAlign = 'middle';
  6076. break;
  6077. case 'insideTop':
  6078. x += width / 2;
  6079. y += distance;
  6080. textAlign = 'center';
  6081. break;
  6082. case 'insideBottom':
  6083. x += width / 2;
  6084. y += height - distance;
  6085. textAlign = 'center';
  6086. textVerticalAlign = 'bottom';
  6087. break;
  6088. case 'insideTopLeft':
  6089. x += distance;
  6090. y += distance;
  6091. break;
  6092. case 'insideTopRight':
  6093. x += width - distance;
  6094. y += distance;
  6095. textAlign = 'right';
  6096. break;
  6097. case 'insideBottomLeft':
  6098. x += distance;
  6099. y += height - distance;
  6100. textVerticalAlign = 'bottom';
  6101. break;
  6102. case 'insideBottomRight':
  6103. x += width - distance;
  6104. y += height - distance;
  6105. textAlign = 'right';
  6106. textVerticalAlign = 'bottom';
  6107. break;
  6108. }
  6109. return {
  6110. x: x,
  6111. y: y,
  6112. textAlign: textAlign,
  6113. textVerticalAlign: textVerticalAlign
  6114. };
  6115. }
  6116. /**
  6117. * Show ellipsis if overflow.
  6118. *
  6119. * @public
  6120. * @param {string} text
  6121. * @param {string} containerWidth
  6122. * @param {string} font
  6123. * @param {number} [ellipsis='...']
  6124. * @param {Object} [options]
  6125. * @param {number} [options.maxIterations=3]
  6126. * @param {number} [options.minChar=0] If truncate result are less
  6127. * then minChar, ellipsis will not show, which is
  6128. * better for user hint in some cases.
  6129. * @param {number} [options.placeholder=''] When all truncated, use the placeholder.
  6130. * @return {string}
  6131. */
  6132. function truncateText(text, containerWidth, font, ellipsis, options) {
  6133. if (!containerWidth) {
  6134. return '';
  6135. }
  6136. var textLines = (text + '').split('\n');
  6137. options = prepareTruncateOptions(containerWidth, font, ellipsis, options);
  6138. // FIXME
  6139. // It is not appropriate that every line has '...' when truncate multiple lines.
  6140. for (var i = 0, len = textLines.length; i < len; i++) {
  6141. textLines[i] = truncateSingleLine(textLines[i], options);
  6142. }
  6143. return textLines.join('\n');
  6144. }
  6145. function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
  6146. options = extend({}, options);
  6147. options.font = font;
  6148. var ellipsis = retrieve2(ellipsis, '...');
  6149. options.maxIterations = retrieve2(options.maxIterations, 2);
  6150. var minChar = options.minChar = retrieve2(options.minChar, 0);
  6151. // FIXME
  6152. // Other languages?
  6153. options.cnCharWidth = getWidth('国', font);
  6154. // FIXME
  6155. // Consider proportional font?
  6156. var ascCharWidth = options.ascCharWidth = getWidth('a', font);
  6157. options.placeholder = retrieve2(options.placeholder, '');
  6158. // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.
  6159. // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.
  6160. var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.
  6161. for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
  6162. contentWidth -= ascCharWidth;
  6163. }
  6164. var ellipsisWidth = getWidth(ellipsis);
  6165. if (ellipsisWidth > contentWidth) {
  6166. ellipsis = '';
  6167. ellipsisWidth = 0;
  6168. }
  6169. contentWidth = containerWidth - ellipsisWidth;
  6170. options.ellipsis = ellipsis;
  6171. options.ellipsisWidth = ellipsisWidth;
  6172. options.contentWidth = contentWidth;
  6173. options.containerWidth = containerWidth;
  6174. return options;
  6175. }
  6176. function truncateSingleLine(textLine, options) {
  6177. var containerWidth = options.containerWidth;
  6178. var font = options.font;
  6179. var contentWidth = options.contentWidth;
  6180. if (!containerWidth) {
  6181. return '';
  6182. }
  6183. var lineWidth = getWidth(textLine, font);
  6184. if (lineWidth <= containerWidth) {
  6185. return textLine;
  6186. }
  6187. for (var j = 0;; j++) {
  6188. if (lineWidth <= contentWidth || j >= options.maxIterations) {
  6189. textLine += options.ellipsis;
  6190. break;
  6191. }
  6192. var subLength = j === 0
  6193. ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)
  6194. : lineWidth > 0
  6195. ? Math.floor(textLine.length * contentWidth / lineWidth)
  6196. : 0;
  6197. textLine = textLine.substr(0, subLength);
  6198. lineWidth = getWidth(textLine, font);
  6199. }
  6200. if (textLine === '') {
  6201. textLine = options.placeholder;
  6202. }
  6203. return textLine;
  6204. }
  6205. function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
  6206. var width = 0;
  6207. var i = 0;
  6208. for (var len = text.length; i < len && width < contentWidth; i++) {
  6209. var charCode = text.charCodeAt(i);
  6210. width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;
  6211. }
  6212. return i;
  6213. }
  6214. /**
  6215. * @public
  6216. * @param {string} font
  6217. * @return {number} line height
  6218. */
  6219. function getLineHeight(font) {
  6220. // FIXME A rough approach.
  6221. return getWidth('国', font);
  6222. }
  6223. /**
  6224. * @public
  6225. * @param {string} text
  6226. * @param {string} font
  6227. * @return {Object} width
  6228. */
  6229. function measureText(text, font) {
  6230. return methods$1.measureText(text, font);
  6231. }
  6232. // Avoid assign to an exported variable, for transforming to cjs.
  6233. methods$1.measureText = function (text, font) {
  6234. var ctx = getContext();
  6235. ctx.font = font || DEFAULT_FONT;
  6236. return ctx.measureText(text);
  6237. };
  6238. /**
  6239. * @public
  6240. * @param {string} text
  6241. * @param {string} font
  6242. * @param {Object} [truncate]
  6243. * @return {Object} block: {lineHeight, lines, height, outerHeight}
  6244. * Notice: for performance, do not calculate outerWidth util needed.
  6245. */
  6246. function parsePlainText(text, font, padding, truncate) {
  6247. text != null && (text += '');
  6248. var lineHeight = getLineHeight(font);
  6249. var lines = text ? text.split('\n') : [];
  6250. var height = lines.length * lineHeight;
  6251. var outerHeight = height;
  6252. if (padding) {
  6253. outerHeight += padding[0] + padding[2];
  6254. }
  6255. if (text && truncate) {
  6256. var truncOuterHeight = truncate.outerHeight;
  6257. var truncOuterWidth = truncate.outerWidth;
  6258. if (truncOuterHeight != null && outerHeight > truncOuterHeight) {
  6259. text = '';
  6260. lines = [];
  6261. }
  6262. else if (truncOuterWidth != null) {
  6263. var options = prepareTruncateOptions(
  6264. truncOuterWidth - (padding ? padding[1] + padding[3] : 0),
  6265. font,
  6266. truncate.ellipsis,
  6267. {minChar: truncate.minChar, placeholder: truncate.placeholder}
  6268. );
  6269. // FIXME
  6270. // It is not appropriate that every line has '...' when truncate multiple lines.
  6271. for (var i = 0, len = lines.length; i < len; i++) {
  6272. lines[i] = truncateSingleLine(lines[i], options);
  6273. }
  6274. }
  6275. }
  6276. return {
  6277. lines: lines,
  6278. height: height,
  6279. outerHeight: outerHeight,
  6280. lineHeight: lineHeight
  6281. };
  6282. }
  6283. /**
  6284. * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'
  6285. * Also consider 'bbbb{a|xxx\nzzz}xxxx\naaaa'.
  6286. *
  6287. * @public
  6288. * @param {string} text
  6289. * @param {Object} style
  6290. * @return {Object} block
  6291. * {
  6292. * width,
  6293. * height,
  6294. * lines: [{
  6295. * lineHeight,
  6296. * width,
  6297. * tokens: [[{
  6298. * styleName,
  6299. * text,
  6300. * width, // include textPadding
  6301. * height, // include textPadding
  6302. * textWidth, // pure text width
  6303. * textHeight, // pure text height
  6304. * lineHeihgt,
  6305. * font,
  6306. * textAlign,
  6307. * textVerticalAlign
  6308. * }], [...], ...]
  6309. * }, ...]
  6310. * }
  6311. * If styleName is undefined, it is plain text.
  6312. */
  6313. function parseRichText(text, style) {
  6314. var contentBlock = {lines: [], width: 0, height: 0};
  6315. text != null && (text += '');
  6316. if (!text) {
  6317. return contentBlock;
  6318. }
  6319. var lastIndex = STYLE_REG.lastIndex = 0;
  6320. var result;
  6321. while ((result = STYLE_REG.exec(text)) != null) {
  6322. var matchedIndex = result.index;
  6323. if (matchedIndex > lastIndex) {
  6324. pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));
  6325. }
  6326. pushTokens(contentBlock, result[2], result[1]);
  6327. lastIndex = STYLE_REG.lastIndex;
  6328. }
  6329. if (lastIndex < text.length) {
  6330. pushTokens(contentBlock, text.substring(lastIndex, text.length));
  6331. }
  6332. var lines = contentBlock.lines;
  6333. var contentHeight = 0;
  6334. var contentWidth = 0;
  6335. // For `textWidth: 100%`
  6336. var pendingList = [];
  6337. var stlPadding = style.textPadding;
  6338. var truncate = style.truncate;
  6339. var truncateWidth = truncate && truncate.outerWidth;
  6340. var truncateHeight = truncate && truncate.outerHeight;
  6341. if (stlPadding) {
  6342. truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);
  6343. truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);
  6344. }
  6345. // Calculate layout info of tokens.
  6346. for (var i = 0; i < lines.length; i++) {
  6347. var line = lines[i];
  6348. var lineHeight = 0;
  6349. var lineWidth = 0;
  6350. for (var j = 0; j < line.tokens.length; j++) {
  6351. var token = line.tokens[j];
  6352. var tokenStyle = token.styleName && style.rich[token.styleName] || {};
  6353. // textPadding should not inherit from style.
  6354. var textPadding = token.textPadding = tokenStyle.textPadding;
  6355. // textFont has been asigned to font by `normalizeStyle`.
  6356. var font = token.font = tokenStyle.font || style.font;
  6357. // textHeight can be used when textVerticalAlign is specified in token.
  6358. var tokenHeight = token.textHeight = retrieve2(
  6359. // textHeight should not be inherited, consider it can be specified
  6360. // as box height of the block.
  6361. tokenStyle.textHeight, getLineHeight(font)
  6362. );
  6363. textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
  6364. token.height = tokenHeight;
  6365. token.lineHeight = retrieve3(
  6366. tokenStyle.textLineHeight, style.textLineHeight, tokenHeight
  6367. );
  6368. token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;
  6369. token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';
  6370. if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {
  6371. return {lines: [], width: 0, height: 0};
  6372. }
  6373. token.textWidth = getWidth(token.text, font);
  6374. var tokenWidth = tokenStyle.textWidth;
  6375. var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';
  6376. // Percent width, can be `100%`, can be used in drawing separate
  6377. // line when box width is needed to be auto.
  6378. if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {
  6379. token.percentWidth = tokenWidth;
  6380. pendingList.push(token);
  6381. tokenWidth = 0;
  6382. // Do not truncate in this case, because there is no user case
  6383. // and it is too complicated.
  6384. }
  6385. else {
  6386. if (tokenWidthNotSpecified) {
  6387. tokenWidth = token.textWidth;
  6388. // FIXME: If image is not loaded and textWidth is not specified, calling
  6389. // `getBoundingRect()` will not get correct result.
  6390. var textBackgroundColor = tokenStyle.textBackgroundColor;
  6391. var bgImg = textBackgroundColor && textBackgroundColor.image;
  6392. // Use cases:
  6393. // (1) If image is not loaded, it will be loaded at render phase and call
  6394. // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded
  6395. // image, and then the right size will be calculated here at the next tick.
  6396. // See `graphic/helper/text.js`.
  6397. // (2) If image loaded, and `textBackgroundColor.image` is image src string,
  6398. // use `imageHelper.findExistImage` to find cached image.
  6399. // `imageHelper.findExistImage` will always be called here before
  6400. // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`
  6401. // which ensures that image will not be rendered before correct size calcualted.
  6402. if (bgImg) {
  6403. bgImg = findExistImage(bgImg);
  6404. if (isImageReady(bgImg)) {
  6405. tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);
  6406. }
  6407. }
  6408. }
  6409. var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;
  6410. tokenWidth += paddingW;
  6411. var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;
  6412. if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {
  6413. if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {
  6414. token.text = '';
  6415. token.textWidth = tokenWidth = 0;
  6416. }
  6417. else {
  6418. token.text = truncateText(
  6419. token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,
  6420. {minChar: truncate.minChar}
  6421. );
  6422. token.textWidth = getWidth(token.text, font);
  6423. tokenWidth = token.textWidth + paddingW;
  6424. }
  6425. }
  6426. }
  6427. lineWidth += (token.width = tokenWidth);
  6428. tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));
  6429. }
  6430. line.width = lineWidth;
  6431. line.lineHeight = lineHeight;
  6432. contentHeight += lineHeight;
  6433. contentWidth = Math.max(contentWidth, lineWidth);
  6434. }
  6435. contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);
  6436. contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);
  6437. if (stlPadding) {
  6438. contentBlock.outerWidth += stlPadding[1] + stlPadding[3];
  6439. contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
  6440. }
  6441. for (var i = 0; i < pendingList.length; i++) {
  6442. var token = pendingList[i];
  6443. var percentWidth = token.percentWidth;
  6444. // Should not base on outerWidth, because token can not be placed out of padding.
  6445. token.width = parseInt(percentWidth, 10) / 100 * contentWidth;
  6446. }
  6447. return contentBlock;
  6448. }
  6449. function pushTokens(block, str, styleName) {
  6450. var isEmptyStr = str === '';
  6451. var strs = str.split('\n');
  6452. var lines = block.lines;
  6453. for (var i = 0; i < strs.length; i++) {
  6454. var text = strs[i];
  6455. var token = {
  6456. styleName: styleName,
  6457. text: text,
  6458. isLineHolder: !text && !isEmptyStr
  6459. };
  6460. // The first token should be appended to the last line.
  6461. if (!i) {
  6462. var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;
  6463. // Consider cases:
  6464. // (1) ''.split('\n') => ['', '\n', ''], the '' at the first item
  6465. // (which is a placeholder) should be replaced by new token.
  6466. // (2) A image backage, where token likes {a|}.
  6467. // (3) A redundant '' will affect textAlign in line.
  6468. // (4) tokens with the same tplName should not be merged, because
  6469. // they should be displayed in different box (with border and padding).
  6470. var tokensLen = tokens.length;
  6471. (tokensLen === 1 && tokens[0].isLineHolder)
  6472. ? (tokens[0] = token)
  6473. // Consider text is '', only insert when it is the "lineHolder" or
  6474. // "emptyStr". Otherwise a redundant '' will affect textAlign in line.
  6475. : ((text || !tokensLen || isEmptyStr) && tokens.push(token));
  6476. }
  6477. // Other tokens always start a new line.
  6478. else {
  6479. // If there is '', insert it as a placeholder.
  6480. lines.push({tokens: [token]});
  6481. }
  6482. }
  6483. }
  6484. function makeFont(style) {
  6485. // FIXME in node-canvas fontWeight is before fontStyle
  6486. // Use `fontSize` `fontFamily` to check whether font properties are defined.
  6487. return (style.fontSize || style.fontFamily) && [
  6488. style.fontStyle,
  6489. style.fontWeight,
  6490. (style.fontSize || 12) + 'px',
  6491. // If font properties are defined, `fontFamily` should not be ignored.
  6492. style.fontFamily || 'sans-serif'
  6493. ].join(' ') || style.textFont || style.font;
  6494. }
  6495. function buildPath(ctx, shape) {
  6496. var x = shape.x;
  6497. var y = shape.y;
  6498. var width = shape.width;
  6499. var height = shape.height;
  6500. var r = shape.r;
  6501. var r1;
  6502. var r2;
  6503. var r3;
  6504. var r4;
  6505. // Convert width and height to positive for better borderRadius
  6506. if (width < 0) {
  6507. x = x + width;
  6508. width = -width;
  6509. }
  6510. if (height < 0) {
  6511. y = y + height;
  6512. height = -height;
  6513. }
  6514. if (typeof r === 'number') {
  6515. r1 = r2 = r3 = r4 = r;
  6516. }
  6517. else if (r instanceof Array) {
  6518. if (r.length === 1) {
  6519. r1 = r2 = r3 = r4 = r[0];
  6520. }
  6521. else if (r.length === 2) {
  6522. r1 = r3 = r[0];
  6523. r2 = r4 = r[1];
  6524. }
  6525. else if (r.length === 3) {
  6526. r1 = r[0];
  6527. r2 = r4 = r[1];
  6528. r3 = r[2];
  6529. }
  6530. else {
  6531. r1 = r[0];
  6532. r2 = r[1];
  6533. r3 = r[2];
  6534. r4 = r[3];
  6535. }
  6536. }
  6537. else {
  6538. r1 = r2 = r3 = r4 = 0;
  6539. }
  6540. var total;
  6541. if (r1 + r2 > width) {
  6542. total = r1 + r2;
  6543. r1 *= width / total;
  6544. r2 *= width / total;
  6545. }
  6546. if (r3 + r4 > width) {
  6547. total = r3 + r4;
  6548. r3 *= width / total;
  6549. r4 *= width / total;
  6550. }
  6551. if (r2 + r3 > height) {
  6552. total = r2 + r3;
  6553. r2 *= height / total;
  6554. r3 *= height / total;
  6555. }
  6556. if (r1 + r4 > height) {
  6557. total = r1 + r4;
  6558. r1 *= height / total;
  6559. r4 *= height / total;
  6560. }
  6561. ctx.moveTo(x + r1, y);
  6562. ctx.lineTo(x + width - r2, y);
  6563. r2 !== 0 && ctx.quadraticCurveTo(
  6564. x + width, y, x + width, y + r2
  6565. );
  6566. ctx.lineTo(x + width, y + height - r3);
  6567. r3 !== 0 && ctx.quadraticCurveTo(
  6568. x + width, y + height, x + width - r3, y + height
  6569. );
  6570. ctx.lineTo(x + r4, y + height);
  6571. r4 !== 0 && ctx.quadraticCurveTo(
  6572. x, y + height, x, y + height - r4
  6573. );
  6574. ctx.lineTo(x, y + r1);
  6575. r1 !== 0 && ctx.quadraticCurveTo(x, y, x + r1, y);
  6576. }
  6577. // TODO: Have not support 'start', 'end' yet.
  6578. var VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};
  6579. var VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};
  6580. /**
  6581. * @param {module:zrender/graphic/Style} style
  6582. * @return {module:zrender/graphic/Style} The input style.
  6583. */
  6584. function normalizeTextStyle(style) {
  6585. normalizeStyle(style);
  6586. each(style.rich, normalizeStyle);
  6587. return style;
  6588. }
  6589. function normalizeStyle(style) {
  6590. if (style) {
  6591. style.font = makeFont(style);
  6592. var textAlign = style.textAlign;
  6593. textAlign === 'middle' && (textAlign = 'center');
  6594. style.textAlign = (
  6595. textAlign == null || VALID_TEXT_ALIGN[textAlign]
  6596. ) ? textAlign : 'left';
  6597. // Compatible with textBaseline.
  6598. var textVerticalAlign = style.textVerticalAlign || style.textBaseline;
  6599. textVerticalAlign === 'center' && (textVerticalAlign = 'middle');
  6600. style.textVerticalAlign = (
  6601. textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]
  6602. ) ? textVerticalAlign : 'top';
  6603. var textPadding = style.textPadding;
  6604. if (textPadding) {
  6605. style.textPadding = normalizeCssArray(style.textPadding);
  6606. }
  6607. }
  6608. }
  6609. /**
  6610. * @param {CanvasRenderingContext2D} ctx
  6611. * @param {string} text
  6612. * @param {module:zrender/graphic/Style} style
  6613. * @param {Object|boolean} [rect] {x, y, width, height}
  6614. * If set false, rect text is not used.
  6615. */
  6616. function renderText(hostEl, ctx, text, style, rect) {
  6617. style.rich
  6618. ? renderRichText(hostEl, ctx, text, style, rect)
  6619. : renderPlainText(hostEl, ctx, text, style, rect);
  6620. }
  6621. function renderPlainText(hostEl, ctx, text, style, rect) {
  6622. var font = setCtx(ctx, 'font', style.font || DEFAULT_FONT);
  6623. var textPadding = style.textPadding;
  6624. var contentBlock = hostEl.__textCotentBlock;
  6625. if (!contentBlock || hostEl.__dirty) {
  6626. contentBlock = hostEl.__textCotentBlock = parsePlainText(
  6627. text, font, textPadding, style.truncate
  6628. );
  6629. }
  6630. var outerHeight = contentBlock.outerHeight;
  6631. var textLines = contentBlock.lines;
  6632. var lineHeight = contentBlock.lineHeight;
  6633. var boxPos = getBoxPosition(outerHeight, style, rect);
  6634. var baseX = boxPos.baseX;
  6635. var baseY = boxPos.baseY;
  6636. var textAlign = boxPos.textAlign;
  6637. var textVerticalAlign = boxPos.textVerticalAlign;
  6638. // Origin of textRotation should be the base point of text drawing.
  6639. applyTextRotation(ctx, style, rect, baseX, baseY);
  6640. var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);
  6641. var textX = baseX;
  6642. var textY = boxY;
  6643. var needDrawBg = needDrawBackground(style);
  6644. if (needDrawBg || textPadding) {
  6645. // Consider performance, do not call getTextWidth util necessary.
  6646. var textWidth = getWidth(text, font);
  6647. var outerWidth = textWidth;
  6648. textPadding && (outerWidth += textPadding[1] + textPadding[3]);
  6649. var boxX = adjustTextX(baseX, outerWidth, textAlign);
  6650. needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);
  6651. if (textPadding) {
  6652. textX = getTextXForPadding(baseX, textAlign, textPadding);
  6653. textY += textPadding[0];
  6654. }
  6655. }
  6656. setCtx(ctx, 'textAlign', textAlign || 'left');
  6657. // Force baseline to be "middle". Otherwise, if using "top", the
  6658. // text will offset downward a little bit in font "Microsoft YaHei".
  6659. setCtx(ctx, 'textBaseline', 'middle');
  6660. // Always set shadowBlur and shadowOffset to avoid leak from displayable.
  6661. setCtx(ctx, 'shadowBlur', style.textShadowBlur || 0);
  6662. setCtx(ctx, 'shadowColor', style.textShadowColor || 'transparent');
  6663. setCtx(ctx, 'shadowOffsetX', style.textShadowOffsetX || 0);
  6664. setCtx(ctx, 'shadowOffsetY', style.textShadowOffsetY || 0);
  6665. // `textBaseline` is set as 'middle'.
  6666. textY += lineHeight / 2;
  6667. var textStrokeWidth = style.textStrokeWidth;
  6668. var textStroke = getStroke(style.textStroke, textStrokeWidth);
  6669. var textFill = getFill(style.textFill);
  6670. if (textStroke) {
  6671. setCtx(ctx, 'lineWidth', textStrokeWidth);
  6672. setCtx(ctx, 'strokeStyle', textStroke);
  6673. }
  6674. if (textFill) {
  6675. setCtx(ctx, 'fillStyle', textFill);
  6676. }
  6677. for (var i = 0; i < textLines.length; i++) {
  6678. // Fill after stroke so the outline will not cover the main part.
  6679. textStroke && ctx.strokeText(textLines[i], textX, textY);
  6680. textFill && ctx.fillText(textLines[i], textX, textY);
  6681. textY += lineHeight;
  6682. }
  6683. }
  6684. function renderRichText(hostEl, ctx, text, style, rect) {
  6685. var contentBlock = hostEl.__textCotentBlock;
  6686. if (!contentBlock || hostEl.__dirty) {
  6687. contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);
  6688. }
  6689. drawRichText(hostEl, ctx, contentBlock, style, rect);
  6690. }
  6691. function drawRichText(hostEl, ctx, contentBlock, style, rect) {
  6692. var contentWidth = contentBlock.width;
  6693. var outerWidth = contentBlock.outerWidth;
  6694. var outerHeight = contentBlock.outerHeight;
  6695. var textPadding = style.textPadding;
  6696. var boxPos = getBoxPosition(outerHeight, style, rect);
  6697. var baseX = boxPos.baseX;
  6698. var baseY = boxPos.baseY;
  6699. var textAlign = boxPos.textAlign;
  6700. var textVerticalAlign = boxPos.textVerticalAlign;
  6701. // Origin of textRotation should be the base point of text drawing.
  6702. applyTextRotation(ctx, style, rect, baseX, baseY);
  6703. var boxX = adjustTextX(baseX, outerWidth, textAlign);
  6704. var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);
  6705. var xLeft = boxX;
  6706. var lineTop = boxY;
  6707. if (textPadding) {
  6708. xLeft += textPadding[3];
  6709. lineTop += textPadding[0];
  6710. }
  6711. var xRight = xLeft + contentWidth;
  6712. needDrawBackground(style) && drawBackground(
  6713. hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight
  6714. );
  6715. for (var i = 0; i < contentBlock.lines.length; i++) {
  6716. var line = contentBlock.lines[i];
  6717. var tokens = line.tokens;
  6718. var tokenCount = tokens.length;
  6719. var lineHeight = line.lineHeight;
  6720. var usedWidth = line.width;
  6721. var leftIndex = 0;
  6722. var lineXLeft = xLeft;
  6723. var lineXRight = xRight;
  6724. var rightIndex = tokenCount - 1;
  6725. var token;
  6726. while (
  6727. leftIndex < tokenCount
  6728. && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')
  6729. ) {
  6730. placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');
  6731. usedWidth -= token.width;
  6732. lineXLeft += token.width;
  6733. leftIndex++;
  6734. }
  6735. while (
  6736. rightIndex >= 0
  6737. && (token = tokens[rightIndex], token.textAlign === 'right')
  6738. ) {
  6739. placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');
  6740. usedWidth -= token.width;
  6741. lineXRight -= token.width;
  6742. rightIndex--;
  6743. }
  6744. // The other tokens are placed as textAlign 'center' if there is enough space.
  6745. lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;
  6746. while (leftIndex <= rightIndex) {
  6747. token = tokens[leftIndex];
  6748. // Consider width specified by user, use 'center' rather than 'left'.
  6749. placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');
  6750. lineXLeft += token.width;
  6751. leftIndex++;
  6752. }
  6753. lineTop += lineHeight;
  6754. }
  6755. }
  6756. function applyTextRotation(ctx, style, rect, x, y) {
  6757. // textRotation only apply in RectText.
  6758. if (rect && style.textRotation) {
  6759. var origin = style.textOrigin;
  6760. if (origin === 'center') {
  6761. x = rect.width / 2 + rect.x;
  6762. y = rect.height / 2 + rect.y;
  6763. }
  6764. else if (origin) {
  6765. x = origin[0] + rect.x;
  6766. y = origin[1] + rect.y;
  6767. }
  6768. ctx.translate(x, y);
  6769. // Positive: anticlockwise
  6770. ctx.rotate(-style.textRotation);
  6771. ctx.translate(-x, -y);
  6772. }
  6773. }
  6774. function placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {
  6775. var tokenStyle = style.rich[token.styleName] || {};
  6776. // 'ctx.textBaseline' is always set as 'middle', for sake of
  6777. // the bias of "Microsoft YaHei".
  6778. var textVerticalAlign = token.textVerticalAlign;
  6779. var y = lineTop + lineHeight / 2;
  6780. if (textVerticalAlign === 'top') {
  6781. y = lineTop + token.height / 2;
  6782. }
  6783. else if (textVerticalAlign === 'bottom') {
  6784. y = lineTop + lineHeight - token.height / 2;
  6785. }
  6786. !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(
  6787. hostEl,
  6788. ctx,
  6789. tokenStyle,
  6790. textAlign === 'right'
  6791. ? x - token.width
  6792. : textAlign === 'center'
  6793. ? x - token.width / 2
  6794. : x,
  6795. y - token.height / 2,
  6796. token.width,
  6797. token.height
  6798. );
  6799. var textPadding = token.textPadding;
  6800. if (textPadding) {
  6801. x = getTextXForPadding(x, textAlign, textPadding);
  6802. y -= token.height / 2 - textPadding[2] - token.textHeight / 2;
  6803. }
  6804. setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));
  6805. setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');
  6806. setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));
  6807. setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));
  6808. setCtx(ctx, 'textAlign', textAlign);
  6809. // Force baseline to be "middle". Otherwise, if using "top", the
  6810. // text will offset downward a little bit in font "Microsoft YaHei".
  6811. setCtx(ctx, 'textBaseline', 'middle');
  6812. setCtx(ctx, 'font', token.font || DEFAULT_FONT);
  6813. var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);
  6814. var textFill = getFill(tokenStyle.textFill || style.textFill);
  6815. var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);
  6816. // Fill after stroke so the outline will not cover the main part.
  6817. if (textStroke) {
  6818. setCtx(ctx, 'lineWidth', textStrokeWidth);
  6819. setCtx(ctx, 'strokeStyle', textStroke);
  6820. ctx.strokeText(token.text, x, y);
  6821. }
  6822. if (textFill) {
  6823. setCtx(ctx, 'fillStyle', textFill);
  6824. ctx.fillText(token.text, x, y);
  6825. }
  6826. }
  6827. function needDrawBackground(style) {
  6828. return style.textBackgroundColor
  6829. || (style.textBorderWidth && style.textBorderColor);
  6830. }
  6831. // style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius}
  6832. // shape: {x, y, width, height}
  6833. function drawBackground(hostEl, ctx, style, x, y, width, height) {
  6834. var textBackgroundColor = style.textBackgroundColor;
  6835. var textBorderWidth = style.textBorderWidth;
  6836. var textBorderColor = style.textBorderColor;
  6837. var isPlainBg = isString(textBackgroundColor);
  6838. setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);
  6839. setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');
  6840. setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);
  6841. setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);
  6842. if (isPlainBg || (textBorderWidth && textBorderColor)) {
  6843. ctx.beginPath();
  6844. var textBorderRadius = style.textBorderRadius;
  6845. if (!textBorderRadius) {
  6846. ctx.rect(x, y, width, height);
  6847. }
  6848. else {
  6849. buildPath(ctx, {
  6850. x: x, y: y, width: width, height: height, r: textBorderRadius
  6851. });
  6852. }
  6853. ctx.closePath();
  6854. }
  6855. if (isPlainBg) {
  6856. setCtx(ctx, 'fillStyle', textBackgroundColor);
  6857. ctx.fill();
  6858. }
  6859. else if (isObject(textBackgroundColor)) {
  6860. var image = textBackgroundColor.image;
  6861. image = createOrUpdateImage(
  6862. image, null, hostEl, onBgImageLoaded, textBackgroundColor
  6863. );
  6864. if (image && isImageReady(image)) {
  6865. ctx.drawImage(image, x, y, width, height);
  6866. }
  6867. }
  6868. if (textBorderWidth && textBorderColor) {
  6869. setCtx(ctx, 'lineWidth', textBorderWidth);
  6870. setCtx(ctx, 'strokeStyle', textBorderColor);
  6871. ctx.stroke();
  6872. }
  6873. }
  6874. function onBgImageLoaded(image, textBackgroundColor) {
  6875. // Replace image, so that `contain/text.js#parseRichText`
  6876. // will get correct result in next tick.
  6877. textBackgroundColor.image = image;
  6878. }
  6879. function getBoxPosition(blockHeiht, style, rect) {
  6880. var baseX = style.x || 0;
  6881. var baseY = style.y || 0;
  6882. var textAlign = style.textAlign;
  6883. var textVerticalAlign = style.textVerticalAlign;
  6884. // Text position represented by coord
  6885. if (rect) {
  6886. var textPosition = style.textPosition;
  6887. if (textPosition instanceof Array) {
  6888. // Percent
  6889. baseX = rect.x + parsePercent(textPosition[0], rect.width);
  6890. baseY = rect.y + parsePercent(textPosition[1], rect.height);
  6891. }
  6892. else {
  6893. var res = adjustTextPositionOnRect(
  6894. textPosition, rect, style.textDistance
  6895. );
  6896. baseX = res.x;
  6897. baseY = res.y;
  6898. // Default align and baseline when has textPosition
  6899. textAlign = textAlign || res.textAlign;
  6900. textVerticalAlign = textVerticalAlign || res.textVerticalAlign;
  6901. }
  6902. // textOffset is only support in RectText, otherwise
  6903. // we have to adjust boundingRect for textOffset.
  6904. var textOffset = style.textOffset;
  6905. if (textOffset) {
  6906. baseX += textOffset[0];
  6907. baseY += textOffset[1];
  6908. }
  6909. }
  6910. return {
  6911. baseX: baseX,
  6912. baseY: baseY,
  6913. textAlign: textAlign,
  6914. textVerticalAlign: textVerticalAlign
  6915. };
  6916. }
  6917. function setCtx(ctx, prop, value) {
  6918. // FIXME ??? performance try
  6919. // if (ctx.__currentValues[prop] !== value) {
  6920. // ctx[prop] = ctx.__currentValues[prop] = value;
  6921. ctx[prop] = value;
  6922. // }
  6923. return ctx[prop];
  6924. }
  6925. /**
  6926. * @param {string} [stroke] If specified, do not check style.textStroke.
  6927. * @param {string} [lineWidth] If specified, do not check style.textStroke.
  6928. * @param {number} style
  6929. */
  6930. function getStroke(stroke, lineWidth) {
  6931. return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')
  6932. ? null
  6933. // TODO pattern and gradient?
  6934. : (stroke.image || stroke.colorStops)
  6935. ? '#000'
  6936. : stroke;
  6937. }
  6938. function getFill(fill) {
  6939. return (fill == null || fill === 'none')
  6940. ? null
  6941. // TODO pattern and gradient?
  6942. : (fill.image || fill.colorStops)
  6943. ? '#000'
  6944. : fill;
  6945. }
  6946. function parsePercent(value, maxValue) {
  6947. if (typeof value === 'string') {
  6948. if (value.lastIndexOf('%') >= 0) {
  6949. return parseFloat(value) / 100 * maxValue;
  6950. }
  6951. return parseFloat(value);
  6952. }
  6953. return value;
  6954. }
  6955. function getTextXForPadding(x, textAlign, textPadding) {
  6956. return textAlign === 'right'
  6957. ? (x - textPadding[1])
  6958. : textAlign === 'center'
  6959. ? (x + textPadding[3] / 2 - textPadding[1] / 2)
  6960. : (x + textPadding[3]);
  6961. }
  6962. /**
  6963. * @param {string} text
  6964. * @param {module:zrender/Style} style
  6965. * @return {boolean}
  6966. */
  6967. function needDrawText(text, style) {
  6968. return text != null
  6969. && (text
  6970. || style.textBackgroundColor
  6971. || (style.textBorderWidth && style.textBorderColor)
  6972. || style.textPadding
  6973. );
  6974. }
  6975. /**
  6976. * Mixin for drawing text in a element bounding rect
  6977. * @module zrender/mixin/RectText
  6978. */
  6979. var tmpRect$1 = new BoundingRect();
  6980. var RectText = function () {};
  6981. RectText.prototype = {
  6982. constructor: RectText,
  6983. /**
  6984. * Draw text in a rect with specified position.
  6985. * @param {CanvasRenderingContext2D} ctx
  6986. * @param {Object} rect Displayable rect
  6987. */
  6988. drawRectText: function (ctx, rect) {
  6989. var style = this.style;
  6990. rect = style.textRect || rect;
  6991. // Optimize, avoid normalize every time.
  6992. this.__dirty && normalizeTextStyle(style, true);
  6993. var text = style.text;
  6994. // Convert to string
  6995. text != null && (text += '');
  6996. if (!needDrawText(text, style)) {
  6997. return;
  6998. }
  6999. // FIXME
  7000. ctx.save();
  7001. // Transform rect to view space
  7002. var transform = this.transform;
  7003. if (!style.transformText) {
  7004. if (transform) {
  7005. tmpRect$1.copy(rect);
  7006. tmpRect$1.applyTransform(transform);
  7007. rect = tmpRect$1;
  7008. }
  7009. }
  7010. else {
  7011. this.setTransform(ctx);
  7012. }
  7013. // transformText and textRotation can not be used at the same time.
  7014. renderText(this, ctx, text, style, rect);
  7015. ctx.restore();
  7016. }
  7017. };
  7018. /**
  7019. * 可绘制的图形基类
  7020. * Base class of all displayable graphic objects
  7021. * @module zrender/graphic/Displayable
  7022. */
  7023. /**
  7024. * @alias module:zrender/graphic/Displayable
  7025. * @extends module:zrender/Element
  7026. * @extends module:zrender/graphic/mixin/RectText
  7027. */
  7028. function Displayable(opts) {
  7029. opts = opts || {};
  7030. Element.call(this, opts);
  7031. // Extend properties
  7032. for (var name in opts) {
  7033. if (
  7034. opts.hasOwnProperty(name) &&
  7035. name !== 'style'
  7036. ) {
  7037. this[name] = opts[name];
  7038. }
  7039. }
  7040. /**
  7041. * @type {module:zrender/graphic/Style}
  7042. */
  7043. this.style = new Style(opts.style, this);
  7044. this._rect = null;
  7045. // Shapes for cascade clipping.
  7046. this.__clipPaths = [];
  7047. // FIXME Stateful must be mixined after style is setted
  7048. // Stateful.call(this, opts);
  7049. }
  7050. Displayable.prototype = {
  7051. constructor: Displayable,
  7052. type: 'displayable',
  7053. /**
  7054. * Displayable 是否为脏,Painter 中会根据该标记判断是否需要是否需要重新绘制
  7055. * Dirty flag. From which painter will determine if this displayable object needs brush
  7056. * @name module:zrender/graphic/Displayable#__dirty
  7057. * @type {boolean}
  7058. */
  7059. __dirty: true,
  7060. /**
  7061. * 图形是否可见,为true时不绘制图形,但是仍能触发鼠标事件
  7062. * If ignore drawing of the displayable object. Mouse event will still be triggered
  7063. * @name module:/zrender/graphic/Displayable#invisible
  7064. * @type {boolean}
  7065. * @default false
  7066. */
  7067. invisible: false,
  7068. /**
  7069. * @name module:/zrender/graphic/Displayable#z
  7070. * @type {number}
  7071. * @default 0
  7072. */
  7073. z: 0,
  7074. /**
  7075. * @name module:/zrender/graphic/Displayable#z
  7076. * @type {number}
  7077. * @default 0
  7078. */
  7079. z2: 0,
  7080. /**
  7081. * z层level,决定绘画在哪层canvas中
  7082. * @name module:/zrender/graphic/Displayable#zlevel
  7083. * @type {number}
  7084. * @default 0
  7085. */
  7086. zlevel: 0,
  7087. /**
  7088. * 是否可拖拽
  7089. * @name module:/zrender/graphic/Displayable#draggable
  7090. * @type {boolean}
  7091. * @default false
  7092. */
  7093. draggable: false,
  7094. /**
  7095. * 是否正在拖拽
  7096. * @name module:/zrender/graphic/Displayable#draggable
  7097. * @type {boolean}
  7098. * @default false
  7099. */
  7100. dragging: false,
  7101. /**
  7102. * 是否相应鼠标事件
  7103. * @name module:/zrender/graphic/Displayable#silent
  7104. * @type {boolean}
  7105. * @default false
  7106. */
  7107. silent: false,
  7108. /**
  7109. * If enable culling
  7110. * @type {boolean}
  7111. * @default false
  7112. */
  7113. culling: false,
  7114. /**
  7115. * Mouse cursor when hovered
  7116. * @name module:/zrender/graphic/Displayable#cursor
  7117. * @type {string}
  7118. */
  7119. cursor: 'pointer',
  7120. /**
  7121. * If hover area is bounding rect
  7122. * @name module:/zrender/graphic/Displayable#rectHover
  7123. * @type {string}
  7124. */
  7125. rectHover: false,
  7126. /**
  7127. * Render the element progressively when the value >= 0,
  7128. * usefull for large data.
  7129. * @type {number}
  7130. */
  7131. progressive: -1,
  7132. beforeBrush: function (ctx) {},
  7133. afterBrush: function (ctx) {},
  7134. /**
  7135. * 图形绘制方法
  7136. * @param {CanvasRenderingContext2D} ctx
  7137. */
  7138. // Interface
  7139. brush: function (ctx, prevEl) {},
  7140. /**
  7141. * 获取最小包围盒
  7142. * @return {module:zrender/core/BoundingRect}
  7143. */
  7144. // Interface
  7145. getBoundingRect: function () {},
  7146. /**
  7147. * 判断坐标 x, y 是否在图形上
  7148. * If displayable element contain coord x, y
  7149. * @param {number} x
  7150. * @param {number} y
  7151. * @return {boolean}
  7152. */
  7153. contain: function (x, y) {
  7154. return this.rectContain(x, y);
  7155. },
  7156. /**
  7157. * @param {Function} cb
  7158. * @param {} context
  7159. */
  7160. traverse: function (cb, context) {
  7161. cb.call(context, this);
  7162. },
  7163. /**
  7164. * 判断坐标 x, y 是否在图形的包围盒上
  7165. * If bounding rect of element contain coord x, y
  7166. * @param {number} x
  7167. * @param {number} y
  7168. * @return {boolean}
  7169. */
  7170. rectContain: function (x, y) {
  7171. var coord = this.transformCoordToLocal(x, y);
  7172. var rect = this.getBoundingRect();
  7173. return rect.contain(coord[0], coord[1]);
  7174. },
  7175. /**
  7176. * 标记图形元素为脏,并且在下一帧重绘
  7177. * Mark displayable element dirty and refresh next frame
  7178. */
  7179. dirty: function () {
  7180. this.__dirty = true;
  7181. this._rect = null;
  7182. this.__zr && this.__zr.refresh();
  7183. },
  7184. /**
  7185. * 图形是否会触发事件
  7186. * If displayable object binded any event
  7187. * @return {boolean}
  7188. */
  7189. // TODO, 通过 bind 绑定的事件
  7190. // isSilent: function () {
  7191. // return !(
  7192. // this.hoverable || this.draggable
  7193. // || this.onmousemove || this.onmouseover || this.onmouseout
  7194. // || this.onmousedown || this.onmouseup || this.onclick
  7195. // || this.ondragenter || this.ondragover || this.ondragleave
  7196. // || this.ondrop
  7197. // );
  7198. // },
  7199. /**
  7200. * Alias for animate('style')
  7201. * @param {boolean} loop
  7202. */
  7203. animateStyle: function (loop) {
  7204. return this.animate('style', loop);
  7205. },
  7206. attrKV: function (key, value) {
  7207. if (key !== 'style') {
  7208. Element.prototype.attrKV.call(this, key, value);
  7209. }
  7210. else {
  7211. this.style.set(value);
  7212. }
  7213. },
  7214. /**
  7215. * @param {Object|string} key
  7216. * @param {*} value
  7217. */
  7218. setStyle: function (key, value) {
  7219. this.style.set(key, value);
  7220. this.dirty(false);
  7221. return this;
  7222. },
  7223. /**
  7224. * Use given style object
  7225. * @param {Object} obj
  7226. */
  7227. useStyle: function (obj) {
  7228. this.style = new Style(obj, this);
  7229. this.dirty(false);
  7230. return this;
  7231. }
  7232. };
  7233. inherits(Displayable, Element);
  7234. mixin(Displayable, RectText);
  7235. /**
  7236. * @alias zrender/graphic/Image
  7237. * @extends module:zrender/graphic/Displayable
  7238. * @constructor
  7239. * @param {Object} opts
  7240. */
  7241. function ZImage(opts) {
  7242. Displayable.call(this, opts);
  7243. }
  7244. ZImage.prototype = {
  7245. constructor: ZImage,
  7246. type: 'image',
  7247. brush: function (ctx, prevEl) {
  7248. var style = this.style;
  7249. var src = style.image;
  7250. // Must bind each time
  7251. style.bind(ctx, this, prevEl);
  7252. var image = this._image = createOrUpdateImage(
  7253. src,
  7254. this._image,
  7255. this,
  7256. this.onload
  7257. );
  7258. if (!image || !isImageReady(image)) {
  7259. return;
  7260. }
  7261. // 图片已经加载完成
  7262. // if (image.nodeName.toUpperCase() == 'IMG') {
  7263. // if (!image.complete) {
  7264. // return;
  7265. // }
  7266. // }
  7267. // Else is canvas
  7268. var x = style.x || 0;
  7269. var y = style.y || 0;
  7270. var width = style.width;
  7271. var height = style.height;
  7272. var aspect = image.width / image.height;
  7273. if (width == null && height != null) {
  7274. // Keep image/height ratio
  7275. width = height * aspect;
  7276. }
  7277. else if (height == null && width != null) {
  7278. height = width / aspect;
  7279. }
  7280. else if (width == null && height == null) {
  7281. width = image.width;
  7282. height = image.height;
  7283. }
  7284. // 设置transform
  7285. this.setTransform(ctx);
  7286. if (style.sWidth && style.sHeight) {
  7287. var sx = style.sx || 0;
  7288. var sy = style.sy || 0;
  7289. ctx.drawImage(
  7290. image,
  7291. sx, sy, style.sWidth, style.sHeight,
  7292. x, y, width, height
  7293. );
  7294. }
  7295. else if (style.sx && style.sy) {
  7296. var sx = style.sx;
  7297. var sy = style.sy;
  7298. var sWidth = width - sx;
  7299. var sHeight = height - sy;
  7300. ctx.drawImage(
  7301. image,
  7302. sx, sy, sWidth, sHeight,
  7303. x, y, width, height
  7304. );
  7305. }
  7306. else {
  7307. ctx.drawImage(image, x, y, width, height);
  7308. }
  7309. this.restoreTransform(ctx);
  7310. // Draw rect text
  7311. if (style.text != null) {
  7312. this.drawRectText(ctx, this.getBoundingRect());
  7313. }
  7314. },
  7315. getBoundingRect: function () {
  7316. var style = this.style;
  7317. if (! this._rect) {
  7318. this._rect = new BoundingRect(
  7319. style.x || 0, style.y || 0, style.width || 0, style.height || 0
  7320. );
  7321. }
  7322. return this._rect;
  7323. }
  7324. };
  7325. inherits(ZImage, Displayable);
  7326. /**
  7327. * Default canvas painter
  7328. * @module zrender/Painter
  7329. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  7330. * errorrik (errorrik@gmail.com)
  7331. * pissang (https://www.github.com/pissang)
  7332. */
  7333. // PENDIGN
  7334. // Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time.
  7335. //
  7336. // Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer.
  7337. var MAX_PROGRESSIVE_LAYER_NUMBER = 5;
  7338. function parseInt10(val) {
  7339. return parseInt(val, 10);
  7340. }
  7341. function isLayerValid(layer) {
  7342. if (!layer) {
  7343. return false;
  7344. }
  7345. if (layer.__builtin__) {
  7346. return true;
  7347. }
  7348. if (typeof(layer.resize) !== 'function'
  7349. || typeof(layer.refresh) !== 'function'
  7350. ) {
  7351. return false;
  7352. }
  7353. return true;
  7354. }
  7355. function preProcessLayer(layer) {
  7356. layer.__unusedCount++;
  7357. }
  7358. function postProcessLayer(layer) {
  7359. if (layer.__unusedCount == 1) {
  7360. layer.clear();
  7361. }
  7362. }
  7363. var tmpRect = new BoundingRect(0, 0, 0, 0);
  7364. var viewRect = new BoundingRect(0, 0, 0, 0);
  7365. function isDisplayableCulled(el, width, height) {
  7366. tmpRect.copy(el.getBoundingRect());
  7367. if (el.transform) {
  7368. tmpRect.applyTransform(el.transform);
  7369. }
  7370. viewRect.width = width;
  7371. viewRect.height = height;
  7372. return !tmpRect.intersect(viewRect);
  7373. }
  7374. function isClipPathChanged(clipPaths, prevClipPaths) {
  7375. if (clipPaths == prevClipPaths) { // Can both be null or undefined
  7376. return false;
  7377. }
  7378. if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {
  7379. return true;
  7380. }
  7381. for (var i = 0; i < clipPaths.length; i++) {
  7382. if (clipPaths[i] !== prevClipPaths[i]) {
  7383. return true;
  7384. }
  7385. }
  7386. }
  7387. function doClip(clipPaths, ctx) {
  7388. for (var i = 0; i < clipPaths.length; i++) {
  7389. var clipPath = clipPaths[i];
  7390. clipPath.setTransform(ctx);
  7391. ctx.beginPath();
  7392. clipPath.buildPath(ctx, clipPath.shape);
  7393. ctx.clip();
  7394. // Transform back
  7395. clipPath.restoreTransform(ctx);
  7396. }
  7397. }
  7398. function createRoot(width, height) {
  7399. var domRoot = document.createElement('div');
  7400. // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬
  7401. domRoot.style.cssText = [
  7402. 'position:relative',
  7403. 'overflow:hidden',
  7404. 'width:' + width + 'px',
  7405. 'height:' + height + 'px',
  7406. 'padding:0',
  7407. 'margin:0',
  7408. 'border-width:0'
  7409. ].join(';') + ';';
  7410. return domRoot;
  7411. }
  7412. /**
  7413. * @alias module:zrender/Painter
  7414. * @constructor
  7415. * @param {HTMLElement} root 绘图容器
  7416. * @param {module:zrender/Storage} storage
  7417. * @param {Object} opts
  7418. */
  7419. var Painter = function (root, storage, opts) {
  7420. this.type = 'canvas';
  7421. // In node environment using node-canvas
  7422. var singleCanvas = !root.nodeName // In node ?
  7423. || root.nodeName.toUpperCase() === 'CANVAS';
  7424. this._opts = opts = extend({}, opts || {});
  7425. /**
  7426. * @type {number}
  7427. */
  7428. this.dpr = opts.devicePixelRatio || devicePixelRatio;
  7429. /**
  7430. * @type {boolean}
  7431. * @private
  7432. */
  7433. this._singleCanvas = singleCanvas;
  7434. /**
  7435. * 绘图容器
  7436. * @type {HTMLElement}
  7437. */
  7438. this.root = root;
  7439. var rootStyle = root.style;
  7440. if (rootStyle) {
  7441. rootStyle['-webkit-tap-highlight-color'] = 'transparent';
  7442. rootStyle['-webkit-user-select'] =
  7443. rootStyle['user-select'] =
  7444. rootStyle['-webkit-touch-callout'] = 'none';
  7445. root.innerHTML = '';
  7446. }
  7447. /**
  7448. * @type {module:zrender/Storage}
  7449. */
  7450. this.storage = storage;
  7451. /**
  7452. * @type {Array.<number>}
  7453. * @private
  7454. */
  7455. var zlevelList = this._zlevelList = [];
  7456. /**
  7457. * @type {Object.<string, module:zrender/Layer>}
  7458. * @private
  7459. */
  7460. var layers = this._layers = {};
  7461. /**
  7462. * @type {Object.<string, Object>}
  7463. * @type {private}
  7464. */
  7465. this._layerConfig = {};
  7466. if (!singleCanvas) {
  7467. this._width = this._getSize(0);
  7468. this._height = this._getSize(1);
  7469. var domRoot = this._domRoot = createRoot(
  7470. this._width, this._height
  7471. );
  7472. root.appendChild(domRoot);
  7473. }
  7474. else {
  7475. if (opts.width != null) {
  7476. root.width = opts.width;
  7477. }
  7478. if (opts.height != null) {
  7479. root.height = opts.height;
  7480. }
  7481. // Use canvas width and height directly
  7482. var width = root.width;
  7483. var height = root.height;
  7484. this._width = width;
  7485. this._height = height;
  7486. // Create layer if only one given canvas
  7487. // Device pixel ratio is fixed to 1 because given canvas has its specified width and height
  7488. var mainLayer = new Layer(root, this, 1);
  7489. mainLayer.initContext();
  7490. // FIXME Use canvas width and height
  7491. // mainLayer.resize(width, height);
  7492. layers[0] = mainLayer;
  7493. zlevelList.push(0);
  7494. this._domRoot = root;
  7495. }
  7496. // Layers for progressive rendering
  7497. this._progressiveLayers = [];
  7498. /**
  7499. * @type {module:zrender/Layer}
  7500. * @private
  7501. */
  7502. this._hoverlayer;
  7503. this._hoverElements = [];
  7504. };
  7505. Painter.prototype = {
  7506. constructor: Painter,
  7507. getType: function () {
  7508. return 'canvas';
  7509. },
  7510. /**
  7511. * If painter use a single canvas
  7512. * @return {boolean}
  7513. */
  7514. isSingleCanvas: function () {
  7515. return this._singleCanvas;
  7516. },
  7517. /**
  7518. * @return {HTMLDivElement}
  7519. */
  7520. getViewportRoot: function () {
  7521. return this._domRoot;
  7522. },
  7523. getViewportRootOffset: function () {
  7524. var viewportRoot = this.getViewportRoot();
  7525. if (viewportRoot) {
  7526. return {
  7527. offsetLeft: viewportRoot.offsetLeft || 0,
  7528. offsetTop: viewportRoot.offsetTop || 0
  7529. };
  7530. }
  7531. },
  7532. /**
  7533. * 刷新
  7534. * @param {boolean} [paintAll=false] 强制绘制所有displayable
  7535. */
  7536. refresh: function (paintAll) {
  7537. var list = this.storage.getDisplayList(true);
  7538. var zlevelList = this._zlevelList;
  7539. this._paintList(list, paintAll);
  7540. // Paint custum layers
  7541. for (var i = 0; i < zlevelList.length; i++) {
  7542. var z = zlevelList[i];
  7543. var layer = this._layers[z];
  7544. if (!layer.__builtin__ && layer.refresh) {
  7545. layer.refresh();
  7546. }
  7547. }
  7548. this.refreshHover();
  7549. if (this._progressiveLayers.length) {
  7550. this._startProgessive();
  7551. }
  7552. return this;
  7553. },
  7554. addHover: function (el, hoverStyle) {
  7555. if (el.__hoverMir) {
  7556. return;
  7557. }
  7558. var elMirror = new el.constructor({
  7559. style: el.style,
  7560. shape: el.shape
  7561. });
  7562. elMirror.__from = el;
  7563. el.__hoverMir = elMirror;
  7564. elMirror.setStyle(hoverStyle);
  7565. this._hoverElements.push(elMirror);
  7566. },
  7567. removeHover: function (el) {
  7568. var elMirror = el.__hoverMir;
  7569. var hoverElements = this._hoverElements;
  7570. var idx = indexOf(hoverElements, elMirror);
  7571. if (idx >= 0) {
  7572. hoverElements.splice(idx, 1);
  7573. }
  7574. el.__hoverMir = null;
  7575. },
  7576. clearHover: function (el) {
  7577. var hoverElements = this._hoverElements;
  7578. for (var i = 0; i < hoverElements.length; i++) {
  7579. var from = hoverElements[i].__from;
  7580. if (from) {
  7581. from.__hoverMir = null;
  7582. }
  7583. }
  7584. hoverElements.length = 0;
  7585. },
  7586. refreshHover: function () {
  7587. var hoverElements = this._hoverElements;
  7588. var len = hoverElements.length;
  7589. var hoverLayer = this._hoverlayer;
  7590. hoverLayer && hoverLayer.clear();
  7591. if (!len) {
  7592. return;
  7593. }
  7594. sort(hoverElements, this.storage.displayableSortFunc);
  7595. // Use a extream large zlevel
  7596. // FIXME?
  7597. if (!hoverLayer) {
  7598. hoverLayer = this._hoverlayer = this.getLayer(1e5);
  7599. }
  7600. var scope = {};
  7601. hoverLayer.ctx.save();
  7602. for (var i = 0; i < len;) {
  7603. var el = hoverElements[i];
  7604. var originalEl = el.__from;
  7605. // Original el is removed
  7606. // PENDING
  7607. if (!(originalEl && originalEl.__zr)) {
  7608. hoverElements.splice(i, 1);
  7609. originalEl.__hoverMir = null;
  7610. len--;
  7611. continue;
  7612. }
  7613. i++;
  7614. // Use transform
  7615. // FIXME style and shape ?
  7616. if (!originalEl.invisible) {
  7617. el.transform = originalEl.transform;
  7618. el.invTransform = originalEl.invTransform;
  7619. el.__clipPaths = originalEl.__clipPaths;
  7620. // el.
  7621. this._doPaintEl(el, hoverLayer, true, scope);
  7622. }
  7623. }
  7624. hoverLayer.ctx.restore();
  7625. },
  7626. _startProgessive: function () {
  7627. var self = this;
  7628. if (!self._furtherProgressive) {
  7629. return;
  7630. }
  7631. // Use a token to stop progress steps triggered by
  7632. // previous zr.refresh calling.
  7633. var token = self._progressiveToken = +new Date();
  7634. self._progress++;
  7635. requestAnimationFrame(step);
  7636. function step() {
  7637. // In case refreshed or disposed
  7638. if (token === self._progressiveToken && self.storage) {
  7639. self._doPaintList(self.storage.getDisplayList());
  7640. if (self._furtherProgressive) {
  7641. self._progress++;
  7642. requestAnimationFrame(step);
  7643. }
  7644. else {
  7645. self._progressiveToken = -1;
  7646. }
  7647. }
  7648. }
  7649. },
  7650. _clearProgressive: function () {
  7651. this._progressiveToken = -1;
  7652. this._progress = 0;
  7653. each(this._progressiveLayers, function (layer) {
  7654. layer.__dirty && layer.clear();
  7655. });
  7656. },
  7657. _paintList: function (list, paintAll) {
  7658. if (paintAll == null) {
  7659. paintAll = false;
  7660. }
  7661. this._updateLayerStatus(list);
  7662. this._clearProgressive();
  7663. this.eachBuiltinLayer(preProcessLayer);
  7664. this._doPaintList(list, paintAll);
  7665. this.eachBuiltinLayer(postProcessLayer);
  7666. },
  7667. _doPaintList: function (list, paintAll) {
  7668. var currentLayer;
  7669. var currentZLevel;
  7670. var ctx;
  7671. // var invTransform = [];
  7672. var scope;
  7673. var progressiveLayerIdx = 0;
  7674. var currentProgressiveLayer;
  7675. var width = this._width;
  7676. var height = this._height;
  7677. var layerProgress;
  7678. var frame = this._progress;
  7679. function flushProgressiveLayer(layer) {
  7680. var dpr = ctx.dpr || 1;
  7681. ctx.save();
  7682. ctx.globalAlpha = 1;
  7683. ctx.shadowBlur = 0;
  7684. // Avoid layer don't clear in next progressive frame
  7685. currentLayer.__dirty = true;
  7686. ctx.setTransform(1, 0, 0, 1, 0, 0);
  7687. ctx.drawImage(layer.dom, 0, 0, width * dpr, height * dpr);
  7688. ctx.restore();
  7689. }
  7690. for (var i = 0, l = list.length; i < l; i++) {
  7691. var el = list[i];
  7692. var elZLevel = this._singleCanvas ? 0 : el.zlevel;
  7693. var elFrame = el.__frame;
  7694. // Flush at current context
  7695. // PENDING
  7696. if (elFrame < 0 && currentProgressiveLayer) {
  7697. flushProgressiveLayer(currentProgressiveLayer);
  7698. currentProgressiveLayer = null;
  7699. }
  7700. // Change draw layer
  7701. if (currentZLevel !== elZLevel) {
  7702. if (ctx) {
  7703. ctx.restore();
  7704. }
  7705. // Reset scope
  7706. scope = {};
  7707. // Only 0 zlevel if only has one canvas
  7708. currentZLevel = elZLevel;
  7709. currentLayer = this.getLayer(currentZLevel);
  7710. if (!currentLayer.__builtin__) {
  7711. zrLog(
  7712. 'ZLevel ' + currentZLevel
  7713. + ' has been used by unkown layer ' + currentLayer.id
  7714. );
  7715. }
  7716. ctx = currentLayer.ctx;
  7717. ctx.save();
  7718. // Reset the count
  7719. currentLayer.__unusedCount = 0;
  7720. if (currentLayer.__dirty || paintAll) {
  7721. currentLayer.clear();
  7722. }
  7723. }
  7724. if (!(currentLayer.__dirty || paintAll)) {
  7725. continue;
  7726. }
  7727. if (elFrame >= 0) {
  7728. // Progressive layer changed
  7729. if (!currentProgressiveLayer) {
  7730. currentProgressiveLayer = this._progressiveLayers[
  7731. Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1)
  7732. ];
  7733. currentProgressiveLayer.ctx.save();
  7734. currentProgressiveLayer.renderScope = {};
  7735. if (currentProgressiveLayer
  7736. && (currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress)
  7737. ) {
  7738. // flushProgressiveLayer(currentProgressiveLayer);
  7739. // Quick jump all progressive elements
  7740. // All progressive element are not dirty, jump over and flush directly
  7741. i = currentProgressiveLayer.__nextIdxNotProg - 1;
  7742. // currentProgressiveLayer = null;
  7743. continue;
  7744. }
  7745. layerProgress = currentProgressiveLayer.__progress;
  7746. if (!currentProgressiveLayer.__dirty) {
  7747. // Keep rendering
  7748. frame = layerProgress;
  7749. }
  7750. currentProgressiveLayer.__progress = frame + 1;
  7751. }
  7752. if (elFrame === frame) {
  7753. this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope);
  7754. }
  7755. }
  7756. else {
  7757. this._doPaintEl(el, currentLayer, paintAll, scope);
  7758. }
  7759. el.__dirty = false;
  7760. }
  7761. if (currentProgressiveLayer) {
  7762. flushProgressiveLayer(currentProgressiveLayer);
  7763. }
  7764. // Restore the lastLayer ctx
  7765. ctx && ctx.restore();
  7766. // If still has clipping state
  7767. // if (scope.prevElClipPaths) {
  7768. // ctx.restore();
  7769. // }
  7770. this._furtherProgressive = false;
  7771. each(this._progressiveLayers, function (layer) {
  7772. if (layer.__maxProgress >= layer.__progress) {
  7773. this._furtherProgressive = true;
  7774. }
  7775. }, this);
  7776. },
  7777. _doPaintEl: function (el, currentLayer, forcePaint, scope) {
  7778. var ctx = currentLayer.ctx;
  7779. var m = el.transform;
  7780. if (
  7781. (currentLayer.__dirty || forcePaint)
  7782. // Ignore invisible element
  7783. && !el.invisible
  7784. // Ignore transparent element
  7785. && el.style.opacity !== 0
  7786. // Ignore scale 0 element, in some environment like node-canvas
  7787. // Draw a scale 0 element can cause all following draw wrong
  7788. // And setTransform with scale 0 will cause set back transform failed.
  7789. && !(m && !m[0] && !m[3])
  7790. // Ignore culled element
  7791. && !(el.culling && isDisplayableCulled(el, this._width, this._height))
  7792. ) {
  7793. var clipPaths = el.__clipPaths;
  7794. // Optimize when clipping on group with several elements
  7795. if (scope.prevClipLayer !== currentLayer
  7796. || isClipPathChanged(clipPaths, scope.prevElClipPaths)
  7797. ) {
  7798. // If has previous clipping state, restore from it
  7799. if (scope.prevElClipPaths) {
  7800. scope.prevClipLayer.ctx.restore();
  7801. scope.prevClipLayer = scope.prevElClipPaths = null;
  7802. // Reset prevEl since context has been restored
  7803. scope.prevEl = null;
  7804. }
  7805. // New clipping state
  7806. if (clipPaths) {
  7807. ctx.save();
  7808. doClip(clipPaths, ctx);
  7809. scope.prevClipLayer = currentLayer;
  7810. scope.prevElClipPaths = clipPaths;
  7811. }
  7812. }
  7813. el.beforeBrush && el.beforeBrush(ctx);
  7814. el.brush(ctx, scope.prevEl || null);
  7815. scope.prevEl = el;
  7816. el.afterBrush && el.afterBrush(ctx);
  7817. }
  7818. },
  7819. /**
  7820. * 获取 zlevel 所在层,如果不存在则会创建一个新的层
  7821. * @param {number} zlevel
  7822. * @return {module:zrender/Layer}
  7823. */
  7824. getLayer: function (zlevel) {
  7825. if (this._singleCanvas) {
  7826. return this._layers[0];
  7827. }
  7828. var layer = this._layers[zlevel];
  7829. if (!layer) {
  7830. // Create a new layer
  7831. layer = new Layer('zr_' + zlevel, this, this.dpr);
  7832. layer.__builtin__ = true;
  7833. if (this._layerConfig[zlevel]) {
  7834. merge(layer, this._layerConfig[zlevel], true);
  7835. }
  7836. this.insertLayer(zlevel, layer);
  7837. // Context is created after dom inserted to document
  7838. // Or excanvas will get 0px clientWidth and clientHeight
  7839. layer.initContext();
  7840. }
  7841. return layer;
  7842. },
  7843. insertLayer: function (zlevel, layer) {
  7844. var layersMap = this._layers;
  7845. var zlevelList = this._zlevelList;
  7846. var len = zlevelList.length;
  7847. var prevLayer = null;
  7848. var i = -1;
  7849. var domRoot = this._domRoot;
  7850. if (layersMap[zlevel]) {
  7851. zrLog('ZLevel ' + zlevel + ' has been used already');
  7852. return;
  7853. }
  7854. // Check if is a valid layer
  7855. if (!isLayerValid(layer)) {
  7856. zrLog('Layer of zlevel ' + zlevel + ' is not valid');
  7857. return;
  7858. }
  7859. if (len > 0 && zlevel > zlevelList[0]) {
  7860. for (i = 0; i < len - 1; i++) {
  7861. if (
  7862. zlevelList[i] < zlevel
  7863. && zlevelList[i + 1] > zlevel
  7864. ) {
  7865. break;
  7866. }
  7867. }
  7868. prevLayer = layersMap[zlevelList[i]];
  7869. }
  7870. zlevelList.splice(i + 1, 0, zlevel);
  7871. layersMap[zlevel] = layer;
  7872. // Vitual layer will not directly show on the screen.
  7873. // (It can be a WebGL layer and assigned to a ZImage element)
  7874. // But it still under management of zrender.
  7875. if (!layer.virtual) {
  7876. if (prevLayer) {
  7877. var prevDom = prevLayer.dom;
  7878. if (prevDom.nextSibling) {
  7879. domRoot.insertBefore(
  7880. layer.dom,
  7881. prevDom.nextSibling
  7882. );
  7883. }
  7884. else {
  7885. domRoot.appendChild(layer.dom);
  7886. }
  7887. }
  7888. else {
  7889. if (domRoot.firstChild) {
  7890. domRoot.insertBefore(layer.dom, domRoot.firstChild);
  7891. }
  7892. else {
  7893. domRoot.appendChild(layer.dom);
  7894. }
  7895. }
  7896. }
  7897. },
  7898. // Iterate each layer
  7899. eachLayer: function (cb, context) {
  7900. var zlevelList = this._zlevelList;
  7901. var z;
  7902. var i;
  7903. for (i = 0; i < zlevelList.length; i++) {
  7904. z = zlevelList[i];
  7905. cb.call(context, this._layers[z], z);
  7906. }
  7907. },
  7908. // Iterate each buildin layer
  7909. eachBuiltinLayer: function (cb, context) {
  7910. var zlevelList = this._zlevelList;
  7911. var layer;
  7912. var z;
  7913. var i;
  7914. for (i = 0; i < zlevelList.length; i++) {
  7915. z = zlevelList[i];
  7916. layer = this._layers[z];
  7917. if (layer.__builtin__) {
  7918. cb.call(context, layer, z);
  7919. }
  7920. }
  7921. },
  7922. // Iterate each other layer except buildin layer
  7923. eachOtherLayer: function (cb, context) {
  7924. var zlevelList = this._zlevelList;
  7925. var layer;
  7926. var z;
  7927. var i;
  7928. for (i = 0; i < zlevelList.length; i++) {
  7929. z = zlevelList[i];
  7930. layer = this._layers[z];
  7931. if (!layer.__builtin__) {
  7932. cb.call(context, layer, z);
  7933. }
  7934. }
  7935. },
  7936. /**
  7937. * 获取所有已创建的层
  7938. * @param {Array.<module:zrender/Layer>} [prevLayer]
  7939. */
  7940. getLayers: function () {
  7941. return this._layers;
  7942. },
  7943. _updateLayerStatus: function (list) {
  7944. var layers = this._layers;
  7945. var progressiveLayers = this._progressiveLayers;
  7946. var elCountsLastFrame = {};
  7947. var progressiveElCountsLastFrame = {};
  7948. this.eachBuiltinLayer(function (layer, z) {
  7949. elCountsLastFrame[z] = layer.elCount;
  7950. layer.elCount = 0;
  7951. layer.__dirty = false;
  7952. });
  7953. each(progressiveLayers, function (layer, idx) {
  7954. progressiveElCountsLastFrame[idx] = layer.elCount;
  7955. layer.elCount = 0;
  7956. layer.__dirty = false;
  7957. });
  7958. var progressiveLayerCount = 0;
  7959. var currentProgressiveLayer;
  7960. var lastProgressiveKey;
  7961. var frameCount = 0;
  7962. for (var i = 0, l = list.length; i < l; i++) {
  7963. var el = list[i];
  7964. var zlevel = this._singleCanvas ? 0 : el.zlevel;
  7965. var layer = layers[zlevel];
  7966. var elProgress = el.progressive;
  7967. if (layer) {
  7968. layer.elCount++;
  7969. layer.__dirty = layer.__dirty || el.__dirty;
  7970. }
  7971. /////// Update progressive
  7972. if (elProgress >= 0) {
  7973. // Fix wrong progressive sequence problem.
  7974. if (lastProgressiveKey !== elProgress) {
  7975. lastProgressiveKey = elProgress;
  7976. frameCount++;
  7977. }
  7978. var elFrame = el.__frame = frameCount - 1;
  7979. if (!currentProgressiveLayer) {
  7980. var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1);
  7981. currentProgressiveLayer = progressiveLayers[idx];
  7982. if (!currentProgressiveLayer) {
  7983. currentProgressiveLayer = progressiveLayers[idx] = new Layer(
  7984. 'progressive', this, this.dpr
  7985. );
  7986. currentProgressiveLayer.initContext();
  7987. }
  7988. currentProgressiveLayer.__maxProgress = 0;
  7989. }
  7990. currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty;
  7991. currentProgressiveLayer.elCount++;
  7992. currentProgressiveLayer.__maxProgress = Math.max(
  7993. currentProgressiveLayer.__maxProgress, elFrame
  7994. );
  7995. if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) {
  7996. // Should keep rendering this layer because progressive rendering is not finished yet
  7997. layer.__dirty = true;
  7998. }
  7999. }
  8000. else {
  8001. el.__frame = -1;
  8002. if (currentProgressiveLayer) {
  8003. currentProgressiveLayer.__nextIdxNotProg = i;
  8004. progressiveLayerCount++;
  8005. currentProgressiveLayer = null;
  8006. }
  8007. }
  8008. }
  8009. if (currentProgressiveLayer) {
  8010. progressiveLayerCount++;
  8011. currentProgressiveLayer.__nextIdxNotProg = i;
  8012. }
  8013. // 层中的元素数量有发生变化
  8014. this.eachBuiltinLayer(function (layer, z) {
  8015. if (elCountsLastFrame[z] !== layer.elCount) {
  8016. layer.__dirty = true;
  8017. }
  8018. });
  8019. progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER);
  8020. each(progressiveLayers, function (layer, idx) {
  8021. if (progressiveElCountsLastFrame[idx] !== layer.elCount) {
  8022. el.__dirty = true;
  8023. }
  8024. if (layer.__dirty) {
  8025. layer.__progress = 0;
  8026. }
  8027. });
  8028. },
  8029. /**
  8030. * 清除hover层外所有内容
  8031. */
  8032. clear: function () {
  8033. this.eachBuiltinLayer(this._clearLayer);
  8034. return this;
  8035. },
  8036. _clearLayer: function (layer) {
  8037. layer.clear();
  8038. },
  8039. /**
  8040. * 修改指定zlevel的绘制参数
  8041. *
  8042. * @param {string} zlevel
  8043. * @param {Object} config 配置对象
  8044. * @param {string} [config.clearColor=0] 每次清空画布的颜色
  8045. * @param {string} [config.motionBlur=false] 是否开启动态模糊
  8046. * @param {number} [config.lastFrameAlpha=0.7]
  8047. * 在开启动态模糊的时候使用,与上一帧混合的alpha值,值越大尾迹越明显
  8048. */
  8049. configLayer: function (zlevel, config) {
  8050. if (config) {
  8051. var layerConfig = this._layerConfig;
  8052. if (!layerConfig[zlevel]) {
  8053. layerConfig[zlevel] = config;
  8054. }
  8055. else {
  8056. merge(layerConfig[zlevel], config, true);
  8057. }
  8058. var layer = this._layers[zlevel];
  8059. if (layer) {
  8060. merge(layer, layerConfig[zlevel], true);
  8061. }
  8062. }
  8063. },
  8064. /**
  8065. * 删除指定层
  8066. * @param {number} zlevel 层所在的zlevel
  8067. */
  8068. delLayer: function (zlevel) {
  8069. var layers = this._layers;
  8070. var zlevelList = this._zlevelList;
  8071. var layer = layers[zlevel];
  8072. if (!layer) {
  8073. return;
  8074. }
  8075. layer.dom.parentNode.removeChild(layer.dom);
  8076. delete layers[zlevel];
  8077. zlevelList.splice(indexOf(zlevelList, zlevel), 1);
  8078. },
  8079. /**
  8080. * 区域大小变化后重绘
  8081. */
  8082. resize: function (width, height) {
  8083. var domRoot = this._domRoot;
  8084. // FIXME Why ?
  8085. domRoot.style.display = 'none';
  8086. // Save input w/h
  8087. var opts = this._opts;
  8088. width != null && (opts.width = width);
  8089. height != null && (opts.height = height);
  8090. width = this._getSize(0);
  8091. height = this._getSize(1);
  8092. domRoot.style.display = '';
  8093. // 优化没有实际改变的resize
  8094. if (this._width != width || height != this._height) {
  8095. domRoot.style.width = width + 'px';
  8096. domRoot.style.height = height + 'px';
  8097. for (var id in this._layers) {
  8098. if (this._layers.hasOwnProperty(id)) {
  8099. this._layers[id].resize(width, height);
  8100. }
  8101. }
  8102. each(this._progressiveLayers, function (layer) {
  8103. layer.resize(width, height);
  8104. });
  8105. this.refresh(true);
  8106. }
  8107. this._width = width;
  8108. this._height = height;
  8109. return this;
  8110. },
  8111. /**
  8112. * 清除单独的一个层
  8113. * @param {number} zlevel
  8114. */
  8115. clearLayer: function (zlevel) {
  8116. var layer = this._layers[zlevel];
  8117. if (layer) {
  8118. layer.clear();
  8119. }
  8120. },
  8121. /**
  8122. * 释放
  8123. */
  8124. dispose: function () {
  8125. this.root.innerHTML = '';
  8126. this.root =
  8127. this.storage =
  8128. this._domRoot =
  8129. this._layers = null;
  8130. },
  8131. /**
  8132. * Get canvas which has all thing rendered
  8133. * @param {Object} opts
  8134. * @param {string} [opts.backgroundColor]
  8135. * @param {number} [opts.pixelRatio]
  8136. */
  8137. getRenderedCanvas: function (opts) {
  8138. opts = opts || {};
  8139. if (this._singleCanvas) {
  8140. return this._layers[0].dom;
  8141. }
  8142. var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
  8143. imageLayer.initContext();
  8144. imageLayer.clearColor = opts.backgroundColor;
  8145. imageLayer.clear();
  8146. var displayList = this.storage.getDisplayList(true);
  8147. var scope = {};
  8148. var zlevel;
  8149. var self = this;
  8150. function findAndDrawOtherLayer(smaller, larger) {
  8151. var zlevelList = self._zlevelList;
  8152. if (smaller == null) {
  8153. smaller = -Infinity;
  8154. }
  8155. var intermediateLayer;
  8156. for (var i = 0; i < zlevelList.length; i++) {
  8157. var z = zlevelList[i];
  8158. var layer = self._layers[z];
  8159. if (!layer.__builtin__ && z > smaller && z < larger) {
  8160. intermediateLayer = layer;
  8161. break;
  8162. }
  8163. }
  8164. if (intermediateLayer && intermediateLayer.renderToCanvas) {
  8165. imageLayer.ctx.save();
  8166. intermediateLayer.renderToCanvas(imageLayer.ctx);
  8167. imageLayer.ctx.restore();
  8168. }
  8169. }
  8170. for (var i = 0; i < displayList.length; i++) {
  8171. var el = displayList[i];
  8172. if (el.zlevel !== zlevel) {
  8173. findAndDrawOtherLayer(zlevel, el.zlevel);
  8174. zlevel = el.zlevel;
  8175. }
  8176. this._doPaintEl(el, imageLayer, true, scope);
  8177. }
  8178. findAndDrawOtherLayer(zlevel, Infinity);
  8179. return imageLayer.dom;
  8180. },
  8181. /**
  8182. * 获取绘图区域宽度
  8183. */
  8184. getWidth: function () {
  8185. return this._width;
  8186. },
  8187. /**
  8188. * 获取绘图区域高度
  8189. */
  8190. getHeight: function () {
  8191. return this._height;
  8192. },
  8193. _getSize: function (whIdx) {
  8194. var opts = this._opts;
  8195. var wh = ['width', 'height'][whIdx];
  8196. var cwh = ['clientWidth', 'clientHeight'][whIdx];
  8197. var plt = ['paddingLeft', 'paddingTop'][whIdx];
  8198. var prb = ['paddingRight', 'paddingBottom'][whIdx];
  8199. if (opts[wh] != null && opts[wh] !== 'auto') {
  8200. return parseFloat(opts[wh]);
  8201. }
  8202. var root = this.root;
  8203. // IE8 does not support getComputedStyle, but it use VML.
  8204. var stl = document.defaultView.getComputedStyle(root);
  8205. return (
  8206. (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))
  8207. - (parseInt10(stl[plt]) || 0)
  8208. - (parseInt10(stl[prb]) || 0)
  8209. ) | 0;
  8210. },
  8211. pathToImage: function (path, dpr) {
  8212. dpr = dpr || this.dpr;
  8213. var canvas = document.createElement('canvas');
  8214. var ctx = canvas.getContext('2d');
  8215. var rect = path.getBoundingRect();
  8216. var style = path.style;
  8217. var shadowBlurSize = style.shadowBlur;
  8218. var shadowOffsetX = style.shadowOffsetX;
  8219. var shadowOffsetY = style.shadowOffsetY;
  8220. var lineWidth = style.hasStroke() ? style.lineWidth : 0;
  8221. var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);
  8222. var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);
  8223. var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);
  8224. var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);
  8225. var width = rect.width + leftMargin + rightMargin;
  8226. var height = rect.height + topMargin + bottomMargin;
  8227. canvas.width = width * dpr;
  8228. canvas.height = height * dpr;
  8229. ctx.scale(dpr, dpr);
  8230. ctx.clearRect(0, 0, width, height);
  8231. ctx.dpr = dpr;
  8232. var pathTransform = {
  8233. position: path.position,
  8234. rotation: path.rotation,
  8235. scale: path.scale
  8236. };
  8237. path.position = [leftMargin - rect.x, topMargin - rect.y];
  8238. path.rotation = 0;
  8239. path.scale = [1, 1];
  8240. path.updateTransform();
  8241. if (path) {
  8242. path.brush(ctx);
  8243. }
  8244. var ImageShape = ZImage;
  8245. var imgShape = new ImageShape({
  8246. style: {
  8247. x: 0,
  8248. y: 0,
  8249. image: canvas
  8250. }
  8251. });
  8252. if (pathTransform.position != null) {
  8253. imgShape.position = path.position = pathTransform.position;
  8254. }
  8255. if (pathTransform.rotation != null) {
  8256. imgShape.rotation = path.rotation = pathTransform.rotation;
  8257. }
  8258. if (pathTransform.scale != null) {
  8259. imgShape.scale = path.scale = pathTransform.scale;
  8260. }
  8261. return imgShape;
  8262. }
  8263. };
  8264. /**
  8265. * 事件辅助类
  8266. * @module zrender/core/event
  8267. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  8268. */
  8269. var isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;
  8270. var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
  8271. function getBoundingClientRect(el) {
  8272. // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect
  8273. return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};
  8274. }
  8275. // `calculate` is optional, default false
  8276. function clientToLocal(el, e, out, calculate) {
  8277. out = out || {};
  8278. // According to the W3C Working Draft, offsetX and offsetY should be relative
  8279. // to the padding edge of the target element. The only browser using this convention
  8280. // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does
  8281. // not support the properties.
  8282. // (see http://www.jacklmoore.com/notes/mouse-position/)
  8283. // In zr painter.dom, padding edge equals to border edge.
  8284. // FIXME
  8285. // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and
  8286. // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y
  8287. // is too complex. So css-transfrom dont support in this case temporarily.
  8288. if (calculate || !env$1.canvasSupported) {
  8289. defaultGetZrXY(el, e, out);
  8290. }
  8291. // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned
  8292. // ancestor element, so we should make sure el is positioned (e.g., not position:static).
  8293. // BTW1, Webkit don't return the same results as FF in non-simple cases (like add
  8294. // zoom-factor, overflow / opacity layers, transforms ...)
  8295. // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.
  8296. // <https://bugs.jquery.com/ticket/8523#comment:14>
  8297. // BTW3, In ff, offsetX/offsetY is always 0.
  8298. else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {
  8299. out.zrX = e.layerX;
  8300. out.zrY = e.layerY;
  8301. }
  8302. // For IE6+, chrome, safari, opera. (When will ff support offsetX?)
  8303. else if (e.offsetX != null) {
  8304. out.zrX = e.offsetX;
  8305. out.zrY = e.offsetY;
  8306. }
  8307. // For some other device, e.g., IOS safari.
  8308. else {
  8309. defaultGetZrXY(el, e, out);
  8310. }
  8311. return out;
  8312. }
  8313. function defaultGetZrXY(el, e, out) {
  8314. // This well-known method below does not support css transform.
  8315. var box = getBoundingClientRect(el);
  8316. out.zrX = e.clientX - box.left;
  8317. out.zrY = e.clientY - box.top;
  8318. }
  8319. /**
  8320. * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标.
  8321. * `calculate` is optional, default false.
  8322. */
  8323. function normalizeEvent(el, e, calculate) {
  8324. e = e || window.event;
  8325. if (e.zrX != null) {
  8326. return e;
  8327. }
  8328. var eventType = e.type;
  8329. var isTouch = eventType && eventType.indexOf('touch') >= 0;
  8330. if (!isTouch) {
  8331. clientToLocal(el, e, e, calculate);
  8332. e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
  8333. }
  8334. else {
  8335. var touch = eventType != 'touchend'
  8336. ? e.targetTouches[0]
  8337. : e.changedTouches[0];
  8338. touch && clientToLocal(el, touch, e, calculate);
  8339. }
  8340. // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;
  8341. // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js
  8342. // If e.which has been defined, if may be readonly,
  8343. // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
  8344. var button = e.button;
  8345. if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
  8346. e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));
  8347. }
  8348. return e;
  8349. }
  8350. function addEventListener(el, name, handler) {
  8351. if (isDomLevel2) {
  8352. el.addEventListener(name, handler);
  8353. }
  8354. else {
  8355. el.attachEvent('on' + name, handler);
  8356. }
  8357. }
  8358. function removeEventListener(el, name, handler) {
  8359. if (isDomLevel2) {
  8360. el.removeEventListener(name, handler);
  8361. }
  8362. else {
  8363. el.detachEvent('on' + name, handler);
  8364. }
  8365. }
  8366. /**
  8367. * preventDefault and stopPropagation.
  8368. * Notice: do not do that in zrender. Upper application
  8369. * do that if necessary.
  8370. *
  8371. * @memberOf module:zrender/core/event
  8372. * @method
  8373. * @param {Event} e : event对象
  8374. */
  8375. /**
  8376. * 动画主类, 调度和管理所有动画控制器
  8377. *
  8378. * @module zrender/animation/Animation
  8379. * @author pissang(https://github.com/pissang)
  8380. */
  8381. // TODO Additive animation
  8382. // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
  8383. // https://developer.apple.com/videos/wwdc2014/#236
  8384. /**
  8385. * @typedef {Object} IZRenderStage
  8386. * @property {Function} update
  8387. */
  8388. /**
  8389. * @alias module:zrender/animation/Animation
  8390. * @constructor
  8391. * @param {Object} [options]
  8392. * @param {Function} [options.onframe]
  8393. * @param {IZRenderStage} [options.stage]
  8394. * @example
  8395. * var animation = new Animation();
  8396. * var obj = {
  8397. * x: 100,
  8398. * y: 100
  8399. * };
  8400. * animation.animate(node.position)
  8401. * .when(1000, {
  8402. * x: 500,
  8403. * y: 500
  8404. * })
  8405. * .when(2000, {
  8406. * x: 100,
  8407. * y: 100
  8408. * })
  8409. * .start('spline');
  8410. */
  8411. var Animation = function (options) {
  8412. options = options || {};
  8413. this.stage = options.stage || {};
  8414. this.onframe = options.onframe || function() {};
  8415. // private properties
  8416. this._clips = [];
  8417. this._running = false;
  8418. this._time;
  8419. this._pausedTime;
  8420. this._pauseStart;
  8421. this._paused = false;
  8422. Eventful.call(this);
  8423. };
  8424. Animation.prototype = {
  8425. constructor: Animation,
  8426. /**
  8427. * 添加 clip
  8428. * @param {module:zrender/animation/Clip} clip
  8429. */
  8430. addClip: function (clip) {
  8431. this._clips.push(clip);
  8432. },
  8433. /**
  8434. * 添加 animator
  8435. * @param {module:zrender/animation/Animator} animator
  8436. */
  8437. addAnimator: function (animator) {
  8438. animator.animation = this;
  8439. var clips = animator.getClips();
  8440. for (var i = 0; i < clips.length; i++) {
  8441. this.addClip(clips[i]);
  8442. }
  8443. },
  8444. /**
  8445. * 删除动画片段
  8446. * @param {module:zrender/animation/Clip} clip
  8447. */
  8448. removeClip: function(clip) {
  8449. var idx = indexOf(this._clips, clip);
  8450. if (idx >= 0) {
  8451. this._clips.splice(idx, 1);
  8452. }
  8453. },
  8454. /**
  8455. * 删除动画片段
  8456. * @param {module:zrender/animation/Animator} animator
  8457. */
  8458. removeAnimator: function (animator) {
  8459. var clips = animator.getClips();
  8460. for (var i = 0; i < clips.length; i++) {
  8461. this.removeClip(clips[i]);
  8462. }
  8463. animator.animation = null;
  8464. },
  8465. _update: function() {
  8466. var time = new Date().getTime() - this._pausedTime;
  8467. var delta = time - this._time;
  8468. var clips = this._clips;
  8469. var len = clips.length;
  8470. var deferredEvents = [];
  8471. var deferredClips = [];
  8472. for (var i = 0; i < len; i++) {
  8473. var clip = clips[i];
  8474. var e = clip.step(time, delta);
  8475. // Throw out the events need to be called after
  8476. // stage.update, like destroy
  8477. if (e) {
  8478. deferredEvents.push(e);
  8479. deferredClips.push(clip);
  8480. }
  8481. }
  8482. // Remove the finished clip
  8483. for (var i = 0; i < len;) {
  8484. if (clips[i]._needsRemove) {
  8485. clips[i] = clips[len - 1];
  8486. clips.pop();
  8487. len--;
  8488. }
  8489. else {
  8490. i++;
  8491. }
  8492. }
  8493. len = deferredEvents.length;
  8494. for (var i = 0; i < len; i++) {
  8495. deferredClips[i].fire(deferredEvents[i]);
  8496. }
  8497. this._time = time;
  8498. this.onframe(delta);
  8499. this.trigger('frame', delta);
  8500. if (this.stage.update) {
  8501. this.stage.update();
  8502. }
  8503. },
  8504. _startLoop: function () {
  8505. var self = this;
  8506. this._running = true;
  8507. function step() {
  8508. if (self._running) {
  8509. requestAnimationFrame(step);
  8510. !self._paused && self._update();
  8511. }
  8512. }
  8513. requestAnimationFrame(step);
  8514. },
  8515. /**
  8516. * 开始运行动画
  8517. */
  8518. start: function () {
  8519. this._time = new Date().getTime();
  8520. this._pausedTime = 0;
  8521. this._startLoop();
  8522. },
  8523. /**
  8524. * 停止运行动画
  8525. */
  8526. stop: function () {
  8527. this._running = false;
  8528. },
  8529. /**
  8530. * Pause
  8531. */
  8532. pause: function () {
  8533. if (!this._paused) {
  8534. this._pauseStart = new Date().getTime();
  8535. this._paused = true;
  8536. }
  8537. },
  8538. /**
  8539. * Resume
  8540. */
  8541. resume: function () {
  8542. if (this._paused) {
  8543. this._pausedTime += (new Date().getTime()) - this._pauseStart;
  8544. this._paused = false;
  8545. }
  8546. },
  8547. /**
  8548. * 清除所有动画片段
  8549. */
  8550. clear: function () {
  8551. this._clips = [];
  8552. },
  8553. /**
  8554. * 对一个目标创建一个animator对象,可以指定目标中的属性使用动画
  8555. * @param {Object} target
  8556. * @param {Object} options
  8557. * @param {boolean} [options.loop=false] 是否循环播放动画
  8558. * @param {Function} [options.getter=null]
  8559. * 如果指定getter函数,会通过getter函数取属性值
  8560. * @param {Function} [options.setter=null]
  8561. * 如果指定setter函数,会通过setter函数设置属性值
  8562. * @return {module:zrender/animation/Animation~Animator}
  8563. */
  8564. // TODO Gap
  8565. animate: function (target, options) {
  8566. options = options || {};
  8567. var animator = new Animator(
  8568. target,
  8569. options.loop,
  8570. options.getter,
  8571. options.setter
  8572. );
  8573. this.addAnimator(animator);
  8574. return animator;
  8575. }
  8576. };
  8577. mixin(Animation, Eventful);
  8578. /**
  8579. * Only implements needed gestures for mobile.
  8580. */
  8581. var GestureMgr = function () {
  8582. /**
  8583. * @private
  8584. * @type {Array.<Object>}
  8585. */
  8586. this._track = [];
  8587. };
  8588. GestureMgr.prototype = {
  8589. constructor: GestureMgr,
  8590. recognize: function (event, target, root) {
  8591. this._doTrack(event, target, root);
  8592. return this._recognize(event);
  8593. },
  8594. clear: function () {
  8595. this._track.length = 0;
  8596. return this;
  8597. },
  8598. _doTrack: function (event, target, root) {
  8599. var touches = event.touches;
  8600. if (!touches) {
  8601. return;
  8602. }
  8603. var trackItem = {
  8604. points: [],
  8605. touches: [],
  8606. target: target,
  8607. event: event
  8608. };
  8609. for (var i = 0, len = touches.length; i < len; i++) {
  8610. var touch = touches[i];
  8611. var pos = clientToLocal(root, touch, {});
  8612. trackItem.points.push([pos.zrX, pos.zrY]);
  8613. trackItem.touches.push(touch);
  8614. }
  8615. this._track.push(trackItem);
  8616. },
  8617. _recognize: function (event) {
  8618. for (var eventName in recognizers) {
  8619. if (recognizers.hasOwnProperty(eventName)) {
  8620. var gestureInfo = recognizers[eventName](this._track, event);
  8621. if (gestureInfo) {
  8622. return gestureInfo;
  8623. }
  8624. }
  8625. }
  8626. }
  8627. };
  8628. function dist$1(pointPair) {
  8629. var dx = pointPair[1][0] - pointPair[0][0];
  8630. var dy = pointPair[1][1] - pointPair[0][1];
  8631. return Math.sqrt(dx * dx + dy * dy);
  8632. }
  8633. function center(pointPair) {
  8634. return [
  8635. (pointPair[0][0] + pointPair[1][0]) / 2,
  8636. (pointPair[0][1] + pointPair[1][1]) / 2
  8637. ];
  8638. }
  8639. var recognizers = {
  8640. pinch: function (track, event) {
  8641. var trackLen = track.length;
  8642. if (!trackLen) {
  8643. return;
  8644. }
  8645. var pinchEnd = (track[trackLen - 1] || {}).points;
  8646. var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;
  8647. if (pinchPre
  8648. && pinchPre.length > 1
  8649. && pinchEnd
  8650. && pinchEnd.length > 1
  8651. ) {
  8652. var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);
  8653. !isFinite(pinchScale) && (pinchScale = 1);
  8654. event.pinchScale = pinchScale;
  8655. var pinchCenter = center(pinchEnd);
  8656. event.pinchX = pinchCenter[0];
  8657. event.pinchY = pinchCenter[1];
  8658. return {
  8659. type: 'pinch',
  8660. target: track[0].target,
  8661. event: event
  8662. };
  8663. }
  8664. }
  8665. // Only pinch currently.
  8666. };
  8667. var TOUCH_CLICK_DELAY = 300;
  8668. var mouseHandlerNames = [
  8669. 'click', 'dblclick', 'mousewheel', 'mouseout',
  8670. 'mouseup', 'mousedown', 'mousemove', 'contextmenu'
  8671. ];
  8672. var touchHandlerNames = [
  8673. 'touchstart', 'touchend', 'touchmove'
  8674. ];
  8675. var pointerEventNames = {
  8676. pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1
  8677. };
  8678. var pointerHandlerNames = map(mouseHandlerNames, function (name) {
  8679. var nm = name.replace('mouse', 'pointer');
  8680. return pointerEventNames[nm] ? nm : name;
  8681. });
  8682. function eventNameFix(name) {
  8683. return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;
  8684. }
  8685. function processGesture(proxy, event, stage) {
  8686. var gestureMgr = proxy._gestureMgr;
  8687. stage === 'start' && gestureMgr.clear();
  8688. var gestureInfo = gestureMgr.recognize(
  8689. event,
  8690. proxy.handler.findHover(event.zrX, event.zrY, null).target,
  8691. proxy.dom
  8692. );
  8693. stage === 'end' && gestureMgr.clear();
  8694. // Do not do any preventDefault here. Upper application do that if necessary.
  8695. if (gestureInfo) {
  8696. var type = gestureInfo.type;
  8697. event.gestureEvent = type;
  8698. proxy.handler.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);
  8699. }
  8700. }
  8701. // function onMSGestureChange(proxy, event) {
  8702. // if (event.translationX || event.translationY) {
  8703. // // mousemove is carried by MSGesture to reduce the sensitivity.
  8704. // proxy.handler.dispatchToElement(event.target, 'mousemove', event);
  8705. // }
  8706. // if (event.scale !== 1) {
  8707. // event.pinchX = event.offsetX;
  8708. // event.pinchY = event.offsetY;
  8709. // event.pinchScale = event.scale;
  8710. // proxy.handler.dispatchToElement(event.target, 'pinch', event);
  8711. // }
  8712. // }
  8713. /**
  8714. * Prevent mouse event from being dispatched after Touch Events action
  8715. * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>
  8716. * 1. Mobile browsers dispatch mouse events 300ms after touchend.
  8717. * 2. Chrome for Android dispatch mousedown for long-touch about 650ms
  8718. * Result: Blocking Mouse Events for 700ms.
  8719. */
  8720. function setTouchTimer(instance) {
  8721. instance._touching = true;
  8722. clearTimeout(instance._touchTimer);
  8723. instance._touchTimer = setTimeout(function () {
  8724. instance._touching = false;
  8725. }, 700);
  8726. }
  8727. var domHandlers = {
  8728. /**
  8729. * Mouse move handler
  8730. * @inner
  8731. * @param {Event} event
  8732. */
  8733. mousemove: function (event) {
  8734. event = normalizeEvent(this.dom, event);
  8735. this.trigger('mousemove', event);
  8736. },
  8737. /**
  8738. * Mouse out handler
  8739. * @inner
  8740. * @param {Event} event
  8741. */
  8742. mouseout: function (event) {
  8743. event = normalizeEvent(this.dom, event);
  8744. var element = event.toElement || event.relatedTarget;
  8745. if (element != this.dom) {
  8746. while (element && element.nodeType != 9) {
  8747. // 忽略包含在root中的dom引起的mouseOut
  8748. if (element === this.dom) {
  8749. return;
  8750. }
  8751. element = element.parentNode;
  8752. }
  8753. }
  8754. this.trigger('mouseout', event);
  8755. },
  8756. /**
  8757. * Touch开始响应函数
  8758. * @inner
  8759. * @param {Event} event
  8760. */
  8761. touchstart: function (event) {
  8762. // Default mouse behaviour should not be disabled here.
  8763. // For example, page may needs to be slided.
  8764. event = normalizeEvent(this.dom, event);
  8765. // Mark touch, which is useful in distinguish touch and
  8766. // mouse event in upper applicatoin.
  8767. event.zrByTouch = true;
  8768. this._lastTouchMoment = new Date();
  8769. processGesture(this, event, 'start');
  8770. // In touch device, trigger `mousemove`(`mouseover`) should
  8771. // be triggered, and must before `mousedown` triggered.
  8772. domHandlers.mousemove.call(this, event);
  8773. domHandlers.mousedown.call(this, event);
  8774. setTouchTimer(this);
  8775. },
  8776. /**
  8777. * Touch移动响应函数
  8778. * @inner
  8779. * @param {Event} event
  8780. */
  8781. touchmove: function (event) {
  8782. event = normalizeEvent(this.dom, event);
  8783. // Mark touch, which is useful in distinguish touch and
  8784. // mouse event in upper applicatoin.
  8785. event.zrByTouch = true;
  8786. processGesture(this, event, 'change');
  8787. // Mouse move should always be triggered no matter whether
  8788. // there is gestrue event, because mouse move and pinch may
  8789. // be used at the same time.
  8790. domHandlers.mousemove.call(this, event);
  8791. setTouchTimer(this);
  8792. },
  8793. /**
  8794. * Touch结束响应函数
  8795. * @inner
  8796. * @param {Event} event
  8797. */
  8798. touchend: function (event) {
  8799. event = normalizeEvent(this.dom, event);
  8800. // Mark touch, which is useful in distinguish touch and
  8801. // mouse event in upper applicatoin.
  8802. event.zrByTouch = true;
  8803. processGesture(this, event, 'end');
  8804. domHandlers.mouseup.call(this, event);
  8805. // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is
  8806. // triggered in `touchstart`. This seems to be illogical, but by this mechanism,
  8807. // we can conveniently implement "hover style" in both PC and touch device just
  8808. // by listening to `mouseover` to add "hover style" and listening to `mouseout`
  8809. // to remove "hover style" on an element, without any additional code for
  8810. // compatibility. (`mouseout` will not be triggered in `touchend`, so "hover
  8811. // style" will remain for user view)
  8812. // click event should always be triggered no matter whether
  8813. // there is gestrue event. System click can not be prevented.
  8814. if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {
  8815. domHandlers.click.call(this, event);
  8816. }
  8817. setTouchTimer(this);
  8818. },
  8819. pointerdown: function (event) {
  8820. domHandlers.mousedown.call(this, event);
  8821. // if (useMSGuesture(this, event)) {
  8822. // this._msGesture.addPointer(event.pointerId);
  8823. // }
  8824. },
  8825. pointermove: function (event) {
  8826. // FIXME
  8827. // pointermove is so sensitive that it always triggered when
  8828. // tap(click) on touch screen, which affect some judgement in
  8829. // upper application. So, we dont support mousemove on MS touch
  8830. // device yet.
  8831. if (!isPointerFromTouch(event)) {
  8832. domHandlers.mousemove.call(this, event);
  8833. }
  8834. },
  8835. pointerup: function (event) {
  8836. domHandlers.mouseup.call(this, event);
  8837. },
  8838. pointerout: function (event) {
  8839. // pointerout will be triggered when tap on touch screen
  8840. // (IE11+/Edge on MS Surface) after click event triggered,
  8841. // which is inconsistent with the mousout behavior we defined
  8842. // in touchend. So we unify them.
  8843. // (check domHandlers.touchend for detailed explanation)
  8844. if (!isPointerFromTouch(event)) {
  8845. domHandlers.mouseout.call(this, event);
  8846. }
  8847. }
  8848. };
  8849. function isPointerFromTouch(event) {
  8850. var pointerType = event.pointerType;
  8851. return pointerType === 'pen' || pointerType === 'touch';
  8852. }
  8853. // function useMSGuesture(handlerProxy, event) {
  8854. // return isPointerFromTouch(event) && !!handlerProxy._msGesture;
  8855. // }
  8856. // Common handlers
  8857. each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
  8858. domHandlers[name] = function (event) {
  8859. event = normalizeEvent(this.dom, event);
  8860. this.trigger(name, event);
  8861. };
  8862. });
  8863. /**
  8864. * 为控制类实例初始化dom 事件处理函数
  8865. *
  8866. * @inner
  8867. * @param {module:zrender/Handler} instance 控制类实例
  8868. */
  8869. function initDomHandler(instance) {
  8870. each(touchHandlerNames, function (name) {
  8871. instance._handlers[name] = bind(domHandlers[name], instance);
  8872. });
  8873. each(pointerHandlerNames, function (name) {
  8874. instance._handlers[name] = bind(domHandlers[name], instance);
  8875. });
  8876. each(mouseHandlerNames, function (name) {
  8877. instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);
  8878. });
  8879. function makeMouseHandler(fn, instance) {
  8880. return function () {
  8881. if (instance._touching) {
  8882. return;
  8883. }
  8884. return fn.apply(instance, arguments);
  8885. };
  8886. }
  8887. }
  8888. function HandlerDomProxy(dom) {
  8889. Eventful.call(this);
  8890. this.dom = dom;
  8891. /**
  8892. * @private
  8893. * @type {boolean}
  8894. */
  8895. this._touching = false;
  8896. /**
  8897. * @private
  8898. * @type {number}
  8899. */
  8900. this._touchTimer;
  8901. /**
  8902. * @private
  8903. * @type {module:zrender/core/GestureMgr}
  8904. */
  8905. this._gestureMgr = new GestureMgr();
  8906. this._handlers = {};
  8907. initDomHandler(this);
  8908. if (env$1.pointerEventsSupported) { // Only IE11+/Edge
  8909. // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),
  8910. // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event
  8911. // at the same time.
  8912. // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on
  8913. // screen, which do not occurs in pointer event.
  8914. // So we use pointer event to both detect touch gesture and mouse behavior.
  8915. mountHandlers(pointerHandlerNames, this);
  8916. // FIXME
  8917. // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,
  8918. // which does not prevent defuault behavior occasionally (which may cause view port
  8919. // zoomed in but use can not zoom it back). And event.preventDefault() does not work.
  8920. // So we have to not to use MSGesture and not to support touchmove and pinch on MS
  8921. // touch screen. And we only support click behavior on MS touch screen now.
  8922. // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.
  8923. // We dont support touch on IE on win7.
  8924. // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>
  8925. // if (typeof MSGesture === 'function') {
  8926. // (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line
  8927. // dom.addEventListener('MSGestureChange', onMSGestureChange);
  8928. // }
  8929. }
  8930. else {
  8931. if (env$1.touchEventsSupported) {
  8932. mountHandlers(touchHandlerNames, this);
  8933. // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.
  8934. // addEventListener(root, 'mouseout', this._mouseoutHandler);
  8935. }
  8936. // 1. Considering some devices that both enable touch and mouse event (like on MS Surface
  8937. // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise
  8938. // mouse event can not be handle in those devices.
  8939. // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent
  8940. // mouseevent after touch event triggered, see `setTouchTimer`.
  8941. mountHandlers(mouseHandlerNames, this);
  8942. }
  8943. function mountHandlers(handlerNames, instance) {
  8944. each(handlerNames, function (name) {
  8945. addEventListener(dom, eventNameFix(name), instance._handlers[name]);
  8946. }, instance);
  8947. }
  8948. }
  8949. var handlerDomProxyProto = HandlerDomProxy.prototype;
  8950. handlerDomProxyProto.dispose = function () {
  8951. var handlerNames = mouseHandlerNames.concat(touchHandlerNames);
  8952. for (var i = 0; i < handlerNames.length; i++) {
  8953. var name = handlerNames[i];
  8954. removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);
  8955. }
  8956. };
  8957. handlerDomProxyProto.setCursor = function (cursorStyle) {
  8958. this.dom.style.cursor = cursorStyle || 'default';
  8959. };
  8960. mixin(HandlerDomProxy, Eventful);
  8961. /*!
  8962. * ZRender, a high performance 2d drawing library.
  8963. *
  8964. * Copyright (c) 2013, Baidu Inc.
  8965. * All rights reserved.
  8966. *
  8967. * LICENSE
  8968. * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
  8969. */
  8970. var useVML = !env$1.canvasSupported;
  8971. var painterCtors = {
  8972. canvas: Painter
  8973. };
  8974. var instances = {}; // ZRender实例map索引
  8975. /**
  8976. * @type {string}
  8977. */
  8978. var version = '3.7.4';
  8979. /**
  8980. * Initializing a zrender instance
  8981. * @param {HTMLElement} dom
  8982. * @param {Object} opts
  8983. * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
  8984. * @param {number} [opts.devicePixelRatio]
  8985. * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)
  8986. * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)
  8987. * @return {module:zrender/ZRender}
  8988. */
  8989. function init(dom, opts) {
  8990. var zr = new ZRender(guid(), dom, opts);
  8991. instances[zr.id] = zr;
  8992. return zr;
  8993. }
  8994. /**
  8995. * Dispose zrender instance
  8996. * @param {module:zrender/ZRender} zr
  8997. */
  8998. function dispose(zr) {
  8999. if (zr) {
  9000. zr.dispose();
  9001. }
  9002. else {
  9003. for (var key in instances) {
  9004. if (instances.hasOwnProperty(key)) {
  9005. instances[key].dispose();
  9006. }
  9007. }
  9008. instances = {};
  9009. }
  9010. return this;
  9011. }
  9012. /**
  9013. * Get zrender instance by id
  9014. * @param {string} id zrender instance id
  9015. * @return {module:zrender/ZRender}
  9016. */
  9017. function getInstance(id) {
  9018. return instances[id];
  9019. }
  9020. function registerPainter(name, Ctor) {
  9021. painterCtors[name] = Ctor;
  9022. }
  9023. function delInstance(id) {
  9024. delete instances[id];
  9025. }
  9026. /**
  9027. * @module zrender/ZRender
  9028. */
  9029. /**
  9030. * @constructor
  9031. * @alias module:zrender/ZRender
  9032. * @param {string} id
  9033. * @param {HTMLElement} dom
  9034. * @param {Object} opts
  9035. * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'
  9036. * @param {number} [opts.devicePixelRatio]
  9037. * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)
  9038. * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)
  9039. */
  9040. var ZRender = function (id, dom, opts) {
  9041. opts = opts || {};
  9042. /**
  9043. * @type {HTMLDomElement}
  9044. */
  9045. this.dom = dom;
  9046. /**
  9047. * @type {string}
  9048. */
  9049. this.id = id;
  9050. var self = this;
  9051. var storage = new Storage();
  9052. var rendererType = opts.renderer;
  9053. // TODO WebGL
  9054. if (useVML) {
  9055. if (!painterCtors.vml) {
  9056. throw new Error('You need to require \'zrender/vml/vml\' to support IE8');
  9057. }
  9058. rendererType = 'vml';
  9059. }
  9060. else if (!rendererType || !painterCtors[rendererType]) {
  9061. rendererType = 'canvas';
  9062. }
  9063. var painter = new painterCtors[rendererType](dom, storage, opts);
  9064. this.storage = storage;
  9065. this.painter = painter;
  9066. var handerProxy = !env$1.node ? new HandlerDomProxy(painter.getViewportRoot()) : null;
  9067. this.handler = new Handler(storage, painter, handerProxy, painter.root);
  9068. /**
  9069. * @type {module:zrender/animation/Animation}
  9070. */
  9071. this.animation = new Animation({
  9072. stage: {
  9073. update: bind(this.flush, this)
  9074. }
  9075. });
  9076. this.animation.start();
  9077. /**
  9078. * @type {boolean}
  9079. * @private
  9080. */
  9081. this._needsRefresh;
  9082. // 修改 storage.delFromStorage, 每次删除元素之前删除动画
  9083. // FIXME 有点ugly
  9084. var oldDelFromStorage = storage.delFromStorage;
  9085. var oldAddToStorage = storage.addToStorage;
  9086. storage.delFromStorage = function (el) {
  9087. oldDelFromStorage.call(storage, el);
  9088. el && el.removeSelfFromZr(self);
  9089. };
  9090. storage.addToStorage = function (el) {
  9091. oldAddToStorage.call(storage, el);
  9092. el.addSelfToZr(self);
  9093. };
  9094. };
  9095. ZRender.prototype = {
  9096. constructor: ZRender,
  9097. /**
  9098. * 获取实例唯一标识
  9099. * @return {string}
  9100. */
  9101. getId: function () {
  9102. return this.id;
  9103. },
  9104. /**
  9105. * 添加元素
  9106. * @param {module:zrender/Element} el
  9107. */
  9108. add: function (el) {
  9109. this.storage.addRoot(el);
  9110. this._needsRefresh = true;
  9111. },
  9112. /**
  9113. * 删除元素
  9114. * @param {module:zrender/Element} el
  9115. */
  9116. remove: function (el) {
  9117. this.storage.delRoot(el);
  9118. this._needsRefresh = true;
  9119. },
  9120. /**
  9121. * Change configuration of layer
  9122. * @param {string} zLevel
  9123. * @param {Object} config
  9124. * @param {string} [config.clearColor=0] Clear color
  9125. * @param {string} [config.motionBlur=false] If enable motion blur
  9126. * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer
  9127. */
  9128. configLayer: function (zLevel, config) {
  9129. this.painter.configLayer(zLevel, config);
  9130. this._needsRefresh = true;
  9131. },
  9132. /**
  9133. * Repaint the canvas immediately
  9134. */
  9135. refreshImmediately: function () {
  9136. // var start = new Date();
  9137. // Clear needsRefresh ahead to avoid something wrong happens in refresh
  9138. // Or it will cause zrender refreshes again and again.
  9139. this._needsRefresh = false;
  9140. this.painter.refresh();
  9141. /**
  9142. * Avoid trigger zr.refresh in Element#beforeUpdate hook
  9143. */
  9144. this._needsRefresh = false;
  9145. // var end = new Date();
  9146. // var log = document.getElementById('log');
  9147. // if (log) {
  9148. // log.innerHTML = log.innerHTML + '<br>' + (end - start);
  9149. // }
  9150. },
  9151. /**
  9152. * Mark and repaint the canvas in the next frame of browser
  9153. */
  9154. refresh: function() {
  9155. this._needsRefresh = true;
  9156. },
  9157. /**
  9158. * Perform all refresh
  9159. */
  9160. flush: function () {
  9161. if (this._needsRefresh) {
  9162. this.refreshImmediately();
  9163. }
  9164. if (this._needsRefreshHover) {
  9165. this.refreshHoverImmediately();
  9166. }
  9167. },
  9168. /**
  9169. * Add element to hover layer
  9170. * @param {module:zrender/Element} el
  9171. * @param {Object} style
  9172. */
  9173. addHover: function (el, style) {
  9174. if (this.painter.addHover) {
  9175. this.painter.addHover(el, style);
  9176. this.refreshHover();
  9177. }
  9178. },
  9179. /**
  9180. * Add element from hover layer
  9181. * @param {module:zrender/Element} el
  9182. */
  9183. removeHover: function (el) {
  9184. if (this.painter.removeHover) {
  9185. this.painter.removeHover(el);
  9186. this.refreshHover();
  9187. }
  9188. },
  9189. /**
  9190. * Clear all hover elements in hover layer
  9191. * @param {module:zrender/Element} el
  9192. */
  9193. clearHover: function () {
  9194. if (this.painter.clearHover) {
  9195. this.painter.clearHover();
  9196. this.refreshHover();
  9197. }
  9198. },
  9199. /**
  9200. * Refresh hover in next frame
  9201. */
  9202. refreshHover: function () {
  9203. this._needsRefreshHover = true;
  9204. },
  9205. /**
  9206. * Refresh hover immediately
  9207. */
  9208. refreshHoverImmediately: function () {
  9209. this._needsRefreshHover = false;
  9210. this.painter.refreshHover && this.painter.refreshHover();
  9211. },
  9212. /**
  9213. * Resize the canvas.
  9214. * Should be invoked when container size is changed
  9215. * @param {Object} [opts]
  9216. * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)
  9217. * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)
  9218. */
  9219. resize: function(opts) {
  9220. opts = opts || {};
  9221. this.painter.resize(opts.width, opts.height);
  9222. this.handler.resize();
  9223. },
  9224. /**
  9225. * Stop and clear all animation immediately
  9226. */
  9227. clearAnimation: function () {
  9228. this.animation.clear();
  9229. },
  9230. /**
  9231. * Get container width
  9232. */
  9233. getWidth: function() {
  9234. return this.painter.getWidth();
  9235. },
  9236. /**
  9237. * Get container height
  9238. */
  9239. getHeight: function() {
  9240. return this.painter.getHeight();
  9241. },
  9242. /**
  9243. * Export the canvas as Base64 URL
  9244. * @param {string} type
  9245. * @param {string} [backgroundColor='#fff']
  9246. * @return {string} Base64 URL
  9247. */
  9248. // toDataURL: function(type, backgroundColor) {
  9249. // return this.painter.getRenderedCanvas({
  9250. // backgroundColor: backgroundColor
  9251. // }).toDataURL(type);
  9252. // },
  9253. /**
  9254. * Converting a path to image.
  9255. * It has much better performance of drawing image rather than drawing a vector path.
  9256. * @param {module:zrender/graphic/Path} e
  9257. * @param {number} width
  9258. * @param {number} height
  9259. */
  9260. pathToImage: function(e, dpr) {
  9261. return this.painter.pathToImage(e, dpr);
  9262. },
  9263. /**
  9264. * Set default cursor
  9265. * @param {string} [cursorStyle='default'] 例如 crosshair
  9266. */
  9267. setCursorStyle: function (cursorStyle) {
  9268. this.handler.setCursorStyle(cursorStyle);
  9269. },
  9270. /**
  9271. * Find hovered element
  9272. * @param {number} x
  9273. * @param {number} y
  9274. * @return {Object} {target, topTarget}
  9275. */
  9276. findHover: function (x, y) {
  9277. return this.handler.findHover(x, y);
  9278. },
  9279. /**
  9280. * Bind event
  9281. *
  9282. * @param {string} eventName Event name
  9283. * @param {Function} eventHandler Handler function
  9284. * @param {Object} [context] Context object
  9285. */
  9286. on: function(eventName, eventHandler, context) {
  9287. this.handler.on(eventName, eventHandler, context);
  9288. },
  9289. /**
  9290. * Unbind event
  9291. * @param {string} eventName Event name
  9292. * @param {Function} [eventHandler] Handler function
  9293. */
  9294. off: function(eventName, eventHandler) {
  9295. this.handler.off(eventName, eventHandler);
  9296. },
  9297. /**
  9298. * Trigger event manually
  9299. *
  9300. * @param {string} eventName Event name
  9301. * @param {event=} event Event object
  9302. */
  9303. trigger: function (eventName, event) {
  9304. this.handler.trigger(eventName, event);
  9305. },
  9306. /**
  9307. * Clear all objects and the canvas.
  9308. */
  9309. clear: function () {
  9310. this.storage.delRoot();
  9311. this.painter.clear();
  9312. },
  9313. /**
  9314. * Dispose self.
  9315. */
  9316. dispose: function () {
  9317. this.animation.stop();
  9318. this.clear();
  9319. this.storage.dispose();
  9320. this.painter.dispose();
  9321. this.handler.dispose();
  9322. this.animation =
  9323. this.storage =
  9324. this.painter =
  9325. this.handler = null;
  9326. delInstance(this.id);
  9327. }
  9328. };
  9329. /**
  9330. * 曲线辅助模块
  9331. * @module zrender/core/curve
  9332. * @author pissang(https://www.github.com/pissang)
  9333. */
  9334. var mathPow = Math.pow;
  9335. var mathSqrt$2 = Math.sqrt;
  9336. var EPSILON$1 = 1e-8;
  9337. var EPSILON_NUMERIC = 1e-4;
  9338. var THREE_SQRT = mathSqrt$2(3);
  9339. var ONE_THIRD = 1 / 3;
  9340. // 临时变量
  9341. var _v0 = create();
  9342. var _v1 = create();
  9343. var _v2 = create();
  9344. function isAroundZero(val) {
  9345. return val > -EPSILON$1 && val < EPSILON$1;
  9346. }
  9347. function isNotAroundZero$1(val) {
  9348. return val > EPSILON$1 || val < -EPSILON$1;
  9349. }
  9350. /**
  9351. * 计算三次贝塞尔值
  9352. * @memberOf module:zrender/core/curve
  9353. * @param {number} p0
  9354. * @param {number} p1
  9355. * @param {number} p2
  9356. * @param {number} p3
  9357. * @param {number} t
  9358. * @return {number}
  9359. */
  9360. function cubicAt(p0, p1, p2, p3, t) {
  9361. var onet = 1 - t;
  9362. return onet * onet * (onet * p0 + 3 * t * p1)
  9363. + t * t * (t * p3 + 3 * onet * p2);
  9364. }
  9365. /**
  9366. * 计算三次贝塞尔导数值
  9367. * @memberOf module:zrender/core/curve
  9368. * @param {number} p0
  9369. * @param {number} p1
  9370. * @param {number} p2
  9371. * @param {number} p3
  9372. * @param {number} t
  9373. * @return {number}
  9374. */
  9375. function cubicDerivativeAt(p0, p1, p2, p3, t) {
  9376. var onet = 1 - t;
  9377. return 3 * (
  9378. ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet
  9379. + (p3 - p2) * t * t
  9380. );
  9381. }
  9382. /**
  9383. * 计算三次贝塞尔方程根,使用盛金公式
  9384. * @memberOf module:zrender/core/curve
  9385. * @param {number} p0
  9386. * @param {number} p1
  9387. * @param {number} p2
  9388. * @param {number} p3
  9389. * @param {number} val
  9390. * @param {Array.<number>} roots
  9391. * @return {number} 有效根数目
  9392. */
  9393. function cubicRootAt(p0, p1, p2, p3, val, roots) {
  9394. // Evaluate roots of cubic functions
  9395. var a = p3 + 3 * (p1 - p2) - p0;
  9396. var b = 3 * (p2 - p1 * 2 + p0);
  9397. var c = 3 * (p1 - p0);
  9398. var d = p0 - val;
  9399. var A = b * b - 3 * a * c;
  9400. var B = b * c - 9 * a * d;
  9401. var C = c * c - 3 * b * d;
  9402. var n = 0;
  9403. if (isAroundZero(A) && isAroundZero(B)) {
  9404. if (isAroundZero(b)) {
  9405. roots[0] = 0;
  9406. }
  9407. else {
  9408. var t1 = -c / b; //t1, t2, t3, b is not zero
  9409. if (t1 >= 0 && t1 <= 1) {
  9410. roots[n++] = t1;
  9411. }
  9412. }
  9413. }
  9414. else {
  9415. var disc = B * B - 4 * A * C;
  9416. if (isAroundZero(disc)) {
  9417. var K = B / A;
  9418. var t1 = -b / a + K; // t1, a is not zero
  9419. var t2 = -K / 2; // t2, t3
  9420. if (t1 >= 0 && t1 <= 1) {
  9421. roots[n++] = t1;
  9422. }
  9423. if (t2 >= 0 && t2 <= 1) {
  9424. roots[n++] = t2;
  9425. }
  9426. }
  9427. else if (disc > 0) {
  9428. var discSqrt = mathSqrt$2(disc);
  9429. var Y1 = A * b + 1.5 * a * (-B + discSqrt);
  9430. var Y2 = A * b + 1.5 * a * (-B - discSqrt);
  9431. if (Y1 < 0) {
  9432. Y1 = -mathPow(-Y1, ONE_THIRD);
  9433. }
  9434. else {
  9435. Y1 = mathPow(Y1, ONE_THIRD);
  9436. }
  9437. if (Y2 < 0) {
  9438. Y2 = -mathPow(-Y2, ONE_THIRD);
  9439. }
  9440. else {
  9441. Y2 = mathPow(Y2, ONE_THIRD);
  9442. }
  9443. var t1 = (-b - (Y1 + Y2)) / (3 * a);
  9444. if (t1 >= 0 && t1 <= 1) {
  9445. roots[n++] = t1;
  9446. }
  9447. }
  9448. else {
  9449. var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));
  9450. var theta = Math.acos(T) / 3;
  9451. var ASqrt = mathSqrt$2(A);
  9452. var tmp = Math.cos(theta);
  9453. var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
  9454. var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
  9455. var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);
  9456. if (t1 >= 0 && t1 <= 1) {
  9457. roots[n++] = t1;
  9458. }
  9459. if (t2 >= 0 && t2 <= 1) {
  9460. roots[n++] = t2;
  9461. }
  9462. if (t3 >= 0 && t3 <= 1) {
  9463. roots[n++] = t3;
  9464. }
  9465. }
  9466. }
  9467. return n;
  9468. }
  9469. /**
  9470. * 计算三次贝塞尔方程极限值的位置
  9471. * @memberOf module:zrender/core/curve
  9472. * @param {number} p0
  9473. * @param {number} p1
  9474. * @param {number} p2
  9475. * @param {number} p3
  9476. * @param {Array.<number>} extrema
  9477. * @return {number} 有效数目
  9478. */
  9479. function cubicExtrema(p0, p1, p2, p3, extrema) {
  9480. var b = 6 * p2 - 12 * p1 + 6 * p0;
  9481. var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
  9482. var c = 3 * p1 - 3 * p0;
  9483. var n = 0;
  9484. if (isAroundZero(a)) {
  9485. if (isNotAroundZero$1(b)) {
  9486. var t1 = -c / b;
  9487. if (t1 >= 0 && t1 <=1) {
  9488. extrema[n++] = t1;
  9489. }
  9490. }
  9491. }
  9492. else {
  9493. var disc = b * b - 4 * a * c;
  9494. if (isAroundZero(disc)) {
  9495. extrema[0] = -b / (2 * a);
  9496. }
  9497. else if (disc > 0) {
  9498. var discSqrt = mathSqrt$2(disc);
  9499. var t1 = (-b + discSqrt) / (2 * a);
  9500. var t2 = (-b - discSqrt) / (2 * a);
  9501. if (t1 >= 0 && t1 <= 1) {
  9502. extrema[n++] = t1;
  9503. }
  9504. if (t2 >= 0 && t2 <= 1) {
  9505. extrema[n++] = t2;
  9506. }
  9507. }
  9508. }
  9509. return n;
  9510. }
  9511. /**
  9512. * 细分三次贝塞尔曲线
  9513. * @memberOf module:zrender/core/curve
  9514. * @param {number} p0
  9515. * @param {number} p1
  9516. * @param {number} p2
  9517. * @param {number} p3
  9518. * @param {number} t
  9519. * @param {Array.<number>} out
  9520. */
  9521. function cubicSubdivide(p0, p1, p2, p3, t, out) {
  9522. var p01 = (p1 - p0) * t + p0;
  9523. var p12 = (p2 - p1) * t + p1;
  9524. var p23 = (p3 - p2) * t + p2;
  9525. var p012 = (p12 - p01) * t + p01;
  9526. var p123 = (p23 - p12) * t + p12;
  9527. var p0123 = (p123 - p012) * t + p012;
  9528. // Seg0
  9529. out[0] = p0;
  9530. out[1] = p01;
  9531. out[2] = p012;
  9532. out[3] = p0123;
  9533. // Seg1
  9534. out[4] = p0123;
  9535. out[5] = p123;
  9536. out[6] = p23;
  9537. out[7] = p3;
  9538. }
  9539. /**
  9540. * 投射点到三次贝塞尔曲线上,返回投射距离。
  9541. * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
  9542. * @param {number} x0
  9543. * @param {number} y0
  9544. * @param {number} x1
  9545. * @param {number} y1
  9546. * @param {number} x2
  9547. * @param {number} y2
  9548. * @param {number} x3
  9549. * @param {number} y3
  9550. * @param {number} x
  9551. * @param {number} y
  9552. * @param {Array.<number>} [out] 投射点
  9553. * @return {number}
  9554. */
  9555. function cubicProjectPoint(
  9556. x0, y0, x1, y1, x2, y2, x3, y3,
  9557. x, y, out
  9558. ) {
  9559. // http://pomax.github.io/bezierinfo/#projections
  9560. var t;
  9561. var interval = 0.005;
  9562. var d = Infinity;
  9563. var prev;
  9564. var next;
  9565. var d1;
  9566. var d2;
  9567. _v0[0] = x;
  9568. _v0[1] = y;
  9569. // 先粗略估计一下可能的最小距离的 t 值
  9570. // PENDING
  9571. for (var _t = 0; _t < 1; _t += 0.05) {
  9572. _v1[0] = cubicAt(x0, x1, x2, x3, _t);
  9573. _v1[1] = cubicAt(y0, y1, y2, y3, _t);
  9574. d1 = distSquare(_v0, _v1);
  9575. if (d1 < d) {
  9576. t = _t;
  9577. d = d1;
  9578. }
  9579. }
  9580. d = Infinity;
  9581. // At most 32 iteration
  9582. for (var i = 0; i < 32; i++) {
  9583. if (interval < EPSILON_NUMERIC) {
  9584. break;
  9585. }
  9586. prev = t - interval;
  9587. next = t + interval;
  9588. // t - interval
  9589. _v1[0] = cubicAt(x0, x1, x2, x3, prev);
  9590. _v1[1] = cubicAt(y0, y1, y2, y3, prev);
  9591. d1 = distSquare(_v1, _v0);
  9592. if (prev >= 0 && d1 < d) {
  9593. t = prev;
  9594. d = d1;
  9595. }
  9596. else {
  9597. // t + interval
  9598. _v2[0] = cubicAt(x0, x1, x2, x3, next);
  9599. _v2[1] = cubicAt(y0, y1, y2, y3, next);
  9600. d2 = distSquare(_v2, _v0);
  9601. if (next <= 1 && d2 < d) {
  9602. t = next;
  9603. d = d2;
  9604. }
  9605. else {
  9606. interval *= 0.5;
  9607. }
  9608. }
  9609. }
  9610. // t
  9611. if (out) {
  9612. out[0] = cubicAt(x0, x1, x2, x3, t);
  9613. out[1] = cubicAt(y0, y1, y2, y3, t);
  9614. }
  9615. // console.log(interval, i);
  9616. return mathSqrt$2(d);
  9617. }
  9618. /**
  9619. * 计算二次方贝塞尔值
  9620. * @param {number} p0
  9621. * @param {number} p1
  9622. * @param {number} p2
  9623. * @param {number} t
  9624. * @return {number}
  9625. */
  9626. function quadraticAt(p0, p1, p2, t) {
  9627. var onet = 1 - t;
  9628. return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
  9629. }
  9630. /**
  9631. * 计算二次方贝塞尔导数值
  9632. * @param {number} p0
  9633. * @param {number} p1
  9634. * @param {number} p2
  9635. * @param {number} t
  9636. * @return {number}
  9637. */
  9638. function quadraticDerivativeAt(p0, p1, p2, t) {
  9639. return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
  9640. }
  9641. /**
  9642. * 计算二次方贝塞尔方程根
  9643. * @param {number} p0
  9644. * @param {number} p1
  9645. * @param {number} p2
  9646. * @param {number} t
  9647. * @param {Array.<number>} roots
  9648. * @return {number} 有效根数目
  9649. */
  9650. function quadraticRootAt(p0, p1, p2, val, roots) {
  9651. var a = p0 - 2 * p1 + p2;
  9652. var b = 2 * (p1 - p0);
  9653. var c = p0 - val;
  9654. var n = 0;
  9655. if (isAroundZero(a)) {
  9656. if (isNotAroundZero$1(b)) {
  9657. var t1 = -c / b;
  9658. if (t1 >= 0 && t1 <= 1) {
  9659. roots[n++] = t1;
  9660. }
  9661. }
  9662. }
  9663. else {
  9664. var disc = b * b - 4 * a * c;
  9665. if (isAroundZero(disc)) {
  9666. var t1 = -b / (2 * a);
  9667. if (t1 >= 0 && t1 <= 1) {
  9668. roots[n++] = t1;
  9669. }
  9670. }
  9671. else if (disc > 0) {
  9672. var discSqrt = mathSqrt$2(disc);
  9673. var t1 = (-b + discSqrt) / (2 * a);
  9674. var t2 = (-b - discSqrt) / (2 * a);
  9675. if (t1 >= 0 && t1 <= 1) {
  9676. roots[n++] = t1;
  9677. }
  9678. if (t2 >= 0 && t2 <= 1) {
  9679. roots[n++] = t2;
  9680. }
  9681. }
  9682. }
  9683. return n;
  9684. }
  9685. /**
  9686. * 计算二次贝塞尔方程极限值
  9687. * @memberOf module:zrender/core/curve
  9688. * @param {number} p0
  9689. * @param {number} p1
  9690. * @param {number} p2
  9691. * @return {number}
  9692. */
  9693. function quadraticExtremum(p0, p1, p2) {
  9694. var divider = p0 + p2 - 2 * p1;
  9695. if (divider === 0) {
  9696. // p1 is center of p0 and p2
  9697. return 0.5;
  9698. }
  9699. else {
  9700. return (p0 - p1) / divider;
  9701. }
  9702. }
  9703. /**
  9704. * 细分二次贝塞尔曲线
  9705. * @memberOf module:zrender/core/curve
  9706. * @param {number} p0
  9707. * @param {number} p1
  9708. * @param {number} p2
  9709. * @param {number} t
  9710. * @param {Array.<number>} out
  9711. */
  9712. function quadraticSubdivide(p0, p1, p2, t, out) {
  9713. var p01 = (p1 - p0) * t + p0;
  9714. var p12 = (p2 - p1) * t + p1;
  9715. var p012 = (p12 - p01) * t + p01;
  9716. // Seg0
  9717. out[0] = p0;
  9718. out[1] = p01;
  9719. out[2] = p012;
  9720. // Seg1
  9721. out[3] = p012;
  9722. out[4] = p12;
  9723. out[5] = p2;
  9724. }
  9725. /**
  9726. * 投射点到二次贝塞尔曲线上,返回投射距离。
  9727. * 投射点有可能会有一个或者多个,这里只返回其中距离最短的一个。
  9728. * @param {number} x0
  9729. * @param {number} y0
  9730. * @param {number} x1
  9731. * @param {number} y1
  9732. * @param {number} x2
  9733. * @param {number} y2
  9734. * @param {number} x
  9735. * @param {number} y
  9736. * @param {Array.<number>} out 投射点
  9737. * @return {number}
  9738. */
  9739. function quadraticProjectPoint(
  9740. x0, y0, x1, y1, x2, y2,
  9741. x, y, out
  9742. ) {
  9743. // http://pomax.github.io/bezierinfo/#projections
  9744. var t;
  9745. var interval = 0.005;
  9746. var d = Infinity;
  9747. _v0[0] = x;
  9748. _v0[1] = y;
  9749. // 先粗略估计一下可能的最小距离的 t 值
  9750. // PENDING
  9751. for (var _t = 0; _t < 1; _t += 0.05) {
  9752. _v1[0] = quadraticAt(x0, x1, x2, _t);
  9753. _v1[1] = quadraticAt(y0, y1, y2, _t);
  9754. var d1 = distSquare(_v0, _v1);
  9755. if (d1 < d) {
  9756. t = _t;
  9757. d = d1;
  9758. }
  9759. }
  9760. d = Infinity;
  9761. // At most 32 iteration
  9762. for (var i = 0; i < 32; i++) {
  9763. if (interval < EPSILON_NUMERIC) {
  9764. break;
  9765. }
  9766. var prev = t - interval;
  9767. var next = t + interval;
  9768. // t - interval
  9769. _v1[0] = quadraticAt(x0, x1, x2, prev);
  9770. _v1[1] = quadraticAt(y0, y1, y2, prev);
  9771. var d1 = distSquare(_v1, _v0);
  9772. if (prev >= 0 && d1 < d) {
  9773. t = prev;
  9774. d = d1;
  9775. }
  9776. else {
  9777. // t + interval
  9778. _v2[0] = quadraticAt(x0, x1, x2, next);
  9779. _v2[1] = quadraticAt(y0, y1, y2, next);
  9780. var d2 = distSquare(_v2, _v0);
  9781. if (next <= 1 && d2 < d) {
  9782. t = next;
  9783. d = d2;
  9784. }
  9785. else {
  9786. interval *= 0.5;
  9787. }
  9788. }
  9789. }
  9790. // t
  9791. if (out) {
  9792. out[0] = quadraticAt(x0, x1, x2, t);
  9793. out[1] = quadraticAt(y0, y1, y2, t);
  9794. }
  9795. // console.log(interval, i);
  9796. return mathSqrt$2(d);
  9797. }
  9798. /**
  9799. * @author Yi Shen(https://github.com/pissang)
  9800. */
  9801. var mathMin$2 = Math.min;
  9802. var mathMax$2 = Math.max;
  9803. var mathSin$2 = Math.sin;
  9804. var mathCos$2 = Math.cos;
  9805. var PI2 = Math.PI * 2;
  9806. var start = create();
  9807. var end = create();
  9808. var extremity = create();
  9809. /**
  9810. * 从顶点数组中计算出最小包围盒,写入`min`和`max`中
  9811. * @module zrender/core/bbox
  9812. * @param {Array<Object>} points 顶点数组
  9813. * @param {number} min
  9814. * @param {number} max
  9815. */
  9816. /**
  9817. * @memberOf module:zrender/core/bbox
  9818. * @param {number} x0
  9819. * @param {number} y0
  9820. * @param {number} x1
  9821. * @param {number} y1
  9822. * @param {Array.<number>} min
  9823. * @param {Array.<number>} max
  9824. */
  9825. function fromLine(x0, y0, x1, y1, min$$1, max$$1) {
  9826. min$$1[0] = mathMin$2(x0, x1);
  9827. min$$1[1] = mathMin$2(y0, y1);
  9828. max$$1[0] = mathMax$2(x0, x1);
  9829. max$$1[1] = mathMax$2(y0, y1);
  9830. }
  9831. var xDim = [];
  9832. var yDim = [];
  9833. /**
  9834. * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中
  9835. * @memberOf module:zrender/core/bbox
  9836. * @param {number} x0
  9837. * @param {number} y0
  9838. * @param {number} x1
  9839. * @param {number} y1
  9840. * @param {number} x2
  9841. * @param {number} y2
  9842. * @param {number} x3
  9843. * @param {number} y3
  9844. * @param {Array.<number>} min
  9845. * @param {Array.<number>} max
  9846. */
  9847. function fromCubic(
  9848. x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1
  9849. ) {
  9850. var cubicExtrema$$1 = cubicExtrema;
  9851. var cubicAt$$1 = cubicAt;
  9852. var i;
  9853. var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);
  9854. min$$1[0] = Infinity;
  9855. min$$1[1] = Infinity;
  9856. max$$1[0] = -Infinity;
  9857. max$$1[1] = -Infinity;
  9858. for (i = 0; i < n; i++) {
  9859. var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);
  9860. min$$1[0] = mathMin$2(x, min$$1[0]);
  9861. max$$1[0] = mathMax$2(x, max$$1[0]);
  9862. }
  9863. n = cubicExtrema$$1(y0, y1, y2, y3, yDim);
  9864. for (i = 0; i < n; i++) {
  9865. var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);
  9866. min$$1[1] = mathMin$2(y, min$$1[1]);
  9867. max$$1[1] = mathMax$2(y, max$$1[1]);
  9868. }
  9869. min$$1[0] = mathMin$2(x0, min$$1[0]);
  9870. max$$1[0] = mathMax$2(x0, max$$1[0]);
  9871. min$$1[0] = mathMin$2(x3, min$$1[0]);
  9872. max$$1[0] = mathMax$2(x3, max$$1[0]);
  9873. min$$1[1] = mathMin$2(y0, min$$1[1]);
  9874. max$$1[1] = mathMax$2(y0, max$$1[1]);
  9875. min$$1[1] = mathMin$2(y3, min$$1[1]);
  9876. max$$1[1] = mathMax$2(y3, max$$1[1]);
  9877. }
  9878. /**
  9879. * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中
  9880. * @memberOf module:zrender/core/bbox
  9881. * @param {number} x0
  9882. * @param {number} y0
  9883. * @param {number} x1
  9884. * @param {number} y1
  9885. * @param {number} x2
  9886. * @param {number} y2
  9887. * @param {Array.<number>} min
  9888. * @param {Array.<number>} max
  9889. */
  9890. function fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {
  9891. var quadraticExtremum$$1 = quadraticExtremum;
  9892. var quadraticAt$$1 = quadraticAt;
  9893. // Find extremities, where derivative in x dim or y dim is zero
  9894. var tx =
  9895. mathMax$2(
  9896. mathMin$2(quadraticExtremum$$1(x0, x1, x2), 1), 0
  9897. );
  9898. var ty =
  9899. mathMax$2(
  9900. mathMin$2(quadraticExtremum$$1(y0, y1, y2), 1), 0
  9901. );
  9902. var x = quadraticAt$$1(x0, x1, x2, tx);
  9903. var y = quadraticAt$$1(y0, y1, y2, ty);
  9904. min$$1[0] = mathMin$2(x0, x2, x);
  9905. min$$1[1] = mathMin$2(y0, y2, y);
  9906. max$$1[0] = mathMax$2(x0, x2, x);
  9907. max$$1[1] = mathMax$2(y0, y2, y);
  9908. }
  9909. /**
  9910. * 从圆弧中计算出最小包围盒,写入`min`和`max`中
  9911. * @method
  9912. * @memberOf module:zrender/core/bbox
  9913. * @param {number} x
  9914. * @param {number} y
  9915. * @param {number} rx
  9916. * @param {number} ry
  9917. * @param {number} startAngle
  9918. * @param {number} endAngle
  9919. * @param {number} anticlockwise
  9920. * @param {Array.<number>} min
  9921. * @param {Array.<number>} max
  9922. */
  9923. function fromArc(
  9924. x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1
  9925. ) {
  9926. var vec2Min = min;
  9927. var vec2Max = max;
  9928. var diff = Math.abs(startAngle - endAngle);
  9929. if (diff % PI2 < 1e-4 && diff > 1e-4) {
  9930. // Is a circle
  9931. min$$1[0] = x - rx;
  9932. min$$1[1] = y - ry;
  9933. max$$1[0] = x + rx;
  9934. max$$1[1] = y + ry;
  9935. return;
  9936. }
  9937. start[0] = mathCos$2(startAngle) * rx + x;
  9938. start[1] = mathSin$2(startAngle) * ry + y;
  9939. end[0] = mathCos$2(endAngle) * rx + x;
  9940. end[1] = mathSin$2(endAngle) * ry + y;
  9941. vec2Min(min$$1, start, end);
  9942. vec2Max(max$$1, start, end);
  9943. // Thresh to [0, Math.PI * 2]
  9944. startAngle = startAngle % (PI2);
  9945. if (startAngle < 0) {
  9946. startAngle = startAngle + PI2;
  9947. }
  9948. endAngle = endAngle % (PI2);
  9949. if (endAngle < 0) {
  9950. endAngle = endAngle + PI2;
  9951. }
  9952. if (startAngle > endAngle && !anticlockwise) {
  9953. endAngle += PI2;
  9954. }
  9955. else if (startAngle < endAngle && anticlockwise) {
  9956. startAngle += PI2;
  9957. }
  9958. if (anticlockwise) {
  9959. var tmp = endAngle;
  9960. endAngle = startAngle;
  9961. startAngle = tmp;
  9962. }
  9963. // var number = 0;
  9964. // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;
  9965. for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
  9966. if (angle > startAngle) {
  9967. extremity[0] = mathCos$2(angle) * rx + x;
  9968. extremity[1] = mathSin$2(angle) * ry + y;
  9969. vec2Min(min$$1, extremity, min$$1);
  9970. vec2Max(max$$1, extremity, max$$1);
  9971. }
  9972. }
  9973. }
  9974. /**
  9975. * Path 代理,可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中
  9976. * 可以用于 isInsidePath 判断以及获取boundingRect
  9977. *
  9978. * @module zrender/core/PathProxy
  9979. * @author Yi Shen (http://www.github.com/pissang)
  9980. */
  9981. // TODO getTotalLength, getPointAtLength
  9982. var CMD = {
  9983. M: 1,
  9984. L: 2,
  9985. C: 3,
  9986. Q: 4,
  9987. A: 5,
  9988. Z: 6,
  9989. // Rect
  9990. R: 7
  9991. };
  9992. // var CMD_MEM_SIZE = {
  9993. // M: 3,
  9994. // L: 3,
  9995. // C: 7,
  9996. // Q: 5,
  9997. // A: 9,
  9998. // R: 5,
  9999. // Z: 1
  10000. // };
  10001. var min$1 = [];
  10002. var max$1 = [];
  10003. var min2 = [];
  10004. var max2 = [];
  10005. var mathMin$1 = Math.min;
  10006. var mathMax$1 = Math.max;
  10007. var mathCos$1 = Math.cos;
  10008. var mathSin$1 = Math.sin;
  10009. var mathSqrt$1 = Math.sqrt;
  10010. var mathAbs = Math.abs;
  10011. var hasTypedArray = typeof Float32Array != 'undefined';
  10012. /**
  10013. * @alias module:zrender/core/PathProxy
  10014. * @constructor
  10015. */
  10016. var PathProxy = function (notSaveData) {
  10017. this._saveData = !(notSaveData || false);
  10018. if (this._saveData) {
  10019. /**
  10020. * Path data. Stored as flat array
  10021. * @type {Array.<Object>}
  10022. */
  10023. this.data = [];
  10024. }
  10025. this._ctx = null;
  10026. };
  10027. /**
  10028. * 快速计算Path包围盒(并不是最小包围盒)
  10029. * @return {Object}
  10030. */
  10031. PathProxy.prototype = {
  10032. constructor: PathProxy,
  10033. _xi: 0,
  10034. _yi: 0,
  10035. _x0: 0,
  10036. _y0: 0,
  10037. // Unit x, Unit y. Provide for avoiding drawing that too short line segment
  10038. _ux: 0,
  10039. _uy: 0,
  10040. _len: 0,
  10041. _lineDash: null,
  10042. _dashOffset: 0,
  10043. _dashIdx: 0,
  10044. _dashSum: 0,
  10045. /**
  10046. * @readOnly
  10047. */
  10048. setScale: function (sx, sy) {
  10049. this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;
  10050. this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;
  10051. },
  10052. getContext: function () {
  10053. return this._ctx;
  10054. },
  10055. /**
  10056. * @param {CanvasRenderingContext2D} ctx
  10057. * @return {module:zrender/core/PathProxy}
  10058. */
  10059. beginPath: function (ctx) {
  10060. this._ctx = ctx;
  10061. ctx && ctx.beginPath();
  10062. ctx && (this.dpr = ctx.dpr);
  10063. // Reset
  10064. if (this._saveData) {
  10065. this._len = 0;
  10066. }
  10067. if (this._lineDash) {
  10068. this._lineDash = null;
  10069. this._dashOffset = 0;
  10070. }
  10071. return this;
  10072. },
  10073. /**
  10074. * @param {number} x
  10075. * @param {number} y
  10076. * @return {module:zrender/core/PathProxy}
  10077. */
  10078. moveTo: function (x, y) {
  10079. this.addData(CMD.M, x, y);
  10080. this._ctx && this._ctx.moveTo(x, y);
  10081. // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用
  10082. // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。
  10083. // 有可能在 beginPath 之后直接调用 lineTo,这时候 x0, y0 需要
  10084. // 在 lineTo 方法中记录,这里先不考虑这种情况,dashed line 也只在 IE10- 中不支持
  10085. this._x0 = x;
  10086. this._y0 = y;
  10087. this._xi = x;
  10088. this._yi = y;
  10089. return this;
  10090. },
  10091. /**
  10092. * @param {number} x
  10093. * @param {number} y
  10094. * @return {module:zrender/core/PathProxy}
  10095. */
  10096. lineTo: function (x, y) {
  10097. var exceedUnit = mathAbs(x - this._xi) > this._ux
  10098. || mathAbs(y - this._yi) > this._uy
  10099. // Force draw the first segment
  10100. || this._len < 5;
  10101. this.addData(CMD.L, x, y);
  10102. if (this._ctx && exceedUnit) {
  10103. this._needsDash() ? this._dashedLineTo(x, y)
  10104. : this._ctx.lineTo(x, y);
  10105. }
  10106. if (exceedUnit) {
  10107. this._xi = x;
  10108. this._yi = y;
  10109. }
  10110. return this;
  10111. },
  10112. /**
  10113. * @param {number} x1
  10114. * @param {number} y1
  10115. * @param {number} x2
  10116. * @param {number} y2
  10117. * @param {number} x3
  10118. * @param {number} y3
  10119. * @return {module:zrender/core/PathProxy}
  10120. */
  10121. bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {
  10122. this.addData(CMD.C, x1, y1, x2, y2, x3, y3);
  10123. if (this._ctx) {
  10124. this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
  10125. : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
  10126. }
  10127. this._xi = x3;
  10128. this._yi = y3;
  10129. return this;
  10130. },
  10131. /**
  10132. * @param {number} x1
  10133. * @param {number} y1
  10134. * @param {number} x2
  10135. * @param {number} y2
  10136. * @return {module:zrender/core/PathProxy}
  10137. */
  10138. quadraticCurveTo: function (x1, y1, x2, y2) {
  10139. this.addData(CMD.Q, x1, y1, x2, y2);
  10140. if (this._ctx) {
  10141. this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)
  10142. : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
  10143. }
  10144. this._xi = x2;
  10145. this._yi = y2;
  10146. return this;
  10147. },
  10148. /**
  10149. * @param {number} cx
  10150. * @param {number} cy
  10151. * @param {number} r
  10152. * @param {number} startAngle
  10153. * @param {number} endAngle
  10154. * @param {boolean} anticlockwise
  10155. * @return {module:zrender/core/PathProxy}
  10156. */
  10157. arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {
  10158. this.addData(
  10159. CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1
  10160. );
  10161. this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
  10162. this._xi = mathCos$1(endAngle) * r + cx;
  10163. this._yi = mathSin$1(endAngle) * r + cx;
  10164. return this;
  10165. },
  10166. // TODO
  10167. arcTo: function (x1, y1, x2, y2, radius) {
  10168. if (this._ctx) {
  10169. this._ctx.arcTo(x1, y1, x2, y2, radius);
  10170. }
  10171. return this;
  10172. },
  10173. // TODO
  10174. rect: function (x, y, w, h) {
  10175. this._ctx && this._ctx.rect(x, y, w, h);
  10176. this.addData(CMD.R, x, y, w, h);
  10177. return this;
  10178. },
  10179. /**
  10180. * @return {module:zrender/core/PathProxy}
  10181. */
  10182. closePath: function () {
  10183. this.addData(CMD.Z);
  10184. var ctx = this._ctx;
  10185. var x0 = this._x0;
  10186. var y0 = this._y0;
  10187. if (ctx) {
  10188. this._needsDash() && this._dashedLineTo(x0, y0);
  10189. ctx.closePath();
  10190. }
  10191. this._xi = x0;
  10192. this._yi = y0;
  10193. return this;
  10194. },
  10195. /**
  10196. * Context 从外部传入,因为有可能是 rebuildPath 完之后再 fill。
  10197. * stroke 同样
  10198. * @param {CanvasRenderingContext2D} ctx
  10199. * @return {module:zrender/core/PathProxy}
  10200. */
  10201. fill: function (ctx) {
  10202. ctx && ctx.fill();
  10203. this.toStatic();
  10204. },
  10205. /**
  10206. * @param {CanvasRenderingContext2D} ctx
  10207. * @return {module:zrender/core/PathProxy}
  10208. */
  10209. stroke: function (ctx) {
  10210. ctx && ctx.stroke();
  10211. this.toStatic();
  10212. },
  10213. /**
  10214. * 必须在其它绘制命令前调用
  10215. * Must be invoked before all other path drawing methods
  10216. * @return {module:zrender/core/PathProxy}
  10217. */
  10218. setLineDash: function (lineDash) {
  10219. if (lineDash instanceof Array) {
  10220. this._lineDash = lineDash;
  10221. this._dashIdx = 0;
  10222. var lineDashSum = 0;
  10223. for (var i = 0; i < lineDash.length; i++) {
  10224. lineDashSum += lineDash[i];
  10225. }
  10226. this._dashSum = lineDashSum;
  10227. }
  10228. return this;
  10229. },
  10230. /**
  10231. * 必须在其它绘制命令前调用
  10232. * Must be invoked before all other path drawing methods
  10233. * @return {module:zrender/core/PathProxy}
  10234. */
  10235. setLineDashOffset: function (offset) {
  10236. this._dashOffset = offset;
  10237. return this;
  10238. },
  10239. /**
  10240. *
  10241. * @return {boolean}
  10242. */
  10243. len: function () {
  10244. return this._len;
  10245. },
  10246. /**
  10247. * 直接设置 Path 数据
  10248. */
  10249. setData: function (data) {
  10250. var len$$1 = data.length;
  10251. if (! (this.data && this.data.length == len$$1) && hasTypedArray) {
  10252. this.data = new Float32Array(len$$1);
  10253. }
  10254. for (var i = 0; i < len$$1; i++) {
  10255. this.data[i] = data[i];
  10256. }
  10257. this._len = len$$1;
  10258. },
  10259. /**
  10260. * 添加子路径
  10261. * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path
  10262. */
  10263. appendPath: function (path) {
  10264. if (!(path instanceof Array)) {
  10265. path = [path];
  10266. }
  10267. var len$$1 = path.length;
  10268. var appendSize = 0;
  10269. var offset = this._len;
  10270. for (var i = 0; i < len$$1; i++) {
  10271. appendSize += path[i].len();
  10272. }
  10273. if (hasTypedArray && (this.data instanceof Float32Array)) {
  10274. this.data = new Float32Array(offset + appendSize);
  10275. }
  10276. for (var i = 0; i < len$$1; i++) {
  10277. var appendPathData = path[i].data;
  10278. for (var k = 0; k < appendPathData.length; k++) {
  10279. this.data[offset++] = appendPathData[k];
  10280. }
  10281. }
  10282. this._len = offset;
  10283. },
  10284. /**
  10285. * 填充 Path 数据。
  10286. * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。
  10287. */
  10288. addData: function (cmd) {
  10289. if (!this._saveData) {
  10290. return;
  10291. }
  10292. var data = this.data;
  10293. if (this._len + arguments.length > data.length) {
  10294. // 因为之前的数组已经转换成静态的 Float32Array
  10295. // 所以不够用时需要扩展一个新的动态数组
  10296. this._expandData();
  10297. data = this.data;
  10298. }
  10299. for (var i = 0; i < arguments.length; i++) {
  10300. data[this._len++] = arguments[i];
  10301. }
  10302. this._prevCmd = cmd;
  10303. },
  10304. _expandData: function () {
  10305. // Only if data is Float32Array
  10306. if (!(this.data instanceof Array)) {
  10307. var newData = [];
  10308. for (var i = 0; i < this._len; i++) {
  10309. newData[i] = this.data[i];
  10310. }
  10311. this.data = newData;
  10312. }
  10313. },
  10314. /**
  10315. * If needs js implemented dashed line
  10316. * @return {boolean}
  10317. * @private
  10318. */
  10319. _needsDash: function () {
  10320. return this._lineDash;
  10321. },
  10322. _dashedLineTo: function (x1, y1) {
  10323. var dashSum = this._dashSum;
  10324. var offset = this._dashOffset;
  10325. var lineDash = this._lineDash;
  10326. var ctx = this._ctx;
  10327. var x0 = this._xi;
  10328. var y0 = this._yi;
  10329. var dx = x1 - x0;
  10330. var dy = y1 - y0;
  10331. var dist$$1 = mathSqrt$1(dx * dx + dy * dy);
  10332. var x = x0;
  10333. var y = y0;
  10334. var dash;
  10335. var nDash = lineDash.length;
  10336. var idx;
  10337. dx /= dist$$1;
  10338. dy /= dist$$1;
  10339. if (offset < 0) {
  10340. // Convert to positive offset
  10341. offset = dashSum + offset;
  10342. }
  10343. offset %= dashSum;
  10344. x -= offset * dx;
  10345. y -= offset * dy;
  10346. while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)
  10347. || (dx == 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {
  10348. idx = this._dashIdx;
  10349. dash = lineDash[idx];
  10350. x += dx * dash;
  10351. y += dy * dash;
  10352. this._dashIdx = (idx + 1) % nDash;
  10353. // Skip positive offset
  10354. if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {
  10355. continue;
  10356. }
  10357. ctx[idx % 2 ? 'moveTo' : 'lineTo'](
  10358. dx >= 0 ? mathMin$1(x, x1) : mathMax$1(x, x1),
  10359. dy >= 0 ? mathMin$1(y, y1) : mathMax$1(y, y1)
  10360. );
  10361. }
  10362. // Offset for next lineTo
  10363. dx = x - x1;
  10364. dy = y - y1;
  10365. this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);
  10366. },
  10367. // Not accurate dashed line to
  10368. _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {
  10369. var dashSum = this._dashSum;
  10370. var offset = this._dashOffset;
  10371. var lineDash = this._lineDash;
  10372. var ctx = this._ctx;
  10373. var x0 = this._xi;
  10374. var y0 = this._yi;
  10375. var t;
  10376. var dx;
  10377. var dy;
  10378. var cubicAt$$1 = cubicAt;
  10379. var bezierLen = 0;
  10380. var idx = this._dashIdx;
  10381. var nDash = lineDash.length;
  10382. var x;
  10383. var y;
  10384. var tmpLen = 0;
  10385. if (offset < 0) {
  10386. // Convert to positive offset
  10387. offset = dashSum + offset;
  10388. }
  10389. offset %= dashSum;
  10390. // Bezier approx length
  10391. for (t = 0; t < 1; t += 0.1) {
  10392. dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)
  10393. - cubicAt$$1(x0, x1, x2, x3, t);
  10394. dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)
  10395. - cubicAt$$1(y0, y1, y2, y3, t);
  10396. bezierLen += mathSqrt$1(dx * dx + dy * dy);
  10397. }
  10398. // Find idx after add offset
  10399. for (; idx < nDash; idx++) {
  10400. tmpLen += lineDash[idx];
  10401. if (tmpLen > offset) {
  10402. break;
  10403. }
  10404. }
  10405. t = (tmpLen - offset) / bezierLen;
  10406. while (t <= 1) {
  10407. x = cubicAt$$1(x0, x1, x2, x3, t);
  10408. y = cubicAt$$1(y0, y1, y2, y3, t);
  10409. // Use line to approximate dashed bezier
  10410. // Bad result if dash is long
  10411. idx % 2 ? ctx.moveTo(x, y)
  10412. : ctx.lineTo(x, y);
  10413. t += lineDash[idx] / bezierLen;
  10414. idx = (idx + 1) % nDash;
  10415. }
  10416. // Finish the last segment and calculate the new offset
  10417. (idx % 2 !== 0) && ctx.lineTo(x3, y3);
  10418. dx = x3 - x;
  10419. dy = y3 - y;
  10420. this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);
  10421. },
  10422. _dashedQuadraticTo: function (x1, y1, x2, y2) {
  10423. // Convert quadratic to cubic using degree elevation
  10424. var x3 = x2;
  10425. var y3 = y2;
  10426. x2 = (x2 + 2 * x1) / 3;
  10427. y2 = (y2 + 2 * y1) / 3;
  10428. x1 = (this._xi + 2 * x1) / 3;
  10429. y1 = (this._yi + 2 * y1) / 3;
  10430. this._dashedBezierTo(x1, y1, x2, y2, x3, y3);
  10431. },
  10432. /**
  10433. * 转成静态的 Float32Array 减少堆内存占用
  10434. * Convert dynamic array to static Float32Array
  10435. */
  10436. toStatic: function () {
  10437. var data = this.data;
  10438. if (data instanceof Array) {
  10439. data.length = this._len;
  10440. if (hasTypedArray) {
  10441. this.data = new Float32Array(data);
  10442. }
  10443. }
  10444. },
  10445. /**
  10446. * @return {module:zrender/core/BoundingRect}
  10447. */
  10448. getBoundingRect: function () {
  10449. min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;
  10450. max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
  10451. var data = this.data;
  10452. var xi = 0;
  10453. var yi = 0;
  10454. var x0 = 0;
  10455. var y0 = 0;
  10456. for (var i = 0; i < data.length;) {
  10457. var cmd = data[i++];
  10458. if (i == 1) {
  10459. // 如果第一个命令是 L, C, Q
  10460. // 则 previous point 同绘制命令的第一个 point
  10461. //
  10462. // 第一个命令为 Arc 的情况下会在后面特殊处理
  10463. xi = data[i];
  10464. yi = data[i + 1];
  10465. x0 = xi;
  10466. y0 = yi;
  10467. }
  10468. switch (cmd) {
  10469. case CMD.M:
  10470. // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
  10471. // 在 closePath 的时候使用
  10472. x0 = data[i++];
  10473. y0 = data[i++];
  10474. xi = x0;
  10475. yi = y0;
  10476. min2[0] = x0;
  10477. min2[1] = y0;
  10478. max2[0] = x0;
  10479. max2[1] = y0;
  10480. break;
  10481. case CMD.L:
  10482. fromLine(xi, yi, data[i], data[i + 1], min2, max2);
  10483. xi = data[i++];
  10484. yi = data[i++];
  10485. break;
  10486. case CMD.C:
  10487. fromCubic(
  10488. xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
  10489. min2, max2
  10490. );
  10491. xi = data[i++];
  10492. yi = data[i++];
  10493. break;
  10494. case CMD.Q:
  10495. fromQuadratic(
  10496. xi, yi, data[i++], data[i++], data[i], data[i + 1],
  10497. min2, max2
  10498. );
  10499. xi = data[i++];
  10500. yi = data[i++];
  10501. break;
  10502. case CMD.A:
  10503. // TODO Arc 判断的开销比较大
  10504. var cx = data[i++];
  10505. var cy = data[i++];
  10506. var rx = data[i++];
  10507. var ry = data[i++];
  10508. var startAngle = data[i++];
  10509. var endAngle = data[i++] + startAngle;
  10510. // TODO Arc 旋转
  10511. var psi = data[i++];
  10512. var anticlockwise = 1 - data[i++];
  10513. if (i == 1) {
  10514. // 直接使用 arc 命令
  10515. // 第一个命令起点还未定义
  10516. x0 = mathCos$1(startAngle) * rx + cx;
  10517. y0 = mathSin$1(startAngle) * ry + cy;
  10518. }
  10519. fromArc(
  10520. cx, cy, rx, ry, startAngle, endAngle,
  10521. anticlockwise, min2, max2
  10522. );
  10523. xi = mathCos$1(endAngle) * rx + cx;
  10524. yi = mathSin$1(endAngle) * ry + cy;
  10525. break;
  10526. case CMD.R:
  10527. x0 = xi = data[i++];
  10528. y0 = yi = data[i++];
  10529. var width = data[i++];
  10530. var height = data[i++];
  10531. // Use fromLine
  10532. fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
  10533. break;
  10534. case CMD.Z:
  10535. xi = x0;
  10536. yi = y0;
  10537. break;
  10538. }
  10539. // Union
  10540. min(min$1, min$1, min2);
  10541. max(max$1, max$1, max2);
  10542. }
  10543. // No data
  10544. if (i === 0) {
  10545. min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;
  10546. }
  10547. return new BoundingRect(
  10548. min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]
  10549. );
  10550. },
  10551. /**
  10552. * Rebuild path from current data
  10553. * Rebuild path will not consider javascript implemented line dash.
  10554. * @param {CanvasRenderingContext2D} ctx
  10555. */
  10556. rebuildPath: function (ctx) {
  10557. var d = this.data;
  10558. var x0, y0;
  10559. var xi, yi;
  10560. var x, y;
  10561. var ux = this._ux;
  10562. var uy = this._uy;
  10563. var len$$1 = this._len;
  10564. for (var i = 0; i < len$$1;) {
  10565. var cmd = d[i++];
  10566. if (i == 1) {
  10567. // 如果第一个命令是 L, C, Q
  10568. // 则 previous point 同绘制命令的第一个 point
  10569. //
  10570. // 第一个命令为 Arc 的情况下会在后面特殊处理
  10571. xi = d[i];
  10572. yi = d[i + 1];
  10573. x0 = xi;
  10574. y0 = yi;
  10575. }
  10576. switch (cmd) {
  10577. case CMD.M:
  10578. x0 = xi = d[i++];
  10579. y0 = yi = d[i++];
  10580. ctx.moveTo(xi, yi);
  10581. break;
  10582. case CMD.L:
  10583. x = d[i++];
  10584. y = d[i++];
  10585. // Not draw too small seg between
  10586. if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {
  10587. ctx.lineTo(x, y);
  10588. xi = x;
  10589. yi = y;
  10590. }
  10591. break;
  10592. case CMD.C:
  10593. ctx.bezierCurveTo(
  10594. d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]
  10595. );
  10596. xi = d[i - 2];
  10597. yi = d[i - 1];
  10598. break;
  10599. case CMD.Q:
  10600. ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);
  10601. xi = d[i - 2];
  10602. yi = d[i - 1];
  10603. break;
  10604. case CMD.A:
  10605. var cx = d[i++];
  10606. var cy = d[i++];
  10607. var rx = d[i++];
  10608. var ry = d[i++];
  10609. var theta = d[i++];
  10610. var dTheta = d[i++];
  10611. var psi = d[i++];
  10612. var fs = d[i++];
  10613. var r = (rx > ry) ? rx : ry;
  10614. var scaleX = (rx > ry) ? 1 : rx / ry;
  10615. var scaleY = (rx > ry) ? ry / rx : 1;
  10616. var isEllipse = Math.abs(rx - ry) > 1e-3;
  10617. var endAngle = theta + dTheta;
  10618. if (isEllipse) {
  10619. ctx.translate(cx, cy);
  10620. ctx.rotate(psi);
  10621. ctx.scale(scaleX, scaleY);
  10622. ctx.arc(0, 0, r, theta, endAngle, 1 - fs);
  10623. ctx.scale(1 / scaleX, 1 / scaleY);
  10624. ctx.rotate(-psi);
  10625. ctx.translate(-cx, -cy);
  10626. }
  10627. else {
  10628. ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);
  10629. }
  10630. if (i == 1) {
  10631. // 直接使用 arc 命令
  10632. // 第一个命令起点还未定义
  10633. x0 = mathCos$1(theta) * rx + cx;
  10634. y0 = mathSin$1(theta) * ry + cy;
  10635. }
  10636. xi = mathCos$1(endAngle) * rx + cx;
  10637. yi = mathSin$1(endAngle) * ry + cy;
  10638. break;
  10639. case CMD.R:
  10640. x0 = xi = d[i];
  10641. y0 = yi = d[i + 1];
  10642. ctx.rect(d[i++], d[i++], d[i++], d[i++]);
  10643. break;
  10644. case CMD.Z:
  10645. ctx.closePath();
  10646. xi = x0;
  10647. yi = y0;
  10648. }
  10649. }
  10650. }
  10651. };
  10652. PathProxy.CMD = CMD;
  10653. /**
  10654. * 线段包含判断
  10655. * @param {number} x0
  10656. * @param {number} y0
  10657. * @param {number} x1
  10658. * @param {number} y1
  10659. * @param {number} lineWidth
  10660. * @param {number} x
  10661. * @param {number} y
  10662. * @return {boolean}
  10663. */
  10664. function containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {
  10665. if (lineWidth === 0) {
  10666. return false;
  10667. }
  10668. var _l = lineWidth;
  10669. var _a = 0;
  10670. var _b = x0;
  10671. // Quick reject
  10672. if (
  10673. (y > y0 + _l && y > y1 + _l)
  10674. || (y < y0 - _l && y < y1 - _l)
  10675. || (x > x0 + _l && x > x1 + _l)
  10676. || (x < x0 - _l && x < x1 - _l)
  10677. ) {
  10678. return false;
  10679. }
  10680. if (x0 !== x1) {
  10681. _a = (y0 - y1) / (x0 - x1);
  10682. _b = (x0 * y1 - x1 * y0) / (x0 - x1) ;
  10683. }
  10684. else {
  10685. return Math.abs(x - x0) <= _l / 2;
  10686. }
  10687. var tmp = _a * x - y + _b;
  10688. var _s = tmp * tmp / (_a * _a + 1);
  10689. return _s <= _l / 2 * _l / 2;
  10690. }
  10691. /**
  10692. * 三次贝塞尔曲线描边包含判断
  10693. * @param {number} x0
  10694. * @param {number} y0
  10695. * @param {number} x1
  10696. * @param {number} y1
  10697. * @param {number} x2
  10698. * @param {number} y2
  10699. * @param {number} x3
  10700. * @param {number} y3
  10701. * @param {number} lineWidth
  10702. * @param {number} x
  10703. * @param {number} y
  10704. * @return {boolean}
  10705. */
  10706. function containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
  10707. if (lineWidth === 0) {
  10708. return false;
  10709. }
  10710. var _l = lineWidth;
  10711. // Quick reject
  10712. if (
  10713. (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)
  10714. || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)
  10715. || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)
  10716. || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)
  10717. ) {
  10718. return false;
  10719. }
  10720. var d = cubicProjectPoint(
  10721. x0, y0, x1, y1, x2, y2, x3, y3,
  10722. x, y, null
  10723. );
  10724. return d <= _l / 2;
  10725. }
  10726. /**
  10727. * 二次贝塞尔曲线描边包含判断
  10728. * @param {number} x0
  10729. * @param {number} y0
  10730. * @param {number} x1
  10731. * @param {number} y1
  10732. * @param {number} x2
  10733. * @param {number} y2
  10734. * @param {number} lineWidth
  10735. * @param {number} x
  10736. * @param {number} y
  10737. * @return {boolean}
  10738. */
  10739. function containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
  10740. if (lineWidth === 0) {
  10741. return false;
  10742. }
  10743. var _l = lineWidth;
  10744. // Quick reject
  10745. if (
  10746. (y > y0 + _l && y > y1 + _l && y > y2 + _l)
  10747. || (y < y0 - _l && y < y1 - _l && y < y2 - _l)
  10748. || (x > x0 + _l && x > x1 + _l && x > x2 + _l)
  10749. || (x < x0 - _l && x < x1 - _l && x < x2 - _l)
  10750. ) {
  10751. return false;
  10752. }
  10753. var d = quadraticProjectPoint(
  10754. x0, y0, x1, y1, x2, y2,
  10755. x, y, null
  10756. );
  10757. return d <= _l / 2;
  10758. }
  10759. var PI2$3 = Math.PI * 2;
  10760. function normalizeRadian(angle) {
  10761. angle %= PI2$3;
  10762. if (angle < 0) {
  10763. angle += PI2$3;
  10764. }
  10765. return angle;
  10766. }
  10767. var PI2$2 = Math.PI * 2;
  10768. /**
  10769. * 圆弧描边包含判断
  10770. * @param {number} cx
  10771. * @param {number} cy
  10772. * @param {number} r
  10773. * @param {number} startAngle
  10774. * @param {number} endAngle
  10775. * @param {boolean} anticlockwise
  10776. * @param {number} lineWidth
  10777. * @param {number} x
  10778. * @param {number} y
  10779. * @return {Boolean}
  10780. */
  10781. function containStroke$4(
  10782. cx, cy, r, startAngle, endAngle, anticlockwise,
  10783. lineWidth, x, y
  10784. ) {
  10785. if (lineWidth === 0) {
  10786. return false;
  10787. }
  10788. var _l = lineWidth;
  10789. x -= cx;
  10790. y -= cy;
  10791. var d = Math.sqrt(x * x + y * y);
  10792. if ((d - _l > r) || (d + _l < r)) {
  10793. return false;
  10794. }
  10795. if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {
  10796. // Is a circle
  10797. return true;
  10798. }
  10799. if (anticlockwise) {
  10800. var tmp = startAngle;
  10801. startAngle = normalizeRadian(endAngle);
  10802. endAngle = normalizeRadian(tmp);
  10803. } else {
  10804. startAngle = normalizeRadian(startAngle);
  10805. endAngle = normalizeRadian(endAngle);
  10806. }
  10807. if (startAngle > endAngle) {
  10808. endAngle += PI2$2;
  10809. }
  10810. var angle = Math.atan2(y, x);
  10811. if (angle < 0) {
  10812. angle += PI2$2;
  10813. }
  10814. return (angle >= startAngle && angle <= endAngle)
  10815. || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);
  10816. }
  10817. function windingLine(x0, y0, x1, y1, x, y) {
  10818. if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
  10819. return 0;
  10820. }
  10821. // Ignore horizontal line
  10822. if (y1 === y0) {
  10823. return 0;
  10824. }
  10825. var dir = y1 < y0 ? 1 : -1;
  10826. var t = (y - y0) / (y1 - y0);
  10827. // Avoid winding error when intersection point is the connect point of two line of polygon
  10828. if (t === 1 || t === 0) {
  10829. dir = y1 < y0 ? 0.5 : -0.5;
  10830. }
  10831. var x_ = t * (x1 - x0) + x0;
  10832. return x_ > x ? dir : 0;
  10833. }
  10834. var CMD$1 = PathProxy.CMD;
  10835. var PI2$1 = Math.PI * 2;
  10836. var EPSILON$2 = 1e-4;
  10837. function isAroundEqual(a, b) {
  10838. return Math.abs(a - b) < EPSILON$2;
  10839. }
  10840. // 临时数组
  10841. var roots = [-1, -1, -1];
  10842. var extrema = [-1, -1];
  10843. function swapExtrema() {
  10844. var tmp = extrema[0];
  10845. extrema[0] = extrema[1];
  10846. extrema[1] = tmp;
  10847. }
  10848. function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
  10849. // Quick reject
  10850. if (
  10851. (y > y0 && y > y1 && y > y2 && y > y3)
  10852. || (y < y0 && y < y1 && y < y2 && y < y3)
  10853. ) {
  10854. return 0;
  10855. }
  10856. var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);
  10857. if (nRoots === 0) {
  10858. return 0;
  10859. }
  10860. else {
  10861. var w = 0;
  10862. var nExtrema = -1;
  10863. var y0_, y1_;
  10864. for (var i = 0; i < nRoots; i++) {
  10865. var t = roots[i];
  10866. // Avoid winding error when intersection point is the connect point of two line of polygon
  10867. var unit = (t === 0 || t === 1) ? 0.5 : 1;
  10868. var x_ = cubicAt(x0, x1, x2, x3, t);
  10869. if (x_ < x) { // Quick reject
  10870. continue;
  10871. }
  10872. if (nExtrema < 0) {
  10873. nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);
  10874. if (extrema[1] < extrema[0] && nExtrema > 1) {
  10875. swapExtrema();
  10876. }
  10877. y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);
  10878. if (nExtrema > 1) {
  10879. y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);
  10880. }
  10881. }
  10882. if (nExtrema == 2) {
  10883. // 分成三段单调函数
  10884. if (t < extrema[0]) {
  10885. w += y0_ < y0 ? unit : -unit;
  10886. }
  10887. else if (t < extrema[1]) {
  10888. w += y1_ < y0_ ? unit : -unit;
  10889. }
  10890. else {
  10891. w += y3 < y1_ ? unit : -unit;
  10892. }
  10893. }
  10894. else {
  10895. // 分成两段单调函数
  10896. if (t < extrema[0]) {
  10897. w += y0_ < y0 ? unit : -unit;
  10898. }
  10899. else {
  10900. w += y3 < y0_ ? unit : -unit;
  10901. }
  10902. }
  10903. }
  10904. return w;
  10905. }
  10906. }
  10907. function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
  10908. // Quick reject
  10909. if (
  10910. (y > y0 && y > y1 && y > y2)
  10911. || (y < y0 && y < y1 && y < y2)
  10912. ) {
  10913. return 0;
  10914. }
  10915. var nRoots = quadraticRootAt(y0, y1, y2, y, roots);
  10916. if (nRoots === 0) {
  10917. return 0;
  10918. }
  10919. else {
  10920. var t = quadraticExtremum(y0, y1, y2);
  10921. if (t >= 0 && t <= 1) {
  10922. var w = 0;
  10923. var y_ = quadraticAt(y0, y1, y2, t);
  10924. for (var i = 0; i < nRoots; i++) {
  10925. // Remove one endpoint.
  10926. var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;
  10927. var x_ = quadraticAt(x0, x1, x2, roots[i]);
  10928. if (x_ < x) { // Quick reject
  10929. continue;
  10930. }
  10931. if (roots[i] < t) {
  10932. w += y_ < y0 ? unit : -unit;
  10933. }
  10934. else {
  10935. w += y2 < y_ ? unit : -unit;
  10936. }
  10937. }
  10938. return w;
  10939. }
  10940. else {
  10941. // Remove one endpoint.
  10942. var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;
  10943. var x_ = quadraticAt(x0, x1, x2, roots[0]);
  10944. if (x_ < x) { // Quick reject
  10945. return 0;
  10946. }
  10947. return y2 < y0 ? unit : -unit;
  10948. }
  10949. }
  10950. }
  10951. // TODO
  10952. // Arc 旋转
  10953. function windingArc(
  10954. cx, cy, r, startAngle, endAngle, anticlockwise, x, y
  10955. ) {
  10956. y -= cy;
  10957. if (y > r || y < -r) {
  10958. return 0;
  10959. }
  10960. var tmp = Math.sqrt(r * r - y * y);
  10961. roots[0] = -tmp;
  10962. roots[1] = tmp;
  10963. var diff = Math.abs(startAngle - endAngle);
  10964. if (diff < 1e-4) {
  10965. return 0;
  10966. }
  10967. if (diff % PI2$1 < 1e-4) {
  10968. // Is a circle
  10969. startAngle = 0;
  10970. endAngle = PI2$1;
  10971. var dir = anticlockwise ? 1 : -1;
  10972. if (x >= roots[0] + cx && x <= roots[1] + cx) {
  10973. return dir;
  10974. } else {
  10975. return 0;
  10976. }
  10977. }
  10978. if (anticlockwise) {
  10979. var tmp = startAngle;
  10980. startAngle = normalizeRadian(endAngle);
  10981. endAngle = normalizeRadian(tmp);
  10982. }
  10983. else {
  10984. startAngle = normalizeRadian(startAngle);
  10985. endAngle = normalizeRadian(endAngle);
  10986. }
  10987. if (startAngle > endAngle) {
  10988. endAngle += PI2$1;
  10989. }
  10990. var w = 0;
  10991. for (var i = 0; i < 2; i++) {
  10992. var x_ = roots[i];
  10993. if (x_ + cx > x) {
  10994. var angle = Math.atan2(y, x_);
  10995. var dir = anticlockwise ? 1 : -1;
  10996. if (angle < 0) {
  10997. angle = PI2$1 + angle;
  10998. }
  10999. if (
  11000. (angle >= startAngle && angle <= endAngle)
  11001. || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)
  11002. ) {
  11003. if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
  11004. dir = -dir;
  11005. }
  11006. w += dir;
  11007. }
  11008. }
  11009. }
  11010. return w;
  11011. }
  11012. function containPath(data, lineWidth, isStroke, x, y) {
  11013. var w = 0;
  11014. var xi = 0;
  11015. var yi = 0;
  11016. var x0 = 0;
  11017. var y0 = 0;
  11018. for (var i = 0; i < data.length;) {
  11019. var cmd = data[i++];
  11020. // Begin a new subpath
  11021. if (cmd === CMD$1.M && i > 1) {
  11022. // Close previous subpath
  11023. if (!isStroke) {
  11024. w += windingLine(xi, yi, x0, y0, x, y);
  11025. }
  11026. // 如果被任何一个 subpath 包含
  11027. // if (w !== 0) {
  11028. // return true;
  11029. // }
  11030. }
  11031. if (i == 1) {
  11032. // 如果第一个命令是 L, C, Q
  11033. // 则 previous point 同绘制命令的第一个 point
  11034. //
  11035. // 第一个命令为 Arc 的情况下会在后面特殊处理
  11036. xi = data[i];
  11037. yi = data[i + 1];
  11038. x0 = xi;
  11039. y0 = yi;
  11040. }
  11041. switch (cmd) {
  11042. case CMD$1.M:
  11043. // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
  11044. // 在 closePath 的时候使用
  11045. x0 = data[i++];
  11046. y0 = data[i++];
  11047. xi = x0;
  11048. yi = y0;
  11049. break;
  11050. case CMD$1.L:
  11051. if (isStroke) {
  11052. if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
  11053. return true;
  11054. }
  11055. }
  11056. else {
  11057. // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN
  11058. w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
  11059. }
  11060. xi = data[i++];
  11061. yi = data[i++];
  11062. break;
  11063. case CMD$1.C:
  11064. if (isStroke) {
  11065. if (containStroke$2(xi, yi,
  11066. data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
  11067. lineWidth, x, y
  11068. )) {
  11069. return true;
  11070. }
  11071. }
  11072. else {
  11073. w += windingCubic(
  11074. xi, yi,
  11075. data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],
  11076. x, y
  11077. ) || 0;
  11078. }
  11079. xi = data[i++];
  11080. yi = data[i++];
  11081. break;
  11082. case CMD$1.Q:
  11083. if (isStroke) {
  11084. if (containStroke$3(xi, yi,
  11085. data[i++], data[i++], data[i], data[i + 1],
  11086. lineWidth, x, y
  11087. )) {
  11088. return true;
  11089. }
  11090. }
  11091. else {
  11092. w += windingQuadratic(
  11093. xi, yi,
  11094. data[i++], data[i++], data[i], data[i + 1],
  11095. x, y
  11096. ) || 0;
  11097. }
  11098. xi = data[i++];
  11099. yi = data[i++];
  11100. break;
  11101. case CMD$1.A:
  11102. // TODO Arc 判断的开销比较大
  11103. var cx = data[i++];
  11104. var cy = data[i++];
  11105. var rx = data[i++];
  11106. var ry = data[i++];
  11107. var theta = data[i++];
  11108. var dTheta = data[i++];
  11109. // TODO Arc 旋转
  11110. var psi = data[i++];
  11111. var anticlockwise = 1 - data[i++];
  11112. var x1 = Math.cos(theta) * rx + cx;
  11113. var y1 = Math.sin(theta) * ry + cy;
  11114. // 不是直接使用 arc 命令
  11115. if (i > 1) {
  11116. w += windingLine(xi, yi, x1, y1, x, y);
  11117. }
  11118. else {
  11119. // 第一个命令起点还未定义
  11120. x0 = x1;
  11121. y0 = y1;
  11122. }
  11123. // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放
  11124. var _x = (x - cx) * ry / rx + cx;
  11125. if (isStroke) {
  11126. if (containStroke$4(
  11127. cx, cy, ry, theta, theta + dTheta, anticlockwise,
  11128. lineWidth, _x, y
  11129. )) {
  11130. return true;
  11131. }
  11132. }
  11133. else {
  11134. w += windingArc(
  11135. cx, cy, ry, theta, theta + dTheta, anticlockwise,
  11136. _x, y
  11137. );
  11138. }
  11139. xi = Math.cos(theta + dTheta) * rx + cx;
  11140. yi = Math.sin(theta + dTheta) * ry + cy;
  11141. break;
  11142. case CMD$1.R:
  11143. x0 = xi = data[i++];
  11144. y0 = yi = data[i++];
  11145. var width = data[i++];
  11146. var height = data[i++];
  11147. var x1 = x0 + width;
  11148. var y1 = y0 + height;
  11149. if (isStroke) {
  11150. if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)
  11151. || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)
  11152. || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)
  11153. || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)
  11154. ) {
  11155. return true;
  11156. }
  11157. }
  11158. else {
  11159. // FIXME Clockwise ?
  11160. w += windingLine(x1, y0, x1, y1, x, y);
  11161. w += windingLine(x0, y1, x0, y0, x, y);
  11162. }
  11163. break;
  11164. case CMD$1.Z:
  11165. if (isStroke) {
  11166. if (containStroke$1(
  11167. xi, yi, x0, y0, lineWidth, x, y
  11168. )) {
  11169. return true;
  11170. }
  11171. }
  11172. else {
  11173. // Close a subpath
  11174. w += windingLine(xi, yi, x0, y0, x, y);
  11175. // 如果被任何一个 subpath 包含
  11176. // FIXME subpaths may overlap
  11177. // if (w !== 0) {
  11178. // return true;
  11179. // }
  11180. }
  11181. xi = x0;
  11182. yi = y0;
  11183. break;
  11184. }
  11185. }
  11186. if (!isStroke && !isAroundEqual(yi, y0)) {
  11187. w += windingLine(xi, yi, x0, y0, x, y) || 0;
  11188. }
  11189. return w !== 0;
  11190. }
  11191. function contain(pathData, x, y) {
  11192. return containPath(pathData, 0, false, x, y);
  11193. }
  11194. function containStroke(pathData, lineWidth, x, y) {
  11195. return containPath(pathData, lineWidth, true, x, y);
  11196. }
  11197. var getCanvasPattern = Pattern.prototype.getCanvasPattern;
  11198. var abs = Math.abs;
  11199. var pathProxyForDraw = new PathProxy(true);
  11200. /**
  11201. * @alias module:zrender/graphic/Path
  11202. * @extends module:zrender/graphic/Displayable
  11203. * @constructor
  11204. * @param {Object} opts
  11205. */
  11206. function Path(opts) {
  11207. Displayable.call(this, opts);
  11208. /**
  11209. * @type {module:zrender/core/PathProxy}
  11210. * @readOnly
  11211. */
  11212. this.path = null;
  11213. }
  11214. Path.prototype = {
  11215. constructor: Path,
  11216. type: 'path',
  11217. __dirtyPath: true,
  11218. strokeContainThreshold: 5,
  11219. brush: function (ctx, prevEl) {
  11220. var style = this.style;
  11221. var path = this.path || pathProxyForDraw;
  11222. var hasStroke = style.hasStroke();
  11223. var hasFill = style.hasFill();
  11224. var fill = style.fill;
  11225. var stroke = style.stroke;
  11226. var hasFillGradient = hasFill && !!(fill.colorStops);
  11227. var hasStrokeGradient = hasStroke && !!(stroke.colorStops);
  11228. var hasFillPattern = hasFill && !!(fill.image);
  11229. var hasStrokePattern = hasStroke && !!(stroke.image);
  11230. style.bind(ctx, this, prevEl);
  11231. this.setTransform(ctx);
  11232. if (this.__dirty) {
  11233. var rect;
  11234. // Update gradient because bounding rect may changed
  11235. if (hasFillGradient) {
  11236. rect = rect || this.getBoundingRect();
  11237. this._fillGradient = style.getGradient(ctx, fill, rect);
  11238. }
  11239. if (hasStrokeGradient) {
  11240. rect = rect || this.getBoundingRect();
  11241. this._strokeGradient = style.getGradient(ctx, stroke, rect);
  11242. }
  11243. }
  11244. // Use the gradient or pattern
  11245. if (hasFillGradient) {
  11246. // PENDING If may have affect the state
  11247. ctx.fillStyle = this._fillGradient;
  11248. }
  11249. else if (hasFillPattern) {
  11250. ctx.fillStyle = getCanvasPattern.call(fill, ctx);
  11251. }
  11252. if (hasStrokeGradient) {
  11253. ctx.strokeStyle = this._strokeGradient;
  11254. }
  11255. else if (hasStrokePattern) {
  11256. ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);
  11257. }
  11258. var lineDash = style.lineDash;
  11259. var lineDashOffset = style.lineDashOffset;
  11260. var ctxLineDash = !!ctx.setLineDash;
  11261. // Update path sx, sy
  11262. var scale = this.getGlobalScale();
  11263. path.setScale(scale[0], scale[1]);
  11264. // Proxy context
  11265. // Rebuild path in following 2 cases
  11266. // 1. Path is dirty
  11267. // 2. Path needs javascript implemented lineDash stroking.
  11268. // In this case, lineDash information will not be saved in PathProxy
  11269. if (this.__dirtyPath
  11270. || (lineDash && !ctxLineDash && hasStroke)
  11271. ) {
  11272. path.beginPath(ctx);
  11273. // Setting line dash before build path
  11274. if (lineDash && !ctxLineDash) {
  11275. path.setLineDash(lineDash);
  11276. path.setLineDashOffset(lineDashOffset);
  11277. }
  11278. this.buildPath(path, this.shape, false);
  11279. // Clear path dirty flag
  11280. if (this.path) {
  11281. this.__dirtyPath = false;
  11282. }
  11283. }
  11284. else {
  11285. // Replay path building
  11286. ctx.beginPath();
  11287. this.path.rebuildPath(ctx);
  11288. }
  11289. hasFill && path.fill(ctx);
  11290. if (lineDash && ctxLineDash) {
  11291. ctx.setLineDash(lineDash);
  11292. ctx.lineDashOffset = lineDashOffset;
  11293. }
  11294. hasStroke && path.stroke(ctx);
  11295. if (lineDash && ctxLineDash) {
  11296. // PENDING
  11297. // Remove lineDash
  11298. ctx.setLineDash([]);
  11299. }
  11300. this.restoreTransform(ctx);
  11301. // Draw rect text
  11302. if (style.text != null) {
  11303. this.drawRectText(ctx, this.getBoundingRect());
  11304. }
  11305. },
  11306. // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath
  11307. // Like in circle
  11308. buildPath: function (ctx, shapeCfg, inBundle) {},
  11309. createPathProxy: function () {
  11310. this.path = new PathProxy();
  11311. },
  11312. getBoundingRect: function () {
  11313. var rect = this._rect;
  11314. var style = this.style;
  11315. var needsUpdateRect = !rect;
  11316. if (needsUpdateRect) {
  11317. var path = this.path;
  11318. if (!path) {
  11319. // Create path on demand.
  11320. path = this.path = new PathProxy();
  11321. }
  11322. if (this.__dirtyPath) {
  11323. path.beginPath();
  11324. this.buildPath(path, this.shape, false);
  11325. }
  11326. rect = path.getBoundingRect();
  11327. }
  11328. this._rect = rect;
  11329. if (style.hasStroke()) {
  11330. // Needs update rect with stroke lineWidth when
  11331. // 1. Element changes scale or lineWidth
  11332. // 2. Shape is changed
  11333. var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());
  11334. if (this.__dirty || needsUpdateRect) {
  11335. rectWithStroke.copy(rect);
  11336. // FIXME Must after updateTransform
  11337. var w = style.lineWidth;
  11338. // PENDING, Min line width is needed when line is horizontal or vertical
  11339. var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
  11340. // Only add extra hover lineWidth when there are no fill
  11341. if (!style.hasFill()) {
  11342. w = Math.max(w, this.strokeContainThreshold || 4);
  11343. }
  11344. // Consider line width
  11345. // Line scale can't be 0;
  11346. if (lineScale > 1e-10) {
  11347. rectWithStroke.width += w / lineScale;
  11348. rectWithStroke.height += w / lineScale;
  11349. rectWithStroke.x -= w / lineScale / 2;
  11350. rectWithStroke.y -= w / lineScale / 2;
  11351. }
  11352. }
  11353. // Return rect with stroke
  11354. return rectWithStroke;
  11355. }
  11356. return rect;
  11357. },
  11358. contain: function (x, y) {
  11359. var localPos = this.transformCoordToLocal(x, y);
  11360. var rect = this.getBoundingRect();
  11361. var style = this.style;
  11362. x = localPos[0];
  11363. y = localPos[1];
  11364. if (rect.contain(x, y)) {
  11365. var pathData = this.path.data;
  11366. if (style.hasStroke()) {
  11367. var lineWidth = style.lineWidth;
  11368. var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
  11369. // Line scale can't be 0;
  11370. if (lineScale > 1e-10) {
  11371. // Only add extra hover lineWidth when there are no fill
  11372. if (!style.hasFill()) {
  11373. lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
  11374. }
  11375. if (containStroke(
  11376. pathData, lineWidth / lineScale, x, y
  11377. )) {
  11378. return true;
  11379. }
  11380. }
  11381. }
  11382. if (style.hasFill()) {
  11383. return contain(pathData, x, y);
  11384. }
  11385. }
  11386. return false;
  11387. },
  11388. /**
  11389. * @param {boolean} dirtyPath
  11390. */
  11391. dirty: function (dirtyPath) {
  11392. if (dirtyPath == null) {
  11393. dirtyPath = true;
  11394. }
  11395. // Only mark dirty, not mark clean
  11396. if (dirtyPath) {
  11397. this.__dirtyPath = dirtyPath;
  11398. this._rect = null;
  11399. }
  11400. this.__dirty = true;
  11401. this.__zr && this.__zr.refresh();
  11402. // Used as a clipping path
  11403. if (this.__clipTarget) {
  11404. this.__clipTarget.dirty();
  11405. }
  11406. },
  11407. /**
  11408. * Alias for animate('shape')
  11409. * @param {boolean} loop
  11410. */
  11411. animateShape: function (loop) {
  11412. return this.animate('shape', loop);
  11413. },
  11414. // Overwrite attrKV
  11415. attrKV: function (key, value) {
  11416. // FIXME
  11417. if (key === 'shape') {
  11418. this.setShape(value);
  11419. this.__dirtyPath = true;
  11420. this._rect = null;
  11421. }
  11422. else {
  11423. Displayable.prototype.attrKV.call(this, key, value);
  11424. }
  11425. },
  11426. /**
  11427. * @param {Object|string} key
  11428. * @param {*} value
  11429. */
  11430. setShape: function (key, value) {
  11431. var shape = this.shape;
  11432. // Path from string may not have shape
  11433. if (shape) {
  11434. if (isObject(key)) {
  11435. for (var name in key) {
  11436. if (key.hasOwnProperty(name)) {
  11437. shape[name] = key[name];
  11438. }
  11439. }
  11440. }
  11441. else {
  11442. shape[key] = value;
  11443. }
  11444. this.dirty(true);
  11445. }
  11446. return this;
  11447. },
  11448. getLineScale: function () {
  11449. var m = this.transform;
  11450. // Get the line scale.
  11451. // Determinant of `m` means how much the area is enlarged by the
  11452. // transformation. So its square root can be used as a scale factor
  11453. // for width.
  11454. return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10
  11455. ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))
  11456. : 1;
  11457. }
  11458. };
  11459. /**
  11460. * 扩展一个 Path element, 比如星形,圆等。
  11461. * Extend a path element
  11462. * @param {Object} props
  11463. * @param {string} props.type Path type
  11464. * @param {Function} props.init Initialize
  11465. * @param {Function} props.buildPath Overwrite buildPath method
  11466. * @param {Object} [props.style] Extended default style config
  11467. * @param {Object} [props.shape] Extended default shape config
  11468. */
  11469. Path.extend = function (defaults$$1) {
  11470. var Sub = function (opts) {
  11471. Path.call(this, opts);
  11472. if (defaults$$1.style) {
  11473. // Extend default style
  11474. this.style.extendFrom(defaults$$1.style, false);
  11475. }
  11476. // Extend default shape
  11477. var defaultShape = defaults$$1.shape;
  11478. if (defaultShape) {
  11479. this.shape = this.shape || {};
  11480. var thisShape = this.shape;
  11481. for (var name in defaultShape) {
  11482. if (
  11483. ! thisShape.hasOwnProperty(name)
  11484. && defaultShape.hasOwnProperty(name)
  11485. ) {
  11486. thisShape[name] = defaultShape[name];
  11487. }
  11488. }
  11489. }
  11490. defaults$$1.init && defaults$$1.init.call(this, opts);
  11491. };
  11492. inherits(Sub, Path);
  11493. // FIXME 不能 extend position, rotation 等引用对象
  11494. for (var name in defaults$$1) {
  11495. // Extending prototype values and methods
  11496. if (name !== 'style' && name !== 'shape') {
  11497. Sub.prototype[name] = defaults$$1[name];
  11498. }
  11499. }
  11500. return Sub;
  11501. };
  11502. inherits(Path, Displayable);
  11503. var CMD$2 = PathProxy.CMD;
  11504. var points = [[], [], []];
  11505. var mathSqrt$3 = Math.sqrt;
  11506. var mathAtan2 = Math.atan2;
  11507. var transformPath = function (path, m) {
  11508. var data = path.data;
  11509. var cmd;
  11510. var nPoint;
  11511. var i;
  11512. var j;
  11513. var k;
  11514. var p;
  11515. var M = CMD$2.M;
  11516. var C = CMD$2.C;
  11517. var L = CMD$2.L;
  11518. var R = CMD$2.R;
  11519. var A = CMD$2.A;
  11520. var Q = CMD$2.Q;
  11521. for (i = 0, j = 0; i < data.length;) {
  11522. cmd = data[i++];
  11523. j = i;
  11524. nPoint = 0;
  11525. switch (cmd) {
  11526. case M:
  11527. nPoint = 1;
  11528. break;
  11529. case L:
  11530. nPoint = 1;
  11531. break;
  11532. case C:
  11533. nPoint = 3;
  11534. break;
  11535. case Q:
  11536. nPoint = 2;
  11537. break;
  11538. case A:
  11539. var x = m[4];
  11540. var y = m[5];
  11541. var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);
  11542. var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);
  11543. var angle = mathAtan2(-m[1] / sy, m[0] / sx);
  11544. // cx
  11545. data[i] *= sx;
  11546. data[i++] += x;
  11547. // cy
  11548. data[i] *= sy;
  11549. data[i++] += y;
  11550. // Scale rx and ry
  11551. // FIXME Assume psi is 0 here
  11552. data[i++] *= sx;
  11553. data[i++] *= sy;
  11554. // Start angle
  11555. data[i++] += angle;
  11556. // end angle
  11557. data[i++] += angle;
  11558. // FIXME psi
  11559. i += 2;
  11560. j = i;
  11561. break;
  11562. case R:
  11563. // x0, y0
  11564. p[0] = data[i++];
  11565. p[1] = data[i++];
  11566. applyTransform(p, p, m);
  11567. data[j++] = p[0];
  11568. data[j++] = p[1];
  11569. // x1, y1
  11570. p[0] += data[i++];
  11571. p[1] += data[i++];
  11572. applyTransform(p, p, m);
  11573. data[j++] = p[0];
  11574. data[j++] = p[1];
  11575. }
  11576. for (k = 0; k < nPoint; k++) {
  11577. var p = points[k];
  11578. p[0] = data[i++];
  11579. p[1] = data[i++];
  11580. applyTransform(p, p, m);
  11581. // Write back
  11582. data[j++] = p[0];
  11583. data[j++] = p[1];
  11584. }
  11585. }
  11586. };
  11587. // command chars
  11588. var cc = [
  11589. 'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',
  11590. 'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'
  11591. ];
  11592. var mathSqrt = Math.sqrt;
  11593. var mathSin = Math.sin;
  11594. var mathCos = Math.cos;
  11595. var PI = Math.PI;
  11596. var vMag = function(v) {
  11597. return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
  11598. };
  11599. var vRatio = function(u, v) {
  11600. return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
  11601. };
  11602. var vAngle = function(u, v) {
  11603. return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)
  11604. * Math.acos(vRatio(u, v));
  11605. };
  11606. function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
  11607. var psi = psiDeg * (PI / 180.0);
  11608. var xp = mathCos(psi) * (x1 - x2) / 2.0
  11609. + mathSin(psi) * (y1 - y2) / 2.0;
  11610. var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0
  11611. + mathCos(psi) * (y1 - y2) / 2.0;
  11612. var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
  11613. if (lambda > 1) {
  11614. rx *= mathSqrt(lambda);
  11615. ry *= mathSqrt(lambda);
  11616. }
  11617. var f = (fa === fs ? -1 : 1)
  11618. * mathSqrt((((rx * rx) * (ry * ry))
  11619. - ((rx * rx) * (yp * yp))
  11620. - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)
  11621. + (ry * ry) * (xp * xp))
  11622. ) || 0;
  11623. var cxp = f * rx * yp / ry;
  11624. var cyp = f * -ry * xp / rx;
  11625. var cx = (x1 + x2) / 2.0
  11626. + mathCos(psi) * cxp
  11627. - mathSin(psi) * cyp;
  11628. var cy = (y1 + y2) / 2.0
  11629. + mathSin(psi) * cxp
  11630. + mathCos(psi) * cyp;
  11631. var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);
  11632. var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];
  11633. var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];
  11634. var dTheta = vAngle(u, v);
  11635. if (vRatio(u, v) <= -1) {
  11636. dTheta = PI;
  11637. }
  11638. if (vRatio(u, v) >= 1) {
  11639. dTheta = 0;
  11640. }
  11641. if (fs === 0 && dTheta > 0) {
  11642. dTheta = dTheta - 2 * PI;
  11643. }
  11644. if (fs === 1 && dTheta < 0) {
  11645. dTheta = dTheta + 2 * PI;
  11646. }
  11647. path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
  11648. }
  11649. function createPathProxyFromString(data) {
  11650. if (!data) {
  11651. return [];
  11652. }
  11653. // command string
  11654. var cs = data.replace(/-/g, ' -')
  11655. .replace(/ /g, ' ')
  11656. .replace(/ /g, ',')
  11657. .replace(/,,/g, ',');
  11658. var n;
  11659. // create pipes so that we can split the data
  11660. for (n = 0; n < cc.length; n++) {
  11661. cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
  11662. }
  11663. // create array
  11664. var arr = cs.split('|');
  11665. // init context point
  11666. var cpx = 0;
  11667. var cpy = 0;
  11668. var path = new PathProxy();
  11669. var CMD = PathProxy.CMD;
  11670. var prevCmd;
  11671. for (n = 1; n < arr.length; n++) {
  11672. var str = arr[n];
  11673. var c = str.charAt(0);
  11674. var off = 0;
  11675. var p = str.slice(1).replace(/e,-/g, 'e-').split(',');
  11676. var cmd;
  11677. if (p.length > 0 && p[0] === '') {
  11678. p.shift();
  11679. }
  11680. for (var i = 0; i < p.length; i++) {
  11681. p[i] = parseFloat(p[i]);
  11682. }
  11683. while (off < p.length && !isNaN(p[off])) {
  11684. if (isNaN(p[0])) {
  11685. break;
  11686. }
  11687. var ctlPtx;
  11688. var ctlPty;
  11689. var rx;
  11690. var ry;
  11691. var psi;
  11692. var fa;
  11693. var fs;
  11694. var x1 = cpx;
  11695. var y1 = cpy;
  11696. // convert l, H, h, V, and v to L
  11697. switch (c) {
  11698. case 'l':
  11699. cpx += p[off++];
  11700. cpy += p[off++];
  11701. cmd = CMD.L;
  11702. path.addData(cmd, cpx, cpy);
  11703. break;
  11704. case 'L':
  11705. cpx = p[off++];
  11706. cpy = p[off++];
  11707. cmd = CMD.L;
  11708. path.addData(cmd, cpx, cpy);
  11709. break;
  11710. case 'm':
  11711. cpx += p[off++];
  11712. cpy += p[off++];
  11713. cmd = CMD.M;
  11714. path.addData(cmd, cpx, cpy);
  11715. c = 'l';
  11716. break;
  11717. case 'M':
  11718. cpx = p[off++];
  11719. cpy = p[off++];
  11720. cmd = CMD.M;
  11721. path.addData(cmd, cpx, cpy);
  11722. c = 'L';
  11723. break;
  11724. case 'h':
  11725. cpx += p[off++];
  11726. cmd = CMD.L;
  11727. path.addData(cmd, cpx, cpy);
  11728. break;
  11729. case 'H':
  11730. cpx = p[off++];
  11731. cmd = CMD.L;
  11732. path.addData(cmd, cpx, cpy);
  11733. break;
  11734. case 'v':
  11735. cpy += p[off++];
  11736. cmd = CMD.L;
  11737. path.addData(cmd, cpx, cpy);
  11738. break;
  11739. case 'V':
  11740. cpy = p[off++];
  11741. cmd = CMD.L;
  11742. path.addData(cmd, cpx, cpy);
  11743. break;
  11744. case 'C':
  11745. cmd = CMD.C;
  11746. path.addData(
  11747. cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]
  11748. );
  11749. cpx = p[off - 2];
  11750. cpy = p[off - 1];
  11751. break;
  11752. case 'c':
  11753. cmd = CMD.C;
  11754. path.addData(
  11755. cmd,
  11756. p[off++] + cpx, p[off++] + cpy,
  11757. p[off++] + cpx, p[off++] + cpy,
  11758. p[off++] + cpx, p[off++] + cpy
  11759. );
  11760. cpx += p[off - 2];
  11761. cpy += p[off - 1];
  11762. break;
  11763. case 'S':
  11764. ctlPtx = cpx;
  11765. ctlPty = cpy;
  11766. var len = path.len();
  11767. var pathData = path.data;
  11768. if (prevCmd === CMD.C) {
  11769. ctlPtx += cpx - pathData[len - 4];
  11770. ctlPty += cpy - pathData[len - 3];
  11771. }
  11772. cmd = CMD.C;
  11773. x1 = p[off++];
  11774. y1 = p[off++];
  11775. cpx = p[off++];
  11776. cpy = p[off++];
  11777. path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
  11778. break;
  11779. case 's':
  11780. ctlPtx = cpx;
  11781. ctlPty = cpy;
  11782. var len = path.len();
  11783. var pathData = path.data;
  11784. if (prevCmd === CMD.C) {
  11785. ctlPtx += cpx - pathData[len - 4];
  11786. ctlPty += cpy - pathData[len - 3];
  11787. }
  11788. cmd = CMD.C;
  11789. x1 = cpx + p[off++];
  11790. y1 = cpy + p[off++];
  11791. cpx += p[off++];
  11792. cpy += p[off++];
  11793. path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
  11794. break;
  11795. case 'Q':
  11796. x1 = p[off++];
  11797. y1 = p[off++];
  11798. cpx = p[off++];
  11799. cpy = p[off++];
  11800. cmd = CMD.Q;
  11801. path.addData(cmd, x1, y1, cpx, cpy);
  11802. break;
  11803. case 'q':
  11804. x1 = p[off++] + cpx;
  11805. y1 = p[off++] + cpy;
  11806. cpx += p[off++];
  11807. cpy += p[off++];
  11808. cmd = CMD.Q;
  11809. path.addData(cmd, x1, y1, cpx, cpy);
  11810. break;
  11811. case 'T':
  11812. ctlPtx = cpx;
  11813. ctlPty = cpy;
  11814. var len = path.len();
  11815. var pathData = path.data;
  11816. if (prevCmd === CMD.Q) {
  11817. ctlPtx += cpx - pathData[len - 4];
  11818. ctlPty += cpy - pathData[len - 3];
  11819. }
  11820. cpx = p[off++];
  11821. cpy = p[off++];
  11822. cmd = CMD.Q;
  11823. path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
  11824. break;
  11825. case 't':
  11826. ctlPtx = cpx;
  11827. ctlPty = cpy;
  11828. var len = path.len();
  11829. var pathData = path.data;
  11830. if (prevCmd === CMD.Q) {
  11831. ctlPtx += cpx - pathData[len - 4];
  11832. ctlPty += cpy - pathData[len - 3];
  11833. }
  11834. cpx += p[off++];
  11835. cpy += p[off++];
  11836. cmd = CMD.Q;
  11837. path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
  11838. break;
  11839. case 'A':
  11840. rx = p[off++];
  11841. ry = p[off++];
  11842. psi = p[off++];
  11843. fa = p[off++];
  11844. fs = p[off++];
  11845. x1 = cpx, y1 = cpy;
  11846. cpx = p[off++];
  11847. cpy = p[off++];
  11848. cmd = CMD.A;
  11849. processArc(
  11850. x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
  11851. );
  11852. break;
  11853. case 'a':
  11854. rx = p[off++];
  11855. ry = p[off++];
  11856. psi = p[off++];
  11857. fa = p[off++];
  11858. fs = p[off++];
  11859. x1 = cpx, y1 = cpy;
  11860. cpx += p[off++];
  11861. cpy += p[off++];
  11862. cmd = CMD.A;
  11863. processArc(
  11864. x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path
  11865. );
  11866. break;
  11867. }
  11868. }
  11869. if (c === 'z' || c === 'Z') {
  11870. cmd = CMD.Z;
  11871. path.addData(cmd);
  11872. }
  11873. prevCmd = cmd;
  11874. }
  11875. path.toStatic();
  11876. return path;
  11877. }
  11878. // TODO Optimize double memory cost problem
  11879. function createPathOptions(str, opts) {
  11880. var pathProxy = createPathProxyFromString(str);
  11881. opts = opts || {};
  11882. opts.buildPath = function (path) {
  11883. if (path.setData) {
  11884. path.setData(pathProxy.data);
  11885. // Svg and vml renderer don't have context
  11886. var ctx = path.getContext();
  11887. if (ctx) {
  11888. path.rebuildPath(ctx);
  11889. }
  11890. }
  11891. else {
  11892. var ctx = path;
  11893. pathProxy.rebuildPath(ctx);
  11894. }
  11895. };
  11896. opts.applyTransform = function (m) {
  11897. transformPath(pathProxy, m);
  11898. this.dirty(true);
  11899. };
  11900. return opts;
  11901. }
  11902. /**
  11903. * Create a Path object from path string data
  11904. * http://www.w3.org/TR/SVG/paths.html#PathData
  11905. * @param {Object} opts Other options
  11906. */
  11907. function createFromString(str, opts) {
  11908. return new Path(createPathOptions(str, opts));
  11909. }
  11910. /**
  11911. * Create a Path class from path string data
  11912. * @param {string} str
  11913. * @param {Object} opts Other options
  11914. */
  11915. function extendFromString(str, opts) {
  11916. return Path.extend(createPathOptions(str, opts));
  11917. }
  11918. /**
  11919. * Merge multiple paths
  11920. */
  11921. // TODO Apply transform
  11922. // TODO stroke dash
  11923. // TODO Optimize double memory cost problem
  11924. function mergePath(pathEls, opts) {
  11925. var pathList = [];
  11926. var len = pathEls.length;
  11927. for (var i = 0; i < len; i++) {
  11928. var pathEl = pathEls[i];
  11929. if (!pathEl.path) {
  11930. pathEl.createPathProxy();
  11931. }
  11932. if (pathEl.__dirtyPath) {
  11933. pathEl.buildPath(pathEl.path, pathEl.shape, true);
  11934. }
  11935. pathList.push(pathEl.path);
  11936. }
  11937. var pathBundle = new Path(opts);
  11938. // Need path proxy.
  11939. pathBundle.createPathProxy();
  11940. pathBundle.buildPath = function (path) {
  11941. path.appendPath(pathList);
  11942. // Svg and vml renderer don't have context
  11943. var ctx = path.getContext();
  11944. if (ctx) {
  11945. path.rebuildPath(ctx);
  11946. }
  11947. };
  11948. return pathBundle;
  11949. }
  11950. var path = (Object.freeze || Object)({
  11951. createFromString: createFromString,
  11952. extendFromString: extendFromString,
  11953. mergePath: mergePath
  11954. });
  11955. // CompoundPath to improve performance
  11956. var CompoundPath = Path.extend({
  11957. type: 'compound',
  11958. shape: {
  11959. paths: null
  11960. },
  11961. _updatePathDirty: function () {
  11962. var dirtyPath = this.__dirtyPath;
  11963. var paths = this.shape.paths;
  11964. for (var i = 0; i < paths.length; i++) {
  11965. // Mark as dirty if any subpath is dirty
  11966. dirtyPath = dirtyPath || paths[i].__dirtyPath;
  11967. }
  11968. this.__dirtyPath = dirtyPath;
  11969. this.__dirty = this.__dirty || dirtyPath;
  11970. },
  11971. beforeBrush: function () {
  11972. this._updatePathDirty();
  11973. var paths = this.shape.paths || [];
  11974. var scale = this.getGlobalScale();
  11975. // Update path scale
  11976. for (var i = 0; i < paths.length; i++) {
  11977. if (!paths[i].path) {
  11978. paths[i].createPathProxy();
  11979. }
  11980. paths[i].path.setScale(scale[0], scale[1]);
  11981. }
  11982. },
  11983. buildPath: function (ctx, shape) {
  11984. var paths = shape.paths || [];
  11985. for (var i = 0; i < paths.length; i++) {
  11986. paths[i].buildPath(ctx, paths[i].shape, true);
  11987. }
  11988. },
  11989. afterBrush: function () {
  11990. var paths = this.shape.paths || [];
  11991. for (var i = 0; i < paths.length; i++) {
  11992. paths[i].__dirtyPath = false;
  11993. }
  11994. },
  11995. getBoundingRect: function () {
  11996. this._updatePathDirty();
  11997. return Path.prototype.getBoundingRect.call(this);
  11998. }
  11999. });
  12000. /**
  12001. * @alias zrender/graphic/Text
  12002. * @extends module:zrender/graphic/Displayable
  12003. * @constructor
  12004. * @param {Object} opts
  12005. */
  12006. var Text = function (opts) { // jshint ignore:line
  12007. Displayable.call(this, opts);
  12008. };
  12009. Text.prototype = {
  12010. constructor: Text,
  12011. type: 'text',
  12012. brush: function (ctx, prevEl) {
  12013. var style = this.style;
  12014. // Optimize, avoid normalize every time.
  12015. this.__dirty && normalizeTextStyle(style, true);
  12016. // Use props with prefix 'text'.
  12017. style.fill = style.stroke = style.shadowBlur = style.shadowColor =
  12018. style.shadowOffsetX = style.shadowOffsetY = null;
  12019. var text = style.text;
  12020. // Convert to string
  12021. text != null && (text += '');
  12022. // Always bind style
  12023. style.bind(ctx, this, prevEl);
  12024. if (!needDrawText(text, style)) {
  12025. return;
  12026. }
  12027. this.setTransform(ctx);
  12028. renderText(this, ctx, text, style);
  12029. this.restoreTransform(ctx);
  12030. },
  12031. getBoundingRect: function () {
  12032. var style = this.style;
  12033. // Optimize, avoid normalize every time.
  12034. this.__dirty && normalizeTextStyle(style, true);
  12035. if (!this._rect) {
  12036. var text = style.text;
  12037. text != null ? (text += '') : (text = '');
  12038. var rect = getBoundingRect(
  12039. style.text + '',
  12040. style.font,
  12041. style.textAlign,
  12042. style.textVerticalAlign,
  12043. style.textPadding,
  12044. style.rich
  12045. );
  12046. rect.x += style.x || 0;
  12047. rect.y += style.y || 0;
  12048. if (getStroke(style.textStroke, style.textStrokeWidth)) {
  12049. var w = style.textStrokeWidth;
  12050. rect.x -= w / 2;
  12051. rect.y -= w / 2;
  12052. rect.width += w;
  12053. rect.height += w;
  12054. }
  12055. this._rect = rect;
  12056. }
  12057. return this._rect;
  12058. }
  12059. };
  12060. inherits(Text, Displayable);
  12061. /**
  12062. * 圆弧
  12063. * @module zrender/graphic/shape/Arc
  12064. */
  12065. var Arc = Path.extend({
  12066. type: 'arc',
  12067. shape: {
  12068. cx: 0,
  12069. cy: 0,
  12070. r: 0,
  12071. startAngle: 0,
  12072. endAngle: Math.PI * 2,
  12073. clockwise: true
  12074. },
  12075. style: {
  12076. stroke: '#000',
  12077. fill: null
  12078. },
  12079. buildPath: function (ctx, shape) {
  12080. var x = shape.cx;
  12081. var y = shape.cy;
  12082. var r = Math.max(shape.r, 0);
  12083. var startAngle = shape.startAngle;
  12084. var endAngle = shape.endAngle;
  12085. var clockwise = shape.clockwise;
  12086. var unitX = Math.cos(startAngle);
  12087. var unitY = Math.sin(startAngle);
  12088. ctx.moveTo(unitX * r + x, unitY * r + y);
  12089. ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
  12090. }
  12091. });
  12092. /**
  12093. * 贝塞尔曲线
  12094. * @module zrender/shape/BezierCurve
  12095. */
  12096. var out = [];
  12097. function someVectorAt(shape, t, isTangent) {
  12098. var cpx2 = shape.cpx2;
  12099. var cpy2 = shape.cpy2;
  12100. if (cpx2 === null || cpy2 === null) {
  12101. return [
  12102. (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),
  12103. (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)
  12104. ];
  12105. }
  12106. else {
  12107. return [
  12108. (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),
  12109. (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)
  12110. ];
  12111. }
  12112. }
  12113. var BezierCurve = Path.extend({
  12114. type: 'bezier-curve',
  12115. shape: {
  12116. x1: 0,
  12117. y1: 0,
  12118. x2: 0,
  12119. y2: 0,
  12120. cpx1: 0,
  12121. cpy1: 0,
  12122. // cpx2: 0,
  12123. // cpy2: 0
  12124. // Curve show percent, for animating
  12125. percent: 1
  12126. },
  12127. style: {
  12128. stroke: '#000',
  12129. fill: null
  12130. },
  12131. buildPath: function (ctx, shape) {
  12132. var x1 = shape.x1;
  12133. var y1 = shape.y1;
  12134. var x2 = shape.x2;
  12135. var y2 = shape.y2;
  12136. var cpx1 = shape.cpx1;
  12137. var cpy1 = shape.cpy1;
  12138. var cpx2 = shape.cpx2;
  12139. var cpy2 = shape.cpy2;
  12140. var percent = shape.percent;
  12141. if (percent === 0) {
  12142. return;
  12143. }
  12144. ctx.moveTo(x1, y1);
  12145. if (cpx2 == null || cpy2 == null) {
  12146. if (percent < 1) {
  12147. quadraticSubdivide(
  12148. x1, cpx1, x2, percent, out
  12149. );
  12150. cpx1 = out[1];
  12151. x2 = out[2];
  12152. quadraticSubdivide(
  12153. y1, cpy1, y2, percent, out
  12154. );
  12155. cpy1 = out[1];
  12156. y2 = out[2];
  12157. }
  12158. ctx.quadraticCurveTo(
  12159. cpx1, cpy1,
  12160. x2, y2
  12161. );
  12162. }
  12163. else {
  12164. if (percent < 1) {
  12165. cubicSubdivide(
  12166. x1, cpx1, cpx2, x2, percent, out
  12167. );
  12168. cpx1 = out[1];
  12169. cpx2 = out[2];
  12170. x2 = out[3];
  12171. cubicSubdivide(
  12172. y1, cpy1, cpy2, y2, percent, out
  12173. );
  12174. cpy1 = out[1];
  12175. cpy2 = out[2];
  12176. y2 = out[3];
  12177. }
  12178. ctx.bezierCurveTo(
  12179. cpx1, cpy1,
  12180. cpx2, cpy2,
  12181. x2, y2
  12182. );
  12183. }
  12184. },
  12185. /**
  12186. * Get point at percent
  12187. * @param {number} t
  12188. * @return {Array.<number>}
  12189. */
  12190. pointAt: function (t) {
  12191. return someVectorAt(this.shape, t, false);
  12192. },
  12193. /**
  12194. * Get tangent at percent
  12195. * @param {number} t
  12196. * @return {Array.<number>}
  12197. */
  12198. tangentAt: function (t) {
  12199. var p = someVectorAt(this.shape, t, true);
  12200. return normalize(p, p);
  12201. }
  12202. });
  12203. /**
  12204. * 圆形
  12205. * @module zrender/shape/Circle
  12206. */
  12207. var Circle = Path.extend({
  12208. type: 'circle',
  12209. shape: {
  12210. cx: 0,
  12211. cy: 0,
  12212. r: 0
  12213. },
  12214. buildPath : function (ctx, shape, inBundle) {
  12215. // Better stroking in ShapeBundle
  12216. // Always do it may have performence issue ( fill may be 2x more cost)
  12217. if (inBundle) {
  12218. ctx.moveTo(shape.cx + shape.r, shape.cy);
  12219. }
  12220. // else {
  12221. // if (ctx.allocate && !ctx.data.length) {
  12222. // ctx.allocate(ctx.CMD_MEM_SIZE.A);
  12223. // }
  12224. // }
  12225. // Better stroking in ShapeBundle
  12226. // ctx.moveTo(shape.cx + shape.r, shape.cy);
  12227. ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);
  12228. }
  12229. });
  12230. /**
  12231. * 水滴形状
  12232. * @module zrender/graphic/shape/Droplet
  12233. */
  12234. var Droplet = Path.extend({
  12235. type: 'droplet',
  12236. shape: {
  12237. cx: 0, cy: 0,
  12238. width: 0, height: 0
  12239. },
  12240. buildPath : function (ctx, shape) {
  12241. var x = shape.cx;
  12242. var y = shape.cy;
  12243. var a = shape.width;
  12244. var b = shape.height;
  12245. ctx.moveTo(x, y + a);
  12246. ctx.bezierCurveTo(
  12247. x + a,
  12248. y + a,
  12249. x + a * 3 / 2,
  12250. y - a / 3,
  12251. x,
  12252. y - b
  12253. );
  12254. ctx.bezierCurveTo(
  12255. x - a * 3 / 2,
  12256. y - a / 3,
  12257. x - a,
  12258. y + a,
  12259. x,
  12260. y + a
  12261. );
  12262. ctx.closePath();
  12263. }
  12264. });
  12265. /**
  12266. * 椭圆形状
  12267. * @module zrender/graphic/shape/Ellipse
  12268. */
  12269. var Ellipse = Path.extend({
  12270. type: 'ellipse',
  12271. shape: {
  12272. cx: 0, cy: 0,
  12273. rx: 0, ry: 0
  12274. },
  12275. buildPath: function (ctx, shape) {
  12276. var k = 0.5522848;
  12277. var x = shape.cx;
  12278. var y = shape.cy;
  12279. var a = shape.rx;
  12280. var b = shape.ry;
  12281. var ox = a * k; // 水平控制点偏移量
  12282. var oy = b * k; // 垂直控制点偏移量
  12283. // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线
  12284. ctx.moveTo(x - a, y);
  12285. ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);
  12286. ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);
  12287. ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);
  12288. ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);
  12289. ctx.closePath();
  12290. }
  12291. });
  12292. /**
  12293. * 心形
  12294. * @module zrender/graphic/shape/Heart
  12295. */
  12296. var Heart = Path.extend({
  12297. type: 'heart',
  12298. shape: {
  12299. cx: 0,
  12300. cy: 0,
  12301. width: 0,
  12302. height: 0
  12303. },
  12304. buildPath: function (ctx, shape) {
  12305. var x = shape.cx;
  12306. var y = shape.cy;
  12307. var a = shape.width;
  12308. var b = shape.height;
  12309. ctx.moveTo(x, y);
  12310. ctx.bezierCurveTo(
  12311. x + a / 2, y - b * 2 / 3,
  12312. x + a * 2, y + b / 3,
  12313. x, y + b
  12314. );
  12315. ctx.bezierCurveTo(
  12316. x - a * 2, y + b / 3,
  12317. x - a / 2, y - b * 2 / 3,
  12318. x, y
  12319. );
  12320. }
  12321. });
  12322. /**
  12323. * 正多边形
  12324. * @module zrender/shape/Isogon
  12325. */
  12326. var PI$1 = Math.PI;
  12327. var sin = Math.sin;
  12328. var cos = Math.cos;
  12329. var Isogon = Path.extend({
  12330. type: 'isogon',
  12331. shape: {
  12332. x: 0, y: 0,
  12333. r: 0, n: 0
  12334. },
  12335. buildPath: function (ctx, shape) {
  12336. var n = shape.n;
  12337. if (!n || n < 2) {
  12338. return;
  12339. }
  12340. var x = shape.x;
  12341. var y = shape.y;
  12342. var r = shape.r;
  12343. var dStep = 2 * PI$1 / n;
  12344. var deg = -PI$1 / 2;
  12345. ctx.moveTo(x + r * cos(deg), y + r * sin(deg));
  12346. for (var i = 0, end = n - 1; i < end; i++) {
  12347. deg += dStep;
  12348. ctx.lineTo(x + r * cos(deg), y + r * sin(deg));
  12349. }
  12350. ctx.closePath();
  12351. return;
  12352. }
  12353. });
  12354. /**
  12355. * 直线
  12356. * @module zrender/graphic/shape/Line
  12357. */
  12358. var Line = Path.extend({
  12359. type: 'line',
  12360. shape: {
  12361. // Start point
  12362. x1: 0,
  12363. y1: 0,
  12364. // End point
  12365. x2: 0,
  12366. y2: 0,
  12367. percent: 1
  12368. },
  12369. style: {
  12370. stroke: '#000',
  12371. fill: null
  12372. },
  12373. buildPath: function (ctx, shape) {
  12374. var x1 = shape.x1;
  12375. var y1 = shape.y1;
  12376. var x2 = shape.x2;
  12377. var y2 = shape.y2;
  12378. var percent = shape.percent;
  12379. if (percent === 0) {
  12380. return;
  12381. }
  12382. ctx.moveTo(x1, y1);
  12383. if (percent < 1) {
  12384. x2 = x1 * (1 - percent) + x2 * percent;
  12385. y2 = y1 * (1 - percent) + y2 * percent;
  12386. }
  12387. ctx.lineTo(x2, y2);
  12388. },
  12389. /**
  12390. * Get point at percent
  12391. * @param {number} percent
  12392. * @return {Array.<number>}
  12393. */
  12394. pointAt: function (p) {
  12395. var shape = this.shape;
  12396. return [
  12397. shape.x1 * (1 - p) + shape.x2 * p,
  12398. shape.y1 * (1 - p) + shape.y2 * p
  12399. ];
  12400. }
  12401. });
  12402. /**
  12403. * Catmull-Rom spline 插值折线
  12404. * @module zrender/shape/util/smoothSpline
  12405. * @author pissang (https://www.github.com/pissang)
  12406. * Kener (@Kener-林峰, kener.linfeng@gmail.com)
  12407. * errorrik (errorrik@gmail.com)
  12408. */
  12409. /**
  12410. * @inner
  12411. */
  12412. function interpolate(p0, p1, p2, p3, t, t2, t3) {
  12413. var v0 = (p2 - p0) * 0.5;
  12414. var v1 = (p3 - p1) * 0.5;
  12415. return (2 * (p1 - p2) + v0 + v1) * t3
  12416. + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
  12417. + v0 * t + p1;
  12418. }
  12419. /**
  12420. * @alias module:zrender/shape/util/smoothSpline
  12421. * @param {Array} points 线段顶点数组
  12422. * @param {boolean} isLoop
  12423. * @return {Array}
  12424. */
  12425. var smoothSpline = function (points, isLoop) {
  12426. var len$$1 = points.length;
  12427. var ret = [];
  12428. var distance$$1 = 0;
  12429. for (var i = 1; i < len$$1; i++) {
  12430. distance$$1 += distance(points[i - 1], points[i]);
  12431. }
  12432. var segs = distance$$1 / 2;
  12433. segs = segs < len$$1 ? len$$1 : segs;
  12434. for (var i = 0; i < segs; i++) {
  12435. var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);
  12436. var idx = Math.floor(pos);
  12437. var w = pos - idx;
  12438. var p0;
  12439. var p1 = points[idx % len$$1];
  12440. var p2;
  12441. var p3;
  12442. if (!isLoop) {
  12443. p0 = points[idx === 0 ? idx : idx - 1];
  12444. p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];
  12445. p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];
  12446. }
  12447. else {
  12448. p0 = points[(idx - 1 + len$$1) % len$$1];
  12449. p2 = points[(idx + 1) % len$$1];
  12450. p3 = points[(idx + 2) % len$$1];
  12451. }
  12452. var w2 = w * w;
  12453. var w3 = w * w2;
  12454. ret.push([
  12455. interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),
  12456. interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)
  12457. ]);
  12458. }
  12459. return ret;
  12460. };
  12461. /**
  12462. * 贝塞尔平滑曲线
  12463. * @module zrender/shape/util/smoothBezier
  12464. * @author pissang (https://www.github.com/pissang)
  12465. * Kener (@Kener-林峰, kener.linfeng@gmail.com)
  12466. * errorrik (errorrik@gmail.com)
  12467. */
  12468. /**
  12469. * 贝塞尔平滑曲线
  12470. * @alias module:zrender/shape/util/smoothBezier
  12471. * @param {Array} points 线段顶点数组
  12472. * @param {number} smooth 平滑等级, 0-1
  12473. * @param {boolean} isLoop
  12474. * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内
  12475. * 比如 [[0, 0], [100, 100]], 这个包围盒会与
  12476. * 整个折线的包围盒做一个并集用来约束控制点。
  12477. * @param {Array} 计算出来的控制点数组
  12478. */
  12479. var smoothBezier = function (points, smooth, isLoop, constraint) {
  12480. var cps = [];
  12481. var v = [];
  12482. var v1 = [];
  12483. var v2 = [];
  12484. var prevPoint;
  12485. var nextPoint;
  12486. var min$$1, max$$1;
  12487. if (constraint) {
  12488. min$$1 = [Infinity, Infinity];
  12489. max$$1 = [-Infinity, -Infinity];
  12490. for (var i = 0, len$$1 = points.length; i < len$$1; i++) {
  12491. min(min$$1, min$$1, points[i]);
  12492. max(max$$1, max$$1, points[i]);
  12493. }
  12494. // 与指定的包围盒做并集
  12495. min(min$$1, min$$1, constraint[0]);
  12496. max(max$$1, max$$1, constraint[1]);
  12497. }
  12498. for (var i = 0, len$$1 = points.length; i < len$$1; i++) {
  12499. var point = points[i];
  12500. if (isLoop) {
  12501. prevPoint = points[i ? i - 1 : len$$1 - 1];
  12502. nextPoint = points[(i + 1) % len$$1];
  12503. }
  12504. else {
  12505. if (i === 0 || i === len$$1 - 1) {
  12506. cps.push(clone$1(points[i]));
  12507. continue;
  12508. }
  12509. else {
  12510. prevPoint = points[i - 1];
  12511. nextPoint = points[i + 1];
  12512. }
  12513. }
  12514. sub(v, nextPoint, prevPoint);
  12515. // use degree to scale the handle length
  12516. scale(v, v, smooth);
  12517. var d0 = distance(point, prevPoint);
  12518. var d1 = distance(point, nextPoint);
  12519. var sum = d0 + d1;
  12520. if (sum !== 0) {
  12521. d0 /= sum;
  12522. d1 /= sum;
  12523. }
  12524. scale(v1, v, -d0);
  12525. scale(v2, v, d1);
  12526. var cp0 = add([], point, v1);
  12527. var cp1 = add([], point, v2);
  12528. if (constraint) {
  12529. max(cp0, cp0, min$$1);
  12530. min(cp0, cp0, max$$1);
  12531. max(cp1, cp1, min$$1);
  12532. min(cp1, cp1, max$$1);
  12533. }
  12534. cps.push(cp0);
  12535. cps.push(cp1);
  12536. }
  12537. if (isLoop) {
  12538. cps.push(cps.shift());
  12539. }
  12540. return cps;
  12541. };
  12542. function buildPath$1(ctx, shape, closePath) {
  12543. var points = shape.points;
  12544. var smooth = shape.smooth;
  12545. if (points && points.length >= 2) {
  12546. if (smooth && smooth !== 'spline') {
  12547. var controlPoints = smoothBezier(
  12548. points, smooth, closePath, shape.smoothConstraint
  12549. );
  12550. ctx.moveTo(points[0][0], points[0][1]);
  12551. var len = points.length;
  12552. for (var i = 0; i < (closePath ? len : len - 1); i++) {
  12553. var cp1 = controlPoints[i * 2];
  12554. var cp2 = controlPoints[i * 2 + 1];
  12555. var p = points[(i + 1) % len];
  12556. ctx.bezierCurveTo(
  12557. cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]
  12558. );
  12559. }
  12560. }
  12561. else {
  12562. if (smooth === 'spline') {
  12563. points = smoothSpline(points, closePath);
  12564. }
  12565. ctx.moveTo(points[0][0], points[0][1]);
  12566. for (var i = 1, l = points.length; i < l; i++) {
  12567. ctx.lineTo(points[i][0], points[i][1]);
  12568. }
  12569. }
  12570. closePath && ctx.closePath();
  12571. }
  12572. }
  12573. /**
  12574. * 多边形
  12575. * @module zrender/shape/Polygon
  12576. */
  12577. var Polygon = Path.extend({
  12578. type: 'polygon',
  12579. shape: {
  12580. points: null,
  12581. smooth: false,
  12582. smoothConstraint: null
  12583. },
  12584. buildPath: function (ctx, shape) {
  12585. buildPath$1(ctx, shape, true);
  12586. }
  12587. });
  12588. /**
  12589. * @module zrender/graphic/shape/Polyline
  12590. */
  12591. var Polyline = Path.extend({
  12592. type: 'polyline',
  12593. shape: {
  12594. points: null,
  12595. smooth: false,
  12596. smoothConstraint: null
  12597. },
  12598. style: {
  12599. stroke: '#000',
  12600. fill: null
  12601. },
  12602. buildPath: function (ctx, shape) {
  12603. buildPath$1(ctx, shape, false);
  12604. }
  12605. });
  12606. /**
  12607. * 矩形
  12608. * @module zrender/graphic/shape/Rect
  12609. */
  12610. var Rect = Path.extend({
  12611. type: 'rect',
  12612. shape: {
  12613. // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4
  12614. // r缩写为1 相当于 [1, 1, 1, 1]
  12615. // r缩写为[1] 相当于 [1, 1, 1, 1]
  12616. // r缩写为[1, 2] 相当于 [1, 2, 1, 2]
  12617. // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]
  12618. r: 0,
  12619. x: 0,
  12620. y: 0,
  12621. width: 0,
  12622. height: 0
  12623. },
  12624. buildPath: function (ctx, shape) {
  12625. var x = shape.x;
  12626. var y = shape.y;
  12627. var width = shape.width;
  12628. var height = shape.height;
  12629. if (!shape.r) {
  12630. ctx.rect(x, y, width, height);
  12631. }
  12632. else {
  12633. buildPath(ctx, shape);
  12634. }
  12635. ctx.closePath();
  12636. return;
  12637. }
  12638. });
  12639. /**
  12640. * 圆环
  12641. * @module zrender/graphic/shape/Ring
  12642. */
  12643. var Ring = Path.extend({
  12644. type: 'ring',
  12645. shape: {
  12646. cx: 0,
  12647. cy: 0,
  12648. r: 0,
  12649. r0: 0
  12650. },
  12651. buildPath: function (ctx, shape) {
  12652. var x = shape.cx;
  12653. var y = shape.cy;
  12654. var PI2 = Math.PI * 2;
  12655. ctx.moveTo(x + shape.r, y);
  12656. ctx.arc(x, y, shape.r, 0, PI2, false);
  12657. ctx.moveTo(x + shape.r0, y);
  12658. ctx.arc(x, y, shape.r0, 0, PI2, true);
  12659. }
  12660. });
  12661. /**
  12662. * 玫瑰线
  12663. * @module zrender/graphic/shape/Rose
  12664. */
  12665. var sin$1 = Math.sin;
  12666. var cos$1 = Math.cos;
  12667. var radian = Math.PI / 180;
  12668. var Rose = Path.extend({
  12669. type: 'rose',
  12670. shape: {
  12671. cx: 0,
  12672. cy: 0,
  12673. r: [],
  12674. k: 0,
  12675. n: 1
  12676. },
  12677. style: {
  12678. stroke: '#000',
  12679. fill: null
  12680. },
  12681. buildPath: function (ctx, shape) {
  12682. var x;
  12683. var y;
  12684. var R = shape.r;
  12685. var r;
  12686. var k = shape.k;
  12687. var n = shape.n;
  12688. var x0 = shape.cx;
  12689. var y0 = shape.cy;
  12690. ctx.moveTo(x0, y0);
  12691. for (var i = 0, len = R.length; i < len ; i++) {
  12692. r = R[i];
  12693. for (var j = 0; j <= 360 * n; j++) {
  12694. x = r
  12695. * sin$1(k / n * j % 360 * radian)
  12696. * cos$1(j * radian)
  12697. + x0;
  12698. y = r
  12699. * sin$1(k / n * j % 360 * radian)
  12700. * sin$1(j * radian)
  12701. + y0;
  12702. ctx.lineTo(x, y);
  12703. }
  12704. }
  12705. }
  12706. });
  12707. // Fix weird bug in some version of IE11 (like 11.0.9600.178**),
  12708. // where exception "unexpected call to method or property access"
  12709. // might be thrown when calling ctx.fill or ctx.stroke after a path
  12710. // whose area size is zero is drawn and ctx.clip() is called and
  12711. // shadowBlur is set. See #4572, #3112, #5777.
  12712. // (e.g.,
  12713. // ctx.moveTo(10, 10);
  12714. // ctx.lineTo(20, 10);
  12715. // ctx.closePath();
  12716. // ctx.clip();
  12717. // ctx.shadowBlur = 10;
  12718. // ...
  12719. // ctx.fill();
  12720. // )
  12721. var shadowTemp = [
  12722. ['shadowBlur', 0],
  12723. ['shadowColor', '#000'],
  12724. ['shadowOffsetX', 0],
  12725. ['shadowOffsetY', 0]
  12726. ];
  12727. var fixClipWithShadow = function (orignalBrush) {
  12728. // version string can be: '11.0'
  12729. return (env$1.browser.ie && env$1.browser.version >= 11)
  12730. ? function () {
  12731. var clipPaths = this.__clipPaths;
  12732. var style = this.style;
  12733. var modified;
  12734. if (clipPaths) {
  12735. for (var i = 0; i < clipPaths.length; i++) {
  12736. var clipPath = clipPaths[i];
  12737. var shape = clipPath && clipPath.shape;
  12738. var type = clipPath && clipPath.type;
  12739. if (shape && (
  12740. (type === 'sector' && shape.startAngle === shape.endAngle)
  12741. || (type === 'rect' && (!shape.width || !shape.height))
  12742. )) {
  12743. for (var j = 0; j < shadowTemp.length; j++) {
  12744. // It is save to put shadowTemp static, because shadowTemp
  12745. // will be all modified each item brush called.
  12746. shadowTemp[j][2] = style[shadowTemp[j][0]];
  12747. style[shadowTemp[j][0]] = shadowTemp[j][1];
  12748. }
  12749. modified = true;
  12750. break;
  12751. }
  12752. }
  12753. }
  12754. orignalBrush.apply(this, arguments);
  12755. if (modified) {
  12756. for (var j = 0; j < shadowTemp.length; j++) {
  12757. style[shadowTemp[j][0]] = shadowTemp[j][2];
  12758. }
  12759. }
  12760. }
  12761. : orignalBrush;
  12762. };
  12763. /**
  12764. * 扇形
  12765. * @module zrender/graphic/shape/Sector
  12766. */
  12767. var Sector = Path.extend({
  12768. type: 'sector',
  12769. shape: {
  12770. cx: 0,
  12771. cy: 0,
  12772. r0: 0,
  12773. r: 0,
  12774. startAngle: 0,
  12775. endAngle: Math.PI * 2,
  12776. clockwise: true
  12777. },
  12778. brush: fixClipWithShadow(Path.prototype.brush),
  12779. buildPath: function (ctx, shape) {
  12780. var x = shape.cx;
  12781. var y = shape.cy;
  12782. var r0 = Math.max(shape.r0 || 0, 0);
  12783. var r = Math.max(shape.r, 0);
  12784. var startAngle = shape.startAngle;
  12785. var endAngle = shape.endAngle;
  12786. var clockwise = shape.clockwise;
  12787. var unitX = Math.cos(startAngle);
  12788. var unitY = Math.sin(startAngle);
  12789. ctx.moveTo(unitX * r0 + x, unitY * r0 + y);
  12790. ctx.lineTo(unitX * r + x, unitY * r + y);
  12791. ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
  12792. ctx.lineTo(
  12793. Math.cos(endAngle) * r0 + x,
  12794. Math.sin(endAngle) * r0 + y
  12795. );
  12796. if (r0 !== 0) {
  12797. ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
  12798. }
  12799. ctx.closePath();
  12800. }
  12801. });
  12802. /**
  12803. * n角星(n>3)
  12804. * @module zrender/graphic/shape/Star
  12805. */
  12806. var PI$2 = Math.PI;
  12807. var cos$2 = Math.cos;
  12808. var sin$2 = Math.sin;
  12809. var Star = Path.extend({
  12810. type: 'star',
  12811. shape: {
  12812. cx: 0,
  12813. cy: 0,
  12814. n: 3,
  12815. r0: null,
  12816. r: 0
  12817. },
  12818. buildPath: function (ctx, shape) {
  12819. var n = shape.n;
  12820. if (!n || n < 2) {
  12821. return;
  12822. }
  12823. var x = shape.cx;
  12824. var y = shape.cy;
  12825. var r = shape.r;
  12826. var r0 = shape.r0;
  12827. // 如果未指定内部顶点外接圆半径,则自动计算
  12828. if (r0 == null) {
  12829. r0 = n > 4
  12830. // 相隔的外部顶点的连线的交点,
  12831. // 被取为内部交点,以此计算r0
  12832. ? r * cos$2(2 * PI$2 / n) / cos$2(PI$2 / n)
  12833. // 二三四角星的特殊处理
  12834. : r / 3;
  12835. }
  12836. var dStep = PI$2 / n;
  12837. var deg = -PI$2 / 2;
  12838. var xStart = x + r * cos$2(deg);
  12839. var yStart = y + r * sin$2(deg);
  12840. deg += dStep;
  12841. // 记录边界点,用于判断inside
  12842. ctx.moveTo(xStart, yStart);
  12843. for (var i = 0, end = n * 2 - 1, ri; i < end; i++) {
  12844. ri = i % 2 === 0 ? r0 : r;
  12845. ctx.lineTo(x + ri * cos$2(deg), y + ri * sin$2(deg));
  12846. deg += dStep;
  12847. }
  12848. ctx.closePath();
  12849. }
  12850. });
  12851. /**
  12852. * 内外旋轮曲线
  12853. * @module zrender/graphic/shape/Trochold
  12854. */
  12855. var cos$3 = Math.cos;
  12856. var sin$3 = Math.sin;
  12857. var Trochoid = Path.extend({
  12858. type: 'trochoid',
  12859. shape: {
  12860. cx: 0,
  12861. cy: 0,
  12862. r: 0,
  12863. r0: 0,
  12864. d: 0,
  12865. location: 'out'
  12866. },
  12867. style: {
  12868. stroke: '#000',
  12869. fill: null
  12870. },
  12871. buildPath: function (ctx, shape) {
  12872. var x1;
  12873. var y1;
  12874. var x2;
  12875. var y2;
  12876. var R = shape.r;
  12877. var r = shape.r0;
  12878. var d = shape.d;
  12879. var offsetX = shape.cx;
  12880. var offsetY = shape.cy;
  12881. var delta = shape.location == 'out' ? 1 : -1;
  12882. if (shape.location && R <= r) {
  12883. return;
  12884. }
  12885. var num = 0;
  12886. var i = 1;
  12887. var theta;
  12888. x1 = (R + delta * r) * cos$3(0)
  12889. - delta * d * cos$3(0) + offsetX;
  12890. y1 = (R + delta * r) * sin$3(0)
  12891. - d * sin$3(0) + offsetY;
  12892. ctx.moveTo(x1, y1);
  12893. // 计算结束时的i
  12894. do {
  12895. num++;
  12896. }
  12897. while ((r * num) % (R + delta * r) !== 0);
  12898. do {
  12899. theta = Math.PI / 180 * i;
  12900. x2 = (R + delta * r) * cos$3(theta)
  12901. - delta * d * cos$3((R / r + delta) * theta)
  12902. + offsetX;
  12903. y2 = (R + delta * r) * sin$3(theta)
  12904. - d * sin$3((R / r + delta) * theta)
  12905. + offsetY;
  12906. ctx.lineTo(x2, y2);
  12907. i++;
  12908. }
  12909. while (i <= (r * num) / (R + delta * r) * 360);
  12910. }
  12911. });
  12912. /**
  12913. * @param {Array.<Object>} colorStops
  12914. */
  12915. var Gradient = function (colorStops) {
  12916. this.colorStops = colorStops || [];
  12917. };
  12918. Gradient.prototype = {
  12919. constructor: Gradient,
  12920. addColorStop: function (offset, color) {
  12921. this.colorStops.push({
  12922. offset: offset,
  12923. color: color
  12924. });
  12925. }
  12926. };
  12927. /**
  12928. * x, y, x2, y2 are all percent from 0 to 1
  12929. * @param {number} [x=0]
  12930. * @param {number} [y=0]
  12931. * @param {number} [x2=1]
  12932. * @param {number} [y2=0]
  12933. * @param {Array.<Object>} colorStops
  12934. * @param {boolean} [globalCoord=false]
  12935. */
  12936. var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {
  12937. // Should do nothing more in this constructor. Because gradient can be
  12938. // declard by `color: {type: 'linear', colorStops: ...}`, where
  12939. // this constructor will not be called.
  12940. this.x = x == null ? 0 : x;
  12941. this.y = y == null ? 0 : y;
  12942. this.x2 = x2 == null ? 1 : x2;
  12943. this.y2 = y2 == null ? 0 : y2;
  12944. // Can be cloned
  12945. this.type = 'linear';
  12946. // If use global coord
  12947. this.global = globalCoord || false;
  12948. Gradient.call(this, colorStops);
  12949. };
  12950. LinearGradient.prototype = {
  12951. constructor: LinearGradient
  12952. };
  12953. inherits(LinearGradient, Gradient);
  12954. /**
  12955. * x, y, r are all percent from 0 to 1
  12956. * @param {number} [x=0.5]
  12957. * @param {number} [y=0.5]
  12958. * @param {number} [r=0.5]
  12959. * @param {Array.<Object>} [colorStops]
  12960. * @param {boolean} [globalCoord=false]
  12961. */
  12962. var RadialGradient = function (x, y, r, colorStops, globalCoord) {
  12963. // Should do nothing more in this constructor. Because gradient can be
  12964. // declard by `color: {type: 'radial', colorStops: ...}`, where
  12965. // this constructor will not be called.
  12966. this.x = x == null ? 0.5 : x;
  12967. this.y = y == null ? 0.5 : y;
  12968. this.r = r == null ? 0.5 : r;
  12969. // Can be cloned
  12970. this.type = 'radial';
  12971. // If use global coord
  12972. this.global = globalCoord || false;
  12973. Gradient.call(this, colorStops);
  12974. };
  12975. RadialGradient.prototype = {
  12976. constructor: RadialGradient
  12977. };
  12978. inherits(RadialGradient, Gradient);
  12979. /**
  12980. * Do not mount those modules on 'src/zrender' for better tree shaking.
  12981. */
  12982. var svgURI = 'http://www.w3.org/2000/svg';
  12983. function createElement(name) {
  12984. return document.createElementNS(svgURI, name);
  12985. }
  12986. // TODO
  12987. // 1. shadow
  12988. // 2. Image: sx, sy, sw, sh
  12989. var CMD$3 = PathProxy.CMD;
  12990. var arrayJoin = Array.prototype.join;
  12991. var NONE = 'none';
  12992. var mathRound = Math.round;
  12993. var mathSin$3 = Math.sin;
  12994. var mathCos$3 = Math.cos;
  12995. var PI$3 = Math.PI;
  12996. var PI2$4 = Math.PI * 2;
  12997. var degree = 180 / PI$3;
  12998. var EPSILON$3 = 1e-4;
  12999. function round4(val) {
  13000. return mathRound(val * 1e4) / 1e4;
  13001. }
  13002. function isAroundZero$1(val) {
  13003. return val < EPSILON$3 && val > -EPSILON$3;
  13004. }
  13005. function pathHasFill(style, isText) {
  13006. var fill = isText ? style.textFill : style.fill;
  13007. return fill != null && fill !== NONE;
  13008. }
  13009. function pathHasStroke(style, isText) {
  13010. var stroke = isText ? style.textStroke : style.stroke;
  13011. return stroke != null && stroke !== NONE;
  13012. }
  13013. function setTransform(svgEl, m) {
  13014. if (m) {
  13015. attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');
  13016. }
  13017. }
  13018. function attr(el, key, val) {
  13019. if (!val || val.type !== 'linear' && val.type !== 'radial') {
  13020. // Don't set attribute for gradient, since it need new dom nodes
  13021. el.setAttribute(key, val);
  13022. }
  13023. }
  13024. function attrXLink(el, key, val) {
  13025. el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);
  13026. }
  13027. function bindStyle(svgEl, style, isText) {
  13028. if (pathHasFill(style, isText)) {
  13029. var fill = isText ? style.textFill : style.fill;
  13030. fill = fill === 'transparent' ? NONE : fill;
  13031. /**
  13032. * FIXME:
  13033. * This is a temporary fix for Chrome's clipping bug
  13034. * that happens when a clip-path is referring another one.
  13035. * This fix should be used before Chrome's bug is fixed.
  13036. * For an element that has clip-path, and fill is none,
  13037. * set it to be "rgba(0, 0, 0, 0.002)" will hide the element.
  13038. * Otherwise, it will show black fill color.
  13039. * 0.002 is used because this won't work for alpha values smaller
  13040. * than 0.002.
  13041. *
  13042. * See
  13043. * https://bugs.chromium.org/p/chromium/issues/detail?id=659790
  13044. * for more information.
  13045. */
  13046. if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {
  13047. fill = 'rgba(0, 0, 0, 0.002)';
  13048. }
  13049. attr(svgEl, 'fill', fill);
  13050. attr(svgEl, 'fill-opacity', style.opacity);
  13051. }
  13052. else {
  13053. attr(svgEl, 'fill', NONE);
  13054. }
  13055. if (pathHasStroke(style, isText)) {
  13056. var stroke = isText ? style.textStroke : style.stroke;
  13057. stroke = stroke === 'transparent' ? NONE : stroke;
  13058. attr(svgEl, 'stroke', stroke);
  13059. var strokeWidth = isText
  13060. ? style.textStrokeWidth
  13061. : style.lineWidth;
  13062. var strokeScale = style.strokeNoScale
  13063. ? style.host.getLineScale()
  13064. : 1;
  13065. attr(svgEl, 'stroke-width', strokeWidth / strokeScale);
  13066. attr(svgEl, 'paint-order', 'stroke');
  13067. attr(svgEl, 'stroke-opacity', style.opacity);
  13068. var lineDash = style.lineDash;
  13069. if (lineDash) {
  13070. attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));
  13071. attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));
  13072. }
  13073. else {
  13074. attr(svgEl, 'stroke-dasharray', '');
  13075. }
  13076. // PENDING
  13077. style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);
  13078. style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);
  13079. style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);
  13080. }
  13081. else {
  13082. attr(svgEl, 'stroke', NONE);
  13083. }
  13084. }
  13085. /***************************************************
  13086. * PATH
  13087. **************************************************/
  13088. function pathDataToString(path) {
  13089. var str = [];
  13090. var data = path.data;
  13091. var dataLength = path.len();
  13092. for (var i = 0; i < dataLength;) {
  13093. var cmd = data[i++];
  13094. var cmdStr = '';
  13095. var nData = 0;
  13096. switch (cmd) {
  13097. case CMD$3.M:
  13098. cmdStr = 'M';
  13099. nData = 2;
  13100. break;
  13101. case CMD$3.L:
  13102. cmdStr = 'L';
  13103. nData = 2;
  13104. break;
  13105. case CMD$3.Q:
  13106. cmdStr = 'Q';
  13107. nData = 4;
  13108. break;
  13109. case CMD$3.C:
  13110. cmdStr = 'C';
  13111. nData = 6;
  13112. break;
  13113. case CMD$3.A:
  13114. var cx = data[i++];
  13115. var cy = data[i++];
  13116. var rx = data[i++];
  13117. var ry = data[i++];
  13118. var theta = data[i++];
  13119. var dTheta = data[i++];
  13120. var psi = data[i++];
  13121. var clockwise = data[i++];
  13122. var dThetaPositive = Math.abs(dTheta);
  13123. var isCircle = isAroundZero$1(dThetaPositive % PI2$4)
  13124. && !isAroundZero$1(dThetaPositive);
  13125. var large = false;
  13126. if (dThetaPositive >= PI2$4) {
  13127. large = true;
  13128. }
  13129. else if (isAroundZero$1(dThetaPositive)) {
  13130. large = false;
  13131. }
  13132. else {
  13133. large = (dTheta > -PI$3 && dTheta < 0 || dTheta > PI$3)
  13134. === !!clockwise;
  13135. }
  13136. var x0 = round4(cx + rx * mathCos$3(theta));
  13137. var y0 = round4(cy + ry * mathSin$3(theta));
  13138. // It will not draw if start point and end point are exactly the same
  13139. // We need to shift the end point with a small value
  13140. // FIXME A better way to draw circle ?
  13141. if (isCircle) {
  13142. if (clockwise) {
  13143. dTheta = PI2$4 - 1e-4;
  13144. }
  13145. else {
  13146. dTheta = -PI2$4 + 1e-4;
  13147. }
  13148. large = true;
  13149. if (i === 9) {
  13150. // Move to (x0, y0) only when CMD.A comes at the
  13151. // first position of a shape.
  13152. // For instance, when drawing a ring, CMD.A comes
  13153. // after CMD.M, so it's unnecessary to move to
  13154. // (x0, y0).
  13155. str.push('M', x0, y0);
  13156. }
  13157. }
  13158. var x = round4(cx + rx * mathCos$3(theta + dTheta));
  13159. var y = round4(cy + ry * mathSin$3(theta + dTheta));
  13160. // FIXME Ellipse
  13161. str.push('A', round4(rx), round4(ry),
  13162. mathRound(psi * degree), +large, +clockwise, x, y);
  13163. break;
  13164. case CMD$3.Z:
  13165. cmdStr = 'Z';
  13166. break;
  13167. case CMD$3.R:
  13168. var x = round4(data[i++]);
  13169. var y = round4(data[i++]);
  13170. var w = round4(data[i++]);
  13171. var h = round4(data[i++]);
  13172. str.push(
  13173. 'M', x, y,
  13174. 'L', x + w, y,
  13175. 'L', x + w, y + h,
  13176. 'L', x, y + h,
  13177. 'L', x, y
  13178. );
  13179. break;
  13180. }
  13181. cmdStr && str.push(cmdStr);
  13182. for (var j = 0; j < nData; j++) {
  13183. // PENDING With scale
  13184. str.push(round4(data[i++]));
  13185. }
  13186. }
  13187. return str.join(' ');
  13188. }
  13189. var svgPath = {};
  13190. svgPath.brush = function (el) {
  13191. var style = el.style;
  13192. var svgEl = el.__svgEl;
  13193. if (!svgEl) {
  13194. svgEl = createElement('path');
  13195. el.__svgEl = svgEl;
  13196. }
  13197. if (!el.path) {
  13198. el.createPathProxy();
  13199. }
  13200. var path = el.path;
  13201. if (el.__dirtyPath) {
  13202. path.beginPath();
  13203. el.buildPath(path, el.shape);
  13204. el.__dirtyPath = false;
  13205. var pathStr = pathDataToString(path);
  13206. if (pathStr.indexOf('NaN') < 0) {
  13207. // Ignore illegal path, which may happen such in out-of-range
  13208. // data in Calendar series.
  13209. attr(svgEl, 'd', pathStr);
  13210. }
  13211. }
  13212. bindStyle(svgEl, style);
  13213. setTransform(svgEl, el.transform);
  13214. if (style.text != null) {
  13215. svgTextDrawRectText(el, el.getBoundingRect());
  13216. }
  13217. };
  13218. /***************************************************
  13219. * IMAGE
  13220. **************************************************/
  13221. var svgImage = {};
  13222. svgImage.brush = function (el) {
  13223. var style = el.style;
  13224. var image = style.image;
  13225. if (image instanceof HTMLImageElement) {
  13226. var src = image.src;
  13227. image = src;
  13228. }
  13229. if (! image) {
  13230. return;
  13231. }
  13232. var x = style.x || 0;
  13233. var y = style.y || 0;
  13234. var dw = style.width;
  13235. var dh = style.height;
  13236. var svgEl = el.__svgEl;
  13237. if (! svgEl) {
  13238. svgEl = createElement('image');
  13239. el.__svgEl = svgEl;
  13240. }
  13241. if (image !== el.__imageSrc) {
  13242. attrXLink(svgEl, 'href', image);
  13243. // Caching image src
  13244. el.__imageSrc = image;
  13245. }
  13246. attr(svgEl, 'width', dw);
  13247. attr(svgEl, 'height', dh);
  13248. attr(svgEl, 'x', x);
  13249. attr(svgEl, 'y', y);
  13250. setTransform(svgEl, el.transform);
  13251. if (style.text != null) {
  13252. svgTextDrawRectText(el, el.getBoundingRect());
  13253. }
  13254. };
  13255. /***************************************************
  13256. * TEXT
  13257. **************************************************/
  13258. var svgText = {};
  13259. var tmpRect$2 = new BoundingRect();
  13260. var svgTextDrawRectText = function (el, rect, textRect) {
  13261. var style = el.style;
  13262. el.__dirty && normalizeTextStyle(style, true);
  13263. var text = style.text;
  13264. // Convert to string
  13265. if (text == null) {
  13266. // Draw no text only when text is set to null, but not ''
  13267. return;
  13268. }
  13269. else {
  13270. text += '';
  13271. }
  13272. var textSvgEl = el.__textSvgEl;
  13273. if (! textSvgEl) {
  13274. textSvgEl = createElement('text');
  13275. el.__textSvgEl = textSvgEl;
  13276. }
  13277. bindStyle(textSvgEl, style, true);
  13278. if (el instanceof Text || el.style.transformText) {
  13279. // Transform text with element
  13280. setTransform(textSvgEl, el.transform);
  13281. }
  13282. else {
  13283. if (el.transform) {
  13284. tmpRect$2.copy(rect);
  13285. tmpRect$2.applyTransform(el.transform);
  13286. rect = tmpRect$2;
  13287. }
  13288. else {
  13289. var pos = el.transformCoordToGlobal(rect.x, rect.y);
  13290. rect.x = pos[0];
  13291. rect.y = pos[1];
  13292. }
  13293. }
  13294. var x;
  13295. var y;
  13296. var textPosition = style.textPosition;
  13297. var distance = style.textDistance;
  13298. var align = style.textAlign || 'left';
  13299. if (typeof style.fontSize === 'number') {
  13300. style.fontSize += 'px';
  13301. }
  13302. var font = style.font
  13303. || [
  13304. style.fontStyle || '',
  13305. style.fontWeight || '',
  13306. style.fontSize || '',
  13307. style.fontFamily || ''
  13308. ].join(' ')
  13309. || DEFAULT_FONT;
  13310. var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);
  13311. textRect = getBoundingRect(text, font, align,
  13312. verticalAlign);
  13313. var lineHeight = textRect.lineHeight;
  13314. // Text position represented by coord
  13315. if (textPosition instanceof Array) {
  13316. x = rect.x + textPosition[0];
  13317. y = rect.y + textPosition[1];
  13318. }
  13319. else {
  13320. var newPos = adjustTextPositionOnRect(
  13321. textPosition, rect, distance
  13322. );
  13323. x = newPos.x;
  13324. y = newPos.y;
  13325. verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);
  13326. align = newPos.textAlign;
  13327. }
  13328. attr(textSvgEl, 'alignment-baseline', verticalAlign);
  13329. if (font) {
  13330. textSvgEl.style.font = font;
  13331. }
  13332. var textPadding = style.textPadding;
  13333. // Make baseline top
  13334. attr(textSvgEl, 'x', x);
  13335. attr(textSvgEl, 'y', y);
  13336. var textLines = text.split('\n');
  13337. var nTextLines = textLines.length;
  13338. var textAnchor = align;
  13339. // PENDING
  13340. if (textAnchor === 'left') {
  13341. textAnchor = 'start';
  13342. textPadding && (x += textPadding[3]);
  13343. }
  13344. else if (textAnchor === 'right') {
  13345. textAnchor = 'end';
  13346. textPadding && (x -= textPadding[1]);
  13347. }
  13348. else if (textAnchor === 'center') {
  13349. textAnchor = 'middle';
  13350. textPadding && (x += (textPadding[3] - textPadding[1]) / 2);
  13351. }
  13352. var dy = 0;
  13353. if (verticalAlign === 'baseline') {
  13354. dy = -textRect.height + lineHeight;
  13355. textPadding && (dy -= textPadding[2]);
  13356. }
  13357. else if (verticalAlign === 'middle') {
  13358. dy = (-textRect.height + lineHeight) / 2;
  13359. textPadding && (y += (textPadding[0] - textPadding[2]) / 2);
  13360. }
  13361. else {
  13362. textPadding && (dy += textPadding[0]);
  13363. }
  13364. // Font may affect position of each tspan elements
  13365. if (el.__text !== text || el.__textFont !== font) {
  13366. var tspanList = el.__tspanList || [];
  13367. el.__tspanList = tspanList;
  13368. for (var i = 0; i < nTextLines; i++) {
  13369. // Using cached tspan elements
  13370. var tspan = tspanList[i];
  13371. if (! tspan) {
  13372. tspan = tspanList[i] = createElement('tspan');
  13373. textSvgEl.appendChild(tspan);
  13374. attr(tspan, 'alignment-baseline', verticalAlign);
  13375. attr(tspan, 'text-anchor', textAnchor);
  13376. }
  13377. else {
  13378. tspan.innerHTML = '';
  13379. }
  13380. attr(tspan, 'x', x);
  13381. attr(tspan, 'y', y + i * lineHeight + dy);
  13382. tspan.appendChild(document.createTextNode(textLines[i]));
  13383. }
  13384. // Remove unsed tspan elements
  13385. for (; i < tspanList.length; i++) {
  13386. textSvgEl.removeChild(tspanList[i]);
  13387. }
  13388. tspanList.length = nTextLines;
  13389. el.__text = text;
  13390. el.__textFont = font;
  13391. }
  13392. else if (el.__tspanList.length) {
  13393. // Update span x and y
  13394. var len = el.__tspanList.length;
  13395. for (var i = 0; i < len; ++i) {
  13396. var tspan = el.__tspanList[i];
  13397. if (tspan) {
  13398. attr(tspan, 'x', x);
  13399. attr(tspan, 'y', y + i * lineHeight + dy);
  13400. }
  13401. }
  13402. }
  13403. };
  13404. function getVerticalAlignForSvg(verticalAlign) {
  13405. if (verticalAlign === 'middle') {
  13406. return 'middle';
  13407. }
  13408. else if (verticalAlign === 'bottom') {
  13409. return 'baseline';
  13410. }
  13411. else {
  13412. return 'hanging';
  13413. }
  13414. }
  13415. svgText.drawRectText = svgTextDrawRectText;
  13416. svgText.brush = function (el) {
  13417. var style = el.style;
  13418. if (style.text != null) {
  13419. // 强制设置 textPosition
  13420. style.textPosition = [0, 0];
  13421. svgTextDrawRectText(el, {
  13422. x: style.x || 0, y: style.y || 0,
  13423. width: 0, height: 0
  13424. }, el.getBoundingRect());
  13425. }
  13426. };
  13427. // Myers' Diff Algorithm
  13428. // Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js
  13429. function Diff() {}
  13430. Diff.prototype = {
  13431. diff: function (oldArr, newArr, equals) {
  13432. if (!equals) {
  13433. equals = function (a, b) {
  13434. return a === b;
  13435. };
  13436. }
  13437. this.equals = equals;
  13438. var self = this;
  13439. oldArr = oldArr.slice();
  13440. newArr = newArr.slice();
  13441. // Allow subclasses to massage the input prior to running
  13442. var newLen = newArr.length;
  13443. var oldLen = oldArr.length;
  13444. var editLength = 1;
  13445. var maxEditLength = newLen + oldLen;
  13446. var bestPath = [{ newPos: -1, components: [] }];
  13447. // Seed editLength = 0, i.e. the content starts with the same values
  13448. var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);
  13449. if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {
  13450. var indices = [];
  13451. for (var i = 0; i < newArr.length; i++) {
  13452. indices.push(i);
  13453. }
  13454. // Identity per the equality and tokenizer
  13455. return [{
  13456. indices: indices, count: newArr.length
  13457. }];
  13458. }
  13459. // Main worker method. checks all permutations of a given edit length for acceptance.
  13460. function execEditLength() {
  13461. for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {
  13462. var basePath;
  13463. var addPath = bestPath[diagonalPath - 1];
  13464. var removePath = bestPath[diagonalPath + 1];
  13465. var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
  13466. if (addPath) {
  13467. // No one else is going to attempt to use this value, clear it
  13468. bestPath[diagonalPath - 1] = undefined;
  13469. }
  13470. var canAdd = addPath && addPath.newPos + 1 < newLen;
  13471. var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
  13472. if (!canAdd && !canRemove) {
  13473. // If this path is a terminal then prune
  13474. bestPath[diagonalPath] = undefined;
  13475. continue;
  13476. }
  13477. // Select the diagonal that we want to branch from. We select the prior
  13478. // path whose position in the new string is the farthest from the origin
  13479. // and does not pass the bounds of the diff graph
  13480. if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
  13481. basePath = clonePath(removePath);
  13482. self.pushComponent(basePath.components, undefined, true);
  13483. }
  13484. else {
  13485. basePath = addPath; // No need to clone, we've pulled it from the list
  13486. basePath.newPos++;
  13487. self.pushComponent(basePath.components, true, undefined);
  13488. }
  13489. oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);
  13490. // If we have hit the end of both strings, then we are done
  13491. if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {
  13492. return buildValues(self, basePath.components, newArr, oldArr);
  13493. }
  13494. else {
  13495. // Otherwise track this path as a potential candidate and continue.
  13496. bestPath[diagonalPath] = basePath;
  13497. }
  13498. }
  13499. editLength++;
  13500. }
  13501. while (editLength <= maxEditLength) {
  13502. var ret = execEditLength();
  13503. if (ret) {
  13504. return ret;
  13505. }
  13506. }
  13507. },
  13508. pushComponent: function (components, added, removed) {
  13509. var last = components[components.length - 1];
  13510. if (last && last.added === added && last.removed === removed) {
  13511. // We need to clone here as the component clone operation is just
  13512. // as shallow array clone
  13513. components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };
  13514. }
  13515. else {
  13516. components.push({count: 1, added: added, removed: removed });
  13517. }
  13518. },
  13519. extractCommon: function (basePath, newArr, oldArr, diagonalPath) {
  13520. var newLen = newArr.length;
  13521. var oldLen = oldArr.length;
  13522. var newPos = basePath.newPos;
  13523. var oldPos = newPos - diagonalPath;
  13524. var commonCount = 0;
  13525. while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {
  13526. newPos++;
  13527. oldPos++;
  13528. commonCount++;
  13529. }
  13530. if (commonCount) {
  13531. basePath.components.push({count: commonCount});
  13532. }
  13533. basePath.newPos = newPos;
  13534. return oldPos;
  13535. },
  13536. tokenize: function (value) {
  13537. return value.slice();
  13538. },
  13539. join: function (value) {
  13540. return value.slice();
  13541. }
  13542. };
  13543. function buildValues(diff, components, newArr, oldArr) {
  13544. var componentPos = 0;
  13545. var componentLen = components.length;
  13546. var newPos = 0;
  13547. var oldPos = 0;
  13548. for (; componentPos < componentLen; componentPos++) {
  13549. var component = components[componentPos];
  13550. if (!component.removed) {
  13551. var indices = [];
  13552. for (var i = newPos; i < newPos + component.count; i++) {
  13553. indices.push(i);
  13554. }
  13555. component.indices = indices;
  13556. newPos += component.count;
  13557. // Common case
  13558. if (!component.added) {
  13559. oldPos += component.count;
  13560. }
  13561. }
  13562. else {
  13563. var indices = [];
  13564. for (var i = oldPos; i < oldPos + component.count; i++) {
  13565. indices.push(i);
  13566. }
  13567. component.indices = indices;
  13568. oldPos += component.count;
  13569. }
  13570. }
  13571. return components;
  13572. }
  13573. function clonePath(path) {
  13574. return { newPos: path.newPos, components: path.components.slice(0) };
  13575. }
  13576. var arrayDiff = new Diff();
  13577. var arrayDiff$1 = function (oldArr, newArr, callback) {
  13578. return arrayDiff.diff(oldArr, newArr, callback);
  13579. };
  13580. /**
  13581. * @file Manages elements that can be defined in <defs> in SVG,
  13582. * e.g., gradients, clip path, etc.
  13583. * @author Zhang Wenli
  13584. */
  13585. var MARK_UNUSED = '0';
  13586. var MARK_USED = '1';
  13587. /**
  13588. * Manages elements that can be defined in <defs> in SVG,
  13589. * e.g., gradients, clip path, etc.
  13590. *
  13591. * @class
  13592. * @param {SVGElement} svgRoot root of SVG document
  13593. * @param {string|string[]} tagNames possible tag names
  13594. * @param {string} markLabel label name to make if the element
  13595. * is used
  13596. */
  13597. function Definable(
  13598. svgRoot,
  13599. tagNames,
  13600. markLabel
  13601. ) {
  13602. this._svgRoot = svgRoot;
  13603. this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;
  13604. this._markLabel = markLabel;
  13605. this.nextId = 0;
  13606. }
  13607. Definable.prototype.createElement = createElement;
  13608. /**
  13609. * Get the <defs> tag for svgRoot; optionally creates one if not exists.
  13610. *
  13611. * @param {boolean} isForceCreating if need to create when not exists
  13612. * @return {SVGDefsElement} SVG <defs> element, null if it doesn't
  13613. * exist and isForceCreating is false
  13614. */
  13615. Definable.prototype.getDefs = function (isForceCreating) {
  13616. var svgRoot = this._svgRoot;
  13617. var defs = this._svgRoot.getElementsByTagName('defs');
  13618. if (defs.length === 0) {
  13619. // Not exist
  13620. if (isForceCreating) {
  13621. defs = svgRoot.insertBefore(
  13622. this.createElement('defs'), // Create new tag
  13623. svgRoot.firstChild // Insert in the front of svg
  13624. );
  13625. if (!defs.contains) {
  13626. // IE doesn't support contains method
  13627. defs.contains = function (el) {
  13628. var children = defs.children;
  13629. if (!children) {
  13630. return false;
  13631. }
  13632. for (var i = children.length - 1; i >= 0; --i) {
  13633. if (children[i] === el) {
  13634. return true;
  13635. }
  13636. }
  13637. return false;
  13638. };
  13639. }
  13640. return defs;
  13641. }
  13642. else {
  13643. return null;
  13644. }
  13645. }
  13646. else {
  13647. return defs[0];
  13648. }
  13649. };
  13650. /**
  13651. * Update DOM element if necessary.
  13652. *
  13653. * @param {Object|string} element style element. e.g., for gradient,
  13654. * it may be '#ccc' or {type: 'linear', ...}
  13655. * @param {Function|undefined} onUpdate update callback
  13656. */
  13657. Definable.prototype.update = function (element, onUpdate) {
  13658. if (!element) {
  13659. return;
  13660. }
  13661. var defs = this.getDefs(false);
  13662. if (element._dom && defs.contains(element._dom)) {
  13663. // Update DOM
  13664. if (typeof onUpdate === 'function') {
  13665. onUpdate();
  13666. }
  13667. }
  13668. else {
  13669. // No previous dom, create new
  13670. var dom = this.add(element);
  13671. if (dom) {
  13672. element._dom = dom;
  13673. }
  13674. }
  13675. };
  13676. /**
  13677. * Add gradient dom to defs
  13678. *
  13679. * @param {SVGElement} dom DOM to be added to <defs>
  13680. */
  13681. Definable.prototype.addDom = function (dom) {
  13682. var defs = this.getDefs(true);
  13683. defs.appendChild(dom);
  13684. };
  13685. /**
  13686. * Remove DOM of a given element.
  13687. *
  13688. * @param {SVGElement} element element to remove dom
  13689. */
  13690. Definable.prototype.removeDom = function (element) {
  13691. var defs = this.getDefs(false);
  13692. defs.removeChild(element._dom);
  13693. };
  13694. /**
  13695. * Get DOMs of this element.
  13696. *
  13697. * @return {HTMLDomElement} doms of this defineable elements in <defs>
  13698. */
  13699. Definable.prototype.getDoms = function () {
  13700. var defs = this.getDefs(false);
  13701. if (!defs) {
  13702. // No dom when defs is not defined
  13703. return [];
  13704. }
  13705. var doms = [];
  13706. each(this._tagNames, function (tagName) {
  13707. var tags = defs.getElementsByTagName(tagName);
  13708. // Note that tags is HTMLCollection, which is array-like
  13709. // rather than real array.
  13710. // So `doms.concat(tags)` add tags as one object.
  13711. doms = doms.concat([].slice.call(tags));
  13712. });
  13713. return doms;
  13714. };
  13715. /**
  13716. * Mark DOMs to be unused before painting, and clear unused ones at the end
  13717. * of the painting.
  13718. */
  13719. Definable.prototype.markAllUnused = function () {
  13720. var doms = this.getDoms();
  13721. var that = this;
  13722. each(doms, function (dom) {
  13723. dom[that._markLabel] = MARK_UNUSED;
  13724. });
  13725. };
  13726. /**
  13727. * Mark a single DOM to be used.
  13728. *
  13729. * @param {SVGElement} dom DOM to mark
  13730. */
  13731. Definable.prototype.markUsed = function (dom) {
  13732. if (dom) {
  13733. dom[this._markLabel] = MARK_USED;
  13734. }
  13735. };
  13736. /**
  13737. * Remove unused DOMs defined in <defs>
  13738. */
  13739. Definable.prototype.removeUnused = function () {
  13740. var defs = this.getDefs(false);
  13741. if (!defs) {
  13742. // Nothing to remove
  13743. return;
  13744. }
  13745. var doms = this.getDoms();
  13746. var that = this;
  13747. each(doms, function (dom) {
  13748. if (dom[that._markLabel] !== MARK_USED) {
  13749. // Remove gradient
  13750. defs.removeChild(dom);
  13751. }
  13752. });
  13753. };
  13754. /**
  13755. * Get SVG proxy.
  13756. *
  13757. * @param {Displayable} displayable displayable element
  13758. * @return {Path|Image|Text} svg proxy of given element
  13759. */
  13760. Definable.prototype.getSvgProxy = function (displayable) {
  13761. if (displayable instanceof Path) {
  13762. return svgPath;
  13763. }
  13764. else if (displayable instanceof ZImage) {
  13765. return svgImage;
  13766. }
  13767. else if (displayable instanceof Text) {
  13768. return svgText;
  13769. }
  13770. else {
  13771. return svgPath;
  13772. }
  13773. };
  13774. /**
  13775. * Get text SVG element.
  13776. *
  13777. * @param {Displayable} displayable displayable element
  13778. * @return {SVGElement} SVG element of text
  13779. */
  13780. Definable.prototype.getTextSvgElement = function (displayable) {
  13781. return displayable.__textSvgEl;
  13782. };
  13783. /**
  13784. * Get SVG element.
  13785. *
  13786. * @param {Displayable} displayable displayable element
  13787. * @return {SVGElement} SVG element
  13788. */
  13789. Definable.prototype.getSvgElement = function (displayable) {
  13790. return displayable.__svgEl;
  13791. };
  13792. /**
  13793. * @file Manages SVG gradient elements.
  13794. * @author Zhang Wenli
  13795. */
  13796. /**
  13797. * Manages SVG gradient elements.
  13798. *
  13799. * @class
  13800. * @extends Definable
  13801. * @param {SVGElement} svgRoot root of SVG document
  13802. */
  13803. function GradientManager(svgRoot) {
  13804. Definable.call(
  13805. this,
  13806. svgRoot,
  13807. ['linearGradient', 'radialGradient'],
  13808. '__gradient_in_use__'
  13809. );
  13810. }
  13811. inherits(GradientManager, Definable);
  13812. /**
  13813. * Create new gradient DOM for fill or stroke if not exist,
  13814. * but will not update gradient if exists.
  13815. *
  13816. * @param {SvgElement} svgElement SVG element to paint
  13817. * @param {Displayable} displayable zrender displayable element
  13818. */
  13819. GradientManager.prototype.addWithoutUpdate = function (
  13820. svgElement,
  13821. displayable
  13822. ) {
  13823. if (displayable && displayable.style) {
  13824. var that = this;
  13825. each(['fill', 'stroke'], function (fillOrStroke) {
  13826. if (displayable.style[fillOrStroke]
  13827. && (displayable.style[fillOrStroke].type === 'linear'
  13828. || displayable.style[fillOrStroke].type === 'radial')
  13829. ) {
  13830. var gradient = displayable.style[fillOrStroke];
  13831. var defs = that.getDefs(true);
  13832. // Create dom in <defs> if not exists
  13833. var dom;
  13834. if (gradient._dom) {
  13835. // Gradient exists
  13836. dom = gradient._dom;
  13837. if (!defs.contains(gradient._dom)) {
  13838. // _dom is no longer in defs, recreate
  13839. that.addDom(dom);
  13840. }
  13841. }
  13842. else {
  13843. // New dom
  13844. dom = that.add(gradient);
  13845. }
  13846. that.markUsed(displayable);
  13847. var id = dom.getAttribute('id');
  13848. svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');
  13849. }
  13850. });
  13851. }
  13852. };
  13853. /**
  13854. * Add a new gradient tag in <defs>
  13855. *
  13856. * @param {Gradient} gradient zr gradient instance
  13857. * @return {SVGLinearGradientElement | SVGRadialGradientElement}
  13858. * created DOM
  13859. */
  13860. GradientManager.prototype.add = function (gradient) {
  13861. var dom;
  13862. if (gradient.type === 'linear') {
  13863. dom = this.createElement('linearGradient');
  13864. }
  13865. else if (gradient.type === 'radial') {
  13866. dom = this.createElement('radialGradient');
  13867. }
  13868. else {
  13869. zrLog('Illegal gradient type.');
  13870. return null;
  13871. }
  13872. // Set dom id with gradient id, since each gradient instance
  13873. // will have no more than one dom element.
  13874. // id may exists before for those dirty elements, in which case
  13875. // id should remain the same, and other attributes should be
  13876. // updated.
  13877. gradient.id = gradient.id || this.nextId++;
  13878. dom.setAttribute('id', 'zr-gradient-' + gradient.id);
  13879. this.updateDom(gradient, dom);
  13880. this.addDom(dom);
  13881. return dom;
  13882. };
  13883. /**
  13884. * Update gradient.
  13885. *
  13886. * @param {Gradient} gradient zr gradient instance
  13887. */
  13888. GradientManager.prototype.update = function (gradient) {
  13889. var that = this;
  13890. Definable.prototype.update.call(this, gradient, function () {
  13891. var type = gradient.type;
  13892. var tagName = gradient._dom.tagName;
  13893. if (type === 'linear' && tagName === 'linearGradient'
  13894. || type === 'radial' && tagName === 'radialGradient'
  13895. ) {
  13896. // Gradient type is not changed, update gradient
  13897. that.updateDom(gradient, gradient._dom);
  13898. }
  13899. else {
  13900. // Remove and re-create if type is changed
  13901. that.removeDom(gradient);
  13902. that.add(gradient);
  13903. }
  13904. });
  13905. };
  13906. /**
  13907. * Update gradient dom
  13908. *
  13909. * @param {Gradient} gradient zr gradient instance
  13910. * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom
  13911. * DOM to update
  13912. */
  13913. GradientManager.prototype.updateDom = function (gradient, dom) {
  13914. if (gradient.type === 'linear') {
  13915. dom.setAttribute('x1', gradient.x);
  13916. dom.setAttribute('y1', gradient.y);
  13917. dom.setAttribute('x2', gradient.x2);
  13918. dom.setAttribute('y2', gradient.y2);
  13919. }
  13920. else if (gradient.type === 'radial') {
  13921. dom.setAttribute('cx', gradient.x);
  13922. dom.setAttribute('cy', gradient.y);
  13923. dom.setAttribute('r', gradient.r);
  13924. }
  13925. else {
  13926. zrLog('Illegal gradient type.');
  13927. return;
  13928. }
  13929. if (gradient.global) {
  13930. // x1, x2, y1, y2 in range of 0 to canvas width or height
  13931. dom.setAttribute('gradientUnits', 'userSpaceOnUse');
  13932. }
  13933. else {
  13934. // x1, x2, y1, y2 in range of 0 to 1
  13935. dom.setAttribute('gradientUnits', 'objectBoundingBox');
  13936. }
  13937. // Remove color stops if exists
  13938. dom.innerHTML = '';
  13939. // Add color stops
  13940. var colors = gradient.colorStops;
  13941. for (var i = 0, len = colors.length; i < len; ++i) {
  13942. var stop = this.createElement('stop');
  13943. stop.setAttribute('offset', colors[i].offset * 100 + '%');
  13944. stop.setAttribute('stop-color', colors[i].color);
  13945. dom.appendChild(stop);
  13946. }
  13947. // Store dom element in gradient, to avoid creating multiple
  13948. // dom instances for the same gradient element
  13949. gradient._dom = dom;
  13950. };
  13951. /**
  13952. * Mark a single gradient to be used
  13953. *
  13954. * @param {Displayable} displayable displayable element
  13955. */
  13956. GradientManager.prototype.markUsed = function (displayable) {
  13957. if (displayable.style) {
  13958. var gradient = displayable.style.fill;
  13959. if (gradient && gradient._dom) {
  13960. Definable.prototype.markUsed.call(this, gradient._dom);
  13961. }
  13962. gradient = displayable.style.stroke;
  13963. if (gradient && gradient._dom) {
  13964. Definable.prototype.markUsed.call(this, gradient._dom);
  13965. }
  13966. }
  13967. };
  13968. /**
  13969. * @file Manages SVG clipPath elements.
  13970. * @author Zhang Wenli
  13971. */
  13972. /**
  13973. * Manages SVG clipPath elements.
  13974. *
  13975. * @class
  13976. * @extends Definable
  13977. * @param {SVGElement} svgRoot root of SVG document
  13978. */
  13979. function ClippathManager(svgRoot) {
  13980. Definable.call(this, svgRoot, 'clipPath', '__clippath_in_use__');
  13981. }
  13982. inherits(ClippathManager, Definable);
  13983. /**
  13984. * Update clipPath.
  13985. *
  13986. * @param {Displayable} displayable displayable element
  13987. */
  13988. ClippathManager.prototype.update = function (displayable) {
  13989. var svgEl = this.getSvgElement(displayable);
  13990. if (svgEl) {
  13991. this.updateDom(svgEl, displayable.__clipPaths, false);
  13992. }
  13993. var textEl = this.getTextSvgElement(displayable);
  13994. if (textEl) {
  13995. // Make another clipPath for text, since it's transform
  13996. // matrix is not the same with svgElement
  13997. this.updateDom(textEl, displayable.__clipPaths, true);
  13998. }
  13999. this.markUsed(displayable);
  14000. };
  14001. /**
  14002. * Create an SVGElement of displayable and create a <clipPath> of its
  14003. * clipPath
  14004. *
  14005. * @param {Displayable} parentEl parent element
  14006. * @param {ClipPath[]} clipPaths clipPaths of parent element
  14007. * @param {boolean} isText if parent element is Text
  14008. */
  14009. ClippathManager.prototype.updateDom = function (
  14010. parentEl,
  14011. clipPaths,
  14012. isText
  14013. ) {
  14014. if (clipPaths && clipPaths.length > 0) {
  14015. // Has clipPath, create <clipPath> with the first clipPath
  14016. var defs = this.getDefs(true);
  14017. var clipPath = clipPaths[0];
  14018. var clipPathEl;
  14019. var id;
  14020. var dom = isText ? '_textDom' : '_dom';
  14021. if (clipPath[dom]) {
  14022. // Use a dom that is already in <defs>
  14023. id = clipPath[dom].getAttribute('id');
  14024. clipPathEl = clipPath[dom];
  14025. // Use a dom that is already in <defs>
  14026. if (!defs.contains(clipPathEl)) {
  14027. // This happens when set old clipPath that has
  14028. // been previously removed
  14029. defs.appendChild(clipPathEl);
  14030. }
  14031. }
  14032. else {
  14033. // New <clipPath>
  14034. id = 'zr-clip-' + this.nextId;
  14035. ++this.nextId;
  14036. clipPathEl = this.createElement('clipPath');
  14037. clipPathEl.setAttribute('id', id);
  14038. defs.appendChild(clipPathEl);
  14039. clipPath[dom] = clipPathEl;
  14040. }
  14041. // Build path and add to <clipPath>
  14042. var svgProxy = this.getSvgProxy(clipPath);
  14043. if (clipPath.transform
  14044. && clipPath.parent.invTransform
  14045. && !isText
  14046. ) {
  14047. /**
  14048. * If a clipPath has a parent with transform, the transform
  14049. * of parent should not be considered when setting transform
  14050. * of clipPath. So we need to transform back from parent's
  14051. * transform, which is done by multiplying parent's inverse
  14052. * transform.
  14053. */
  14054. // Store old transform
  14055. var transform = Array.prototype.slice.call(
  14056. clipPath.transform
  14057. );
  14058. // Transform back from parent, and brush path
  14059. mul$1(
  14060. clipPath.transform,
  14061. clipPath.parent.invTransform,
  14062. clipPath.transform
  14063. );
  14064. svgProxy.brush(clipPath);
  14065. // Set back transform of clipPath
  14066. clipPath.transform = transform;
  14067. }
  14068. else {
  14069. svgProxy.brush(clipPath);
  14070. }
  14071. var pathEl = this.getSvgElement(clipPath);
  14072. /**
  14073. * Use `cloneNode()` here to appendChild to multiple parents,
  14074. * which may happend when Text and other shapes are using the same
  14075. * clipPath. Since Text will create an extra clipPath DOM due to
  14076. * different transform rules.
  14077. */
  14078. clipPathEl.appendChild(pathEl.cloneNode());
  14079. parentEl.setAttribute('clip-path', 'url(#' + id + ')');
  14080. if (clipPaths.length > 1) {
  14081. // Make the other clipPaths recursively
  14082. this.updateDom(clipPathEl, clipPaths.slice(1), isText);
  14083. }
  14084. }
  14085. else {
  14086. // No clipPath
  14087. if (parentEl) {
  14088. parentEl.setAttribute('clip-path', 'none');
  14089. }
  14090. }
  14091. };
  14092. /**
  14093. * Mark a single clipPath to be used
  14094. *
  14095. * @param {Displayable} displayable displayable element
  14096. */
  14097. ClippathManager.prototype.markUsed = function (displayable) {
  14098. var that = this;
  14099. if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {
  14100. each(displayable.__clipPaths, function (clipPath) {
  14101. if (clipPath._dom) {
  14102. Definable.prototype.markUsed.call(that, clipPath._dom);
  14103. }
  14104. if (clipPath._textDom) {
  14105. Definable.prototype.markUsed.call(that, clipPath._textDom);
  14106. }
  14107. });
  14108. }
  14109. };
  14110. /**
  14111. * SVG Painter
  14112. * @module zrender/svg/Painter
  14113. */
  14114. function parseInt10$1(val) {
  14115. return parseInt(val, 10);
  14116. }
  14117. function getSvgProxy(el) {
  14118. if (el instanceof Path) {
  14119. return svgPath;
  14120. }
  14121. else if (el instanceof ZImage) {
  14122. return svgImage;
  14123. }
  14124. else if (el instanceof Text) {
  14125. return svgText;
  14126. }
  14127. else {
  14128. return svgPath;
  14129. }
  14130. }
  14131. function checkParentAvailable(parent, child) {
  14132. return child && parent && child.parentNode !== parent;
  14133. }
  14134. function insertAfter(parent, child, prevSibling) {
  14135. if (checkParentAvailable(parent, child) && prevSibling) {
  14136. var nextSibling = prevSibling.nextSibling;
  14137. nextSibling ? parent.insertBefore(child, nextSibling)
  14138. : parent.appendChild(child);
  14139. }
  14140. }
  14141. function prepend(parent, child) {
  14142. if (checkParentAvailable(parent, child)) {
  14143. var firstChild = parent.firstChild;
  14144. firstChild ? parent.insertBefore(child, firstChild)
  14145. : parent.appendChild(child);
  14146. }
  14147. }
  14148. function remove(parent, child) {
  14149. if (child && parent && child.parentNode === parent) {
  14150. parent.removeChild(child);
  14151. }
  14152. }
  14153. function getTextSvgElement(displayable) {
  14154. return displayable.__textSvgEl;
  14155. }
  14156. function getSvgElement(displayable) {
  14157. return displayable.__svgEl;
  14158. }
  14159. /**
  14160. * @alias module:zrender/svg/Painter
  14161. * @constructor
  14162. * @param {HTMLElement} root 绘图容器
  14163. * @param {module:zrender/Storage} storage
  14164. * @param {Object} opts
  14165. */
  14166. var SVGPainter = function (root, storage, opts) {
  14167. this.root = root;
  14168. this.storage = storage;
  14169. this._opts = opts = extend({}, opts || {});
  14170. var svgRoot = createElement('svg');
  14171. svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  14172. svgRoot.setAttribute('version', '1.1');
  14173. svgRoot.setAttribute('baseProfile', 'full');
  14174. svgRoot.style['user-select'] = 'none';
  14175. svgRoot.style.cssText = 'position:absolute;left:0;top:0;';
  14176. this.gradientManager = new GradientManager(svgRoot);
  14177. this.clipPathManager = new ClippathManager(svgRoot);
  14178. var viewport = document.createElement('div');
  14179. viewport.style.cssText = 'overflow:hidden;position:relative';
  14180. this._svgRoot = svgRoot;
  14181. this._viewport = viewport;
  14182. root.appendChild(viewport);
  14183. viewport.appendChild(svgRoot);
  14184. this.resize(opts.width, opts.height);
  14185. this._visibleList = [];
  14186. };
  14187. SVGPainter.prototype = {
  14188. constructor: SVGPainter,
  14189. getType: function () {
  14190. return 'svg';
  14191. },
  14192. getViewportRoot: function () {
  14193. return this._viewport;
  14194. },
  14195. getViewportRootOffset: function () {
  14196. var viewportRoot = this.getViewportRoot();
  14197. if (viewportRoot) {
  14198. return {
  14199. offsetLeft: viewportRoot.offsetLeft || 0,
  14200. offsetTop: viewportRoot.offsetTop || 0
  14201. };
  14202. }
  14203. },
  14204. refresh: function () {
  14205. var list = this.storage.getDisplayList(true);
  14206. this._paintList(list);
  14207. },
  14208. _paintList: function (list) {
  14209. this.gradientManager.markAllUnused();
  14210. this.clipPathManager.markAllUnused();
  14211. var svgRoot = this._svgRoot;
  14212. var visibleList = this._visibleList;
  14213. var listLen = list.length;
  14214. var newVisibleList = [];
  14215. var i;
  14216. for (i = 0; i < listLen; i++) {
  14217. var displayable = list[i];
  14218. var svgProxy = getSvgProxy(displayable);
  14219. if (!displayable.invisible) {
  14220. if (displayable.__dirty) {
  14221. svgProxy && svgProxy.brush(displayable);
  14222. // Update clipPath
  14223. this.clipPathManager.update(displayable);
  14224. // Update gradient
  14225. if (displayable.style) {
  14226. this.gradientManager
  14227. .update(displayable.style.fill);
  14228. this.gradientManager
  14229. .update(displayable.style.stroke);
  14230. }
  14231. displayable.__dirty = false;
  14232. }
  14233. newVisibleList.push(displayable);
  14234. }
  14235. }
  14236. var diff = arrayDiff$1(visibleList, newVisibleList);
  14237. var prevSvgElement;
  14238. // First do remove, in case element moved to the head and do remove
  14239. // after add
  14240. for (i = 0; i < diff.length; i++) {
  14241. var item = diff[i];
  14242. if (item.removed) {
  14243. for (var k = 0; k < item.count; k++) {
  14244. var displayable = visibleList[item.indices[k]];
  14245. var svgElement = getSvgElement(displayable);
  14246. var textSvgElement = getTextSvgElement(displayable);
  14247. remove(svgRoot, svgElement);
  14248. remove(svgRoot, textSvgElement);
  14249. }
  14250. }
  14251. }
  14252. for (i = 0; i < diff.length; i++) {
  14253. var item = diff[i];
  14254. if (item.added) {
  14255. for (var k = 0; k < item.count; k++) {
  14256. var displayable = newVisibleList[item.indices[k]];
  14257. var svgElement = getSvgElement(displayable);
  14258. var textSvgElement = getTextSvgElement(displayable);
  14259. prevSvgElement
  14260. ? insertAfter(svgRoot, svgElement, prevSvgElement)
  14261. : prepend(svgRoot, svgElement);
  14262. if (svgElement) {
  14263. insertAfter(svgRoot, textSvgElement, svgElement);
  14264. }
  14265. else if (prevSvgElement) {
  14266. insertAfter(
  14267. svgRoot, textSvgElement, prevSvgElement
  14268. );
  14269. }
  14270. else {
  14271. prepend(svgRoot, textSvgElement);
  14272. }
  14273. // Insert text
  14274. insertAfter(svgRoot, textSvgElement, svgElement);
  14275. prevSvgElement = textSvgElement || svgElement
  14276. || prevSvgElement;
  14277. this.gradientManager
  14278. .addWithoutUpdate(svgElement, displayable);
  14279. this.clipPathManager.markUsed(displayable);
  14280. }
  14281. }
  14282. else if (!item.removed) {
  14283. for (var k = 0; k < item.count; k++) {
  14284. var displayable = newVisibleList[item.indices[k]];
  14285. prevSvgElement
  14286. = svgElement
  14287. = getTextSvgElement(displayable)
  14288. || getSvgElement(displayable)
  14289. || prevSvgElement;
  14290. this.gradientManager.markUsed(displayable);
  14291. this.gradientManager
  14292. .addWithoutUpdate(svgElement, displayable);
  14293. this.clipPathManager.markUsed(displayable);
  14294. }
  14295. }
  14296. }
  14297. this.gradientManager.removeUnused();
  14298. this.clipPathManager.removeUnused();
  14299. this._visibleList = newVisibleList;
  14300. },
  14301. _getDefs: function (isForceCreating) {
  14302. var svgRoot = this._svgRoot;
  14303. var defs = this._svgRoot.getElementsByTagName('defs');
  14304. if (defs.length === 0) {
  14305. // Not exist
  14306. if (isForceCreating) {
  14307. var defs = svgRoot.insertBefore(
  14308. createElement('defs'), // Create new tag
  14309. svgRoot.firstChild // Insert in the front of svg
  14310. );
  14311. if (!defs.contains) {
  14312. // IE doesn't support contains method
  14313. defs.contains = function (el) {
  14314. var children = defs.children;
  14315. if (!children) {
  14316. return false;
  14317. }
  14318. for (var i = children.length - 1; i >= 0; --i) {
  14319. if (children[i] === el) {
  14320. return true;
  14321. }
  14322. }
  14323. return false;
  14324. };
  14325. }
  14326. return defs;
  14327. }
  14328. else {
  14329. return null;
  14330. }
  14331. }
  14332. else {
  14333. return defs[0];
  14334. }
  14335. },
  14336. resize: function (width, height) {
  14337. var viewport = this._viewport;
  14338. // FIXME Why ?
  14339. viewport.style.display = 'none';
  14340. // Save input w/h
  14341. var opts = this._opts;
  14342. width != null && (opts.width = width);
  14343. height != null && (opts.height = height);
  14344. width = this._getSize(0);
  14345. height = this._getSize(1);
  14346. viewport.style.display = '';
  14347. if (this._width !== width && this._height !== height) {
  14348. this._width = width;
  14349. this._height = height;
  14350. var viewportStyle = viewport.style;
  14351. viewportStyle.width = width + 'px';
  14352. viewportStyle.height = height + 'px';
  14353. var svgRoot = this._svgRoot;
  14354. // Set width by 'svgRoot.width = width' is invalid
  14355. svgRoot.setAttribute('width', width);
  14356. svgRoot.setAttribute('height', height);
  14357. }
  14358. },
  14359. /**
  14360. * 获取绘图区域宽度
  14361. */
  14362. getWidth: function () {
  14363. return this._width;
  14364. },
  14365. /**
  14366. * 获取绘图区域高度
  14367. */
  14368. getHeight: function () {
  14369. return this._height;
  14370. },
  14371. _getSize: function (whIdx) {
  14372. var opts = this._opts;
  14373. var wh = ['width', 'height'][whIdx];
  14374. var cwh = ['clientWidth', 'clientHeight'][whIdx];
  14375. var plt = ['paddingLeft', 'paddingTop'][whIdx];
  14376. var prb = ['paddingRight', 'paddingBottom'][whIdx];
  14377. if (opts[wh] != null && opts[wh] !== 'auto') {
  14378. return parseFloat(opts[wh]);
  14379. }
  14380. var root = this.root;
  14381. // IE8 does not support getComputedStyle, but it use VML.
  14382. var stl = document.defaultView.getComputedStyle(root);
  14383. return (
  14384. (root[cwh] || parseInt10$1(stl[wh]) || parseInt10$1(root.style[wh]))
  14385. - (parseInt10$1(stl[plt]) || 0)
  14386. - (parseInt10$1(stl[prb]) || 0)
  14387. ) | 0;
  14388. },
  14389. dispose: function () {
  14390. this.root.innerHTML = '';
  14391. this._svgRoot
  14392. = this._viewport
  14393. = this.storage
  14394. = null;
  14395. },
  14396. clear: function () {
  14397. if (this._viewport) {
  14398. this.root.removeChild(this._viewport);
  14399. }
  14400. },
  14401. pathToSvg: function () {
  14402. this.refresh();
  14403. var html = this._svgRoot.outerHTML;
  14404. return 'data:img/svg+xml;utf-8,' + unescape(html);
  14405. }
  14406. };
  14407. // Not supported methods
  14408. function createMethodNotSupport(method) {
  14409. return function () {
  14410. zrLog('In SVG mode painter not support method "' + method + '"');
  14411. };
  14412. }
  14413. // Unsuppoted methods
  14414. each([
  14415. 'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',
  14416. 'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',
  14417. 'toDataURL', 'pathToImage'
  14418. ], function (name) {
  14419. SVGPainter.prototype[name] = createMethodNotSupport(name);
  14420. });
  14421. registerPainter('svg', SVGPainter);
  14422. var urn = 'urn:schemas-microsoft-com:vml';
  14423. var win = typeof window === 'undefined' ? null : window;
  14424. var vmlInited = false;
  14425. var doc = win && win.document;
  14426. function createNode(tagName) {
  14427. return doCreateNode(tagName);
  14428. }
  14429. // Avoid assign to an exported variable, for transforming to cjs.
  14430. var doCreateNode;
  14431. if (doc && !env$1.canvasSupported) {
  14432. try {
  14433. !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);
  14434. doCreateNode = function (tagName) {
  14435. return doc.createElement('<zrvml:' + tagName + ' class="zrvml">');
  14436. };
  14437. }
  14438. catch (e) {
  14439. doCreateNode = function (tagName) {
  14440. return doc.createElement('<' + tagName + ' xmlns="' + urn + '" class="zrvml">');
  14441. };
  14442. }
  14443. }
  14444. // From raphael
  14445. function initVML() {
  14446. if (vmlInited || !doc) {
  14447. return;
  14448. }
  14449. vmlInited = true;
  14450. var styleSheets = doc.styleSheets;
  14451. if (styleSheets.length < 31) {
  14452. doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');
  14453. }
  14454. else {
  14455. // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx
  14456. styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');
  14457. }
  14458. }
  14459. // http://www.w3.org/TR/NOTE-VML
  14460. // TODO Use proxy like svg instead of overwrite brush methods
  14461. var CMD$4 = PathProxy.CMD;
  14462. var round = Math.round;
  14463. var sqrt = Math.sqrt;
  14464. var abs$1 = Math.abs;
  14465. var cos$4 = Math.cos;
  14466. var sin$4 = Math.sin;
  14467. var mathMax$3 = Math.max;
  14468. if (!env$1.canvasSupported) {
  14469. var comma = ',';
  14470. var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';
  14471. var Z = 21600;
  14472. var Z2 = Z / 2;
  14473. var ZLEVEL_BASE = 100000;
  14474. var Z_BASE = 1000;
  14475. var initRootElStyle = function (el) {
  14476. el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';
  14477. el.coordsize = Z + ',' + Z;
  14478. el.coordorigin = '0,0';
  14479. };
  14480. var encodeHtmlAttribute = function (s) {
  14481. return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
  14482. };
  14483. var rgb2Str = function (r, g, b) {
  14484. return 'rgb(' + [r, g, b].join(',') + ')';
  14485. };
  14486. var append$1 = function (parent, child) {
  14487. if (child && parent && child.parentNode !== parent) {
  14488. parent.appendChild(child);
  14489. }
  14490. };
  14491. var remove$1 = function (parent, child) {
  14492. if (child && parent && child.parentNode === parent) {
  14493. parent.removeChild(child);
  14494. }
  14495. };
  14496. var getZIndex = function (zlevel, z, z2) {
  14497. // z 的取值范围为 [0, 1000]
  14498. return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2;
  14499. };
  14500. var parsePercent$1 = function (value, maxValue) {
  14501. if (typeof value === 'string') {
  14502. if (value.lastIndexOf('%') >= 0) {
  14503. return parseFloat(value) / 100 * maxValue;
  14504. }
  14505. return parseFloat(value);
  14506. }
  14507. return value;
  14508. };
  14509. /***************************************************
  14510. * PATH
  14511. **************************************************/
  14512. var setColorAndOpacity = function (el, color, opacity) {
  14513. var colorArr = parse(color);
  14514. opacity = +opacity;
  14515. if (isNaN(opacity)) {
  14516. opacity = 1;
  14517. }
  14518. if (colorArr) {
  14519. el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);
  14520. el.opacity = opacity * colorArr[3];
  14521. }
  14522. };
  14523. var getColorAndAlpha = function (color) {
  14524. var colorArr = parse(color);
  14525. return [
  14526. rgb2Str(colorArr[0], colorArr[1], colorArr[2]),
  14527. colorArr[3]
  14528. ];
  14529. };
  14530. var updateFillNode = function (el, style, zrEl) {
  14531. // TODO pattern
  14532. var fill = style.fill;
  14533. if (fill != null) {
  14534. // Modified from excanvas
  14535. if (fill instanceof Gradient) {
  14536. var gradientType;
  14537. var angle = 0;
  14538. var focus = [0, 0];
  14539. // additional offset
  14540. var shift = 0;
  14541. // scale factor for offset
  14542. var expansion = 1;
  14543. var rect = zrEl.getBoundingRect();
  14544. var rectWidth = rect.width;
  14545. var rectHeight = rect.height;
  14546. if (fill.type === 'linear') {
  14547. gradientType = 'gradient';
  14548. var transform = zrEl.transform;
  14549. var p0 = [fill.x * rectWidth, fill.y * rectHeight];
  14550. var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];
  14551. if (transform) {
  14552. applyTransform(p0, p0, transform);
  14553. applyTransform(p1, p1, transform);
  14554. }
  14555. var dx = p1[0] - p0[0];
  14556. var dy = p1[1] - p0[1];
  14557. angle = Math.atan2(dx, dy) * 180 / Math.PI;
  14558. // The angle should be a non-negative number.
  14559. if (angle < 0) {
  14560. angle += 360;
  14561. }
  14562. // Very small angles produce an unexpected result because they are
  14563. // converted to a scientific notation string.
  14564. if (angle < 1e-6) {
  14565. angle = 0;
  14566. }
  14567. }
  14568. else {
  14569. gradientType = 'gradientradial';
  14570. var p0 = [fill.x * rectWidth, fill.y * rectHeight];
  14571. var transform = zrEl.transform;
  14572. var scale$$1 = zrEl.scale;
  14573. var width = rectWidth;
  14574. var height = rectHeight;
  14575. focus = [
  14576. // Percent in bounding rect
  14577. (p0[0] - rect.x) / width,
  14578. (p0[1] - rect.y) / height
  14579. ];
  14580. if (transform) {
  14581. applyTransform(p0, p0, transform);
  14582. }
  14583. width /= scale$$1[0] * Z;
  14584. height /= scale$$1[1] * Z;
  14585. var dimension = mathMax$3(width, height);
  14586. shift = 2 * 0 / dimension;
  14587. expansion = 2 * fill.r / dimension - shift;
  14588. }
  14589. // We need to sort the color stops in ascending order by offset,
  14590. // otherwise IE won't interpret it correctly.
  14591. var stops = fill.colorStops.slice();
  14592. stops.sort(function(cs1, cs2) {
  14593. return cs1.offset - cs2.offset;
  14594. });
  14595. var length$$1 = stops.length;
  14596. // Color and alpha list of first and last stop
  14597. var colorAndAlphaList = [];
  14598. var colors = [];
  14599. for (var i = 0; i < length$$1; i++) {
  14600. var stop = stops[i];
  14601. var colorAndAlpha = getColorAndAlpha(stop.color);
  14602. colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);
  14603. if (i === 0 || i === length$$1 - 1) {
  14604. colorAndAlphaList.push(colorAndAlpha);
  14605. }
  14606. }
  14607. if (length$$1 >= 2) {
  14608. var color1 = colorAndAlphaList[0][0];
  14609. var color2 = colorAndAlphaList[1][0];
  14610. var opacity1 = colorAndAlphaList[0][1] * style.opacity;
  14611. var opacity2 = colorAndAlphaList[1][1] * style.opacity;
  14612. el.type = gradientType;
  14613. el.method = 'none';
  14614. el.focus = '100%';
  14615. el.angle = angle;
  14616. el.color = color1;
  14617. el.color2 = color2;
  14618. el.colors = colors.join(',');
  14619. // When colors attribute is used, the meanings of opacity and o:opacity2
  14620. // are reversed.
  14621. el.opacity = opacity2;
  14622. // FIXME g_o_:opacity ?
  14623. el.opacity2 = opacity1;
  14624. }
  14625. if (gradientType === 'radial') {
  14626. el.focusposition = focus.join(',');
  14627. }
  14628. }
  14629. else {
  14630. // FIXME Change from Gradient fill to color fill
  14631. setColorAndOpacity(el, fill, style.opacity);
  14632. }
  14633. }
  14634. };
  14635. var updateStrokeNode = function (el, style) {
  14636. // if (style.lineJoin != null) {
  14637. // el.joinstyle = style.lineJoin;
  14638. // }
  14639. // if (style.miterLimit != null) {
  14640. // el.miterlimit = style.miterLimit * Z;
  14641. // }
  14642. // if (style.lineCap != null) {
  14643. // el.endcap = style.lineCap;
  14644. // }
  14645. if (style.lineDash != null) {
  14646. el.dashstyle = style.lineDash.join(' ');
  14647. }
  14648. if (style.stroke != null && !(style.stroke instanceof Gradient)) {
  14649. setColorAndOpacity(el, style.stroke, style.opacity);
  14650. }
  14651. };
  14652. var updateFillAndStroke = function (vmlEl, type, style, zrEl) {
  14653. var isFill = type == 'fill';
  14654. var el = vmlEl.getElementsByTagName(type)[0];
  14655. // Stroke must have lineWidth
  14656. if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {
  14657. vmlEl[isFill ? 'filled' : 'stroked'] = 'true';
  14658. // FIXME Remove before updating, or set `colors` will throw error
  14659. if (style[type] instanceof Gradient) {
  14660. remove$1(vmlEl, el);
  14661. }
  14662. if (!el) {
  14663. el = createNode(type);
  14664. }
  14665. isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);
  14666. append$1(vmlEl, el);
  14667. }
  14668. else {
  14669. vmlEl[isFill ? 'filled' : 'stroked'] = 'false';
  14670. remove$1(vmlEl, el);
  14671. }
  14672. };
  14673. var points$1 = [[], [], []];
  14674. var pathDataToString$1 = function (path, m) {
  14675. var M = CMD$4.M;
  14676. var C = CMD$4.C;
  14677. var L = CMD$4.L;
  14678. var A = CMD$4.A;
  14679. var Q = CMD$4.Q;
  14680. var str = [];
  14681. var nPoint;
  14682. var cmdStr;
  14683. var cmd;
  14684. var i;
  14685. var xi;
  14686. var yi;
  14687. var data = path.data;
  14688. var dataLength = path.len();
  14689. for (i = 0; i < dataLength;) {
  14690. cmd = data[i++];
  14691. cmdStr = '';
  14692. nPoint = 0;
  14693. switch (cmd) {
  14694. case M:
  14695. cmdStr = ' m ';
  14696. nPoint = 1;
  14697. xi = data[i++];
  14698. yi = data[i++];
  14699. points$1[0][0] = xi;
  14700. points$1[0][1] = yi;
  14701. break;
  14702. case L:
  14703. cmdStr = ' l ';
  14704. nPoint = 1;
  14705. xi = data[i++];
  14706. yi = data[i++];
  14707. points$1[0][0] = xi;
  14708. points$1[0][1] = yi;
  14709. break;
  14710. case Q:
  14711. case C:
  14712. cmdStr = ' c ';
  14713. nPoint = 3;
  14714. var x1 = data[i++];
  14715. var y1 = data[i++];
  14716. var x2 = data[i++];
  14717. var y2 = data[i++];
  14718. var x3;
  14719. var y3;
  14720. if (cmd === Q) {
  14721. // Convert quadratic to cubic using degree elevation
  14722. x3 = x2;
  14723. y3 = y2;
  14724. x2 = (x2 + 2 * x1) / 3;
  14725. y2 = (y2 + 2 * y1) / 3;
  14726. x1 = (xi + 2 * x1) / 3;
  14727. y1 = (yi + 2 * y1) / 3;
  14728. }
  14729. else {
  14730. x3 = data[i++];
  14731. y3 = data[i++];
  14732. }
  14733. points$1[0][0] = x1;
  14734. points$1[0][1] = y1;
  14735. points$1[1][0] = x2;
  14736. points$1[1][1] = y2;
  14737. points$1[2][0] = x3;
  14738. points$1[2][1] = y3;
  14739. xi = x3;
  14740. yi = y3;
  14741. break;
  14742. case A:
  14743. var x = 0;
  14744. var y = 0;
  14745. var sx = 1;
  14746. var sy = 1;
  14747. var angle = 0;
  14748. if (m) {
  14749. // Extract SRT from matrix
  14750. x = m[4];
  14751. y = m[5];
  14752. sx = sqrt(m[0] * m[0] + m[1] * m[1]);
  14753. sy = sqrt(m[2] * m[2] + m[3] * m[3]);
  14754. angle = Math.atan2(-m[1] / sy, m[0] / sx);
  14755. }
  14756. var cx = data[i++];
  14757. var cy = data[i++];
  14758. var rx = data[i++];
  14759. var ry = data[i++];
  14760. var startAngle = data[i++] + angle;
  14761. var endAngle = data[i++] + startAngle + angle;
  14762. // FIXME
  14763. // var psi = data[i++];
  14764. i++;
  14765. var clockwise = data[i++];
  14766. var x0 = cx + cos$4(startAngle) * rx;
  14767. var y0 = cy + sin$4(startAngle) * ry;
  14768. var x1 = cx + cos$4(endAngle) * rx;
  14769. var y1 = cy + sin$4(endAngle) * ry;
  14770. var type = clockwise ? ' wa ' : ' at ';
  14771. if (Math.abs(x0 - x1) < 1e-4) {
  14772. // IE won't render arches drawn counter clockwise if x0 == x1.
  14773. if (Math.abs(endAngle - startAngle) > 1e-2) {
  14774. // Offset x0 by 1/80 of a pixel. Use something
  14775. // that can be represented in binary
  14776. if (clockwise) {
  14777. x0 += 270 / Z;
  14778. }
  14779. }
  14780. else {
  14781. // Avoid case draw full circle
  14782. if (Math.abs(y0 - cy) < 1e-4) {
  14783. if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {
  14784. y1 -= 270 / Z;
  14785. }
  14786. else {
  14787. y1 += 270 / Z;
  14788. }
  14789. }
  14790. else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {
  14791. x1 += 270 / Z;
  14792. }
  14793. else {
  14794. x1 -= 270 / Z;
  14795. }
  14796. }
  14797. }
  14798. str.push(
  14799. type,
  14800. round(((cx - rx) * sx + x) * Z - Z2), comma,
  14801. round(((cy - ry) * sy + y) * Z - Z2), comma,
  14802. round(((cx + rx) * sx + x) * Z - Z2), comma,
  14803. round(((cy + ry) * sy + y) * Z - Z2), comma,
  14804. round((x0 * sx + x) * Z - Z2), comma,
  14805. round((y0 * sy + y) * Z - Z2), comma,
  14806. round((x1 * sx + x) * Z - Z2), comma,
  14807. round((y1 * sy + y) * Z - Z2)
  14808. );
  14809. xi = x1;
  14810. yi = y1;
  14811. break;
  14812. case CMD$4.R:
  14813. var p0 = points$1[0];
  14814. var p1 = points$1[1];
  14815. // x0, y0
  14816. p0[0] = data[i++];
  14817. p0[1] = data[i++];
  14818. // x1, y1
  14819. p1[0] = p0[0] + data[i++];
  14820. p1[1] = p0[1] + data[i++];
  14821. if (m) {
  14822. applyTransform(p0, p0, m);
  14823. applyTransform(p1, p1, m);
  14824. }
  14825. p0[0] = round(p0[0] * Z - Z2);
  14826. p1[0] = round(p1[0] * Z - Z2);
  14827. p0[1] = round(p0[1] * Z - Z2);
  14828. p1[1] = round(p1[1] * Z - Z2);
  14829. str.push(
  14830. // x0, y0
  14831. ' m ', p0[0], comma, p0[1],
  14832. // x1, y0
  14833. ' l ', p1[0], comma, p0[1],
  14834. // x1, y1
  14835. ' l ', p1[0], comma, p1[1],
  14836. // x0, y1
  14837. ' l ', p0[0], comma, p1[1]
  14838. );
  14839. break;
  14840. case CMD$4.Z:
  14841. // FIXME Update xi, yi
  14842. str.push(' x ');
  14843. }
  14844. if (nPoint > 0) {
  14845. str.push(cmdStr);
  14846. for (var k = 0; k < nPoint; k++) {
  14847. var p = points$1[k];
  14848. m && applyTransform(p, p, m);
  14849. // 不 round 会非常慢
  14850. str.push(
  14851. round(p[0] * Z - Z2), comma, round(p[1] * Z - Z2),
  14852. k < nPoint - 1 ? comma : ''
  14853. );
  14854. }
  14855. }
  14856. }
  14857. return str.join('');
  14858. };
  14859. // Rewrite the original path method
  14860. Path.prototype.brushVML = function (vmlRoot) {
  14861. var style = this.style;
  14862. var vmlEl = this._vmlEl;
  14863. if (!vmlEl) {
  14864. vmlEl = createNode('shape');
  14865. initRootElStyle(vmlEl);
  14866. this._vmlEl = vmlEl;
  14867. }
  14868. updateFillAndStroke(vmlEl, 'fill', style, this);
  14869. updateFillAndStroke(vmlEl, 'stroke', style, this);
  14870. var m = this.transform;
  14871. var needTransform = m != null;
  14872. var strokeEl = vmlEl.getElementsByTagName('stroke')[0];
  14873. if (strokeEl) {
  14874. var lineWidth = style.lineWidth;
  14875. // Get the line scale.
  14876. // Determinant of this.m_ means how much the area is enlarged by the
  14877. // transformation. So its square root can be used as a scale factor
  14878. // for width.
  14879. if (needTransform && !style.strokeNoScale) {
  14880. var det = m[0] * m[3] - m[1] * m[2];
  14881. lineWidth *= sqrt(abs$1(det));
  14882. }
  14883. strokeEl.weight = lineWidth + 'px';
  14884. }
  14885. var path = this.path || (this.path = new PathProxy());
  14886. if (this.__dirtyPath) {
  14887. path.beginPath();
  14888. this.buildPath(path, this.shape);
  14889. path.toStatic();
  14890. this.__dirtyPath = false;
  14891. }
  14892. vmlEl.path = pathDataToString$1(path, this.transform);
  14893. vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
  14894. // Append to root
  14895. append$1(vmlRoot, vmlEl);
  14896. // Text
  14897. if (style.text != null) {
  14898. this.drawRectText(vmlRoot, this.getBoundingRect());
  14899. }
  14900. else {
  14901. this.removeRectText(vmlRoot);
  14902. }
  14903. };
  14904. Path.prototype.onRemove = function (vmlRoot) {
  14905. remove$1(vmlRoot, this._vmlEl);
  14906. this.removeRectText(vmlRoot);
  14907. };
  14908. Path.prototype.onAdd = function (vmlRoot) {
  14909. append$1(vmlRoot, this._vmlEl);
  14910. this.appendRectText(vmlRoot);
  14911. };
  14912. /***************************************************
  14913. * IMAGE
  14914. **************************************************/
  14915. var isImage = function (img) {
  14916. // FIXME img instanceof Image 如果 img 是一个字符串的时候,IE8 下会报错
  14917. return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';
  14918. // return img instanceof Image;
  14919. };
  14920. // Rewrite the original path method
  14921. ZImage.prototype.brushVML = function (vmlRoot) {
  14922. var style = this.style;
  14923. var image = style.image;
  14924. // Image original width, height
  14925. var ow;
  14926. var oh;
  14927. if (isImage(image)) {
  14928. var src = image.src;
  14929. if (src === this._imageSrc) {
  14930. ow = this._imageWidth;
  14931. oh = this._imageHeight;
  14932. }
  14933. else {
  14934. var imageRuntimeStyle = image.runtimeStyle;
  14935. var oldRuntimeWidth = imageRuntimeStyle.width;
  14936. var oldRuntimeHeight = imageRuntimeStyle.height;
  14937. imageRuntimeStyle.width = 'auto';
  14938. imageRuntimeStyle.height = 'auto';
  14939. // get the original size
  14940. ow = image.width;
  14941. oh = image.height;
  14942. // and remove overides
  14943. imageRuntimeStyle.width = oldRuntimeWidth;
  14944. imageRuntimeStyle.height = oldRuntimeHeight;
  14945. // Caching image original width, height and src
  14946. this._imageSrc = src;
  14947. this._imageWidth = ow;
  14948. this._imageHeight = oh;
  14949. }
  14950. image = src;
  14951. }
  14952. else {
  14953. if (image === this._imageSrc) {
  14954. ow = this._imageWidth;
  14955. oh = this._imageHeight;
  14956. }
  14957. }
  14958. if (!image) {
  14959. return;
  14960. }
  14961. var x = style.x || 0;
  14962. var y = style.y || 0;
  14963. var dw = style.width;
  14964. var dh = style.height;
  14965. var sw = style.sWidth;
  14966. var sh = style.sHeight;
  14967. var sx = style.sx || 0;
  14968. var sy = style.sy || 0;
  14969. var hasCrop = sw && sh;
  14970. var vmlEl = this._vmlEl;
  14971. if (!vmlEl) {
  14972. // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。
  14973. // vmlEl = vmlCore.createNode('group');
  14974. vmlEl = doc.createElement('div');
  14975. initRootElStyle(vmlEl);
  14976. this._vmlEl = vmlEl;
  14977. }
  14978. var vmlElStyle = vmlEl.style;
  14979. var hasRotation = false;
  14980. var m;
  14981. var scaleX = 1;
  14982. var scaleY = 1;
  14983. if (this.transform) {
  14984. m = this.transform;
  14985. scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);
  14986. scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);
  14987. hasRotation = m[1] || m[2];
  14988. }
  14989. if (hasRotation) {
  14990. // If filters are necessary (rotation exists), create them
  14991. // filters are bog-slow, so only create them if abbsolutely necessary
  14992. // The following check doesn't account for skews (which don't exist
  14993. // in the canvas spec (yet) anyway.
  14994. // From excanvas
  14995. var p0 = [x, y];
  14996. var p1 = [x + dw, y];
  14997. var p2 = [x, y + dh];
  14998. var p3 = [x + dw, y + dh];
  14999. applyTransform(p0, p0, m);
  15000. applyTransform(p1, p1, m);
  15001. applyTransform(p2, p2, m);
  15002. applyTransform(p3, p3, m);
  15003. var maxX = mathMax$3(p0[0], p1[0], p2[0], p3[0]);
  15004. var maxY = mathMax$3(p0[1], p1[1], p2[1], p3[1]);
  15005. var transformFilter = [];
  15006. transformFilter.push('M11=', m[0] / scaleX, comma,
  15007. 'M12=', m[2] / scaleY, comma,
  15008. 'M21=', m[1] / scaleX, comma,
  15009. 'M22=', m[3] / scaleY, comma,
  15010. 'Dx=', round(x * scaleX + m[4]), comma,
  15011. 'Dy=', round(y * scaleY + m[5]));
  15012. vmlElStyle.padding = '0 ' + round(maxX) + 'px ' + round(maxY) + 'px 0';
  15013. // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用
  15014. vmlElStyle.filter = imageTransformPrefix + '.Matrix('
  15015. + transformFilter.join('') + ', SizingMethod=clip)';
  15016. }
  15017. else {
  15018. if (m) {
  15019. x = x * scaleX + m[4];
  15020. y = y * scaleY + m[5];
  15021. }
  15022. vmlElStyle.filter = '';
  15023. vmlElStyle.left = round(x) + 'px';
  15024. vmlElStyle.top = round(y) + 'px';
  15025. }
  15026. var imageEl = this._imageEl;
  15027. var cropEl = this._cropEl;
  15028. if (!imageEl) {
  15029. imageEl = doc.createElement('div');
  15030. this._imageEl = imageEl;
  15031. }
  15032. var imageELStyle = imageEl.style;
  15033. if (hasCrop) {
  15034. // Needs know image original width and height
  15035. if (! (ow && oh)) {
  15036. var tmpImage = new Image();
  15037. var self = this;
  15038. tmpImage.onload = function () {
  15039. tmpImage.onload = null;
  15040. ow = tmpImage.width;
  15041. oh = tmpImage.height;
  15042. // Adjust image width and height to fit the ratio destinationSize / sourceSize
  15043. imageELStyle.width = round(scaleX * ow * dw / sw) + 'px';
  15044. imageELStyle.height = round(scaleY * oh * dh / sh) + 'px';
  15045. // Caching image original width, height and src
  15046. self._imageWidth = ow;
  15047. self._imageHeight = oh;
  15048. self._imageSrc = image;
  15049. };
  15050. tmpImage.src = image;
  15051. }
  15052. else {
  15053. imageELStyle.width = round(scaleX * ow * dw / sw) + 'px';
  15054. imageELStyle.height = round(scaleY * oh * dh / sh) + 'px';
  15055. }
  15056. if (! cropEl) {
  15057. cropEl = doc.createElement('div');
  15058. cropEl.style.overflow = 'hidden';
  15059. this._cropEl = cropEl;
  15060. }
  15061. var cropElStyle = cropEl.style;
  15062. cropElStyle.width = round((dw + sx * dw / sw) * scaleX);
  15063. cropElStyle.height = round((dh + sy * dh / sh) * scaleY);
  15064. cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='
  15065. + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';
  15066. if (! cropEl.parentNode) {
  15067. vmlEl.appendChild(cropEl);
  15068. }
  15069. if (imageEl.parentNode != cropEl) {
  15070. cropEl.appendChild(imageEl);
  15071. }
  15072. }
  15073. else {
  15074. imageELStyle.width = round(scaleX * dw) + 'px';
  15075. imageELStyle.height = round(scaleY * dh) + 'px';
  15076. vmlEl.appendChild(imageEl);
  15077. if (cropEl && cropEl.parentNode) {
  15078. vmlEl.removeChild(cropEl);
  15079. this._cropEl = null;
  15080. }
  15081. }
  15082. var filterStr = '';
  15083. var alpha = style.opacity;
  15084. if (alpha < 1) {
  15085. filterStr += '.Alpha(opacity=' + round(alpha * 100) + ') ';
  15086. }
  15087. filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';
  15088. imageELStyle.filter = filterStr;
  15089. vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
  15090. // Append to root
  15091. append$1(vmlRoot, vmlEl);
  15092. // Text
  15093. if (style.text != null) {
  15094. this.drawRectText(vmlRoot, this.getBoundingRect());
  15095. }
  15096. };
  15097. ZImage.prototype.onRemove = function (vmlRoot) {
  15098. remove$1(vmlRoot, this._vmlEl);
  15099. this._vmlEl = null;
  15100. this._cropEl = null;
  15101. this._imageEl = null;
  15102. this.removeRectText(vmlRoot);
  15103. };
  15104. ZImage.prototype.onAdd = function (vmlRoot) {
  15105. append$1(vmlRoot, this._vmlEl);
  15106. this.appendRectText(vmlRoot);
  15107. };
  15108. /***************************************************
  15109. * TEXT
  15110. **************************************************/
  15111. var DEFAULT_STYLE_NORMAL = 'normal';
  15112. var fontStyleCache = {};
  15113. var fontStyleCacheCount = 0;
  15114. var MAX_FONT_CACHE_SIZE = 100;
  15115. var fontEl = document.createElement('div');
  15116. var getFontStyle = function (fontString) {
  15117. var fontStyle = fontStyleCache[fontString];
  15118. if (!fontStyle) {
  15119. // Clear cache
  15120. if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {
  15121. fontStyleCacheCount = 0;
  15122. fontStyleCache = {};
  15123. }
  15124. var style = fontEl.style;
  15125. var fontFamily;
  15126. try {
  15127. style.font = fontString;
  15128. fontFamily = style.fontFamily.split(',')[0];
  15129. }
  15130. catch (e) {
  15131. }
  15132. fontStyle = {
  15133. style: style.fontStyle || DEFAULT_STYLE_NORMAL,
  15134. variant: style.fontVariant || DEFAULT_STYLE_NORMAL,
  15135. weight: style.fontWeight || DEFAULT_STYLE_NORMAL,
  15136. size: parseFloat(style.fontSize || 12) | 0,
  15137. family: fontFamily || 'Microsoft YaHei'
  15138. };
  15139. fontStyleCache[fontString] = fontStyle;
  15140. fontStyleCacheCount++;
  15141. }
  15142. return fontStyle;
  15143. };
  15144. var textMeasureEl;
  15145. // Overwrite measure text method
  15146. $override$1('measureText', function (text, textFont) {
  15147. var doc$$1 = doc;
  15148. if (!textMeasureEl) {
  15149. textMeasureEl = doc$$1.createElement('div');
  15150. textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'
  15151. + 'padding:0;margin:0;border:none;white-space:pre;';
  15152. doc.body.appendChild(textMeasureEl);
  15153. }
  15154. try {
  15155. textMeasureEl.style.font = textFont;
  15156. } catch (ex) {
  15157. // Ignore failures to set to invalid font.
  15158. }
  15159. textMeasureEl.innerHTML = '';
  15160. // Don't use innerHTML or innerText because they allow markup/whitespace.
  15161. textMeasureEl.appendChild(doc$$1.createTextNode(text));
  15162. return {
  15163. width: textMeasureEl.offsetWidth
  15164. };
  15165. });
  15166. var tmpRect$3 = new BoundingRect();
  15167. var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {
  15168. var style = this.style;
  15169. // Optimize, avoid normalize every time.
  15170. this.__dirty && normalizeTextStyle(style, true);
  15171. var text = style.text;
  15172. // Convert to string
  15173. text != null && (text += '');
  15174. if (!text) {
  15175. return;
  15176. }
  15177. // Convert rich text to plain text. Rich text is not supported in
  15178. // IE8-, but tags in rich text template will be removed.
  15179. if (style.rich) {
  15180. var contentBlock = parseRichText(text, style);
  15181. text = [];
  15182. for (var i = 0; i < contentBlock.lines.length; i++) {
  15183. var tokens = contentBlock.lines[i].tokens;
  15184. var textLine = [];
  15185. for (var j = 0; j < tokens.length; j++) {
  15186. textLine.push(tokens[j].text);
  15187. }
  15188. text.push(textLine.join(''));
  15189. }
  15190. text = text.join('\n');
  15191. }
  15192. var x;
  15193. var y;
  15194. var align = style.textAlign;
  15195. var verticalAlign = style.textVerticalAlign;
  15196. var fontStyle = getFontStyle(style.font);
  15197. // FIXME encodeHtmlAttribute ?
  15198. var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '
  15199. + fontStyle.size + 'px "' + fontStyle.family + '"';
  15200. textRect = textRect || getBoundingRect(text, font, align, verticalAlign);
  15201. // Transform rect to view space
  15202. var m = this.transform;
  15203. // Ignore transform for text in other element
  15204. if (m && !fromTextEl) {
  15205. tmpRect$3.copy(rect);
  15206. tmpRect$3.applyTransform(m);
  15207. rect = tmpRect$3;
  15208. }
  15209. if (!fromTextEl) {
  15210. var textPosition = style.textPosition;
  15211. var distance$$1 = style.textDistance;
  15212. // Text position represented by coord
  15213. if (textPosition instanceof Array) {
  15214. x = rect.x + parsePercent$1(textPosition[0], rect.width);
  15215. y = rect.y + parsePercent$1(textPosition[1], rect.height);
  15216. align = align || 'left';
  15217. }
  15218. else {
  15219. var res = adjustTextPositionOnRect(
  15220. textPosition, rect, distance$$1
  15221. );
  15222. x = res.x;
  15223. y = res.y;
  15224. // Default align and baseline when has textPosition
  15225. align = align || res.textAlign;
  15226. verticalAlign = verticalAlign || res.textVerticalAlign;
  15227. }
  15228. }
  15229. else {
  15230. x = rect.x;
  15231. y = rect.y;
  15232. }
  15233. x = adjustTextX(x, textRect.width, align);
  15234. y = adjustTextY(y, textRect.height, verticalAlign);
  15235. // Force baseline 'middle'
  15236. y += textRect.height / 2;
  15237. // var fontSize = fontStyle.size;
  15238. // 1.75 is an arbitrary number, as there is no info about the text baseline
  15239. // switch (baseline) {
  15240. // case 'hanging':
  15241. // case 'top':
  15242. // y += fontSize / 1.75;
  15243. // break;
  15244. // case 'middle':
  15245. // break;
  15246. // default:
  15247. // // case null:
  15248. // // case 'alphabetic':
  15249. // // case 'ideographic':
  15250. // // case 'bottom':
  15251. // y -= fontSize / 2.25;
  15252. // break;
  15253. // }
  15254. // switch (align) {
  15255. // case 'left':
  15256. // break;
  15257. // case 'center':
  15258. // x -= textRect.width / 2;
  15259. // break;
  15260. // case 'right':
  15261. // x -= textRect.width;
  15262. // break;
  15263. // case 'end':
  15264. // align = elementStyle.direction == 'ltr' ? 'right' : 'left';
  15265. // break;
  15266. // case 'start':
  15267. // align = elementStyle.direction == 'rtl' ? 'right' : 'left';
  15268. // break;
  15269. // default:
  15270. // align = 'left';
  15271. // }
  15272. var createNode$$1 = createNode;
  15273. var textVmlEl = this._textVmlEl;
  15274. var pathEl;
  15275. var textPathEl;
  15276. var skewEl;
  15277. if (!textVmlEl) {
  15278. textVmlEl = createNode$$1('line');
  15279. pathEl = createNode$$1('path');
  15280. textPathEl = createNode$$1('textpath');
  15281. skewEl = createNode$$1('skew');
  15282. // FIXME Why here is not cammel case
  15283. // Align 'center' seems wrong
  15284. textPathEl.style['v-text-align'] = 'left';
  15285. initRootElStyle(textVmlEl);
  15286. pathEl.textpathok = true;
  15287. textPathEl.on = true;
  15288. textVmlEl.from = '0 0';
  15289. textVmlEl.to = '1000 0.05';
  15290. append$1(textVmlEl, skewEl);
  15291. append$1(textVmlEl, pathEl);
  15292. append$1(textVmlEl, textPathEl);
  15293. this._textVmlEl = textVmlEl;
  15294. }
  15295. else {
  15296. // 这里是在前面 appendChild 保证顺序的前提下
  15297. skewEl = textVmlEl.firstChild;
  15298. pathEl = skewEl.nextSibling;
  15299. textPathEl = pathEl.nextSibling;
  15300. }
  15301. var coords = [x, y];
  15302. var textVmlElStyle = textVmlEl.style;
  15303. // Ignore transform for text in other element
  15304. if (m && fromTextEl) {
  15305. applyTransform(coords, coords, m);
  15306. skewEl.on = true;
  15307. skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma +
  15308. m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';
  15309. // Text position
  15310. skewEl.offset = (round(coords[0]) || 0) + ',' + (round(coords[1]) || 0);
  15311. // Left top point as origin
  15312. skewEl.origin = '0 0';
  15313. textVmlElStyle.left = '0px';
  15314. textVmlElStyle.top = '0px';
  15315. }
  15316. else {
  15317. skewEl.on = false;
  15318. textVmlElStyle.left = round(x) + 'px';
  15319. textVmlElStyle.top = round(y) + 'px';
  15320. }
  15321. textPathEl.string = encodeHtmlAttribute(text);
  15322. // TODO
  15323. try {
  15324. textPathEl.style.font = font;
  15325. }
  15326. // Error font format
  15327. catch (e) {}
  15328. updateFillAndStroke(textVmlEl, 'fill', {
  15329. fill: style.textFill,
  15330. opacity: style.opacity
  15331. }, this);
  15332. updateFillAndStroke(textVmlEl, 'stroke', {
  15333. stroke: style.textStroke,
  15334. opacity: style.opacity,
  15335. lineDash: style.lineDash
  15336. }, this);
  15337. textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);
  15338. // Attached to root
  15339. append$1(vmlRoot, textVmlEl);
  15340. };
  15341. var removeRectText = function (vmlRoot) {
  15342. remove$1(vmlRoot, this._textVmlEl);
  15343. this._textVmlEl = null;
  15344. };
  15345. var appendRectText = function (vmlRoot) {
  15346. append$1(vmlRoot, this._textVmlEl);
  15347. };
  15348. var list = [RectText, Displayable, ZImage, Path, Text];
  15349. // In case Displayable has been mixed in RectText
  15350. for (var i$1 = 0; i$1 < list.length; i$1++) {
  15351. var proto = list[i$1].prototype;
  15352. proto.drawRectText = drawRectText;
  15353. proto.removeRectText = removeRectText;
  15354. proto.appendRectText = appendRectText;
  15355. }
  15356. Text.prototype.brushVML = function (vmlRoot) {
  15357. var style = this.style;
  15358. if (style.text != null) {
  15359. this.drawRectText(vmlRoot, {
  15360. x: style.x || 0, y: style.y || 0,
  15361. width: 0, height: 0
  15362. }, this.getBoundingRect(), true);
  15363. }
  15364. else {
  15365. this.removeRectText(vmlRoot);
  15366. }
  15367. };
  15368. Text.prototype.onRemove = function (vmlRoot) {
  15369. this.removeRectText(vmlRoot);
  15370. };
  15371. Text.prototype.onAdd = function (vmlRoot) {
  15372. this.appendRectText(vmlRoot);
  15373. };
  15374. }
  15375. /**
  15376. * VML Painter.
  15377. *
  15378. * @module zrender/vml/Painter
  15379. */
  15380. function parseInt10$2(val) {
  15381. return parseInt(val, 10);
  15382. }
  15383. /**
  15384. * @alias module:zrender/vml/Painter
  15385. */
  15386. function VMLPainter(root, storage) {
  15387. initVML();
  15388. this.root = root;
  15389. this.storage = storage;
  15390. var vmlViewport = document.createElement('div');
  15391. var vmlRoot = document.createElement('div');
  15392. vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';
  15393. vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';
  15394. root.appendChild(vmlViewport);
  15395. this._vmlRoot = vmlRoot;
  15396. this._vmlViewport = vmlViewport;
  15397. this.resize();
  15398. // Modify storage
  15399. var oldDelFromStorage = storage.delFromStorage;
  15400. var oldAddToStorage = storage.addToStorage;
  15401. storage.delFromStorage = function (el) {
  15402. oldDelFromStorage.call(storage, el);
  15403. if (el) {
  15404. el.onRemove && el.onRemove(vmlRoot);
  15405. }
  15406. };
  15407. storage.addToStorage = function (el) {
  15408. // Displayable already has a vml node
  15409. el.onAdd && el.onAdd(vmlRoot);
  15410. oldAddToStorage.call(storage, el);
  15411. };
  15412. this._firstPaint = true;
  15413. }
  15414. VMLPainter.prototype = {
  15415. constructor: VMLPainter,
  15416. getType: function () {
  15417. return 'vml';
  15418. },
  15419. /**
  15420. * @return {HTMLDivElement}
  15421. */
  15422. getViewportRoot: function () {
  15423. return this._vmlViewport;
  15424. },
  15425. getViewportRootOffset: function () {
  15426. var viewportRoot = this.getViewportRoot();
  15427. if (viewportRoot) {
  15428. return {
  15429. offsetLeft: viewportRoot.offsetLeft || 0,
  15430. offsetTop: viewportRoot.offsetTop || 0
  15431. };
  15432. }
  15433. },
  15434. /**
  15435. * 刷新
  15436. */
  15437. refresh: function () {
  15438. var list = this.storage.getDisplayList(true, true);
  15439. this._paintList(list);
  15440. },
  15441. _paintList: function (list) {
  15442. var vmlRoot = this._vmlRoot;
  15443. for (var i = 0; i < list.length; i++) {
  15444. var el = list[i];
  15445. if (el.invisible || el.ignore) {
  15446. if (!el.__alreadyNotVisible) {
  15447. el.onRemove(vmlRoot);
  15448. }
  15449. // Set as already invisible
  15450. el.__alreadyNotVisible = true;
  15451. }
  15452. else {
  15453. if (el.__alreadyNotVisible) {
  15454. el.onAdd(vmlRoot);
  15455. }
  15456. el.__alreadyNotVisible = false;
  15457. if (el.__dirty) {
  15458. el.beforeBrush && el.beforeBrush();
  15459. (el.brushVML || el.brush).call(el, vmlRoot);
  15460. el.afterBrush && el.afterBrush();
  15461. }
  15462. }
  15463. el.__dirty = false;
  15464. }
  15465. if (this._firstPaint) {
  15466. // Detached from document at first time
  15467. // to avoid page refreshing too many times
  15468. // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变
  15469. this._vmlViewport.appendChild(vmlRoot);
  15470. this._firstPaint = false;
  15471. }
  15472. },
  15473. resize: function (width, height) {
  15474. var width = width == null ? this._getWidth() : width;
  15475. var height = height == null ? this._getHeight() : height;
  15476. if (this._width != width || this._height != height) {
  15477. this._width = width;
  15478. this._height = height;
  15479. var vmlViewportStyle = this._vmlViewport.style;
  15480. vmlViewportStyle.width = width + 'px';
  15481. vmlViewportStyle.height = height + 'px';
  15482. }
  15483. },
  15484. dispose: function () {
  15485. this.root.innerHTML = '';
  15486. this._vmlRoot =
  15487. this._vmlViewport =
  15488. this.storage = null;
  15489. },
  15490. getWidth: function () {
  15491. return this._width;
  15492. },
  15493. getHeight: function () {
  15494. return this._height;
  15495. },
  15496. clear: function () {
  15497. if (this._vmlViewport) {
  15498. this.root.removeChild(this._vmlViewport);
  15499. }
  15500. },
  15501. _getWidth: function () {
  15502. var root = this.root;
  15503. var stl = root.currentStyle;
  15504. return ((root.clientWidth || parseInt10$2(stl.width))
  15505. - parseInt10$2(stl.paddingLeft)
  15506. - parseInt10$2(stl.paddingRight)) | 0;
  15507. },
  15508. _getHeight: function () {
  15509. var root = this.root;
  15510. var stl = root.currentStyle;
  15511. return ((root.clientHeight || parseInt10$2(stl.height))
  15512. - parseInt10$2(stl.paddingTop)
  15513. - parseInt10$2(stl.paddingBottom)) | 0;
  15514. }
  15515. };
  15516. // Not supported methods
  15517. function createMethodNotSupport$1(method) {
  15518. return function () {
  15519. zrLog('In IE8.0 VML mode painter not support method "' + method + '"');
  15520. };
  15521. }
  15522. // Unsupported methods
  15523. each([
  15524. 'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',
  15525. 'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'
  15526. ], function (name) {
  15527. VMLPainter.prototype[name] = createMethodNotSupport$1(name);
  15528. });
  15529. registerPainter('vml', VMLPainter);
  15530. exports.version = version;
  15531. exports.init = init;
  15532. exports.dispose = dispose;
  15533. exports.getInstance = getInstance;
  15534. exports.registerPainter = registerPainter;
  15535. exports.matrix = matrix;
  15536. exports.vector = vector;
  15537. exports.color = color;
  15538. exports.path = path;
  15539. exports.util = util;
  15540. exports.Group = Group;
  15541. exports.Path = Path;
  15542. exports.Image = ZImage;
  15543. exports.CompoundPath = CompoundPath;
  15544. exports.Text = Text;
  15545. exports.Arc = Arc;
  15546. exports.BezierCurve = BezierCurve;
  15547. exports.Circle = Circle;
  15548. exports.Droplet = Droplet;
  15549. exports.Ellipse = Ellipse;
  15550. exports.Heart = Heart;
  15551. exports.Isogon = Isogon;
  15552. exports.Line = Line;
  15553. exports.Polygon = Polygon;
  15554. exports.Polyline = Polyline;
  15555. exports.Rect = Rect;
  15556. exports.Ring = Ring;
  15557. exports.Rose = Rose;
  15558. exports.Sector = Sector;
  15559. exports.Star = Star;
  15560. exports.Trochoid = Trochoid;
  15561. exports.LinearGradient = LinearGradient;
  15562. exports.RadialGradient = RadialGradient;
  15563. exports.Pattern = Pattern;
  15564. exports.BoundingRect = BoundingRect;
  15565. })));
  15566. //# sourceMappingURL=zrender.js.map