two.module.js 422 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403
  1. /*
  2. MIT License
  3. Copyright (c) 2012 - 2021 jonobr1 / http://jonobr1.com
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. */
  20. /**
  21. * @name Two.Commands
  22. * @property {Object} - Map of possible path commands. Taken from the SVG specification.
  23. */
  24. var Commands = {
  25. move: 'M',
  26. line: 'L',
  27. curve: 'C',
  28. arc: 'A',
  29. close: 'Z'
  30. };
  31. var root;
  32. if (typeof window !== 'undefined') {
  33. root = window;
  34. } else if (typeof global !== 'undefined') {
  35. root = global;
  36. } else if (typeof self !== 'undefined') {
  37. root = self;
  38. }
  39. var root$1 = root;
  40. var Matrix$1;
  41. /**
  42. * @name Two.Utils.decomposeMatrix
  43. * @function
  44. * @param {Two.Matrix} matrix - The matrix to decompose.
  45. * @returns {Object} An object containing relevant skew values.
  46. * @description Decompose a 2D 3x3 Matrix to find the skew.
  47. */
  48. var decomposeMatrix = function(matrix) {
  49. // TODO: Include skewX, skewY
  50. // https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati/417813
  51. // https://stackoverflow.com/questions/45159314/decompose-2d-transformation-matrix
  52. return {
  53. translateX: matrix.e,
  54. translateY: matrix.f,
  55. scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
  56. scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
  57. rotation: 180 * Math.atan2(matrix.b, matrix.a) / Math.PI
  58. };
  59. };
  60. var setMatrix = function(M) {
  61. Matrix$1 = M;
  62. };
  63. /**
  64. * @name Two.Utils.getComputedMatrix
  65. * @function
  66. * @param {Two.Shape} object - The Two.js object that has a matrix property to calculate from.
  67. * @param {Two.Matrix} [matrix] - The matrix to apply calculated transformations to if available.
  68. * @returns {Two.Matrix} The computed matrix of a nested object. If no `matrix` was passed in arguments then a `new Two.Matrix` is returned.
  69. * @description Method to get the world space transformation of a given object in a Two.js scene.
  70. */
  71. var getComputedMatrix = function(object, matrix) {
  72. matrix = (matrix && matrix.identity()) || new Matrix$1();
  73. var parent = object, matrices = [];
  74. while (parent && parent._matrix) {
  75. matrices.push(parent._matrix);
  76. parent = parent.parent;
  77. }
  78. matrices.reverse();
  79. for (var i = 0; i < matrices.length; i++) {
  80. var m = matrices[i];
  81. var e = m.elements;
  82. matrix.multiply(
  83. e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9]);
  84. }
  85. return matrix;
  86. };
  87. /**
  88. * @name Two.Utils.lerp
  89. * @function
  90. * @param {Number} a - Start value.
  91. * @param {Number} b - End value.
  92. * @param {Number} t - Zero-to-one value describing percentage between a and b.
  93. * @returns {Number}
  94. * @description Linear interpolation between two values `a` and `b` by an amount `t`.
  95. */
  96. var lerp = function(a, b, t) {
  97. return t * (b - a) + a;
  98. };
  99. /**
  100. * @name Two.Utils.mod
  101. * @function
  102. * @param {Number} v - The value to modulo
  103. * @param {Number} l - The value to modulo by
  104. * @returns {Number}
  105. * @description Modulo with added functionality to handle negative values in a positive manner.
  106. */
  107. var mod = function(v, l) {
  108. while (v < 0) {
  109. v += l;
  110. }
  111. return v % l;
  112. };
  113. var NumArray = root$1.Float32Array || Array;
  114. /**
  115. * @name Two.Utils.toFixed
  116. * @function
  117. * @param {Number} v - Any float
  118. * @returns {Number} That float trimmed to the third decimal place.
  119. * @description A pretty fast toFixed(3) alternative.
  120. * @see {@link http://jsperf.com/parsefloat-tofixed-vs-math-round/18}
  121. */
  122. var toFixed = function(v) {
  123. return Math.floor(v * 1000000) / 1000000;
  124. };
  125. var math = /*#__PURE__*/Object.freeze({
  126. __proto__: null,
  127. decomposeMatrix: decomposeMatrix,
  128. getComputedMatrix: getComputedMatrix,
  129. setMatrix: setMatrix,
  130. lerp: lerp,
  131. mod: mod,
  132. NumArray: NumArray,
  133. toFixed: toFixed
  134. });
  135. var slice = Array.prototype.slice;
  136. var isArrayLike = function(collection) {
  137. if (collection === null || collection === undefined) return false;
  138. var length = collection.length;
  139. // Arrays cannot hold more than 2^32 - 1 items
  140. return (typeof length == 'number' && length >= 0 && length < 4294967296);
  141. };
  142. var _ = {
  143. isNaN: function(obj) {
  144. return typeof obj === 'number' && obj !== +obj;
  145. },
  146. isElement: function(obj) {
  147. return !!(obj && obj.nodeType === 1);
  148. },
  149. isObject: function(obj) {
  150. var type = typeof obj;
  151. return type === 'function' || type === 'object' && !!obj;
  152. },
  153. extend: function(base) {
  154. var sources = slice.call(arguments, 1);
  155. for (var i = 0; i < sources.length; i++) {
  156. var obj = sources[i];
  157. for (var k in obj) {
  158. base[k] = obj[k];
  159. }
  160. }
  161. return base;
  162. },
  163. defaults: function(base) {
  164. var sources = slice.call(arguments, 1);
  165. for (var i = 0; i < sources.length; i++) {
  166. var obj = sources[i];
  167. for (var k in obj) {
  168. if (base[k] === void 0) {
  169. base[k] = obj[k];
  170. }
  171. }
  172. }
  173. return base;
  174. },
  175. each: function(obj, iteratee, context) {
  176. var ctx = context || this;
  177. var keys = !isArrayLike(obj) && Object.keys(obj);
  178. var length = (keys || obj).length;
  179. for (var i = 0; i < length; i++) {
  180. var k = keys ? keys[i] : i;
  181. iteratee.call(ctx, obj[k], k, obj);
  182. }
  183. return obj;
  184. },
  185. /**
  186. * @name Two.Utils.performance
  187. * @property {Date} - A special `Date` like object to get the current millis of the session. Used internally to calculate time between frames.
  188. * e.g: `Utils.performance.now() // milliseconds since epoch`
  189. */
  190. performance: ((root$1.performance && root$1.performance.now) ? root$1.performance : Date),
  191. };
  192. /**
  193. * @name Two.Events
  194. * @class
  195. * @description Object inherited by many Two.js objects in order to facilitate custom events.
  196. */
  197. var Events = {
  198. /**
  199. * @name Two.Events#on
  200. * @function
  201. * @param {String} [name] - The name of the event to bind a function to.
  202. * @param {Function} [handler] - The function to be invoked when the event is dispatched.
  203. * @description Call to add a listener to a specific event name.
  204. */
  205. on: addEventListener,
  206. /**
  207. * @name Two.Events#off
  208. * @function
  209. * @param {String} [name] - The name of the event intended to be removed.
  210. * @param {Function} [handler] - The handler intended to be reomved.
  211. * @description Call to remove listeners from a specific event. If only `name` is passed then all the handlers attached to that `name` will be removed. If no arguments are passed then all handlers for every event on the obejct are removed.
  212. */
  213. off: removeEventListener,
  214. /**
  215. * @name Two.Events#trigger
  216. * @function
  217. * @param {String} name - The name of the event to dispatch.
  218. * @param arguments - Anything can be passed after the name and those will be passed on to handlers attached to the event in the order they are passed.
  219. * @description Call to trigger a custom event. Any additional arguments passed after the name will be passed along to the attached handlers.
  220. */
  221. trigger: function(name) {
  222. var scope = this;
  223. if (!scope._events) return scope;
  224. var args = Array.prototype.slice.call(arguments, 1);
  225. var events = scope._events[name];
  226. if (events) dispatch(scope, events, args);
  227. return scope;
  228. },
  229. listen: function(obj, name, handler) {
  230. var bound = this;
  231. if (obj) {
  232. var event = function () {
  233. handler.apply(bound, arguments);
  234. };
  235. // Add references about the object that assigned this listener
  236. event.obj = obj;
  237. event.name = name;
  238. event.handler = handler;
  239. obj.on(name, event);
  240. }
  241. return bound;
  242. },
  243. ignore: function(obj, name, handler) {
  244. var scope = this;
  245. obj.off(name, handler);
  246. return scope;
  247. },
  248. /**
  249. * @name Two.Events.Types
  250. * @property {Object} - Object of different types of Two.js specific events.
  251. */
  252. Types: {
  253. play: 'play',
  254. pause: 'pause',
  255. update: 'update',
  256. render: 'render',
  257. resize: 'resize',
  258. change: 'change',
  259. remove: 'remove',
  260. insert: 'insert',
  261. order: 'order',
  262. load: 'load'
  263. }
  264. };
  265. /**
  266. * @name Two.Events.bind
  267. * @function
  268. * @description Alias for {@link Two.Events.on}.
  269. */
  270. Events.bind = addEventListener;
  271. /**
  272. * @name Two.Events.unbind
  273. * @function
  274. * @description Alias for {@link Two.Events.off}.
  275. */
  276. Events.unbind = removeEventListener;
  277. /**
  278. * @private
  279. * @returns {Two.Events} - Returns an instance of self for the purpose of chaining.
  280. */
  281. function addEventListener(name, handler) {
  282. var scope = this;
  283. scope._events || (scope._events = {});
  284. var list = scope._events[name] || (scope._events[name] = []);
  285. list.push(handler);
  286. return scope;
  287. }
  288. /**
  289. * @private
  290. * @returns {Two.Events} - Returns an instance of self for the purpose of chaining.
  291. */
  292. function removeEventListener(name, handler) {
  293. var scope = this;
  294. if (!scope._events) {
  295. return scope;
  296. }
  297. if (!name && !handler) {
  298. scope._events = {};
  299. return scope;
  300. }
  301. var names = name ? [name] : Object.keys(scope._events);
  302. for (var i = 0, l = names.length; i < l; i++) {
  303. name = names[i];
  304. var list = scope._events[name];
  305. if (list) {
  306. var events = [];
  307. if (handler) {
  308. for (var j = 0, k = list.length; j < k; j++) {
  309. var ev = list[j];
  310. ev = ev.handler ? ev.handler : ev;
  311. if (handler && handler !== ev) {
  312. events.push(ev);
  313. }
  314. }
  315. }
  316. scope._events[name] = events;
  317. }
  318. }
  319. return scope;
  320. }
  321. function dispatch(obj, events, args) {
  322. var method;
  323. switch (args.length) {
  324. case 0:
  325. method = function(i) {
  326. events[i].call(obj, args[0]);
  327. };
  328. break;
  329. case 1:
  330. method = function(i) {
  331. events[i].call(obj, args[0], args[1]);
  332. };
  333. break;
  334. case 2:
  335. method = function(i) {
  336. events[i].call(obj, args[0], args[1], args[2]);
  337. };
  338. break;
  339. case 3:
  340. method = function(i) {
  341. events[i].call(obj, args[0], args[1], args[2], args[3]);
  342. };
  343. break;
  344. default:
  345. method = function(i) {
  346. events[i].apply(obj, args);
  347. };
  348. }
  349. for (var i = 0; i < events.length; i++) {
  350. method(i);
  351. }
  352. }
  353. /**
  354. * @name Two.Vector
  355. * @class
  356. * @param {Number} [x=0] - Any number to represent the horizontal x-component of the vector.
  357. * @param {Number} [y=0] - Any number to represent the vertical y-component of the vector.
  358. * @description A class to store x / y component vector data. In addition to storing data `Two.Vector` has suped up methods for commonplace mathematical operations.
  359. */
  360. function Vector(x, y) {
  361. /**
  362. * @name Two.Vector#x
  363. * @property {Number} - The horizontal x-component of the vector.
  364. */
  365. this.x = x || 0;
  366. /**
  367. * @name Two.Vector#y
  368. * @property {Number} - The vertical y-component of the vector.
  369. */
  370. this.y = y || 0;
  371. }
  372. _.extend(Vector, {
  373. /**
  374. * @name Two.Vector.zero
  375. * @readonly
  376. * @property {Two.Vector} - Handy reference to a vector with component values 0, 0 at all times.
  377. */
  378. zero: new Vector(),
  379. /**
  380. * @name Two.Vector.add
  381. * @function
  382. * @param {Two.Vector} v1
  383. * @param {Two.Vector} v2
  384. * @returns {Two.Vector}
  385. * @description Add two vectors together.
  386. */
  387. add: function(v1, v2) {
  388. return new Vector(v1.x + v2.x, v1.y + v2.y);
  389. },
  390. /**
  391. * @name Two.Vector.sub
  392. * @function
  393. * @param {Two.Vector} v1
  394. * @param {Two.Vector} v2
  395. * @returns {Two.Vector}
  396. * @description Subtract two vectors: `v2` from `v1`.
  397. */
  398. sub: function(v1, v2) {
  399. return new Vector(v1.x - v2.x, v1.y - v2.y);
  400. },
  401. /**
  402. * @name Two.Vector.subtract
  403. * @function
  404. * @description Alias for {@link Two.Vector.sub}.
  405. */
  406. subtract: function(v1, v2) {
  407. return Vector.sub(v1, v2);
  408. },
  409. /**
  410. * @name Two.Vector.ratioBetween
  411. * @function
  412. * @param {Two.Vector} A
  413. * @param {Two.Vector} B
  414. * @returns {Number} The ratio betwen two points `v1` and `v2`.
  415. */
  416. ratioBetween: function(v1, v2) {
  417. return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length());
  418. },
  419. /**
  420. * @name Two.Vector.angleBetween
  421. * @function
  422. * @param {Two.Vector} v1
  423. * @param {Two.Vector} v2
  424. * @returns {Number} The angle between points `v1` and `v2`.
  425. */
  426. angleBetween: function(v1, v2) {
  427. var dx, dy;
  428. if (arguments.length >= 4) {
  429. dx = arguments[0] - arguments[2];
  430. dy = arguments[1] - arguments[3];
  431. return Math.atan2(dy, dx);
  432. }
  433. dx = v1.x - v2.x;
  434. dy = v1.y - v2.y;
  435. return Math.atan2(dy, dx);
  436. },
  437. /**
  438. * @name Two.Vector.distanceBetween
  439. * @function
  440. * @param {Two.Vector} v1
  441. * @param {Two.Vector} v2
  442. * @returns {Number} The distance between points `v1` and `v2`. Distance is always positive.
  443. */
  444. distanceBetween: function(v1, v2) {
  445. return Math.sqrt(Vector.distanceBetweenSquared(v1, v2));
  446. },
  447. /**
  448. * @name Two.Vector.distanceBetweenSquared
  449. * @function
  450. * @param {Two.Vector} v1
  451. * @param {Two.Vector} v2
  452. * @returns {Number} The squared distance between points `v1` and `v2`.
  453. */
  454. distanceBetweenSquared: function(v1, v2) {
  455. var dx = v1.x - v2.x;
  456. var dy = v1.y - v2.y;
  457. return dx * dx + dy * dy;
  458. },
  459. /**
  460. * @name Two.Vector.MakeObservable
  461. * @function
  462. * @param {Object} object - The object to make observable.
  463. * @description Convenience function to apply observable qualities of a {@link Two.Vector} to any object. Handy if you'd like to extend the {@link Two.Vector} class on a custom class.
  464. */
  465. MakeObservable: function(object) {
  466. // /**
  467. // * Override Backbone bind / on in order to add properly broadcasting.
  468. // * This allows Two.Vector to not broadcast events unless event listeners
  469. // * are explicity bound to it.
  470. // */
  471. object.bind = object.on = function() {
  472. if (!this._bound) {
  473. this._x = this.x;
  474. this._y = this.y;
  475. Object.defineProperty(this, 'x', xgs);
  476. Object.defineProperty(this, 'y', ygs);
  477. _.extend(this, BoundProto);
  478. this._bound = true; // Reserved for event initialization check
  479. }
  480. Events.bind.apply(this, arguments);
  481. return this;
  482. };
  483. }
  484. });
  485. _.extend(Vector.prototype, Events, {
  486. constructor: Vector,
  487. /**
  488. * @name Two.Vector#set
  489. * @function
  490. * @param {Number} x
  491. * @param {Number} y
  492. * @description Set the x / y components of a vector to specific number values.
  493. */
  494. set: function(x, y) {
  495. this.x = x;
  496. this.y = y;
  497. return this;
  498. },
  499. /**
  500. * @name Two.Vector#copy
  501. * @function
  502. * @param {Two.Vector} v
  503. * @description Copy the x / y components of another object `v`.
  504. */
  505. copy: function(v) {
  506. this.x = v.x;
  507. this.y = v.y;
  508. return this;
  509. },
  510. /**
  511. * @name Two.Vector#clear
  512. * @function
  513. * @description Set the x / y component values of the vector to zero.
  514. */
  515. clear: function() {
  516. this.x = 0;
  517. this.y = 0;
  518. return this;
  519. },
  520. /**
  521. * @name Two.Vector#clone
  522. * @function
  523. * @description Create a new vector and copy the existing values onto the newly created instance.
  524. */
  525. clone: function() {
  526. return new Vector(this.x, this.y);
  527. },
  528. /**
  529. * @name Two.Vector#add
  530. * @function
  531. * @param {Two.Vector} v
  532. * @description Add an object with x / y component values to the instance.
  533. * @overloaded
  534. */
  535. /**
  536. * @name Two.Vector#add
  537. * @function
  538. * @param {Number} v
  539. * @description Add the **same** number to both x / y component values of the instance.
  540. * @overloaded
  541. */
  542. /**
  543. * @name Two.Vector#add
  544. * @function
  545. * @param {Number} x
  546. * @param {Number} y
  547. * @description Add `x` / `y` values to their respective component value on the instance.
  548. * @overloaded
  549. */
  550. add: function(x, y) {
  551. if (arguments.length <= 0) {
  552. return this;
  553. } else if (arguments.length <= 1) {
  554. if (typeof x === 'number') {
  555. this.x += x;
  556. this.y += x;
  557. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  558. this.x += x.x;
  559. this.y += x.y;
  560. }
  561. } else {
  562. this.x += x;
  563. this.y += y;
  564. }
  565. return this;
  566. },
  567. /**
  568. * @name Two.Vector#addSelf
  569. * @function
  570. * @description Alias for {@link Two.Vector.add}.
  571. */
  572. addSelf: function(v) {
  573. return this.add.apply(this, arguments);
  574. },
  575. /**
  576. * @name Two.Vector#sub
  577. * @function
  578. * @param {Two.Vector} v
  579. * @description Subtract an object with x / y component values to the instance.
  580. * @overloaded
  581. */
  582. /**
  583. * @name Two.Vector#sub
  584. * @function
  585. * @param {Number} v
  586. * @description Subtract the **same** number to both x / y component values of the instance.
  587. * @overloaded
  588. */
  589. /**
  590. * @name Two.Vector#sub
  591. * @function
  592. * @param {Number} x
  593. * @param {Number} y
  594. * @description Subtract `x` / `y` values to their respective component value on the instance.
  595. * @overloaded
  596. */
  597. sub: function(x, y) {
  598. if (arguments.length <= 0) {
  599. return this;
  600. } else if (arguments.length <= 1) {
  601. if (typeof x === 'number') {
  602. this.x -= x;
  603. this.y -= x;
  604. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  605. this.x -= x.x;
  606. this.y -= x.y;
  607. }
  608. } else {
  609. this.x -= x;
  610. this.y -= y;
  611. }
  612. return this;
  613. },
  614. /**
  615. * @name Two.Vector#subtract
  616. * @function
  617. * @description Alias for {@link Two.Vector.sub}.
  618. */
  619. subtract: function() {
  620. return this.sub.apply(this, arguments);
  621. },
  622. /**
  623. * @name Two.Vector#subSelf
  624. * @function
  625. * @description Alias for {@link Two.Vector.sub}.
  626. */
  627. subSelf: function(v) {
  628. return this.sub.apply(this, arguments);
  629. },
  630. /**
  631. * @name Two.Vector#subtractSelf
  632. * @function
  633. * @description Alias for {@link Two.Vector.sub}.
  634. */
  635. subtractSelf: function(v) {
  636. return this.sub.apply(this, arguments);
  637. },
  638. /**
  639. * @name Two.Vector#multiply
  640. * @function
  641. * @param {Two.Vector} v
  642. * @description Multiply an object with x / y component values to the instance.
  643. * @overloaded
  644. */
  645. /**
  646. * @name Two.Vector#multiply
  647. * @function
  648. * @param {Number} v
  649. * @description Multiply the **same** number to both x / y component values of the instance.
  650. * @overloaded
  651. */
  652. /**
  653. * @name Two.Vector#multiply
  654. * @function
  655. * @param {Number} x
  656. * @param {Number} y
  657. * @description Multiply `x` / `y` values to their respective component value on the instance.
  658. * @overloaded
  659. */
  660. multiply: function(x, y) {
  661. if (arguments.length <= 0) {
  662. return this;
  663. } else if (arguments.length <= 1) {
  664. if (typeof x === 'number') {
  665. this.x *= x;
  666. this.y *= x;
  667. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  668. this.x *= x.x;
  669. this.y *= x.y;
  670. }
  671. } else {
  672. this.x *= x;
  673. this.y *= y;
  674. }
  675. return this;
  676. },
  677. /**
  678. * @name Two.Vector#multiplySelf
  679. * @function
  680. * @description Alias for {@link Two.Vector.multiply}.
  681. */
  682. multiplySelf: function(v) {
  683. return this.multiply.apply(this, arguments);
  684. },
  685. /**
  686. * @name Two.Vector#multiplyScalar
  687. * @function
  688. * @param {Number} s - The scalar to multiply by.
  689. * @description Mulitiply the vector by a single number. Shorthand to call {@link Two.Vector#multiply} directly.
  690. */
  691. multiplyScalar: function(s) {
  692. return this.multiply(s);
  693. },
  694. /**
  695. * @name Two.Vector#divide
  696. * @function
  697. * @param {Two.Vector} v
  698. * @description Divide an object with x / y component values to the instance.
  699. * @overloaded
  700. */
  701. /**
  702. * @name Two.Vector#divide
  703. * @function
  704. * @param {Number} v
  705. * @description Divide the **same** number to both x / y component values of the instance.
  706. * @overloaded
  707. */
  708. /**
  709. * @name Two.Vector#divide
  710. * @function
  711. * @param {Number} x
  712. * @param {Number} y
  713. * @description Divide `x` / `y` values to their respective component value on the instance.
  714. * @overloaded
  715. */
  716. divide: function(x, y) {
  717. if (arguments.length <= 0) {
  718. return this;
  719. } else if (arguments.length <= 1) {
  720. if (typeof x === 'number') {
  721. this.x /= x;
  722. this.y /= x;
  723. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  724. this.x /= x.x;
  725. this.y /= x.y;
  726. }
  727. } else {
  728. this.x /= x;
  729. this.y /= y;
  730. }
  731. if (_.isNaN(this.x)) {
  732. this.x = 0;
  733. }
  734. if (_.isNaN(this.y)) {
  735. this.y = 0;
  736. }
  737. return this;
  738. },
  739. /**
  740. * @name Two.Vector#divideSelf
  741. * @function
  742. * @description Alias for {@link Two.Vector.divide}.
  743. */
  744. divideSelf: function(v) {
  745. return this.divide.apply(this, arguments);
  746. },
  747. /**
  748. * @name Two.Vector#divideScalar
  749. * @function
  750. * @param {Number} s - The scalar to divide by.
  751. * @description Divide the vector by a single number. Shorthand to call {@link Two.Vector#divide} directly.
  752. */
  753. divideScalar: function(s) {
  754. return this.divide(s);
  755. },
  756. /**
  757. * @name Two.Vector#negate
  758. * @function
  759. * @description Invert each component's sign value.
  760. */
  761. negate: function() {
  762. return this.multiply(-1);
  763. },
  764. /**
  765. * @name Two.Vector#negate
  766. * @function
  767. * @returns {Number}
  768. * @description Get the [dot product](https://en.wikipedia.org/wiki/Dot_product) of the vector.
  769. */
  770. dot: function(v) {
  771. return this.x * v.x + this.y * v.y;
  772. },
  773. /**
  774. * @name Two.Vector#length
  775. * @function
  776. * @returns {Number}
  777. * @description Get the length of a vector.
  778. */
  779. length: function() {
  780. return Math.sqrt(this.lengthSquared());
  781. },
  782. /**
  783. * @name Two.Vector#lengthSquared
  784. * @function
  785. * @returns {Number}
  786. * @description Get the length of the vector to the power of two. Widely used as less expensive than {@link Two.Vector#length}, because it isn't square-rooting any numbers.
  787. */
  788. lengthSquared: function() {
  789. return this.x * this.x + this.y * this.y;
  790. },
  791. /**
  792. * @name Two.Vector#normalize
  793. * @function
  794. * @description Normalize the vector from negative one to one.
  795. */
  796. normalize: function() {
  797. return this.divideScalar(this.length());
  798. },
  799. /**
  800. * @name Two.Vector#distanceTo
  801. * @function
  802. * @returns {Number}
  803. * @description Get the distance between two vectors.
  804. */
  805. distanceTo: function(v) {
  806. return Math.sqrt(this.distanceToSquared(v));
  807. },
  808. /**
  809. * @name Two.Vector#distanceToSquared
  810. * @function
  811. * @returns {Number}
  812. * @description Get the distance between two vectors to the power of two. Widely used as less expensive than {@link Two.Vector#distanceTo}, because it isn't square-rooting any numbers.
  813. */
  814. distanceToSquared: function(v) {
  815. var dx = this.x - v.x,
  816. dy = this.y - v.y;
  817. return dx * dx + dy * dy;
  818. },
  819. /**
  820. * @name Two.Vector#setLength
  821. * @function
  822. * @param {Number} l - length to set vector to.
  823. * @description Set the length of a vector.
  824. */
  825. setLength: function(l) {
  826. return this.normalize().multiplyScalar(l);
  827. },
  828. /**
  829. * @name Two.Vector#equals
  830. * @function
  831. * @param {Two.Vector} v - The vector to compare against.
  832. * @param {Number} [eps=0.0001] - An options epsilon for precision.
  833. * @returns {Boolean}
  834. * @description Qualify if one vector roughly equal another. With a margin of error defined by epsilon.
  835. */
  836. equals: function(v, eps) {
  837. eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  838. return (this.distanceTo(v) < eps);
  839. },
  840. /**
  841. * @name Two.Vector#lerp
  842. * @function
  843. * @param {Two.Vector} v - The destination vector to step towards.
  844. * @param {Number} t - The zero to one value of how close the current vector gets to the destination vector.
  845. * @description Linear interpolate one vector to another by an amount `t` defined as a zero to one number.
  846. * @see [Matt DesLauriers](https://twitter.com/mattdesl/status/1031305279227478016) has a good thread about this.
  847. */
  848. lerp: function(v, t) {
  849. var x = (v.x - this.x) * t + this.x;
  850. var y = (v.y - this.y) * t + this.y;
  851. return this.set(x, y);
  852. },
  853. /**
  854. * @name Two.Vector#isZero
  855. * @function
  856. * @param {Number} [eps=0.0001] - Optional precision amount to check against.
  857. * @returns {Boolean}
  858. * @description Check to see if vector is roughly zero, based on the `epsilon` precision value.
  859. */
  860. isZero: function(eps) {
  861. eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  862. return (this.length() < eps);
  863. },
  864. /**
  865. * @name Two.Vector#toString
  866. * @function
  867. * @returns {String}
  868. * @description Return a comma-separated string of x, y value. Great for storing in a database.
  869. */
  870. toString: function() {
  871. return this.x + ', ' + this.y;
  872. },
  873. /**
  874. * @name Two.Vector#toObject
  875. * @function
  876. * @returns {Object}
  877. * @description Return a JSON compatible plain object that represents the vector.
  878. */
  879. toObject: function() {
  880. return { x: this.x, y: this.y };
  881. },
  882. /**
  883. * @name Two.Vector#rotate
  884. * @function
  885. * @param {Number} Number - The amoun to rotate the vector by.
  886. * @description Rotate a vector.
  887. */
  888. rotate: function(Number) {
  889. var cos = Math.cos(Number);
  890. var sin = Math.sin(Number);
  891. this.x = this.x * cos - this.y * sin;
  892. this.y = this.x * sin + this.y * cos;
  893. return this;
  894. }
  895. });
  896. // The same set of prototypical functions, but using the underlying
  897. // getter or setter for `x` and `y` values. This set of functions
  898. // is used instead of the previously documented ones above when
  899. // Two.Vector#bind is invoked and there is event dispatching processed
  900. // on x / y property changes.
  901. var BoundProto = {
  902. constructor: Vector,
  903. set: function(x, y) {
  904. this._x = x;
  905. this._y = y;
  906. return this.trigger(Events.Types.change);
  907. },
  908. copy: function(v) {
  909. this._x = v.x;
  910. this._y = v.y;
  911. return this.trigger(Events.Types.change);
  912. },
  913. clear: function() {
  914. this._x = 0;
  915. this._y = 0;
  916. return this.trigger(Events.Types.change);
  917. },
  918. clone: function() {
  919. return new Vector(this._x, this._y);
  920. },
  921. add: function(x, y) {
  922. if (arguments.length <= 0) {
  923. return this;
  924. } else if (arguments.length <= 1) {
  925. if (typeof x === 'number') {
  926. this._x += x;
  927. this._y += x;
  928. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  929. this._x += x.x;
  930. this._y += x.y;
  931. }
  932. } else {
  933. this._x += x;
  934. this._y += y;
  935. }
  936. return this.trigger(Events.Types.change);
  937. },
  938. sub: function(x, y) {
  939. if (arguments.length <= 0) {
  940. return this;
  941. } else if (arguments.length <= 1) {
  942. if (typeof x === 'number') {
  943. this._x -= x;
  944. this._y -= x;
  945. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  946. this._x -= x.x;
  947. this._y -= x.y;
  948. }
  949. } else {
  950. this._x -= x;
  951. this._y -= y;
  952. }
  953. return this.trigger(Events.Types.change);
  954. },
  955. multiply: function(x, y) {
  956. if (arguments.length <= 0) {
  957. return this;
  958. } else if (arguments.length <= 1) {
  959. if (typeof x === 'number') {
  960. this._x *= x;
  961. this._y *= x;
  962. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  963. this._x *= x.x;
  964. this._y *= x.y;
  965. }
  966. } else {
  967. this._x *= x;
  968. this._y *= y;
  969. }
  970. return this.trigger(Events.Types.change);
  971. },
  972. divide: function(x, y) {
  973. if (arguments.length <= 0) {
  974. return this;
  975. } else if (arguments.length <= 1) {
  976. if (typeof x === 'number') {
  977. this._x /= x;
  978. this._y /= x;
  979. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  980. this._x /= x.x;
  981. this._y /= x.y;
  982. }
  983. } else {
  984. this._x /= x;
  985. this._y /= y;
  986. }
  987. if (_.isNaN(this._x)) {
  988. this._x = 0;
  989. }
  990. if (_.isNaN(this._y)) {
  991. this._y = 0;
  992. }
  993. return this.trigger(Events.Types.change);
  994. },
  995. dot: function(v) {
  996. return this._x * v.x + this._y * v.y;
  997. },
  998. lengthSquared: function() {
  999. return this._x * this._x + this._y * this._y;
  1000. },
  1001. distanceToSquared: function(v) {
  1002. var dx = this._x - v.x,
  1003. dy = this._y - v.y;
  1004. return dx * dx + dy * dy;
  1005. },
  1006. lerp: function(v, t) {
  1007. var x = (v.x - this._x) * t + this._x;
  1008. var y = (v.y - this._y) * t + this._y;
  1009. return this.set(x, y);
  1010. },
  1011. toString: function() {
  1012. return this._x + ', ' + this._y;
  1013. },
  1014. toObject: function() {
  1015. return { x: this._x, y: this._y };
  1016. },
  1017. rotate: function (Number) {
  1018. var cos = Math.cos(Number);
  1019. var sin = Math.sin(Number);
  1020. this._x = this._x * cos - this._y * sin;
  1021. this._y = this._x * sin + this._y * cos;
  1022. return this;
  1023. }
  1024. };
  1025. var xgs = {
  1026. enumerable: true,
  1027. get: function() {
  1028. return this._x;
  1029. },
  1030. set: function(v) {
  1031. this._x = v;
  1032. this.trigger(Events.Types.change, 'x');
  1033. }
  1034. };
  1035. var ygs = {
  1036. enumerable: true,
  1037. get: function() {
  1038. return this._y;
  1039. },
  1040. set: function(v) {
  1041. this._y = v;
  1042. this.trigger(Events.Types.change, 'y');
  1043. }
  1044. };
  1045. Vector.MakeObservable(Vector.prototype);
  1046. /**
  1047. * @class
  1048. * @name Two.Anchor
  1049. * @param {Number} [x=0] - The x position of the root anchor point.
  1050. * @param {Number} [y=0] - The y position of the root anchor point.
  1051. * @param {Number} [lx=0] - The x position of the left handle point.
  1052. * @param {Number} [ly=0] - The y position of the left handle point.
  1053. * @param {Number} [rx=0] - The x position of the right handle point.
  1054. * @param {Number} [ry=0] - The y position of the right handle point.
  1055. * @param {String} [command=Two.Commands.move] - The command to describe how to render. Applicable commands are {@link Two.Commands}
  1056. * @extends Two.Vector
  1057. * @description An object that holds 3 {@link Two.Vector}s, the anchor point and its corresponding handles: `left` and `right`. In order to properly describe the bezier curve about the point there is also a command property to describe what type of drawing should occur when Two.js renders the anchors.
  1058. */
  1059. function Anchor(x, y, lx, ly, rx, ry, command) {
  1060. Vector.call(this, x, y);
  1061. this._broadcast = (function() {
  1062. this.trigger(Events.Types.change);
  1063. }).bind(this);
  1064. this._command = command || Commands.move;
  1065. this._relative = true;
  1066. var ilx = typeof lx === 'number';
  1067. var ily = typeof ly === 'number';
  1068. var irx = typeof rx === 'number';
  1069. var iry = typeof ry === 'number';
  1070. // Append the `controls` object only if control points are specified,
  1071. // keeping the Two.Anchor inline with a Two.Vector until it needs to
  1072. // evolve beyond those functions - e.g: a simple 2 component vector.
  1073. if (ilx || ily || irx || iry) {
  1074. Anchor.AppendCurveProperties(this);
  1075. }
  1076. if (ilx) {
  1077. this.controls.left.x = lx;
  1078. }
  1079. if (ily) {
  1080. this.controls.left.y = ly;
  1081. }
  1082. if (irx) {
  1083. this.controls.right.x = rx;
  1084. }
  1085. if (iry) {
  1086. this.controls.right.y = ry;
  1087. }
  1088. }
  1089. _.extend(Anchor, {
  1090. /**
  1091. * @name Two.Anchor.AppendCurveProperties
  1092. * @function
  1093. * @param {Two.Anchor} anchor - The instance to append the `control`object to.
  1094. * @description Adds the `controls` property as an object with `left` and `right` properties to access the bezier control handles that define how the curve is drawn. It also sets the `relative` property to `true` making vectors in the `controls` object relative to their corresponding root anchor point.
  1095. */
  1096. AppendCurveProperties: function(anchor) {
  1097. anchor.relative = true;
  1098. /**
  1099. * @name Two.Anchor#controls
  1100. * @property {Object} controls
  1101. * @description An plain object that holds the controls handles for a {@link Two.Anchor}.
  1102. */
  1103. anchor.controls = {};
  1104. /**
  1105. * @name Two.Anchor#controls#left
  1106. * @property {Two.Vector} left
  1107. * @description The "left" control point to define handles on a bezier curve.
  1108. */
  1109. anchor.controls.left = new Vector(0, 0);
  1110. /**
  1111. * @name Two.Anchor#controls#right
  1112. * @property {Two.Vector} right
  1113. * @description The "left" control point to define handles on a bezier curve.
  1114. */
  1115. anchor.controls.right = new Vector(0, 0);
  1116. },
  1117. /**
  1118. * @name Two.Anchor.MakeObservable
  1119. * @function
  1120. * @param {Object} object - The object to make observable.
  1121. * @description Convenience function to apply observable qualities of a {@link Two.Anchor} to any object. Handy if you'd like to extend the {@link Two.Anchor} class on a custom class.
  1122. */
  1123. MakeObservable: function(object) {
  1124. /**
  1125. * @name Two.Anchor#command
  1126. * @property {Two.Commands}
  1127. * @description A draw command associated with the anchor point.
  1128. */
  1129. Object.defineProperty(object, 'command', {
  1130. enumerable: true,
  1131. get: function() {
  1132. return this._command;
  1133. },
  1134. set: function(c) {
  1135. this._command = c;
  1136. if (this._command === Commands.curve && !_.isObject(this.controls)) {
  1137. Anchor.AppendCurveProperties(this);
  1138. }
  1139. this.trigger(Events.Types.change);
  1140. }
  1141. });
  1142. /**
  1143. * @name Two.Anchor#relative
  1144. * @property {Boolean}
  1145. * @description A boolean to render control points relative to the root anchor point or in global coordinate-space to the rest of the scene.
  1146. */
  1147. Object.defineProperty(object, 'relative', {
  1148. enumerable: true,
  1149. get: function() {
  1150. return this._relative;
  1151. },
  1152. set: function(b) {
  1153. if (this._relative != b) {
  1154. this._relative = !!b;
  1155. this.trigger(Events.Types.change);
  1156. }
  1157. }
  1158. });
  1159. _.extend(object, Vector.prototype, AnchorProto);
  1160. // Make it possible to bind and still have the Anchor specific
  1161. // inheritance from Two.Vector. In this case relying on `Two.Vector`
  1162. // to do much of the heavy event-listener binding / unbinding.
  1163. object.bind = object.on = function() {
  1164. var bound = this._bound;
  1165. Vector.prototype.bind.apply(this, arguments);
  1166. if (!bound) {
  1167. _.extend(this, AnchorProto);
  1168. }
  1169. };
  1170. }
  1171. });
  1172. var AnchorProto = {
  1173. constructor: Anchor,
  1174. /**
  1175. * @name Two.Anchor#listen
  1176. * @function
  1177. * @description Convenience method used mainly by {@link Two.Path#vertices} to listen and propagate changes from control points up to their respective anchors and further if necessary.
  1178. */
  1179. listen: function() {
  1180. if (!_.isObject(this.controls)) {
  1181. Anchor.AppendCurveProperties(this);
  1182. }
  1183. this.controls.left.bind(Events.Types.change, this._broadcast);
  1184. this.controls.right.bind(Events.Types.change, this._broadcast);
  1185. return this;
  1186. },
  1187. /**
  1188. * @name Two.Anchor#ignore
  1189. * @function
  1190. * @description Convenience method used mainly by {@link Two.Path#vertices} to ignore changes from a specific anchor's control points.
  1191. */
  1192. ignore: function() {
  1193. this.controls.left.unbind(Events.Types.change, this._broadcast);
  1194. this.controls.right.unbind(Events.Types.change, this._broadcast);
  1195. return this;
  1196. },
  1197. /**
  1198. * @name Two.Anchor#copy
  1199. * @function
  1200. * @param {Two.Anchor} v - The anchor to apply values to.
  1201. * @description Copy the properties of one {@link Two.Anchor} onto another.
  1202. */
  1203. copy: function(v) {
  1204. this.x = v.x;
  1205. this.y = v.y;
  1206. if (typeof v.command === 'string') {
  1207. this.command = v.command;
  1208. }
  1209. if (_.isObject(v.controls)) {
  1210. if (!_.isObject(this.controls)) {
  1211. Anchor.AppendCurveProperties(this);
  1212. }
  1213. // TODO: Do we need to listen here?
  1214. this.controls.left.copy(v.controls.left);
  1215. this.controls.right.copy(v.controls.right);
  1216. }
  1217. if (typeof v.relative === 'boolean') {
  1218. this.relative = v.relative;
  1219. }
  1220. // TODO: Hack for `Two.Commands.arc`
  1221. if (this.command === Commands.arc) {
  1222. this.rx = v.rx;
  1223. this.ry = v.ry;
  1224. this.xAxisRotation = v.xAxisRotation;
  1225. this.largeArcFlag = v.largeArcFlag;
  1226. this.sweepFlag = v.sweepFlag;
  1227. }
  1228. return this;
  1229. },
  1230. /**
  1231. * @name Two.Anchor#clone
  1232. * @function
  1233. * @returns {Two.Anchor}
  1234. * @description Create a new {@link Two.Anchor}, set all its values to the current instance and return it for use.
  1235. */
  1236. clone: function() {
  1237. var controls = this.controls;
  1238. var clone = new Anchor(
  1239. this.x,
  1240. this.y,
  1241. controls && controls.left.x,
  1242. controls && controls.left.y,
  1243. controls && controls.right.x,
  1244. controls && controls.right.y,
  1245. this.command
  1246. );
  1247. clone.relative = this._relative;
  1248. return clone;
  1249. },
  1250. /**
  1251. * @name Two.Anchor#toObject
  1252. * @function
  1253. * @returns {Object} - An object with properties filled out to mirror {@link Two.Anchor}.
  1254. * @description Create a JSON compatible plain object of the current instance. Intended for use with storing values in a database.
  1255. */
  1256. toObject: function() {
  1257. var o = {
  1258. x: this.x,
  1259. y: this.y
  1260. };
  1261. if (this._command) {
  1262. o.command = this._command;
  1263. }
  1264. if (this._relative) {
  1265. o.relative = this._relative;
  1266. }
  1267. if (this.controls) {
  1268. o.controls = {
  1269. left: this.controls.left.toObject(),
  1270. right: this.controls.right.toObject()
  1271. };
  1272. }
  1273. return o;
  1274. },
  1275. /**
  1276. * @name Two.Anchor#toString
  1277. * @function
  1278. * @returns {String} - A String with comma-separated values reflecting the various values on the current instance.
  1279. * @description Create a string form of the current instance. Intended for use with storing values in a database. This is lighter to store than the JSON compatible {@link Two.Anchor#toObject}.
  1280. */
  1281. toString: function() {
  1282. if (!this.controls) {
  1283. return [this._x, this._y].join(', ');
  1284. }
  1285. return [this._x, this._y, this.controls.left.x, this.controls.left.y,
  1286. this.controls.right.x, this.controls.right.y, this._command,
  1287. this._relative ? 1 : 0].join(', ');
  1288. }
  1289. };
  1290. Anchor.MakeObservable(Anchor.prototype);
  1291. var count = 0;
  1292. var Constants = {
  1293. /**
  1294. * @name Two.nextFrameID
  1295. * @property {Number}
  1296. * @description The id of the next requestAnimationFrame function.
  1297. */
  1298. nextFrameID: null,
  1299. // Primitive
  1300. /**
  1301. * @name Two.Types
  1302. * @property {Object} - The different rendering types available in the library.
  1303. */
  1304. Types: {
  1305. webgl: 'WebGLRenderer',
  1306. svg: 'SVGRenderer',
  1307. canvas: 'CanvasRenderer'
  1308. },
  1309. /**
  1310. * @name Two.Version
  1311. * @property {String} - The current working version of the library.
  1312. */
  1313. Version: 'v0.7.6',
  1314. /**
  1315. * @name Two.PublishDate
  1316. * @property {String} - The automatically generated publish date in the build process to verify version release candidates.
  1317. */
  1318. PublishDate: '2021-06-08T20:19:33.699Z',
  1319. /**
  1320. * @name Two.Identifier
  1321. * @property {String} - String prefix for all Two.js object's ids. This trickles down to SVG ids.
  1322. */
  1323. Identifier: 'two-',
  1324. /**
  1325. * @name Two.Resolution
  1326. * @property {Number} - Default amount of vertices to be used for interpreting Arcs and ArcSegments.
  1327. */
  1328. Resolution: 12,
  1329. /**
  1330. * @name Two.AutoCalculateImportedMatrices
  1331. * @property {Boolean} - When importing SVGs through the {@link two#interpret} and {@link two#load}, this boolean determines whether Two.js infers and then overrides the exact transformation matrix of the reference SVG.
  1332. * @nota-bene `false` copies the exact transformation matrix values, but also sets the path's `matrix.manual = true`.
  1333. */
  1334. AutoCalculateImportedMatrices: true,
  1335. /**
  1336. * @name Two.Instances
  1337. * @property {Two[]} - Registered list of all Two.js instances in the current session.
  1338. */
  1339. Instances: [],
  1340. /**
  1341. * @function Two.uniqueId
  1342. * @description Simple method to access an incrementing value. Used for `id` allocation on all Two.js objects.
  1343. * @returns {Number} Ever increasing Number.
  1344. */
  1345. uniqueId: function() {
  1346. return count++;
  1347. }
  1348. };
  1349. var HALF_PI$3 = Math.PI / 2;
  1350. /**
  1351. * @name Two.Utils.Curve
  1352. * @property {Object} - Additional utility constant variables related to curve math and calculations.
  1353. */
  1354. var Curve = {
  1355. CollinearityEpsilon: Math.pow(10, -30),
  1356. RecursionLimit: 16,
  1357. CuspLimit: 0,
  1358. Tolerance: {
  1359. distance: 0.25,
  1360. angle: 0,
  1361. epsilon: Number.EPSILON
  1362. },
  1363. // Lookup tables for abscissas and weights with values for n = 2 .. 16.
  1364. // As values are symmetric, only store half of them and adapt algorithm
  1365. // to factor in symmetry.
  1366. abscissas: [
  1367. [ 0.5773502691896257645091488],
  1368. [0,0.7745966692414833770358531],
  1369. [ 0.3399810435848562648026658,0.8611363115940525752239465],
  1370. [0,0.5384693101056830910363144,0.9061798459386639927976269],
  1371. [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016],
  1372. [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897],
  1373. [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609],
  1374. [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762],
  1375. [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640],
  1376. [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380],
  1377. [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491],
  1378. [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294],
  1379. [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973],
  1380. [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657],
  1381. [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542]
  1382. ],
  1383. weights: [
  1384. [1],
  1385. [0.8888888888888888888888889,0.5555555555555555555555556],
  1386. [0.6521451548625461426269361,0.3478548451374538573730639],
  1387. [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640],
  1388. [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961],
  1389. [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114],
  1390. [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314],
  1391. [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922],
  1392. [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688],
  1393. [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537],
  1394. [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160],
  1395. [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216],
  1396. [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329],
  1397. [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284],
  1398. [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806]
  1399. ]
  1400. };
  1401. /**
  1402. * @name Two.Utils.getComponentOnCubicBezier
  1403. * @function
  1404. * @param {Number} t - Zero-to-one value describing what percentage to calculate.
  1405. * @param {Number} a - The firt point's component value.
  1406. * @param {Number} b - The first point's bezier component value.
  1407. * @param {Number} c - The second point's bezier component value.
  1408. * @param {Number} d - The second point's component value.
  1409. * @returns {Number} The coordinate value for a specific component along a cubic bezier curve by `t`.
  1410. */
  1411. var getComponentOnCubicBezier = function(t, a, b, c, d) {
  1412. var k = 1 - t;
  1413. return (k * k * k * a) + (3 * k * k * t * b) + (3 * k * t * t * c) +
  1414. (t * t * t * d);
  1415. };
  1416. /**
  1417. * @name Two.Utils.subdivide
  1418. * @function
  1419. * @param {Number} x1 - x position of first anchor point.
  1420. * @param {Number} y1 - y position of first anchor point.
  1421. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1422. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1423. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1424. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1425. * @param {Number} x4 - x position of second anchor point.
  1426. * @param {Number} y4 - y position of second anchor point.
  1427. * @param {Number} [limit=Two.Utils.Curve.RecursionLimit] - The amount of vertices to create by subdividing.
  1428. * @returns {Anchor[]} A list of anchor points ordered in between `x1`, `y1` and `x4`, `y4`
  1429. * @description Given 2 points (a, b) and corresponding control point for each return an array of points that represent points plotted along the curve. The number of returned points is determined by `limit`.
  1430. */
  1431. var subdivide = function(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1432. limit = limit || Curve.RecursionLimit;
  1433. var amount = limit + 1;
  1434. // TODO: Abstract 0.001 to a limiting variable
  1435. // Don't recurse if the end points are identical
  1436. if (Math.abs(x1 - x4) < 0.001 && Math.abs(y1 - y4) < 0.001) {
  1437. return [new Anchor(x4, y4)];
  1438. }
  1439. var result = [];
  1440. for (var i = 0; i < amount; i++) {
  1441. var t = i / amount;
  1442. var x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
  1443. var y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
  1444. result.push(new Anchor(x, y));
  1445. }
  1446. return result;
  1447. };
  1448. /**
  1449. * @name Two.Utils.getCurveLength
  1450. * @function
  1451. * @param {Number} x1 - x position of first anchor point.
  1452. * @param {Number} y1 - y position of first anchor point.
  1453. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1454. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1455. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1456. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1457. * @param {Number} x4 - x position of second anchor point.
  1458. * @param {Number} y4 - y position of second anchor point.
  1459. * @param {Number} [limit=Two.Utils.Curve.RecursionLimit] - The amount of vertices to create by subdividing.
  1460. * @returns {Number} The length of a curve.
  1461. * @description Given 2 points (a, b) and corresponding control point for each, return a float that represents the length of the curve using Gauss-Legendre algorithm. Limit iterations of calculation by `limit`.
  1462. */
  1463. var getCurveLength$1 = function(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1464. // TODO: Better / fuzzier equality check
  1465. // Linear calculation
  1466. if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) {
  1467. var dx = x4 - x1;
  1468. var dy = y4 - y1;
  1469. return Math.sqrt(dx * dx + dy * dy);
  1470. }
  1471. // Calculate the coefficients of a Bezier derivative.
  1472. var ax = 9 * (x2 - x3) + 3 * (x4 - x1),
  1473. bx = 6 * (x1 + x3) - 12 * x2,
  1474. cx = 3 * (x2 - x1),
  1475. ay = 9 * (y2 - y3) + 3 * (y4 - y1),
  1476. by = 6 * (y1 + y3) - 12 * y2,
  1477. cy = 3 * (y2 - y1);
  1478. var integrand = function(t) {
  1479. // Calculate quadratic equations of derivatives for x and y
  1480. var dx = (ax * t + bx) * t + cx,
  1481. dy = (ay * t + by) * t + cy;
  1482. return Math.sqrt(dx * dx + dy * dy);
  1483. };
  1484. return integrate(
  1485. integrand, 0, 1, limit || Curve.RecursionLimit
  1486. );
  1487. };
  1488. /**
  1489. * @name Two.Utils.getCurveBoundingBox
  1490. * @function
  1491. * @param {Number} x1 - x position of first anchor point.
  1492. * @param {Number} y1 - y position of first anchor point.
  1493. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1494. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1495. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1496. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1497. * @param {Number} x4 - x position of second anchor point.
  1498. * @param {Number} y4 - y position of second anchor point.
  1499. * @returns {Object} Object contains min and max `x` / `y` bounds.
  1500. * @see {@link https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js#L856}
  1501. */
  1502. var getCurveBoundingBox = function(x1, y1, x2, y2, x3, y3, x4, y4) {
  1503. var tvalues = [];
  1504. var bounds = [[], []];
  1505. var a, b, c, t, t1, t2, b2ac, sqrtb2ac;
  1506. for (var i = 0; i < 2; ++i) {
  1507. if (i == 0) {
  1508. b = 6 * x1 - 12 * x2 + 6 * x3;
  1509. a = -3 * x1 + 9 * x2 - 9 * x3 + 3 * x4;
  1510. c = 3 * x2 - 3 * x1;
  1511. } else {
  1512. b = 6 * y1 - 12 * y2 + 6 * y3;
  1513. a = -3 * y1 + 9 * y2 - 9 * y3 + 3 * y4;
  1514. c = 3 * y2 - 3 * y1;
  1515. }
  1516. if (Math.abs(a) < 1e-12) {
  1517. if (Math.abs(b) < 1e-12) {
  1518. continue;
  1519. }
  1520. t = -c / b;
  1521. if (0 < t && t < 1) {
  1522. tvalues.push(t);
  1523. }
  1524. continue;
  1525. }
  1526. b2ac = b * b - 4 * c * a;
  1527. sqrtb2ac = Math.sqrt(b2ac);
  1528. if (b2ac < 0) {
  1529. continue;
  1530. }
  1531. t1 = (-b + sqrtb2ac) / (2 * a);
  1532. if (0 < t1 && t1 < 1) {
  1533. tvalues.push(t1);
  1534. }
  1535. t2 = (-b - sqrtb2ac) / (2 * a);
  1536. if (0 < t2 && t2 < 1) {
  1537. tvalues.push(t2);
  1538. }
  1539. }
  1540. var j = tvalues.length;
  1541. var jlen = j;
  1542. var mt;
  1543. while (j--) {
  1544. t = tvalues[j];
  1545. mt = 1 - t;
  1546. bounds[0][j] = mt * mt * mt * x1 + 3 * mt * mt * t * x2 + 3 * mt * t * t * x3 + t * t * t * x4;
  1547. bounds[1][j] = mt * mt * mt * y1 + 3 * mt * mt * t * y2 + 3 * mt * t * t * y3 + t * t * t * y4;
  1548. }
  1549. bounds[0][jlen] = x1;
  1550. bounds[1][jlen] = y1;
  1551. bounds[0][jlen + 1] = x4;
  1552. bounds[1][jlen + 1] = y4;
  1553. bounds[0].length = bounds[1].length = jlen + 2;
  1554. return {
  1555. min: { x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1]) },
  1556. max: { x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1]) }
  1557. };
  1558. };
  1559. /**
  1560. * @name Two.Utils.integrate
  1561. * @function
  1562. * @param {Function} f
  1563. * @param {Number} a
  1564. * @param {Number} b
  1565. * @param {Number} n
  1566. * @description Integration for `getCurveLength` calculations.
  1567. * @see [Paper.js](@link https://github.com/paperjs/paper.js/blob/master/src/util/Numerical.js#L101)
  1568. */
  1569. var integrate = function(f, a, b, n) {
  1570. var x = Curve.abscissas[n - 2],
  1571. w = Curve.weights[n - 2],
  1572. A = 0.5 * (b - a),
  1573. B = A + a,
  1574. i = 0,
  1575. m = (n + 1) >> 1,
  1576. sum = n & 1 ? w[i++] * f(B) : 0; // Handle odd n
  1577. while (i < m) {
  1578. var Ax = A * x[i];
  1579. sum += w[i++] * (f(B + Ax) + f(B - Ax));
  1580. }
  1581. return A * sum;
  1582. };
  1583. /**
  1584. * @name Two.Utils.getCurveFromPoints
  1585. * @function
  1586. * @param {Anchor[]} points
  1587. * @param {Boolean} closed
  1588. * @description Sets the bezier handles on {@link Anchor}s in the `points` list with estimated values to create a catmull-rom like curve. Used by {@link Two.Path#plot}.
  1589. */
  1590. var getCurveFromPoints = function(points, closed) {
  1591. var l = points.length, last = l - 1;
  1592. for (var i = 0; i < l; i++) {
  1593. var point = points[i];
  1594. if (!_.isObject(point.controls)) {
  1595. Anchor.AppendCurveProperties(point);
  1596. }
  1597. var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0);
  1598. var next = closed ? mod(i + 1, l) : Math.min(i + 1, last);
  1599. var a = points[prev];
  1600. var b = point;
  1601. var c = points[next];
  1602. getControlPoints(a, b, c);
  1603. b.command = i === 0 ? Commands.move : Commands.curve;
  1604. }
  1605. };
  1606. /**
  1607. * @name Two.Utils.getControlPoints
  1608. * @function
  1609. * @param {Anchor} a
  1610. * @param {Anchor} b
  1611. * @param {Anchor} c
  1612. * @returns {Anchor} Returns the passed middle point `b`.
  1613. * @description Given three coordinates set the control points for the middle, b, vertex based on its position with the adjacent points.
  1614. */
  1615. var getControlPoints = function(a, b, c) {
  1616. var a1 = Vector.angleBetween(a, b);
  1617. var a2 = Vector.angleBetween(c, b);
  1618. var d1 = Vector.distanceBetween(a, b);
  1619. var d2 = Vector.distanceBetween(c, b);
  1620. var mid = (a1 + a2) / 2;
  1621. // TODO: Issue 73
  1622. if (d1 < 0.0001 || d2 < 0.0001) {
  1623. if (typeof b.relative === 'boolean' && !b.relative) {
  1624. b.controls.left.copy(b);
  1625. b.controls.right.copy(b);
  1626. }
  1627. return b;
  1628. }
  1629. d1 *= 0.33; // Why 0.33?
  1630. d2 *= 0.33;
  1631. if (a2 < a1) {
  1632. mid += HALF_PI$3;
  1633. } else {
  1634. mid -= HALF_PI$3;
  1635. }
  1636. b.controls.left.x = Math.cos(mid) * d1;
  1637. b.controls.left.y = Math.sin(mid) * d1;
  1638. mid -= Math.PI;
  1639. b.controls.right.x = Math.cos(mid) * d2;
  1640. b.controls.right.y = Math.sin(mid) * d2;
  1641. if (typeof b.relative === 'boolean' && !b.relative) {
  1642. b.controls.left.x += b.x;
  1643. b.controls.left.y += b.y;
  1644. b.controls.right.x += b.x;
  1645. b.controls.right.y += b.y;
  1646. }
  1647. return b;
  1648. };
  1649. /**
  1650. * @name Two.Utils.getReflection
  1651. * @function
  1652. * @param {Vector} a
  1653. * @param {Vector} b
  1654. * @param {Boolean} [relative=false]
  1655. * @returns {Vector} New {@link Vector} that represents the reflection point.
  1656. * @description Get the reflection of a point `b` about point `a`. Where `a` is in absolute space and `b` is relative to `a`.
  1657. * @see {@link http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes}
  1658. */
  1659. var getReflection = function(a, b, relative) {
  1660. return new Vector(
  1661. 2 * a.x - (b.x + a.x) - (relative ? a.x : 0),
  1662. 2 * a.y - (b.y + a.y) - (relative ? a.y : 0)
  1663. );
  1664. };
  1665. /**
  1666. * @name Two.Utils.getAnchorsFromArcData
  1667. * @function
  1668. * @param {Vector} center
  1669. * @param {Number} xAxisRotation
  1670. * @param {Number} rx - x radius
  1671. * @param {Number} ry - y radius
  1672. * @param {Number} ts
  1673. * @param {Number} td
  1674. * @param {Boolean} [ccw=false] - Set path traversal to counter-clockwise
  1675. */
  1676. var getAnchorsFromArcData = function(center, xAxisRotation, rx, ry, ts, td, ccw) {
  1677. var resolution = Constants.Resolution;
  1678. for (var i = 0; i < resolution; i++) {
  1679. var pct = (i + 1) / resolution;
  1680. if (ccw) {
  1681. pct = 1 - pct;
  1682. }
  1683. var theta = pct * td + ts;
  1684. var x = rx * Math.cos(theta);
  1685. var y = ry * Math.sin(theta);
  1686. // x += center.x;
  1687. // y += center.y;
  1688. var anchor = new Anchor(x, y);
  1689. Anchor.AppendCurveProperties(anchor);
  1690. anchor.command = Commands.line;
  1691. }
  1692. };
  1693. var Curves = /*#__PURE__*/Object.freeze({
  1694. __proto__: null,
  1695. Curve: Curve,
  1696. getComponentOnCubicBezier: getComponentOnCubicBezier,
  1697. subdivide: subdivide,
  1698. getCurveLength: getCurveLength$1,
  1699. getCurveBoundingBox: getCurveBoundingBox,
  1700. integrate: integrate,
  1701. getCurveFromPoints: getCurveFromPoints,
  1702. getControlPoints: getControlPoints,
  1703. getReflection: getReflection,
  1704. getAnchorsFromArcData: getAnchorsFromArcData
  1705. });
  1706. var devicePixelRatio = root$1.devicePixelRatio || 1;
  1707. var getBackingStoreRatio = function(ctx) {
  1708. return ctx.webkitBackingStorePixelRatio ||
  1709. ctx.mozBackingStorePixelRatio ||
  1710. ctx.msBackingStorePixelRatio ||
  1711. ctx.oBackingStorePixelRatio ||
  1712. ctx.backingStorePixelRatio || 1;
  1713. };
  1714. /**
  1715. * @name Two.Utils.getRatio
  1716. * @function
  1717. * @param {CanvasRenderingContext2D} ctx
  1718. * @returns {Number} The ratio of a unit in Two.js to the pixel density of a session's screen.
  1719. * @see [High DPI Rendering](http://www.html5rocks.com/en/tutorials/canvas/hidpi/)
  1720. */
  1721. var getRatio = function(ctx) {
  1722. return devicePixelRatio / getBackingStoreRatio(ctx);
  1723. };
  1724. // Constants
  1725. var cos$5 = Math.cos, sin$5 = Math.sin, tan = Math.tan;
  1726. var array = [];
  1727. /**
  1728. * @name Two.Matrix
  1729. * @class
  1730. * @param {Number} [a=1] - The value for element at the first column and first row.
  1731. * @param {Number} [b=0] - The value for element at the second column and first row.
  1732. * @param {Number} [c=0] - The value for element at the third column and first row.
  1733. * @param {Number} [d=0] - The value for element at the first column and second row.
  1734. * @param {Number} [e=1] - The value for element at the second column and second row.
  1735. * @param {Number} [f=0] - The value for element at the third column and second row.
  1736. * @param {Number} [g=0] - The value for element at the first column and third row.
  1737. * @param {Number} [h=0] - The value for element at the second column and third row.
  1738. * @param {Number} [i=1] - The value for element at the third column and third row.
  1739. * @description A class to store 3 x 3 transformation matrix information. In addition to storing data `Two.Matrix` has suped up methods for commonplace mathematical operations.
  1740. * @nota-bene Order is based on how to construct transformation strings for the browser.
  1741. */
  1742. function Matrix(a, b, c, d, e, f) {
  1743. /**
  1744. * @name Two.Matrix#elements
  1745. * @property {Number[]} - The underlying data stored as an array.
  1746. */
  1747. this.elements = new NumArray(9);
  1748. var elements = a;
  1749. if (!Array.isArray(elements)) {
  1750. elements = Array.prototype.slice.call(arguments);
  1751. }
  1752. // initialize the elements with default values.
  1753. this.identity();
  1754. if (elements.length > 0) {
  1755. this.set(elements);
  1756. }
  1757. }
  1758. setMatrix(Matrix);
  1759. _.extend(Matrix, {
  1760. /**
  1761. * @name Two.Matrix.Identity
  1762. * @property {Number[]} - A stored reference to the default value of a 3 x 3 matrix.
  1763. */
  1764. Identity: [
  1765. 1, 0, 0,
  1766. 0, 1, 0,
  1767. 0, 0, 1
  1768. ],
  1769. /**
  1770. * @name Two.Matrix.Multiply
  1771. * @function
  1772. * @param {Two.Matrix} A
  1773. * @param {Two.Matrix} B
  1774. * @param {Two.Matrix} [C] - An optional matrix to apply the multiplication to.
  1775. * @returns {Two.Matrix} - If an optional `C` matrix isn't passed then a new one is created and returned.
  1776. * @description Multiply two matrices together and return the result.
  1777. */
  1778. Multiply: function(A, B, C) {
  1779. if (B.length <= 3) { // Multiply Vector
  1780. var x, y, z, e = A;
  1781. var a = B[0] || 0,
  1782. b = B[1] || 0,
  1783. c = B[2] || 0;
  1784. // Go down rows first
  1785. // a, d, g, b, e, h, c, f, i
  1786. x = e[0] * a + e[1] * b + e[2] * c;
  1787. y = e[3] * a + e[4] * b + e[5] * c;
  1788. z = e[6] * a + e[7] * b + e[8] * c;
  1789. return { x: x, y: y, z: z };
  1790. }
  1791. var A0 = A[0], A1 = A[1], A2 = A[2];
  1792. var A3 = A[3], A4 = A[4], A5 = A[5];
  1793. var A6 = A[6], A7 = A[7], A8 = A[8];
  1794. var B0 = B[0], B1 = B[1], B2 = B[2];
  1795. var B3 = B[3], B4 = B[4], B5 = B[5];
  1796. var B6 = B[6], B7 = B[7], B8 = B[8];
  1797. C = C || new NumArray(9);
  1798. C[0] = A0 * B0 + A1 * B3 + A2 * B6;
  1799. C[1] = A0 * B1 + A1 * B4 + A2 * B7;
  1800. C[2] = A0 * B2 + A1 * B5 + A2 * B8;
  1801. C[3] = A3 * B0 + A4 * B3 + A5 * B6;
  1802. C[4] = A3 * B1 + A4 * B4 + A5 * B7;
  1803. C[5] = A3 * B2 + A4 * B5 + A5 * B8;
  1804. C[6] = A6 * B0 + A7 * B3 + A8 * B6;
  1805. C[7] = A6 * B1 + A7 * B4 + A8 * B7;
  1806. C[8] = A6 * B2 + A7 * B5 + A8 * B8;
  1807. return C;
  1808. }
  1809. });
  1810. _.extend(Matrix.prototype, Events, {
  1811. constructor: Matrix,
  1812. /**
  1813. * @name Two.Matrix#manual
  1814. * @property {Boolean} - Determines whether Two.js automatically calculates the values for the matrix or if the developer intends to manage the matrix.
  1815. * @nota-bene - Setting to `true` nullifies {@link Two.Shape#translation}, {@link Two.Shape#rotation}, and {@link Two.Shape#scale}.
  1816. */
  1817. manual: false,
  1818. /**
  1819. * @name Two.Matrix#set
  1820. * @function
  1821. * @param {Number} a - The value for element at the first column and first row.
  1822. * @param {Number} b - The value for element at the second column and first row.
  1823. * @param {Number} c - The value for element at the third column and first row.
  1824. * @param {Number} d - The value for element at the first column and second row.
  1825. * @param {Number} e - The value for element at the second column and second row.
  1826. * @param {Number} f - The value for element at the third column and second row.
  1827. * @param {Number} g - The value for element at the first column and third row.
  1828. * @param {Number} h - The value for element at the second column and third row.
  1829. * @param {Number} i - The value for element at the third column and third row.
  1830. * @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
  1831. */
  1832. /**
  1833. * @name Two.Matrix#set
  1834. * @function
  1835. * @param {Number[]} a - The array of elements to apply.
  1836. * @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
  1837. */
  1838. set: function(a, b, c, d, e, f, g, h, i) {
  1839. var elements;
  1840. if (typeof b === 'undefined') {
  1841. elements = a;
  1842. a = elements[0];
  1843. b = elements[1];
  1844. c = elements[2];
  1845. d = elements[3];
  1846. e = elements[4];
  1847. f = elements[5];
  1848. g = elements[6];
  1849. h = elements[7];
  1850. i = elements[8];
  1851. }
  1852. this.elements[0] = a;
  1853. this.elements[1] = b;
  1854. this.elements[2] = c;
  1855. this.elements[3] = d;
  1856. this.elements[4] = e;
  1857. this.elements[5] = f;
  1858. this.elements[6] = g;
  1859. this.elements[7] = h;
  1860. this.elements[8] = i;
  1861. return this.trigger(Events.Types.change);
  1862. },
  1863. /**
  1864. * @name Two.Matrix#copy
  1865. * @function
  1866. * @description Copy the matrix of one to the current instance.
  1867. */
  1868. copy: function(m) {
  1869. this.elements[0] = m.elements[0];
  1870. this.elements[1] = m.elements[1];
  1871. this.elements[2] = m.elements[2];
  1872. this.elements[3] = m.elements[3];
  1873. this.elements[4] = m.elements[4];
  1874. this.elements[5] = m.elements[5];
  1875. this.elements[6] = m.elements[6];
  1876. this.elements[7] = m.elements[7];
  1877. this.elements[8] = m.elements[8];
  1878. this.manual = m.manual;
  1879. return this.trigger(Events.Types.change);
  1880. },
  1881. /**
  1882. * @name Two.Matrix#identity
  1883. * @function
  1884. * @description Turn matrix to the identity, like resetting.
  1885. */
  1886. identity: function() {
  1887. this.elements[0] = Matrix.Identity[0];
  1888. this.elements[1] = Matrix.Identity[1];
  1889. this.elements[2] = Matrix.Identity[2];
  1890. this.elements[3] = Matrix.Identity[3];
  1891. this.elements[4] = Matrix.Identity[4];
  1892. this.elements[5] = Matrix.Identity[5];
  1893. this.elements[6] = Matrix.Identity[6];
  1894. this.elements[7] = Matrix.Identity[7];
  1895. this.elements[8] = Matrix.Identity[8];
  1896. return this.trigger(Events.Types.change);
  1897. },
  1898. /**
  1899. * @name Two.Matrix#multiply
  1900. * @function
  1901. * @param {Number} a - The scalar to be multiplied.
  1902. * @description Multiply all components of the matrix against a single scalar value.
  1903. * @overloaded
  1904. */
  1905. /**
  1906. * @name Two.Matrix#multiply
  1907. * @function
  1908. * @param {Number} a - The x component to be multiplied.
  1909. * @param {Number} b - The y component to be multiplied.
  1910. * @param {Number} c - The z component to be multiplied.
  1911. * @description Multiply all components of a matrix against a 3 component vector.
  1912. * @overloaded
  1913. */
  1914. /**
  1915. * @name Two.Matrix#multiply
  1916. * @function
  1917. * @param {Number} a - The value at the first column and first row of the matrix to be multiplied.
  1918. * @param {Number} b - The value at the second column and first row of the matrix to be multiplied.
  1919. * @param {Number} c - The value at the third column and first row of the matrix to be multiplied.
  1920. * @param {Number} d - The value at the first column and second row of the matrix to be multiplied.
  1921. * @param {Number} e - The value at the second column and second row of the matrix to be multiplied.
  1922. * @param {Number} f - The value at the third column and second row of the matrix to be multiplied.
  1923. * @param {Number} g - The value at the first column and third row of the matrix to be multiplied.
  1924. * @param {Number} h - The value at the second column and third row of the matrix to be multiplied.
  1925. * @param {Number} i - The value at the third column and third row of the matrix to be multiplied.
  1926. * @description Multiply all components of a matrix against another matrix.
  1927. * @overloaded
  1928. */
  1929. multiply: function(a, b, c, d, e, f, g, h, i) {
  1930. // Multiply scalar
  1931. if (typeof b === 'undefined') {
  1932. this.elements[0] *= a;
  1933. this.elements[1] *= a;
  1934. this.elements[2] *= a;
  1935. this.elements[3] *= a;
  1936. this.elements[4] *= a;
  1937. this.elements[5] *= a;
  1938. this.elements[6] *= a;
  1939. this.elements[7] *= a;
  1940. this.elements[8] *= a;
  1941. return this.trigger(Events.Types.change);
  1942. }
  1943. if (typeof d === 'undefined') { // Multiply Vector
  1944. var x, y, z;
  1945. a = a || 0;
  1946. b = b || 0;
  1947. c = c || 0;
  1948. e = this.elements;
  1949. // Go down rows first
  1950. // a, d, g, b, e, h, c, f, i
  1951. x = e[0] * a + e[1] * b + e[2] * c;
  1952. y = e[3] * a + e[4] * b + e[5] * c;
  1953. z = e[6] * a + e[7] * b + e[8] * c;
  1954. return { x: x, y: y, z: z };
  1955. }
  1956. // Multiple matrix
  1957. var A = this.elements;
  1958. var B = [a, b, c, d, e, f, g, h, i];
  1959. var A0 = A[0], A1 = A[1], A2 = A[2];
  1960. var A3 = A[3], A4 = A[4], A5 = A[5];
  1961. var A6 = A[6], A7 = A[7], A8 = A[8];
  1962. var B0 = B[0], B1 = B[1], B2 = B[2];
  1963. var B3 = B[3], B4 = B[4], B5 = B[5];
  1964. var B6 = B[6], B7 = B[7], B8 = B[8];
  1965. this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
  1966. this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
  1967. this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;
  1968. this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
  1969. this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
  1970. this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;
  1971. this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
  1972. this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
  1973. this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;
  1974. return this.trigger(Events.Types.change);
  1975. },
  1976. /**
  1977. * @name Two.Matrix#inverse
  1978. * @function
  1979. * @param {Two.Matrix} [out] - The optional matrix to apply the inversion to.
  1980. * @description Return an inverted version of the matrix. If no optional one is passed a new matrix is created and returned.
  1981. */
  1982. inverse: function(out) {
  1983. var a = this.elements;
  1984. out = out || new Matrix();
  1985. var a00 = a[0], a01 = a[1], a02 = a[2];
  1986. var a10 = a[3], a11 = a[4], a12 = a[5];
  1987. var a20 = a[6], a21 = a[7], a22 = a[8];
  1988. var b01 = a22 * a11 - a12 * a21;
  1989. var b11 = -a22 * a10 + a12 * a20;
  1990. var b21 = a21 * a10 - a11 * a20;
  1991. // Calculate the determinant
  1992. var det = a00 * b01 + a01 * b11 + a02 * b21;
  1993. if (!det) {
  1994. return null;
  1995. }
  1996. det = 1.0 / det;
  1997. out.elements[0] = b01 * det;
  1998. out.elements[1] = (-a22 * a01 + a02 * a21) * det;
  1999. out.elements[2] = (a12 * a01 - a02 * a11) * det;
  2000. out.elements[3] = b11 * det;
  2001. out.elements[4] = (a22 * a00 - a02 * a20) * det;
  2002. out.elements[5] = (-a12 * a00 + a02 * a10) * det;
  2003. out.elements[6] = b21 * det;
  2004. out.elements[7] = (-a21 * a00 + a01 * a20) * det;
  2005. out.elements[8] = (a11 * a00 - a01 * a10) * det;
  2006. return out;
  2007. },
  2008. /**
  2009. * @name Two.Matrix#scale
  2010. * @function
  2011. * @param {Number} scale - The one dimensional scale to apply to the matrix.
  2012. * @description Uniformly scale the transformation matrix.
  2013. */
  2014. /**
  2015. * @name Two.Matrix#scale
  2016. * @function
  2017. * @param {Number} sx - The horizontal scale factor.
  2018. * @param {Number} sy - The vertical scale factor
  2019. * @description Scale the transformation matrix in two dimensions.
  2020. */
  2021. scale: function(sx, sy) {
  2022. var l = arguments.length;
  2023. if (l <= 1) {
  2024. sy = sx;
  2025. }
  2026. return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);
  2027. },
  2028. /**
  2029. * @name Two.Matrix#rotate
  2030. * @function
  2031. * @param {Number} Number - The amount to rotate in Number.
  2032. * @description Rotate the matrix.
  2033. */
  2034. rotate: function(Number) {
  2035. var c = cos$5(Number);
  2036. var s = sin$5(Number);
  2037. return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);
  2038. },
  2039. /**
  2040. * @name Two.Matrix#translate
  2041. * @function
  2042. * @param {Number} x - The horizontal translation value to apply.
  2043. * @param {Number} y - The vertical translation value to apply.
  2044. * @description Translate the matrix.
  2045. */
  2046. translate: function(x, y) {
  2047. return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);
  2048. },
  2049. /**
  2050. * @name Two.Matrix#skewX
  2051. * @function
  2052. * @param {Number} Number - The amount to skew in Number.
  2053. * @description Skew the matrix by an angle in the x axis direction.
  2054. */
  2055. skewX: function(Number) {
  2056. var a = tan(Number);
  2057. return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);
  2058. },
  2059. /**
  2060. * @name Two.Matrix#skewY
  2061. * @function
  2062. * @param {Number} Number - The amount to skew in Number.
  2063. * @description Skew the matrix by an angle in the y axis direction.
  2064. */
  2065. skewY: function(Number) {
  2066. var a = tan(Number);
  2067. return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);
  2068. },
  2069. /**
  2070. * @name Two.Matrix#toString
  2071. * @function
  2072. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
  2073. * @returns {String} - The transformation matrix as a 6 component string separated by spaces.
  2074. * @description Create a transform string. Used for the Two.js rendering APIs.
  2075. */
  2076. toString: function(fullMatrix) {
  2077. array.length = 0;
  2078. this.toTransformArray(fullMatrix, array);
  2079. return array.map(toFixed).join(' ');
  2080. },
  2081. /**
  2082. * @name Two.Matrix#toTransformArray
  2083. * @function
  2084. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 in the format for 2D transformations.
  2085. * @param {Number[]} [output] - An array empty or otherwise to apply the values to.
  2086. * @description Create a transform array. Used for the Two.js rendering APIs.
  2087. */
  2088. toTransformArray: function(fullMatrix, output) {
  2089. var elements = this.elements;
  2090. var hasOutput = !!output;
  2091. var a = elements[0];
  2092. var b = elements[1];
  2093. var c = elements[2];
  2094. var d = elements[3];
  2095. var e = elements[4];
  2096. var f = elements[5];
  2097. if (fullMatrix) {
  2098. var g = elements[6];
  2099. var h = elements[7];
  2100. var i = elements[8];
  2101. if (hasOutput) {
  2102. output[0] = a;
  2103. output[1] = d;
  2104. output[2] = g;
  2105. output[3] = b;
  2106. output[4] = e;
  2107. output[5] = h;
  2108. output[6] = c;
  2109. output[7] = f;
  2110. output[8] = i;
  2111. return;
  2112. }
  2113. return [
  2114. a, d, g, b, e, h, c, f, i
  2115. ];
  2116. }
  2117. if (hasOutput) {
  2118. output[0] = a;
  2119. output[1] = d;
  2120. output[2] = b;
  2121. output[3] = e;
  2122. output[4] = c;
  2123. output[5] = f;
  2124. return;
  2125. }
  2126. return [
  2127. a, d, b, e, c, f // Specific format see LN:19
  2128. ];
  2129. },
  2130. /**
  2131. * @name Two.Matrix#toArray
  2132. * @function
  2133. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
  2134. * @param {Number[]} [output] - An array empty or otherwise to apply the values to.
  2135. * @description Create a transform array. Used for the Two.js rendering APIs.
  2136. */
  2137. toArray: function(fullMatrix, output) {
  2138. var elements = this.elements;
  2139. var hasOutput = !!output;
  2140. var a = elements[0];
  2141. var b = elements[1];
  2142. var c = elements[2];
  2143. var d = elements[3];
  2144. var e = elements[4];
  2145. var f = elements[5];
  2146. if (fullMatrix) {
  2147. var g = elements[6];
  2148. var h = elements[7];
  2149. var i = elements[8];
  2150. if (hasOutput) {
  2151. output[0] = a;
  2152. output[1] = b;
  2153. output[2] = c;
  2154. output[3] = d;
  2155. output[4] = e;
  2156. output[5] = f;
  2157. output[6] = g;
  2158. output[7] = h;
  2159. output[8] = i;
  2160. return;
  2161. }
  2162. return [
  2163. a, b, c, d, e, f, g, h, i
  2164. ];
  2165. }
  2166. if (hasOutput) {
  2167. output[0] = a;
  2168. output[1] = b;
  2169. output[2] = c;
  2170. output[3] = d;
  2171. output[4] = e;
  2172. output[5] = f;
  2173. return;
  2174. }
  2175. return [
  2176. a, b, c, d, e, f
  2177. ];
  2178. },
  2179. /**
  2180. * @name Two.Matrix#toObject
  2181. * @function
  2182. * @description Create a JSON compatible object that represents information of the matrix.
  2183. */
  2184. toObject: function() {
  2185. return {
  2186. elements: this.toArray(true),
  2187. manual: !!this.manual
  2188. };
  2189. },
  2190. /**
  2191. * @name Two.Matrix#clone
  2192. * @function
  2193. * @description Clone the current matrix.
  2194. */
  2195. clone: function() {
  2196. return new Matrix().copy(this);
  2197. }
  2198. });
  2199. /**
  2200. * @name Two.Shape
  2201. * @class
  2202. * @extends Two.Events
  2203. * @description The foundational transformation object for the Two.js scenegraph.
  2204. */
  2205. function Shape() {
  2206. /**
  2207. * @name Two.Shape#renderer
  2208. * @property {Object}
  2209. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  2210. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  2211. */
  2212. this.renderer = {};
  2213. this._renderer.flagMatrix = Shape.FlagMatrix.bind(this);
  2214. this.isShape = true;
  2215. /**
  2216. * @name Two.Shape#id
  2217. * @property {String} - Session specific unique identifier.
  2218. * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
  2219. */
  2220. this.id = Constants.Identifier + Constants.uniqueId();
  2221. /**
  2222. * @name Two.Shape#classList
  2223. * @property {String[]}
  2224. * @description A list of class strings stored if imported / interpreted from an SVG element.
  2225. */
  2226. this.classList = [];
  2227. /**
  2228. * @name Two.Shape#matrix
  2229. * @property {Two.Matrix}
  2230. * @description The transformation matrix of the shape.
  2231. * @nota-bene {@link Two.Shape#translation}, {@link Two.Shape#rotation}, {@link Two.Shape#scale}, {@link Two.Shape#skewX}, and {@link Two.Shape#skewY} apply their values to the matrix when changed. The matrix is what is sent to the renderer to be drawn.
  2232. */
  2233. this.matrix = new Matrix();
  2234. /**
  2235. * @name Two.Shape#translation
  2236. * @property {Two.Vector} - The x and y value for where the shape is placed relative to its parent.
  2237. */
  2238. this.translation = new Vector();
  2239. /**
  2240. * @name Two.Shape#rotation
  2241. * @property {Number} - The value in Number for how much the shape is rotated relative to its parent.
  2242. */
  2243. this.rotation = 0;
  2244. /**
  2245. * @name Two.Shape#scale
  2246. * @property {Number} - The value for how much the shape is scaled relative to its parent.
  2247. * @nota-bene This value can be replaced with a {@link Two.Vector} to do non-uniform scaling. e.g: `shape.scale = new Two.Vector(2, 1);`
  2248. */
  2249. this.scale = 1;
  2250. /**
  2251. * @name Two.Shape#skewX
  2252. * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
  2253. * @description Skew the shape by an angle in the x axis direction.
  2254. */
  2255. this.skewX = 0;
  2256. /**
  2257. * @name Two.Shape#skewY
  2258. * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
  2259. * @description Skew the shape by an angle in the y axis direction.
  2260. */
  2261. this.skewY = 0;
  2262. }
  2263. _.extend(Shape, {
  2264. /**
  2265. * @name Two.Shape.FlagMatrix
  2266. * @function
  2267. * @description Utility function used in conjunction with event handlers to update the flagMatrix of a shape.
  2268. */
  2269. FlagMatrix: function() {
  2270. this._flagMatrix = true;
  2271. },
  2272. /**
  2273. * @name Two.Shape.MakeObservable
  2274. * @function
  2275. * @param {Object} object - The object to make observable.
  2276. * @description Convenience function to apply observable qualities of a {@link Two.Shape} to any object. Handy if you'd like to extend the {@link Two.Shape} class on a custom class.
  2277. */
  2278. MakeObservable: function(object) {
  2279. var translation = {
  2280. enumerable: false,
  2281. get: function() {
  2282. return this._translation;
  2283. },
  2284. set: function(v) {
  2285. if (this._translation) {
  2286. this._translation.unbind(Events.Types.change, this._renderer.flagMatrix);
  2287. }
  2288. this._translation = v;
  2289. this._translation.bind(Events.Types.change, this._renderer.flagMatrix);
  2290. Shape.FlagMatrix.call(this);
  2291. }
  2292. };
  2293. Object.defineProperty(object, 'translation', translation);
  2294. Object.defineProperty(object, 'position', translation);
  2295. Object.defineProperty(object, 'rotation', {
  2296. enumerable: true,
  2297. get: function() {
  2298. return this._rotation;
  2299. },
  2300. set: function(v) {
  2301. this._rotation = v;
  2302. this._flagMatrix = true;
  2303. }
  2304. });
  2305. Object.defineProperty(object, 'scale', {
  2306. enumerable: true,
  2307. get: function() {
  2308. return this._scale;
  2309. },
  2310. set: function(v) {
  2311. if (this._scale instanceof Vector) {
  2312. this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
  2313. }
  2314. this._scale = v;
  2315. if (this._scale instanceof Vector) {
  2316. this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
  2317. }
  2318. this._flagMatrix = true;
  2319. this._flagScale = true;
  2320. }
  2321. });
  2322. Object.defineProperty(object, 'skewX', {
  2323. enumerable: true,
  2324. get: function() {
  2325. return this._skewX;
  2326. },
  2327. set: function(v) {
  2328. this._skewX = v;
  2329. this._flagMatrix = true;
  2330. }
  2331. });
  2332. Object.defineProperty(object, 'skewY', {
  2333. enumerable: true,
  2334. get: function() {
  2335. return this._skewY;
  2336. },
  2337. set: function(v) {
  2338. this._skewY = v;
  2339. this._flagMatrix = true;
  2340. }
  2341. });
  2342. Object.defineProperty(object, 'matrix', {
  2343. enumerable: true,
  2344. get: function() {
  2345. return this._matrix;
  2346. },
  2347. set: function(v) {
  2348. this._matrix = v;
  2349. this._flagMatrix = true;
  2350. }
  2351. });
  2352. Object.defineProperty(object, 'id', {
  2353. enumerable: true,
  2354. get: function() {
  2355. return this._id;
  2356. },
  2357. set: function(v) {
  2358. var id = this._id;
  2359. if (v === this._id) {
  2360. return;
  2361. }
  2362. this._id = v;
  2363. this._flagId = true;
  2364. if (this.parent) {
  2365. delete this.parent.children.ids[id];
  2366. this.parent.children.ids[this._id] = this;
  2367. }
  2368. }
  2369. });
  2370. Object.defineProperty(object, 'className', {
  2371. enumerable: true,
  2372. get: function() {
  2373. return this._className;
  2374. },
  2375. set: function(v) {
  2376. this._flagClassName = this._className !== v;
  2377. if (this._flagClassName) {
  2378. var prev = this._className.split(/\s+?/);
  2379. var dest = v.split(/\s+?/);
  2380. for (var i = 0; i < prev.length; i++) {
  2381. var className = prev[i];
  2382. var index = Array.prototype.indexOf.call(this.classList, className);
  2383. if (index >= 0) {
  2384. this.classList.splice(index, 1);
  2385. }
  2386. }
  2387. this.classList = this.classList.concat(dest);
  2388. }
  2389. this._className = v;
  2390. }
  2391. });
  2392. Object.defineProperty(object, 'renderer', {
  2393. enumerable: false,
  2394. get: function() {
  2395. return this._renderer;
  2396. },
  2397. set: function(obj) {
  2398. this._renderer = obj;
  2399. }
  2400. });
  2401. }
  2402. });
  2403. _.extend(Shape.prototype, Events, {
  2404. constructor: Shape,
  2405. // Flags
  2406. /**
  2407. * @name Two.Shape#_id
  2408. * @private
  2409. * @property {Boolean} - Determines whether the id needs updating.
  2410. */
  2411. _flagId: true,
  2412. /**
  2413. * @name Two.Shape#_flagMatrix
  2414. * @private
  2415. * @property {Boolean} - Determines whether the matrix needs updating.
  2416. */
  2417. _flagMatrix: true,
  2418. /**
  2419. * @name Two.Shape#_flagScale
  2420. * @private
  2421. * @property {Boolean} - Determines whether the scale needs updating.
  2422. */
  2423. _flagScale: false,
  2424. // _flagMask: false,
  2425. // _flagClip: false,
  2426. /**
  2427. * @name Two.Shape#_flagClassName
  2428. * @private
  2429. * @property {Boolean} - Determines whether the {@link Two.Group#className} need updating.
  2430. */
  2431. _flagClassName: false,
  2432. // Underlying Properties
  2433. _id: '',
  2434. /**
  2435. * @name Two.Shape#_translation
  2436. * @private
  2437. * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
  2438. */
  2439. _translation: null,
  2440. /**
  2441. * @name Two.Shape#_rotation
  2442. * @private
  2443. * @property {Number} - The rotation value in Number.
  2444. */
  2445. _rotation: 0,
  2446. /**
  2447. * @name Two.Shape#_translation
  2448. * @private
  2449. * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
  2450. */
  2451. _scale: 1,
  2452. /**
  2453. * @name Two.Shape#_skewX
  2454. * @private
  2455. * @property {Number} - The rotation value in Number.
  2456. */
  2457. _skewX: 0,
  2458. /**
  2459. * @name Two.Shape#_skewY
  2460. * @private
  2461. * @property {Number} - The rotation value in Number.
  2462. */
  2463. _skewY: 0,
  2464. /**
  2465. * @name Two.Shape#className
  2466. * @property {String} - A class to be applied to the element to be compatible with CSS styling.
  2467. * @nota-bene Only available for the SVG renderer.
  2468. */
  2469. _className: '',
  2470. /**
  2471. * @name Two.Shape#addTo
  2472. * @function
  2473. * @param {Two.Group} group - The parent the shape adds itself to.
  2474. * @description Convenience method to add itself to the scenegraph.
  2475. */
  2476. addTo: function(group) {
  2477. group.add(this);
  2478. return this;
  2479. },
  2480. /**
  2481. * @name Two.Shape#clone
  2482. * @function
  2483. * @param {Two.Group} [parent] - Optional argument to automatically add the shape to a scenegraph.
  2484. * @returns {Two.Shape}
  2485. * @description Create a new {@link Two.Shape} with the same values as the current shape.
  2486. */
  2487. clone: function(parent) {
  2488. var clone = new Shape();
  2489. clone.translation.copy(this.translation);
  2490. clone.rotation = this.rotation;
  2491. clone.scale = this.scale;
  2492. clone.skewX = this.skewX;
  2493. clone.skewY = this.skewY;
  2494. if (this.matrix.manual) {
  2495. clone.matrix.copy(this.matrix);
  2496. }
  2497. if (parent) {
  2498. parent.add(clone);
  2499. }
  2500. return clone._update();
  2501. },
  2502. /**
  2503. * @name Two.Shape#_update
  2504. * @function
  2505. * @private
  2506. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  2507. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  2508. * @nota-bene Try not to call this method more than once a frame.
  2509. */
  2510. _update: function(bubbles) {
  2511. if (!this._matrix.manual && this._flagMatrix) {
  2512. this._matrix
  2513. .identity()
  2514. .translate(this.translation.x, this.translation.y);
  2515. if (this._scale instanceof Vector) {
  2516. this._matrix.scale(this._scale.x, this._scale.y);
  2517. } else {
  2518. this._matrix.scale(this._scale);
  2519. }
  2520. this._matrix.rotate(this.rotation);
  2521. this._matrix.skewX(this.skewX);
  2522. this._matrix.skewY(this.skewY);
  2523. }
  2524. if (bubbles) {
  2525. if (this.parent && this.parent._update) {
  2526. this.parent._update();
  2527. }
  2528. }
  2529. return this;
  2530. },
  2531. /**
  2532. * @name Two.Shape#flagReset
  2533. * @function
  2534. * @private
  2535. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  2536. */
  2537. flagReset: function() {
  2538. this._flagId = this._flagMatrix = this._flagScale =
  2539. this._flagClassName = false;
  2540. return this;
  2541. }
  2542. });
  2543. Shape.MakeObservable(Shape.prototype);
  2544. /**
  2545. * @name Two.Collection
  2546. * @class
  2547. * @extends Two.Events
  2548. * @description An `Array` like object with additional event propagation on actions. `pop`, `shift`, and `splice` trigger `removed` events. `push`, `unshift`, and `splice` with more than 2 arguments trigger 'inserted'. Finally, `sort` and `reverse` trigger `order` events.
  2549. */
  2550. function Collection() {
  2551. Array.call(this);
  2552. if (arguments[0] && Array.isArray(arguments[0])) {
  2553. if (arguments[0].length > 0) {
  2554. Array.prototype.push.apply(this, arguments[0]);
  2555. }
  2556. } else if (arguments.length > 0) {
  2557. Array.prototype.push.apply(this, arguments);
  2558. }
  2559. }
  2560. Collection.prototype = new Array();
  2561. _.extend(Collection.prototype, Events, {
  2562. constructor: Collection,
  2563. pop: function() {
  2564. var popped = Array.prototype.pop.apply(this, arguments);
  2565. this.trigger(Events.Types.remove, [popped]);
  2566. return popped;
  2567. },
  2568. shift: function() {
  2569. var shifted = Array.prototype.shift.apply(this, arguments);
  2570. this.trigger(Events.Types.remove, [shifted]);
  2571. return shifted;
  2572. },
  2573. push: function() {
  2574. var pushed = Array.prototype.push.apply(this, arguments);
  2575. this.trigger(Events.Types.insert, arguments);
  2576. return pushed;
  2577. },
  2578. unshift: function() {
  2579. var unshifted = Array.prototype.unshift.apply(this, arguments);
  2580. this.trigger(Events.Types.insert, arguments);
  2581. return unshifted;
  2582. },
  2583. splice: function() {
  2584. var spliced = Array.prototype.splice.apply(this, arguments);
  2585. var inserted;
  2586. this.trigger(Events.Types.remove, spliced);
  2587. if (arguments.length > 2) {
  2588. inserted = this.slice(arguments[0], arguments[0] + arguments.length - 2);
  2589. this.trigger(Events.Types.insert, inserted);
  2590. this.trigger(Events.Types.order);
  2591. }
  2592. return spliced;
  2593. },
  2594. sort: function() {
  2595. Array.prototype.sort.apply(this, arguments);
  2596. this.trigger(Events.Types.order);
  2597. return this;
  2598. },
  2599. reverse: function() {
  2600. Array.prototype.reverse.apply(this, arguments);
  2601. this.trigger(Events.Types.order);
  2602. return this;
  2603. },
  2604. indexOf: function() {
  2605. return Array.prototype.indexOf.apply(this, arguments);
  2606. }
  2607. });
  2608. /**
  2609. * @class
  2610. * @name Two.Group.Children
  2611. * @extends Two.Collection
  2612. * @description A children collection which is accesible both by index and by object `id`.
  2613. */
  2614. function Children(children) {
  2615. Collection.apply(this, arguments);
  2616. Object.defineProperty(this, '_events', {
  2617. value : {},
  2618. enumerable: false
  2619. });
  2620. /**
  2621. * @name Two.Group.Children#ids
  2622. * @property {Object} - Map of all elements in the list keyed by `id`s.
  2623. */
  2624. this.ids = {};
  2625. this.attach(
  2626. Array.isArray(children) ? children : Array.prototype.slice.call(arguments)
  2627. );
  2628. this.on(Events.Types.insert, this.attach);
  2629. this.on(Events.Types.remove, this.detach);
  2630. }
  2631. Children.prototype = new Collection();
  2632. _.extend(Children.prototype, {
  2633. constructor: Children,
  2634. /**
  2635. * @function
  2636. * @name Two.Group.Children#attach
  2637. * @param {Two.Shape[]} children - The objects which extend {@link Two.Shape} to be added.
  2638. * @description Adds elements to the `ids` map.
  2639. */
  2640. attach: function(children) {
  2641. for (var i = 0; i < children.length; i++) {
  2642. var child = children[i];
  2643. if (child && child.id) {
  2644. this.ids[child.id] = child;
  2645. }
  2646. }
  2647. return this;
  2648. },
  2649. /**
  2650. * @function
  2651. * @name Two.Group.Children#detach
  2652. * @param {Two.Shape[]} children - The objects which extend {@link Two.Shape} to be removed.
  2653. * @description Removes elements to the `ids` map.
  2654. */
  2655. detach: function(children) {
  2656. for (var i = 0; i < children.length; i++) {
  2657. delete this.ids[children[i].id];
  2658. }
  2659. return this;
  2660. }
  2661. });
  2662. // Constants
  2663. var min$3 = Math.min, max$3 = Math.max;
  2664. /**
  2665. * @name Two.Group
  2666. * @class
  2667. * @extends Two.Shape
  2668. * @param {Two.Shape[]} [children] - A list of objects that inherit {@link Two.Shape}. For instance, the array could be a {@link Two.Path}, {@link Two.Text}, and {@link Two.RoundedRectangle}.
  2669. * @description This is the primary class for grouping objects that are then drawn in Two.js. In Illustrator this is a group, in After Effects it would be a Null Object. Whichever the case, the `Two.Group` contains a transformation matrix and commands to style its children, but it by itself doesn't render to the screen.
  2670. * @nota-bene The {@link Two#scene} is an instance of `Two.Group`.
  2671. */
  2672. function Group(children) {
  2673. Shape.call(this, true);
  2674. this._renderer.type = 'group';
  2675. /**
  2676. * @name Two.Group#additions
  2677. * @property {Two.Shape[]}
  2678. * @description An automatically updated list of children that need to be appended to the renderer's scenegraph.
  2679. */
  2680. this.additions = [];
  2681. /**
  2682. * @name Two.Group#subtractions
  2683. * @property {Two.Shape[]}
  2684. * @description An automatically updated list of children that need to be removed from the renderer's scenegraph.
  2685. */
  2686. this.subtractions = [];
  2687. /**
  2688. * @name Two.Group#children
  2689. * @property {Two.Group.Children}
  2690. * @description A list of all the children in the scenegraph.
  2691. * @nota-bene Ther order of this list indicates the order each element is rendered to the screen.
  2692. */
  2693. this.children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments);
  2694. }
  2695. _.extend(Group, {
  2696. Children: Children,
  2697. /**
  2698. * @name Two.Group.InsertChildren
  2699. * @function
  2700. * @param {Two.Shape[]} children - The objects to be inserted.
  2701. * @description Cached method to let renderers know children have been added to a {@link Two.Group}.
  2702. */
  2703. InsertChildren: function(children) {
  2704. for (var i = 0; i < children.length; i++) {
  2705. replaceParent.call(this, children[i], this);
  2706. }
  2707. },
  2708. /**
  2709. * @name Two.Group.RemoveChildren
  2710. * @function
  2711. * @param {Two.Shape[]} children - The objects to be removed.
  2712. * @description Cached method to let renderers know children have been removed from a {@link Two.Group}.
  2713. */
  2714. RemoveChildren: function(children) {
  2715. for (var i = 0; i < children.length; i++) {
  2716. replaceParent.call(this, children[i]);
  2717. }
  2718. },
  2719. /**
  2720. * @name Two.Group.OrderChildren
  2721. * @function
  2722. * @description Cached method to let renderers know order has been updated on a {@link Two.Group}.
  2723. */
  2724. OrderChildren: function(children) {
  2725. this._flagOrder = true;
  2726. },
  2727. /**
  2728. * @name Two.Group.Properties
  2729. * @property {String[]} - A list of properties that are on every {@link Two.Group}.
  2730. */
  2731. Properties: [
  2732. 'fill',
  2733. 'stroke',
  2734. 'linewidth',
  2735. 'cap',
  2736. 'join',
  2737. 'miter',
  2738. 'closed',
  2739. 'curved',
  2740. 'automatic'
  2741. ],
  2742. /**
  2743. * @name Two.Group.MakeObservable
  2744. * @function
  2745. * @param {Object} object - The object to make observable.
  2746. * @description Convenience function to apply observable qualities of a {@link Two.Group} to any object. Handy if you'd like to extend the {@link Two.Group} class on a custom class.
  2747. */
  2748. MakeObservable: function(object) {
  2749. var properties = Group.Properties;
  2750. Object.defineProperty(object, 'visible', {
  2751. enumerable: true,
  2752. get: function() {
  2753. return this._visible;
  2754. },
  2755. set: function(v) {
  2756. this._flagVisible = this._visible !== v || this._flagVisible;
  2757. this._visible = v;
  2758. }
  2759. });
  2760. Object.defineProperty(object, 'opacity', {
  2761. enumerable: true,
  2762. get: function() {
  2763. return this._opacity;
  2764. },
  2765. set: function(v) {
  2766. this._flagOpacity = this._opacity !== v || this._flagOpacity;
  2767. this._opacity = v;
  2768. }
  2769. });
  2770. Object.defineProperty(object, 'beginning', {
  2771. enumerable: true,
  2772. get: function() {
  2773. return this._beginning;
  2774. },
  2775. set: function(v) {
  2776. this._flagBeginning = this._beginning !== v || this._flagBeginning;
  2777. this._beginning = v;
  2778. }
  2779. });
  2780. Object.defineProperty(object, 'ending', {
  2781. enumerable: true,
  2782. get: function() {
  2783. return this._ending;
  2784. },
  2785. set: function(v) {
  2786. this._flagEnding = this._ending !== v || this._flagEnding;
  2787. this._ending = v;
  2788. }
  2789. });
  2790. Object.defineProperty(object, 'length', {
  2791. enumerable: true,
  2792. get: function() {
  2793. if (this._flagLength || this._length <= 0) {
  2794. this._length = 0;
  2795. if (!this.children) {
  2796. return this._length;
  2797. }
  2798. for (var i = 0; i < this.children.length; i++) {
  2799. var child = this.children[i];
  2800. this._length += child.length;
  2801. }
  2802. }
  2803. return this._length;
  2804. }
  2805. });
  2806. Shape.MakeObservable(object);
  2807. Group.MakeGetterSetters(object, properties);
  2808. Object.defineProperty(object, 'children', {
  2809. enumerable: true,
  2810. get: function() {
  2811. return this._children;
  2812. },
  2813. set: function(children) {
  2814. var insertChildren = Group.InsertChildren.bind(this);
  2815. var removeChildren = Group.RemoveChildren.bind(this);
  2816. var orderChildren = Group.OrderChildren.bind(this);
  2817. if (this._children) {
  2818. this._children.unbind();
  2819. if (this._children.length > 0) {
  2820. removeChildren(this._children);
  2821. }
  2822. }
  2823. this._children = new Children(children);
  2824. this._children.bind(Events.Types.insert, insertChildren);
  2825. this._children.bind(Events.Types.remove, removeChildren);
  2826. this._children.bind(Events.Types.order, orderChildren);
  2827. if (children.length > 0) {
  2828. insertChildren(children);
  2829. }
  2830. }
  2831. });
  2832. Object.defineProperty(object, 'mask', {
  2833. enumerable: true,
  2834. get: function() {
  2835. return this._mask;
  2836. },
  2837. set: function(v) {
  2838. this._mask = v;
  2839. this._flagMask = true;
  2840. if (!v.clip) {
  2841. v.clip = true;
  2842. }
  2843. }
  2844. });
  2845. },
  2846. /**
  2847. * @name Two.Group.MakeGetterSetters
  2848. * @function
  2849. * @param {Two.Group} group - The group to apply getters and setters.
  2850. * @param {Object} properties - A key / value object containing properties to inherit.
  2851. * @description Convenience method to apply getter / setter logic on an array of properties. Used in {@link Two.Group.MakeObservable}.
  2852. */
  2853. MakeGetterSetters: function(group, properties) {
  2854. if (!Array.isArray(properties)) {
  2855. properties = [properties];
  2856. }
  2857. _.each(properties, function(k) {
  2858. Group.MakeGetterSetter(group, k);
  2859. });
  2860. },
  2861. /**
  2862. * @name Two.Group.MakeGetterSetter
  2863. * @function
  2864. * @param {Two.Group} group - The group to apply getters and setters.
  2865. * @param {String} key - The key which will become a property on the group.
  2866. * @description Convenience method to apply getter / setter logic specific to how `Two.Group`s trickle down styles to their children. Used in {@link Two.Group.MakeObservable}.
  2867. */
  2868. MakeGetterSetter: function(group, key) {
  2869. var secret = '_' + key;
  2870. Object.defineProperty(group, key, {
  2871. enumerable: true,
  2872. get: function() {
  2873. return this[secret];
  2874. },
  2875. set: function(v) {
  2876. this[secret] = v;
  2877. // Trickle down styles
  2878. for (var i = 0; i < this.children.length; i++) {
  2879. var child = this.children[i];
  2880. child[key] = v;
  2881. }
  2882. }
  2883. });
  2884. }
  2885. });
  2886. _.extend(Group.prototype, Shape.prototype, {
  2887. constructor: Group,
  2888. // Flags
  2889. // http://en.wikipedia.org/wiki/Flag
  2890. /**
  2891. * @name Two.Group#_flagAdditions
  2892. * @private
  2893. * @property {Boolean} - Determines whether the {@link Two.Group#additions} needs updating.
  2894. */
  2895. _flagAdditions: false,
  2896. /**
  2897. * @name Two.Group#_flagSubtractions
  2898. * @private
  2899. * @property {Boolean} - Determines whether the {@link Two.Group#subtractions} needs updating.
  2900. */
  2901. _flagSubtractions: false,
  2902. /**
  2903. * @name Two.Group#_flagOrder
  2904. * @private
  2905. * @property {Boolean} - Determines whether the {@link Two.Group#order} needs updating.
  2906. */
  2907. _flagOrder: false,
  2908. /**
  2909. * @name Two.Group#_flagVisible
  2910. * @private
  2911. * @property {Boolean} - Determines whether the {@link Two.Group#visible} needs updating.
  2912. */
  2913. /**
  2914. * @name Two.Group#_flagOpacity
  2915. * @private
  2916. * @property {Boolean} - Determines whether the {@link Two.Group#opacity} needs updating.
  2917. */
  2918. _flagOpacity: true,
  2919. /**
  2920. * @name Two.Group#_flagBeginning
  2921. * @private
  2922. * @property {Boolean} - Determines whether the {@link Two.Group#beginning} needs updating.
  2923. */
  2924. _flagBeginning: false,
  2925. /**
  2926. * @name Two.Group#_flagEnding
  2927. * @private
  2928. * @property {Boolean} - Determines whether the {@link Two.Group#ending} needs updating.
  2929. */
  2930. _flagEnding: false,
  2931. /**
  2932. * @name Two.Group#_flagLength
  2933. * @private
  2934. * @property {Boolean} - Determines whether the {@link Two.Group#length} needs updating.
  2935. */
  2936. _flagLength: false,
  2937. /**
  2938. * @name Two.Group#_flagMask
  2939. * @private
  2940. * @property {Boolean} - Determines whether the {@link Two.Group#mask} needs updating.
  2941. */
  2942. _flagMask: false,
  2943. // Underlying Properties
  2944. /**
  2945. * @name Two.Group#fill
  2946. * @property {(String|Two.Gradient|Two.Texture)} - The value of what all child shapes should be filled in with.
  2947. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  2948. */
  2949. _fill: '#fff',
  2950. /**
  2951. * @name Two.Group#stroke
  2952. * @property {(String|Two.Gradient|Two.Texture)} - The value of what all child shapes should be outlined in with.
  2953. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  2954. */
  2955. _stroke: '#000',
  2956. /**
  2957. * @name Two.Group#linewidth
  2958. * @property {Number} - The thickness in pixels of the stroke for all child shapes.
  2959. */
  2960. _linewidth: 1.0,
  2961. /**
  2962. * @name Two.Group#opacity
  2963. * @property {Number} - The opaqueness of all child shapes.
  2964. * @nota-bene Becomes multiplied by the individual child's opacity property.
  2965. */
  2966. _opacity: 1.0,
  2967. /**
  2968. * @name Two.Group#visible
  2969. * @property {Boolean} - Display the path or not.
  2970. * @nota-bene For {@link Two.CanvasRenderer} and {@link Two.WebGLRenderer} when set to false all updating is disabled improving performance dramatically with many objects in the scene.
  2971. */
  2972. _visible: true,
  2973. /**
  2974. * @name Two.Group#cap
  2975. * @property {String}
  2976. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty}
  2977. */
  2978. _cap: 'round',
  2979. /**
  2980. * @name Two.Group#join
  2981. * @property {String}
  2982. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty}
  2983. */
  2984. _join: 'round',
  2985. /**
  2986. * @name Two.Group#miter
  2987. * @property {String}
  2988. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty}
  2989. */
  2990. _miter: 4,
  2991. /**
  2992. * @name Two.Group#closed
  2993. * @property {Boolean} - Determines whether a final line is drawn between the final point in the `vertices` array and the first point of all child shapes.
  2994. */
  2995. _closed: true,
  2996. /**
  2997. * @name Two.Group#curved
  2998. * @property {Boolean} - When the child's path is `automatic = true` this boolean determines whether the lines between the points are curved or not.
  2999. */
  3000. _curved: false,
  3001. /**
  3002. * @name Two.Group#automatic
  3003. * @property {Boolean} - Determines whether or not Two.js should calculate curves, lines, and commands automatically for you or to let the developer manipulate them for themselves.
  3004. */
  3005. _automatic: true,
  3006. /**
  3007. * @name Two.Group#beginning
  3008. * @property {Number} - Number between zero and one to state the beginning of where the path is rendered.
  3009. * @description {@link Two.Group#beginning} is a percentage value that represents at what percentage into all child shapes should the renderer start drawing.
  3010. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Group#ending}.
  3011. */
  3012. _beginning: 0,
  3013. /**
  3014. * @name Two.Group#ending
  3015. * @property {Number} - Number between zero and one to state the ending of where the path is rendered.
  3016. * @description {@link Two.Group#ending} is a percentage value that represents at what percentage into all child shapes should the renderer start drawing.
  3017. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Group#beginning}.
  3018. */
  3019. _ending: 1.0,
  3020. /**
  3021. * @name Two.Group#length
  3022. * @property {Number} - The sum of distances between all child lengths.
  3023. */
  3024. _length: 0,
  3025. /**
  3026. * @name Two.Group#mask
  3027. * @property {Two.Shape} - The Two.js object to clip from a group's rendering.
  3028. */
  3029. _mask: null,
  3030. /**
  3031. * @name Two.Group#clone
  3032. * @function
  3033. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  3034. * @returns {Two.Group}
  3035. * @description Create a new instance of {@link Two.Group} with the same properties of the current group.
  3036. */
  3037. clone: function(parent) {
  3038. // /**
  3039. // * TODO: Group has a gotcha in that it's at the moment required to be bound to
  3040. // * an instance of two in order to add elements correctly. This needs to
  3041. // * be rethought and fixed.
  3042. // */
  3043. var clone = new Group();
  3044. var children = this.children.map(function(child) {
  3045. return child.clone();
  3046. });
  3047. clone.add(children);
  3048. clone.opacity = this.opacity;
  3049. if (this.mask) {
  3050. clone.mask = this.mask;
  3051. }
  3052. clone.translation.copy(this.translation);
  3053. clone.rotation = this.rotation;
  3054. clone.scale = this.scale;
  3055. clone.className = this.className;
  3056. if (this.matrix.manual) {
  3057. clone.matrix.copy(this.matrix);
  3058. }
  3059. if (parent) {
  3060. parent.add(clone);
  3061. }
  3062. return clone._update();
  3063. },
  3064. /**
  3065. * @name Two.Group#toObject
  3066. * @function
  3067. * @returns {Object}
  3068. * @description Return a JSON compatible plain object that represents the group.
  3069. */
  3070. toObject: function() {
  3071. var result = {
  3072. children: [],
  3073. translation: this.translation.toObject(),
  3074. rotation: this.rotation,
  3075. scale: this.scale instanceof Vector ? this.scale.toObject() : this.scale,
  3076. opacity: this.opacity,
  3077. className: this.className,
  3078. mask: (this.mask ? this.mask.toObject() : null)
  3079. };
  3080. if (this.matrix.manual) {
  3081. result.matrix = this.matrix.toObject();
  3082. }
  3083. _.each(this.children, function(child, i) {
  3084. result.children[i] = child.toObject();
  3085. }, this);
  3086. return result;
  3087. },
  3088. /**
  3089. * @name Two.Group#corner
  3090. * @function
  3091. * @description Orient the children of the group to the upper left-hand corner of that group.
  3092. */
  3093. corner: function() {
  3094. var rect = this.getBoundingClientRect(true);
  3095. for (var i = 0; i < this.children.length; i++) {
  3096. var child = this.children[i];
  3097. child.translation.x -= rect.left;
  3098. child.translation.y -= rect.top;
  3099. }
  3100. return this;
  3101. },
  3102. /**
  3103. * @name Two.Group#center
  3104. * @function
  3105. * @description Orient the children of the group to the center of that group.
  3106. */
  3107. center: function() {
  3108. var rect = this.getBoundingClientRect(true);
  3109. var cx = rect.left + rect.width / 2 - this.translation.x;
  3110. var cy = rect.top + rect.height / 2 - this.translation.y;
  3111. for (var i = 0; i < this.children.length; i++) {
  3112. var child = this.children[i];
  3113. if (child.isShape) {
  3114. child.translation.x -= cx;
  3115. child.translation.y -= cy;
  3116. }
  3117. }
  3118. return this;
  3119. },
  3120. /**
  3121. * @name Two.Group#getById
  3122. * @function
  3123. * @description Recursively search for id. Returns the first element found.
  3124. * @returns {Two.Shape} - Or `null` if nothing is found.
  3125. */
  3126. getById: function (id) {
  3127. var found = null;
  3128. function search(node) {
  3129. if (node.id === id) {
  3130. return node;
  3131. } else if (node.children) {
  3132. for (var i = 0; i < node.children.length; i++) {
  3133. found = search(node.children[i]);
  3134. if (found) {
  3135. return found;
  3136. }
  3137. }
  3138. }
  3139. return null;
  3140. }
  3141. return search(this);
  3142. },
  3143. /**
  3144. * @name Two.Group#getByClassName
  3145. * @function
  3146. * @description Recursively search for classes. Returns an array of matching elements.
  3147. * @returns {Two.Shape[]} - Or empty array if nothing is found.
  3148. */
  3149. getByClassName: function(className) {
  3150. var found = [];
  3151. function search(node) {
  3152. if (Array.prototype.indexOf.call(node.classList, className) >= 0) {
  3153. found.push(node);
  3154. }
  3155. if (node.children) {
  3156. for (var i = 0; i < node.children.length; i++) {
  3157. var child = node.children[i];
  3158. search(child);
  3159. }
  3160. }
  3161. return found;
  3162. }
  3163. return search(this);
  3164. },
  3165. /**
  3166. * @name Two.Group#getByType
  3167. * @function
  3168. * @description Recursively search for children of a specific type, e.g. {@link Two.Path}. Pass a reference to this type as the param. Returns an array of matching elements.
  3169. * @returns {Two.Shape[]} - Empty array if nothing is found.
  3170. */
  3171. getByType: function(type) {
  3172. var found = [];
  3173. function search(node) {
  3174. if (node instanceof type) {
  3175. found.push(node);
  3176. }
  3177. if (node.children) {
  3178. for (var i = 0; i < node.children.length; i++) {
  3179. var child = node.children[i];
  3180. search(child);
  3181. }
  3182. }
  3183. return found;
  3184. }
  3185. return search(this);
  3186. },
  3187. /**
  3188. * @name Two.Group#add
  3189. * @function
  3190. * @param {Two.Shape[]} objects - An array of objects to be added. Can be also be supplied as individual arguments.
  3191. * @description Add objects to the group.
  3192. */
  3193. add: function(objects) {
  3194. // Allow to pass multiple objects either as array or as multiple arguments
  3195. // If it's an array also create copy of it in case we're getting passed
  3196. // a childrens array directly.
  3197. if (!(objects instanceof Array)) {
  3198. objects = Array.prototype.slice.call(arguments);
  3199. } else {
  3200. objects = objects.slice();
  3201. }
  3202. // Add the objects
  3203. for (var i = 0; i < objects.length; i++) {
  3204. var child = objects[i];
  3205. if (!(child && child.id)) {
  3206. continue;
  3207. }
  3208. var index = Array.prototype.indexOf.call(this.children, child);
  3209. if (index >= 0) {
  3210. this.children.splice(index, 1);
  3211. }
  3212. this.children.push(child);
  3213. }
  3214. return this;
  3215. },
  3216. /**
  3217. * @name Two.Group#add
  3218. * @function
  3219. * @param {Two.Shape[]} objects - An array of objects to be removed. Can be also removed as individual arguments.
  3220. * @description Remove objects from the group.
  3221. */
  3222. remove: function(objects) {
  3223. var l = arguments.length,
  3224. grandparent = this.parent;
  3225. // Allow to call remove without arguments
  3226. // This will detach the object from its own parent.
  3227. if (l <= 0 && grandparent) {
  3228. grandparent.remove(this);
  3229. return this;
  3230. }
  3231. // Allow to pass multiple objects either as array or as multiple arguments
  3232. // If it's an array also create copy of it in case we're getting passed
  3233. // a childrens array directly.
  3234. if (!(objects instanceof Array)) {
  3235. objects = Array.prototype.slice.call(arguments);
  3236. } else {
  3237. objects = objects.slice();
  3238. }
  3239. // Remove the objects
  3240. for (var i = 0; i < objects.length; i++) {
  3241. var object = objects[i];
  3242. if (!object || !this.children.ids[object.id]) {
  3243. continue;
  3244. }
  3245. var index = this.children.indexOf(object);
  3246. if (index >= 0) {
  3247. this.children.splice(index, 1);
  3248. }
  3249. }
  3250. return this;
  3251. },
  3252. /**
  3253. * @name Two.Group#getBoundingClientRect
  3254. * @function
  3255. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  3256. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  3257. * @description Return an object with top, left, right, bottom, width, and height parameters of the group.
  3258. */
  3259. getBoundingClientRect: function(shallow) {
  3260. var rect, matrix, a, b, c, d, tc, lc, rc, bc;
  3261. // TODO: Update this to not __always__ update. Just when it needs to.
  3262. this._update(true);
  3263. // Variables need to be defined here, because of nested nature of groups.
  3264. var left = Infinity, right = -Infinity,
  3265. top = Infinity, bottom = -Infinity;
  3266. var regex = /texture|gradient/i;
  3267. matrix = shallow ? this._matrix : getComputedMatrix(this);
  3268. for (var i = 0; i < this.children.length; i++) {
  3269. var child = this.children[i];
  3270. if (!child.visible || regex.test(child._renderer.type)) {
  3271. continue;
  3272. }
  3273. rect = child.getBoundingClientRect(shallow);
  3274. tc = typeof rect.top !== 'number' || _.isNaN(rect.top) || !isFinite(rect.top);
  3275. lc = typeof rect.left !== 'number' || _.isNaN(rect.left) || !isFinite(rect.left);
  3276. rc = typeof rect.right !== 'number' || _.isNaN(rect.right) || !isFinite(rect.right);
  3277. bc = typeof rect.bottom !== 'number' || _.isNaN(rect.bottom) || !isFinite(rect.bottom);
  3278. if (tc || lc || rc || bc) {
  3279. continue;
  3280. }
  3281. top = min$3(rect.top, top);
  3282. left = min$3(rect.left, left);
  3283. right = max$3(rect.right, right);
  3284. bottom = max$3(rect.bottom, bottom);
  3285. }
  3286. if (shallow) {
  3287. a = matrix.multiply(left, top, 1);
  3288. b = matrix.multiply(left, bottom, 1);
  3289. c = matrix.multiply(right, top, 1);
  3290. d = matrix.multiply(right, bottom, 1);
  3291. top = min$3(a.y, b.y, c.y, d.y);
  3292. left = min$3(a.x, b.x, c.x, d.x);
  3293. right = max$3(a.x, b.x, c.x, d.x);
  3294. bottom = max$3(a.y, b.y, c.y, d.y);
  3295. }
  3296. return {
  3297. top: top,
  3298. left: left,
  3299. right: right,
  3300. bottom: bottom,
  3301. width: right - left,
  3302. height: bottom - top
  3303. };
  3304. },
  3305. /**
  3306. * @name Two.Group#noFill
  3307. * @function
  3308. * @description Apply `noFill` method to all child shapes.
  3309. */
  3310. noFill: function() {
  3311. this.children.forEach(function(child) {
  3312. child.noFill();
  3313. });
  3314. return this;
  3315. },
  3316. /**
  3317. * @name Two.Group#noStroke
  3318. * @function
  3319. * @description Apply `noStroke` method to all child shapes.
  3320. */
  3321. noStroke: function() {
  3322. this.children.forEach(function(child) {
  3323. child.noStroke();
  3324. });
  3325. return this;
  3326. },
  3327. /**
  3328. * @name Two.Group#subdivide
  3329. * @function
  3330. * @description Apply `subdivide` method to all child shapes.
  3331. */
  3332. subdivide: function() {
  3333. var args = arguments;
  3334. this.children.forEach(function(child) {
  3335. child.subdivide.apply(child, args);
  3336. });
  3337. return this;
  3338. },
  3339. /**
  3340. * @name Two.Group#_update
  3341. * @function
  3342. * @private
  3343. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  3344. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  3345. * @nota-bene Try not to call this method more than once a frame.
  3346. */
  3347. _update: function() {
  3348. var i, l, child;
  3349. if (this._flagBeginning || this._flagEnding) {
  3350. var beginning = Math.min(this._beginning, this._ending);
  3351. var ending = Math.max(this._beginning, this._ending);
  3352. var length = this.length;
  3353. var sum = 0;
  3354. var bd = beginning * length;
  3355. var ed = ending * length;
  3356. for (i = 0; i < this.children.length; i++) {
  3357. child = this.children[i];
  3358. l = child.length;
  3359. if (bd > sum + l) {
  3360. child.beginning = 1;
  3361. child.ending = 1;
  3362. } else if (ed < sum) {
  3363. child.beginning = 0;
  3364. child.ending = 0;
  3365. } else if (bd > sum && bd < sum + l) {
  3366. child.beginning = (bd - sum) / l;
  3367. child.ending = 1;
  3368. } else if (ed > sum && ed < sum + l) {
  3369. child.beginning = 0;
  3370. child.ending = (ed - sum) / l;
  3371. } else {
  3372. child.beginning = 0;
  3373. child.ending = 1;
  3374. }
  3375. sum += l;
  3376. }
  3377. }
  3378. return Shape.prototype._update.apply(this, arguments);
  3379. },
  3380. /**
  3381. * @name Two.Group#flagReset
  3382. * @function
  3383. * @private
  3384. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  3385. */
  3386. flagReset: function() {
  3387. if (this._flagAdditions) {
  3388. this.additions.length = 0;
  3389. this._flagAdditions = false;
  3390. }
  3391. if (this._flagSubtractions) {
  3392. this.subtractions.length = 0;
  3393. this._flagSubtractions = false;
  3394. }
  3395. this._flagOrder = this._flagMask = this._flagOpacity =
  3396. this._flagBeginning = this._flagEnding = false;
  3397. Shape.prototype.flagReset.call(this);
  3398. return this;
  3399. }
  3400. });
  3401. Group.MakeObservable(Group.prototype);
  3402. // /**
  3403. // * Helper function used to sync parent-child relationship within the
  3404. // * `Two.Group.children` object.
  3405. // *
  3406. // * Set the parent of the passed object to another object
  3407. // * and updates parent-child relationships
  3408. // * Calling with one arguments will simply remove the parenting
  3409. // */
  3410. function replaceParent(child, newParent) {
  3411. var parent = child.parent;
  3412. var index;
  3413. if (parent === newParent) {
  3414. add();
  3415. return;
  3416. }
  3417. if (parent && parent.children.ids[child.id]) {
  3418. index = Array.prototype.indexOf.call(parent.children, child);
  3419. parent.children.splice(index, 1);
  3420. splice();
  3421. }
  3422. if (newParent) {
  3423. add();
  3424. return;
  3425. }
  3426. splice();
  3427. if (parent._flagAdditions && parent.additions.length === 0) {
  3428. parent._flagAdditions = false;
  3429. }
  3430. if (parent._flagSubtractions && parent.subtractions.length === 0) {
  3431. parent._flagSubtractions = false;
  3432. }
  3433. delete child.parent;
  3434. function add() {
  3435. if (newParent.subtractions.length > 0) {
  3436. index = Array.prototype.indexOf.call(newParent.subtractions, child);
  3437. if (index >= 0) {
  3438. newParent.subtractions.splice(index, 1);
  3439. }
  3440. }
  3441. if (newParent.additions.length > 0) {
  3442. index = Array.prototype.indexOf.call(newParent.additions, child);
  3443. if (index >= 0) {
  3444. newParent.additions.splice(index, 1);
  3445. }
  3446. }
  3447. child.parent = newParent;
  3448. newParent.additions.push(child);
  3449. newParent._flagAdditions = true;
  3450. }
  3451. function splice() {
  3452. index = Array.prototype.indexOf.call(parent.additions, child);
  3453. if (index >= 0) {
  3454. parent.additions.splice(index, 1);
  3455. }
  3456. index = Array.prototype.indexOf.call(parent.subtractions, child);
  3457. if (index < 0) {
  3458. parent.subtractions.push(child);
  3459. parent._flagSubtractions = true;
  3460. }
  3461. }
  3462. }
  3463. // Constants
  3464. var emptyArray = [];
  3465. var TWO_PI$5 = Math.PI * 2,
  3466. max$2 = Math.max,
  3467. min$2 = Math.min,
  3468. abs = Math.abs,
  3469. sin$4 = Math.sin,
  3470. cos$4 = Math.cos,
  3471. acos = Math.acos,
  3472. sqrt = Math.sqrt;
  3473. // Returns true if this is a non-transforming matrix
  3474. var isDefaultMatrix = function (m) {
  3475. return (m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0);
  3476. };
  3477. var canvas = {
  3478. isHidden: /(undefined|none|transparent)/i,
  3479. alignments: {
  3480. left: 'start',
  3481. middle: 'center',
  3482. right: 'end'
  3483. },
  3484. shim: function(elem, name) {
  3485. elem.tagName = elem.nodeName = name || 'canvas';
  3486. elem.nodeType = 1;
  3487. elem.getAttribute = function(prop) {
  3488. return this[prop];
  3489. };
  3490. elem.setAttribute = function(prop, val) {
  3491. this[prop] = val;
  3492. return this;
  3493. };
  3494. return elem;
  3495. },
  3496. group: {
  3497. renderChild: function(child) {
  3498. canvas[child._renderer.type].render.call(child, this.ctx, true, this.clip);
  3499. },
  3500. render: function(ctx) {
  3501. if (!this._visible) {
  3502. return this;
  3503. }
  3504. this._update();
  3505. var matrix = this._matrix.elements;
  3506. var parent = this.parent;
  3507. this._renderer.opacity = this._opacity
  3508. * (parent && parent._renderer ? parent._renderer.opacity : 1);
  3509. var mask = this._mask;
  3510. // var clip = this._clip;
  3511. var defaultMatrix = isDefaultMatrix(matrix);
  3512. var shouldIsolate = !defaultMatrix || !!mask;
  3513. if (!this._renderer.context) {
  3514. this._renderer.context = {};
  3515. }
  3516. this._renderer.context.ctx = ctx;
  3517. // this._renderer.context.clip = clip;
  3518. if (shouldIsolate) {
  3519. ctx.save();
  3520. if (!defaultMatrix) {
  3521. ctx.transform(matrix[0], matrix[3], matrix[1],
  3522. matrix[4], matrix[2], matrix[5]);
  3523. }
  3524. }
  3525. if (mask) {
  3526. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3527. }
  3528. if (this._opacity > 0 && this._scale !== 0) {
  3529. for (var i = 0; i < this.children.length; i++) {
  3530. var child = this.children[i];
  3531. canvas[child._renderer.type].render.call(child, ctx);
  3532. }
  3533. }
  3534. if (shouldIsolate) {
  3535. ctx.restore();
  3536. }
  3537. // Commented two-way functionality of clips / masks with groups and
  3538. // polygons. Uncomment when this bug is fixed:
  3539. // https://code.google.com/p/chromium/issues/detail?id=370951
  3540. // if (clip) {
  3541. // ctx.clip();
  3542. // }
  3543. return this.flagReset();
  3544. }
  3545. },
  3546. path: {
  3547. render: function(ctx, forced, parentClipped) {
  3548. var matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter,
  3549. closed, commands, length, last, next, prev, a, b, c, d, ux, uy, vx, vy,
  3550. ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset, dashes, po;
  3551. po = (this.parent && this.parent._renderer)
  3552. ? this.parent._renderer.opacity : 1;
  3553. mask = this._mask;
  3554. clip = this._clip;
  3555. opacity = this._opacity * (po || 1);
  3556. visible = this._visible;
  3557. if (!forced && (!visible || clip || opacity === 0)) {
  3558. return this;
  3559. }
  3560. this._update();
  3561. matrix = this._matrix.elements;
  3562. stroke = this._stroke;
  3563. linewidth = this._linewidth;
  3564. fill = this._fill;
  3565. cap = this._cap;
  3566. join = this._join;
  3567. miter = this._miter;
  3568. closed = this._closed;
  3569. commands = this._renderer.vertices; // Commands
  3570. length = commands.length;
  3571. last = length - 1;
  3572. defaultMatrix = isDefaultMatrix(matrix);
  3573. dashes = this.dashes;
  3574. // Transform
  3575. if (!defaultMatrix) {
  3576. ctx.save();
  3577. ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  3578. }
  3579. // Commented two-way functionality of clips / masks with groups and
  3580. // polygons. Uncomment when this bug is fixed:
  3581. // https://code.google.com/p/chromium/issues/detail?id=370951
  3582. if (mask) {
  3583. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3584. }
  3585. // Styles
  3586. if (fill) {
  3587. if (typeof fill === 'string') {
  3588. ctx.fillStyle = fill;
  3589. } else {
  3590. canvas[fill._renderer.type].render.call(fill, ctx);
  3591. ctx.fillStyle = fill._renderer.effect;
  3592. }
  3593. }
  3594. if (stroke) {
  3595. if (typeof stroke === 'string') {
  3596. ctx.strokeStyle = stroke;
  3597. } else {
  3598. canvas[stroke._renderer.type].render.call(stroke, ctx);
  3599. ctx.strokeStyle = stroke._renderer.effect;
  3600. }
  3601. if (linewidth) {
  3602. ctx.lineWidth = linewidth;
  3603. }
  3604. if (miter) {
  3605. ctx.miterLimit = miter;
  3606. }
  3607. if (join) {
  3608. ctx.lineJoin = join;
  3609. }
  3610. if (!closed && cap) {
  3611. ctx.lineCap = cap;
  3612. }
  3613. }
  3614. if (typeof opacity === 'number') {
  3615. ctx.globalAlpha = opacity;
  3616. }
  3617. if (dashes && dashes.length > 0) {
  3618. ctx.lineDashOffset = dashes.offset || 0;
  3619. ctx.setLineDash(dashes);
  3620. }
  3621. ctx.beginPath();
  3622. for (var i = 0; i < commands.length; i++) {
  3623. b = commands[i];
  3624. x = b.x;
  3625. y = b.y;
  3626. switch (b.command) {
  3627. case Commands.close:
  3628. ctx.closePath();
  3629. break;
  3630. case Commands.arc:
  3631. var rx = b.rx;
  3632. var ry = b.ry;
  3633. var xAxisRotation = b.xAxisRotation;
  3634. var largeArcFlag = b.largeArcFlag;
  3635. var sweepFlag = b.sweepFlag;
  3636. prev = closed ? mod(i - 1, length) : max$2(i - 1, 0);
  3637. a = commands[prev];
  3638. var ax = a.x;
  3639. var ay = a.y;
  3640. canvas.renderSvgArcCommand(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y);
  3641. break;
  3642. case Commands.curve:
  3643. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  3644. next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  3645. a = commands[prev];
  3646. c = commands[next];
  3647. ar = (a.controls && a.controls.right) || Vector.zero;
  3648. bl = (b.controls && b.controls.left) || Vector.zero;
  3649. if (a._relative) {
  3650. vx = (ar.x + a.x);
  3651. vy = (ar.y + a.y);
  3652. } else {
  3653. vx = ar.x;
  3654. vy = ar.y;
  3655. }
  3656. if (b._relative) {
  3657. ux = (bl.x + b.x);
  3658. uy = (bl.y + b.y);
  3659. } else {
  3660. ux = bl.x;
  3661. uy = bl.y;
  3662. }
  3663. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  3664. if (i >= last && closed) {
  3665. c = d;
  3666. br = (b.controls && b.controls.right) || Vector.zero;
  3667. cl = (c.controls && c.controls.left) || Vector.zero;
  3668. if (b._relative) {
  3669. vx = (br.x + b.x);
  3670. vy = (br.y + b.y);
  3671. } else {
  3672. vx = br.x;
  3673. vy = br.y;
  3674. }
  3675. if (c._relative) {
  3676. ux = (cl.x + c.x);
  3677. uy = (cl.y + c.y);
  3678. } else {
  3679. ux = cl.x;
  3680. uy = cl.y;
  3681. }
  3682. x = c.x;
  3683. y = c.y;
  3684. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  3685. }
  3686. break;
  3687. case Commands.line:
  3688. ctx.lineTo(x, y);
  3689. break;
  3690. case Commands.move:
  3691. d = b;
  3692. ctx.moveTo(x, y);
  3693. break;
  3694. }
  3695. }
  3696. // Loose ends
  3697. if (closed) {
  3698. ctx.closePath();
  3699. }
  3700. if (!clip && !parentClipped) {
  3701. if (!canvas.isHidden.test(fill)) {
  3702. isOffset = fill._renderer && fill._renderer.offset;
  3703. if (isOffset) {
  3704. ctx.save();
  3705. ctx.translate(
  3706. - fill._renderer.offset.x, - fill._renderer.offset.y);
  3707. ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  3708. }
  3709. ctx.fill();
  3710. if (isOffset) {
  3711. ctx.restore();
  3712. }
  3713. }
  3714. if (!canvas.isHidden.test(stroke)) {
  3715. isOffset = stroke._renderer && stroke._renderer.offset;
  3716. if (isOffset) {
  3717. ctx.save();
  3718. ctx.translate(
  3719. - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  3720. ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  3721. ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  3722. }
  3723. ctx.stroke();
  3724. if (isOffset) {
  3725. ctx.restore();
  3726. }
  3727. }
  3728. }
  3729. if (!defaultMatrix) {
  3730. ctx.restore();
  3731. }
  3732. if (clip && !parentClipped) {
  3733. ctx.clip();
  3734. }
  3735. if (dashes && dashes.length > 0) {
  3736. ctx.setLineDash(emptyArray);
  3737. }
  3738. return this.flagReset();
  3739. }
  3740. },
  3741. text: {
  3742. render: function(ctx, forced, parentClipped) {
  3743. var po = (this.parent && this.parent._renderer)
  3744. ? this.parent._renderer.opacity : 1;
  3745. var opacity = this._opacity * po;
  3746. var visible = this._visible;
  3747. var mask = this._mask;
  3748. var clip = this._clip;
  3749. if (!forced && (!visible || clip || opacity === 0)) {
  3750. return this;
  3751. }
  3752. this._update();
  3753. var matrix = this._matrix.elements;
  3754. var stroke = this._stroke;
  3755. var linewidth = this._linewidth;
  3756. var fill = this._fill;
  3757. var decoration = this._decoration;
  3758. var defaultMatrix = isDefaultMatrix(matrix);
  3759. var isOffset = fill._renderer && fill._renderer.offset
  3760. && stroke._renderer && stroke._renderer.offset;
  3761. var dashes = this.dashes;
  3762. var alignment = canvas.alignments[this._alignment] || this._alignment;
  3763. var baseline = this._baseline;
  3764. var a, b, c, d, e, sx, sy, x1, y1, x2, y2;
  3765. // Transform
  3766. if (!defaultMatrix) {
  3767. ctx.save();
  3768. ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  3769. }
  3770. // Commented two-way functionality of clips / masks with groups and
  3771. // polygons. Uncomment when this bug is fixed:
  3772. // https://code.google.com/p/chromium/issues/detail?id=370951
  3773. if (mask) {
  3774. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3775. }
  3776. if (!isOffset) {
  3777. ctx.font = [this._style, this._weight, this._size + 'px/' +
  3778. this._leading + 'px', this._family].join(' ');
  3779. }
  3780. ctx.textAlign = alignment;
  3781. ctx.textBaseline = baseline;
  3782. // Styles
  3783. if (fill) {
  3784. if (typeof fill === 'string') {
  3785. ctx.fillStyle = fill;
  3786. } else {
  3787. canvas[fill._renderer.type].render.call(fill, ctx);
  3788. ctx.fillStyle = fill._renderer.effect;
  3789. }
  3790. }
  3791. if (stroke) {
  3792. if (typeof stroke === 'string') {
  3793. ctx.strokeStyle = stroke;
  3794. } else {
  3795. canvas[stroke._renderer.type].render.call(stroke, ctx);
  3796. ctx.strokeStyle = stroke._renderer.effect;
  3797. }
  3798. if (linewidth) {
  3799. ctx.lineWidth = linewidth;
  3800. }
  3801. }
  3802. if (typeof opacity === 'number') {
  3803. ctx.globalAlpha = opacity;
  3804. }
  3805. if (dashes && dashes.length > 0) {
  3806. ctx.lineDashOffset = dashes.offset || 0;
  3807. ctx.setLineDash(dashes);
  3808. }
  3809. if (!clip && !parentClipped) {
  3810. if (!canvas.isHidden.test(fill)) {
  3811. if (fill._renderer && fill._renderer.offset) {
  3812. sx = fill._renderer.scale.x;
  3813. sy = fill._renderer.scale.y;
  3814. ctx.save();
  3815. ctx.translate( - fill._renderer.offset.x,
  3816. - fill._renderer.offset.y);
  3817. ctx.scale(sx, sy);
  3818. a = this._size / fill._renderer.scale.y;
  3819. b = this._leading / fill._renderer.scale.y;
  3820. ctx.font = [this._style, this._weight, a + 'px/',
  3821. b + 'px', this._family].join(' ');
  3822. c = fill._renderer.offset.x / fill._renderer.scale.x;
  3823. d = fill._renderer.offset.y / fill._renderer.scale.y;
  3824. ctx.fillText(this.value, c, d);
  3825. ctx.restore();
  3826. } else {
  3827. ctx.fillText(this.value, 0, 0);
  3828. }
  3829. }
  3830. if (!canvas.isHidden.test(stroke)) {
  3831. if (stroke._renderer && stroke._renderer.offset) {
  3832. sx = stroke._renderer.scale.x;
  3833. sy = stroke._renderer.scale.y;
  3834. ctx.save();
  3835. ctx.translate(- stroke._renderer.offset.x,
  3836. - stroke._renderer.offset.y);
  3837. ctx.scale(sx, sy);
  3838. a = this._size / stroke._renderer.scale.y;
  3839. b = this._leading / stroke._renderer.scale.y;
  3840. ctx.font = [this._style, this._weight, a + 'px/',
  3841. b + 'px', this._family].join(' ');
  3842. c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  3843. d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  3844. e = linewidth / stroke._renderer.scale.x;
  3845. ctx.lineWidth = e;
  3846. ctx.strokeText(this.value, c, d);
  3847. ctx.restore();
  3848. } else {
  3849. ctx.strokeText(this.value, 0, 0);
  3850. }
  3851. }
  3852. }
  3853. // Handle text-decoration
  3854. if (/(underline|strikethrough)/i.test(decoration)) {
  3855. var metrics = ctx.measureText(this.value);
  3856. var scalar = 1;
  3857. switch (decoration) {
  3858. case 'underline':
  3859. y1 = metrics.actualBoundingBoxAscent;
  3860. y2 = metrics.actualBoundingBoxAscent;
  3861. break;
  3862. case 'strikethrough':
  3863. y1 = 0;
  3864. y2 = 0;
  3865. scalar = 0.5;
  3866. break;
  3867. }
  3868. switch (baseline) {
  3869. case 'top':
  3870. y1 += this._size * scalar;
  3871. y2 += this._size * scalar;
  3872. break;
  3873. case 'baseline':
  3874. case 'bottom':
  3875. y1 -= this._size * scalar;
  3876. y2 -= this._size * scalar;
  3877. break;
  3878. }
  3879. switch (alignment) {
  3880. case 'left':
  3881. case 'start':
  3882. x1 = 0;
  3883. x2 = metrics.width;
  3884. break;
  3885. case 'right':
  3886. case 'end':
  3887. x1 = - metrics.width;
  3888. x2 = 0;
  3889. break;
  3890. default:
  3891. x1 = - metrics.width / 2;
  3892. x2 = metrics.width / 2;
  3893. }
  3894. ctx.lineWidth = Math.max(Math.floor(this._size / 15), 1);
  3895. ctx.strokeStyle = ctx.fillStyle;
  3896. ctx.beginPath();
  3897. ctx.moveTo(x1, y1);
  3898. ctx.lineTo(x2, y2);
  3899. ctx.stroke();
  3900. }
  3901. if (!defaultMatrix) {
  3902. ctx.restore();
  3903. }
  3904. // TODO: Test for text
  3905. if (clip && !parentClipped) {
  3906. ctx.clip();
  3907. }
  3908. if (dashes && dashes.length > 0) {
  3909. ctx.setLineDash(emptyArray);
  3910. }
  3911. return this.flagReset();
  3912. }
  3913. },
  3914. 'linear-gradient': {
  3915. render: function(ctx) {
  3916. this._update();
  3917. if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  3918. this._renderer.effect = ctx.createLinearGradient(
  3919. this.left._x, this.left._y,
  3920. this.right._x, this.right._y
  3921. );
  3922. for (var i = 0; i < this.stops.length; i++) {
  3923. var stop = this.stops[i];
  3924. this._renderer.effect.addColorStop(stop._offset, stop._color);
  3925. }
  3926. }
  3927. return this.flagReset();
  3928. }
  3929. },
  3930. 'radial-gradient': {
  3931. render: function(ctx) {
  3932. this._update();
  3933. if (!this._renderer.effect || this._flagCenter || this._flagFocal
  3934. || this._flagRadius || this._flagStops) {
  3935. this._renderer.effect = ctx.createRadialGradient(
  3936. this.center._x, this.center._y, 0,
  3937. this.focal._x, this.focal._y, this._radius
  3938. );
  3939. for (var i = 0; i < this.stops.length; i++) {
  3940. var stop = this.stops[i];
  3941. this._renderer.effect.addColorStop(stop._offset, stop._color);
  3942. }
  3943. }
  3944. return this.flagReset();
  3945. }
  3946. },
  3947. texture: {
  3948. render: function(ctx) {
  3949. this._update();
  3950. var image = this.image;
  3951. if (!this._renderer.effect || ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) {
  3952. this._renderer.effect = ctx.createPattern(this.image, this._repeat);
  3953. }
  3954. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  3955. if (!(this._renderer.offset instanceof Vector)) {
  3956. this._renderer.offset = new Vector();
  3957. }
  3958. this._renderer.offset.x = - this._offset.x;
  3959. this._renderer.offset.y = - this._offset.y;
  3960. if (image) {
  3961. this._renderer.offset.x += image.width / 2;
  3962. this._renderer.offset.y += image.height / 2;
  3963. if (this._scale instanceof Vector) {
  3964. this._renderer.offset.x *= this._scale.x;
  3965. this._renderer.offset.y *= this._scale.y;
  3966. } else {
  3967. this._renderer.offset.x *= this._scale;
  3968. this._renderer.offset.y *= this._scale;
  3969. }
  3970. }
  3971. }
  3972. if (this._flagScale || this._flagLoaded) {
  3973. if (!(this._renderer.scale instanceof Vector)) {
  3974. this._renderer.scale = new Vector();
  3975. }
  3976. if (this._scale instanceof Vector) {
  3977. this._renderer.scale.copy(this._scale);
  3978. } else {
  3979. this._renderer.scale.set(this._scale, this._scale);
  3980. }
  3981. }
  3982. return this.flagReset();
  3983. }
  3984. },
  3985. renderSvgArcCommand: function(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y) {
  3986. xAxisRotation = xAxisRotation * Math.PI / 180;
  3987. // Ensure radii are positive
  3988. rx = abs(rx);
  3989. ry = abs(ry);
  3990. // Compute (x1′, y1′)
  3991. var dx2 = (ax - x) / 2.0;
  3992. var dy2 = (ay - y) / 2.0;
  3993. var x1p = cos$4(xAxisRotation) * dx2 + sin$4(xAxisRotation) * dy2;
  3994. var y1p = - sin$4(xAxisRotation) * dx2 + cos$4(xAxisRotation) * dy2;
  3995. // Compute (cx′, cy′)
  3996. var rxs = rx * rx;
  3997. var rys = ry * ry;
  3998. var x1ps = x1p * x1p;
  3999. var y1ps = y1p * y1p;
  4000. // Ensure radii are large enough
  4001. var cr = x1ps / rxs + y1ps / rys;
  4002. if (cr > 1) {
  4003. // scale up rx,ry equally so cr == 1
  4004. var s = sqrt(cr);
  4005. rx = s * rx;
  4006. ry = s * ry;
  4007. rxs = rx * rx;
  4008. rys = ry * ry;
  4009. }
  4010. var dq = (rxs * y1ps + rys * x1ps);
  4011. var pq = (rxs * rys - dq) / dq;
  4012. var q = sqrt(max$2(0, pq));
  4013. if (largeArcFlag === sweepFlag) q = - q;
  4014. var cxp = q * rx * y1p / ry;
  4015. var cyp = - q * ry * x1p / rx;
  4016. // Step 3: Compute (cx, cy) from (cx′, cy′)
  4017. var cx = cos$4(xAxisRotation) * cxp
  4018. - sin$4(xAxisRotation) * cyp + (ax + x) / 2;
  4019. var cy = sin$4(xAxisRotation) * cxp
  4020. + cos$4(xAxisRotation) * cyp + (ay + y) / 2;
  4021. // Step 4: Compute θ1 and Δθ
  4022. var startAngle = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
  4023. var delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry,
  4024. (- x1p - cxp) / rx, (- y1p - cyp) / ry) % TWO_PI$5;
  4025. var endAngle = startAngle + delta;
  4026. var clockwise = sweepFlag === 0;
  4027. renderArcEstimate(ctx, cx, cy, rx, ry, startAngle, endAngle,
  4028. clockwise, xAxisRotation);
  4029. }
  4030. };
  4031. /**
  4032. * @name Two.CanvasRenderer
  4033. * @class
  4034. * @extends Two.Events
  4035. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  4036. * @param {Element} [parameters.domElement] - The `<canvas />` to draw to. If none given a new one will be constructed.
  4037. * @param {Boolean} [parameters.overdraw] - Determines whether the canvas should clear the background or not. Defaults to `true`.
  4038. * @param {Boolean} [parameters.smoothing=true] - Determines whether the canvas should antialias drawing. Set it to `false` when working with pixel art. `false` can lead to better performance, since it would use a cheaper interpolation algorithm.
  4039. * @description This class is used by {@link Two} when constructing with `type` of `Two.Types.canvas`. It takes Two.js' scenegraph and renders it to a `<canvas />`.
  4040. */
  4041. function Renderer$2(params) {
  4042. // It might not make a big difference on GPU backed canvases.
  4043. var smoothing = (params.smoothing !== false);
  4044. /**
  4045. * @name Two.CanvasRenderer#domElement
  4046. * @property {Element} - The `<canvas />` associated with the Two.js scene.
  4047. */
  4048. this.domElement = params.domElement || document.createElement('canvas');
  4049. /**
  4050. * @name Two.CanvasRenderer#ctx
  4051. * @property {Canvas2DContext} - Associated two dimensional context to render on the `<canvas />`.
  4052. */
  4053. this.ctx = this.domElement.getContext('2d');
  4054. /**
  4055. * @name Two.CanvasRenderer#overdraw
  4056. * @property {Boolean} - Determines whether the canvas clears the background each draw call.
  4057. * @default true
  4058. */
  4059. this.overdraw = params.overdraw || false;
  4060. if (typeof this.ctx.imageSmoothingEnabled !== 'undefined') {
  4061. this.ctx.imageSmoothingEnabled = smoothing;
  4062. }
  4063. /**
  4064. * @name Two.CanvasRenderer#scene
  4065. * @property {Two.Group} - The root group of the scenegraph.
  4066. */
  4067. this.scene = new Group();
  4068. this.scene.parent = this;
  4069. }
  4070. _.extend(Renderer$2, {
  4071. /**
  4072. * @name Two.CanvasRenderer.Utils
  4073. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<canvas />`.
  4074. */
  4075. Utils: canvas
  4076. });
  4077. _.extend(Renderer$2.prototype, Events, {
  4078. constructor: Renderer$2,
  4079. /**
  4080. * @name Two.CanvasRenderer#setSize
  4081. * @function
  4082. * @fires resize
  4083. * @param {Number} width - The new width of the renderer.
  4084. * @param {Number} height - The new height of the renderer.
  4085. * @param {Number} [ratio] - The new pixel ratio (pixel density) of the renderer. Defaults to calculate the pixel density of the user's screen.
  4086. * @description Change the size of the renderer.
  4087. */
  4088. setSize: function(width, height, ratio) {
  4089. this.width = width;
  4090. this.height = height;
  4091. this.ratio = typeof ratio === 'undefined' ? getRatio(this.ctx) : ratio;
  4092. this.domElement.width = width * this.ratio;
  4093. this.domElement.height = height * this.ratio;
  4094. if (this.domElement.style) {
  4095. _.extend(this.domElement.style, {
  4096. width: width + 'px',
  4097. height: height + 'px'
  4098. });
  4099. }
  4100. return this.trigger(Events.Types.resize, width, height, ratio);
  4101. },
  4102. /**
  4103. * @name Two.CanvasRenderer#render
  4104. * @function
  4105. * @description Render the current scene to the `<canvas />`.
  4106. */
  4107. render: function() {
  4108. var isOne = this.ratio === 1;
  4109. if (!isOne) {
  4110. this.ctx.save();
  4111. this.ctx.scale(this.ratio, this.ratio);
  4112. }
  4113. if (!this.overdraw) {
  4114. this.ctx.clearRect(0, 0, this.width, this.height);
  4115. }
  4116. canvas.group.render.call(this.scene, this.ctx);
  4117. if (!isOne) {
  4118. this.ctx.restore();
  4119. }
  4120. return this;
  4121. }
  4122. });
  4123. function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, clockwise, xAxisRotation) {
  4124. var epsilon = Curve.Tolerance.epsilon;
  4125. var deltaAngle = endAngle - startAngle;
  4126. var samePoints = Math.abs(deltaAngle) < epsilon;
  4127. // ensures that deltaAngle is 0 .. 2 PI
  4128. deltaAngle = mod(deltaAngle, TWO_PI$5);
  4129. if (deltaAngle < epsilon) {
  4130. if (samePoints) {
  4131. deltaAngle = 0;
  4132. } else {
  4133. deltaAngle = TWO_PI$5;
  4134. }
  4135. }
  4136. if (clockwise === true && ! samePoints) {
  4137. if (deltaAngle === TWO_PI$5) {
  4138. deltaAngle = - TWO_PI$5;
  4139. } else {
  4140. deltaAngle = deltaAngle - TWO_PI$5;
  4141. }
  4142. }
  4143. for (var i = 0; i < Constants.Resolution; i++) {
  4144. var t = i / (Constants.Resolution - 1);
  4145. var angle = startAngle + t * deltaAngle;
  4146. var x = ox + rx * Math.cos(angle);
  4147. var y = oy + ry * Math.sin(angle);
  4148. if (xAxisRotation !== 0) {
  4149. var cos = Math.cos(xAxisRotation);
  4150. var sin = Math.sin(xAxisRotation);
  4151. var tx = x - ox;
  4152. var ty = y - oy;
  4153. // Rotate the point about the center of the ellipse.
  4154. x = tx * cos - ty * sin + ox;
  4155. y = tx * sin + ty * cos + oy;
  4156. }
  4157. ctx.lineTo(x, y);
  4158. }
  4159. }
  4160. function svgAngle(ux, uy, vx, vy) {
  4161. var dot = ux * vx + uy * vy;
  4162. var len = sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy);
  4163. // floating point precision, slightly over values appear
  4164. var ang = acos(max$2(-1, min$2(1, dot / len)));
  4165. if ((ux * vy - uy * vx) < 0) {
  4166. ang = - ang;
  4167. }
  4168. return ang;
  4169. }
  4170. var CanvasShim = {
  4171. Image: null,
  4172. isHeadless: false,
  4173. /**
  4174. * @name Two.Utils.shim
  4175. * @function
  4176. * @param {canvas} canvas - The instanced `Canvas` object provided by `node-canvas`.
  4177. * @param {Image} [Image] - The prototypical `Image` object provided by `node-canvas`. This is only necessary to pass if you're going to load bitmap imagery.
  4178. * @returns {canvas} Returns the instanced canvas object you passed from with additional attributes needed for Two.js.
  4179. * @description Convenience method for defining all the dependencies from the npm package `node-canvas`. See [node-canvas](https://github.com/Automattic/node-canvas) for additional information on setting up HTML5 `<canvas />` drawing in a node.js environment.
  4180. */
  4181. shim: function(canvas, Image) {
  4182. Renderer$2.Utils.shim(canvas);
  4183. if (typeof Image !== 'undefined') {
  4184. CanvasShim.Image = Image;
  4185. }
  4186. CanvasShim.isHeadless = true;
  4187. return canvas;
  4188. }
  4189. };
  4190. var dom = {
  4191. hasEventListeners: typeof root$1.addEventListener === 'function',
  4192. bind: function(elem, event, func, bool) {
  4193. if (this.hasEventListeners) {
  4194. elem.addEventListener(event, func, !!bool);
  4195. } else {
  4196. elem.attachEvent('on' + event, func);
  4197. }
  4198. return dom;
  4199. },
  4200. unbind: function(elem, event, func, bool) {
  4201. if (dom.hasEventListeners) {
  4202. elem.removeEventListeners(event, func, !!bool);
  4203. } else {
  4204. elem.detachEvent('on' + event, func);
  4205. }
  4206. return dom;
  4207. },
  4208. getRequestAnimationFrame: function() {
  4209. var lastTime = 0;
  4210. var vendors = ['ms', 'moz', 'webkit', 'o'];
  4211. var request = root$1.requestAnimationFrame, cancel;
  4212. if(!request) {
  4213. for (var i = 0; i < vendors.length; i++) {
  4214. request = root$1[vendors[i] + 'RequestAnimationFrame'] || request;
  4215. cancel = root$1[vendors[i] + 'CancelAnimationFrame']
  4216. || root$1[vendors[i] + 'CancelRequestAnimationFrame'] || cancel;
  4217. }
  4218. request = request || function(callback, element) {
  4219. var currTime = new Date().getTime();
  4220. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  4221. var id = root$1.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
  4222. lastTime = currTime + timeToCall;
  4223. return id;
  4224. };
  4225. }
  4226. return request;
  4227. }
  4228. };
  4229. var temp = (root$1.document ? root$1.document.createElement('div') : {});
  4230. temp.id = 'help-two-load';
  4231. Object.defineProperty(dom, 'temp', {
  4232. enumerable: true,
  4233. get: function() {
  4234. if (_.isElement(temp) && !root$1.document.head.contains(temp)) {
  4235. _.extend(temp.style, {
  4236. display: 'none'
  4237. });
  4238. root$1.document.head.appendChild(temp);
  4239. }
  4240. return temp;
  4241. }
  4242. });
  4243. /**
  4244. * @name Two.Utils.Error
  4245. * @class
  4246. * @description Custom error throwing for Two.js specific identification.
  4247. */
  4248. function TwoError(message) {
  4249. this.name = 'Two.js';
  4250. this.message = message;
  4251. }
  4252. TwoError.prototype = new Error();
  4253. _.extend(TwoError.prototype, {
  4254. constructor: TwoError
  4255. });
  4256. /**
  4257. * @name Two.Utils.defineGetterSetter
  4258. * @function
  4259. * @this Two#
  4260. * @param {String} property - The property to add an enumerable getter / setter to.
  4261. * @description Convenience function to setup the flag based getter / setter that most properties are defined as in Two.js.
  4262. */
  4263. var defineGetterSetter = function(property) {
  4264. var object = this;
  4265. var secret = '_' + property;
  4266. var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  4267. Object.defineProperty(object, property, {
  4268. enumerable: true,
  4269. get: function() {
  4270. return this[secret];
  4271. },
  4272. set: function(v) {
  4273. this[secret] = v;
  4274. this[flag] = true;
  4275. }
  4276. });
  4277. };
  4278. /**
  4279. * @name Two.Registry
  4280. * @class
  4281. * @description An arbitrary class to manage a directory of things. Mainly used for keeping tabs of textures in Two.js.
  4282. */
  4283. function Registry() {
  4284. this.map = {};
  4285. }
  4286. _.extend(Registry.prototype, {
  4287. constructor: Registry,
  4288. /**
  4289. * @name Two.Registry#add
  4290. * @function
  4291. * @param {String} id - A unique identifier.
  4292. * @param value - Any type of variable to be registered to the directory.
  4293. * @description Adds any value to the directory. Assigned by the `id`.
  4294. */
  4295. add: function(id, obj) {
  4296. this.map[id] = obj;
  4297. return this;
  4298. },
  4299. /**
  4300. * @name Two.Registry#remove
  4301. * @function
  4302. * @param {String} id - A unique identifier.
  4303. * @description Remove any value from the directory by its `id`.
  4304. */
  4305. remove: function(id) {
  4306. delete this.map[id];
  4307. return this;
  4308. },
  4309. /**
  4310. * @name Two.Registry#get
  4311. * @function
  4312. * @param {String} id - A unique identifier.
  4313. * @returns {?Object} The associated value. If unavailable then `undefined` is returned.
  4314. * @description Get a registered value by its `id`.
  4315. */
  4316. get: function(id) {
  4317. return this.map[id];
  4318. },
  4319. /**
  4320. * @name Two.Registry#contains
  4321. * @function
  4322. * @param {String} id - A unique identifier.
  4323. * @returns {Boolean}
  4324. * @description Convenience method to see if a value is registered to an `id` already.
  4325. */
  4326. contains: function(id) {
  4327. return id in this.map;
  4328. }
  4329. });
  4330. /**
  4331. * @name Two.Stop
  4332. * @class
  4333. * @param {Number} [offset] - The offset percentage of the stop represented as a zero-to-one value. Default value flip flops from zero-to-one as new stops are created.
  4334. * @param {String} [color] - The color of the stop. Default value flip flops from white to black as new stops are created.
  4335. * @param {Number} [opacity] - The opacity value. Default value is 1, cannot be lower than 0.
  4336. * @nota-bene Used specifically in conjunction with {@link Two.Gradient}s to control color graduation.
  4337. */
  4338. function Stop(offset, color, opacity) {
  4339. /**
  4340. * @name Two.Stop#renderer
  4341. * @property {Object}
  4342. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4343. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4344. */
  4345. this.renderer = {};
  4346. this._renderer.type = 'stop';
  4347. /**
  4348. * @name Two.Stop#offset
  4349. * @property {Number} - The offset percentage of the stop represented as a zero-to-one value.
  4350. */
  4351. this.offset = typeof offset === 'number' ? offset
  4352. : Stop.Index <= 0 ? 0 : 1;
  4353. /**
  4354. * @name Two.Stop#opacity
  4355. * @property {Number} - The alpha percentage of the stop represented as a zero-to-one value.
  4356. */
  4357. this.opacity = typeof opacity === 'number' ? opacity : 1;
  4358. /**
  4359. * @name Two.Stop#color
  4360. * @property {String} - The color of the stop.
  4361. */
  4362. this.color = (typeof color === 'string') ? color
  4363. : Stop.Index <= 0 ? '#fff' : '#000';
  4364. Stop.Index = (Stop.Index + 1) % 2;
  4365. }
  4366. _.extend(Stop, {
  4367. /**
  4368. * @name Two.Stop.Index
  4369. * @property {Number} - The current index being referenced for calculating a stop's default offset value.
  4370. */
  4371. Index: 0,
  4372. /**
  4373. * @name Two.Stop.Properties
  4374. * @property {String[]} - A list of properties that are on every {@link Two.Stop}.
  4375. */
  4376. Properties: [
  4377. 'offset',
  4378. 'opacity',
  4379. 'color'
  4380. ],
  4381. /**
  4382. * @name Two.Stop.MakeObservable
  4383. * @function
  4384. * @param {Object} object - The object to make observable.
  4385. * @description Convenience function to apply observable qualities of a {@link Two.Stop} to any object. Handy if you'd like to extend the {@link Two.Stop} class on a custom class.
  4386. */
  4387. MakeObservable: function(object) {
  4388. _.each(Stop.Properties, function(property) {
  4389. var object = this;
  4390. var secret = '_' + property;
  4391. var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  4392. Object.defineProperty(object, property, {
  4393. enumerable: true,
  4394. get: function() {
  4395. return this[secret];
  4396. },
  4397. set: function(v) {
  4398. this[secret] = v;
  4399. this[flag] = true;
  4400. if (this.parent) {
  4401. this.parent._flagStops = true;
  4402. }
  4403. }
  4404. });
  4405. }, object);
  4406. Object.defineProperty(object, 'renderer', {
  4407. enumerable: false,
  4408. get: function() {
  4409. return this._renderer;
  4410. },
  4411. set: function(obj) {
  4412. this._renderer = obj;
  4413. }
  4414. });
  4415. }
  4416. });
  4417. _.extend(Stop.prototype, Events, {
  4418. constructor: Stop,
  4419. /**
  4420. * @name Two.Stop#clone
  4421. * @function
  4422. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4423. * @returns {Two.Stop}
  4424. * @description Create a new instance of {@link Two.Stop} with the same properties of the current path.
  4425. */
  4426. clone: function() {
  4427. var clone = new Stop();
  4428. _.each(Stop.Properties, function(property) {
  4429. clone[property] = this[property];
  4430. }, this);
  4431. return clone;
  4432. },
  4433. /**
  4434. * @name Two.Stop#toObject
  4435. * @function
  4436. * @returns {Object}
  4437. * @description Return a JSON compatible plain object that represents the path.
  4438. */
  4439. toObject: function() {
  4440. var result = {};
  4441. _.each(Stop.Properties, function(k) {
  4442. result[k] = this[k];
  4443. }, this);
  4444. return result;
  4445. },
  4446. /**
  4447. * @name Two.Stop#flagReset
  4448. * @function
  4449. * @private
  4450. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4451. */
  4452. flagReset: function() {
  4453. this._flagOffset = this._flagColor = this._flagOpacity = false;
  4454. return this;
  4455. }
  4456. });
  4457. Stop.MakeObservable(Stop.prototype);
  4458. /**
  4459. * @name Two.Gradient
  4460. * @class
  4461. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4462. * @description This is the base class for constructing different types of gradients with Two.js. The two common gradients are {@link Two.LinearGradient} and {@link Two.RadialGradient}.
  4463. */
  4464. function Gradient(stops) {
  4465. /**
  4466. * @name Two.Gradient#renderer
  4467. * @property {Object}
  4468. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4469. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4470. */
  4471. this.renderer = {};
  4472. this._renderer.type = 'gradient';
  4473. /**
  4474. * @name Two.Gradient#id
  4475. * @property {String} - Session specific unique identifier.
  4476. * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
  4477. */
  4478. this.id = Constants.Identifier + Constants.uniqueId();
  4479. this.classList = [];
  4480. this._renderer.flagStops = Gradient.FlagStops.bind(this);
  4481. this._renderer.bindStops = Gradient.BindStops.bind(this);
  4482. this._renderer.unbindStops = Gradient.UnbindStops.bind(this);
  4483. /**
  4484. * @name Two.Gradient#spread
  4485. * @property {String} - Indicates what happens if the gradient starts or ends inside the bounds of the target rectangle. Possible values are `'pad'`, `'reflect'`, and `'repeat'`.
  4486. * @see {@link https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementSpreadMethodAttribute} for more information
  4487. */
  4488. this.spread = 'pad';
  4489. /**
  4490. * @name Two.Gradient#stops
  4491. * @property {Two.Stop[]} - An ordered list of {@link Two.Stop}s for rendering the gradient.
  4492. */
  4493. if (stops) {
  4494. this.stops = stops;
  4495. }
  4496. }
  4497. _.extend(Gradient, {
  4498. /**
  4499. * @name Two.Gradient.Stop
  4500. * @see {@link Two.Stop}
  4501. */
  4502. Stop: Stop,
  4503. /**
  4504. * @name Two.Gradient.Properties
  4505. * @property {String[]} - A list of properties that are on every {@link Two.Gradient}.
  4506. */
  4507. Properties: [
  4508. 'spread'
  4509. ],
  4510. /**
  4511. * @name Two.Gradient.MakeObservable
  4512. * @function
  4513. * @param {Object} object - The object to make observable.
  4514. * @description Convenience function to apply observable qualities of a {@link Two.Gradient} to any object. Handy if you'd like to extend the {@link Two.Gradient} class on a custom class.
  4515. */
  4516. MakeObservable: function(object) {
  4517. _.each(Gradient.Properties, defineGetterSetter, object);
  4518. Object.defineProperty(object, 'stops', {
  4519. enumerable: true,
  4520. get: function() {
  4521. return this._stops;
  4522. },
  4523. set: function(stops) {
  4524. var bindStops = this._renderer.bindStops;
  4525. var unbindStops = this._renderer.unbindStops;
  4526. // Remove previous listeners
  4527. if (this._stops) {
  4528. this._stops
  4529. .unbind(Events.Types.insert, bindStops)
  4530. .unbind(Events.Types.remove, unbindStops);
  4531. }
  4532. // Create new Collection with copy of Stops
  4533. this._stops = new Collection((stops || []).slice(0));
  4534. // Listen for Collection changes and bind / unbind
  4535. this._stops
  4536. .bind(Events.Types.insert, bindStops)
  4537. .bind(Events.Types.remove, unbindStops);
  4538. // Bind Initial Stops
  4539. bindStops(this._stops);
  4540. }
  4541. });
  4542. Object.defineProperty(object, 'renderer', {
  4543. enumerable: false,
  4544. get: function() {
  4545. return this._renderer;
  4546. },
  4547. set: function(obj) {
  4548. this._renderer = obj;
  4549. }
  4550. });
  4551. Object.defineProperty(object, 'id', {
  4552. enumerable: true,
  4553. get: function() {
  4554. return this._id;
  4555. },
  4556. set: function(v) {
  4557. this._id = v;
  4558. }
  4559. });
  4560. },
  4561. /**
  4562. * @name Two.Gradient.FlagStops
  4563. * @function
  4564. * @description Cached method to let renderers know stops have been updated on a {@link Two.Gradient}.
  4565. */
  4566. FlagStops: function() {
  4567. this._flagStops = true;
  4568. },
  4569. /**
  4570. * @name Two.Gradient.BindVertices
  4571. * @function
  4572. * @description Cached method to let {@link Two.Gradient} know vertices have been added to the instance.
  4573. */
  4574. BindStops: function(items) {
  4575. // This function is called a lot
  4576. // when importing a large SVG
  4577. var i = items.length;
  4578. while(i--) {
  4579. items[i].bind(Events.Types.change, this._renderer.flagStops);
  4580. items[i].parent = this;
  4581. }
  4582. this._renderer.flagStops();
  4583. },
  4584. /**
  4585. * @name Two.Gradient.UnbindStops
  4586. * @function
  4587. * @description Cached method to let {@link Two.Gradient} know vertices have been removed from the instance.
  4588. */
  4589. UnbindStops: function(items) {
  4590. var i = items.length;
  4591. while(i--) {
  4592. items[i].unbind(Events.Types.change, this._renderer.flagStops);
  4593. delete items[i].parent;
  4594. }
  4595. this._renderer.flagStops();
  4596. }
  4597. });
  4598. _.extend(Gradient.prototype, Events, {
  4599. constructor: Gradient,
  4600. /**
  4601. * @name Two.Gradient#_flagId
  4602. * @private
  4603. * @property {Boolean} - Determines whether the {@link Two.Gradient#id} needs updating.
  4604. */
  4605. _flagId: false,
  4606. /**
  4607. * @name Two.Gradient#_flagStops
  4608. * @private
  4609. * @property {Boolean} - Determines whether the {@link Two.Gradient#stops} needs updating.
  4610. */
  4611. _flagStops: false,
  4612. /**
  4613. * @name Two.Gradient#_flagSpread
  4614. * @private
  4615. * @property {Boolean} - Determines whether the {@link Two.Gradient#spread} needs updating.
  4616. */
  4617. _flagSpread: false,
  4618. _id: '',
  4619. /**
  4620. * @name Two.Gradient#clone
  4621. * @function
  4622. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4623. * @returns {Two.Gradient}
  4624. * @description Create a new instance of {@link Two.Gradient} with the same properties of the current path.
  4625. */
  4626. clone: function(parent) {
  4627. var stops = this.stops.map(function(s) {
  4628. return s.clone();
  4629. });
  4630. var clone = new Gradient(stops);
  4631. _.each(Gradient.Properties, function(k) {
  4632. clone[k] = this[k];
  4633. }, this);
  4634. if (parent) {
  4635. parent.add(clone);
  4636. }
  4637. return clone;
  4638. },
  4639. /**
  4640. * @name Two.Gradient#toObject
  4641. * @function
  4642. * @returns {Object}
  4643. * @description Return a JSON compatible plain object that represents the path.
  4644. */
  4645. toObject: function() {
  4646. var result = {
  4647. stops: this.stops.map(function(s) {
  4648. return s.toObject();
  4649. })
  4650. };
  4651. _.each(Gradient.Properties, function(k) {
  4652. result[k] = this[k];
  4653. }, this);
  4654. return result;
  4655. },
  4656. /**
  4657. * @name Two.Gradient#_update
  4658. * @function
  4659. * @private
  4660. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4661. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  4662. * @nota-bene Try not to call this method more than once a frame.
  4663. */
  4664. _update: function() {
  4665. if (this._flagSpread || this._flagStops) {
  4666. this.trigger(Events.Types.change);
  4667. }
  4668. return this;
  4669. },
  4670. /**
  4671. * @name Two.Gradient#flagReset
  4672. * @function
  4673. * @private
  4674. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4675. */
  4676. flagReset: function() {
  4677. this._flagSpread = this._flagStops = false;
  4678. return this;
  4679. }
  4680. });
  4681. Gradient.MakeObservable(Gradient.prototype);
  4682. /**
  4683. * @name Two.LinearGradient
  4684. * @class
  4685. * @extends Two.Gradient
  4686. * @param {Number} [x1=0] - The x position of the first end point of the linear gradient.
  4687. * @param {Number} [y1=0] - The y position of the first end point of the linear gradient.
  4688. * @param {Number} [x2=0] - The x position of the second end point of the linear gradient.
  4689. * @param {Number} [y2=0] - The y position of the second end point of the linear gradient.
  4690. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4691. * @nota-bene The linear gradient lives within the space of the parent object's matrix space.
  4692. */
  4693. function LinearGradient(x1, y1, x2, y2, stops) {
  4694. Gradient.call(this, stops);
  4695. this._renderer.type = 'linear-gradient';
  4696. var flagEndPoints = LinearGradient.FlagEndPoints.bind(this);
  4697. /**
  4698. * @name Two.LinearGradient#left
  4699. * @property {Two.Vector} - The x and y value for where the first end point is placed on the canvas.
  4700. */
  4701. this.left = new Vector().bind(Events.Types.change, flagEndPoints);
  4702. /**
  4703. * @name Two.LinearGradient#right
  4704. * @property {Two.Vector} - The x and y value for where the second end point is placed on the canvas.
  4705. */
  4706. this.right = new Vector().bind(Events.Types.change, flagEndPoints);
  4707. if (typeof x1 === 'number') {
  4708. this.left.x = x1;
  4709. }
  4710. if (typeof y1 === 'number') {
  4711. this.left.y = y1;
  4712. }
  4713. if (typeof x2 === 'number') {
  4714. this.right.x = x2;
  4715. }
  4716. if (typeof y2 === 'number') {
  4717. this.right.y = y2;
  4718. }
  4719. }
  4720. _.extend(LinearGradient, {
  4721. /**
  4722. * @name Two.LinearGradient.Stop
  4723. * @see {@link Two.Stop}
  4724. */
  4725. Stop: Stop,
  4726. /**
  4727. * @name Two.LinearGradient.MakeObservable
  4728. * @function
  4729. * @param {Object} object - The object to make observable.
  4730. * @description Convenience function to apply observable qualities of a {@link Two.LinearGradient} to any object. Handy if you'd like to extend the {@link Two.LinearGradient} class on a custom class.
  4731. */
  4732. MakeObservable: function(object) {
  4733. Gradient.MakeObservable(object);
  4734. },
  4735. /**
  4736. * @name Two.LinearGradient.FlagEndPoints
  4737. * @function
  4738. * @description Cached method to let renderers know end points have been updated on a {@link Two.LinearGradient}.
  4739. */
  4740. FlagEndPoints: function() {
  4741. this._flagEndPoints = true;
  4742. }
  4743. });
  4744. _.extend(LinearGradient.prototype, Gradient.prototype, {
  4745. constructor: LinearGradient,
  4746. /**
  4747. * @name Two.LinearGradient#_flagEndPoints
  4748. * @private
  4749. * @property {Boolean} - Determines whether the {@link Two.LinearGradient#left} or {@link Two.LinearGradient#right} changed and needs to update.
  4750. */
  4751. _flagEndPoints: false,
  4752. /**
  4753. * @name Two.LinearGradient#clone
  4754. * @function
  4755. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4756. * @returns {Two.Gradient}
  4757. * @description Create a new instance of {@link Two.LinearGradient} with the same properties of the current path.
  4758. */
  4759. clone: function(parent) {
  4760. var stops = this.stops.map(function(stop) {
  4761. return stop.clone();
  4762. });
  4763. var clone = new LinearGradient(this.left._x, this.left._y,
  4764. this.right._x, this.right._y, stops);
  4765. _.each(Gradient.Properties, function(k) {
  4766. clone[k] = this[k];
  4767. }, this);
  4768. if (parent) {
  4769. parent.add(clone);
  4770. }
  4771. return clone;
  4772. },
  4773. /**
  4774. * @name Two.LinearGradient#toObject
  4775. * @function
  4776. * @returns {Object}
  4777. * @description Return a JSON compatible plain object that represents the path.
  4778. */
  4779. toObject: function() {
  4780. var result = Gradient.prototype.toObject.call(this);
  4781. result.left = this.left.toObject();
  4782. result.right = this.right.toObject();
  4783. return result;
  4784. },
  4785. /**
  4786. * @name Two.LinearGradient#_update
  4787. * @function
  4788. * @private
  4789. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4790. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  4791. * @nota-bene Try not to call this method more than once a frame.
  4792. */
  4793. _update: function() {
  4794. if (this._flagEndPoints || this._flagSpread || this._flagStops) {
  4795. this.trigger(Events.Types.change);
  4796. }
  4797. return this;
  4798. },
  4799. /**
  4800. * @name Two.LinearGradient#flagReset
  4801. * @function
  4802. * @private
  4803. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4804. */
  4805. flagReset: function() {
  4806. this._flagEndPoints = false;
  4807. Gradient.prototype.flagReset.call(this);
  4808. return this;
  4809. }
  4810. });
  4811. LinearGradient.MakeObservable(LinearGradient.prototype);
  4812. /**
  4813. * @name Two.RadialGradient
  4814. * @class
  4815. * @extends Two.Gradient
  4816. * @param {Number} [x=0] - The x position of the origin of the radial gradient.
  4817. * @param {Number} [y=0] - The y position of the origin of the radial gradient.
  4818. * @param {Number} [radius=0] - The radius of the radial gradient.
  4819. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4820. * @param {Number} [focalX=0] - The x position of the focal point on the radial gradient.
  4821. * @param {Number} [focalY=0] - The y position of the focal point on the radial gradient.
  4822. * @nota-bene The radial gradient lives within the space of the parent object's matrix space.
  4823. */
  4824. function RadialGradient(cx, cy, r, stops, fx, fy) {
  4825. Gradient.call(this, stops);
  4826. this._renderer.type = 'radial-gradient';
  4827. /**
  4828. * @name Two.RadialGradient#center
  4829. * @property {Two.Vector} - The x and y value for where the origin of the radial gradient is.
  4830. */
  4831. this.center = new Vector()
  4832. .bind(Events.Types.change, (function() {
  4833. this._flagCenter = true;
  4834. }).bind(this));
  4835. this.radius = typeof r === 'number' ? r : 20;
  4836. /**
  4837. * @name Two.RadialGradient#focal
  4838. * @property {Two.Vector} - The x and y value for where the focal point of the radial gradient is.
  4839. * @nota-bene This effects the spray or spread of the radial gradient.
  4840. */
  4841. this.focal = new Vector()
  4842. .bind(Events.Types.change, (function() {
  4843. this._flagFocal = true;
  4844. }).bind(this));
  4845. if (typeof cx === 'number') {
  4846. this.center.x = cx;
  4847. }
  4848. if (typeof cy === 'number') {
  4849. this.center.y = cy;
  4850. }
  4851. this.focal.copy(this.center);
  4852. if (typeof fx === 'number') {
  4853. this.focal.x = fx;
  4854. }
  4855. if (typeof fy === 'number') {
  4856. this.focal.y = fy;
  4857. }
  4858. }
  4859. _.extend(RadialGradient, {
  4860. /**
  4861. * @name Two.RadialGradient.Stop
  4862. * @see {@link Two.Stop}
  4863. */
  4864. Stop: Stop,
  4865. /**
  4866. * @name Two.RadialGradient.Properties
  4867. * @property {String[]} - A list of properties that are on every {@link Two.RadialGradient}.
  4868. */
  4869. Properties: [
  4870. 'radius'
  4871. ],
  4872. /**
  4873. * @name Two.RadialGradient.MakeObservable
  4874. * @function
  4875. * @param {Object} object - The object to make observable.
  4876. * @description Convenience function to apply observable qualities of a {@link Two.RadialGradient} to any object. Handy if you'd like to extend the {@link Two.RadialGradient} class on a custom class.
  4877. */
  4878. MakeObservable: function(object) {
  4879. Gradient.MakeObservable(object);
  4880. _.each(RadialGradient.Properties, defineGetterSetter, object);
  4881. }
  4882. });
  4883. _.extend(RadialGradient.prototype, Gradient.prototype, {
  4884. constructor: RadialGradient,
  4885. /**
  4886. * @name Two.RadialGradient#_flagRadius
  4887. * @private
  4888. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#radius} changed and needs to update.
  4889. */
  4890. _flagRadius: false,
  4891. /**
  4892. * @name Two.RadialGradient#_flagCenter
  4893. * @private
  4894. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#center} changed and needs to update.
  4895. */
  4896. _flagCenter: false,
  4897. /**
  4898. * @name Two.RadialGradient#_flagFocal
  4899. * @private
  4900. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#focal} changed and needs to update.
  4901. */
  4902. _flagFocal: false,
  4903. /**
  4904. * @name Two.RadialGradient#clone
  4905. * @function
  4906. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4907. * @returns {Two.Gradient}
  4908. * @description Create a new instance of {@link Two.RadialGradient} with the same properties of the current path.
  4909. */
  4910. clone: function(parent) {
  4911. var stops = this.stops.map(function(stop) {
  4912. return stop.clone();
  4913. });
  4914. var clone = new RadialGradient(this.center._x, this.center._y,
  4915. this._radius, stops, this.focal._x, this.focal._y);
  4916. _.each(Gradient.Properties.concat(RadialGradient.Properties), function(k) {
  4917. clone[k] = this[k];
  4918. }, this);
  4919. if (parent) {
  4920. parent.add(clone);
  4921. }
  4922. return clone;
  4923. },
  4924. /**
  4925. * @name Two.RadialGradient#toObject
  4926. * @function
  4927. * @returns {Object}
  4928. * @description Return a JSON compatible plain object that represents the path.
  4929. */
  4930. toObject: function() {
  4931. var result = Gradient.prototype.toObject.call(this);
  4932. _.each(RadialGradient.Properties, function(k) {
  4933. result[k] = this[k];
  4934. }, this);
  4935. result.center = this.center.toObject();
  4936. result.focal = this.focal.toObject();
  4937. return result;
  4938. },
  4939. /**
  4940. * @name Two.RadialGradient#_update
  4941. * @function
  4942. * @private
  4943. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4944. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  4945. * @nota-bene Try not to call this method more than once a frame.
  4946. */
  4947. _update: function() {
  4948. if (this._flagRadius || this._flatCenter || this._flagFocal
  4949. || this._flagSpread || this._flagStops) {
  4950. this.trigger(Events.Types.change);
  4951. }
  4952. return this;
  4953. },
  4954. /**
  4955. * @name Two.RadialGradient#flagReset
  4956. * @function
  4957. * @private
  4958. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4959. */
  4960. flagReset: function() {
  4961. this._flagRadius = this._flagCenter = this._flagFocal = false;
  4962. Gradient.prototype.flagReset.call(this);
  4963. return this;
  4964. }
  4965. });
  4966. RadialGradient.MakeObservable(RadialGradient.prototype);
  4967. var anchor;
  4968. var regex$1 = {
  4969. video: /\.(mp4|webm|ogg)$/i,
  4970. image: /\.(jpe?g|png|gif|tiff|webp)$/i,
  4971. effect: /texture|gradient/i
  4972. };
  4973. if (root$1.document) {
  4974. anchor = document.createElement('a');
  4975. }
  4976. /**
  4977. * @name Two.Texture
  4978. * @class
  4979. * @extends Two.Shape
  4980. * @param {String|HTMLImageElement} [src] - The URL path to an image file or an `<img />` element.
  4981. * @param {Function} [callback] - An optional callback function once the image has been loaded.
  4982. * @description Fundamental to work with bitmap data, a.k.a. pregenerated imagery, in Two.js. Supported formats include jpg, png, gif, and tiff. See {@link Two.Texture.RegularExpressions} for a full list of supported formats.
  4983. */
  4984. function Texture(src, callback) {
  4985. /**
  4986. * @name Two.Texture#renderer
  4987. * @property {Object}
  4988. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4989. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4990. */
  4991. this.renderer = {};
  4992. this._renderer.type = 'texture';
  4993. this._renderer.flagOffset = Texture.FlagOffset.bind(this);
  4994. this._renderer.flagScale = Texture.FlagScale.bind(this);
  4995. this.id = Constants.Identifier + Constants.uniqueId();
  4996. this.classList = [];
  4997. /**
  4998. * @name Two.Texture#loaded
  4999. * @property {Boolean} - Shorthand value to determine if image has been loaded into the texture.
  5000. */
  5001. this.loaded = false;
  5002. /**
  5003. * @name Two.Texture#repeat
  5004. * @property {String} - CSS style declaration to tile {@link Two.Path}. Valid values include: `'no-repeat'`, `'repeat'`, `'repeat-x'`, `'repeat-y'`.
  5005. * @see {@link https://www.w3.org/TR/2dcontext/#dom-context-2d-createpattern}
  5006. */
  5007. this.repeat = 'no-repeat';
  5008. /**
  5009. * @name Two.Texture#offset
  5010. * @property {Two.Vector} - A two-component vector describing any pixel offset of the texture when applied to a {@link Two.Path}.
  5011. */
  5012. this.offset = new Vector();
  5013. if (typeof callback === 'function') {
  5014. var loaded = (function() {
  5015. this.unbind(Events.Types.load, loaded);
  5016. if (typeof callback === 'function') {
  5017. callback();
  5018. }
  5019. }).bind(this);
  5020. this.bind(Events.Types.load, loaded);
  5021. }
  5022. /**
  5023. * @name Two.Texture#src
  5024. * @property {String} - The URL path to the image data.
  5025. * @nota-bene This property is ultimately serialized in a {@link Two.Registry} to cache retrieval.
  5026. */
  5027. if (typeof src === 'string') {
  5028. this.src = src;
  5029. } else if (typeof src === 'object') {
  5030. var elemString = Object.prototype.toString.call(src);
  5031. if (
  5032. elemString === '[object HTMLImageElement]' ||
  5033. elemString === '[object HTMLCanvasElement]' ||
  5034. elemString === '[object HTMLVideoElement]' ||
  5035. elemString === '[object Image]'
  5036. ) {
  5037. /**
  5038. * @name Two.Texture#image
  5039. * @property {Element} - The corresponding DOM Element of the texture. Can be a `<img />`, `<canvas />`, or `<video />` element. See {@link Two.Texture.RegularExpressions} for a full list of supported elements.
  5040. * @nota-bene In headless environments this is a `Canvas.Image` object. See {@link https://github.com/Automattic/node-canvas} for more information on headless image objects.
  5041. */
  5042. this.image = src;
  5043. }
  5044. }
  5045. this._update();
  5046. }
  5047. _.extend(Texture, {
  5048. /**
  5049. * @name Two.Texture.Properties
  5050. * @property {String[]} - A list of properties that are on every {@link Two.Texture}.
  5051. */
  5052. Properties: [
  5053. 'id',
  5054. 'src',
  5055. 'loaded',
  5056. 'repeat'
  5057. ],
  5058. /**
  5059. * @name Two.Texture.RegularExpressions
  5060. * @property {Object} - A map of compatible DOM Elements categorized by media format.
  5061. */
  5062. RegularExpressions: regex$1,
  5063. /**
  5064. * @name Two.Texture.ImageRegistry
  5065. * @property {Two.Registry} - A canonical listing of image data used in a single session of Two.js.
  5066. * @nota-bene This object is used to cache image data between different textures.
  5067. */
  5068. ImageRegistry: new Registry(),
  5069. /**
  5070. * @name Two.Texture.getAbsoluteURL
  5071. * @property {Function} - Serializes a URL as an absolute path for canonical attribution in {@link Two.ImageRegistry}.
  5072. * @param {String} path
  5073. * @returns {String} - The serialized absolute path.
  5074. */
  5075. getAbsoluteURL: function(path) {
  5076. if (!anchor) {
  5077. // TODO: Fix for headless environments
  5078. return path;
  5079. }
  5080. anchor.href = path;
  5081. return anchor.href;
  5082. },
  5083. /**
  5084. * @name Two.Texture.loadHeadlessBuffer
  5085. * @property {Function} - Loads an image as a buffer in headless environments.
  5086. * @param {Two.Texture} texture - The {@link Two.Texture} to be loaded.
  5087. * @param {Function} loaded - The callback function to be triggered once the image is loaded.
  5088. * @nota-bene - This function uses node's `fs.readFileSync` to spoof the `<img />` loading process in the browser.
  5089. */
  5090. loadHeadlessBuffer: function(texture, loaded) {
  5091. texture.image.onload = loaded;
  5092. texture.image.src = texture.src;
  5093. },
  5094. /**
  5095. * @name Two.Texture.getTag
  5096. * @property {Function} - Retrieves the tag name of an image, video, or canvas node.
  5097. * @param {HTMLImageElement} - The image to infer the tag name from.
  5098. * @returns {String} - Returns the tag name of an image, video, or canvas node.
  5099. */
  5100. getTag: function(image) {
  5101. return (image && image.nodeName && image.nodeName.toLowerCase())
  5102. // Headless environments
  5103. || 'img';
  5104. },
  5105. /**
  5106. * @name Two.Texture.getImage
  5107. * @property {Function} - Convenience function to set {@link Two.Texture#image} properties with canonincal versions set in {@link Two.Texture.ImageRegistry}.
  5108. * @param {String} src - The URL path of the image.
  5109. * @returns {HTMLImageElement} - Returns either a cached version of the image or a new one that is registered in {@link Two.Texture.ImageRegistry}.
  5110. */
  5111. getImage: function(src) {
  5112. var absoluteSrc = Texture.getAbsoluteURL(src);
  5113. if (Texture.ImageRegistry.contains(absoluteSrc)) {
  5114. return Texture.ImageRegistry.get(absoluteSrc);
  5115. }
  5116. var image;
  5117. if (CanvasShim.Image) {
  5118. // TODO: Fix for headless environments
  5119. image = new CanvasShim.Image();
  5120. Renderer$2.Utils.shim(image, 'img');
  5121. } else if (root$1.document) {
  5122. if (regex$1.video.test(absoluteSrc)) {
  5123. image = document.createElement('video');
  5124. } else {
  5125. image = document.createElement('img');
  5126. }
  5127. } else {
  5128. console.warn('Two.js: no prototypical image defined for Two.Texture');
  5129. }
  5130. image.crossOrigin = 'anonymous';
  5131. return image;
  5132. },
  5133. /**
  5134. * @name Two.Register
  5135. * @interface
  5136. * @description A collection of functions to register different types of textures. Used internally by a {@link Two.Texture}.
  5137. */
  5138. Register: {
  5139. canvas: function(texture, callback) {
  5140. texture._src = '#' + texture.id;
  5141. Texture.ImageRegistry.add(texture.src, texture.image);
  5142. if (typeof callback === 'function') {
  5143. callback();
  5144. }
  5145. },
  5146. img: function(texture, callback) {
  5147. var image = texture.image;
  5148. var loaded = function(e) {
  5149. if (!CanvasShim.isHeadless && image.removeEventListener && typeof image.removeEventListener === 'function') {
  5150. image.removeEventListener('load', loaded, false);
  5151. image.removeEventListener('error', error, false);
  5152. }
  5153. if (typeof callback === 'function') {
  5154. callback();
  5155. }
  5156. };
  5157. var error = function(e) {
  5158. if (!CanvasShim.isHeadless && typeof image.removeEventListener === 'function') {
  5159. image.removeEventListener('load', loaded, false);
  5160. image.removeEventListener('error', error, false);
  5161. }
  5162. throw new TwoError('unable to load ' + texture.src);
  5163. };
  5164. if (typeof image.width === 'number' && image.width > 0
  5165. && typeof image.height === 'number' && image.height > 0) {
  5166. loaded();
  5167. } else if (!CanvasShim.isHeadless && typeof image.addEventListener === 'function') {
  5168. image.addEventListener('load', loaded, false);
  5169. image.addEventListener('error', error, false);
  5170. }
  5171. texture._src = Texture.getAbsoluteURL(texture._src);
  5172. if (!CanvasShim.isHeadless && image && image.getAttribute('two-src')) {
  5173. return;
  5174. }
  5175. if (!CanvasShim.isHeadless) {
  5176. image.setAttribute('two-src', texture.src);
  5177. }
  5178. Texture.ImageRegistry.add(texture.src, image);
  5179. if (CanvasShim.isHeadless) {
  5180. Texture.loadHeadlessBuffer(texture, loaded);
  5181. } else {
  5182. texture.image.src = texture.src;
  5183. }
  5184. },
  5185. video: function(texture, callback) {
  5186. if (CanvasShim.isHeadless) {
  5187. throw new TwoError('video textures are not implemented in headless environments.');
  5188. }
  5189. var loaded = function(e) {
  5190. texture.image.removeEventListener('canplaythrough', loaded, false);
  5191. texture.image.removeEventListener('error', error, false);
  5192. texture.image.width = texture.image.videoWidth;
  5193. texture.image.height = texture.image.videoHeight;
  5194. if (typeof callback === 'function') {
  5195. callback();
  5196. }
  5197. };
  5198. var error = function(e) {
  5199. texture.image.removeEventListener('canplaythrough', loaded, false);
  5200. texture.image.removeEventListener('error', error, false);
  5201. throw new TwoError('unable to load ' + texture.src);
  5202. };
  5203. texture._src = Texture.getAbsoluteURL(texture._src);
  5204. if (!texture.image.getAttribute('two-src')) {
  5205. texture.image.setAttribute('two-src', texture.src);
  5206. Texture.ImageRegistry.add(texture.src, texture.image);
  5207. }
  5208. if (texture.image.readyState >= 4) {
  5209. loaded();
  5210. } else {
  5211. texture.image.addEventListener('canplaythrough', loaded, false);
  5212. texture.image.addEventListener('error', error, false);
  5213. texture.image.src = texture.src;
  5214. texture.image.load();
  5215. }
  5216. }
  5217. },
  5218. /**
  5219. * @name Two.Texture.load
  5220. * @function
  5221. * @param {Two.Texture} texture - The texture to load.
  5222. * @param {Function} callback - The function to be called once the texture is loaded.
  5223. */
  5224. load: function(texture, callback) {
  5225. var image = texture.image;
  5226. var tag = Texture.getTag(image);
  5227. if (texture._flagImage) {
  5228. if (/canvas/i.test(tag)) {
  5229. Texture.Register.canvas(texture, callback);
  5230. } else {
  5231. texture._src = (!CanvasShim.isHeadless && image.getAttribute('two-src')) || image.src;
  5232. Texture.Register[tag](texture, callback);
  5233. }
  5234. }
  5235. if (texture._flagSrc) {
  5236. if (!image) {
  5237. image = Texture.getImage(texture.src);
  5238. texture.image = image;
  5239. }
  5240. tag = Texture.getTag(image);
  5241. Texture.Register[tag](texture, callback);
  5242. }
  5243. },
  5244. /**
  5245. * @name Two.Texture.FlagOffset
  5246. * @function
  5247. * @description Cached method to let renderers know `offset` has been updated on a {@link Two.Texture}.
  5248. */
  5249. FlagOffset: function() {
  5250. this._flagOffset = true;
  5251. },
  5252. /**
  5253. * @name Two.Texture.FlagScale
  5254. * @function
  5255. * @description Cached method to let renderers know `scale` has been updated on a {@link Two.Texture}.
  5256. */
  5257. FlagScale: function() {
  5258. this._flagScale = true;
  5259. },
  5260. /**
  5261. * @name Two.Texture.MakeObservable
  5262. * @function
  5263. * @param {Object} object - The object to make observable.
  5264. * @description Convenience function to apply observable qualities of a {@link Two.Texture} to any object. Handy if you'd like to extend or inherit the {@link Two.Texture} class on a custom class.
  5265. */
  5266. MakeObservable: function(object) {
  5267. _.each(Texture.Properties, defineGetterSetter, object);
  5268. Object.defineProperty(object, 'image', {
  5269. enumerable: true,
  5270. get: function() {
  5271. return this._image;
  5272. },
  5273. set: function(image) {
  5274. var tag = Texture.getTag(image);
  5275. var index;
  5276. switch (tag) {
  5277. case 'canvas':
  5278. index = '#' + image.id;
  5279. break;
  5280. default:
  5281. index = image.src;
  5282. }
  5283. if (Texture.ImageRegistry.contains(index)) {
  5284. this._image = Texture.ImageRegistry.get(image.src);
  5285. } else {
  5286. this._image = image;
  5287. }
  5288. this._flagImage = true;
  5289. }
  5290. });
  5291. Object.defineProperty(object, 'offset', {
  5292. enumerable: true,
  5293. get: function() {
  5294. return this._offset;
  5295. },
  5296. set: function(v) {
  5297. if (this._offset) {
  5298. this._offset.unbind(Events.Types.change, this._renderer.flagOffset);
  5299. }
  5300. this._offset = v;
  5301. this._offset.bind(Events.Types.change, this._renderer.flagOffset);
  5302. this._flagOffset = true;
  5303. }
  5304. });
  5305. Object.defineProperty(object, 'scale', {
  5306. enumerable: true,
  5307. get: function() {
  5308. return this._scale;
  5309. },
  5310. set: function(v) {
  5311. if (this._scale instanceof Vector) {
  5312. this._scale.unbind(Events.Types.change, this._renderer.flagScale);
  5313. }
  5314. this._scale = v;
  5315. if (this._scale instanceof Vector) {
  5316. this._scale.bind(Events.Types.change, this._renderer.flagScale);
  5317. }
  5318. this._flagScale = true;
  5319. }
  5320. });
  5321. Object.defineProperty(object, 'renderer', {
  5322. enumerable: false,
  5323. get: function() {
  5324. return this._renderer;
  5325. },
  5326. set: function(obj) {
  5327. this._renderer = obj;
  5328. }
  5329. });
  5330. }
  5331. });
  5332. _.extend(Texture.prototype, Events, Shape.prototype, {
  5333. constructor: Texture,
  5334. /**
  5335. * @name Two.Texture#_flagId
  5336. * @private
  5337. * @property {Boolean} - Determines whether the {@link Two.Texture#id} needs updating.
  5338. */
  5339. _flagId: false,
  5340. /**
  5341. * @name Two.Texture#_flagSrc
  5342. * @private
  5343. * @property {Boolean} - Determines whether the {@link Two.Texture#src} needs updating.
  5344. */
  5345. _flagSrc: false,
  5346. /**
  5347. * @name Two.Texture#_flagImage
  5348. * @private
  5349. * @property {Boolean} - Determines whether the {@link Two.Texture#image} needs updating.
  5350. */
  5351. _flagImage: false,
  5352. /**
  5353. * @name Two.Texture#_flagVideo
  5354. * @private
  5355. * @property {Boolean} - Determines whether the {@link Two.Texture#video} needs updating.
  5356. */
  5357. _flagVideo: false,
  5358. /**
  5359. * @name Two.Texture#_flagLoaded
  5360. * @private
  5361. * @property {Boolean} - Determines whether the {@link Two.Texture#loaded} needs updating.
  5362. */
  5363. _flagLoaded: false,
  5364. /**
  5365. * @name Two.Texture#_flagRepeat
  5366. * @private
  5367. * @property {Boolean} - Determines whether the {@link Two.Texture#repeat} needs updating.
  5368. */
  5369. _flagRepeat: false,
  5370. /**
  5371. * @name Two.Texture#_flagOffset
  5372. * @private
  5373. * @property {Boolean} - Determines whether the {@link Two.Texture#offset} needs updating.
  5374. */
  5375. _flagOffset: false,
  5376. /**
  5377. * @name Two.Texture#_flagScale
  5378. * @private
  5379. * @property {Boolean} - Determines whether the {@link Two.Texture#scale} needs updating.
  5380. */
  5381. _flagScale: false,
  5382. /**
  5383. * @name Two.Texture#_id
  5384. * @private
  5385. * @see {@link Two.Texture#id}
  5386. */
  5387. _id: '',
  5388. /**
  5389. * @name Two.Texture#_src
  5390. * @private
  5391. * @see {@link Two.Texture#src}
  5392. */
  5393. _src: '',
  5394. /**
  5395. * @name Two.Texture#_image
  5396. * @private
  5397. * @see {@link Two.Texture#image}
  5398. */
  5399. _image: null,
  5400. /**
  5401. * @name Two.Texture#_loaded
  5402. * @private
  5403. * @see {@link Two.Texture#loaded}
  5404. */
  5405. _loaded: false,
  5406. /**
  5407. * @name Two.Texture#_repeat
  5408. * @private
  5409. * @see {@link Two.Texture#repeat}
  5410. */
  5411. _repeat: 'no-repeat',
  5412. /**
  5413. * @name Two.Texture#_scale
  5414. * @private
  5415. * @see {@link Two.Texture#scale}
  5416. */
  5417. _scale: 1,
  5418. /**
  5419. * @name Two.Texture#_offset
  5420. * @private
  5421. * @see {@link Two.Texture#offset}
  5422. */
  5423. _offset: null,
  5424. /**
  5425. * @name Two.Texture#clone
  5426. * @function
  5427. * @returns {Two.Texture}
  5428. * @description Create a new instance of {@link Two.Texture} with the same properties of the current texture.
  5429. */
  5430. clone: function() {
  5431. var clone = new Texture(this.src);
  5432. clone.repeat = this.repeat;
  5433. clone.offset.copy(this.origin);
  5434. clone.scale = this.scale;
  5435. return clone;
  5436. },
  5437. /**
  5438. * @name Two.Texture#toObject
  5439. * @function
  5440. * @returns {Object}
  5441. * @description Return a JSON compatible plain object that represents the texture.
  5442. */
  5443. toObject: function() {
  5444. return {
  5445. src: this.src,
  5446. // image: this.image,
  5447. repeat: this.repeat,
  5448. origin: this.origin.toObject(),
  5449. scale: typeof this.scale === 'number' ? this.scale : this.scale.toObject()
  5450. };
  5451. },
  5452. /**
  5453. * @name Two.Texture#_update
  5454. * @function
  5455. * @private
  5456. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  5457. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  5458. * @nota-bene Try not to call this method more than once a frame.
  5459. */
  5460. _update: function() {
  5461. if (this._flagSrc || this._flagImage) {
  5462. this.trigger(Events.Types.change);
  5463. if (this._flagSrc || this._flagImage) {
  5464. this.loaded = false;
  5465. Texture.load(this, (function() {
  5466. this.loaded = true;
  5467. this
  5468. .trigger(Events.Types.change)
  5469. .trigger(Events.Types.load);
  5470. }).bind(this));
  5471. }
  5472. }
  5473. if (this._image && this._image.readyState >= 4) {
  5474. this._flagVideo = true;
  5475. }
  5476. return this;
  5477. },
  5478. /**
  5479. * @name Two.Texture#flagReset
  5480. * @function
  5481. * @private
  5482. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  5483. */
  5484. flagReset: function() {
  5485. this._flagSrc = this._flagImage = this._flagLoaded
  5486. = this._flagVideo = this._flagScale = this._flagOffset = false;
  5487. return this;
  5488. }
  5489. });
  5490. Texture.MakeObservable(Texture.prototype);
  5491. // Constants
  5492. var min$1 = Math.min, max$1 = Math.max,
  5493. ceil = Math.ceil, floor = Math.floor;
  5494. /**
  5495. * @name Two.Path
  5496. * @class
  5497. * @extends Two.Shape
  5498. * @param {Two.Anchor[]} [vertices] - A list of {@link Two.Anchor}s that represent the order and coordinates to construct the rendered shape.
  5499. * @param {Boolean} [closed=false] - Describes whether the shape is closed or open.
  5500. * @param {Boolean} [curved=false] - Describes whether the shape automatically calculates bezier handles for each vertex.
  5501. * @param {Boolean} [manual=false] - Describes whether the developer controls how vertices are plotted or if Two.js automatically plots coordinates based on closed and curved booleans.
  5502. * @description This is the primary primitive class for creating all drawable shapes in Two.js. Unless specified methods return their instance of `Two.Path` for the purpose of chaining.
  5503. */
  5504. function Path(vertices, closed, curved, manual) {
  5505. Shape.call(this);
  5506. this._renderer.type = 'path';
  5507. this._renderer.flagVertices = Path.FlagVertices.bind(this);
  5508. this._renderer.bindVertices = Path.BindVertices.bind(this);
  5509. this._renderer.unbindVertices = Path.UnbindVertices.bind(this);
  5510. this._renderer.flagFill = Path.FlagFill.bind(this);
  5511. this._renderer.flagStroke = Path.FlagStroke.bind(this);
  5512. this._renderer.vertices = [];
  5513. this._renderer.collection = [];
  5514. /**
  5515. * @name Two.Path#closed
  5516. * @property {Boolean} - Determines whether a final line is drawn between the final point in the `vertices` array and the first point.
  5517. */
  5518. this._closed = !!closed;
  5519. /**
  5520. * @name Two.Path#curved
  5521. * @property {Boolean} - When the path is `automatic = true` this boolean determines whether the lines between the points are curved or not.
  5522. */
  5523. this._curved = !!curved;
  5524. /**
  5525. * @name Two.Path#beginning
  5526. * @property {Number} - Number between zero and one to state the beginning of where the path is rendered.
  5527. * @description {@link Two.Path#beginning} is a percentage value that represents at what percentage into the path should the renderer start drawing.
  5528. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Path#ending}.
  5529. */
  5530. this.beginning = 0;
  5531. /**
  5532. * @name Two.Path#ending
  5533. * @property {Number} - Number between zero and one to state the ending of where the path is rendered.
  5534. * @description {@link Two.Path#ending} is a percentage value that represents at what percentage into the path should the renderer start drawing.
  5535. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Path#beginning}.
  5536. */
  5537. this.ending = 1;
  5538. // Style properties
  5539. /**
  5540. * @name Two.Path#fill
  5541. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the path should be filled in with.
  5542. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  5543. */
  5544. this.fill = '#fff';
  5545. /**
  5546. * @name Two.Path#stroke
  5547. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the path should be outlined in with.
  5548. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  5549. */
  5550. this.stroke = '#000';
  5551. /**
  5552. * @name Two.Path#linewidth
  5553. * @property {Number} - The thickness in pixels of the stroke.
  5554. */
  5555. this.linewidth = 1.0;
  5556. /**
  5557. * @name Two.Path#opacity
  5558. * @property {Number} - The opaqueness of the path.
  5559. * @nota-bene Can be used in conjunction with CSS Colors that have an alpha value.
  5560. */
  5561. this.opacity = 1.0;
  5562. /**
  5563. * @name Two.Path#className
  5564. * @property {String} - A class to be applied to the element to be compatible with CSS styling.
  5565. * @nota-bene Only available for the SVG renderer.
  5566. */
  5567. this.className = '';
  5568. /**
  5569. * @name Two.Path#visible
  5570. * @property {Boolean} - Display the path or not.
  5571. * @nota-bene For {@link Two.CanvasRenderer} and {@link Two.WebGLRenderer} when set to false all updating is disabled improving performance dramatically with many objects in the scene.
  5572. */
  5573. this.visible = true;
  5574. /**
  5575. * @name Two.Path#cap
  5576. * @property {String}
  5577. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty}
  5578. */
  5579. this.cap = 'butt'; // Default of Adobe Illustrator
  5580. /**
  5581. * @name Two.Path#join
  5582. * @property {String}
  5583. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty}
  5584. */
  5585. this.join = 'miter'; // Default of Adobe Illustrator
  5586. /**
  5587. * @name Two.Path#miter
  5588. * @property {String}
  5589. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty}
  5590. */
  5591. this.miter = 4; // Default of Adobe Illustrator
  5592. /**
  5593. * @name Two.Path#vertices
  5594. * @property {Two.Anchor[]} - An ordered list of anchor points for rendering the path.
  5595. * @description A list of {@link Two.Anchor} objects that consist of what form the path takes.
  5596. * @nota-bene The array when manipulating is actually a {@link Two.Collection}.
  5597. */
  5598. this.vertices = vertices;
  5599. /**
  5600. * @name Two.Path#automatic
  5601. * @property {Boolean} - Determines whether or not Two.js should calculate curves, lines, and commands automatically for you or to let the developer manipulate them for themselves.
  5602. */
  5603. this.automatic = !manual;
  5604. /**
  5605. * @name Two.Path#dashes
  5606. * @property {Number[]} - Array of numbers. Odd indices represent dash length. Even indices represent dash space.
  5607. * @description A list of numbers that represent the repeated dash length and dash space applied to the stroke of the text.
  5608. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray} for more information on the SVG stroke-dasharray attribute.
  5609. */
  5610. this.dashes = [];
  5611. /**
  5612. * @name Two.Path#dashes#offset
  5613. * @property {Number} - A number in pixels to offset {@link Two.Path#dashes} display.
  5614. */
  5615. this.dashes.offset = 0;
  5616. }
  5617. _.extend(Path, {
  5618. /**
  5619. * @name Two.Path.Properties
  5620. * @property {String[]} - A list of properties that are on every {@link Two.Path}.
  5621. */
  5622. Properties: [
  5623. 'fill',
  5624. 'stroke',
  5625. 'linewidth',
  5626. 'opacity',
  5627. 'visible',
  5628. 'cap',
  5629. 'join',
  5630. 'miter',
  5631. 'closed',
  5632. 'curved',
  5633. 'automatic',
  5634. 'beginning',
  5635. 'ending'
  5636. ],
  5637. Utils: {
  5638. getCurveLength: getCurveLength
  5639. },
  5640. /**
  5641. * @name Two.Path.FlagVertices
  5642. * @function
  5643. * @description Cached method to let renderers know vertices have been updated on a {@link Two.Path}.
  5644. */
  5645. FlagVertices: function() {
  5646. this._flagVertices = true;
  5647. this._flagLength = true;
  5648. if (this.parent) {
  5649. this.parent._flagLength = true;
  5650. }
  5651. },
  5652. /**
  5653. * @name Two.Path.BindVertices
  5654. * @function
  5655. * @description Cached method to let {@link Two.Path} know vertices have been added to the instance.
  5656. */
  5657. BindVertices: function(items) {
  5658. // This function is called a lot
  5659. // when importing a large SVG
  5660. var i = items.length;
  5661. while (i--) {
  5662. items[i].bind(Events.Types.change, this._renderer.flagVertices);
  5663. }
  5664. this._renderer.flagVertices();
  5665. },
  5666. /**
  5667. * @name Two.Path.UnbindVertices
  5668. * @function
  5669. * @description Cached method to let {@link Two.Path} know vertices have been removed from the instance.
  5670. */
  5671. UnbindVertices: function(items) {
  5672. var i = items.length;
  5673. while (i--) {
  5674. items[i].unbind(Events.Types.change, this._renderer.flagVertices);
  5675. }
  5676. this._renderer.flagVertices();
  5677. },
  5678. /**
  5679. * @name Two.Path.FlagFill
  5680. * @function
  5681. * @description Cached method to let {@link Two.Path} know the fill has changed.
  5682. */
  5683. FlagFill: function() {
  5684. this._flagFill = true;
  5685. },
  5686. /**
  5687. * @name Two.Path.FlagFill
  5688. * @function
  5689. * @description Cached method to let {@link Two.Path} know the stroke has changed.
  5690. */
  5691. FlagStroke: function() {
  5692. this._flagStroke = true;
  5693. },
  5694. /**
  5695. * @name Two.Path.MakeObservable
  5696. * @function
  5697. * @param {Object} object - The object to make observable.
  5698. * @description Convenience function to apply observable qualities of a {@link Two.Path} to any object. Handy if you'd like to extend the {@link Two.Path} class on a custom class.
  5699. */
  5700. MakeObservable: function(object) {
  5701. Shape.MakeObservable(object);
  5702. // Only the 7 defined properties are flagged like this. The subsequent
  5703. // properties behave differently and need to be hand written.
  5704. _.each(Path.Properties.slice(2, 8), defineGetterSetter, object);
  5705. Object.defineProperty(object, 'fill', {
  5706. enumerable: true,
  5707. get: function() {
  5708. return this._fill;
  5709. },
  5710. set: function(f) {
  5711. if (this._fill instanceof Gradient
  5712. || this._fill instanceof LinearGradient
  5713. || this._fill instanceof RadialGradient
  5714. || this._fill instanceof Texture) {
  5715. this._fill.unbind(Events.Types.change, this._renderer.flagFill);
  5716. }
  5717. this._fill = f;
  5718. this._flagFill = true;
  5719. if (this._fill instanceof Gradient
  5720. || this._fill instanceof LinearGradient
  5721. || this._fill instanceof RadialGradient
  5722. || this._fill instanceof Texture) {
  5723. this._fill.bind(Events.Types.change, this._renderer.flagFill);
  5724. }
  5725. }
  5726. });
  5727. Object.defineProperty(object, 'stroke', {
  5728. enumerable: true,
  5729. get: function() {
  5730. return this._stroke;
  5731. },
  5732. set: function(f) {
  5733. if (this._stroke instanceof Gradient
  5734. || this._stroke instanceof LinearGradient
  5735. || this._stroke instanceof RadialGradient
  5736. || this._stroke instanceof Texture) {
  5737. this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
  5738. }
  5739. this._stroke = f;
  5740. this._flagStroke = true;
  5741. if (this._stroke instanceof Gradient
  5742. || this._stroke instanceof LinearGradient
  5743. || this._stroke instanceof RadialGradient
  5744. || this._stroke instanceof Texture) {
  5745. this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
  5746. }
  5747. }
  5748. });
  5749. /**
  5750. * @name Two.Path#length
  5751. * @property {Number} - The sum of distances between all {@link Two.Path#vertices}.
  5752. */
  5753. Object.defineProperty(object, 'length', {
  5754. get: function() {
  5755. if (this._flagLength) {
  5756. this._updateLength();
  5757. }
  5758. return this._length;
  5759. }
  5760. });
  5761. Object.defineProperty(object, 'closed', {
  5762. enumerable: true,
  5763. get: function() {
  5764. return this._closed;
  5765. },
  5766. set: function(v) {
  5767. this._closed = !!v;
  5768. this._flagVertices = true;
  5769. }
  5770. });
  5771. Object.defineProperty(object, 'curved', {
  5772. enumerable: true,
  5773. get: function() {
  5774. return this._curved;
  5775. },
  5776. set: function(v) {
  5777. this._curved = !!v;
  5778. this._flagVertices = true;
  5779. }
  5780. });
  5781. Object.defineProperty(object, 'automatic', {
  5782. enumerable: true,
  5783. get: function() {
  5784. return this._automatic;
  5785. },
  5786. set: function(v) {
  5787. if (v === this._automatic) {
  5788. return;
  5789. }
  5790. this._automatic = !!v;
  5791. var method = this._automatic ? 'ignore' : 'listen';
  5792. _.each(this.vertices, function(v) {
  5793. v[method]();
  5794. });
  5795. }
  5796. });
  5797. Object.defineProperty(object, 'beginning', {
  5798. enumerable: true,
  5799. get: function() {
  5800. return this._beginning;
  5801. },
  5802. set: function(v) {
  5803. this._beginning = v;
  5804. this._flagVertices = true;
  5805. }
  5806. });
  5807. Object.defineProperty(object, 'ending', {
  5808. enumerable: true,
  5809. get: function() {
  5810. return this._ending;
  5811. },
  5812. set: function(v) {
  5813. this._ending = v;
  5814. this._flagVertices = true;
  5815. }
  5816. });
  5817. Object.defineProperty(object, 'vertices', {
  5818. enumerable: true,
  5819. get: function() {
  5820. return this._collection;
  5821. },
  5822. set: function(vertices) {
  5823. var bindVertices = this._renderer.bindVertices;
  5824. var unbindVertices = this._renderer.unbindVertices;
  5825. // Remove previous listeners
  5826. if (this._collection) {
  5827. this._collection
  5828. .unbind(Events.Types.insert, bindVertices)
  5829. .unbind(Events.Types.remove, unbindVertices);
  5830. }
  5831. // Create new Collection with copy of vertices
  5832. if (vertices instanceof Collection) {
  5833. this._collection = vertices;
  5834. } else {
  5835. this._collection = new Collection(vertices || []);
  5836. }
  5837. // Listen for Collection changes and bind / unbind
  5838. this._collection
  5839. .bind(Events.Types.insert, bindVertices)
  5840. .bind(Events.Types.remove, unbindVertices);
  5841. // Bind Initial Vertices
  5842. bindVertices(this._collection);
  5843. }
  5844. });
  5845. /**
  5846. * @name Two.Path#mask
  5847. * @property {Two.Shape} - The shape whose alpha property becomes a clipping area for the path.
  5848. * @nota-bene This property is currently not working becuase of SVG spec issues found here {@link https://code.google.com/p/chromium/issues/detail?id=370951}.
  5849. */
  5850. Object.defineProperty(object, 'mask', {
  5851. enumerable: true,
  5852. get: function() {
  5853. return this._mask;
  5854. },
  5855. set: function(v) {
  5856. this._mask = v;
  5857. this._flagMask = true;
  5858. if (!v.clip) {
  5859. v.clip = true;
  5860. }
  5861. }
  5862. });
  5863. /**
  5864. * @name Two.Path#clip
  5865. * @property {Boolean} - Tells Two.js renderer if this object represents a mask for another object (or not).
  5866. */
  5867. Object.defineProperty(object, 'clip', {
  5868. enumerable: true,
  5869. get: function() {
  5870. return this._clip;
  5871. },
  5872. set: function(v) {
  5873. this._clip = v;
  5874. this._flagClip = true;
  5875. }
  5876. });
  5877. Object.defineProperty(object, 'dashes', {
  5878. enumerable: true,
  5879. get: function() {
  5880. return this._dashes;
  5881. },
  5882. set: function(v) {
  5883. if (typeof v.offset !== 'number') {
  5884. v.offset = this._dashes.offset || 0;
  5885. }
  5886. this._dashes = v;
  5887. }
  5888. });
  5889. }
  5890. });
  5891. _.extend(Path.prototype, Shape.prototype, {
  5892. constructor: Path,
  5893. // Flags
  5894. // http://en.wikipedia.org/wiki/Flag
  5895. /**
  5896. * @name Two.Path#_flagVertices
  5897. * @private
  5898. * @property {Boolean} - Determines whether the {@link Two.Path#vertices} need updating.
  5899. */
  5900. _flagVertices: true,
  5901. /**
  5902. * @name Two.Path#_flagLength
  5903. * @private
  5904. * @property {Boolean} - Determines whether the {@link Two.Path#length} needs updating.
  5905. */
  5906. _flagLength: true,
  5907. /**
  5908. * @name Two.Path#_flagFill
  5909. * @private
  5910. * @property {Boolean} - Determines whether the {@link Two.Path#fill} needs updating.
  5911. */
  5912. _flagFill: true,
  5913. /**
  5914. * @name Two.Path#_flagStroke
  5915. * @private
  5916. * @property {Boolean} - Determines whether the {@link Two.Path#stroke} needs updating.
  5917. */
  5918. _flagStroke: true,
  5919. /**
  5920. * @name Two.Path#_flagLinewidth
  5921. * @private
  5922. * @property {Boolean} - Determines whether the {@link Two.Path#linewidth} needs updating.
  5923. */
  5924. _flagLinewidth: true,
  5925. /**
  5926. * @name Two.Path#_flagOpacity
  5927. * @private
  5928. * @property {Boolean} - Determines whether the {@link Two.Path#opacity} needs updating.
  5929. */
  5930. _flagOpacity: true,
  5931. /**
  5932. * @name Two.Path#_flagVisible
  5933. * @private
  5934. * @property {Boolean} - Determines whether the {@link Two.Path#visible} needs updating.
  5935. */
  5936. _flagVisible: true,
  5937. /**
  5938. * @name Two.Path#_flagCap
  5939. * @private
  5940. * @property {Boolean} - Determines whether the {@link Two.Path#cap} needs updating.
  5941. */
  5942. _flagCap: true,
  5943. /**
  5944. * @name Two.Path#_flagJoin
  5945. * @private
  5946. * @property {Boolean} - Determines whether the {@link Two.Path#join} needs updating.
  5947. */
  5948. _flagJoin: true,
  5949. /**
  5950. * @name Two.Path#_flagMiter
  5951. * @private
  5952. * @property {Boolean} - Determines whether the {@link Two.Path#miter} needs updating.
  5953. */
  5954. _flagMiter: true,
  5955. /**
  5956. * @name Two.Path#_flagMask
  5957. * @private
  5958. * @property {Boolean} - Determines whether the {@link Two.Path#mask} needs updating.
  5959. */
  5960. _flagMask: false,
  5961. /**
  5962. * @name Two.Path#_flagClip
  5963. * @private
  5964. * @property {Boolean} - Determines whether the {@link Two.Path#clip} needs updating.
  5965. */
  5966. _flagClip: false,
  5967. // Underlying Properties
  5968. /**
  5969. * @name Two.Path#_length
  5970. * @private
  5971. * @see {@link Two.Path#length}
  5972. */
  5973. _length: 0,
  5974. /**
  5975. * @name Two.Path#_fill
  5976. * @private
  5977. * @see {@link Two.Path#fill}
  5978. */
  5979. _fill: '#fff',
  5980. /**
  5981. * @name Two.Path#_stroke
  5982. * @private
  5983. * @see {@link Two.Path#stroke}
  5984. */
  5985. _stroke: '#000',
  5986. /**
  5987. * @name Two.Path#_linewidth
  5988. * @private
  5989. * @see {@link Two.Path#linewidth}
  5990. */
  5991. _linewidth: 1.0,
  5992. /**
  5993. * @name Two.Path#_opacity
  5994. * @private
  5995. * @see {@link Two.Path#opacity}
  5996. */
  5997. _opacity: 1.0,
  5998. /**
  5999. * @name Two.Path#_visible
  6000. * @private
  6001. * @see {@link Two.Path#visible}
  6002. */
  6003. _visible: true,
  6004. /**
  6005. * @name Two.Path#_cap
  6006. * @private
  6007. * @see {@link Two.Path#cap}
  6008. */
  6009. _cap: 'round',
  6010. /**
  6011. * @name Two.Path#_join
  6012. * @private
  6013. * @see {@link Two.Path#join}
  6014. */
  6015. _join: 'round',
  6016. /**
  6017. * @name Two.Path#_miter
  6018. * @private
  6019. * @see {@link Two.Path#miter}
  6020. */
  6021. _miter: 4,
  6022. /**
  6023. * @name Two.Path#_closed
  6024. * @private
  6025. * @see {@link Two.Path#closed}
  6026. */
  6027. _closed: true,
  6028. /**
  6029. * @name Two.Path#_curved
  6030. * @private
  6031. * @see {@link Two.Path#curved}
  6032. */
  6033. _curved: false,
  6034. /**
  6035. * @name Two.Path#_automatic
  6036. * @private
  6037. * @see {@link Two.Path#automatic}
  6038. */
  6039. _automatic: true,
  6040. /**
  6041. * @name Two.Path#_beginning
  6042. * @private
  6043. * @see {@link Two.Path#beginning}
  6044. */
  6045. _beginning: 0,
  6046. /**
  6047. * @name Two.Path#_ending
  6048. * @private
  6049. * @see {@link Two.Path#ending}
  6050. */
  6051. _ending: 1.0,
  6052. /**
  6053. * @name Two.Path#_mask
  6054. * @private
  6055. * @see {@link Two.Path#mask}
  6056. */
  6057. _mask: null,
  6058. /**
  6059. * @name Two.Path#_clip
  6060. * @private
  6061. * @see {@link Two.Path#clip}
  6062. */
  6063. _clip: false,
  6064. /**
  6065. * @name Two.Path#_dashes
  6066. * @private
  6067. * @see {@link Two.Path#dashes}
  6068. */
  6069. _dashes: [],
  6070. /**
  6071. * @name Two.Path#clone
  6072. * @function
  6073. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  6074. * @returns {Two.Path}
  6075. * @description Create a new instance of {@link Two.Path} with the same properties of the current path.
  6076. */
  6077. clone: function(parent) {
  6078. var clone = new Path();
  6079. for (var j = 0; j < this.vertices.length; j++) {
  6080. clone.vertices.push(this.vertices[j].clone());
  6081. }
  6082. for (var i = 0; i < Path.Properties.length; i++) {
  6083. var k = Path.Properties[i];
  6084. clone[k] = this[k];
  6085. }
  6086. clone.className = this.className;
  6087. clone.translation.copy(this.translation);
  6088. clone.rotation = this.rotation;
  6089. clone.scale = this.scale;
  6090. clone.skewX = this.skewX;
  6091. clone.skewY = this.skewY;
  6092. if (this.matrix.manual) {
  6093. clone.matrix.copy(this.matrix);
  6094. }
  6095. if (parent) {
  6096. parent.add(clone);
  6097. }
  6098. return clone._update();
  6099. },
  6100. /**
  6101. * @name Two.Path#toObject
  6102. * @function
  6103. * @returns {Object}
  6104. * @description Return a JSON compatible plain object that represents the path.
  6105. */
  6106. toObject: function() {
  6107. var result = {
  6108. vertices: this.vertices.map(function(v) {
  6109. return v.toObject();
  6110. })
  6111. };
  6112. _.each(Path.Properties, function(k) {
  6113. result[k] = this[k];
  6114. }, this);
  6115. result.className = this.className;
  6116. result.translation = this.translation.toObject();
  6117. result.rotation = this.rotation;
  6118. result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale;
  6119. result.skewX = this.skewX;
  6120. result.skewY = this.skewY;
  6121. if (this.matrix.manual) {
  6122. result.matrix = this.matrix.toObject();
  6123. }
  6124. return result;
  6125. },
  6126. /**
  6127. * @name Two.Path#noFill
  6128. * @function
  6129. * @description Short hand method to set fill to `transparent`.
  6130. */
  6131. noFill: function() {
  6132. this.fill = 'transparent';
  6133. return this;
  6134. },
  6135. /**
  6136. * @name Two.Path#noStroke
  6137. * @function
  6138. * @description Short hand method to set stroke to `transparent`.
  6139. */
  6140. noStroke: function() {
  6141. this.stroke = undefined;
  6142. return this;
  6143. },
  6144. /**
  6145. * @name Two.Path#corner
  6146. * @function
  6147. * @description Orient the vertices of the shape to the upper left-hand corner of the path.
  6148. */
  6149. corner: function() {
  6150. var rect = this.getBoundingClientRect(true);
  6151. var hw = rect.width / 2;
  6152. var hh = rect.height / 2;
  6153. var cx = rect.left + rect.width / 2;
  6154. var cy = rect.top + rect.height / 2;
  6155. for (var i = 0; i < this.vertices.length; i++) {
  6156. var v = this.vertices[i];
  6157. v.x -= cx;
  6158. v.y -= cy;
  6159. v.x += hw;
  6160. v.y += hh;
  6161. }
  6162. return this;
  6163. },
  6164. /**
  6165. * @name Two.Path#center
  6166. * @function
  6167. * @description Orient the vertices of the shape to the center of the path.
  6168. */
  6169. center: function() {
  6170. var rect = this.getBoundingClientRect(true);
  6171. var cx = rect.left + rect.width / 2 - this.translation.x;
  6172. var cy = rect.top + rect.height / 2 - this.translation.y;
  6173. for (var i = 0; i < this.vertices.length; i++) {
  6174. var v = this.vertices[i];
  6175. v.x -= cx;
  6176. v.y -= cy;
  6177. }
  6178. return this;
  6179. },
  6180. /**
  6181. * @name Two.Path#remove
  6182. * @function
  6183. * @description Remove self from the scene / parent.
  6184. */
  6185. remove: function() {
  6186. if (!this.parent) {
  6187. return this;
  6188. }
  6189. this.parent.remove(this);
  6190. return this;
  6191. },
  6192. /**
  6193. * @name Two.Path#getBoundingClientRect
  6194. * @function
  6195. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  6196. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  6197. * @description Return an object with top, left, right, bottom, width, and height parameters of the path.
  6198. */
  6199. getBoundingClientRect: function(shallow) {
  6200. var matrix, border, l, i, v0, v1, c0x, c0y, c1x, c1y, a, b, c, d;
  6201. var left = Infinity, right = -Infinity,
  6202. top = Infinity, bottom = -Infinity;
  6203. // TODO: Update this to not __always__ update. Just when it needs to.
  6204. this._update(true);
  6205. matrix = shallow ? this._matrix : getComputedMatrix(this);
  6206. border = (this.linewidth || 0) / 2;
  6207. l = this._renderer.vertices.length;
  6208. if (l <= 0) {
  6209. return {
  6210. width: 0,
  6211. height: 0
  6212. };
  6213. }
  6214. for (i = 0; i < l; i++) {
  6215. v1 = this._renderer.vertices[i];
  6216. // If i = 0, then this "wraps around" to the last vertex. Otherwise, it's the previous vertex.
  6217. // This is important for handling cyclic paths.
  6218. v0 = this._renderer.vertices[(i + l - 1) % l];
  6219. if (v0.controls && v1.controls) {
  6220. c0x = v0.controls.right.x;
  6221. c0y = v0.controls.right.y;
  6222. if (v0.relative) {
  6223. c0x += v0.x;
  6224. c0y += v0.y;
  6225. }
  6226. c1x = v1.controls.left.x;
  6227. c1y = v1.controls.left.y;
  6228. if (v1.relative) {
  6229. c1x += v1.x;
  6230. c1y += v1.y;
  6231. }
  6232. var bb = getCurveBoundingBox(v0.x, v0.y,
  6233. c0x, c0y, c1x, c1y, v1.x, v1.y);
  6234. top = min$1(bb.min.y - border, top);
  6235. left = min$1(bb.min.x - border, left);
  6236. right = max$1(bb.max.x + border, right);
  6237. bottom = max$1(bb.max.y + border, bottom);
  6238. } else {
  6239. if (i <= 1) {
  6240. top = min$1(v0.y - border, top);
  6241. left = min$1(v0.x - border, left);
  6242. right = max$1(v0.x + border, right);
  6243. bottom = max$1(v0.y + border, bottom);
  6244. }
  6245. top = min$1(v1.y - border, top);
  6246. left = min$1(v1.x - border, left);
  6247. right = max$1(v1.x + border, right);
  6248. bottom = max$1(v1.y + border, bottom);
  6249. }
  6250. }
  6251. a = matrix.multiply(left, top, 1);
  6252. b = matrix.multiply(left, bottom, 1);
  6253. c = matrix.multiply(right, top, 1);
  6254. d = matrix.multiply(right, bottom, 1);
  6255. top = min$1(a.y, b.y, c.y, d.y);
  6256. left = min$1(a.x, b.x, c.x, d.x);
  6257. right = max$1(a.x, b.x, c.x, d.x);
  6258. bottom = max$1(a.y, b.y, c.y, d.y);
  6259. return {
  6260. top: top,
  6261. left: left,
  6262. right: right,
  6263. bottom: bottom,
  6264. width: right - left,
  6265. height: bottom - top
  6266. };
  6267. },
  6268. /**
  6269. * @name Two.Path#getPointAt
  6270. * @function
  6271. * @param {Boolean} t - Percentage value describing where on the Two.Path to estimate and assign coordinate values.
  6272. * @param {Two.Vector} [obj=undefined] - Object to apply calculated x, y to. If none available returns new Object.
  6273. * @returns {Object}
  6274. * @description Given a float `t` from 0 to 1, return a point or assign a passed `obj`'s coordinates to that percentage on this Two.Path's curve.
  6275. */
  6276. getPointAt: function(t, obj) {
  6277. var ia, ib, result;
  6278. var x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right;
  6279. var target = this.length * Math.min(Math.max(t, 0), 1);
  6280. var length = this.vertices.length;
  6281. var last = length - 1;
  6282. var a = null;
  6283. var b = null;
  6284. for (var i = 0, l = this._lengths.length, sum = 0; i < l; i++) {
  6285. if (sum + this._lengths[i] >= target) {
  6286. if (this._closed) {
  6287. ia = mod(i, length);
  6288. ib = mod(i - 1, length);
  6289. if (i === 0) {
  6290. ia = ib;
  6291. ib = i;
  6292. }
  6293. } else {
  6294. ia = i;
  6295. ib = Math.min(Math.max(i - 1, 0), last);
  6296. }
  6297. a = this.vertices[ia];
  6298. b = this.vertices[ib];
  6299. target -= sum;
  6300. if (this._lengths[i] !== 0) {
  6301. t = target / this._lengths[i];
  6302. } else {
  6303. t = 0;
  6304. }
  6305. break;
  6306. }
  6307. sum += this._lengths[i];
  6308. }
  6309. if (a === null || b === null) {
  6310. return null;
  6311. }
  6312. if (!a) {
  6313. return b;
  6314. } else if (!b) {
  6315. return a;
  6316. }
  6317. right = b.controls && b.controls.right;
  6318. left = a.controls && a.controls.left;
  6319. x1 = b.x;
  6320. y1 = b.y;
  6321. x2 = (right || b).x;
  6322. y2 = (right || b).y;
  6323. x3 = (left || a).x;
  6324. y3 = (left || a).y;
  6325. x4 = a.x;
  6326. y4 = a.y;
  6327. if (right && b.relative) {
  6328. x2 += b.x;
  6329. y2 += b.y;
  6330. }
  6331. if (left && a.relative) {
  6332. x3 += a.x;
  6333. y3 += a.y;
  6334. }
  6335. x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
  6336. y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
  6337. // Higher order points for control calculation.
  6338. var t1x = lerp(x1, x2, t);
  6339. var t1y = lerp(y1, y2, t);
  6340. var t2x = lerp(x2, x3, t);
  6341. var t2y = lerp(y2, y3, t);
  6342. var t3x = lerp(x3, x4, t);
  6343. var t3y = lerp(y3, y4, t);
  6344. // Calculate the returned points control points.
  6345. var brx = lerp(t1x, t2x, t);
  6346. var bry = lerp(t1y, t2y, t);
  6347. var alx = lerp(t2x, t3x, t);
  6348. var aly = lerp(t2y, t3y, t);
  6349. if (_.isObject(obj)) {
  6350. obj.x = x;
  6351. obj.y = y;
  6352. if (!_.isObject(obj.controls)) {
  6353. Anchor.AppendCurveProperties(obj);
  6354. }
  6355. obj.controls.left.x = brx;
  6356. obj.controls.left.y = bry;
  6357. obj.controls.right.x = alx;
  6358. obj.controls.right.y = aly;
  6359. if (!typeof obj.relative === 'boolean' || obj.relative) {
  6360. obj.controls.left.x -= x;
  6361. obj.controls.left.y -= y;
  6362. obj.controls.right.x -= x;
  6363. obj.controls.right.y -= y;
  6364. }
  6365. obj.t = t;
  6366. return obj;
  6367. }
  6368. result = new Anchor(
  6369. x, y, brx - x, bry - y, alx - x, aly - y,
  6370. this._curved ? Commands.curve : Commands.line
  6371. );
  6372. result.t = t;
  6373. return result;
  6374. },
  6375. /**
  6376. * @name Two.Path#plot
  6377. * @function
  6378. * @description Based on closed / curved and sorting of vertices plot where all points should be and where the respective handles should be too.
  6379. * @nota-bene While this method is public it is internally called by {@link Two.Path#_update} when `automatic = true`.
  6380. */
  6381. plot: function() {
  6382. if (this.curved) {
  6383. getCurveFromPoints(this._collection, this.closed);
  6384. return this;
  6385. }
  6386. for (var i = 0; i < this._collection.length; i++) {
  6387. this._collection[i].command = i === 0 ? Commands.move : Commands.line;
  6388. }
  6389. return this;
  6390. },
  6391. /**
  6392. * @name Two.Path#subdivide
  6393. * @function
  6394. * @param {Number} limit - How many times to recurse subdivisions.
  6395. * @description Insert a {@link Two.Anchor} at the midpoint between every item in {@link Two.Path#vertices}.
  6396. */
  6397. subdivide: function(limit) {
  6398. //TODO: DRYness (function below)
  6399. this._update();
  6400. var last = this.vertices.length - 1;
  6401. var b = this.vertices[last];
  6402. var closed = this._closed || this.vertices[last]._command === Commands.close;
  6403. var points = [];
  6404. _.each(this.vertices, function(a, i) {
  6405. if (i <= 0 && !closed) {
  6406. b = a;
  6407. return;
  6408. }
  6409. if (a.command === Commands.move) {
  6410. points.push(new Anchor(b.x, b.y));
  6411. if (i > 0) {
  6412. points[points.length - 1].command = Commands.line;
  6413. }
  6414. b = a;
  6415. return;
  6416. }
  6417. var verts = getSubdivisions(a, b, limit);
  6418. points = points.concat(verts);
  6419. // Assign commands to all the verts
  6420. _.each(verts, function(v, i) {
  6421. if (i <= 0 && b.command === Commands.move) {
  6422. v.command = Commands.move;
  6423. } else {
  6424. v.command = Commands.line;
  6425. }
  6426. });
  6427. if (i >= last) {
  6428. // TODO: Add check if the two vectors in question are the same values.
  6429. if (this._closed && this._automatic) {
  6430. b = a;
  6431. verts = getSubdivisions(a, b, limit);
  6432. points = points.concat(verts);
  6433. // Assign commands to all the verts
  6434. _.each(verts, function(v, i) {
  6435. if (i <= 0 && b.command === Commands.move) {
  6436. v.command = Commands.move;
  6437. } else {
  6438. v.command = Commands.line;
  6439. }
  6440. });
  6441. } else if (closed) {
  6442. points.push(new Anchor(a.x, a.y));
  6443. }
  6444. points[points.length - 1].command = closed
  6445. ? Commands.close : Commands.line;
  6446. }
  6447. b = a;
  6448. }, this);
  6449. this._automatic = false;
  6450. this._curved = false;
  6451. this.vertices = points;
  6452. return this;
  6453. },
  6454. /**
  6455. * @name Two.Path#_updateLength
  6456. * @function
  6457. * @private
  6458. * @param {Number} [limit=] -
  6459. * @param {Boolean} [silent=false] - If set to `true` then the path isn't updated before calculation. Useful for internal use.
  6460. * @description Recalculate the {@link Two.Path#length} value.
  6461. */
  6462. _updateLength: function(limit, silent) {
  6463. //TODO: DRYness (function above)
  6464. if (!silent) {
  6465. this._update();
  6466. }
  6467. var length = this.vertices.length;
  6468. var last = length - 1;
  6469. var b = this.vertices[last];
  6470. var closed = false;//this._closed || this.vertices[last]._command === Commands.close;
  6471. var sum = 0;
  6472. if (typeof this._lengths === 'undefined') {
  6473. this._lengths = [];
  6474. }
  6475. _.each(this.vertices, function(a, i) {
  6476. if ((i <= 0 && !closed) || a.command === Commands.move) {
  6477. b = a;
  6478. this._lengths[i] = 0;
  6479. return;
  6480. }
  6481. this._lengths[i] = getCurveLength(a, b, limit);
  6482. sum += this._lengths[i];
  6483. if (i >= last && closed) {
  6484. b = this.vertices[(i + 1) % length];
  6485. this._lengths[i + 1] = getCurveLength(a, b, limit);
  6486. sum += this._lengths[i + 1];
  6487. }
  6488. b = a;
  6489. }, this);
  6490. this._length = sum;
  6491. this._flagLength = false;
  6492. return this;
  6493. },
  6494. /**
  6495. * @name Two.Path#_update
  6496. * @function
  6497. * @private
  6498. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  6499. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  6500. * @nota-bene Try not to call this method more than once a frame.
  6501. */
  6502. _update: function() {
  6503. if (this._flagVertices) {
  6504. if (this._automatic) {
  6505. this.plot();
  6506. }
  6507. if (this._flagLength) {
  6508. this._updateLength(undefined, true);
  6509. }
  6510. var l = this._collection.length;
  6511. var closed = this._closed;
  6512. var beginning = Math.min(this._beginning, this._ending);
  6513. var ending = Math.max(this._beginning, this._ending);
  6514. var bid = getIdByLength(this, beginning * this._length);
  6515. var eid = getIdByLength(this, ending * this._length);
  6516. var low = ceil(bid);
  6517. var high = floor(eid);
  6518. var left, right, prev, next, v;
  6519. this._renderer.vertices.length = 0;
  6520. for (var i = 0; i < l; i++) {
  6521. if (this._renderer.collection.length <= i) {
  6522. // Expected to be `relative` anchor points.
  6523. this._renderer.collection.push(new Anchor());
  6524. }
  6525. if (i > high && !right) {
  6526. v = this._renderer.collection[i];
  6527. v.copy(this._collection[i]);
  6528. this.getPointAt(ending, v);
  6529. v.command = this._renderer.collection[i].command;
  6530. this._renderer.vertices.push(v);
  6531. right = v;
  6532. prev = this._collection[i - 1];
  6533. // Project control over the percentage `t`
  6534. // of the in-between point
  6535. if (prev && prev.controls) {
  6536. v.controls.right.clear();
  6537. this._renderer.collection[i - 1].controls.right
  6538. .clear()
  6539. .lerp(prev.controls.right, v.t);
  6540. }
  6541. } else if (i >= low && i <= high) {
  6542. v = this._renderer.collection[i]
  6543. .copy(this._collection[i]);
  6544. this._renderer.vertices.push(v);
  6545. if (i === high && contains(this, ending)) {
  6546. right = v;
  6547. if (!closed && right.controls) {
  6548. right.controls.right.clear();
  6549. }
  6550. } else if (i === low && contains(this, beginning)) {
  6551. left = v;
  6552. left.command = Commands.move;
  6553. if (!closed && left.controls) {
  6554. left.controls.left.clear();
  6555. }
  6556. }
  6557. }
  6558. }
  6559. // Prepend the trimmed point if necessary.
  6560. if (low > 0 && !left) {
  6561. i = low - 1;
  6562. v = this._renderer.collection[i];
  6563. v.copy(this._collection[i]);
  6564. this.getPointAt(beginning, v);
  6565. v.command = Commands.move;
  6566. this._renderer.vertices.unshift(v);
  6567. left = v;
  6568. next = this._collection[i + 1];
  6569. // Project control over the percentage `t`
  6570. // of the in-between point
  6571. if (next && next.controls) {
  6572. v.controls.left.clear();
  6573. this._renderer.collection[i + 1].controls.left
  6574. .copy(next.controls.left)
  6575. .lerp(Vector.zero, v.t);
  6576. }
  6577. }
  6578. }
  6579. Shape.prototype._update.apply(this, arguments);
  6580. return this;
  6581. },
  6582. /**
  6583. * @name Two.Path#flagReset
  6584. * @function
  6585. * @private
  6586. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  6587. */
  6588. flagReset: function() {
  6589. this._flagVertices = this._flagFill = this._flagStroke =
  6590. this._flagLinewidth = this._flagOpacity = this._flagVisible =
  6591. this._flagCap = this._flagJoin = this._flagMiter =
  6592. this._flagClip = false;
  6593. Shape.prototype.flagReset.call(this);
  6594. return this;
  6595. }
  6596. });
  6597. Path.MakeObservable(Path.prototype);
  6598. // Utility functions
  6599. function contains(path, t) {
  6600. if (t === 0 || t === 1) {
  6601. return true;
  6602. }
  6603. var length = path._length;
  6604. var target = length * t;
  6605. var elapsed = 0;
  6606. for (var i = 0; i < path._lengths.length; i++) {
  6607. var dist = path._lengths[i];
  6608. if (elapsed >= target) {
  6609. return target - elapsed >= 0;
  6610. }
  6611. elapsed += dist;
  6612. }
  6613. return false;
  6614. }
  6615. /**
  6616. * @private
  6617. * @param {Two.Path} path - The path to analyze against.
  6618. * @param {Number} target - The target length at which to find an anchor.
  6619. * @returns {Number}
  6620. * @description Return the id of an anchor based on a target length.
  6621. */
  6622. function getIdByLength(path, target) {
  6623. var total = path._length;
  6624. if (target <= 0) {
  6625. return 0;
  6626. } else if (target >= total) {
  6627. return path._lengths.length - 1;
  6628. }
  6629. for (var i = 0, sum = 0; i < path._lengths.length; i++) {
  6630. if (sum + path._lengths[i] >= target) {
  6631. target -= sum;
  6632. return Math.max(i - 1, 0) + target / path._lengths[i];
  6633. }
  6634. sum += path._lengths[i];
  6635. }
  6636. return - 1;
  6637. }
  6638. function getCurveLength(a, b, limit) {
  6639. // TODO: DRYness
  6640. var x1, x2, x3, x4, y1, y2, y3, y4;
  6641. var right = b.controls && b.controls.right;
  6642. var left = a.controls && a.controls.left;
  6643. x1 = b.x;
  6644. y1 = b.y;
  6645. x2 = (right || b).x;
  6646. y2 = (right || b).y;
  6647. x3 = (left || a).x;
  6648. y3 = (left || a).y;
  6649. x4 = a.x;
  6650. y4 = a.y;
  6651. if (right && b._relative) {
  6652. x2 += b.x;
  6653. y2 += b.y;
  6654. }
  6655. if (left && a._relative) {
  6656. x3 += a.x;
  6657. y3 += a.y;
  6658. }
  6659. return getCurveLength$1(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  6660. }
  6661. function getSubdivisions(a, b, limit) {
  6662. // TODO: DRYness
  6663. var x1, x2, x3, x4, y1, y2, y3, y4;
  6664. var right = b.controls && b.controls.right;
  6665. var left = a.controls && a.controls.left;
  6666. x1 = b.x;
  6667. y1 = b.y;
  6668. x2 = (right || b).x;
  6669. y2 = (right || b).y;
  6670. x3 = (left || a).x;
  6671. y3 = (left || a).y;
  6672. x4 = a.x;
  6673. y4 = a.y;
  6674. if (right && b._relative) {
  6675. x2 += b.x;
  6676. y2 += b.y;
  6677. }
  6678. if (left && a._relative) {
  6679. x3 += a.x;
  6680. y3 += a.y;
  6681. }
  6682. return subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  6683. }
  6684. /**
  6685. * @name Two.Rectangle
  6686. * @class
  6687. * @extends Two.Path
  6688. * @param {Number} [x=0] - The x position of the rectangle.
  6689. * @param {Number} [y=0] - The y position of the rectangle.
  6690. * @param {Number} [width] - The width value of the rectangle.
  6691. * @param {Number} [height] - The width value of the rectangle.
  6692. */
  6693. function Rectangle(x, y, width, height) {
  6694. Path.call(this, [
  6695. new Anchor(),
  6696. new Anchor(),
  6697. new Anchor(),
  6698. new Anchor()
  6699. // new Anchor() // TODO: Figure out how to handle this for `beginning` / `ending` animations
  6700. ], true, false, true);
  6701. /**
  6702. * @name Two.Rectangle#width
  6703. * @property {Number} - The size of the width of the rectangle.
  6704. */
  6705. this.width = width;
  6706. /**
  6707. * @name Two.Rectangle#height
  6708. * @property {Number} - The size of the height of the rectangle.
  6709. */
  6710. this.height = height;
  6711. /**
  6712. * @name Two.Rectangle#origin
  6713. * @property {Number} - A two-component vector describing the origin offset to draw the rectangle. Default is `0, 0`.
  6714. */
  6715. this.origin = new Vector();
  6716. this.translation.set(x, y);
  6717. this._update();
  6718. }
  6719. _.extend(Rectangle, {
  6720. /**
  6721. * @name Two.Rectangle.Properties
  6722. * @property {String[]} - A list of properties that are on every {@link Two.Rectangle}.
  6723. */
  6724. Properties: ['width', 'height'],
  6725. /**
  6726. * @name Two.Rectangle.MakeObservable
  6727. * @function
  6728. * @param {Object} object - The object to make observable.
  6729. * @description Convenience function to apply observable qualities of a {@link Two.Rectangle} to any object. Handy if you'd like to extend the {@link Two.Rectangle} class on a custom class.
  6730. */
  6731. MakeObservable: function(object) {
  6732. Path.MakeObservable(object);
  6733. _.each(Rectangle.Properties, defineGetterSetter, object);
  6734. Object.defineProperty(object, 'origin', {
  6735. enumerable: true,
  6736. get: function() {
  6737. return this._origin;
  6738. },
  6739. set: function(v) {
  6740. if (this._origin) {
  6741. this._origin.unbind(Events.Types.change, this._renderer.flagVertices);
  6742. }
  6743. this._origin = v;
  6744. this._origin.bind(Events.Types.change, this._renderer.flagVertices);
  6745. this._renderer.flagVertices();
  6746. }
  6747. });
  6748. }
  6749. });
  6750. _.extend(Rectangle.prototype, Path.prototype, {
  6751. constructor: Rectangle,
  6752. /**
  6753. * @name Two.Rectangle#_flagWidth
  6754. * @private
  6755. * @property {Boolean} - Determines whether the {@link Two.Rectangle#width} needs updating.
  6756. */
  6757. _flagWidth: 0,
  6758. /**
  6759. * @name Two.Rectangle#_flagHeight
  6760. * @private
  6761. * @property {Boolean} - Determines whether the {@link Two.Rectangle#height} needs updating.
  6762. */
  6763. _flagHeight: 0,
  6764. /**
  6765. * @name Two.Rectangle#_width
  6766. * @private
  6767. * @see {@link Two.Rectangle#width}
  6768. */
  6769. _width: 0,
  6770. /**
  6771. * @name Two.Rectangle#_height
  6772. * @private
  6773. * @see {@link Two.Rectangle#height}
  6774. */
  6775. _height: 0,
  6776. _origin: null,
  6777. /**
  6778. * @name Two.Rectangle#_update
  6779. * @function
  6780. * @private
  6781. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  6782. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  6783. * @nota-bene Try not to call this method more than once a frame.
  6784. */
  6785. _update: function() {
  6786. if (this._flagVertices || this._flagWidth || this._flagHeight) {
  6787. var xr = this._width / 2;
  6788. var yr = this._height / 2;
  6789. if (!this._closed && this.vertices.length === 4) {
  6790. this.vertices.push(new Anchor());
  6791. }
  6792. this.vertices[0].set(-xr, -yr).add(this._origin).command = Commands.move;
  6793. this.vertices[1].set(xr, -yr).add(this._origin).command = Commands.line;
  6794. this.vertices[2].set(xr, yr).add(this._origin).command = Commands.line;
  6795. this.vertices[3].set(-xr, yr).add(this._origin).command = Commands.line;
  6796. // FYI: Two.Sprite and Two.ImageSequence have 4 verts
  6797. if (this.vertices[4]) {
  6798. this.vertices[4].set(-xr, -yr).add(this._origin).command = Commands.line;
  6799. }
  6800. }
  6801. Path.prototype._update.call(this);
  6802. return this;
  6803. },
  6804. /**
  6805. * @name Two.Rectangle#flagReset
  6806. * @function
  6807. * @private
  6808. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  6809. */
  6810. flagReset: function() {
  6811. this._flagWidth = this._flagHeight = false;
  6812. Path.prototype.flagReset.call(this);
  6813. return this;
  6814. },
  6815. /**
  6816. * @name Two.Rectangle#clone
  6817. * @function
  6818. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  6819. * @returns {Two.Rectangle}
  6820. * @description Create a new instance of {@link Two.Rectangle} with the same properties of the current path.
  6821. */
  6822. clone: function(parent) {
  6823. var clone = new Rectangle(0, 0, this.width, this.height);
  6824. clone.translation.copy(this.translation);
  6825. clone.rotation = this.rotation;
  6826. clone.scale = this.scale;
  6827. clone.skewX = this.skewX;
  6828. clone.skewY = this.skewY;
  6829. if (this.matrix.manual) {
  6830. clone.matrix.copy(this.matrix);
  6831. }
  6832. _.each(Path.Properties, function(k) {
  6833. clone[k] = this[k];
  6834. }, this);
  6835. if (parent) {
  6836. parent.add(clone);
  6837. }
  6838. return clone;
  6839. },
  6840. /**
  6841. * @name Two.Rectangle#toObject
  6842. * @function
  6843. * @returns {Object}
  6844. * @description Return a JSON compatible plain object that represents the path.
  6845. */
  6846. toObject: function() {
  6847. var object = Path.prototype.toObject.call(this);
  6848. object.width = this.width;
  6849. object.height = this.height;
  6850. object.origin = this.origin.toObject();
  6851. return object;
  6852. }
  6853. });
  6854. Rectangle.MakeObservable(Rectangle.prototype);
  6855. /**
  6856. * @name Two.Sprite
  6857. * @class
  6858. * @extends Two.Rectangle
  6859. * @param {String|Two.Texture} [path] - The URL path or {@link Two.Texture} to be used as the bitmap data displayed on the sprite.
  6860. * @param {Number} [ox=0] - The initial `x` position of the Two.Sprite.
  6861. * @param {Number} [oy=0] - The initial `y` position of the Two.Sprite.
  6862. * @param {Number} [cols=1] - The number of columns the sprite contains.
  6863. * @param {Number} [rows=1] - The number of rows the sprite contains.
  6864. * @param {Number} [frameRate=0] - The frame rate at which the partitions of the image should playback at.
  6865. * @description A convenient package to display still or animated images through a tiled image source. For more information on the principals of animated imagery through tiling see [Texture Atlas](https://en.wikipedia.org/wiki/Texture_atlas) on Wikipedia.
  6866. */
  6867. function Sprite(path, ox, oy, cols, rows, frameRate) {
  6868. // Not using default constructor of Rectangle due to odd `beginning` / `ending` behavior.
  6869. // See: https://github.com/jonobr1/two.js/issues/383
  6870. Path.call(this, [
  6871. new Anchor(),
  6872. new Anchor(),
  6873. new Anchor(),
  6874. new Anchor()
  6875. ], true);
  6876. this.noStroke();
  6877. this.noFill();
  6878. /**
  6879. * @name Two.Sprite#texture
  6880. * @property {Two.Texture} - The texture to be used as bitmap data to display image in the scene.
  6881. */
  6882. if (path instanceof Texture) {
  6883. this.texture = path;
  6884. } else if (typeof path === 'string') {
  6885. this.texture = new Texture(path);
  6886. }
  6887. this.origin = new Vector();
  6888. this._update();
  6889. this.translation.set(ox || 0, oy || 0);
  6890. /**
  6891. * @name Two.Sprite#columns
  6892. * @property {Number} - The number of columns to split the texture into. Defaults to `1`.
  6893. */
  6894. if (typeof cols === 'number') {
  6895. this.columns = cols;
  6896. }
  6897. /**
  6898. * @name Two.Sprite#rows
  6899. * @property {Number} - The number of rows to split the texture into. Defaults to `1`.
  6900. */
  6901. if (typeof rows === 'number') {
  6902. this.rows = rows;
  6903. }
  6904. /**
  6905. * @name Two.Sprite#frameRate
  6906. * @property {Number} - The number of frames to animate against per second. Defaults to `0` for non-animated sprites.
  6907. */
  6908. if (typeof frameRate === 'number') {
  6909. this.frameRate = frameRate;
  6910. }
  6911. /**
  6912. * @name Two.Sprite#index
  6913. * @property {Number} - The index of the current tile of the sprite to display. Defaults to `0`.
  6914. */
  6915. this.index = 0;
  6916. }
  6917. _.extend(Sprite, {
  6918. /**
  6919. * @name Two.Sprite.Properties
  6920. * @property {String[]} - A list of properties that are on every {@link Two.Sprite}.
  6921. */
  6922. Properties: [
  6923. 'texture', 'columns', 'rows', 'frameRate', 'index'
  6924. ],
  6925. /**
  6926. * @name Two.Sprite.MakeObservable
  6927. * @function
  6928. * @param {Object} object - The object to make observable.
  6929. * @description Convenience function to apply observable qualities of a {@link Two.Sprite} to any object. Handy if you'd like to extend or inherit the {@link Two.Sprite} class on a custom class.
  6930. */
  6931. MakeObservable: function(obj) {
  6932. Rectangle.MakeObservable(obj);
  6933. _.each(Sprite.Properties, defineGetterSetter, obj);
  6934. }
  6935. });
  6936. _.extend(Sprite.prototype, Rectangle.prototype, {
  6937. constructor: Sprite,
  6938. /**
  6939. * @name Two.Sprite#_flagTexture
  6940. * @private
  6941. * @property {Boolean} - Determines whether the {@link Two.Sprite#texture} needs updating.
  6942. */
  6943. _flagTexture: false,
  6944. /**
  6945. * @name Two.Sprite#_flagColumns
  6946. * @private
  6947. * @property {Boolean} - Determines whether the {@link Two.Sprite#columns} need updating.
  6948. */
  6949. _flagColumns: false,
  6950. /**
  6951. * @name Two.Sprite#_flagRows
  6952. * @private
  6953. * @property {Boolean} - Determines whether the {@link Two.Sprite#rows} need updating.
  6954. */
  6955. _flagRows: false,
  6956. /**
  6957. * @name Two.Sprite#_flagFrameRate
  6958. * @private
  6959. * @property {Boolean} - Determines whether the {@link Two.Sprite#flagFrameRate} needs updating.
  6960. */
  6961. _flagFrameRate: false,
  6962. /**
  6963. * @name Two.Sprite#_flagIndex
  6964. * @private
  6965. * @property {Boolean} - Determines whether the {@link Two.Sprite#index} needs updating.
  6966. */
  6967. flagIndex: false,
  6968. // Private variables
  6969. /**
  6970. * @name Two.Sprite#_amount
  6971. * @private
  6972. * @property {Number} - Number of frames for a given {@link Two.Sprite}.
  6973. */
  6974. _amount: 1,
  6975. /**
  6976. * @name Two.Sprite#_duration
  6977. * @private
  6978. * @property {Number} - Number of milliseconds a {@link Two.Sprite}.
  6979. */
  6980. _duration: 0,
  6981. /**
  6982. * @name Two.Sprite#_startTime
  6983. * @private
  6984. * @property {Milliseconds} - Epoch time in milliseconds of when the {@link Two.Sprite} started.
  6985. */
  6986. _startTime: 0,
  6987. /**
  6988. * @name Two.Sprite#_playing
  6989. * @private
  6990. * @property {Boolean} - Dictates whether the {@link Two.Sprite} is animating or not.
  6991. */
  6992. _playing: false,
  6993. /**
  6994. * @name Two.Sprite#_firstFrame
  6995. * @private
  6996. * @property {Number} - The frame the {@link Two.Sprite} should start with.
  6997. */
  6998. _firstFrame: 0,
  6999. /**
  7000. * @name Two.Sprite#_lastFrame
  7001. * @private
  7002. * @property {Number} - The frame the {@link Two.Sprite} should end with.
  7003. */
  7004. _lastFrame: 0,
  7005. /**
  7006. * @name Two.Sprite#_playing
  7007. * @private
  7008. * @property {Boolean} - Dictates whether the {@link Two.Sprite} should loop or not.
  7009. */
  7010. _loop: true,
  7011. // Exposed through getter-setter
  7012. /**
  7013. * @name Two.Sprite#_texture
  7014. * @private
  7015. * @see {@link Two.Sprite#texture}
  7016. */
  7017. _texture: null,
  7018. /**
  7019. * @name Two.Sprite#_columns
  7020. * @private
  7021. * @see {@link Two.Sprite#columns}
  7022. */
  7023. _columns: 1,
  7024. /**
  7025. * @name Two.Sprite#_rows
  7026. * @private
  7027. * @see {@link Two.Sprite#rows}
  7028. */
  7029. _rows: 1,
  7030. /**
  7031. * @name Two.Sprite#_frameRate
  7032. * @private
  7033. * @see {@link Two.Sprite#frameRate}
  7034. */
  7035. _frameRate: 0,
  7036. /**
  7037. * @name Two.Sprite#_index
  7038. * @private
  7039. * @property {Number} - The current frame the {@link Two.Sprite} is currently displaying.
  7040. */
  7041. _index: 0,
  7042. /**
  7043. * @name Two.Sprite#_origin
  7044. * @private
  7045. * @see {@link Two.Sprite#origin}
  7046. */
  7047. _origin: null,
  7048. /**
  7049. * @name Two.Sprite#play
  7050. * @function
  7051. * @param {Number} [firstFrame=0] - The index of the frame to start the animation with.
  7052. * @param {Number} [lastFrame] - The index of the frame to end the animation with. Defaults to the last item in the {@link Two.Sprite#textures}.
  7053. * @param {Function} [onLastFrame] - Optional callback function to be triggered after playing the last frame. This fires multiple times when the sprite is looped.
  7054. * @description Initiate animation playback of a {@link Two.Sprite}.
  7055. */
  7056. play: function(firstFrame, lastFrame, onLastFrame) {
  7057. this._playing = true;
  7058. this._firstFrame = 0;
  7059. this._lastFrame = this.amount - 1;
  7060. this._startTime = _.performance.now();
  7061. if (typeof firstFrame === 'number') {
  7062. this._firstFrame = firstFrame;
  7063. }
  7064. if (typeof lastFrame === 'number') {
  7065. this._lastFrame = lastFrame;
  7066. }
  7067. if (typeof onLastFrame === 'function') {
  7068. this._onLastFrame = onLastFrame;
  7069. } else {
  7070. delete this._onLastFrame;
  7071. }
  7072. if (this._index !== this._firstFrame) {
  7073. this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  7074. / this._frameRate;
  7075. }
  7076. return this;
  7077. },
  7078. /**
  7079. * @name Two.Sprite#pause
  7080. * @function
  7081. * @description Halt animation playback of a {@link Two.Sprite}.
  7082. */
  7083. pause: function() {
  7084. this._playing = false;
  7085. return this;
  7086. },
  7087. /**
  7088. * @name Two.Sprite#stop
  7089. * @function
  7090. * @description Halt animation playback of a {@link Two.Sprite} and set the current frame back to the first frame.
  7091. */
  7092. stop: function() {
  7093. this._playing = false;
  7094. this._index = 0;
  7095. return this;
  7096. },
  7097. /**
  7098. * @name Two.Sprite#clone
  7099. * @function
  7100. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7101. * @returns {Two.Sprite}
  7102. * @description Create a new instance of {@link Two.Sprite} with the same properties of the current sprite.
  7103. */
  7104. clone: function(parent) {
  7105. var clone = new Sprite(
  7106. this.texture, this.translation.x, this.translation.y,
  7107. this.columns, this.rows, this.frameRate
  7108. );
  7109. if (this.playing) {
  7110. clone.play(this._firstFrame, this._lastFrame);
  7111. clone._loop = this._loop;
  7112. }
  7113. if (parent) {
  7114. parent.add(clone);
  7115. }
  7116. return clone;
  7117. },
  7118. /**
  7119. * @name Two.Sprite#toObject
  7120. * @function
  7121. * @returns {Object}
  7122. * @description Return a JSON compatible plain object that represents the path.
  7123. */
  7124. toObject: function() {
  7125. var object = Rectangle.prototype.toObject.call(this);
  7126. object.texture = this.texture.toObject();
  7127. object.columns = this.columns;
  7128. object.rows = this.rows;
  7129. object.frameRate = this.frameRate;
  7130. object.index = this.index;
  7131. object._firstFrame = this._firstFrame;
  7132. object._lastFrame = this._lastFrame;
  7133. object._loop = this._loop;
  7134. return object;
  7135. },
  7136. /**
  7137. * @name Two.Sprite#_update
  7138. * @function
  7139. * @private
  7140. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7141. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  7142. * @nota-bene Try not to call this method more than once a frame.
  7143. */
  7144. _update: function() {
  7145. var effect = this._texture;
  7146. var cols = this._columns;
  7147. var rows = this._rows;
  7148. var width, height, elapsed, amount, duration;
  7149. var index, iw, ih, frames;
  7150. if (this._flagColumns || this._flagRows) {
  7151. this._amount = this._columns * this._rows;
  7152. }
  7153. if (this._flagFrameRate) {
  7154. this._duration = 1000 * this._amount / this._frameRate;
  7155. }
  7156. if (this._flagTexture) {
  7157. this.fill = this._texture;
  7158. }
  7159. if (this._texture.loaded) {
  7160. iw = effect.image.width;
  7161. ih = effect.image.height;
  7162. width = iw / cols;
  7163. height = ih / rows;
  7164. amount = this._amount;
  7165. if (this.width !== width) {
  7166. this.width = width;
  7167. }
  7168. if (this.height !== height) {
  7169. this.height = height;
  7170. }
  7171. if (this._playing && this._frameRate > 0) {
  7172. if (_.isNaN(this._lastFrame)) {
  7173. this._lastFrame = amount - 1;
  7174. }
  7175. // TODO: Offload perf logic to instance of `Two`.
  7176. elapsed = _.performance.now() - this._startTime;
  7177. frames = this._lastFrame + 1;
  7178. duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  7179. if (this._loop) {
  7180. elapsed = elapsed % duration;
  7181. } else {
  7182. elapsed = Math.min(elapsed, duration);
  7183. }
  7184. index = lerp(this._firstFrame, frames, elapsed / duration);
  7185. index = Math.floor(index);
  7186. if (index !== this._index) {
  7187. this._index = index;
  7188. if (index >= this._lastFrame - 1 && this._onLastFrame) {
  7189. this._onLastFrame(); // Shortcut for chainable sprite animations
  7190. }
  7191. }
  7192. }
  7193. var col = this._index % cols;
  7194. var row = Math.floor(this._index / cols);
  7195. var ox = - width * col + (iw - width) / 2;
  7196. var oy = - height * row + (ih - height) / 2;
  7197. // TODO: Improve performance
  7198. if (ox !== effect.offset.x) {
  7199. effect.offset.x = ox;
  7200. }
  7201. if (oy !== effect.offset.y) {
  7202. effect.offset.y = oy;
  7203. }
  7204. }
  7205. Rectangle.prototype._update.call(this);
  7206. return this;
  7207. },
  7208. /**
  7209. * @name Two.Sprite#flagReset
  7210. * @function
  7211. * @private
  7212. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7213. */
  7214. flagReset: function() {
  7215. this._flagTexture = this._flagColumns = this._flagRows
  7216. = this._flagFrameRate = false;
  7217. Rectangle.prototype.flagReset.call(this);
  7218. return this;
  7219. }
  7220. });
  7221. Sprite.MakeObservable(Sprite.prototype);
  7222. var TWO_PI$4 = Math.PI * 2, HALF_PI$2 = Math.PI / 2;
  7223. var cos$3 = Math.cos, sin$3 = Math.sin;
  7224. /**
  7225. * @name Two.Circle
  7226. * @class
  7227. * @extends Two.Path
  7228. * @param {Number} [x=0] - The x position of the circle.
  7229. * @param {Number} [y=0] - The y position of the circle.
  7230. * @param {Number} [radius=0] - The radius value of the circle.
  7231. * @param {Number} [resolution=4] - The number of vertices used to construct the circle.
  7232. */
  7233. function Circle(ox, oy, r, resolution) {
  7234. // At least 2 vertices are required for proper circlage
  7235. var amount = resolution ? Math.max(resolution, 2) : 4;
  7236. var points = [];
  7237. for (var i = 0; i < amount; i++) {
  7238. points.push(new Anchor(0, 0, 0, 0, 0, 0));
  7239. }
  7240. Path.call(this, points, true, true, true);
  7241. /**
  7242. * @name Two.Circle#radius
  7243. * @property {Number} - The size of the radius of the circle.
  7244. */
  7245. if (typeof r === 'number') {
  7246. this.radius = r;
  7247. }
  7248. this._update();
  7249. if (typeof ox === 'number') {
  7250. this.translation.x = ox;
  7251. }
  7252. if (typeof oy === 'number') {
  7253. this.translation.y = oy;
  7254. }
  7255. }
  7256. _.extend(Circle, {
  7257. /**
  7258. * @name Two.Circle.Properties
  7259. * @property {String[]} - A list of properties that are on every {@link Two.Circle}.
  7260. */
  7261. Properties: ['radius'],
  7262. /**
  7263. * @name Two.Circle.MakeObservable
  7264. * @function
  7265. * @param {Object} object - The object to make observable.
  7266. * @description Convenience function to apply observable qualities of a {@link Two.Circle} to any object. Handy if you'd like to extend the {@link Two.Circle} class on a custom class.
  7267. */
  7268. MakeObservable: function(obj) {
  7269. Path.MakeObservable(obj);
  7270. _.each(Circle.Properties, defineGetterSetter, obj);
  7271. }
  7272. });
  7273. _.extend(Circle.prototype, Path.prototype, {
  7274. constructor: Circle,
  7275. /**
  7276. * @name Two.Circle#_flagRadius
  7277. * @private
  7278. * @property {Boolean} - Determines whether the {@link Two.Circle#radius} needs updating.
  7279. */
  7280. _flagRadius: false,
  7281. /**
  7282. * @name Two.Circle#_radius
  7283. * @private
  7284. * @see {@link Two.Circle#radius}
  7285. */
  7286. _radius: 0,
  7287. /**
  7288. * @name Two.Circle#_update
  7289. * @function
  7290. * @private
  7291. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7292. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  7293. * @nota-bene Try not to call this method more than once a frame.
  7294. */
  7295. _update: function() {
  7296. if (this._flagVertices || this._flagRadius) {
  7297. var length = this.vertices.length;
  7298. if (!this._closed && length > 2) {
  7299. length -= 1;
  7300. }
  7301. // Coefficient for approximating circular arcs with Bezier curves
  7302. var c = (4 / 3) * Math.tan(Math.PI / (length * 2));
  7303. var radius = this._radius;
  7304. var rc = radius * c;
  7305. for (var i = 0; i < this.vertices.length; i++) {
  7306. var pct = i / length;
  7307. var theta = pct * TWO_PI$4;
  7308. var x = radius * cos$3(theta);
  7309. var y = radius * sin$3(theta);
  7310. var lx = rc * cos$3(theta - HALF_PI$2);
  7311. var ly = rc * sin$3(theta - HALF_PI$2);
  7312. var rx = rc * cos$3(theta + HALF_PI$2);
  7313. var ry = rc * sin$3(theta + HALF_PI$2);
  7314. var v = this.vertices[i];
  7315. v.command = i === 0 ? Commands.move : Commands.curve;
  7316. v.set(x, y);
  7317. v.controls.left.set(lx, ly);
  7318. v.controls.right.set(rx, ry);
  7319. }
  7320. }
  7321. Path.prototype._update.call(this);
  7322. return this;
  7323. },
  7324. /**
  7325. * @name Two.Circle#flagReset
  7326. * @function
  7327. * @private
  7328. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7329. */
  7330. flagReset: function() {
  7331. this._flagRadius = false;
  7332. Path.prototype.flagReset.call(this);
  7333. return this;
  7334. },
  7335. /**
  7336. * @name Two.Circle#clone
  7337. * @function
  7338. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7339. * @returns {Two.Circle}
  7340. * @description Create a new instance of {@link Two.Circle} with the same properties of the current path.
  7341. */
  7342. clone: function(parent) {
  7343. var clone = new Circle(0, 0, this.radius, this.vertices.length);
  7344. clone.translation.copy(this.translation);
  7345. clone.rotation = this.rotation;
  7346. clone.scale = this.scale;
  7347. clone.skewX = this.skewX;
  7348. clone.skewY = this.skewY;
  7349. if (this.matrix.manual) {
  7350. clone.matrix.copy(this.matrix);
  7351. }
  7352. _.each(Path.Properties, function(k) {
  7353. clone[k] = this[k];
  7354. }, this);
  7355. if (parent) {
  7356. parent.add(clone);
  7357. }
  7358. return clone;
  7359. },
  7360. /**
  7361. * @name Two.Circle#toObject
  7362. * @function
  7363. * @returns {Object}
  7364. * @description Return a JSON compatible plain object that represents the path.
  7365. */
  7366. toObject: function() {
  7367. var object = Path.prototype.toObject.call(this);
  7368. _.each(Circle.Properties, function(property) {
  7369. object[property] = this[property];
  7370. }, this);
  7371. return object;
  7372. }
  7373. });
  7374. Circle.MakeObservable(Circle.prototype);
  7375. var TWO_PI$3 = Math.PI * 2, HALF_PI$1 = Math.PI / 2;
  7376. var cos$2 = Math.cos, sin$2 = Math.sin;
  7377. /**
  7378. * @name Two.Ellipse
  7379. * @class
  7380. * @extends Two.Path
  7381. * @param {Number} [x=0] - The x position of the ellipse.
  7382. * @param {Number} [y=0] - The y position of the ellipse.
  7383. * @param {Number} [rx=0] - The radius value of the ellipse in the x direction.
  7384. * @param {Number} [ry=0] - The radius value of the ellipse in the y direction.
  7385. * @param {Number} [resolution=4] - The number of vertices used to construct the ellipse.
  7386. */
  7387. function Ellipse(ox, oy, rx, ry, resolution) {
  7388. if (typeof ry !== 'number' && typeof rx === 'number') {
  7389. ry = rx;
  7390. }
  7391. // At least 2 vertices are required for proper circlage
  7392. var amount = resolution ? Math.max(resolution, 2) : 4;
  7393. var points = [];
  7394. for (var i = 0; i < amount; i++) {
  7395. points.push(new Anchor());
  7396. }
  7397. Path.call(this, points, true, true, true);
  7398. /**
  7399. * @name Two.Ellipse#width
  7400. * @property {Number} - The width of the ellipse.
  7401. */
  7402. if (typeof rx === 'number') {
  7403. this.width = rx * 2;
  7404. }
  7405. /**
  7406. * @name Two.Ellipse#height
  7407. * @property {Number} - The height of the ellipse.
  7408. */
  7409. if (typeof ry === 'number') {
  7410. this.height = ry * 2;
  7411. }
  7412. this._update();
  7413. this.translation.set(ox, oy);
  7414. }
  7415. _.extend(Ellipse, {
  7416. /**
  7417. * @name Two.Ellipse.Properties
  7418. * @property {String[]} - A list of properties that are on every {@link Two.Ellipse}.
  7419. */
  7420. Properties: ['width', 'height'],
  7421. /**
  7422. * @name Two.Ellipse.MakeObservable
  7423. * @function
  7424. * @param {Object} object - The object to make observable.
  7425. * @description Convenience function to apply observable qualities of a {@link Two.Ellipse} to any object. Handy if you'd like to extend the {@link Two.Ellipse} class on a custom class.
  7426. */
  7427. MakeObservable: function(obj) {
  7428. Path.MakeObservable(obj);
  7429. _.each(Ellipse.Properties, defineGetterSetter, obj);
  7430. }
  7431. });
  7432. _.extend(Ellipse.prototype, Path.prototype, {
  7433. /**
  7434. * @name Two.Ellipse#_flagWidth
  7435. * @private
  7436. * @property {Boolean} - Determines whether the {@link Two.Ellipse#width} needs updating.
  7437. */
  7438. _flagWidth: false,
  7439. /**
  7440. * @name Two.Ellipse#_flagHeight
  7441. * @private
  7442. * @property {Boolean} - Determines whether the {@link Two.Ellipse#height} needs updating.
  7443. */
  7444. _flagHeight: false,
  7445. /**
  7446. * @name Two.Polygon#_width
  7447. * @private
  7448. * @see {@link Two.Ellipse#width}
  7449. */
  7450. _width: 0,
  7451. /**
  7452. * @name Two.Polygon#_height
  7453. * @private
  7454. * @see {@link Two.Ellipse#height}
  7455. */
  7456. _height: 0,
  7457. constructor: Ellipse,
  7458. /**
  7459. * @name Two.Ellipse#_update
  7460. * @function
  7461. * @private
  7462. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7463. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  7464. * @nota-bene Try not to call this method more than once a frame.
  7465. */
  7466. _update: function() {
  7467. if (this._flagVertices || this._flagWidth || this._flagHeight) {
  7468. var length = this.vertices.length;
  7469. if (!this._closed && length > 2) {
  7470. length -= 1;
  7471. }
  7472. // Coefficient for approximating circular arcs with Bezier curves
  7473. var c = (4 / 3) * Math.tan(Math.PI / (this.vertices.length * 2));
  7474. var radiusX = this._width / 2;
  7475. var radiusY = this._height / 2;
  7476. for (var i = 0; i < this.vertices.length; i++) {
  7477. var pct = i / length;
  7478. var theta = pct * TWO_PI$3;
  7479. var x = radiusX * cos$2(theta);
  7480. var y = radiusY * sin$2(theta);
  7481. var lx = radiusX * c * cos$2(theta - HALF_PI$1);
  7482. var ly = radiusY * c * sin$2(theta - HALF_PI$1);
  7483. var rx = radiusX * c * cos$2(theta + HALF_PI$1);
  7484. var ry = radiusY * c * sin$2(theta + HALF_PI$1);
  7485. var v = this.vertices[i];
  7486. v.command = i === 0 ? Commands.move : Commands.curve;
  7487. v.set(x, y);
  7488. v.controls.left.set(lx, ly);
  7489. v.controls.right.set(rx, ry);
  7490. }
  7491. }
  7492. Path.prototype._update.call(this);
  7493. return this;
  7494. },
  7495. /**
  7496. * @name Two.Ellipse#flagReset
  7497. * @function
  7498. * @private
  7499. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7500. */
  7501. flagReset: function() {
  7502. this._flagWidth = this._flagHeight = false;
  7503. Path.prototype.flagReset.call(this);
  7504. return this;
  7505. },
  7506. /**
  7507. * @name Two.Ellipse#clone
  7508. * @function
  7509. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7510. * @returns {Two.Polygon}
  7511. * @description Create a new instance of {@link Two.Polygon} with the same properties of the current path.
  7512. */
  7513. clone: function(parent) {
  7514. var rx = this.width / 2;
  7515. var ry = this.height / 2;
  7516. var resolution = this.vertices.length;
  7517. var clone = new Ellipse(0, 0, rx, ry, resolution);
  7518. clone.translation.copy(this.translation);
  7519. clone.rotation = this.rotation;
  7520. clone.scale = this.scale;
  7521. clone.skewX = this.skewX;
  7522. clone.skewY = this.skewY;
  7523. if (this.matrix.manual) {
  7524. clone.matrix.copy(this.matrix);
  7525. }
  7526. _.each(Path.Properties, function(k) {
  7527. clone[k] = this[k];
  7528. }, this);
  7529. if (parent) {
  7530. parent.add(clone);
  7531. }
  7532. return clone;
  7533. },
  7534. /**
  7535. * @name Two.Ellipse#toObject
  7536. * @function
  7537. * @returns {Object}
  7538. * @description Return a JSON compatible plain object that represents the path.
  7539. */
  7540. toObject: function() {
  7541. var object = Path.prototype.toObject.call(this);
  7542. _.each(Ellipse.Properties, function(property) {
  7543. object[property] = this[property];
  7544. }, this);
  7545. return object;
  7546. }
  7547. });
  7548. Ellipse.MakeObservable(Ellipse.prototype);
  7549. /**
  7550. * @name Two.Line
  7551. * @class
  7552. * @extends Two.Path
  7553. * @param {Number} [x1=0] - The x position of the first vertex on the line.
  7554. * @param {Number} [y1=0] - The y position of the first vertex on the line.
  7555. * @param {Number} [x2=0] - The x position of the second vertex on the line.
  7556. * @param {Number} [y2=0] - The y position of the second vertex on the line.
  7557. */
  7558. function Line(x1, y1, x2, y2) {
  7559. Path.call(this, [
  7560. new Anchor(x1, y1),
  7561. new Anchor(x2, y2)
  7562. ]);
  7563. this.vertices[0].command = Commands.move;
  7564. this.vertices[1].command = Commands.line;
  7565. this.automatic = false;
  7566. }
  7567. _.extend(Line.prototype, Path.prototype, {
  7568. constructor: Line
  7569. });
  7570. Path.MakeObservable(Line.prototype);
  7571. /**
  7572. * @name Two.RoundedRectangle
  7573. * @class
  7574. * @extends Two.Path
  7575. * @param {Number} [x=0] - The x position of the rounded rectangle.
  7576. * @param {Number} [y=0] - The y position of the rounded rectangle.
  7577. * @param {Number} [width=0] - The width value of the rounded rectangle.
  7578. * @param {Number} [height=0] - The width value of the rounded rectangle.
  7579. * @param {Number} [radius=0] - The radius value of the rounded rectangle.
  7580. * @param {Number} [resolution=12] - The number of vertices used to construct the rounded rectangle.
  7581. */
  7582. function RoundedRectangle(ox, oy, width, height, radius) {
  7583. if (typeof radius === 'undefined' &&
  7584. typeof width === 'number' && typeof height === 'number') {
  7585. radius = Math.floor(Math.min(width, height) / 12);
  7586. }
  7587. var amount = 10;
  7588. var points = [];
  7589. for (var i = 0; i < amount; i++) {
  7590. points.push(
  7591. new Anchor(0, 0, 0, 0, 0, 0,
  7592. i === 0 ? Commands.move : Commands.curve)
  7593. );
  7594. }
  7595. // points[points.length - 1].command = Two.Commands.close;
  7596. Path.call(this, points);
  7597. this.closed = true;
  7598. this.automatic = false;
  7599. this._renderer.flagRadius = RoundedRectangle.FlagRadius.bind(this);
  7600. /**
  7601. * @name Two.RoundedRectangle#width
  7602. * @property {Number} - The width of the rounded rectangle.
  7603. */
  7604. if (typeof width === 'number') {
  7605. this.width = width;
  7606. }
  7607. /**
  7608. * @name Two.RoundedRectangle#height
  7609. * @property {Number} - The height of the rounded rectangle.
  7610. */
  7611. if (typeof height === 'number') {
  7612. this.height = height;
  7613. }
  7614. /**
  7615. * @name Two.RoundedRectangle#radius
  7616. * @property {Number} - The size of the radius of the rounded rectangle.
  7617. */
  7618. if (typeof radius === 'number') {
  7619. this.radius = radius;
  7620. }
  7621. this._update();
  7622. this.translation.set(ox, oy);
  7623. }
  7624. _.extend(RoundedRectangle, {
  7625. /**
  7626. * @name Two.RoundedRectangle.Properties
  7627. * @property {String[]} - A list of properties that are on every {@link Two.RoundedRectangle}.
  7628. */
  7629. Properties: ['width', 'height'],
  7630. /**
  7631. * @name Two.RoundedRectangle.FlagRadius
  7632. * @property {Function} - A convenience function to trigger the flag for radius changing.
  7633. */
  7634. FlagRadius: function() {
  7635. this._flagRadius = true;
  7636. },
  7637. /**
  7638. * @name Two.RoundedRectangle.MakeObservable
  7639. * @function
  7640. * @param {Object} object - The object to make observable.
  7641. * @description Convenience function to apply observable qualities of a {@link Two.RoundedRectangle} to any object. Handy if you'd like to extend the {@link Two.RoundedRectangle} class on a custom class.
  7642. */
  7643. MakeObservable: function(object) {
  7644. Path.MakeObservable(object);
  7645. _.each(RoundedRectangle.Properties, defineGetterSetter, object);
  7646. Object.defineProperty(object, 'radius', {
  7647. enumerable: true,
  7648. get: function() {
  7649. return this._radius;
  7650. },
  7651. set: function(v) {
  7652. if (this._radius instanceof Vector) {
  7653. this._radius.unbind(Events.Types.change, this._renderer.flagRadius);
  7654. }
  7655. this._radius = v;
  7656. if (this._radius instanceof Vector) {
  7657. this._radius.bind(Events.Types.change, this._renderer.flagRadius);
  7658. }
  7659. this._flagRadius = true;
  7660. }
  7661. });
  7662. }
  7663. });
  7664. _.extend(RoundedRectangle.prototype, Path.prototype, {
  7665. constructor: RoundedRectangle,
  7666. /**
  7667. * @name Two.RoundedRectangle#_flagWidth
  7668. * @private
  7669. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#width} needs updating.
  7670. */
  7671. _flagWidth: false,
  7672. /**
  7673. * @name Two.RoundedRectangle#_flagHeight
  7674. * @private
  7675. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#height} needs updating.
  7676. */
  7677. _flagHeight: false,
  7678. /**
  7679. * @name Two.RoundedRectangle#_flagRadius
  7680. * @private
  7681. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#radius} needs updating.
  7682. */
  7683. _flagRadius: false,
  7684. /**
  7685. * @name Two.RoundedRectangle#_width
  7686. * @private
  7687. * @see {@link Two.RoundedRectangle#width}
  7688. */
  7689. _width: 0,
  7690. /**
  7691. * @name Two.RoundedRectangle#_height
  7692. * @private
  7693. * @see {@link Two.RoundedRectangle#height}
  7694. */
  7695. _height: 0,
  7696. /**
  7697. * @name Two.RoundedRectangle#_radius
  7698. * @private
  7699. * @see {@link Two.RoundedRectangle#radius}
  7700. */
  7701. _radius: 12,
  7702. /**
  7703. * @name Two.RoundedRectangle#_update
  7704. * @function
  7705. * @private
  7706. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7707. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  7708. * @nota-bene Try not to call this method more than once a frame.
  7709. */
  7710. _update: function() {
  7711. if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagRadius) {
  7712. var width = this._width;
  7713. var height = this._height;
  7714. var rx, ry;
  7715. if (this._radius instanceof Vector) {
  7716. rx = this._radius.x;
  7717. ry = this._radius.y;
  7718. } else {
  7719. rx = this._radius;
  7720. ry = this._radius;
  7721. }
  7722. var v;
  7723. var w = width / 2;
  7724. var h = height / 2;
  7725. v = this.vertices[0];
  7726. v.x = - (w - rx);
  7727. v.y = - h;
  7728. // Upper Right Corner
  7729. v = this.vertices[1];
  7730. v.x = (w - rx);
  7731. v.y = - h;
  7732. v.controls.left.clear();
  7733. v.controls.right.x = rx;
  7734. v.controls.right.y = 0;
  7735. v = this.vertices[2];
  7736. v.x = w;
  7737. v.y = - (h - ry);
  7738. v.controls.right.clear();
  7739. v.controls.left.clear();
  7740. // Bottom Right Corner
  7741. v = this.vertices[3];
  7742. v.x = w;
  7743. v.y = (h - ry);
  7744. v.controls.left.clear();
  7745. v.controls.right.x = 0;
  7746. v.controls.right.y = ry;
  7747. v = this.vertices[4];
  7748. v.x = (w - rx);
  7749. v.y = h;
  7750. v.controls.right.clear();
  7751. v.controls.left.clear();
  7752. // Bottom Left Corner
  7753. v = this.vertices[5];
  7754. v.x = - (w - rx);
  7755. v.y = h;
  7756. v.controls.left.clear();
  7757. v.controls.right.x = - rx;
  7758. v.controls.right.y = 0;
  7759. v = this.vertices[6];
  7760. v.x = - w;
  7761. v.y = (h - ry);
  7762. v.controls.left.clear();
  7763. v.controls.right.clear();
  7764. // Upper Left Corner
  7765. v = this.vertices[7];
  7766. v.x = - w;
  7767. v.y = - (h - ry);
  7768. v.controls.left.clear();
  7769. v.controls.right.x = 0;
  7770. v.controls.right.y = - ry;
  7771. v = this.vertices[8];
  7772. v.x = - (w - rx);
  7773. v.y = - h;
  7774. v.controls.left.clear();
  7775. v.controls.right.clear();
  7776. v = this.vertices[9];
  7777. v.copy(this.vertices[8]);
  7778. }
  7779. Path.prototype._update.call(this);
  7780. return this;
  7781. },
  7782. /**
  7783. * @name Two.RoundedRectangle#flagReset
  7784. * @function
  7785. * @private
  7786. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7787. */
  7788. flagReset: function() {
  7789. this._flagWidth = this._flagHeight = this._flagRadius = false;
  7790. Path.prototype.flagReset.call(this);
  7791. return this;
  7792. },
  7793. /**
  7794. * @name Two.RoundedRectangle#clone
  7795. * @function
  7796. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7797. * @returns {Two.RoundedRectangle}
  7798. * @description Create a new instance of {@link Two.RoundedRectangle} with the same properties of the current path.
  7799. */
  7800. clone: function(parent) {
  7801. var width = this.width;
  7802. var height = this.height;
  7803. var radius = this.radius;
  7804. var clone = new RoundedRectangle(0, 0, width, height, radius);
  7805. clone.translation.copy(this.translation);
  7806. clone.rotation = this.rotation;
  7807. clone.scale = this.scale;
  7808. clone.skewX = this.skewX;
  7809. clone.skewY = this.skewY;
  7810. if (this.matrix.manual) {
  7811. clone.matrix.copy(this.matrix);
  7812. }
  7813. _.each(Path.Properties, function(k) {
  7814. clone[k] = this[k];
  7815. }, this);
  7816. if (parent) {
  7817. parent.add(clone);
  7818. }
  7819. return clone;
  7820. },
  7821. /**
  7822. * @name Two.RoundedRectangle#toObject
  7823. * @function
  7824. * @returns {Object}
  7825. * @description Return a JSON compatible plain object that represents the path.
  7826. */
  7827. toObject: function() {
  7828. var object = Path.prototype.toObject.call(this);
  7829. _.each(RoundedRectangle.Properties, function(property) {
  7830. object[property] = this[property];
  7831. }, this);
  7832. object.radius = typeof this.radius === 'number'
  7833. ? this.radius : this.radius.toObject();
  7834. return object;
  7835. }
  7836. });
  7837. RoundedRectangle.MakeObservable(RoundedRectangle.prototype);
  7838. var min = Math.min, max = Math.max;
  7839. /**
  7840. * @name Two.Text
  7841. * @class
  7842. * @extends Two.Shape
  7843. * @param {String} [message] - The String to be rendered to the scene.
  7844. * @param {Number} [x=0] - The position in the x direction for the object.
  7845. * @param {Number} [y=0] - The position in the y direction for the object.
  7846. * @param {Object} [styles] - An object where styles are applied. Attribute must exist in Two.Text.Properties.
  7847. * @description This is a primitive class for creating drawable text that can be added to the scenegraph.
  7848. * @returns {Two.Text}
  7849. */
  7850. function Text(message, x, y, styles) {
  7851. Shape.call(this);
  7852. this._renderer.type = 'text';
  7853. this._renderer.flagFill = Text.FlagFill.bind(this);
  7854. this._renderer.flagStroke = Text.FlagStroke.bind(this);
  7855. this.value = message;
  7856. if (typeof x === 'number') {
  7857. this.translation.x = x;
  7858. }
  7859. if (typeof y === 'number') {
  7860. this.translation.y = y;
  7861. }
  7862. /**
  7863. * @name Two.Text#dashes
  7864. * @property {Number[]} - Array of numbers. Odd indices represent dash length. Even indices represent dash space.
  7865. * @description A list of numbers that represent the repeated dash length and dash space applied to the stroke of the text.
  7866. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray} for more information on the SVG stroke-dasharray attribute.
  7867. */
  7868. this.dashes = [];
  7869. /**
  7870. * @name Two.Text#dashes#offset
  7871. * @property {Number} - A number in pixels to offset {@link Two.Text#dashes} display.
  7872. */
  7873. this.dashes.offset = 0;
  7874. if (!_.isObject(styles)) {
  7875. return this;
  7876. }
  7877. _.each(Text.Properties, function(property) {
  7878. if (property in styles) {
  7879. this[property] = styles[property];
  7880. }
  7881. }, this);
  7882. }
  7883. _.extend(Text, {
  7884. /**
  7885. * @name Two.Text.Ratio
  7886. * @property {Number} - Approximate aspect ratio of a typeface's character width to height.
  7887. */
  7888. Ratio: 0.6,
  7889. /**
  7890. * @name Two.Text.Properties
  7891. * @property {String[]} - A list of properties that are on every {@link Two.Text}.
  7892. */
  7893. Properties: [
  7894. 'value', 'family', 'size', 'leading', 'alignment', 'linewidth', 'style',
  7895. 'weight', 'decoration', 'baseline', 'opacity', 'visible', 'className',
  7896. 'fill', 'stroke',
  7897. ],
  7898. /**
  7899. * @name Two.Text.FlagFill
  7900. * @function
  7901. * @description Cached method to let renderers know the fill property have been updated on a {@link Two.Text}.
  7902. */
  7903. FlagFill: function() {
  7904. this._flagFill = true;
  7905. },
  7906. /**
  7907. * @name Two.Text.FlagStroke
  7908. * @function
  7909. * @description Cached method to let renderers know the stroke property have been updated on a {@link Two.Text}.
  7910. */
  7911. FlagStroke: function() {
  7912. this._flagStroke = true;
  7913. },
  7914. MakeObservable: function(object) {
  7915. Shape.MakeObservable(object);
  7916. _.each(Text.Properties.slice(0, 12), defineGetterSetter, object);
  7917. Object.defineProperty(object, 'fill', {
  7918. enumerable: true,
  7919. get: function() {
  7920. return this._fill;
  7921. },
  7922. set: function(f) {
  7923. if (this._fill instanceof Gradient
  7924. || this._fill instanceof LinearGradient
  7925. || this._fill instanceof RadialGradient
  7926. || this._fill instanceof Texture) {
  7927. this._fill.unbind(Events.Types.change, this._renderer.flagFill);
  7928. }
  7929. this._fill = f;
  7930. this._flagFill = true;
  7931. if (this._fill instanceof Gradient
  7932. || this._fill instanceof LinearGradient
  7933. || this._fill instanceof RadialGradient
  7934. || this._fill instanceof Texture) {
  7935. this._fill.bind(Events.Types.change, this._renderer.flagFill);
  7936. }
  7937. }
  7938. });
  7939. Object.defineProperty(object, 'stroke', {
  7940. enumerable: true,
  7941. get: function() {
  7942. return this._stroke;
  7943. },
  7944. set: function(f) {
  7945. if (this._stroke instanceof Gradient
  7946. || this._stroke instanceof LinearGradient
  7947. || this._stroke instanceof RadialGradient
  7948. || this._stroke instanceof Texture) {
  7949. this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
  7950. }
  7951. this._stroke = f;
  7952. this._flagStroke = true;
  7953. if (this._stroke instanceof Gradient
  7954. || this._stroke instanceof LinearGradient
  7955. || this._stroke instanceof RadialGradient
  7956. || this._stroke instanceof Texture) {
  7957. this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
  7958. }
  7959. }
  7960. });
  7961. Object.defineProperty(object, 'mask', {
  7962. enumerable: true,
  7963. get: function() {
  7964. return this._mask;
  7965. },
  7966. set: function(v) {
  7967. this._mask = v;
  7968. this._flagMask = true;
  7969. if (!v.clip) {
  7970. v.clip = true;
  7971. }
  7972. }
  7973. });
  7974. Object.defineProperty(object, 'clip', {
  7975. enumerable: true,
  7976. get: function() {
  7977. return this._clip;
  7978. },
  7979. set: function(v) {
  7980. this._clip = v;
  7981. this._flagClip = true;
  7982. }
  7983. });
  7984. Object.defineProperty(object, 'dashes', {
  7985. enumerable: true,
  7986. get: function() {
  7987. return this._dashes;
  7988. },
  7989. set: function(v) {
  7990. if (typeof v.offset !== 'number') {
  7991. v.offset = this._dashes.offset || 0;
  7992. }
  7993. this._dashes = v;
  7994. }
  7995. });
  7996. }
  7997. });
  7998. _.extend(Text.prototype, Shape.prototype, {
  7999. constructor: Text,
  8000. // Flags
  8001. // http://en.wikipedia.org/wiki/Flag
  8002. /**
  8003. * @name Two.Text#_flagValue
  8004. * @private
  8005. * @property {Boolean} - Determines whether the {@link Two.Text#value} need updating.
  8006. */
  8007. _flagValue: true,
  8008. /**
  8009. * @name Two.Text#_flagFamily
  8010. * @private
  8011. * @property {Boolean} - Determines whether the {@link Two.Text#family} need updating.
  8012. */
  8013. _flagFamily: true,
  8014. /**
  8015. * @name Two.Text#_flagSize
  8016. * @private
  8017. * @property {Boolean} - Determines whether the {@link Two.Text#size} need updating.
  8018. */
  8019. _flagSize: true,
  8020. /**
  8021. * @name Two.Text#_flagLeading
  8022. * @private
  8023. * @property {Boolean} - Determines whether the {@link Two.Text#leading} need updating.
  8024. */
  8025. _flagLeading: true,
  8026. /**
  8027. * @name Two.Text#_flagAlignment
  8028. * @private
  8029. * @property {Boolean} - Determines whether the {@link Two.Text#alignment} need updating.
  8030. */
  8031. _flagAlignment: true,
  8032. /**
  8033. * @name Two.Text#_flagBaseline
  8034. * @private
  8035. * @property {Boolean} - Determines whether the {@link Two.Text#baseline} need updating.
  8036. */
  8037. _flagBaseline: true,
  8038. /**
  8039. * @name Two.Text#_flagStyle
  8040. * @private
  8041. * @property {Boolean} - Determines whether the {@link Two.Text#style} need updating.
  8042. */
  8043. _flagStyle: true,
  8044. /**
  8045. * @name Two.Text#_flagWeight
  8046. * @private
  8047. * @property {Boolean} - Determines whether the {@link Two.Text#weight} need updating.
  8048. */
  8049. _flagWeight: true,
  8050. /**
  8051. * @name Two.Text#_flagDecoration
  8052. * @private
  8053. * @property {Boolean} - Determines whether the {@link Two.Text#decoration} need updating.
  8054. */
  8055. _flagDecoration: true,
  8056. /**
  8057. * @name Two.Text#_flagFill
  8058. * @private
  8059. * @property {Boolean} - Determines whether the {@link Two.Text#fill} need updating.
  8060. */
  8061. _flagFill: true,
  8062. /**
  8063. * @name Two.Text#_flagStroke
  8064. * @private
  8065. * @property {Boolean} - Determines whether the {@link Two.Text#stroke} need updating.
  8066. */
  8067. _flagStroke: true,
  8068. /**
  8069. * @name Two.Text#_flagLinewidth
  8070. * @private
  8071. * @property {Boolean} - Determines whether the {@link Two.Text#linewidth} need updating.
  8072. */
  8073. _flagLinewidth: true,
  8074. /**
  8075. * @name Two.Text#_flagOpacity
  8076. * @private
  8077. * @property {Boolean} - Determines whether the {@link Two.Text#opacity} need updating.
  8078. */
  8079. _flagOpacity: true,
  8080. /**
  8081. * @name Two.Text#_flagClassName
  8082. * @private
  8083. * @property {Boolean} - Determines whether the {@link Two.Text#className} need updating.
  8084. */
  8085. _flagClassName: true,
  8086. /**
  8087. * @name Two.Text#_flagVisible
  8088. * @private
  8089. * @property {Boolean} - Determines whether the {@link Two.Text#visible} need updating.
  8090. */
  8091. _flagVisible: true,
  8092. /**
  8093. * @name Two.Path#_flagMask
  8094. * @private
  8095. * @property {Boolean} - Determines whether the {@link Two.Path#mask} needs updating.
  8096. */
  8097. _flagMask: false,
  8098. /**
  8099. * @name Two.Text#_flagClip
  8100. * @private
  8101. * @property {Boolean} - Determines whether the {@link Two.Text#clip} need updating.
  8102. */
  8103. _flagClip: false,
  8104. // Underlying Properties
  8105. /**
  8106. * @name Two.Text#value
  8107. * @property {String} - The characters to be rendered to the the screen. Referred to in the documentation sometimes as the `message`.
  8108. */
  8109. _value: '',
  8110. /**
  8111. * @name Two.Text#family
  8112. * @property {String} - The font family Two.js should attempt to regsiter for rendering. The default value is `'sans-serif'`. Comma separated font names can be supplied as a "stack", similar to the CSS implementation of `font-family`.
  8113. */
  8114. _family: 'sans-serif',
  8115. /**
  8116. * @name Two.Text#size
  8117. * @property {Number} - The font size in Two.js point space. Defaults to `13`.
  8118. */
  8119. _size: 13,
  8120. /**
  8121. * @name Two.Text#leading
  8122. * @property {Number} - The height between lines measured from base to base in Two.js point space. Defaults to `17`.
  8123. */
  8124. _leading: 17,
  8125. /**
  8126. * @name Two.Text#alignment
  8127. * @property {String} - Alignment of text in relation to {@link Two.Text#translation}'s coordinates. Possible values include `'left'`, `'center'`, `'right'`. Defaults to `'center'`.
  8128. */
  8129. _alignment: 'center',
  8130. /**
  8131. * @name Two.Text#baseline
  8132. * @property {String} - The vertical aligment of the text in relation to {@link Two.Text#translation}'s coordinates. Possible values include `'top'`, `'middle'`, `'bottom'`, and `'baseline'`. Defaults to `'baseline'`.
  8133. */
  8134. _baseline: 'middle',
  8135. /**
  8136. * @name Two.Text#style
  8137. * @property {String} - The font's style. Possible values include '`normal`', `'italic'`. Defaults to `'normal'`.
  8138. */
  8139. _style: 'normal',
  8140. /**
  8141. * @name Two.Text#weight
  8142. * @property {Number} - A number at intervals of 100 to describe the font's weight. This compatibility varies with the typeface's variant weights. Larger values are bolder. Smaller values are thinner. Defaults to `'500'`.
  8143. */
  8144. _weight: 500,
  8145. /**
  8146. * @name Two.Text#decoration
  8147. * @property {String} - String to delineate whether text should be decorated with for instance an `'underline'`. Defaults to `'none'`.
  8148. */
  8149. _decoration: 'none',
  8150. /**
  8151. * @name Two.Text#fill
  8152. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the text object should be filled in with.
  8153. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  8154. */
  8155. _fill: '#000',
  8156. /**
  8157. * @name Two.Text#stroke
  8158. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the text object should be filled in with.
  8159. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  8160. */
  8161. _stroke: 'transparent',
  8162. /**
  8163. * @name Two.Text#linewidth
  8164. * @property {Number} - The thickness in pixels of the stroke.
  8165. */
  8166. _linewidth: 1,
  8167. /**
  8168. * @name Two.Text#opacity
  8169. * @property {Number} - The opaqueness of the text object.
  8170. * @nota-bene Can be used in conjunction with CSS Colors that have an alpha value.
  8171. */
  8172. _opacity: 1,
  8173. /**
  8174. * @name Two.Text#className
  8175. * @property {String} - A class to be applied to the element to be compatible with CSS styling. Only available for the {@link Two.SvgRenderer}.
  8176. */
  8177. _className: '',
  8178. /**
  8179. * @name Two.Text#visible
  8180. * @property {Boolean} - Display the text object or not.
  8181. * @nota-bene For {@link Two.CanvasRenderer} and {@link Two.WebGLRenderer} when set to false all updating is disabled improving performance dramatically with many objects in the scene.
  8182. */
  8183. _visible: true,
  8184. /**
  8185. * @name Two.Text#mask
  8186. * @property {Two.Shape} - The shape whose alpha property becomes a clipping area for the text.
  8187. * @nota-bene This property is currently not working becuase of SVG spec issues found here {@link https://code.google.com/p/chromium/issues/detail?id=370951}.
  8188. */
  8189. _mask: null,
  8190. /**
  8191. * @name Two.Text#clip
  8192. * @property {Two.Shape} - Object to define clipping area.
  8193. * @nota-bene This property is currently not working becuase of SVG spec issues found here {@link https://code.google.com/p/chromium/issues/detail?id=370951}.
  8194. */
  8195. _clip: false,
  8196. /**
  8197. * @name Two.Text#_dashes
  8198. * @private
  8199. * @see {@link Two.Text#dashes}
  8200. */
  8201. _dashes: [],
  8202. /**
  8203. * @name Two.Text#remove
  8204. * @function
  8205. * @description Remove self from the scene / parent.
  8206. */
  8207. remove: function() {
  8208. if (!this.parent) {
  8209. return this;
  8210. }
  8211. this.parent.remove(this);
  8212. return this;
  8213. },
  8214. /**
  8215. * @name Two.Text#clone
  8216. * @function
  8217. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  8218. * @returns {Two.Text}
  8219. * @description Create a new instance of {@link Two.Text} with the same properties of the current text object.
  8220. */
  8221. clone: function(parent) {
  8222. var clone = new Text(this.value);
  8223. clone.translation.copy(this.translation);
  8224. clone.rotation = this.rotation;
  8225. clone.scale = this.scale;
  8226. _.each(Text.Properties, function(property) {
  8227. clone[property] = this[property];
  8228. }, this);
  8229. if (this.matrix.manual) {
  8230. clone.matrix.copy(this.matrix);
  8231. }
  8232. if (parent) {
  8233. parent.add(clone);
  8234. }
  8235. return clone._update();
  8236. },
  8237. /**
  8238. * @name Two.Text#toObject
  8239. * @function
  8240. * @returns {Object}
  8241. * @description Return a JSON compatible plain object that represents the text object.
  8242. */
  8243. toObject: function() {
  8244. var result = {
  8245. translation: this.translation.toObject(),
  8246. rotation: this.rotation,
  8247. scale: this.scale
  8248. };
  8249. if (this.matrix.manual) {
  8250. result.matrix = this.matrix.toObject();
  8251. }
  8252. _.each(Text.Properties, function(property) {
  8253. result[property] = this[property];
  8254. }, this);
  8255. return result;
  8256. },
  8257. /**
  8258. * @name Two.Text#noFill
  8259. * @function
  8260. * @description Short hand method to set fill to `transparent`.
  8261. */
  8262. noFill: function() {
  8263. this.fill = 'transparent';
  8264. return this;
  8265. },
  8266. /**
  8267. * @name Two.Text#noStroke
  8268. * @function
  8269. * @description Short hand method to set stroke to `transparent`.
  8270. */
  8271. noStroke: function() {
  8272. this.stroke = undefined;
  8273. this.linewidth = undefined;
  8274. return this;
  8275. },
  8276. // A shim to not break `getBoundingClientRect` calls.
  8277. // TODO: Implement a way to calculate proper bounding
  8278. // boxes of `Two.Text`.
  8279. /**
  8280. * @name Two.Text#getBoundingClientRect
  8281. * @function
  8282. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  8283. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  8284. * @description Return an object with top, left, right, bottom, width, and height parameters of the text object.
  8285. */
  8286. getBoundingClientRect: function(shallow) {
  8287. var matrix, a, b, c, d;
  8288. var left, right, top, bottom;
  8289. // TODO: Update this to not __always__ update. Just when it needs to.
  8290. this._update(true);
  8291. matrix = shallow ? this._matrix : getComputedMatrix(this);
  8292. var height = this.leading;
  8293. var width = this.value.length * this.size * Text.Ratio;
  8294. var border = (this._linewidth || 0) / 2;
  8295. switch (this.alignment) {
  8296. case 'left':
  8297. left = - border;
  8298. right = width + border;
  8299. break;
  8300. case 'right':
  8301. left = - (width + border);
  8302. right = border;
  8303. break;
  8304. default:
  8305. left = - (width / 2 + border);
  8306. right = width / 2 + border;
  8307. }
  8308. switch (this.baseline) {
  8309. case 'top':
  8310. top = - border;
  8311. bottom = height + border;
  8312. break;
  8313. case 'bottom':
  8314. top = - (height + border);
  8315. bottom = border;
  8316. break;
  8317. default:
  8318. top = - (height / 2 + border);
  8319. bottom = height / 2 + border;
  8320. }
  8321. a = matrix.multiply(left, top, 1);
  8322. b = matrix.multiply(left, bottom, 1);
  8323. c = matrix.multiply(right, top, 1);
  8324. d = matrix.multiply(right, bottom, 1);
  8325. top = min(a.y, b.y, c.y, d.y);
  8326. left = min(a.x, b.x, c.x, d.x);
  8327. right = max(a.x, b.x, c.x, d.x);
  8328. bottom = max(a.y, b.y, c.y, d.y);
  8329. return {
  8330. top: top,
  8331. left: left,
  8332. right: right,
  8333. bottom: bottom,
  8334. width: right - left,
  8335. height: bottom - top
  8336. };
  8337. },
  8338. /**
  8339. * @name Two.Text#flagReset
  8340. * @function
  8341. * @private
  8342. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  8343. */
  8344. flagReset: function() {
  8345. this._flagValue = this._flagFamily = this._flagSize =
  8346. this._flagLeading = this._flagAlignment = this._flagFill =
  8347. this._flagStroke = this._flagLinewidth = this._flagOpacity =
  8348. this._flagVisible = this._flagClip = this._flagDecoration =
  8349. this._flagClassName = this._flagBaseline = this._flagWeight =
  8350. this._flagStyle = false;
  8351. Shape.prototype.flagReset.call(this);
  8352. return this;
  8353. }
  8354. });
  8355. Text.MakeObservable(Text.prototype);
  8356. // https://github.com/jonobr1/two.js/issues/507#issuecomment-777159213
  8357. var regex = {
  8358. path: /[+-]?(?:\d*\.\d+|\d+)(?:[eE][+-]\d+)?/g
  8359. };
  8360. var alignments = {
  8361. start: 'left',
  8362. middle: 'center',
  8363. end: 'right'
  8364. };
  8365. /**
  8366. * @name Two.Utils.getAlignment
  8367. * @function
  8368. * @param {AlignmentString}
  8369. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor}
  8370. */
  8371. var getAlignment = function(anchor) {
  8372. return alignments[anchor];
  8373. };
  8374. var getBaseline = function(node) {
  8375. var a = node.getAttribute('dominant-baseline');
  8376. var b = node.getAttribute('alignment-baseline');
  8377. return a || b;
  8378. };
  8379. var getTagName = function(tag) {
  8380. return tag.replace(/svg:/ig, '').toLowerCase();
  8381. };
  8382. var applyTransformsToVector = function(transforms, vector) {
  8383. vector.x += transforms.translateX;
  8384. vector.y += transforms.translateY;
  8385. vector.x *= transforms.scaleX;
  8386. vector.y *= transforms.scaleY;
  8387. if (transforms.rotation !== 0) {
  8388. // TODO: Test further
  8389. var l = vector.length();
  8390. vector.x = l * Math.cos(transforms.rotation);
  8391. vector.y = l * Math.sin(transforms.rotation);
  8392. }
  8393. };
  8394. /**
  8395. * @name Two.Utils.extractCSSText
  8396. * @function
  8397. * @param {String} text - The CSS text body to be parsed and extracted.
  8398. * @param {Object} [styles] - The styles object to apply CSS key values to.
  8399. * @returns {Object} styles
  8400. * @description Parse CSS text body and apply them as key value pairs to a JavaScript object.
  8401. */
  8402. var extractCSSText = function(text, styles) {
  8403. var commands, command, name, value;
  8404. if (!styles) {
  8405. styles = {};
  8406. }
  8407. commands = text.split(';');
  8408. for (var i = 0; i < commands.length; i++) {
  8409. command = commands[i].split(':');
  8410. name = command[0];
  8411. value = command[1];
  8412. if (typeof name === 'undefined' || typeof value === 'undefined') {
  8413. continue;
  8414. }
  8415. styles[name] = value.replace(/\s/, '');
  8416. }
  8417. return styles;
  8418. };
  8419. /**
  8420. * @name Two.Utils.getSvgStyles
  8421. * @function
  8422. * @param {SVGElement} node - The SVG node to parse.
  8423. * @returns {Object} styles
  8424. * @description Get the CSS comands from the `style` attribute of an SVG node and apply them as key value pairs to a JavaScript object.
  8425. */
  8426. var getSvgStyles = function(node) {
  8427. var styles = {};
  8428. var attributes = getSvgAttributes(node);
  8429. var length = Math.max(attributes.length, node.style.length);
  8430. for (var i = 0; i < length; i++) {
  8431. var command = node.style[i];
  8432. var attribute = attributes[i];
  8433. if (command) {
  8434. styles[command] = node.style[command];
  8435. }
  8436. if (attribute) {
  8437. styles[attribute] = node.getAttribute(attribute);
  8438. }
  8439. }
  8440. return styles;
  8441. };
  8442. var getSvgAttributes = function(node) {
  8443. var attributes = node.getAttributeNames();
  8444. // Reserved attributes to remove
  8445. var keywords = ['id', 'class', 'transform', 'xmlns', 'viewBox'];
  8446. for (var i = 0; i < keywords.length; i++) {
  8447. var keyword = keywords[i];
  8448. var index = Array.prototype.indexOf.call(attributes, keyword);
  8449. if (index >= 0) {
  8450. attributes.splice(index, 1);
  8451. }
  8452. }
  8453. return attributes;
  8454. };
  8455. /**
  8456. * @name Two.Utils.applySvgViewBox
  8457. * @function
  8458. * @param {Two.Shape} node - The Two.js object to apply viewbox matrix to
  8459. * @param {String} value - The viewBox value from the SVG attribute
  8460. * @returns {Two.Shape} node
  8461. * @description Applies the transform of the SVG Viewbox on a given node.
  8462. */
  8463. var applySvgViewBox = function(node, value) {
  8464. var elements = value.split(/\s/);
  8465. var x = parseFloat(elements[0]);
  8466. var y = parseFloat(elements[1]);
  8467. var width = parseFloat(elements[2]);
  8468. var height = parseFloat(elements[3]);
  8469. var s = Math.min(this.width / width, this.height / height);
  8470. node.translation.x -= x * s;
  8471. node.translation.y -= y * s;
  8472. node.scale = s;
  8473. return node;
  8474. };
  8475. /**
  8476. * @name Two.Utils.applySvgAttributes
  8477. * @function
  8478. * @param {SVGElement} node - An SVG Node to extrapolate attributes from.
  8479. * @param {Two.Shape} elem - The Two.js object to apply extrapolated attributes to.
  8480. * @returns {Two.Shape} The Two.js object passed now with applied attributes.
  8481. * @description This function iterates through an SVG Node's properties and stores ones of interest. It tries to resolve styles applied via CSS as well.
  8482. * @TODO Reverse calculate {@link Two.Gradient}s for fill / stroke of any given path.
  8483. */
  8484. var applySvgAttributes = function(node, elem, parentStyles) {
  8485. var styles = {}, attributes = {}, extracted = {}, i, m, key, value, attr;
  8486. var transforms, x, y;
  8487. var id, scene, ref, tagName;
  8488. // Not available in non browser environments
  8489. if (root$1.getComputedStyle) {
  8490. // Convert CSSStyleDeclaration to a normal object
  8491. var computedStyles = root$1.getComputedStyle(node);
  8492. i = computedStyles.length;
  8493. while (i--) {
  8494. key = computedStyles[i];
  8495. value = computedStyles[key];
  8496. // Gecko returns undefined for unset properties
  8497. // Webkit returns the default value
  8498. if (typeof value !== 'undefined') {
  8499. styles[key] = value;
  8500. }
  8501. }
  8502. }
  8503. // Convert NodeMap to a normal object
  8504. for (i = 0; i < node.attributes.length; i++) {
  8505. attr = node.attributes[i];
  8506. if (/style/i.test(attr.nodeName)) {
  8507. extractCSSText(attr.value, extracted);
  8508. } else {
  8509. attributes[attr.nodeName] = attr.value;
  8510. }
  8511. }
  8512. // Getting the correct opacity is a bit tricky, since SVG path elements don't
  8513. // support opacity as an attribute, but you can apply it via CSS.
  8514. // So we take the opacity and set (stroke/fill)-opacity to the same value.
  8515. if (typeof styles.opacity !== 'undefined') {
  8516. styles['stroke-opacity'] = styles.opacity;
  8517. styles['fill-opacity'] = styles.opacity;
  8518. delete styles.opacity;
  8519. }
  8520. // Merge attributes and applied styles (attributes take precedence)
  8521. if (parentStyles) {
  8522. _.defaults(styles, parentStyles);
  8523. }
  8524. _.extend(styles, extracted, attributes);
  8525. // Similarly visibility is influenced by the value of both display and visibility.
  8526. // Calculate a unified value here which defaults to `true`.
  8527. styles.visible = !(typeof styles.display === 'undefined' && /none/i.test(styles.display))
  8528. || (typeof styles.visibility === 'undefined' && /hidden/i.test(styles.visibility));
  8529. // Now iterate the whole thing
  8530. for (key in styles) {
  8531. value = styles[key];
  8532. switch (key) {
  8533. case 'gradientTransform':
  8534. // TODO: Check this out https://github.com/paperjs/paper.js/blob/develop/src/svg/SvgImport.js#L315
  8535. if (/none/i.test(value)) break;
  8536. m = (node.gradientTransform && node.gradientTransform.baseVal && node.gradientTransform.baseVal.length > 0)
  8537. ? node.gradientTransform.baseVal[0].matrix
  8538. : (node.getCTM ? node.getCTM() : null);
  8539. if (m === null) break;
  8540. transforms = decomposeMatrix(m);
  8541. switch (elem._renderer.type) {
  8542. case 'linear-gradient':
  8543. applyTransformsToVector(transforms, elem.left);
  8544. applyTransformsToVector(transforms, elem.right);
  8545. break;
  8546. case 'radial-gradient':
  8547. elem.center.x += transforms.translateX;
  8548. elem.center.y += transforms.translateY;
  8549. elem.focal.x += transforms.translateX;
  8550. elem.focal.y += transforms.translateY;
  8551. elem.radius *= Math.max(transforms.scaleX, transforms.scaleY);
  8552. break;
  8553. }
  8554. break;
  8555. case 'transform':
  8556. // TODO: Check this out https://github.com/paperjs/paper.js/blob/develop/src/svg/SvgImport.js#L315
  8557. if (/none/i.test(value)) break;
  8558. m = (node.transform && node.transform.baseVal && node.transform.baseVal.length > 0)
  8559. ? node.transform.baseVal[0].matrix
  8560. : (node.getCTM ? node.getCTM() : null);
  8561. // Might happen when transform string is empty or not valid.
  8562. if (m === null) break;
  8563. if (Constants.AutoCalculateImportedMatrices) {
  8564. // Decompose and infer Two.js related properties.
  8565. transforms = decomposeMatrix(m);
  8566. elem.translation.set(transforms.translateX, transforms.translateY);
  8567. elem.rotation = Math.PI * (transforms.rotation / 180);
  8568. elem.scale = new Vector(transforms.scaleX, transforms.scaleY);
  8569. x = parseFloat((styles.x + '').replace('px'));
  8570. y = parseFloat((styles.y + '').replace('px'));
  8571. // Override based on attributes.
  8572. if (x) {
  8573. elem.translation.x = x;
  8574. }
  8575. if (y) {
  8576. elem.translation.y = y;
  8577. }
  8578. } else {
  8579. // Edit the underlying matrix and don't force an auto calc.
  8580. m = node.getCTM();
  8581. elem._matrix.manual = true;
  8582. elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f);
  8583. }
  8584. break;
  8585. case 'viewBox':
  8586. applySvgViewBox.call(this, elem, value);
  8587. break;
  8588. case 'visible':
  8589. if (elem instanceof Group) {
  8590. elem._visible = value;
  8591. break;
  8592. }
  8593. elem.visible = value;
  8594. break;
  8595. case 'stroke-linecap':
  8596. if (elem instanceof Group) {
  8597. elem._cap = value;
  8598. break;
  8599. }
  8600. elem.cap = value;
  8601. break;
  8602. case 'stroke-linejoin':
  8603. if (elem instanceof Group) {
  8604. elem._join = value;
  8605. break;
  8606. }
  8607. elem.join = value;
  8608. break;
  8609. case 'stroke-miterlimit':
  8610. if (elem instanceof Group) {
  8611. elem._miter = value;
  8612. break;
  8613. }
  8614. elem.miter = value;
  8615. break;
  8616. case 'stroke-width':
  8617. if (elem instanceof Group) {
  8618. elem._linewidth = parseFloat(value);
  8619. break;
  8620. }
  8621. elem.linewidth = parseFloat(value);
  8622. break;
  8623. case 'opacity':
  8624. case 'stroke-opacity':
  8625. case 'fill-opacity':
  8626. // Only apply styles to rendered shapes
  8627. // in the scene.
  8628. if (elem instanceof Group) {
  8629. elem._opacity = parseFloat(value);
  8630. break;
  8631. }
  8632. elem.opacity = parseFloat(value);
  8633. break;
  8634. case 'clip-path':
  8635. if (/url\(#.*\)/i.test(value)) {
  8636. id = value.replace(/url\(#(.*)\)/i, '$1');
  8637. if (read.defs.current && read.defs.current.contains(id)) {
  8638. ref = read.defs.current.get(id);
  8639. if (ref && ref.childNodes.length > 0) {
  8640. ref = ref.childNodes[0];
  8641. tagName = getTagName(ref.nodeName);
  8642. elem.mask = read[tagName].call(this, ref, {});
  8643. switch (elem._renderer.type) {
  8644. case 'path':
  8645. // The matrix here needs to change to insure that the object
  8646. // clipping is in the same coordinate space as the `elem`.
  8647. elem.position.add(elem.mask.position);
  8648. elem.mask.position.clear();
  8649. break;
  8650. }
  8651. }
  8652. }
  8653. }
  8654. break;
  8655. case 'fill':
  8656. case 'stroke':
  8657. if (elem instanceof Group) {
  8658. key = '_' + key;
  8659. }
  8660. if (/url\(#.*\)/i.test(value)) {
  8661. id = value.replace(/url\(#(.*)\)/i, '$1');
  8662. if (read.defs.current && read.defs.current.contains(id)) {
  8663. ref = read.defs.current.get(id);
  8664. tagName = getTagName(ref.nodeName);
  8665. ref = read[tagName].call(this, ref, {});
  8666. } else {
  8667. scene = getScene(this);
  8668. ref = scene.getById(id);
  8669. }
  8670. elem[key] = ref;
  8671. } else {
  8672. elem[key] = (/none/i.test(value)) ? 'transparent' : value;
  8673. }
  8674. break;
  8675. case 'id':
  8676. elem.id = value;
  8677. // Overwritten id for non-conflicts on same page SVG documents
  8678. // TODO: Make this non-descructive
  8679. node.id = value + '-' + Constants.Identifier + 'applied';
  8680. break;
  8681. case 'class':
  8682. case 'className':
  8683. elem.classList = value.split(' ');
  8684. break;
  8685. case 'x':
  8686. case 'y':
  8687. var ca = elem instanceof Gradient;
  8688. var cb = elem instanceof LinearGradient;
  8689. var cc = elem instanceof RadialGradient;
  8690. if (ca || cb || cc) {
  8691. break;
  8692. }
  8693. if (value.match('[a-z%]$') && !value.endsWith('px')) {
  8694. var error = new TwoError(
  8695. 'only pixel values are supported with the ' + key + ' attribute.');
  8696. console.warn(error.name, error.message);
  8697. }
  8698. elem.translation[key] = parseFloat(value);
  8699. break;
  8700. case 'font-family':
  8701. if (elem instanceof Text) {
  8702. elem.family = value;
  8703. }
  8704. break;
  8705. case 'font-size':
  8706. if (elem instanceof Text) {
  8707. elem.size = value;
  8708. }
  8709. break;
  8710. case 'font-weight':
  8711. if (elem instanceof Text) {
  8712. elem.weight = value;
  8713. }
  8714. break;
  8715. case 'font-style':
  8716. if (elem instanceof Text) {
  8717. elem.style = value;
  8718. }
  8719. break;
  8720. case 'text-decoration':
  8721. if (elem instanceof Text) {
  8722. elem.decoration = value;
  8723. }
  8724. break;
  8725. case 'line-height':
  8726. if (elem instanceof Text) {
  8727. elem.leading = value;
  8728. }
  8729. break;
  8730. }
  8731. }
  8732. return styles;
  8733. };
  8734. /**
  8735. * @name Two.Utils.updateDefsCache
  8736. * @function
  8737. * @param {SVGElement} node - The SVG Node with which to update the defs cache.
  8738. * @param {Object} Object - The defs cache to be updated.
  8739. * @description Update the cache of children of <defs /> tags.
  8740. */
  8741. var updateDefsCache = function(node, defsCache) {
  8742. for (var i = 0, l = node.childNodes.length; i < l; i++) {
  8743. var n = node.childNodes[i];
  8744. if (!n.id) continue;
  8745. var tagName = getTagName(node.nodeName);
  8746. if (tagName === '#text') continue;
  8747. defsCache.add(n.id, n);
  8748. }
  8749. };
  8750. /**
  8751. * @name Two.Utils.getScene
  8752. * @param {Two.Shape} node - The currently available object in the scenegraph.
  8753. * @returns {Group} - The highest order {@link Two.Group} in the scenegraph.
  8754. * @property {Function}
  8755. */
  8756. var getScene = function(node) {
  8757. while (node.parent) {
  8758. node = node.parent;
  8759. }
  8760. return node.scene;
  8761. };
  8762. /**
  8763. * @name Two.Utils.read
  8764. * @property {Object} read - A map of functions to read any number of SVG node types and create Two.js equivalents of them. Primarily used by the {@link Two#interpret} method.
  8765. */
  8766. var read = {
  8767. svg: function(node) {
  8768. var defs = read.defs.current = new Registry();
  8769. var elements = node.getElementsByTagName('defs');
  8770. for (var i = 0; i < elements.length; i++) {
  8771. updateDefsCache(elements[i], defs);
  8772. }
  8773. var svg = read.g.call(this, node);
  8774. // var viewBox = node.getAttribute('viewBox');
  8775. svg.defs = defs; // Export out the <defs /> for later use
  8776. // Utils.applySvgViewBox(svg, viewBox);
  8777. delete read.defs.current;
  8778. return svg;
  8779. },
  8780. defs: function(node) {
  8781. return null;
  8782. },
  8783. use: function(node, styles) {
  8784. var error;
  8785. var href = node.getAttribute('href') || node.getAttribute('xlink:href');
  8786. if (!href) {
  8787. error = new TwoError('encountered <use /> with no href.');
  8788. console.warn(error.name, error.message);
  8789. return null;
  8790. }
  8791. var id = href.slice(1);
  8792. if (!read.defs.current.contains(id)) {
  8793. error = new TwoError(
  8794. 'unable to find element for reference ' + href + '.');
  8795. console.warn(error.name, error.message);
  8796. return null;
  8797. }
  8798. var template = read.defs.current.get(id);
  8799. var fullNode = template.cloneNode(true);
  8800. var overwriteAttrs = ['x', 'y', 'width', 'height', 'href', 'xlink:href'];
  8801. for (var i = 0; i < node.attributes.length; i++) {
  8802. var attr = node.attributes[i];
  8803. var ca = overwriteAttrs.includes(attr.nodeName);
  8804. var cb = !fullNode.hasAttribute(attr.nodeName);
  8805. if (ca || cb) {
  8806. fullNode.setAttribute(attr.nodeName, attr.value);
  8807. }
  8808. }
  8809. var tagName = getTagName(fullNode.nodeName);
  8810. return read[tagName].call(this, fullNode, styles);
  8811. },
  8812. g: function(node, parentStyles) {
  8813. var styles;
  8814. var group = new Group();
  8815. applySvgAttributes.call(this, node, group, parentStyles);
  8816. this.add(group);
  8817. // Switched up order to inherit more specific styles
  8818. styles = getSvgStyles.call(this, node);
  8819. for (var i = 0, l = node.childNodes.length; i < l; i++) {
  8820. var n = node.childNodes[i];
  8821. var tag = n.nodeName;
  8822. if (!tag) return;
  8823. var tagName = getTagName(tag);
  8824. if (tagName in read) {
  8825. var o = read[tagName].call(group, n, styles);
  8826. if (!!o && !o.parent) {
  8827. group.add(o);
  8828. }
  8829. }
  8830. }
  8831. return group;
  8832. },
  8833. polygon: function(node, parentStyles) {
  8834. var points = node.getAttribute('points');
  8835. var verts = [];
  8836. points.replace(/(-?[\d.eE-]+)[,|\s](-?[\d.eE-]+)/g, function(match, p1, p2) {
  8837. verts.push(new Anchor(parseFloat(p1), parseFloat(p2)));
  8838. });
  8839. var poly = new Path(verts, true).noStroke();
  8840. poly.fill = 'black';
  8841. applySvgAttributes.call(this, node, poly, parentStyles);
  8842. return poly;
  8843. },
  8844. polyline: function(node, parentStyles) {
  8845. var poly = read.polygon.call(this, node, parentStyles);
  8846. poly.closed = false;
  8847. return poly;
  8848. },
  8849. path: function(node, parentStyles) {
  8850. var path = node.getAttribute('d');
  8851. var points = [];
  8852. var closed = false, relative = false;
  8853. if (path) {
  8854. // Create a Two.Path from the paths.
  8855. var coord = new Anchor();
  8856. var control, coords;
  8857. var commands = path.match(/[a-df-z][^a-df-z]*/ig);
  8858. var last = commands.length - 1;
  8859. // Split up polybeziers
  8860. _.each(commands.slice(0), function(command, i) {
  8861. var items = command.slice(1).trim().match(regex.path);
  8862. var type = command[0];
  8863. var lower = type.toLowerCase();
  8864. var bin, j, l, ct, times, result = [];
  8865. if (i === 0) {
  8866. commands = [];
  8867. }
  8868. switch (lower) {
  8869. case 'h':
  8870. case 'v':
  8871. if (items.length > 1) {
  8872. bin = 1;
  8873. }
  8874. break;
  8875. case 'm':
  8876. case 'l':
  8877. case 't':
  8878. if (items.length > 2) {
  8879. bin = 2;
  8880. }
  8881. break;
  8882. case 's':
  8883. case 'q':
  8884. if (items.length > 4) {
  8885. bin = 4;
  8886. }
  8887. break;
  8888. case 'c':
  8889. if (items.length > 6) {
  8890. bin = 6;
  8891. }
  8892. break;
  8893. case 'a':
  8894. if (items.length > 7) {
  8895. bin = 7;
  8896. }
  8897. break;
  8898. }
  8899. // This means we have a polybezier.
  8900. if (bin) {
  8901. for (j = 0, l = items.length, times = 0; j < l; j+=bin) {
  8902. ct = type;
  8903. if (times > 0) {
  8904. switch (type) {
  8905. case 'm':
  8906. ct = 'l';
  8907. break;
  8908. case 'M':
  8909. ct = 'L';
  8910. break;
  8911. }
  8912. }
  8913. result.push(ct + items.slice(j, j + bin).join(' '));
  8914. times++;
  8915. }
  8916. commands = Array.prototype.concat.apply(commands, result);
  8917. } else {
  8918. commands.push(command);
  8919. }
  8920. });
  8921. // Create the vertices for our Two.Path
  8922. _.each(commands, function(command, i) {
  8923. var result, x, y;
  8924. var type = command[0];
  8925. var lower = type.toLowerCase();
  8926. coords = command.slice(1).trim().match(regex.path);
  8927. relative = type === lower;
  8928. var x1, y1, x2, y2, x3, y3, x4, y4, reflection;
  8929. switch (lower) {
  8930. case 'z':
  8931. if (i >= last) {
  8932. closed = true;
  8933. } else {
  8934. x = coord.x;
  8935. y = coord.y;
  8936. result = new Anchor(
  8937. x, y,
  8938. undefined, undefined,
  8939. undefined, undefined,
  8940. Commands.close
  8941. );
  8942. // Make coord be the last `m` command
  8943. for (var j = points.length - 1; j >= 0; j--) {
  8944. var point = points[j];
  8945. if (/m/i.test(point.command)) {
  8946. coord = point;
  8947. break;
  8948. }
  8949. }
  8950. }
  8951. break;
  8952. case 'm':
  8953. case 'l':
  8954. control = undefined;
  8955. x = parseFloat(coords[0]);
  8956. y = parseFloat(coords[1]);
  8957. result = new Anchor(
  8958. x, y,
  8959. undefined, undefined,
  8960. undefined, undefined,
  8961. /m/i.test(lower) ? Commands.move : Commands.line
  8962. );
  8963. if (relative) {
  8964. result.addSelf(coord);
  8965. }
  8966. // result.controls.left.copy(result);
  8967. // result.controls.right.copy(result);
  8968. coord = result;
  8969. break;
  8970. case 'h':
  8971. case 'v':
  8972. var a = /h/i.test(lower) ? 'x' : 'y';
  8973. var b = /x/i.test(a) ? 'y' : 'x';
  8974. result = new Anchor(
  8975. undefined, undefined,
  8976. undefined, undefined,
  8977. undefined, undefined,
  8978. Commands.line
  8979. );
  8980. result[a] = parseFloat(coords[0]);
  8981. result[b] = coord[b];
  8982. if (relative) {
  8983. result[a] += coord[a];
  8984. }
  8985. // result.controls.left.copy(result);
  8986. // result.controls.right.copy(result);
  8987. coord = result;
  8988. break;
  8989. case 'c':
  8990. case 's':
  8991. x1 = coord.x;
  8992. y1 = coord.y;
  8993. if (!control) {
  8994. control = new Vector();//.copy(coord);
  8995. }
  8996. if (/c/i.test(lower)) {
  8997. x2 = parseFloat(coords[0]);
  8998. y2 = parseFloat(coords[1]);
  8999. x3 = parseFloat(coords[2]);
  9000. y3 = parseFloat(coords[3]);
  9001. x4 = parseFloat(coords[4]);
  9002. y4 = parseFloat(coords[5]);
  9003. } else {
  9004. // Calculate reflection control point for proper x2, y2
  9005. // inclusion.
  9006. reflection = getReflection(coord, control, relative);
  9007. x2 = reflection.x;
  9008. y2 = reflection.y;
  9009. x3 = parseFloat(coords[0]);
  9010. y3 = parseFloat(coords[1]);
  9011. x4 = parseFloat(coords[2]);
  9012. y4 = parseFloat(coords[3]);
  9013. }
  9014. if (relative) {
  9015. x2 += x1;
  9016. y2 += y1;
  9017. x3 += x1;
  9018. y3 += y1;
  9019. x4 += x1;
  9020. y4 += y1;
  9021. }
  9022. if (!_.isObject(coord.controls)) {
  9023. Anchor.AppendCurveProperties(coord);
  9024. }
  9025. coord.controls.right.set(x2 - coord.x, y2 - coord.y);
  9026. result = new Anchor(
  9027. x4, y4,
  9028. x3 - x4, y3 - y4,
  9029. undefined, undefined,
  9030. Commands.curve
  9031. );
  9032. coord = result;
  9033. control = result.controls.left;
  9034. break;
  9035. case 't':
  9036. case 'q':
  9037. x1 = coord.x;
  9038. y1 = coord.y;
  9039. if (!control) {
  9040. control = new Vector();
  9041. }
  9042. if (/q/i.test(lower)) {
  9043. x2 = parseFloat(coords[0]);
  9044. y2 = parseFloat(coords[1]);
  9045. x3 = parseFloat(coords[0]);
  9046. y3 = parseFloat(coords[1]);
  9047. x4 = parseFloat(coords[2]);
  9048. y4 = parseFloat(coords[3]);
  9049. } else {
  9050. reflection = getReflection(coord, control, relative);
  9051. x2 = reflection.x;
  9052. y2 = reflection.y;
  9053. x3 = reflection.x;
  9054. y3 = reflection.y;
  9055. x4 = parseFloat(coords[0]);
  9056. y4 = parseFloat(coords[1]);
  9057. }
  9058. if (relative) {
  9059. x2 += x1;
  9060. y2 += y1;
  9061. x3 += x1;
  9062. y3 += y1;
  9063. x4 += x1;
  9064. y4 += y1;
  9065. }
  9066. if (!_.isObject(coord.controls)) {
  9067. Anchor.AppendCurveProperties(coord);
  9068. }
  9069. coord.controls.right.set(
  9070. (x2 - coord.x) * 0.33, (y2 - coord.y) * 0.33);
  9071. result = new Anchor(
  9072. x4, y4,
  9073. x3 - x4, y3 - y4,
  9074. undefined, undefined,
  9075. Commands.curve
  9076. );
  9077. coord = result;
  9078. control = result.controls.left;
  9079. break;
  9080. case 'a':
  9081. x1 = coord.x;
  9082. y1 = coord.y;
  9083. var rx = parseFloat(coords[0]);
  9084. var ry = parseFloat(coords[1]);
  9085. var xAxisRotation = parseFloat(coords[2]);// * PI / 180;
  9086. var largeArcFlag = parseFloat(coords[3]);
  9087. var sweepFlag = parseFloat(coords[4]);
  9088. x4 = parseFloat(coords[5]);
  9089. y4 = parseFloat(coords[6]);
  9090. if (relative) {
  9091. x4 += x1;
  9092. y4 += y1;
  9093. }
  9094. var anchor = new Anchor(x4, y4);
  9095. anchor.command = Commands.arc;
  9096. anchor.rx = rx;
  9097. anchor.ry = ry;
  9098. anchor.xAxisRotation = xAxisRotation;
  9099. anchor.largeArcFlag = largeArcFlag;
  9100. anchor.sweepFlag = sweepFlag;
  9101. result = anchor;
  9102. coord = anchor;
  9103. control = undefined;
  9104. break;
  9105. }
  9106. if (result) {
  9107. if (Array.isArray(result)) {
  9108. points = points.concat(result);
  9109. } else {
  9110. points.push(result);
  9111. }
  9112. }
  9113. });
  9114. }
  9115. path = new Path(points, closed, undefined, true).noStroke();
  9116. path.fill = 'black';
  9117. var rect = path.getBoundingClientRect(true);
  9118. // Center objects to stay consistent
  9119. // with the rest of the Two.js API.
  9120. rect.centroid = {
  9121. x: rect.left + rect.width / 2,
  9122. y: rect.top + rect.height / 2
  9123. };
  9124. _.each(path.vertices, function(v) {
  9125. v.subSelf(rect.centroid);
  9126. });
  9127. applySvgAttributes.call(this, node, path, parentStyles);
  9128. path.translation.addSelf(rect.centroid);
  9129. return path;
  9130. },
  9131. circle: function(node, parentStyles) {
  9132. var x = parseFloat(node.getAttribute('cx'));
  9133. var y = parseFloat(node.getAttribute('cy'));
  9134. var r = parseFloat(node.getAttribute('r'));
  9135. var circle = new Circle(0, 0, r).noStroke();
  9136. circle.fill = 'black';
  9137. applySvgAttributes.call(this, node, circle, parentStyles);
  9138. circle.translation.x = x;
  9139. circle.translation.y = y;
  9140. return circle;
  9141. },
  9142. ellipse: function(node, parentStyles) {
  9143. var x = parseFloat(node.getAttribute('cx'));
  9144. var y = parseFloat(node.getAttribute('cy'));
  9145. var width = parseFloat(node.getAttribute('rx'));
  9146. var height = parseFloat(node.getAttribute('ry'));
  9147. var ellipse = new Ellipse(0, 0, width, height).noStroke();
  9148. ellipse.fill = 'black';
  9149. applySvgAttributes.call(this, node, ellipse, parentStyles);
  9150. ellipse.translation.x = x;
  9151. ellipse.translation.y = y;
  9152. return ellipse;
  9153. },
  9154. rect: function(node, parentStyles) {
  9155. var rx = parseFloat(node.getAttribute('rx'));
  9156. var ry = parseFloat(node.getAttribute('ry'));
  9157. if (!_.isNaN(rx) || !_.isNaN(ry)) {
  9158. return read['rounded-rect'](node);
  9159. }
  9160. var width = parseFloat(node.getAttribute('width'));
  9161. var height = parseFloat(node.getAttribute('height'));
  9162. var w2 = width / 2;
  9163. var h2 = height / 2;
  9164. var rect = new Rectangle(0, 0, width, height)
  9165. .noStroke();
  9166. rect.fill = 'black';
  9167. applySvgAttributes.call(this, node, rect, parentStyles);
  9168. // For rectangles, (x, y) is the center of the shape rather than the top
  9169. // left corner.
  9170. rect.translation.x += w2;
  9171. rect.translation.y += h2;
  9172. return rect;
  9173. },
  9174. 'rounded-rect': function(node, parentStyles) {
  9175. var rx = parseFloat(node.getAttribute('rx')) || 0;
  9176. var ry = parseFloat(node.getAttribute('ry')) || 0;
  9177. var width = parseFloat(node.getAttribute('width'));
  9178. var height = parseFloat(node.getAttribute('height'));
  9179. var w2 = width / 2;
  9180. var h2 = height / 2;
  9181. var radius = new Vector(rx, ry);
  9182. var rect = new RoundedRectangle(0, 0, width, height, radius)
  9183. .noStroke();
  9184. rect.fill = 'black';
  9185. applySvgAttributes.call(this, node, rect, parentStyles);
  9186. // For rectangles, (x, y) is the center of the shape rather than the top
  9187. // left corner.
  9188. rect.translation.x += w2;
  9189. rect.translation.y += h2;
  9190. return rect;
  9191. },
  9192. line: function(node, parentStyles) {
  9193. var x1 = parseFloat(node.getAttribute('x1'));
  9194. var y1 = parseFloat(node.getAttribute('y1'));
  9195. var x2 = parseFloat(node.getAttribute('x2'));
  9196. var y2 = parseFloat(node.getAttribute('y2'));
  9197. var line = new Line(x1, y1, x2, y2).noFill();
  9198. applySvgAttributes.call(this, node, line, parentStyles);
  9199. return line;
  9200. },
  9201. lineargradient: function(node, parentStyles) {
  9202. var x1 = parseFloat(node.getAttribute('x1'));
  9203. var y1 = parseFloat(node.getAttribute('y1'));
  9204. var x2 = parseFloat(node.getAttribute('x2'));
  9205. var y2 = parseFloat(node.getAttribute('y2'));
  9206. var ox = (x2 + x1) / 2;
  9207. var oy = (y2 + y1) / 2;
  9208. var stops = [];
  9209. for (var i = 0; i < node.children.length; i++) {
  9210. var child = node.children[i];
  9211. var offset = child.getAttribute('offset');
  9212. if (/%/ig.test(offset)) {
  9213. offset = parseFloat(offset.replace(/%/ig, '')) / 100;
  9214. }
  9215. offset = parseFloat(offset);
  9216. var color = child.getAttribute('stop-color');
  9217. var opacity = child.getAttribute('stop-opacity');
  9218. var style = child.getAttribute('style');
  9219. var matches;
  9220. if (color === null) {
  9221. matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
  9222. color = matches && matches.length > 1 ? matches[1] : undefined;
  9223. }
  9224. if (opacity === null) {
  9225. matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
  9226. opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  9227. } else {
  9228. opacity = parseFloat(opacity);
  9229. }
  9230. stops.push(new Stop(offset, color, opacity));
  9231. }
  9232. var gradient = new LinearGradient(x1 - ox, y1 - oy, x2 - ox,
  9233. y2 - oy, stops);
  9234. applySvgAttributes.call(this, node, gradient, parentStyles);
  9235. return gradient;
  9236. },
  9237. radialgradient: function(node, parentStyles) {
  9238. var cx = parseFloat(node.getAttribute('cx')) || 0;
  9239. var cy = parseFloat(node.getAttribute('cy')) || 0;
  9240. var r = parseFloat(node.getAttribute('r'));
  9241. var fx = parseFloat(node.getAttribute('fx'));
  9242. var fy = parseFloat(node.getAttribute('fy'));
  9243. if (_.isNaN(fx)) {
  9244. fx = cx;
  9245. }
  9246. if (_.isNaN(fy)) {
  9247. fy = cy;
  9248. }
  9249. var ox = Math.abs(cx + fx) / 2;
  9250. var oy = Math.abs(cy + fy) / 2;
  9251. var stops = [];
  9252. for (var i = 0; i < node.children.length; i++) {
  9253. var child = node.children[i];
  9254. var offset = child.getAttribute('offset');
  9255. if (/%/ig.test(offset)) {
  9256. offset = parseFloat(offset.replace(/%/ig, '')) / 100;
  9257. }
  9258. offset = parseFloat(offset);
  9259. var color = child.getAttribute('stop-color');
  9260. var opacity = child.getAttribute('stop-opacity');
  9261. var style = child.getAttribute('style');
  9262. var matches;
  9263. if (color === null) {
  9264. matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
  9265. color = matches && matches.length > 1 ? matches[1] : undefined;
  9266. }
  9267. if (opacity === null) {
  9268. matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
  9269. opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  9270. } else {
  9271. opacity = parseFloat(opacity);
  9272. }
  9273. stops.push(new Stop(offset, color, opacity));
  9274. }
  9275. var gradient = new RadialGradient(cx - ox, cy - oy, r,
  9276. stops, fx - ox, fy - oy);
  9277. applySvgAttributes.call(this, node, gradient, parentStyles);
  9278. return gradient;
  9279. },
  9280. text: function(node, parentStyles) {
  9281. var alignment = getAlignment(node.getAttribute('text-anchor')) || 'left';
  9282. var baseline = getBaseline(node) || 'baseline';
  9283. var message = node.textContent;
  9284. var text = new Text(message);
  9285. applySvgAttributes.call(this, node, text, parentStyles);
  9286. text.alignment = alignment;
  9287. text.baseline = baseline;
  9288. return text;
  9289. },
  9290. clippath: function(node, parentStyles) {
  9291. if (read.defs.current && !read.defs.current.contains(node.id)) {
  9292. read.defs.current.add(node.id, node);
  9293. }
  9294. return null;
  9295. },
  9296. image: function(node, parentStyles) {
  9297. var href = node.getAttribute('href') || node.getAttribute('xlink:href');
  9298. if (!href) {
  9299. var error = new TwoError('encountered <image /> with no href.');
  9300. console.warn(error.name, error.message);
  9301. return null;
  9302. }
  9303. var x = parseFloat(node.getAttribute('x')) || 0;
  9304. var y = parseFloat(node.getAttribute('y')) || 0;
  9305. var width = parseFloat(node.getAttribute('width'));
  9306. var height = parseFloat(node.getAttribute('height'));
  9307. var sprite = new Sprite(href, x, y);
  9308. if (!_.isNaN(width)) {
  9309. sprite.width = width;
  9310. }
  9311. if (!_.isNaN(height)) {
  9312. sprite.height = height;
  9313. }
  9314. applySvgAttributes.call(this, node, sprite, parentStyles);
  9315. return sprite;
  9316. }
  9317. };
  9318. /**
  9319. * @name Two.Utils.xhr
  9320. * @function
  9321. * @param {String} path
  9322. * @param {Function} callback
  9323. * @returns {XMLHttpRequest} The constructed and called XHR request.
  9324. * @description Canonical method to initiate `GET` requests in the browser. Mainly used by {@link Two#load} method.
  9325. */
  9326. function xhr(path, callback) {
  9327. var xhr = new XMLHttpRequest();
  9328. xhr.open('GET', path);
  9329. xhr.onreadystatechange = function() {
  9330. if (xhr.readyState === 4 && xhr.status === 200) {
  9331. callback(xhr.responseText);
  9332. }
  9333. };
  9334. xhr.send();
  9335. return xhr;
  9336. }
  9337. /**
  9338. * @name Two.ImageSequence
  9339. * @class
  9340. * @extends Two.Rectangle
  9341. * @param {String|String[]|Two.Texture|Two.Texture[]} paths - A list of URLs or {@link Two.Texture}s.
  9342. * @param {Number} [ox=0] - The initial `x` position of the Two.ImageSequence.
  9343. * @param {Number} [oy=0] - The initial `y` position of the Two.ImageSequence.
  9344. * @param {Number} [frameRate=30] - The frame rate at which the images should playback at.
  9345. * @description A convenient package to display still or animated images organized as a series of still images.
  9346. */
  9347. function ImageSequence(paths, ox, oy, frameRate) {
  9348. // Not using default constructor of Rectangle due to odd `beginning` / `ending` behavior.
  9349. // See: https://github.com/jonobr1/two.js/issues/383
  9350. Path.call(this, [
  9351. new Anchor(),
  9352. new Anchor(),
  9353. new Anchor(),
  9354. new Anchor()
  9355. ], true);
  9356. this._renderer.flagTextures = ImageSequence.FlagTextures.bind(this);
  9357. this._renderer.bindTextures = ImageSequence.BindTextures.bind(this);
  9358. this._renderer.unbindTextures = ImageSequence.UnbindTextures.bind(this);
  9359. this.noStroke();
  9360. this.noFill();
  9361. /**
  9362. * @name Two.ImageSequence#textures
  9363. * @property {Two.Texture[]} - A list of textures to be used as frames for animating the {@link Two.ImageSequence}.
  9364. */
  9365. if (Array.isArray(paths)) {
  9366. this.textures = paths.map(ImageSequence.GenerateTexture.bind(this));
  9367. } else {
  9368. // If just a single path convert into a single Two.Texture
  9369. this.textures = [ImageSequence.GenerateTexture(paths)];
  9370. }
  9371. this.origin = new Vector();
  9372. this._update();
  9373. this.translation.set(ox || 0, oy || 0);
  9374. /**
  9375. * @name Two.ImageSequence#frameRate
  9376. * @property {Number} - The number of frames to animate against per second.
  9377. */
  9378. if (typeof frameRate === 'number') {
  9379. this.frameRate = frameRate;
  9380. } else {
  9381. this.frameRate = ImageSequence.DefaultFrameRate;
  9382. }
  9383. /**
  9384. * @name Two.ImageSequence#index
  9385. * @property {Number} - The index of the current tile of the sprite to display. Defaults to `0`.
  9386. */
  9387. this.index = 0;
  9388. }
  9389. _.extend(ImageSequence, {
  9390. /**
  9391. * @name Two.ImageSequence.Properties
  9392. * @property {String[]} - A list of properties that are on every {@link Two.ImageSequence}.
  9393. */
  9394. Properties: [
  9395. 'frameRate',
  9396. 'index'
  9397. ],
  9398. /**
  9399. * @name Two.ImageSequence.DefaultFrameRate
  9400. * @property The default frame rate that {@link Two.ImageSequence#frameRate} is set to when instantiated.
  9401. */
  9402. DefaultFrameRate: 30,
  9403. /**
  9404. * @name Two.ImageSequence.FlagTextures
  9405. * @function
  9406. * @description Cached method to let renderers know textures have been updated on a {@link Two.ImageSequence}.
  9407. */
  9408. FlagTextures: function() {
  9409. this._flagTextures = true;
  9410. },
  9411. /**
  9412. * @name Two.ImageSequence.BindTextures
  9413. * @function
  9414. * @description Cached method to let {@link Two.ImageSequence} know textures have been added to the instance.
  9415. */
  9416. BindTextures: function(items) {
  9417. var i = items.length;
  9418. while (i--) {
  9419. items[i].bind(Events.Types.change, this._renderer.flagTextures);
  9420. }
  9421. this._renderer.flagTextures();
  9422. },
  9423. /**
  9424. * @name Two.ImageSequence.UnbindVertices
  9425. * @function
  9426. * @description Cached method to let {@link Two.ImageSequence} know textures have been removed from the instance.
  9427. */
  9428. UnbindTextures: function(items) {
  9429. var i = items.length;
  9430. while (i--) {
  9431. items[i].unbind(Events.Types.change, this._renderer.flagTextures);
  9432. }
  9433. this._renderer.flagTextures();
  9434. },
  9435. /**
  9436. * @name Two.ImageSequence.MakeObservable
  9437. * @function
  9438. * @param {Object} object - The object to make observable.
  9439. * @description Convenience function to apply observable qualities of a {@link Two.ImageSequence} to any object. Handy if you'd like to extend or inherit the {@link Two.ImageSequence} class on a custom class.
  9440. */
  9441. MakeObservable: function(obj) {
  9442. Rectangle.MakeObservable(obj);
  9443. _.each(ImageSequence.Properties, defineGetterSetter, obj);
  9444. Object.defineProperty(obj, 'textures', {
  9445. enumerable: true,
  9446. get: function() {
  9447. return this._textures;
  9448. },
  9449. set: function(textures) {
  9450. var bindTextures = this._renderer.bindTextures;
  9451. var unbindTextures = this._renderer.unbindTextures;
  9452. // Remove previous listeners
  9453. if (this._textures) {
  9454. this._textures
  9455. .unbind(Events.Types.insert, bindTextures)
  9456. .unbind(Events.Types.remove, unbindTextures);
  9457. }
  9458. // Create new Collection with copy of vertices
  9459. this._textures = new Collection((textures || []).slice(0));
  9460. // Listen for Collection changes and bind / unbind
  9461. this._textures
  9462. .bind(Events.Types.insert, bindTextures)
  9463. .bind(Events.Types.remove, unbindTextures);
  9464. // Bind Initial Textures
  9465. bindTextures(this._textures);
  9466. }
  9467. });
  9468. },
  9469. /**
  9470. * @name Two.ImageSequence.GenerateTexture
  9471. * @property {Function} - Shorthand function to prepare source image material into readable format by {@link Two.ImageSequence}.
  9472. * @param {String|Two.Texture} textureOrString - The texture or string to create a {@link Two.Texture} from.
  9473. * @description Function used internally by {@link Two.ImageSequence} to parse arguments and return {@link Two.Texture}s.
  9474. * @returns {Two.Texture}
  9475. */
  9476. GenerateTexture: function(obj) {
  9477. if (obj instanceof Texture) {
  9478. return obj;
  9479. } else if (typeof obj === 'string') {
  9480. return new Texture(obj);
  9481. }
  9482. }
  9483. });
  9484. _.extend(ImageSequence.prototype, Rectangle.prototype, {
  9485. constructor: ImageSequence,
  9486. /**
  9487. * @name Two.ImageSequence#_flagTextures
  9488. * @private
  9489. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#textures} need updating.
  9490. */
  9491. _flagTextures: false,
  9492. /**
  9493. * @name Two.ImageSequence#_flagFrameRate
  9494. * @private
  9495. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#frameRate} needs updating.
  9496. */
  9497. _flagFrameRate: false,
  9498. /**
  9499. * @name Two.ImageSequence#_flagIndex
  9500. * @private
  9501. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#index} needs updating.
  9502. */
  9503. _flagIndex: false,
  9504. // Private variables
  9505. /**
  9506. * @name Two.ImageSequence#_amount
  9507. * @private
  9508. * @property {Number} - Number of frames for a given {@link Two.ImageSequence}.
  9509. */
  9510. _amount: 1,
  9511. /**
  9512. * @name Two.ImageSequence#_duration
  9513. * @private
  9514. * @property {Number} - Number of milliseconds a {@link Two.ImageSequence}.
  9515. */
  9516. _duration: 0,
  9517. /**
  9518. * @name Two.ImageSequence#_index
  9519. * @private
  9520. * @property {Number} - The current frame the {@link Two.ImageSequence} is currently displaying.
  9521. */
  9522. _index: 0,
  9523. /**
  9524. * @name Two.ImageSequence#_startTime
  9525. * @private
  9526. * @property {Milliseconds} - Epoch time in milliseconds of when the {@link Two.ImageSequence} started.
  9527. */
  9528. _startTime: 0,
  9529. /**
  9530. * @name Two.ImageSequence#_playing
  9531. * @private
  9532. * @property {Boolean} - Dictates whether the {@link Two.ImageSequence} is animating or not.
  9533. */
  9534. _playing: false,
  9535. /**
  9536. * @name Two.ImageSequence#_firstFrame
  9537. * @private
  9538. * @property {Number} - The frame the {@link Two.ImageSequence} should start with.
  9539. */
  9540. _firstFrame: 0,
  9541. /**
  9542. * @name Two.ImageSequence#_lastFrame
  9543. * @private
  9544. * @property {Number} - The frame the {@link Two.ImageSequence} should end with.
  9545. */
  9546. _lastFrame: 0,
  9547. /**
  9548. * @name Two.ImageSequence#_playing
  9549. * @private
  9550. * @property {Boolean} - Dictates whether the {@link Two.ImageSequence} should loop or not.
  9551. */
  9552. _loop: true,
  9553. // Exposed through getter-setter
  9554. /**
  9555. * @name Two.ImageSequence#_textures
  9556. * @private
  9557. * @see {@link Two.ImageSequence#textures}
  9558. */
  9559. _textures: null,
  9560. /**
  9561. * @name Two.ImageSequence#_frameRate
  9562. * @private
  9563. * @see {@link Two.ImageSequence#frameRate}
  9564. */
  9565. _frameRate: 0,
  9566. /**
  9567. * @name Two.ImageSequence#_origin
  9568. * @private
  9569. * @see {@link Two.ImageSequence#origin}
  9570. */
  9571. _origin: null,
  9572. /**
  9573. * @name Two.ImageSequence#play
  9574. * @function
  9575. * @param {Number} [firstFrame=0] - The index of the frame to start the animation with.
  9576. * @param {Number} [lastFrame] - The index of the frame to end the animation with. Defaults to the last item in the {@link Two.ImageSequence#textures}.
  9577. * @param {Function} [onLastFrame] - Optional callback function to be triggered after playing the last frame. This fires multiple times when the image sequence is looped.
  9578. * @description Initiate animation playback of a {@link Two.ImageSequence}.
  9579. */
  9580. play: function(firstFrame, lastFrame, onLastFrame) {
  9581. this._playing = true;
  9582. this._firstFrame = 0;
  9583. this._lastFrame = this.amount - 1;
  9584. this._startTime = _.performance.now();
  9585. if (typeof firstFrame === 'number') {
  9586. this._firstFrame = firstFrame;
  9587. }
  9588. if (typeof lastFrame === 'number') {
  9589. this._lastFrame = lastFrame;
  9590. }
  9591. if (typeof onLastFrame === 'function') {
  9592. this._onLastFrame = onLastFrame;
  9593. } else {
  9594. delete this._onLastFrame;
  9595. }
  9596. if (this._index !== this._firstFrame) {
  9597. this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  9598. / this._frameRate;
  9599. }
  9600. return this;
  9601. },
  9602. /**
  9603. * @name Two.ImageSequence#pause
  9604. * @function
  9605. * @description Halt animation playback of a {@link Two.ImageSequence}.
  9606. */
  9607. pause: function() {
  9608. this._playing = false;
  9609. return this;
  9610. },
  9611. /**
  9612. * @name Two.ImageSequence#stop
  9613. * @function
  9614. * @description Halt animation playback of a {@link Two.ImageSequence} and set the current frame back to the first frame.
  9615. */
  9616. stop: function() {
  9617. this._playing = false;
  9618. this._index = this._firstFrame;
  9619. return this;
  9620. },
  9621. /**
  9622. * @name Two.ImageSequence#clone
  9623. * @function
  9624. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  9625. * @returns {Two.ImageSequence}
  9626. * @description Create a new instance of {@link Two.ImageSequence} with the same properties of the current image sequence.
  9627. */
  9628. clone: function(parent) {
  9629. var clone = new ImageSequence(this.textures, this.translation.x,
  9630. this.translation.y, this.frameRate);
  9631. clone._loop = this._loop;
  9632. if (this._playing) {
  9633. clone.play();
  9634. }
  9635. if (parent) {
  9636. parent.add(clone);
  9637. }
  9638. return clone;
  9639. },
  9640. /**
  9641. * @name Two.ImageSequence#toObject
  9642. * @function
  9643. * @returns {Object}
  9644. * @description Return a JSON compatible plain object that represents the path.
  9645. */
  9646. toObject: function() {
  9647. var object = Rectangle.prototype.toObject.call(this);
  9648. object.textures = this.textures.map(function(texture) {
  9649. return texture.toObject();
  9650. });
  9651. object.frameRate = this.frameRate;
  9652. object.index = this.index;
  9653. object._firstFrame = this._firstFrame;
  9654. object._lastFrame = this._lastFrame;
  9655. object._loop = this._loop;
  9656. return object;
  9657. },
  9658. /**
  9659. * @name Two.ImageSequence#_update
  9660. * @function
  9661. * @private
  9662. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  9663. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  9664. * @nota-bene Try not to call this method more than once a frame.
  9665. */
  9666. _update: function() {
  9667. var effects = this._textures;
  9668. var width, height, elapsed, amount, duration, texture;
  9669. var index, frames;
  9670. if (this._flagTextures) {
  9671. this._amount = effects.length;
  9672. }
  9673. if (this._flagFrameRate) {
  9674. this._duration = 1000 * this._amount / this._frameRate;
  9675. }
  9676. if (this._playing && this._frameRate > 0) {
  9677. amount = this._amount;
  9678. if (_.isNaN(this._lastFrame)) {
  9679. this._lastFrame = amount - 1;
  9680. }
  9681. // TODO: Offload perf logic to instance of `Two`.
  9682. elapsed = _.performance.now() - this._startTime;
  9683. frames = this._lastFrame + 1;
  9684. duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  9685. if (this._loop) {
  9686. elapsed = elapsed % duration;
  9687. } else {
  9688. elapsed = Math.min(elapsed, duration);
  9689. }
  9690. index = lerp(this._firstFrame, frames, elapsed / duration);
  9691. index = Math.floor(index);
  9692. if (index !== this._index) {
  9693. this._index = index;
  9694. texture = effects[this._index];
  9695. if (texture.loaded) {
  9696. width = texture.image.width;
  9697. height = texture.image.height;
  9698. if (this.width !== width) {
  9699. this.width = width;
  9700. }
  9701. if (this.height !== height) {
  9702. this.height = height;
  9703. }
  9704. this.fill = texture;
  9705. if (index >= this._lastFrame - 1 && this._onLastFrame) {
  9706. this._onLastFrame(); // Shortcut for chainable sprite animations
  9707. }
  9708. }
  9709. }
  9710. } else if (this._flagIndex || !(this.fill instanceof Texture)) {
  9711. texture = effects[this._index];
  9712. if (texture.loaded) {
  9713. width = texture.image.width;
  9714. height = texture.image.height;
  9715. if (this.width !== width) {
  9716. this.width = width;
  9717. }
  9718. if (this.height !== height) {
  9719. this.height = height;
  9720. }
  9721. }
  9722. this.fill = texture;
  9723. }
  9724. Rectangle.prototype._update.call(this);
  9725. return this;
  9726. },
  9727. /**
  9728. * @name Two.ImageSequence#flagReset
  9729. * @function
  9730. * @private
  9731. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  9732. */
  9733. flagReset: function() {
  9734. this._flagTextures = this._flagFrameRate = false;
  9735. Rectangle.prototype.flagReset.call(this);
  9736. return this;
  9737. }
  9738. });
  9739. ImageSequence.MakeObservable(ImageSequence.prototype);
  9740. var TWO_PI$2 = Math.PI * 2, HALF_PI = Math.PI / 2;
  9741. /**
  9742. * @name Two.ArcSegment
  9743. * @class
  9744. * @extends Two.Path
  9745. * @param {Number} [x=0] - The x position of the arc segment.
  9746. * @param {Number} [y=0] - The y position of the arc segment.
  9747. * @param {Number} [innerRadius=0] - The inner radius value of the arc segment.
  9748. * @param {Number} [outerRadius=0] - The outer radius value of the arc segment.
  9749. * @param {Number} [startAngle=0] - The start angle of the arc segment in Number.
  9750. * @param {Number} [endAngle=6.2831] - The end angle of the arc segment in Number.
  9751. * @param {Number} [resolution=24] - The number of vertices used to construct the arc segment.
  9752. */
  9753. function ArcSegment(ox, oy, ir, or, sa, ea, res) {
  9754. var amount = res || (Constants.Resolution * 3);
  9755. var points = [];
  9756. for (var i = 0; i < amount; i++) {
  9757. points.push(new Anchor());
  9758. }
  9759. Path.call(this, points, true, false, true);
  9760. /**
  9761. * @name Two.ArcSegment#innerRadius
  9762. * @property {Number} - The size of the inner radius of the arc segment.
  9763. */
  9764. if (typeof ir === 'number') {
  9765. this.innerRadius = ir;
  9766. }
  9767. /**
  9768. * @name Two.ArcSegment#outerRadius
  9769. * @property {Number} - The size of the outer radius of the arc segment.
  9770. */
  9771. if (typeof or === 'number') {
  9772. this.outerRadius = or;
  9773. }
  9774. /**
  9775. * @name Two.ArcSegment#startRadius
  9776. * @property {Number} - The angle of one side for the arc segment.
  9777. */
  9778. if (typeof sa === 'number') {
  9779. this.startAngle = sa;
  9780. }
  9781. /**
  9782. * @name Two.ArcSegment#endAngle
  9783. * @property {Number} - The angle of the other side for the arc segment.
  9784. */
  9785. if (typeof ea === 'number') {
  9786. this.endAngle = ea;
  9787. }
  9788. this._update();
  9789. if (typeof ox === 'number') {
  9790. this.translation.x = ox;
  9791. }
  9792. if (typeof oy === 'number') {
  9793. this.translation.y = oy;
  9794. }
  9795. }
  9796. _.extend(ArcSegment, {
  9797. /**
  9798. * @name Two.ArcSegment.Properties
  9799. * @property {String[]} - A list of properties that are on every {@link Two.ArcSegment}.
  9800. */
  9801. Properties: ['startAngle', 'endAngle', 'innerRadius', 'outerRadius'],
  9802. /**
  9803. * @name Two.ArcSegment.MakeObservable
  9804. * @function
  9805. * @param {Object} object - The object to make observable.
  9806. * @description Convenience function to apply observable qualities of a {@link Two.ArcSegment} to any object. Handy if you'd like to extend the {@link Two.ArcSegment} class on a custom class.
  9807. */
  9808. MakeObservable: function(obj) {
  9809. Path.MakeObservable(obj);
  9810. _.each(ArcSegment.Properties, defineGetterSetter, obj);
  9811. }
  9812. });
  9813. _.extend(ArcSegment.prototype, Path.prototype, {
  9814. constructor: ArcSegment,
  9815. /**
  9816. * @name Two.ArcSegment#_flagStartAngle
  9817. * @private
  9818. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#startAngle} needs updating.
  9819. */
  9820. _flagStartAngle: false,
  9821. /**
  9822. * @name Two.ArcSegment#_flagEndAngle
  9823. * @private
  9824. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#endAngle} needs updating.
  9825. */
  9826. _flagEndAngle: false,
  9827. /**
  9828. * @name Two.ArcSegment#_flagInnerRadius
  9829. * @private
  9830. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#innerRadius} needs updating.
  9831. */
  9832. _flagInnerRadius: false,
  9833. /**
  9834. * @name Two.ArcSegment#_flagOuterRadius
  9835. * @private
  9836. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#outerRadius} needs updating.
  9837. */
  9838. _flagOuterRadius: false,
  9839. /**
  9840. * @name Two.ArcSegment#_startAngle
  9841. * @private
  9842. * @see {@link Two.ArcSegment#startAngle}
  9843. */
  9844. _startAngle: 0,
  9845. /**
  9846. * @name Two.ArcSegment#_endAngle
  9847. * @private
  9848. * @see {@link Two.ArcSegment#endAngle}
  9849. */
  9850. _endAngle: TWO_PI$2,
  9851. /**
  9852. * @name Two.ArcSegment#_innerRadius
  9853. * @private
  9854. * @see {@link Two.ArcSegment#innerRadius}
  9855. */
  9856. _innerRadius: 0,
  9857. /**
  9858. * @name Two.ArcSegment#_outerRadius
  9859. * @private
  9860. * @see {@link Two.ArcSegment#outerRadius}
  9861. */
  9862. _outerRadius: 0,
  9863. /**
  9864. * @name Two.ArcSegment#_update
  9865. * @function
  9866. * @private
  9867. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  9868. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  9869. * @nota-bene Try not to call this method more than once a frame.
  9870. */
  9871. _update: function() {
  9872. if (this._flagVertices || this._flagStartAngle || this._flagEndAngle
  9873. || this._flagInnerRadius || this._flagOuterRadius) {
  9874. var sa = this._startAngle;
  9875. var ea = this._endAngle;
  9876. var ir = this._innerRadius;
  9877. var or = this._outerRadius;
  9878. var connected = mod(sa, TWO_PI$2) === mod(ea, TWO_PI$2);
  9879. var punctured = ir > 0;
  9880. var vertices = this.vertices;
  9881. var length = (punctured ? vertices.length / 2 : vertices.length);
  9882. var command, id = 0;
  9883. if (connected) {
  9884. length--;
  9885. } else if (!punctured) {
  9886. length -= 2;
  9887. }
  9888. /**
  9889. * Outer Circle
  9890. */
  9891. for (var i = 0, last = length - 1; i < length; i++) {
  9892. var pct = i / last;
  9893. var v = vertices[id];
  9894. var theta = pct * (ea - sa) + sa;
  9895. var step = (ea - sa) / length;
  9896. var x = or * Math.cos(theta);
  9897. var y = or * Math.sin(theta);
  9898. switch (i) {
  9899. case 0:
  9900. command = Commands.move;
  9901. break;
  9902. default:
  9903. command = Commands.curve;
  9904. }
  9905. v.command = command;
  9906. v.x = x;
  9907. v.y = y;
  9908. v.controls.left.clear();
  9909. v.controls.right.clear();
  9910. if (v.command === Commands.curve) {
  9911. var amp = or * step / Math.PI;
  9912. v.controls.left.x = amp * Math.cos(theta - HALF_PI);
  9913. v.controls.left.y = amp * Math.sin(theta - HALF_PI);
  9914. v.controls.right.x = amp * Math.cos(theta + HALF_PI);
  9915. v.controls.right.y = amp * Math.sin(theta + HALF_PI);
  9916. if (i === 1) {
  9917. v.controls.left.multiplyScalar(2);
  9918. }
  9919. if (i === last) {
  9920. v.controls.right.multiplyScalar(2);
  9921. }
  9922. }
  9923. id++;
  9924. }
  9925. if (punctured) {
  9926. if (connected) {
  9927. vertices[id].command = Commands.close;
  9928. id++;
  9929. } else {
  9930. length--;
  9931. last = length - 1;
  9932. }
  9933. /**
  9934. * Inner Circle
  9935. */
  9936. for (i = 0; i < length; i++) {
  9937. pct = i / last;
  9938. v = vertices[id];
  9939. theta = (1 - pct) * (ea - sa) + sa;
  9940. step = (ea - sa) / length;
  9941. x = ir * Math.cos(theta);
  9942. y = ir * Math.sin(theta);
  9943. command = Commands.curve;
  9944. if (i <= 0) {
  9945. command = connected ? Commands.move : Commands.line;
  9946. }
  9947. v.command = command;
  9948. v.x = x;
  9949. v.y = y;
  9950. v.controls.left.clear();
  9951. v.controls.right.clear();
  9952. if (v.command === Commands.curve) {
  9953. amp = ir * step / Math.PI;
  9954. v.controls.left.x = amp * Math.cos(theta + HALF_PI);
  9955. v.controls.left.y = amp * Math.sin(theta + HALF_PI);
  9956. v.controls.right.x = amp * Math.cos(theta - HALF_PI);
  9957. v.controls.right.y = amp * Math.sin(theta - HALF_PI);
  9958. if (i === 1) {
  9959. v.controls.left.multiplyScalar(2);
  9960. }
  9961. if (i === last) {
  9962. v.controls.right.multiplyScalar(2);
  9963. }
  9964. }
  9965. id++;
  9966. }
  9967. // Final Point
  9968. vertices[id].copy(vertices[0]);
  9969. vertices[id].command = Commands.line;
  9970. } else if (!connected) {
  9971. vertices[id].command = Commands.line;
  9972. vertices[id].x = 0;
  9973. vertices[id].y = 0;
  9974. id++;
  9975. // Final Point
  9976. vertices[id].copy(vertices[0]);
  9977. vertices[id].command = Commands.line;
  9978. }
  9979. }
  9980. Path.prototype._update.call(this);
  9981. return this;
  9982. },
  9983. /**
  9984. * @name Two.ArcSegment#flagReset
  9985. * @function
  9986. * @private
  9987. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  9988. */
  9989. flagReset: function() {
  9990. Path.prototype.flagReset.call(this);
  9991. this._flagStartAngle = this._flagEndAngle
  9992. = this._flagInnerRadius = this._flagOuterRadius = false;
  9993. return this;
  9994. },
  9995. /**
  9996. * @name Two.ArcSegment#clone
  9997. * @function
  9998. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  9999. * @returns {Two.ArcSegment}
  10000. * @description Create a new instance of {@link Two.ArcSegment} with the same properties of the current path.
  10001. */
  10002. clone: function(parent) {
  10003. var ir = this.innerRadius;
  10004. var or = this.outerRadius;
  10005. var sa = this.startAngle;
  10006. var ea = this.endAngle;
  10007. var resolution = this.vertices.length;
  10008. var clone = new ArcSegment(0, 0, ir, or, sa, ea, resolution);
  10009. clone.translation.copy(this.translation);
  10010. clone.rotation = this.rotation;
  10011. clone.scale = this.scale;
  10012. clone.skewX = this.skewX;
  10013. clone.skewY = this.skewY;
  10014. if (this.matrix.manual) {
  10015. clone.matrix.copy(this.matrix);
  10016. }
  10017. _.each(Path.Properties, function(k) {
  10018. clone[k] = this[k];
  10019. }, this);
  10020. if (parent) {
  10021. parent.add(clone);
  10022. }
  10023. return clone;
  10024. },
  10025. /**
  10026. * @name Two.ArcSegment#toObject
  10027. * @function
  10028. * @returns {Object}
  10029. * @description Return a JSON compatible plain object that represents the path.
  10030. */
  10031. toObject: function() {
  10032. var object = Path.prototype.toObject.call(this);
  10033. _.each(ArcSegment.Properties, function(property) {
  10034. object[property] = this[property];
  10035. }, this);
  10036. return object;
  10037. }
  10038. });
  10039. ArcSegment.MakeObservable(ArcSegment.prototype);
  10040. var TWO_PI$1 = Math.PI * 2, cos$1 = Math.cos, sin$1 = Math.sin;
  10041. /**
  10042. * @name Two.Polygon
  10043. * @class
  10044. * @extends Two.Path
  10045. * @param {Number} [x=0] - The x position of the polygon.
  10046. * @param {Number} [y=0] - The y position of the polygon.
  10047. * @param {Number} [radius=0] - The radius value of the polygon.
  10048. * @param {Number} [sides=12] - The number of vertices used to construct the polygon.
  10049. */
  10050. function Polygon(ox, oy, r, sides) {
  10051. sides = Math.max(sides || 0, 3);
  10052. Path.call(this);
  10053. this.closed = true;
  10054. this.automatic = false;
  10055. /**
  10056. * @name Two.Polygon#width
  10057. * @property {Number} - The size of the width of the polygon.
  10058. */
  10059. if (typeof r === 'number') {
  10060. this.width = r * 2;
  10061. }
  10062. /**
  10063. * @name Two.Polygon#height
  10064. * @property {Number} - The size of the height of the polygon.
  10065. */
  10066. if (typeof r === 'number') {
  10067. this.height = r * 2;
  10068. }
  10069. /**
  10070. * @name Two.Polygon#sides
  10071. * @property {Number} - The amount of sides the polyogn has.
  10072. */
  10073. if (typeof sides === 'number') {
  10074. this.sides = sides;
  10075. }
  10076. this._update();
  10077. if (typeof ox === 'number') {
  10078. this.translation.x = ox;
  10079. }
  10080. if (typeof oy === 'number') {
  10081. this.translation.y = oy;
  10082. }
  10083. }
  10084. _.extend(Polygon, {
  10085. /**
  10086. * @name Two.Polygon.Properties
  10087. * @property {String[]} - A list of properties that are on every {@link Two.Polygon}.
  10088. */
  10089. Properties: ['width', 'height', 'sides'],
  10090. /**
  10091. * @name Two.Polygon.MakeObservable
  10092. * @function
  10093. * @param {Object} object - The object to make observable.
  10094. * @description Convenience function to apply observable qualities of a {@link Two.Polygon} to any object. Handy if you'd like to extend the {@link Two.Polygon} class on a custom class.
  10095. */
  10096. MakeObservable: function(obj) {
  10097. Path.MakeObservable(obj);
  10098. _.each(Polygon.Properties, defineGetterSetter, obj);
  10099. }
  10100. });
  10101. _.extend(Polygon.prototype, Path.prototype, {
  10102. constructor: Polygon,
  10103. /**
  10104. * @name Two.Polygon#_flagWidth
  10105. * @private
  10106. * @property {Boolean} - Determines whether the {@link Two.Polygon#width} needs updating.
  10107. */
  10108. _flagWidth: false,
  10109. /**
  10110. * @name Two.Polygon#_flagHeight
  10111. * @private
  10112. * @property {Boolean} - Determines whether the {@link Two.Polygon#height} needs updating.
  10113. */
  10114. _flagHeight: false,
  10115. /**
  10116. * @name Two.Polygon#_flagSides
  10117. * @private
  10118. * @property {Boolean} - Determines whether the {@link Two.Polygon#sides} needs updating.
  10119. */
  10120. _flagSides: false,
  10121. /**
  10122. * @name Two.Polygon#_width
  10123. * @private
  10124. * @see {@link Two.Polygon#width}
  10125. */
  10126. _width: 0,
  10127. /**
  10128. * @name Two.Polygon#_height
  10129. * @private
  10130. * @see {@link Two.Polygon#height}
  10131. */
  10132. _height: 0,
  10133. /**
  10134. * @name Two.Polygon#_sides
  10135. * @private
  10136. * @see {@link Two.Polygon#sides}
  10137. */
  10138. _sides: 0,
  10139. /**
  10140. * @name Two.Polygon#_update
  10141. * @function
  10142. * @private
  10143. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  10144. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  10145. * @nota-bene Try not to call this method more than once a frame.
  10146. */
  10147. _update: function() {
  10148. if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagSides) {
  10149. var sides = this._sides;
  10150. var amount = sides + 1;
  10151. var length = this.vertices.length;
  10152. if (length > sides) {
  10153. this.vertices.splice(sides - 1, length - sides);
  10154. length = sides;
  10155. }
  10156. for (var i = 0; i < amount; i++) {
  10157. var pct = (i + 0.5) / sides;
  10158. var theta = TWO_PI$1 * pct + Math.PI / 2;
  10159. var x = this._width * cos$1(theta) / 2;
  10160. var y = this._height * sin$1(theta) / 2;
  10161. if (i >= length) {
  10162. this.vertices.push(new Anchor(x, y));
  10163. } else {
  10164. this.vertices[i].set(x, y);
  10165. }
  10166. this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
  10167. }
  10168. }
  10169. Path.prototype._update.call(this);
  10170. return this;
  10171. },
  10172. /**
  10173. * @name Two.Polygon#flagReset
  10174. * @function
  10175. * @private
  10176. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  10177. */
  10178. flagReset: function() {
  10179. this._flagWidth = this._flagHeight = this._flagSides = false;
  10180. Path.prototype.flagReset.call(this);
  10181. return this;
  10182. },
  10183. /**
  10184. * @name Two.Polygon#clone
  10185. * @function
  10186. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  10187. * @returns {Two.Polygon}
  10188. * @description Create a new instance of {@link Two.Polygon} with the same properties of the current path.
  10189. */
  10190. clone: function(parent) {
  10191. var clone = new Polygon(0, 0, this.radius, this.sides);
  10192. clone.translation.copy(this.translation);
  10193. clone.rotation = this.rotation;
  10194. clone.scale = this.scale;
  10195. clone.skewX = this.skewX;
  10196. clone.skewY = this.skewY;
  10197. if (this.matrix.manual) {
  10198. clone.matrix.copy(this.matrix);
  10199. }
  10200. _.each(Path.Properties, function(k) {
  10201. clone[k] = this[k];
  10202. }, this);
  10203. if (parent) {
  10204. parent.add(clone);
  10205. }
  10206. return clone;
  10207. },
  10208. /**
  10209. * @name Two.Polygon#toObject
  10210. * @function
  10211. * @returns {Object}
  10212. * @description Return a JSON compatible plain object that represents the path.
  10213. */
  10214. toObject: function() {
  10215. var object = Path.prototype.toObject.call(this);
  10216. _.each(Polygon.Properties, function(property) {
  10217. object[property] = this[property];
  10218. }, this);
  10219. return object;
  10220. }
  10221. });
  10222. Polygon.MakeObservable(Polygon.prototype);
  10223. var TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  10224. /**
  10225. * @name Two.Star
  10226. * @class
  10227. * @extends Two.Path
  10228. * @param {Number} [x=0] - The x position of the star.
  10229. * @param {Number} [y=0] - The y position of the star.
  10230. * @param {Number} [innerRadius=0] - The inner radius value of the star.
  10231. * @param {Number} [outerRadius=0] - The outer radius value of the star.
  10232. * @param {Number} [sides=5] - The number of sides used to construct the star.
  10233. */
  10234. function Star(ox, oy, ir, or, sides) {
  10235. if (arguments.length <= 3) {
  10236. or = ir;
  10237. ir = or / 2;
  10238. }
  10239. if (typeof sides !== 'number' || sides <= 0) {
  10240. sides = 5;
  10241. }
  10242. Path.call(this);
  10243. this.closed = true;
  10244. this.automatic = false;
  10245. /**
  10246. * @name Two.Star#innerRadius
  10247. * @property {Number} - The size of the inner radius of the star.
  10248. */
  10249. if (typeof ir === 'number') {
  10250. this.innerRadius = ir;
  10251. }
  10252. /**
  10253. * @name Two.Star#outerRadius
  10254. * @property {Number} - The size of the outer radius of the star.
  10255. */
  10256. if (typeof or === 'number') {
  10257. this.outerRadius = or;
  10258. }
  10259. /**
  10260. * @name Two.Star#sides
  10261. * @property {Number} - The amount of sides the star has.
  10262. */
  10263. if (typeof sides === 'number') {
  10264. this.sides = sides;
  10265. }
  10266. this._update();
  10267. if (typeof ox === 'number') {
  10268. this.translation.x = ox;
  10269. }
  10270. if (typeof oy === 'number') {
  10271. this.translation.y = oy;
  10272. }
  10273. }
  10274. _.extend(Star, {
  10275. /**
  10276. * @name Two.Star.Properties
  10277. * @property {String[]} - A list of properties that are on every {@link Two.Star}.
  10278. */
  10279. Properties: ['innerRadius', 'outerRadius', 'sides'],
  10280. /**
  10281. * @name Two.Star.MakeObservable
  10282. * @function
  10283. * @param {Object} object - The object to make observable.
  10284. * @description Convenience function to apply observable qualities of a {@link Two.Star} to any object. Handy if you'd like to extend the {@link Two.Star} class on a custom class.
  10285. */
  10286. MakeObservable: function(obj) {
  10287. Path.MakeObservable(obj);
  10288. _.each(Star.Properties, defineGetterSetter, obj);
  10289. }
  10290. });
  10291. _.extend(Star.prototype, Path.prototype, {
  10292. constructor: Star,
  10293. /**
  10294. * @name Two.Star#_flagInnerRadius
  10295. * @private
  10296. * @property {Boolean} - Determines whether the {@link Two.Star#innerRadius} needs updating.
  10297. */
  10298. _flagInnerRadius: false,
  10299. /**
  10300. * @name Two.Star#_flagOuterRadius
  10301. * @private
  10302. * @property {Boolean} - Determines whether the {@link Two.Star#outerRadius} needs updating.
  10303. */
  10304. _flagOuterRadius: false,
  10305. /**
  10306. * @name Two.Star#_flagSides
  10307. * @private
  10308. * @property {Boolean} - Determines whether the {@link Two.Star#sides} needs updating.
  10309. */
  10310. _flagSides: false,
  10311. /**
  10312. * @name Two.Star#_innerRadius
  10313. * @private
  10314. * @see {@link Two.Star#innerRadius}
  10315. */
  10316. _innerRadius: 0,
  10317. /**
  10318. * @name Two.Star#_outerRadius
  10319. * @private
  10320. * @see {@link Two.Star#outerRadius}
  10321. */
  10322. _outerRadius: 0,
  10323. /**
  10324. * @name Two.Star#_sides
  10325. * @private
  10326. * @see {@link Two.Star#sides}
  10327. */
  10328. _sides: 0,
  10329. /**
  10330. * @name Two.Star#_update
  10331. * @function
  10332. * @private
  10333. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  10334. * @description This is called before rendering happens by the renderer. This applies all changes necessary so that rendering is up-to-date but not updated more than it needs to be.
  10335. * @nota-bene Try not to call this method more than once a frame.
  10336. */
  10337. _update: function() {
  10338. if (this._flagVertices || this._flagInnerRadius || this._flagOuterRadius || this._flagSides) {
  10339. var sides = this._sides * 2;
  10340. var amount = sides + 1;
  10341. var length = this.vertices.length;
  10342. if (length > sides) {
  10343. this.vertices.splice(sides - 1, length - sides);
  10344. length = sides;
  10345. }
  10346. for (var i = 0; i < amount; i++) {
  10347. var pct = (i + 0.5) / sides;
  10348. var theta = TWO_PI * pct;
  10349. var r = (!(i % 2) ? this._innerRadius : this._outerRadius) / 2;
  10350. var x = r * cos(theta);
  10351. var y = r * sin(theta);
  10352. if (i >= length) {
  10353. this.vertices.push(new Anchor(x, y));
  10354. } else {
  10355. this.vertices[i].set(x, y);
  10356. }
  10357. this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
  10358. }
  10359. }
  10360. Path.prototype._update.call(this);
  10361. return this;
  10362. },
  10363. /**
  10364. * @name Two.Star#flagReset
  10365. * @function
  10366. * @private
  10367. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  10368. */
  10369. flagReset: function() {
  10370. this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false;
  10371. Path.prototype.flagReset.call(this);
  10372. return this;
  10373. },
  10374. /**
  10375. * @name Two.Star#clone
  10376. * @function
  10377. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  10378. * @returns {Two.Star}
  10379. * @description Create a new instance of {@link Two.Star} with the same properties of the current path.
  10380. */
  10381. clone: function(parent) {
  10382. var ir = this.innerRadius;
  10383. var or = this.outerRadius;
  10384. var sides = this.sides;
  10385. var clone = new Star(0, 0, ir, or, sides);
  10386. clone.translation.copy(this.translation);
  10387. clone.rotation = this.rotation;
  10388. clone.scale = this.scale;
  10389. clone.skewX = this.skewX;
  10390. clone.skewY = this.skewY;
  10391. if (this.matrix.manual) {
  10392. clone.matrix.copy(this.matrix);
  10393. }
  10394. _.each(Path.Properties, function(k) {
  10395. clone[k] = this[k];
  10396. }, this);
  10397. if (parent) {
  10398. parent.add(clone);
  10399. }
  10400. return clone;
  10401. },
  10402. /**
  10403. * @name Two.Star#toObject
  10404. * @function
  10405. * @returns {Object}
  10406. * @description Return a JSON compatible plain object that represents the path.
  10407. */
  10408. toObject: function() {
  10409. var object = Path.prototype.toObject.call(this);
  10410. _.each(Star.Properties, function(property) {
  10411. object[property] = this[property];
  10412. }, this);
  10413. return object;
  10414. }
  10415. });
  10416. Star.MakeObservable(Star.prototype);
  10417. var svg = {
  10418. version: 1.1,
  10419. ns: 'http://www.w3.org/2000/svg',
  10420. xlink: 'http://www.w3.org/1999/xlink',
  10421. alignments: {
  10422. left: 'start',
  10423. center: 'middle',
  10424. right: 'end'
  10425. },
  10426. // Create an svg namespaced element.
  10427. createElement: function(name, attrs) {
  10428. var tag = name;
  10429. var elem = document.createElementNS(svg.ns, tag);
  10430. if (tag === 'svg') {
  10431. attrs = _.defaults(attrs || {}, {
  10432. version: svg.version
  10433. });
  10434. }
  10435. if (attrs && Object.keys(attrs).length > 0) {
  10436. svg.setAttributes(elem, attrs);
  10437. }
  10438. return elem;
  10439. },
  10440. // Add attributes from an svg element.
  10441. setAttributes: function(elem, attrs) {
  10442. var keys = Object.keys(attrs);
  10443. for (var i = 0; i < keys.length; i++) {
  10444. if (/href/.test(keys[i])) {
  10445. elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]);
  10446. } else {
  10447. elem.setAttribute(keys[i], attrs[keys[i]]);
  10448. }
  10449. }
  10450. return this;
  10451. },
  10452. // Remove attributes from an svg element.
  10453. removeAttributes: function(elem, attrs) {
  10454. for (var key in attrs) {
  10455. elem.removeAttribute(key);
  10456. }
  10457. return this;
  10458. },
  10459. // Turn a set of vertices into a string for the d property of a path
  10460. // element. It is imperative that the string collation is as fast as
  10461. // possible, because this call will be happening multiple times a
  10462. // second.
  10463. toString: function(points, closed) {
  10464. var l = points.length,
  10465. last = l - 1,
  10466. d, // The elusive last Commands.move point
  10467. string = '';
  10468. for (var i = 0; i < l; i++) {
  10469. var b = points[i];
  10470. var command;
  10471. var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0);
  10472. var next = closed ? mod(i + 1, l) : Math.min(i + 1, last);
  10473. var a = points[prev];
  10474. var c = points[next];
  10475. var vx, vy, ux, uy, ar, bl, br, cl;
  10476. var rx, ry, xAxisRotation, largeArcFlag, sweepFlag;
  10477. // Access x and y directly,
  10478. // bypassing the getter
  10479. var x = toFixed(b.x);
  10480. var y = toFixed(b.y);
  10481. switch (b.command) {
  10482. case Commands.close:
  10483. command = Commands.close;
  10484. break;
  10485. case Commands.arc:
  10486. rx = b.rx;
  10487. ry = b.ry;
  10488. xAxisRotation = b.xAxisRotation;
  10489. largeArcFlag = b.largeArcFlag;
  10490. sweepFlag = b.sweepFlag;
  10491. command = Commands.arc + ' ' + rx + ' ' + ry + ' '
  10492. + xAxisRotation + ' ' + largeArcFlag + ' ' + sweepFlag + ' '
  10493. + x + ' ' + y;
  10494. break;
  10495. case Commands.curve:
  10496. ar = (a.controls && a.controls.right) || Vector.zero;
  10497. bl = (b.controls && b.controls.left) || Vector.zero;
  10498. if (a.relative) {
  10499. vx = toFixed((ar.x + a.x));
  10500. vy = toFixed((ar.y + a.y));
  10501. } else {
  10502. vx = toFixed(ar.x);
  10503. vy = toFixed(ar.y);
  10504. }
  10505. if (b.relative) {
  10506. ux = toFixed((bl.x + b.x));
  10507. uy = toFixed((bl.y + b.y));
  10508. } else {
  10509. ux = toFixed(bl.x);
  10510. uy = toFixed(bl.y);
  10511. }
  10512. command = ((i === 0) ? Commands.move : Commands.curve) +
  10513. ' ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  10514. break;
  10515. case Commands.move:
  10516. d = b;
  10517. command = Commands.move + ' ' + x + ' ' + y;
  10518. break;
  10519. default:
  10520. command = b.command + ' ' + x + ' ' + y;
  10521. }
  10522. // Add a final point and close it off
  10523. if (i >= last && closed) {
  10524. if (b.command === Commands.curve) {
  10525. // Make sure we close to the most previous Commands.move
  10526. c = d;
  10527. br = (b.controls && b.controls.right) || b;
  10528. cl = (c.controls && c.controls.left) || c;
  10529. if (b.relative) {
  10530. vx = toFixed((br.x + b.x));
  10531. vy = toFixed((br.y + b.y));
  10532. } else {
  10533. vx = toFixed(br.x);
  10534. vy = toFixed(br.y);
  10535. }
  10536. if (c.relative) {
  10537. ux = toFixed((cl.x + c.x));
  10538. uy = toFixed((cl.y + c.y));
  10539. } else {
  10540. ux = toFixed(cl.x);
  10541. uy = toFixed(cl.y);
  10542. }
  10543. x = toFixed(c.x);
  10544. y = toFixed(c.y);
  10545. command +=
  10546. ' C ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  10547. }
  10548. if (b.command !== Commands.close) {
  10549. command += ' Z';
  10550. }
  10551. }
  10552. string += command + ' ';
  10553. }
  10554. return string;
  10555. },
  10556. getClip: function(shape, domElement) {
  10557. var clip = shape._renderer.clip;
  10558. if (!clip) {
  10559. clip = shape._renderer.clip = svg.createElement('clipPath', {
  10560. 'clip-rule': 'nonzero'
  10561. });
  10562. domElement.defs.appendChild(clip);
  10563. }
  10564. return clip;
  10565. },
  10566. group: {
  10567. // TODO: Can speed up.
  10568. // TODO: How does this effect a f
  10569. appendChild: function(object) {
  10570. var elem = object._renderer.elem;
  10571. if (!elem) {
  10572. return;
  10573. }
  10574. var tag = elem.nodeName;
  10575. if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) {
  10576. return;
  10577. }
  10578. this.elem.appendChild(elem);
  10579. },
  10580. removeChild: function(object) {
  10581. var elem = object._renderer.elem;
  10582. if (!elem || elem.parentNode != this.elem) {
  10583. return;
  10584. }
  10585. var tag = elem.nodeName;
  10586. if (!tag) {
  10587. return;
  10588. }
  10589. // Defer subtractions while clipping.
  10590. if (object._clip) {
  10591. return;
  10592. }
  10593. this.elem.removeChild(elem);
  10594. },
  10595. orderChild: function(object) {
  10596. this.elem.appendChild(object._renderer.elem);
  10597. },
  10598. renderChild: function(child) {
  10599. svg[child._renderer.type].render.call(child, this);
  10600. },
  10601. render: function(domElement) {
  10602. // Shortcut for hidden objects.
  10603. // Doesn't reset the flags, so changes are stored and
  10604. // applied once the object is visible again
  10605. if ((!this._visible && !this._flagVisible)
  10606. || (this._opacity === 0 && !this._flagOpacity)) {
  10607. return this;
  10608. }
  10609. this._update();
  10610. if (!this._renderer.elem) {
  10611. this._renderer.elem = svg.createElement('g', {
  10612. id: this.id
  10613. });
  10614. domElement.appendChild(this._renderer.elem);
  10615. }
  10616. // _Update styles for the <g>
  10617. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10618. var context = {
  10619. domElement: domElement,
  10620. elem: this._renderer.elem
  10621. };
  10622. if (flagMatrix) {
  10623. this._renderer.elem.setAttribute('transform', 'matrix(' + this._matrix.toString() + ')');
  10624. }
  10625. for (var i = 0; i < this.children.length; i++) {
  10626. var child = this.children[i];
  10627. svg[child._renderer.type].render.call(child, domElement);
  10628. }
  10629. if (this._flagId) {
  10630. this._renderer.elem.setAttribute('id', this._id);
  10631. }
  10632. if (this._flagOpacity) {
  10633. this._renderer.elem.setAttribute('opacity', this._opacity);
  10634. }
  10635. if (this._flagVisible) {
  10636. this._renderer.elem.setAttribute('display', this._visible ? 'inline' : 'none');
  10637. }
  10638. if (this._flagClassName) {
  10639. this._renderer.elem.setAttribute('class', this.classList.join(' '));
  10640. }
  10641. if (this._flagAdditions) {
  10642. this.additions.forEach(svg.group.appendChild, context);
  10643. }
  10644. if (this._flagSubtractions) {
  10645. this.subtractions.forEach(svg.group.removeChild, context);
  10646. }
  10647. if (this._flagOrder) {
  10648. this.children.forEach(svg.group.orderChild, context);
  10649. }
  10650. // Commented two-way functionality of clips / masks with groups and
  10651. // polygons. Uncomment when this bug is fixed:
  10652. // https://code.google.com/p/chromium/issues/detail?id=370951
  10653. // if (this._flagClip) {
  10654. // clip = svg.getClip(this, domElement);
  10655. // elem = this._renderer.elem;
  10656. // if (this._clip) {
  10657. // elem.removeAttribute('id');
  10658. // clip.setAttribute('id', this.id);
  10659. // clip.appendChild(elem);
  10660. // } else {
  10661. // clip.removeAttribute('id');
  10662. // elem.setAttribute('id', this.id);
  10663. // this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10664. // }
  10665. // }
  10666. if (this._flagMask) {
  10667. if (this._mask) {
  10668. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10669. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10670. } else {
  10671. this._renderer.elem.removeAttribute('clip-path');
  10672. }
  10673. }
  10674. return this.flagReset();
  10675. }
  10676. },
  10677. path: {
  10678. render: function(domElement) {
  10679. // Shortcut for hidden objects.
  10680. // Doesn't reset the flags, so changes are stored and
  10681. // applied once the object is visible again
  10682. if (this._opacity === 0 && !this._flagOpacity) {
  10683. return this;
  10684. }
  10685. this._update();
  10686. // Collect any attribute that needs to be changed here
  10687. var changed = {};
  10688. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10689. if (flagMatrix) {
  10690. changed.transform = 'matrix(' + this._matrix.toString() + ')';
  10691. }
  10692. if (this._flagId) {
  10693. changed.id = this._id;
  10694. }
  10695. if (this._flagVertices) {
  10696. var vertices = svg.toString(this._renderer.vertices, this._closed);
  10697. changed.d = vertices;
  10698. }
  10699. if (this._fill && this._fill._renderer) {
  10700. this._fill._update();
  10701. svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  10702. }
  10703. if (this._flagFill) {
  10704. changed.fill = this._fill && this._fill.id
  10705. ? 'url(#' + this._fill.id + ')' : this._fill;
  10706. }
  10707. if (this._stroke && this._stroke._renderer) {
  10708. this._stroke._update();
  10709. svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  10710. }
  10711. if (this._flagStroke) {
  10712. changed.stroke = this._stroke && this._stroke.id
  10713. ? 'url(#' + this._stroke.id + ')' : this._stroke;
  10714. }
  10715. if (this._flagLinewidth) {
  10716. changed['stroke-width'] = this._linewidth;
  10717. }
  10718. if (this._flagOpacity) {
  10719. changed['stroke-opacity'] = this._opacity;
  10720. changed['fill-opacity'] = this._opacity;
  10721. }
  10722. if (this._flagClassName) {
  10723. changed['class'] = this.classList.join(' ');
  10724. }
  10725. if (this._flagVisible) {
  10726. changed.visibility = this._visible ? 'visible' : 'hidden';
  10727. }
  10728. if (this._flagCap) {
  10729. changed['stroke-linecap'] = this._cap;
  10730. }
  10731. if (this._flagJoin) {
  10732. changed['stroke-linejoin'] = this._join;
  10733. }
  10734. if (this._flagMiter) {
  10735. changed['stroke-miterlimit'] = this._miter;
  10736. }
  10737. if (this.dashes && this.dashes.length > 0) {
  10738. changed['stroke-dasharray'] = this.dashes.join(' ');
  10739. changed['stroke-dashoffset'] = this.dashes.offset || 0;
  10740. }
  10741. // If there is no attached DOM element yet,
  10742. // create it with all necessary attributes.
  10743. if (!this._renderer.elem) {
  10744. changed.id = this._id;
  10745. this._renderer.elem = svg.createElement('path', changed);
  10746. domElement.appendChild(this._renderer.elem);
  10747. // Otherwise apply all pending attributes
  10748. } else {
  10749. svg.setAttributes(this._renderer.elem, changed);
  10750. }
  10751. if (this._flagClip) {
  10752. var clip = svg.getClip(this, domElement);
  10753. var elem = this._renderer.elem;
  10754. if (this._clip) {
  10755. elem.removeAttribute('id');
  10756. clip.setAttribute('id', this.id);
  10757. clip.appendChild(elem);
  10758. } else {
  10759. clip.removeAttribute('id');
  10760. elem.setAttribute('id', this.id);
  10761. this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10762. }
  10763. }
  10764. // Commented two-way functionality of clips / masks with groups and
  10765. // polygons. Uncomment when this bug is fixed:
  10766. // https://code.google.com/p/chromium/issues/detail?id=370951
  10767. if (this._flagMask) {
  10768. if (this._mask) {
  10769. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10770. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10771. } else {
  10772. this._renderer.elem.removeAttribute('clip-path');
  10773. }
  10774. }
  10775. return this.flagReset();
  10776. }
  10777. },
  10778. text: {
  10779. render: function(domElement) {
  10780. this._update();
  10781. var changed = {};
  10782. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10783. if (flagMatrix) {
  10784. changed.transform = 'matrix(' + this._matrix.toString() + ')';
  10785. }
  10786. if (this._flagId) {
  10787. changed.id = this._id;
  10788. }
  10789. if (this._flagFamily) {
  10790. changed['font-family'] = this._family;
  10791. }
  10792. if (this._flagSize) {
  10793. changed['font-size'] = this._size;
  10794. }
  10795. if (this._flagLeading) {
  10796. changed['line-height'] = this._leading;
  10797. }
  10798. if (this._flagAlignment) {
  10799. changed['text-anchor'] = svg.alignments[this._alignment] || this._alignment;
  10800. }
  10801. if (this._flagBaseline) {
  10802. changed['alignment-baseline'] = changed['dominant-baseline'] = this._baseline;
  10803. }
  10804. if (this._flagStyle) {
  10805. changed['font-style'] = this._style;
  10806. }
  10807. if (this._flagWeight) {
  10808. changed['font-weight'] = this._weight;
  10809. }
  10810. if (this._flagDecoration) {
  10811. changed['text-decoration'] = this._decoration;
  10812. }
  10813. if (this._fill && this._fill._renderer) {
  10814. this._fill._update();
  10815. svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  10816. }
  10817. if (this._flagFill) {
  10818. changed.fill = this._fill && this._fill.id
  10819. ? 'url(#' + this._fill.id + ')' : this._fill;
  10820. }
  10821. if (this._stroke && this._stroke._renderer) {
  10822. this._stroke._update();
  10823. svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  10824. }
  10825. if (this._flagStroke) {
  10826. changed.stroke = this._stroke && this._stroke.id
  10827. ? 'url(#' + this._stroke.id + ')' : this._stroke;
  10828. }
  10829. if (this._flagLinewidth) {
  10830. changed['stroke-width'] = this._linewidth;
  10831. }
  10832. if (this._flagOpacity) {
  10833. changed.opacity = this._opacity;
  10834. }
  10835. if (this._flagClassName) {
  10836. changed['class'] = this.classList.join(' ');
  10837. }
  10838. if (this._flagVisible) {
  10839. changed.visibility = this._visible ? 'visible' : 'hidden';
  10840. }
  10841. if (this.dashes && this.dashes.length > 0) {
  10842. changed['stroke-dasharray'] = this.dashes.join(' ');
  10843. changed['stroke-dashoffset'] = this.dashes.offset || 0;
  10844. }
  10845. if (!this._renderer.elem) {
  10846. changed.id = this._id;
  10847. this._renderer.elem = svg.createElement('text', changed);
  10848. domElement.defs.appendChild(this._renderer.elem);
  10849. } else {
  10850. svg.setAttributes(this._renderer.elem, changed);
  10851. }
  10852. if (this._flagClip) {
  10853. var clip = svg.getClip(this, domElement);
  10854. var elem = this._renderer.elem;
  10855. if (this._clip) {
  10856. elem.removeAttribute('id');
  10857. clip.setAttribute('id', this.id);
  10858. clip.appendChild(elem);
  10859. } else {
  10860. clip.removeAttribute('id');
  10861. elem.setAttribute('id', this.id);
  10862. this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10863. }
  10864. }
  10865. // Commented two-way functionality of clips / masks with groups and
  10866. // polygons. Uncomment when this bug is fixed:
  10867. // https://code.google.com/p/chromium/issues/detail?id=370951
  10868. if (this._flagMask) {
  10869. if (this._mask) {
  10870. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10871. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10872. } else {
  10873. this._renderer.elem.removeAttribute('clip-path');
  10874. }
  10875. }
  10876. if (this._flagValue) {
  10877. this._renderer.elem.textContent = this._value;
  10878. }
  10879. return this.flagReset();
  10880. }
  10881. },
  10882. 'linear-gradient': {
  10883. render: function(domElement, silent) {
  10884. if (!silent) {
  10885. this._update();
  10886. }
  10887. var changed = {};
  10888. if (this._flagId) {
  10889. changed.id = this._id;
  10890. }
  10891. if (this._flagEndPoints) {
  10892. changed.x1 = this.left._x;
  10893. changed.y1 = this.left._y;
  10894. changed.x2 = this.right._x;
  10895. changed.y2 = this.right._y;
  10896. }
  10897. if (this._flagSpread) {
  10898. changed.spreadMethod = this._spread;
  10899. }
  10900. // If there is no attached DOM element yet,
  10901. // create it with all necessary attributes.
  10902. if (!this._renderer.elem) {
  10903. changed.id = this._id;
  10904. changed.gradientUnits = 'userSpaceOnUse';
  10905. this._renderer.elem = svg.createElement('linearGradient', changed);
  10906. domElement.defs.appendChild(this._renderer.elem);
  10907. // Otherwise apply all pending attributes
  10908. } else {
  10909. svg.setAttributes(this._renderer.elem, changed);
  10910. }
  10911. if (this._flagStops) {
  10912. var lengthChanged = this._renderer.elem.childNodes.length
  10913. !== this.stops.length;
  10914. if (lengthChanged) {
  10915. while (this._renderer.elem.lastChild) {
  10916. this._renderer.elem.removeChild(this._renderer.elem.lastChild);
  10917. }
  10918. }
  10919. for (var i = 0; i < this.stops.length; i++) {
  10920. var stop = this.stops[i];
  10921. var attrs = {};
  10922. if (stop._flagOffset) {
  10923. attrs.offset = 100 * stop._offset + '%';
  10924. }
  10925. if (stop._flagColor) {
  10926. attrs['stop-color'] = stop._color;
  10927. }
  10928. if (stop._flagOpacity) {
  10929. attrs['stop-opacity'] = stop._opacity;
  10930. }
  10931. if (!stop._renderer.elem) {
  10932. stop._renderer.elem = svg.createElement('stop', attrs);
  10933. } else {
  10934. svg.setAttributes(stop._renderer.elem, attrs);
  10935. }
  10936. if (lengthChanged) {
  10937. this._renderer.elem.appendChild(stop._renderer.elem);
  10938. }
  10939. stop.flagReset();
  10940. }
  10941. }
  10942. return this.flagReset();
  10943. }
  10944. },
  10945. 'radial-gradient': {
  10946. render: function(domElement, silent) {
  10947. if (!silent) {
  10948. this._update();
  10949. }
  10950. var changed = {};
  10951. if (this._flagId) {
  10952. changed.id = this._id;
  10953. }
  10954. if (this._flagCenter) {
  10955. changed.cx = this.center._x;
  10956. changed.cy = this.center._y;
  10957. }
  10958. if (this._flagFocal) {
  10959. changed.fx = this.focal._x;
  10960. changed.fy = this.focal._y;
  10961. }
  10962. if (this._flagRadius) {
  10963. changed.r = this._radius;
  10964. }
  10965. if (this._flagSpread) {
  10966. changed.spreadMethod = this._spread;
  10967. }
  10968. // If there is no attached DOM element yet,
  10969. // create it with all necessary attributes.
  10970. if (!this._renderer.elem) {
  10971. changed.id = this._id;
  10972. changed.gradientUnits = 'userSpaceOnUse';
  10973. this._renderer.elem = svg.createElement('radialGradient', changed);
  10974. domElement.defs.appendChild(this._renderer.elem);
  10975. // Otherwise apply all pending attributes
  10976. } else {
  10977. svg.setAttributes(this._renderer.elem, changed);
  10978. }
  10979. if (this._flagStops) {
  10980. var lengthChanged = this._renderer.elem.childNodes.length
  10981. !== this.stops.length;
  10982. if (lengthChanged) {
  10983. while (this._renderer.elem.lastChild) {
  10984. this._renderer.elem.removeChild(this._renderer.elem.lastChild);
  10985. }
  10986. }
  10987. for (var i = 0; i < this.stops.length; i++) {
  10988. var stop = this.stops[i];
  10989. var attrs = {};
  10990. if (stop._flagOffset) {
  10991. attrs.offset = 100 * stop._offset + '%';
  10992. }
  10993. if (stop._flagColor) {
  10994. attrs['stop-color'] = stop._color;
  10995. }
  10996. if (stop._flagOpacity) {
  10997. attrs['stop-opacity'] = stop._opacity;
  10998. }
  10999. if (!stop._renderer.elem) {
  11000. stop._renderer.elem = svg.createElement('stop', attrs);
  11001. } else {
  11002. svg.setAttributes(stop._renderer.elem, attrs);
  11003. }
  11004. if (lengthChanged) {
  11005. this._renderer.elem.appendChild(stop._renderer.elem);
  11006. }
  11007. stop.flagReset();
  11008. }
  11009. }
  11010. return this.flagReset();
  11011. }
  11012. },
  11013. texture: {
  11014. render: function(domElement, silent) {
  11015. if (!silent) {
  11016. this._update();
  11017. }
  11018. var changed = {};
  11019. var styles = { x: 0, y: 0 };
  11020. var image = this.image;
  11021. if (this._flagId) {
  11022. changed.id = this._id;
  11023. }
  11024. if (this._flagLoaded && this.loaded) {
  11025. switch (image.nodeName.toLowerCase()) {
  11026. case 'canvas':
  11027. styles.href = styles['xlink:href'] = image.toDataURL('image/png');
  11028. break;
  11029. case 'img':
  11030. case 'image':
  11031. styles.href = styles['xlink:href'] = this.src;
  11032. break;
  11033. }
  11034. }
  11035. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  11036. changed.x = this._offset.x;
  11037. changed.y = this._offset.y;
  11038. if (image) {
  11039. changed.x -= image.width / 2;
  11040. changed.y -= image.height / 2;
  11041. if (this._scale instanceof Vector) {
  11042. changed.x *= this._scale.x;
  11043. changed.y *= this._scale.y;
  11044. } else {
  11045. changed.x *= this._scale;
  11046. changed.y *= this._scale;
  11047. }
  11048. }
  11049. if (changed.x > 0) {
  11050. changed.x *= - 1;
  11051. }
  11052. if (changed.y > 0) {
  11053. changed.y *= - 1;
  11054. }
  11055. }
  11056. if (this._flagScale || this._flagLoaded || this._flagRepeat) {
  11057. changed.width = 0;
  11058. changed.height = 0;
  11059. if (image) {
  11060. styles.width = changed.width = image.width;
  11061. styles.height = changed.height = image.height;
  11062. // TODO: Hack / Band-aid
  11063. switch (this._repeat) {
  11064. case 'no-repeat':
  11065. changed.width += 1;
  11066. changed.height += 1;
  11067. break;
  11068. }
  11069. if (this._scale instanceof Vector) {
  11070. changed.width *= this._scale.x;
  11071. changed.height *= this._scale.y;
  11072. } else {
  11073. changed.width *= this._scale;
  11074. changed.height *= this._scale;
  11075. }
  11076. }
  11077. }
  11078. if (this._flagScale || this._flagLoaded) {
  11079. if (!this._renderer.image) {
  11080. this._renderer.image = svg.createElement('image', styles);
  11081. } else {
  11082. svg.setAttributes(this._renderer.image, styles);
  11083. }
  11084. }
  11085. if (!this._renderer.elem) {
  11086. changed.id = this._id;
  11087. changed.patternUnits = 'userSpaceOnUse';
  11088. this._renderer.elem = svg.createElement('pattern', changed);
  11089. domElement.defs.appendChild(this._renderer.elem);
  11090. } else if (Object.keys(changed).length !== 0) {
  11091. svg.setAttributes(this._renderer.elem, changed);
  11092. }
  11093. if (this._renderer.elem && this._renderer.image && !this._renderer.appended) {
  11094. this._renderer.elem.appendChild(this._renderer.image);
  11095. this._renderer.appended = true;
  11096. }
  11097. return this.flagReset();
  11098. }
  11099. }
  11100. };
  11101. /**
  11102. * @name Two.SVGRenderer
  11103. * @class
  11104. * @extends Two.Events
  11105. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  11106. * @param {Element} [parameters.domElement] - The `<svg />` to draw to. If none given a new one will be constructed.
  11107. * @description This class is used by {@link Two} when constructing with `type` of `Two.Types.svg` (the default type). It takes Two.js' scenegraph and renders it to a `<svg />`.
  11108. */
  11109. function Renderer$1(params) {
  11110. /**
  11111. * @name Two.SVGRenderer#domElement
  11112. * @property {Element} - The `<svg />` associated with the Two.js scene.
  11113. */
  11114. this.domElement = params.domElement || svg.createElement('svg');
  11115. /**
  11116. * @name Two.SVGRenderer#scene
  11117. * @property {Two.Group} - The root group of the scenegraph.
  11118. */
  11119. this.scene = new Group();
  11120. this.scene.parent = this;
  11121. /**
  11122. * @name Two.SVGRenderer#defs
  11123. * @property {SvgDefintionsElement} - The `<defs />` to apply gradients, patterns, and bitmap imagery.
  11124. */
  11125. this.defs = svg.createElement('defs');
  11126. this.domElement.appendChild(this.defs);
  11127. this.domElement.defs = this.defs;
  11128. this.domElement.style.overflow = 'hidden';
  11129. }
  11130. _.extend(Renderer$1, {
  11131. /**
  11132. * @name Two.SVGRenderer.Utils
  11133. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<svg />`.
  11134. */
  11135. Utils: svg
  11136. });
  11137. _.extend(Renderer$1.prototype, Events, {
  11138. constructor: Renderer$1,
  11139. /**
  11140. * @name Two.SVGRenderer#setSize
  11141. * @function
  11142. * @param {Number} width - The new width of the renderer.
  11143. * @param {Number} height - The new height of the renderer.
  11144. * @description Change the size of the renderer.
  11145. * @nota-bene Triggers a `Two.Events.resize`.
  11146. */
  11147. setSize: function(width, height) {
  11148. this.width = width;
  11149. this.height = height;
  11150. svg.setAttributes(this.domElement, {
  11151. width: width,
  11152. height: height
  11153. });
  11154. return this.trigger(Events.Types.resize, width, height);
  11155. },
  11156. /**
  11157. * @name Two.SVGRenderer#render
  11158. * @function
  11159. * @description Render the current scene to the `<svg />`.
  11160. */
  11161. render: function() {
  11162. svg.group.render.call(this.scene, this.domElement);
  11163. return this;
  11164. }
  11165. });
  11166. // Constants
  11167. var multiplyMatrix = Matrix.Multiply,
  11168. identity = [1, 0, 0, 0, 1, 0, 0, 0, 1],
  11169. transformation = new NumArray(9),
  11170. CanvasUtils = Renderer$2.Utils;
  11171. var webgl = {
  11172. isHidden: /(undefined|none|transparent)/i,
  11173. canvas: (root$1.document ? root$1.document.createElement('canvas') : { getContext: function() {} }),
  11174. alignments: {
  11175. left: 'start',
  11176. middle: 'center',
  11177. right: 'end'
  11178. },
  11179. matrix: new Matrix(),
  11180. group: {
  11181. removeChild: function(child, gl) {
  11182. if (child.children) {
  11183. for (var i = 0; i < child.children.length; i++) {
  11184. webgl.group.removeChild(child.children[i], gl);
  11185. }
  11186. return;
  11187. }
  11188. // Deallocate texture to free up gl memory.
  11189. gl.deleteTexture(child._renderer.texture);
  11190. delete child._renderer.texture;
  11191. },
  11192. render: function(gl, program) {
  11193. if (!this._visible) {
  11194. return;
  11195. }
  11196. this._update();
  11197. var parent = this.parent;
  11198. var flagParentMatrix = (parent._matrix && parent._matrix.manual) || parent._flagMatrix;
  11199. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11200. if (flagParentMatrix || flagMatrix) {
  11201. if (!this._renderer.matrix) {
  11202. this._renderer.matrix = new NumArray(9);
  11203. }
  11204. // Reduce amount of object / array creation / deletion
  11205. this._matrix.toTransformArray(true, transformation);
  11206. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11207. if (!(this._renderer.scale instanceof Vector)) {
  11208. this._renderer.scale = new Vector();
  11209. }
  11210. if (this._scale instanceof Vector) {
  11211. this._renderer.scale.x = this._scale.x;
  11212. this._renderer.scale.y = this._scale.y;
  11213. } else {
  11214. this._renderer.scale.x = this._scale;
  11215. this._renderer.scale.y = this._scale;
  11216. }
  11217. if (!(/renderer/i.test(parent._renderer.type))) {
  11218. this._renderer.scale.x *= parent._renderer.scale.x;
  11219. this._renderer.scale.y *= parent._renderer.scale.y;
  11220. }
  11221. if (flagParentMatrix) {
  11222. this._flagMatrix = true;
  11223. }
  11224. }
  11225. if (this._mask) {
  11226. // Stencil away everything that isn't rendered by the mask
  11227. gl.clear(gl.STENCIL_BUFFER_BIT);
  11228. gl.enable(gl.STENCIL_TEST);
  11229. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11230. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11231. // Don't draw the element onto the canvas, only onto the stencil buffer
  11232. gl.colorMask(false, false, false, false);
  11233. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11234. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11235. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11236. gl.colorMask(true, true, true, true);
  11237. }
  11238. this._flagOpacity = parent._flagOpacity || this._flagOpacity;
  11239. this._renderer.opacity = this._opacity
  11240. * (parent && parent._renderer ? parent._renderer.opacity : 1);
  11241. var i;
  11242. if (this._flagSubtractions) {
  11243. for (i = 0; i < this.subtractions.length; i++) {
  11244. webgl.group.removeChild(this.subtractions[i], gl);
  11245. }
  11246. }
  11247. for (i = 0; i < this.children.length; i++) {
  11248. var child = this.children[i];
  11249. webgl[child._renderer.type].render.call(child, gl, program);
  11250. }
  11251. if (this._mask) {
  11252. gl.disable(gl.STENCIL_TEST);
  11253. }
  11254. return this.flagReset();
  11255. }
  11256. },
  11257. path: {
  11258. updateCanvas: function(elem) {
  11259. var next, prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
  11260. var isOffset;
  11261. var commands = elem._renderer.vertices;
  11262. var canvas = this.canvas;
  11263. var ctx = this.ctx;
  11264. // Styles
  11265. var scale = elem._renderer.scale;
  11266. var stroke = elem._stroke;
  11267. var linewidth = elem._linewidth;
  11268. var fill = elem._fill;
  11269. var opacity = elem._renderer.opacity || elem._opacity;
  11270. var cap = elem._cap;
  11271. var join = elem._join;
  11272. var miter = elem._miter;
  11273. var closed = elem._closed;
  11274. var dashes = elem.dashes;
  11275. var length = commands.length;
  11276. var last = length - 1;
  11277. canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
  11278. canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
  11279. var centroid = elem._renderer.rect.centroid;
  11280. var cx = centroid.x;
  11281. var cy = centroid.y;
  11282. ctx.clearRect(0, 0, canvas.width, canvas.height);
  11283. if (fill) {
  11284. if (typeof fill === 'string') {
  11285. ctx.fillStyle = fill;
  11286. } else {
  11287. webgl[fill._renderer.type].render.call(fill, ctx, elem);
  11288. ctx.fillStyle = fill._renderer.effect;
  11289. }
  11290. }
  11291. if (stroke) {
  11292. if (typeof stroke === 'string') {
  11293. ctx.strokeStyle = stroke;
  11294. } else {
  11295. webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  11296. ctx.strokeStyle = stroke._renderer.effect;
  11297. }
  11298. if (linewidth) {
  11299. ctx.lineWidth = linewidth;
  11300. }
  11301. if (miter) {
  11302. ctx.miterLimit = miter;
  11303. }
  11304. if (join) {
  11305. ctx.lineJoin = join;
  11306. }
  11307. if (!closed && cap) {
  11308. ctx.lineCap = cap;
  11309. }
  11310. }
  11311. if (typeof opacity === 'number') {
  11312. ctx.globalAlpha = opacity;
  11313. }
  11314. if (dashes && dashes.length > 0) {
  11315. ctx.lineDashOffset = dashes.offset || 0;
  11316. ctx.setLineDash(dashes);
  11317. }
  11318. var d;
  11319. ctx.save();
  11320. ctx.scale(scale.x, scale.y);
  11321. ctx.translate(cx, cy);
  11322. ctx.beginPath();
  11323. for (var i = 0; i < commands.length; i++) {
  11324. var b = commands[i];
  11325. x = b.x;
  11326. y = b.y;
  11327. switch (b.command) {
  11328. case Commands.close:
  11329. ctx.closePath();
  11330. break;
  11331. case Commands.arc:
  11332. var rx = b.rx;
  11333. var ry = b.ry;
  11334. var xAxisRotation = b.xAxisRotation;
  11335. var largeArcFlag = b.largeArcFlag;
  11336. var sweepFlag = b.sweepFlag;
  11337. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  11338. a = commands[prev];
  11339. var ax = a.x;
  11340. var ay = a.y;
  11341. CanvasUtils.renderSvgArcCommand(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y);
  11342. break;
  11343. case Commands.curve:
  11344. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  11345. next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  11346. a = commands[prev];
  11347. c = commands[next];
  11348. ar = (a.controls && a.controls.right) || Vector.zero;
  11349. bl = (b.controls && b.controls.left) || Vector.zero;
  11350. if (a._relative) {
  11351. vx = ar.x + a.x;
  11352. vy = ar.y + a.y;
  11353. } else {
  11354. vx = ar.x;
  11355. vy = ar.y;
  11356. }
  11357. if (b._relative) {
  11358. ux = bl.x + b.x;
  11359. uy = bl.y + b.y;
  11360. } else {
  11361. ux = bl.x;
  11362. uy = bl.y;
  11363. }
  11364. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  11365. if (i >= last && closed) {
  11366. c = d;
  11367. br = (b.controls && b.controls.right) || Vector.zero;
  11368. cl = (c.controls && c.controls.left) || Vector.zero;
  11369. if (b._relative) {
  11370. vx = br.x + b.x;
  11371. vy = br.y + b.y;
  11372. } else {
  11373. vx = br.x;
  11374. vy = br.y;
  11375. }
  11376. if (c._relative) {
  11377. ux = cl.x + c.x;
  11378. uy = cl.y + c.y;
  11379. } else {
  11380. ux = cl.x;
  11381. uy = cl.y;
  11382. }
  11383. x = c.x;
  11384. y = c.y;
  11385. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  11386. }
  11387. break;
  11388. case Commands.line:
  11389. ctx.lineTo(x, y);
  11390. break;
  11391. case Commands.move:
  11392. d = b;
  11393. ctx.moveTo(x, y);
  11394. break;
  11395. }
  11396. }
  11397. // Loose ends
  11398. if (closed) {
  11399. ctx.closePath();
  11400. }
  11401. if (!webgl.isHidden.test(fill)) {
  11402. isOffset = fill._renderer && fill._renderer.offset;
  11403. if (isOffset) {
  11404. ctx.save();
  11405. ctx.translate(
  11406. - fill._renderer.offset.x, - fill._renderer.offset.y);
  11407. ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  11408. }
  11409. ctx.fill();
  11410. if (isOffset) {
  11411. ctx.restore();
  11412. }
  11413. }
  11414. if (!webgl.isHidden.test(stroke)) {
  11415. isOffset = stroke._renderer && stroke._renderer.offset;
  11416. if (isOffset) {
  11417. ctx.save();
  11418. ctx.translate(
  11419. - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  11420. ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  11421. ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  11422. }
  11423. ctx.stroke();
  11424. if (isOffset) {
  11425. ctx.restore();
  11426. }
  11427. }
  11428. ctx.restore();
  11429. },
  11430. // Returns the rect of a set of verts. Typically takes vertices that are
  11431. // "centered" around 0 and returns them to be anchored upper-left.
  11432. getBoundingClientRect: function(vertices, border, rect) {
  11433. var left = Infinity, right = -Infinity,
  11434. top = Infinity, bottom = -Infinity,
  11435. width, height;
  11436. vertices.forEach(function(v) {
  11437. var x = v.x, y = v.y, controls = v.controls;
  11438. var a, b, c, d, cl, cr;
  11439. top = Math.min(y, top);
  11440. left = Math.min(x, left);
  11441. right = Math.max(x, right);
  11442. bottom = Math.max(y, bottom);
  11443. if (!v.controls) {
  11444. return;
  11445. }
  11446. cl = controls.left;
  11447. cr = controls.right;
  11448. if (!cl || !cr) {
  11449. return;
  11450. }
  11451. a = v._relative ? cl.x + x : cl.x;
  11452. b = v._relative ? cl.y + y : cl.y;
  11453. c = v._relative ? cr.x + x : cr.x;
  11454. d = v._relative ? cr.y + y : cr.y;
  11455. if (!a || !b || !c || !d) {
  11456. return;
  11457. }
  11458. top = Math.min(b, d, top);
  11459. left = Math.min(a, c, left);
  11460. right = Math.max(a, c, right);
  11461. bottom = Math.max(b, d, bottom);
  11462. });
  11463. // Expand borders
  11464. if (typeof border === 'number') {
  11465. top -= border;
  11466. left -= border;
  11467. right += border;
  11468. bottom += border;
  11469. }
  11470. width = right - left;
  11471. height = bottom - top;
  11472. rect.top = top;
  11473. rect.left = left;
  11474. rect.right = right;
  11475. rect.bottom = bottom;
  11476. rect.width = width;
  11477. rect.height = height;
  11478. if (!rect.centroid) {
  11479. rect.centroid = {};
  11480. }
  11481. rect.centroid.x = - left;
  11482. rect.centroid.y = - top;
  11483. },
  11484. render: function(gl, program, forcedParent) {
  11485. if (!this._visible || !this._opacity) {
  11486. return this;
  11487. }
  11488. this._update();
  11489. // Calculate what changed
  11490. var parent = forcedParent || this.parent;
  11491. var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  11492. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11493. var parentChanged = this._renderer.parent !== parent;
  11494. var flagTexture = this._flagVertices || this._flagFill
  11495. || (this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  11496. || (this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  11497. || (this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale))
  11498. || (this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  11499. || (this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  11500. || (this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale))
  11501. || this._flagStroke || this._flagLinewidth || this._flagOpacity
  11502. || parent._flagOpacity || this._flagVisible || this._flagCap
  11503. || this._flagJoin || this._flagMiter || this._flagScale
  11504. || (this.dashes && this.dashes.length > 0)
  11505. || !this._renderer.texture;
  11506. if (flagParentMatrix || flagMatrix || parentChanged) {
  11507. if (!this._renderer.matrix) {
  11508. this._renderer.matrix = new NumArray(9);
  11509. }
  11510. // Reduce amount of object / array creation / deletion
  11511. this._matrix.toTransformArray(true, transformation);
  11512. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11513. if (!(this._renderer.scale instanceof Vector)) {
  11514. this._renderer.scale = new Vector();
  11515. }
  11516. if (this._scale instanceof Vector) {
  11517. this._renderer.scale.x = this._scale.x * parent._renderer.scale.x;
  11518. this._renderer.scale.y = this._scale.y * parent._renderer.scale.y;
  11519. } else {
  11520. this._renderer.scale.x = this._scale * parent._renderer.scale.x;
  11521. this._renderer.scale.y = this._scale * parent._renderer.scale.y;
  11522. }
  11523. if (parentChanged) {
  11524. this._renderer.parent = parent;
  11525. }
  11526. }
  11527. if (this._mask) {
  11528. // Stencil away everything that isn't rendered by the mask
  11529. gl.clear(gl.STENCIL_BUFFER_BIT);
  11530. gl.enable(gl.STENCIL_TEST);
  11531. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11532. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11533. // Don't draw the element onto the canvas, only onto the stencil buffer
  11534. gl.colorMask(false, false, false, false);
  11535. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11536. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11537. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11538. gl.colorMask(true, true, true, true);
  11539. }
  11540. if (flagTexture) {
  11541. if (!this._renderer.rect) {
  11542. this._renderer.rect = {};
  11543. }
  11544. this._renderer.opacity = this._opacity * parent._renderer.opacity;
  11545. webgl.path.getBoundingClientRect(this._renderer.vertices, this._linewidth, this._renderer.rect);
  11546. webgl.updateTexture.call(webgl, gl, this);
  11547. } else {
  11548. // We still need to update child Two elements on the fill and
  11549. // stroke properties.
  11550. if (this._fill && this._fill._update) {
  11551. this._fill._update();
  11552. }
  11553. if (this._stroke && this._stroke._update) {
  11554. this._stroke._update();
  11555. }
  11556. }
  11557. if (this._clip && !forcedParent) {
  11558. return;
  11559. }
  11560. // Draw Texture
  11561. gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  11562. // Draw Rect
  11563. var rect = this._renderer.rect;
  11564. gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  11565. gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
  11566. gl.drawArrays(gl.TRIANGLES, 0, 6);
  11567. if (this._mask) {
  11568. gl.disable(gl.STENCIL_TEST);
  11569. }
  11570. return this.flagReset();
  11571. }
  11572. },
  11573. text: {
  11574. updateCanvas: function(elem) {
  11575. var canvas = this.canvas;
  11576. var ctx = this.ctx;
  11577. // Styles
  11578. var scale = elem._renderer.scale;
  11579. var stroke = elem._stroke;
  11580. var linewidth = elem._linewidth * scale;
  11581. var fill = elem._fill;
  11582. var opacity = elem._renderer.opacity || elem._opacity;
  11583. var dashes = elem.dashes;
  11584. var decoration = elem._decoration;
  11585. canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
  11586. canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
  11587. var centroid = elem._renderer.rect.centroid;
  11588. var cx = centroid.x;
  11589. var cy = centroid.y;
  11590. var a, b, c, d, e, sx, sy, x1, y1, x2, y2;
  11591. var isOffset = fill._renderer && fill._renderer.offset
  11592. && stroke._renderer && stroke._renderer.offset;
  11593. ctx.clearRect(0, 0, canvas.width, canvas.height);
  11594. if (!isOffset) {
  11595. ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  11596. elem._leading + 'px', elem._family].join(' ');
  11597. }
  11598. ctx.textAlign = 'center';
  11599. ctx.textBaseline = 'middle';
  11600. // Styles
  11601. if (fill) {
  11602. if (typeof fill === 'string') {
  11603. ctx.fillStyle = fill;
  11604. } else {
  11605. webgl[fill._renderer.type].render.call(fill, ctx, elem);
  11606. ctx.fillStyle = fill._renderer.effect;
  11607. }
  11608. }
  11609. if (stroke) {
  11610. if (typeof stroke === 'string') {
  11611. ctx.strokeStyle = stroke;
  11612. } else {
  11613. webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  11614. ctx.strokeStyle = stroke._renderer.effect;
  11615. }
  11616. if (linewidth) {
  11617. ctx.lineWidth = linewidth;
  11618. }
  11619. }
  11620. if (typeof opacity === 'number') {
  11621. ctx.globalAlpha = opacity;
  11622. }
  11623. if (dashes && dashes.length > 0) {
  11624. ctx.lineDashOffset = dashes.offset || 0;
  11625. ctx.setLineDash(dashes);
  11626. }
  11627. ctx.save();
  11628. ctx.scale(scale.x, scale.y);
  11629. ctx.translate(cx, cy);
  11630. if (!webgl.isHidden.test(fill)) {
  11631. if (fill._renderer && fill._renderer.offset) {
  11632. sx = fill._renderer.scale.x;
  11633. sy = fill._renderer.scale.y;
  11634. ctx.save();
  11635. ctx.translate( - fill._renderer.offset.x,
  11636. - fill._renderer.offset.y);
  11637. ctx.scale(sx, sy);
  11638. a = elem._size / fill._renderer.scale.y;
  11639. b = elem._leading / fill._renderer.scale.y;
  11640. ctx.font = [elem._style, elem._weight, a + 'px/',
  11641. b + 'px', elem._family].join(' ');
  11642. c = fill._renderer.offset.x / fill._renderer.scale.x;
  11643. d = fill._renderer.offset.y / fill._renderer.scale.y;
  11644. ctx.fillText(elem.value, c, d);
  11645. ctx.restore();
  11646. } else {
  11647. ctx.fillText(elem.value, 0, 0);
  11648. }
  11649. }
  11650. if (!webgl.isHidden.test(stroke)) {
  11651. if (stroke._renderer && stroke._renderer.offset) {
  11652. sx = stroke._renderer.scale.x;
  11653. sy = stroke._renderer.scale.y;
  11654. ctx.save();
  11655. ctx.translate(- stroke._renderer.offset.x,
  11656. - stroke._renderer.offset.y);
  11657. ctx.scale(sx, sy);
  11658. a = elem._size / stroke._renderer.scale.y;
  11659. b = elem._leading / stroke._renderer.scale.y;
  11660. ctx.font = [elem._style, elem._weight, a + 'px/',
  11661. b + 'px', elem._family].join(' ');
  11662. c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  11663. d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  11664. e = linewidth / stroke._renderer.scale.x;
  11665. ctx.lineWidth = e;
  11666. ctx.strokeText(elem.value, c, d);
  11667. ctx.restore();
  11668. } else {
  11669. ctx.strokeText(elem.value, 0, 0);
  11670. }
  11671. }
  11672. // Handle text-decoration
  11673. if (/(underline|strikethrough)/i.test(decoration)) {
  11674. var metrics = ctx.measureText(elem.value);
  11675. switch (decoration) {
  11676. case 'underline':
  11677. y1 = metrics.actualBoundingBoxAscent;
  11678. y2 = metrics.actualBoundingBoxAscent;
  11679. break;
  11680. case 'strikethrough':
  11681. y1 = 0;
  11682. y2 = 0;
  11683. break;
  11684. }
  11685. x1 = - metrics.width / 2;
  11686. x2 = metrics.width / 2;
  11687. ctx.lineWidth = Math.max(Math.floor(elem._size / 15), 1);
  11688. ctx.strokeStyle = ctx.fillStyle;
  11689. ctx.beginPath();
  11690. ctx.moveTo(x1, y1);
  11691. ctx.lineTo(x2, y2);
  11692. ctx.stroke();
  11693. }
  11694. ctx.restore();
  11695. },
  11696. getBoundingClientRect: function(elem, rect) {
  11697. var ctx = webgl.ctx;
  11698. ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  11699. elem._leading + 'px', elem._family].join(' ');
  11700. ctx.textAlign = 'center';
  11701. ctx.textBaseline = elem._baseline;
  11702. // TODO: Estimate this better
  11703. var width = ctx.measureText(elem._value).width * 1.25;
  11704. var height = Math.max(elem._size, elem._leading) * 1.25;
  11705. if (this._linewidth && !webgl.isHidden.test(this._stroke)) {
  11706. width += this._linewidth * 2;
  11707. height += this._linewidth * 2;
  11708. }
  11709. var w = width / 2;
  11710. var h = height / 2;
  11711. switch (webgl.alignments[elem._alignment] || elem._alignment) {
  11712. case webgl.alignments.left:
  11713. rect.left = 0;
  11714. rect.right = width;
  11715. break;
  11716. case webgl.alignments.right:
  11717. rect.left = - width;
  11718. rect.right = 0;
  11719. break;
  11720. default:
  11721. rect.left = - w;
  11722. rect.right = w;
  11723. }
  11724. // TODO: Gradients aren't inherited...
  11725. switch (elem._baseline) {
  11726. case 'bottom':
  11727. rect.top = - height;
  11728. rect.bottom = 0;
  11729. break;
  11730. case 'top':
  11731. rect.top = 0;
  11732. rect.bottom = height;
  11733. break;
  11734. default:
  11735. rect.top = - h;
  11736. rect.bottom = h;
  11737. }
  11738. rect.width = width;
  11739. rect.height = height;
  11740. if (!rect.centroid) {
  11741. rect.centroid = {};
  11742. }
  11743. // TODO:
  11744. rect.centroid.x = w;
  11745. rect.centroid.y = h;
  11746. },
  11747. render: function(gl, program, forcedParent) {
  11748. if (!this._visible || !this._opacity) {
  11749. return this;
  11750. }
  11751. this._update();
  11752. // Calculate what changed
  11753. var parent = forcedParent || this.parent;
  11754. var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  11755. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11756. var parentChanged = this._renderer.parent !== parent;
  11757. var flagTexture = this._flagVertices || this._flagFill
  11758. || (this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  11759. || (this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  11760. || (this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale))
  11761. || (this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  11762. || (this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  11763. || (this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale))
  11764. || this._flagStroke || this._flagLinewidth || this._flagOpacity
  11765. || parent._flagOpacity || this._flagVisible || this._flagScale
  11766. || this._flagValue || this._flagFamily || this._flagSize
  11767. || this._flagLeading || this._flagAlignment || this._flagBaseline
  11768. || this._flagStyle || this._flagWeight || this._flagDecoration
  11769. || (this.dashes && this.dashes.length > 0)
  11770. || !this._renderer.texture;
  11771. if (flagParentMatrix || flagMatrix || parentChanged) {
  11772. if (!this._renderer.matrix) {
  11773. this._renderer.matrix = new NumArray(9);
  11774. }
  11775. // Reduce amount of object / array creation / deletion
  11776. this._matrix.toTransformArray(true, transformation);
  11777. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11778. if (!(this._renderer.scale instanceof Vector)) {
  11779. this._renderer.scale = new Vector();
  11780. }
  11781. if (this._scale instanceof Vector) {
  11782. this._renderer.scale.x = this._scale.x * parent._renderer.scale.x;
  11783. this._renderer.scale.y = this._scale.y * parent._renderer.scale.y;
  11784. } else {
  11785. this._renderer.scale.x = this._scale * parent._renderer.scale.x;
  11786. this._renderer.scale.y = this._scale * parent._renderer.scale.y;
  11787. }
  11788. if (parentChanged) {
  11789. this._renderer.parent = parent;
  11790. }
  11791. }
  11792. if (this._mask) {
  11793. // Stencil away everything that isn't rendered by the mask
  11794. gl.clear(gl.STENCIL_BUFFER_BIT);
  11795. gl.enable(gl.STENCIL_TEST);
  11796. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11797. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11798. // Don't draw the element onto the canvas, only onto the stencil buffer
  11799. gl.colorMask(false, false, false, false);
  11800. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11801. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11802. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11803. gl.colorMask(true, true, true, true);
  11804. }
  11805. if (flagTexture) {
  11806. if (!this._renderer.rect) {
  11807. this._renderer.rect = {};
  11808. }
  11809. this._renderer.opacity = this._opacity * parent._renderer.opacity;
  11810. webgl.text.getBoundingClientRect(this, this._renderer.rect);
  11811. webgl.updateTexture.call(webgl, gl, this);
  11812. } else {
  11813. // We still need to update child Two elements on the fill and
  11814. // stroke properties.
  11815. if (this._fill && this._fill._update) {
  11816. this._fill._update();
  11817. }
  11818. if (this._stroke && this._stroke._update) {
  11819. this._stroke._update();
  11820. }
  11821. }
  11822. if (this._clip && !forcedParent) {
  11823. return;
  11824. }
  11825. // Draw Texture
  11826. gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  11827. // Draw Rect
  11828. var rect = this._renderer.rect;
  11829. gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  11830. gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
  11831. gl.drawArrays(gl.TRIANGLES, 0, 6);
  11832. if (this._mask) {
  11833. gl.disable(gl.STENCIL_TEST);
  11834. }
  11835. return this.flagReset();
  11836. }
  11837. },
  11838. 'linear-gradient': {
  11839. render: function(ctx, elem) {
  11840. if (!ctx.canvas.getContext('2d')) {
  11841. return;
  11842. }
  11843. this._update();
  11844. if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  11845. this._renderer.effect = ctx.createLinearGradient(
  11846. this.left._x, this.left._y,
  11847. this.right._x, this.right._y
  11848. );
  11849. for (var i = 0; i < this.stops.length; i++) {
  11850. var stop = this.stops[i];
  11851. this._renderer.effect.addColorStop(stop._offset, stop._color);
  11852. }
  11853. }
  11854. return this.flagReset();
  11855. }
  11856. },
  11857. 'radial-gradient': {
  11858. render: function(ctx, elem) {
  11859. if (!ctx.canvas.getContext('2d')) {
  11860. return;
  11861. }
  11862. this._update();
  11863. if (!this._renderer.effect || this._flagCenter || this._flagFocal
  11864. || this._flagRadius || this._flagStops) {
  11865. this._renderer.effect = ctx.createRadialGradient(
  11866. this.center._x, this.center._y, 0,
  11867. this.focal._x, this.focal._y, this._radius
  11868. );
  11869. for (var i = 0; i < this.stops.length; i++) {
  11870. var stop = this.stops[i];
  11871. this._renderer.effect.addColorStop(stop._offset, stop._color);
  11872. }
  11873. }
  11874. return this.flagReset();
  11875. }
  11876. },
  11877. texture: {
  11878. render: function(ctx, elem) {
  11879. if (!ctx.canvas.getContext('2d')) {
  11880. return;
  11881. }
  11882. this._update();
  11883. var image = this.image;
  11884. if (((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) {
  11885. this._renderer.effect = ctx.createPattern(image, this._repeat);
  11886. } else if (!this._renderer.effect) {
  11887. return this.flagReset();
  11888. }
  11889. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  11890. if (!(this._renderer.offset instanceof Vector)) {
  11891. this._renderer.offset = new Vector();
  11892. }
  11893. this._renderer.offset.x = - this._offset.x;
  11894. this._renderer.offset.y = - this._offset.y;
  11895. if (image) {
  11896. this._renderer.offset.x += image.width / 2;
  11897. this._renderer.offset.y += image.height / 2;
  11898. if (this._scale instanceof Vector) {
  11899. this._renderer.offset.x *= this._scale.x;
  11900. this._renderer.offset.y *= this._scale.y;
  11901. } else {
  11902. this._renderer.offset.x *= this._scale;
  11903. this._renderer.offset.y *= this._scale;
  11904. }
  11905. }
  11906. }
  11907. if (this._flagScale || this._flagLoaded) {
  11908. if (!(this._renderer.scale instanceof Vector)) {
  11909. this._renderer.scale = new Vector();
  11910. }
  11911. if (this._scale instanceof Vector) {
  11912. this._renderer.scale.copy(this._scale);
  11913. } else {
  11914. this._renderer.scale.set(this._scale, this._scale);
  11915. }
  11916. }
  11917. return this.flagReset();
  11918. }
  11919. },
  11920. updateTexture: function(gl, elem) {
  11921. this[elem._renderer.type].updateCanvas.call(webgl, elem);
  11922. if (!elem._renderer.texture) {
  11923. elem._renderer.texture = gl.createTexture();
  11924. }
  11925. gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture);
  11926. // Set the parameters so we can render any size image.
  11927. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  11928. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  11929. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  11930. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  11931. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  11932. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  11933. if (this.canvas.width <= 0 || this.canvas.height <= 0) {
  11934. return;
  11935. }
  11936. // Upload the image into the texture.
  11937. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
  11938. },
  11939. program: {
  11940. create: function(gl, shaders) {
  11941. var program, linked, error;
  11942. program = gl.createProgram();
  11943. _.each(shaders, function(s) {
  11944. gl.attachShader(program, s);
  11945. });
  11946. gl.linkProgram(program);
  11947. linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  11948. if (!linked) {
  11949. error = gl.getProgramInfoLog(program);
  11950. gl.deleteProgram(program);
  11951. throw new TwoError('unable to link program: ' + error);
  11952. }
  11953. return program;
  11954. }
  11955. },
  11956. shaders: {
  11957. create: function(gl, source, type) {
  11958. var shader, compiled, error;
  11959. shader = gl.createShader(gl[type]);
  11960. gl.shaderSource(shader, source);
  11961. gl.compileShader(shader);
  11962. compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  11963. if (!compiled) {
  11964. error = gl.getShaderInfoLog(shader);
  11965. gl.deleteShader(shader);
  11966. throw new TwoError('unable to compile shader ' + shader + ': ' + error);
  11967. }
  11968. return shader;
  11969. },
  11970. types: {
  11971. vertex: 'VERTEX_SHADER',
  11972. fragment: 'FRAGMENT_SHADER'
  11973. },
  11974. vertex: [
  11975. 'precision mediump float;',
  11976. 'attribute vec2 a_position;',
  11977. '',
  11978. 'uniform mat3 u_matrix;',
  11979. 'uniform vec2 u_resolution;',
  11980. 'uniform vec4 u_rect;',
  11981. '',
  11982. 'varying vec2 v_textureCoords;',
  11983. '',
  11984. 'void main() {',
  11985. ' vec2 rectCoords = (a_position * (u_rect.zw - u_rect.xy)) + u_rect.xy;',
  11986. ' vec2 projected = (u_matrix * vec3(rectCoords, 1.0)).xy;',
  11987. ' vec2 normal = projected / u_resolution;',
  11988. ' vec2 clipspace = (normal * 2.0) - 1.0;',
  11989. '',
  11990. ' gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);',
  11991. ' v_textureCoords = a_position;',
  11992. '}'
  11993. ].join('\n'),
  11994. fragment: [
  11995. 'precision mediump float;',
  11996. '',
  11997. 'uniform sampler2D u_image;',
  11998. 'varying vec2 v_textureCoords;',
  11999. '',
  12000. 'void main() {',
  12001. ' vec4 texel = texture2D(u_image, v_textureCoords);',
  12002. ' if (texel.a == 0.0) {',
  12003. ' discard;',
  12004. ' }',
  12005. ' gl_FragColor = texel;',
  12006. '}'
  12007. ].join('\n')
  12008. },
  12009. TextureRegistry: new Registry()
  12010. };
  12011. webgl.ctx = webgl.canvas.getContext('2d');
  12012. /**
  12013. * @name Two.WebGLRenderer
  12014. * @class
  12015. * @extends Two.Events
  12016. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  12017. * @param {Element} [parameters.domElement] - The `<canvas />` to draw to. If none given a new one will be constructed.
  12018. * @param {HTMLCanvasElement} [parameters.offscreenElement] - The offscreen two dimensional `<canvas />` to render each element on WebGL texture updates.
  12019. * @param {Boolean} [parameters.antialias] - Determines whether the canvas should clear render with antialias on.
  12020. * @description This class is used by {@link Two} when constructing with `type` of `Two.Types.webgl`. It takes Two.js' scenegraph and renders it to a `<canvas />` through the WebGL api.
  12021. * @see {@link https://www.khronos.org/registry/webgl/specs/latest/1.0/}
  12022. */
  12023. function Renderer(params) {
  12024. var gl, vs, fs;
  12025. /**
  12026. * @name Two.WebGLRenderer#domElement
  12027. * @property {Element} - The `<canvas />` associated with the Two.js scene.
  12028. */
  12029. this.domElement = params.domElement || document.createElement('canvas');
  12030. if (typeof params.offscreenElement !== 'undefined') {
  12031. webgl.canvas = params.offscreenElement;
  12032. webgl.ctx = webgl.canvas.getContext('2d');
  12033. }
  12034. /**
  12035. * @name Two.WebGLRenderer#scene
  12036. * @property {Two.Group} - The root group of the scenegraph.
  12037. */
  12038. this.scene = new Group();
  12039. this.scene.parent = this;
  12040. this._renderer = {
  12041. type: 'renderer',
  12042. matrix: new NumArray(identity),
  12043. scale: 1,
  12044. opacity: 1
  12045. };
  12046. this._flagMatrix = true;
  12047. // http://games.greggman.com/game/webgl-and-alpha/
  12048. // http://www.khronos.org/registry/webgl/specs/latest/#5.2
  12049. params = _.defaults(params || {}, {
  12050. antialias: false,
  12051. alpha: true,
  12052. premultipliedAlpha: true,
  12053. stencil: true,
  12054. preserveDrawingBuffer: true,
  12055. overdraw: false
  12056. });
  12057. /**
  12058. * @name Two.WebGLRenderer#overdraw
  12059. * @property {Boolean} - Determines whether the canvas clears the background each draw call.
  12060. * @default true
  12061. */
  12062. this.overdraw = params.overdraw;
  12063. /**
  12064. * @name Two.WebGLRenderer#ctx
  12065. * @property {WebGLContext} - Associated two dimensional context to render on the `<canvas />`.
  12066. */
  12067. gl = this.ctx = this.domElement.getContext('webgl', params) ||
  12068. this.domElement.getContext('experimental-webgl', params);
  12069. if (!this.ctx) {
  12070. throw new TwoError(
  12071. 'unable to create a webgl context. Try using another renderer.');
  12072. }
  12073. // Compile Base Shaders to draw in pixel space.
  12074. vs = webgl.shaders.create(
  12075. gl, webgl.shaders.vertex, webgl.shaders.types.vertex);
  12076. fs = webgl.shaders.create(
  12077. gl, webgl.shaders.fragment, webgl.shaders.types.fragment);
  12078. /**
  12079. * @name Two.WebGLRenderer#program
  12080. * @property {WebGLProgram} - Associated WebGL program to render all elements from the scenegraph.
  12081. */
  12082. this.program = webgl.program.create(gl, [vs, fs]);
  12083. gl.useProgram(this.program);
  12084. // Create and bind the drawing buffer
  12085. // look up where the vertex data needs to go.
  12086. this.program.position = gl.getAttribLocation(this.program, 'a_position');
  12087. this.program.matrix = gl.getUniformLocation(this.program, 'u_matrix');
  12088. this.program.rect = gl.getUniformLocation(this.program, 'u_rect');
  12089. // Bind the vertex buffer
  12090. var positionBuffer = gl.createBuffer();
  12091. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  12092. gl.vertexAttribPointer(this.program.position, 2, gl.FLOAT, false, 0, 0);
  12093. gl.enableVertexAttribArray(this.program.position);
  12094. gl.bufferData(
  12095. gl.ARRAY_BUFFER,
  12096. new NumArray([
  12097. 0, 0,
  12098. 1, 0,
  12099. 0, 1,
  12100. 0, 1,
  12101. 1, 0,
  12102. 1, 1
  12103. ]),
  12104. gl.STATIC_DRAW);
  12105. // Setup some initial statements of the gl context
  12106. gl.enable(gl.BLEND);
  12107. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  12108. gl.blendEquation(gl.FUNC_ADD);
  12109. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  12110. }
  12111. _.extend(Renderer, {
  12112. /**
  12113. * @name Two.WebGLRenderer.Utils
  12114. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<canvas />` through the WebGL API.
  12115. */
  12116. Utils: webgl
  12117. });
  12118. _.extend(Renderer.prototype, Events, {
  12119. constructor: Renderer,
  12120. /**
  12121. * @name Two.WebGLRenderer#setSize
  12122. * @function
  12123. * @fires resize
  12124. * @param {Number} width - The new width of the renderer.
  12125. * @param {Number} height - The new height of the renderer.
  12126. * @param {Number} [ratio] - The new pixel ratio (pixel density) of the renderer. Defaults to calculate the pixel density of the user's screen.
  12127. * @description Change the size of the renderer.
  12128. */
  12129. setSize: function(width, height, ratio) {
  12130. this.width = width;
  12131. this.height = height;
  12132. this.ratio = typeof ratio === 'undefined' ? getRatio(this.ctx) : ratio;
  12133. this.domElement.width = width * this.ratio;
  12134. this.domElement.height = height * this.ratio;
  12135. if (_.isObject(this.domElement.style)) {
  12136. _.extend(this.domElement.style, {
  12137. width: width + 'px',
  12138. height: height + 'px'
  12139. });
  12140. }
  12141. // Set for this.stage parent scaling to account for HDPI
  12142. this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio;
  12143. this._flagMatrix = true;
  12144. this.ctx.viewport(0, 0, width * this.ratio, height * this.ratio);
  12145. var resolutionLocation = this.ctx.getUniformLocation(
  12146. this.program, 'u_resolution');
  12147. this.ctx.uniform2f(resolutionLocation, width * this.ratio, height * this.ratio);
  12148. return this.trigger(Events.Types.resize, width, height, ratio);
  12149. },
  12150. /**
  12151. * @name Two.WebGLRenderer#render
  12152. * @function
  12153. * @description Render the current scene to the `<canvas />`.
  12154. */
  12155. render: function() {
  12156. var gl = this.ctx;
  12157. if (!this.overdraw) {
  12158. gl.clear(gl.COLOR_BUFFER_BIT);
  12159. }
  12160. webgl.group.render.call(this.scene, gl, this.program);
  12161. this._flagMatrix = false;
  12162. return this;
  12163. }
  12164. });
  12165. // Utils
  12166. /**
  12167. * @name Two
  12168. * @class
  12169. * @global
  12170. * @param {Object} [options]
  12171. * @param {Boolean} [options.fullscreen=false] - Set to `true` to automatically make the stage adapt to the width and height of the parent document. This parameter overrides `width` and `height` parameters if set to `true`. This overrides `options.fitted` as well.
  12172. * @param {Boolean} [options.fitted=false] = Set to `true` to automatically make the stage adapt to the width and height of the parent element. This parameter overrides `width` and `height` parameters if set to `true`.
  12173. * @param {Number} [options.width=640] - The width of the stage on construction. This can be set at a later time.
  12174. * @param {Number} [options.height=480] - The height of the stage on construction. This can be set at a later time.
  12175. * @param {String} [options.type=Two.Types.svg] - The type of renderer to setup drawing with. See {@link Two.Types} for available options.
  12176. * @param {Boolean} [options.autostart=false] - Set to `true` to add the instance to draw on `requestAnimationFrame`. This is a convenient substitute for {@link Two#play}.
  12177. * @param {Element} [options.domElement] - The canvas or SVG element to draw into. This overrides the `options.type` argument.
  12178. * @description The entrypoint for Two.js. Instantiate a `new Two` in order to setup a scene to render to. `Two` is also the publicly accessible namespace that all other sub-classes, functions, and utilities attach to.
  12179. */
  12180. function Two(options) {
  12181. // Determine what Renderer to use and setup a scene.
  12182. var params = _.defaults(options || {}, {
  12183. fullscreen: false,
  12184. fitted: false,
  12185. width: 640,
  12186. height: 480,
  12187. type: Two.Types.svg,
  12188. autostart: false
  12189. });
  12190. _.each(params, function(v, k) {
  12191. if (/fullscreen/i.test(k) || /autostart/i.test(k)) {
  12192. return;
  12193. }
  12194. this[k] = v;
  12195. }, this);
  12196. // Specified domElement overrides type declaration only if the element does not support declared renderer type.
  12197. if (_.isElement(params.domElement)) {
  12198. var tagName = params.domElement.tagName.toLowerCase();
  12199. // TODO: Reconsider this if statement's logic.
  12200. if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(this.type+'-'+tagName)) {
  12201. this.type = Two.Types[tagName];
  12202. }
  12203. }
  12204. this.renderer = new Two[this.type](this);
  12205. this.setPlaying(params.autostart);
  12206. this.frameCount = 0;
  12207. /**
  12208. * @name Two#fit
  12209. * @function
  12210. * @description If `options.fullscreen` or `options.fitted` in construction create this function. It sets the `width` and `height` of the instance to its respective parent `window` or `element` depending on the `options` passed.
  12211. */
  12212. if (params.fullscreen) {
  12213. this.fit = fitToWindow.bind(this);
  12214. this.fit.domElement = window;
  12215. this.fit.attached = true;
  12216. _.extend(document.body.style, {
  12217. overflow: 'hidden',
  12218. margin: 0,
  12219. padding: 0,
  12220. top: 0,
  12221. left: 0,
  12222. right: 0,
  12223. bottom: 0,
  12224. position: 'fixed'
  12225. });
  12226. _.extend(this.renderer.domElement.style, {
  12227. display: 'block',
  12228. top: 0,
  12229. left: 0,
  12230. right: 0,
  12231. bottom: 0,
  12232. position: 'fixed'
  12233. });
  12234. dom.bind(this.fit.domElement, 'resize', this.fit);
  12235. this.fit();
  12236. } else if (params.fitted) {
  12237. this.fit = fitToParent.bind(this);
  12238. _.extend(this.renderer.domElement.style, {
  12239. display: 'block'
  12240. });
  12241. } else if (!_.isElement(params.domElement)) {
  12242. this.renderer.setSize(params.width, params.height, this.ratio);
  12243. this.width = params.width;
  12244. this.height = params.height;
  12245. }
  12246. this.renderer.bind(Events.Types.resize, updateDimensions.bind(this));
  12247. this.scene = this.renderer.scene;
  12248. Two.Instances.push(this);
  12249. if (params.autostart) {
  12250. raf.init();
  12251. }
  12252. }
  12253. _.extend(Two, Constants);
  12254. _.extend(Two.prototype, Events, {
  12255. constructor: Two,
  12256. /**
  12257. * @name Two#type
  12258. * @property {String} - A string representing which type of renderer the instance has instantiated.
  12259. */
  12260. type: '',
  12261. /**
  12262. * @name Two#renderer
  12263. * @property {(Two.SVGRenderer|Two.CanvasRenderer|Two.WebGLRenderer)} - The instantiated rendering class for the instance. For a list of possible rendering types check out Two.Types.
  12264. */
  12265. renderer: null,
  12266. /**
  12267. * @name Two#scene
  12268. * @property {Two.Group} - The base level {@link Two.Group} which houses all objects for the instance. Because it is a {@link Two.Group} transformations can be applied to it that will affect all objects in the instance. This is handy as a makeshift inverted camera.
  12269. */
  12270. scene: null,
  12271. /**
  12272. * @name Two#width
  12273. * @property {Number} - The width of the instance's dom element.
  12274. */
  12275. width: 0,
  12276. /**
  12277. * @name Two#height
  12278. * @property {Number} - The height of the instance's dom element.
  12279. */
  12280. height: 0,
  12281. /**
  12282. * @name Two#frameCount
  12283. * @property {Number} - An integer representing how many frames have elapsed.
  12284. */
  12285. frameCount: 0,
  12286. /**
  12287. * @name Two#timeDelta
  12288. * @property {Number} - A number representing how much time has elapsed since the last frame in milliseconds.
  12289. */
  12290. timeDelta: 0,
  12291. /**
  12292. * @name Two#playing
  12293. * @property {Boolean} - A boolean representing whether or not the instance is being updated through the automatic `requestAnimationFrame`.
  12294. */
  12295. playing: false,
  12296. /**
  12297. * @name Two#appendTo
  12298. * @function
  12299. * @param {Element} elem - The DOM element to append the Two.js stage to.
  12300. * @description Shorthand method to append your instance of Two.js to the `document`.
  12301. */
  12302. appendTo: function(elem) {
  12303. elem.appendChild(this.renderer.domElement);
  12304. if (this.fit) {
  12305. if (this.fit.domElement !== window) {
  12306. this.fit.domElement = elem;
  12307. this.fit.attached = false;
  12308. }
  12309. this.update();
  12310. }
  12311. return this;
  12312. },
  12313. /**
  12314. * @name Two#play
  12315. * @function
  12316. * @fires Two.Events.Types.play event
  12317. * @description Call to start an internal animation loop.
  12318. * @nota-bene This function initiates a `requestAnimationFrame` loop.
  12319. */
  12320. play: function() {
  12321. this.playing = true;
  12322. raf.init();
  12323. return this.trigger(Events.Types.play);
  12324. },
  12325. /**
  12326. * @name Two#pause
  12327. * @function
  12328. * @fires Two.Events.Types.pause event
  12329. * @description Call to stop the internal animation loop for a specific instance of Two.js.
  12330. */
  12331. pause: function() {
  12332. this.playing = false;
  12333. return this.trigger(Events.Types.pause);
  12334. },
  12335. setPlaying: function(p) {
  12336. this.playing = p;
  12337. },
  12338. /**
  12339. * @name Two#release
  12340. * @function
  12341. * @param {Object} obj
  12342. * @returns {Object} The object passed for event deallocation.
  12343. * @description Release an arbitrary class' events from the Two.js corpus and recurse through its children and or vertices.
  12344. */
  12345. release: function(obj) {
  12346. var i, v, child;
  12347. if (!_.isObject(obj)) {
  12348. return;
  12349. }
  12350. if (typeof obj.unbind === 'function') {
  12351. obj.unbind();
  12352. }
  12353. if (obj.vertices) {
  12354. if (typeof obj.vertices.unbind === 'function') {
  12355. obj.vertices.unbind();
  12356. }
  12357. for (i = 0; i < obj.vertices.length; i++) {
  12358. v = obj.vertices[i];
  12359. if (typeof v.unbind === 'function') {
  12360. v.unbind();
  12361. }
  12362. }
  12363. }
  12364. if (obj.children) {
  12365. for (i = 0; i < obj.children.length; i++) {
  12366. child = obj.children[i];
  12367. this.release(child);
  12368. }
  12369. }
  12370. return obj;
  12371. },
  12372. /**
  12373. * @name Two#update
  12374. * @function
  12375. * @fires Two.Events.Types.update event
  12376. * @description Update positions and calculations in one pass before rendering. Then render to the canvas.
  12377. * @nota-bene This function is called automatically if using {@link Two#play} or the `autostart` parameter in construction.
  12378. */
  12379. update: function() {
  12380. var animated = !!this._lastFrame;
  12381. var now = _.performance.now();
  12382. if (animated) {
  12383. this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3));
  12384. }
  12385. this._lastFrame = now;
  12386. if (this.fit && this.fit.domElement && !this.fit.attached) {
  12387. dom.bind(this.fit.domElement, 'resize', this.fit);
  12388. this.fit.attached = true;
  12389. this.fit();
  12390. }
  12391. var width = this.width;
  12392. var height = this.height;
  12393. var renderer = this.renderer;
  12394. // Update width / height for the renderer
  12395. if (width !== renderer.width || height !== renderer.height) {
  12396. renderer.setSize(width, height, this.ratio);
  12397. }
  12398. this.trigger(Events.Types.update, this.frameCount, this.timeDelta);
  12399. return this.render();
  12400. },
  12401. /**
  12402. * @name Two#render
  12403. * @function
  12404. * @fires render
  12405. * @description Render all drawable and visible objects of the scene.
  12406. */
  12407. render: function() {
  12408. this.renderer.render();
  12409. return this.trigger(Events.Types.render, this.frameCount++);
  12410. },
  12411. // Convenience Methods
  12412. /**
  12413. * @name Two#add
  12414. * @function
  12415. * @param {(Two.Shape[]|...Two.Shape)} [objects] - An array of Two.js objects. Alternatively can add objects as individual arguments.
  12416. * @description A shorthand method to add specific Two.js objects to the scene.
  12417. */
  12418. add: function(o) {
  12419. var objects = o;
  12420. if (!(objects instanceof Array)) {
  12421. objects = Array.prototype.slice.call(arguments);
  12422. }
  12423. this.scene.add(objects);
  12424. return this;
  12425. },
  12426. /**
  12427. * @name Two#remove
  12428. * @function
  12429. * @param {(Two.Shape[]|...Two.Shape)} [objects] - An array of Two.js objects.
  12430. * @description A shorthand method to remove specific Two.js objects from the scene.
  12431. */
  12432. remove: function(o) {
  12433. var objects = o;
  12434. if (!(objects instanceof Array)) {
  12435. objects = Array.prototype.slice.call(arguments);
  12436. }
  12437. this.scene.remove(objects);
  12438. return this;
  12439. },
  12440. /**
  12441. * @name Two#clear
  12442. * @function
  12443. * @description Removes all objects from the instance's scene. If you intend to have the browser garbage collect this, don't forget to delete the references in your application as well.
  12444. */
  12445. clear: function() {
  12446. this.scene.remove(this.scene.children);
  12447. return this;
  12448. },
  12449. /**
  12450. * @name Two#makeLine
  12451. * @function
  12452. * @param {Number} x1
  12453. * @param {Number} y1
  12454. * @param {Number} x2
  12455. * @param {Number} y2
  12456. * @returns {Two.Line}
  12457. * @description Creates a Two.js line and adds it to the scene.
  12458. */
  12459. makeLine: function(x1, y1, x2, y2) {
  12460. var line = new Line(x1, y1, x2, y2);
  12461. this.scene.add(line);
  12462. return line;
  12463. },
  12464. /**
  12465. * @name Two#makeArrow
  12466. * @function
  12467. * @param {Number} x1
  12468. * @param {Number} y1
  12469. * @param {Number} x2
  12470. * @param {Number} y2
  12471. * @returns {Two.Path}
  12472. * @description Creates a Two.js arrow and adds it to the scene.
  12473. */
  12474. makeArrow: function(x1, y1, x2, y2, size) {
  12475. var headlen = typeof size === 'number' ? size : 10;
  12476. var angle = Math.atan2(y2 - y1, x2 - x1);
  12477. var vertices = [
  12478. new Anchor(x1, y1, undefined, undefined, undefined, undefined, Commands.move),
  12479. new Anchor(x2, y2, undefined, undefined, undefined, undefined, Commands.line),
  12480. new Anchor(
  12481. x2 - headlen * Math.cos(angle - Math.PI / 4),
  12482. y2 - headlen * Math.sin(angle - Math.PI / 4),
  12483. undefined, undefined, undefined, undefined, Commands.line
  12484. ),
  12485. new Anchor(x2, y2, undefined, undefined, undefined, undefined, Commands.move),
  12486. new Anchor(
  12487. x2 - headlen * Math.cos(angle + Math.PI / 4),
  12488. y2 - headlen * Math.sin(angle + Math.PI / 4),
  12489. undefined, undefined, undefined, undefined, Commands.line
  12490. )
  12491. ];
  12492. var path = new Path(vertices, false, false, true);
  12493. path.noFill();
  12494. path.cap = 'round';
  12495. path.join = 'round';
  12496. this.scene.add(path);
  12497. return path;
  12498. },
  12499. /**
  12500. * @name Two#makeRectangle
  12501. * @function
  12502. * @param {Number} x
  12503. * @param {Number} y
  12504. * @param {Number} width
  12505. * @param {Number} height
  12506. * @returns {Two.Rectangle}
  12507. * @description Creates a Two.js rectangle and adds it to the scene.
  12508. */
  12509. makeRectangle: function(x, y, width, height) {
  12510. var rect = new Rectangle(x, y, width, height);
  12511. this.scene.add(rect);
  12512. return rect;
  12513. },
  12514. /**
  12515. * @name Two#makeRoundedRectangle
  12516. * @function
  12517. * @param {Number} x
  12518. * @param {Number} y
  12519. * @param {Number} width
  12520. * @param {Number} height
  12521. * @param {Number} sides
  12522. * @returns {Two.Rectangle}
  12523. * @description Creates a Two.js rounded rectangle and adds it to the scene.
  12524. */
  12525. makeRoundedRectangle: function(x, y, width, height, sides) {
  12526. var rect = new RoundedRectangle(x, y, width, height, sides);
  12527. this.scene.add(rect);
  12528. return rect;
  12529. },
  12530. /**
  12531. * @name Two#makeCircle
  12532. * @function
  12533. * @param {Number} x
  12534. * @param {Number} y
  12535. * @param {Number} radius
  12536. * @param {Number} [resolution=4]
  12537. * @returns {Two.Circle}
  12538. * @description Creates a Two.js circle and adds it to the scene.
  12539. */
  12540. makeCircle: function(x, y, radius, resolution) {
  12541. var circle = new Circle(x, y, radius, resolution);
  12542. this.scene.add(circle);
  12543. return circle;
  12544. },
  12545. /**
  12546. * @name Two#makeEllipse
  12547. * @function
  12548. * @param {Number} x
  12549. * @param {Number} y
  12550. * @param {Number} rx
  12551. * @param {Number} ry
  12552. * @param {Number} [resolution=4]
  12553. * @returns {Two.Ellipse}
  12554. * @description Creates a Two.js ellipse and adds it to the scene.
  12555. */
  12556. makeEllipse: function(x, y, rx, ry, resolution) {
  12557. var ellipse = new Ellipse(x, y, rx, ry, resolution);
  12558. this.scene.add(ellipse);
  12559. return ellipse;
  12560. },
  12561. /**
  12562. * @name Two#makeStar
  12563. * @function
  12564. * @param {Number} x
  12565. * @param {Number} y
  12566. * @param {Number} outerRadius
  12567. * @param {Number} innerRadius
  12568. * @param {Number} sides
  12569. * @returns {Two.Star}
  12570. * @description Creates a Two.js star and adds it to the scene.
  12571. */
  12572. makeStar: function(ox, oy, outerRadius, innerRadius, sides) {
  12573. var star = new Star(ox, oy, outerRadius, innerRadius, sides);
  12574. this.scene.add(star);
  12575. return star;
  12576. },
  12577. /**
  12578. * @name Two#makeCurve
  12579. * @function
  12580. * @param {Two.Anchor[]} [points] - An array of {@link Two.Anchor} points.
  12581. * @param {...Number} - Alternatively you can pass alternating `x` / `y` coordinate values as individual arguments. These will be combined into {@link Two.Anchor}s for use in the path.
  12582. * @returns {Two.Path} - Where `path.curved` is set to `true`.
  12583. * @description Creates a Two.js path that is curved and adds it to the scene.
  12584. * @nota-bene In either case of passing an array or passing numbered arguments the last argument is an optional `Boolean` that defines whether the path should be open or closed.
  12585. */
  12586. makeCurve: function(p) {
  12587. var l = arguments.length, points = p;
  12588. if (!Array.isArray(p)) {
  12589. points = [];
  12590. for (var i = 0; i < l; i+=2) {
  12591. var x = arguments[i];
  12592. if (typeof x !== 'number') {
  12593. break;
  12594. }
  12595. var y = arguments[i + 1];
  12596. points.push(new Anchor(x, y));
  12597. }
  12598. }
  12599. var last = arguments[l - 1];
  12600. var curve = new Path(points, !(typeof last === 'boolean' ? last : undefined), true);
  12601. var rect = curve.getBoundingClientRect();
  12602. curve.center().translation
  12603. .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  12604. this.scene.add(curve);
  12605. return curve;
  12606. },
  12607. /**
  12608. * @name Two#makePolygon
  12609. * @function
  12610. * @param {Number} x
  12611. * @param {Number} y
  12612. * @param {Number} radius
  12613. * @param {Number} sides
  12614. * @returns {Two.Polygon}
  12615. * @description Creates a Two.js polygon and adds it to the scene.
  12616. */
  12617. makePolygon: function(x, y, radius, sides) {
  12618. var poly = new Polygon(x, y, radius, sides);
  12619. this.scene.add(poly);
  12620. return poly;
  12621. },
  12622. /**
  12623. * @name Two#makeArcSegment
  12624. * @function
  12625. * @param {Number} x
  12626. * @param {Number} y
  12627. * @param {Number} innerRadius
  12628. * @param {Number} outerRadius
  12629. * @param {Number} startAngle
  12630. * @param {Number} endAngle
  12631. * @param {Number} [resolution=Two.Resolution] - The number of vertices that should comprise the arc segment.
  12632. */
  12633. makeArcSegment: function(ox, oy, ir, or, sa, ea, res) {
  12634. var arcSegment = new ArcSegment(ox, oy, ir, or, sa, ea, res);
  12635. this.scene.add(arcSegment);
  12636. return arcSegment;
  12637. },
  12638. /**
  12639. * @name Two#makePath
  12640. * @function
  12641. * @param {Two.Anchor[]} [points] - An array of {@link Two.Anchor} points.
  12642. * @param {...Number} - Alternatively you can pass alternating `x` / `y` coordinate values as individual arguments. These will be combined into {@link Two.Anchor}s for use in the path.
  12643. * @returns {Two.Path}
  12644. * @description Creates a Two.js path and adds it to the scene.
  12645. * @nota-bene In either case of passing an array or passing numbered arguments the last argument is an optional `Boolean` that defines whether the path should be open or closed.
  12646. */
  12647. makePath: function(p) {
  12648. var l = arguments.length, points = p;
  12649. if (!Array.isArray(p)) {
  12650. points = [];
  12651. for (var i = 0; i < l; i+=2) {
  12652. var x = arguments[i];
  12653. if (typeof x !== 'number') {
  12654. break;
  12655. }
  12656. var y = arguments[i + 1];
  12657. points.push(new Anchor(x, y));
  12658. }
  12659. }
  12660. var last = arguments[l - 1];
  12661. var path = new Path(points, !(typeof last === 'boolean' ? last : undefined));
  12662. var rect = path.getBoundingClientRect();
  12663. if (typeof rect.top === 'number' && typeof rect.left === 'number' &&
  12664. typeof rect.right === 'number' && typeof rect.bottom === 'number') {
  12665. path.center().translation
  12666. .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  12667. }
  12668. this.scene.add(path);
  12669. return path;
  12670. },
  12671. /**
  12672. * @name Two#makeText
  12673. * @function
  12674. * @param {String} message
  12675. * @param {Number} x
  12676. * @param {Number} y
  12677. * @param {Object} [styles] - An object to describe any of the {@link Two.Text.Properties} including `fill`, `stroke`, `linewidth`, `family`, `alignment`, `leading`, `opacity`, etc..
  12678. * @returns {Two.Text}
  12679. * @description Creates a Two.js text object and adds it to the scene.
  12680. */
  12681. makeText: function(message, x, y, styles) {
  12682. var text = new Text(message, x, y, styles);
  12683. this.add(text);
  12684. return text;
  12685. },
  12686. /**
  12687. * @name Two#makeLinearGradient
  12688. * @function
  12689. * @param {Number} x1
  12690. * @param {Number} y1
  12691. * @param {Number} x2
  12692. * @param {Number} y2
  12693. * @param {...Two.Stop} stops - Any number of color stops sometimes reffered to as ramp stops. If none are supplied then the default black-to-white two stop gradient is applied.
  12694. * @returns {Two.LinearGradient}
  12695. * @description Creates a Two.js linear gradient and ads it to the scene. In the case of an effect it's added to an invisible "definitions" group.
  12696. */
  12697. makeLinearGradient: function(x1, y1, x2, y2 /* stops */) {
  12698. var stops = Array.prototype.slice.call(arguments, 4);
  12699. var gradient = new LinearGradient(x1, y1, x2, y2, stops);
  12700. this.add(gradient);
  12701. return gradient;
  12702. },
  12703. /**
  12704. * @name Two#makeRadialGradient
  12705. * @function
  12706. * @param {Number} x1
  12707. * @param {Number} y1
  12708. * @param {Number} radius
  12709. * @param {...Two.Stop} stops - Any number of color stops sometimes reffered to as ramp stops. If none are supplied then the default black-to-white two stop gradient is applied.
  12710. * @returns {Two.RadialGradient}
  12711. * @description Creates a Two.js linear-gradient object and ads it to the scene. In the case of an effect it's added to an invisible "definitions" group.
  12712. */
  12713. makeRadialGradient: function(x1, y1, r /* stops */) {
  12714. var stops = Array.prototype.slice.call(arguments, 3);
  12715. var gradient = new RadialGradient(x1, y1, r, stops);
  12716. this.add(gradient);
  12717. return gradient;
  12718. },
  12719. /**
  12720. * @name Two#makeSprite
  12721. * @function
  12722. * @param {(String|Two.Texture)} pathOrTexture - The URL path to an image or an already created {@link Two.Texture}.
  12723. * @param {Number} x
  12724. * @param {Number} y
  12725. * @param {Number} [columns=1]
  12726. * @param {Number} [rows=1]
  12727. * @param {Number} [frameRate=0]
  12728. * @param {Boolean} [autostart=false]
  12729. * @returns {Two.Sprite}
  12730. * @description Creates a Two.js sprite object and adds it to the scene. Sprites can be used for still images as well as animations.
  12731. */
  12732. makeSprite: function(path, x, y, cols, rows, frameRate, autostart) {
  12733. var sprite = new Sprite(path, x, y, cols, rows, frameRate);
  12734. if (autostart) {
  12735. sprite.play();
  12736. }
  12737. this.add(sprite);
  12738. return sprite;
  12739. },
  12740. /**
  12741. * @name Two#makeImageSequence
  12742. * @function
  12743. * @param {(String[]|Two.Texture[])} pathsOrTextures - An array of paths or of {@link Two.Textures}.
  12744. * @param {Number} x
  12745. * @param {Number} y
  12746. * @param {Number} [frameRate=0]
  12747. * @param {Boolean} [autostart=false]
  12748. * @returns {Two.ImageSequence}
  12749. * @description Creates a Two.js image sequence object and adds it to the scene.
  12750. */
  12751. makeImageSequence: function(paths, x, y, frameRate, autostart) {
  12752. var imageSequence = new ImageSequence(paths, x, y, frameRate);
  12753. if (autostart) {
  12754. imageSequence.play();
  12755. }
  12756. this.add(imageSequence);
  12757. return imageSequence;
  12758. },
  12759. /**
  12760. * @name Two#makeTexture
  12761. * @function
  12762. * @param {(String|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement)} [pathOrSource] - The URL path to an image or a DOM image-like element.
  12763. * @param {Function} [callback] - Function to be invoked when the image is loaded.
  12764. * @returns {Two.Texture}
  12765. * @description Creates a Two.js texture object.
  12766. */
  12767. makeTexture: function(path, callback) {
  12768. var texture = new Texture(path, callback);
  12769. return texture;
  12770. },
  12771. /**
  12772. * @name Two#makeGroup
  12773. * @function
  12774. * @param {(Two.Shape[]|...Two.Shape)} [objects] - Two.js objects to be added to the group in the form of an array or as individual arguments.
  12775. * @returns {Two.Group}
  12776. * @description Creates a Two.js group object and adds it to the scene.
  12777. */
  12778. makeGroup: function(o) {
  12779. var objects = o;
  12780. if (!(objects instanceof Array)) {
  12781. objects = Array.prototype.slice.call(arguments);
  12782. }
  12783. var group = new Group();
  12784. this.scene.add(group);
  12785. group.add(objects);
  12786. return group;
  12787. },
  12788. /**
  12789. * @name Two#interpret
  12790. * @function
  12791. * @param {SVGElement} SVGElement - The SVG node to be parsed.
  12792. * @param {Boolean} shallow - Don't create a top-most group but append all content directly.
  12793. * @param {Boolean} add – Automatically add the reconstructed SVG node to scene.
  12794. * @returns {Two.Group}
  12795. * @description Interpret an SVG Node and add it to this instance's scene. The distinction should be made that this doesn't `import` svg's, it solely interprets them into something compatible for Two.js - this is slightly different than a direct transcription.
  12796. */
  12797. interpret: function(SVGElement, shallow, add) {
  12798. var tag = SVGElement.tagName.toLowerCase();
  12799. add = (typeof add !== 'undefined') ? add : true;
  12800. if (!(tag in read)) {
  12801. return null;
  12802. }
  12803. var node = read[tag].call(this, SVGElement);
  12804. if (add) {
  12805. this.add(shallow && node instanceof Group ? node.children : node);
  12806. } else if (node.parent) {
  12807. // Remove `g` tags that have been added to scenegraph / DOM
  12808. // in order to be compatible with `getById` methods.
  12809. node.remove();
  12810. }
  12811. return node;
  12812. },
  12813. /**
  12814. * @name Two#load
  12815. * @function
  12816. * @param {String|SVGElement} pathOrSVGContent - The URL path of an SVG file or an SVG document as text.
  12817. * @param {Function} callback - Function to call once loading has completed.
  12818. * @returns {Two.Group}
  12819. * @description Load an SVG file or SVG text and interpret it into Two.js legible objects.
  12820. */
  12821. load: function(text, callback) {
  12822. var group = new Group();
  12823. var elem, i, j, child;
  12824. var attach = (function(data) {
  12825. dom.temp.innerHTML = data;
  12826. for (i = 0; i < dom.temp.children.length; i++) {
  12827. elem = dom.temp.children[i];
  12828. if (/svg/i.test(elem.nodeName)) {
  12829. child = this.interpret(elem);
  12830. // Two.Utils.applySvgViewBox.call(this, group, elem.getAttribute('viewBox'));
  12831. for (j = 0; j < child.children.length; j++) {
  12832. group.add(child.children[j]);
  12833. }
  12834. } else {
  12835. group.add(this.interpret(elem));
  12836. }
  12837. }
  12838. if (typeof callback === 'function') {
  12839. var svg = dom.temp.children.length <= 1
  12840. ? dom.temp.children[0] : dom.temp.children;
  12841. callback(group, svg);
  12842. }
  12843. }).bind(this);
  12844. if (/.*\.svg/ig.test(text)) {
  12845. xhr(text, attach);
  12846. return group;
  12847. }
  12848. attach(text);
  12849. return group;
  12850. }
  12851. });
  12852. function fitToWindow() {
  12853. var wr = document.body.getBoundingClientRect();
  12854. var width = this.width = wr.width;
  12855. var height = this.height = wr.height;
  12856. this.renderer.setSize(width, height, this.ratio);
  12857. }
  12858. function fitToParent() {
  12859. var parent = this.renderer.domElement.parentElement;
  12860. if (!parent) {
  12861. console.warn('Two.js: Attempting to fit to parent, but no parent found.');
  12862. return;
  12863. }
  12864. var wr = parent.getBoundingClientRect();
  12865. var width = this.width = wr.width;
  12866. var height = this.height = wr.height;
  12867. this.renderer.setSize(width, height, this.ratio);
  12868. }
  12869. function updateDimensions(width, height) {
  12870. this.width = width;
  12871. this.height = height;
  12872. this.trigger(Events.Types.resize, width, height);
  12873. }
  12874. // Request Animation Frame
  12875. var raf = dom.getRequestAnimationFrame();
  12876. function loop() {
  12877. for (var i = 0; i < Two.Instances.length; i++) {
  12878. var t = Two.Instances[i];
  12879. if (t.playing) {
  12880. t.update();
  12881. }
  12882. }
  12883. Two.nextFrameID = raf(loop);
  12884. }
  12885. raf.init = function() {
  12886. loop();
  12887. raf.init = function() {};
  12888. };
  12889. _.extend(Two, {
  12890. Anchor: Anchor,
  12891. Collection: Collection,
  12892. Events: Events,
  12893. Group: Group,
  12894. Matrix: Matrix,
  12895. Path: Path,
  12896. Registry: Registry,
  12897. Shape: Shape,
  12898. Text: Text,
  12899. Vector: Vector,
  12900. Gradient: Gradient,
  12901. ImageSequence: ImageSequence,
  12902. LinearGradient: LinearGradient,
  12903. RadialGradient: RadialGradient,
  12904. Sprite: Sprite,
  12905. Stop: Stop,
  12906. Texture: Texture,
  12907. ArcSegment: ArcSegment,
  12908. Circle: Circle,
  12909. Ellipse: Ellipse,
  12910. Line: Line,
  12911. Polygon: Polygon,
  12912. Rectangle: Rectangle,
  12913. RoundedRectangle: RoundedRectangle,
  12914. Star: Star,
  12915. CanvasRenderer: Renderer$2,
  12916. SVGRenderer: Renderer$1,
  12917. WebGLRenderer: Renderer,
  12918. Commands: Commands,
  12919. /**
  12920. * @name Two.Utils
  12921. * @property {Object} - A massive object filled with utility functions and properties.
  12922. */
  12923. Utils: _.extend({
  12924. Error: TwoError,
  12925. getRatio: getRatio,
  12926. defineGetterSetter: defineGetterSetter,
  12927. read: read,
  12928. xhr: xhr
  12929. }, _, CanvasShim, Curves, math)
  12930. });
  12931. export default Two;