two.js 447 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411
  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. (function (global, factory) {
  21. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  22. typeof define === 'function' && define.amd ? define(factory) :
  23. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Two = factory());
  24. }(this, (function () { 'use strict';
  25. /**
  26. * @name Two.Commands
  27. * @property {Object} - Map of possible path commands. Taken from the SVG specification.
  28. */
  29. var Commands = {
  30. move: 'M',
  31. line: 'L',
  32. curve: 'C',
  33. arc: 'A',
  34. close: 'Z'
  35. };
  36. var root;
  37. if (typeof window !== 'undefined') {
  38. root = window;
  39. } else if (typeof global !== 'undefined') {
  40. root = global;
  41. } else if (typeof self !== 'undefined') {
  42. root = self;
  43. }
  44. var root$1 = root;
  45. var Matrix$1;
  46. /**
  47. * @name Two.Utils.decomposeMatrix
  48. * @function
  49. * @param {Two.Matrix} matrix - The matrix to decompose.
  50. * @returns {Object} An object containing relevant skew values.
  51. * @description Decompose a 2D 3x3 Matrix to find the skew.
  52. */
  53. var decomposeMatrix = function(matrix) {
  54. // TODO: Include skewX, skewY
  55. // https://math.stackexchange.com/questions/237369/given-this-transformation-matrix-how-do-i-decompose-it-into-translation-rotati/417813
  56. // https://stackoverflow.com/questions/45159314/decompose-2d-transformation-matrix
  57. return {
  58. translateX: matrix.e,
  59. translateY: matrix.f,
  60. scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
  61. scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
  62. rotation: 180 * Math.atan2(matrix.b, matrix.a) / Math.PI
  63. };
  64. };
  65. var setMatrix = function(M) {
  66. Matrix$1 = M;
  67. };
  68. /**
  69. * @name Two.Utils.getComputedMatrix
  70. * @function
  71. * @param {Two.Shape} object - The Two.js object that has a matrix property to calculate from.
  72. * @param {Two.Matrix} [matrix] - The matrix to apply calculated transformations to if available.
  73. * @returns {Two.Matrix} The computed matrix of a nested object. If no `matrix` was passed in arguments then a `new Two.Matrix` is returned.
  74. * @description Method to get the world space transformation of a given object in a Two.js scene.
  75. */
  76. var getComputedMatrix = function(object, matrix) {
  77. matrix = (matrix && matrix.identity()) || new Matrix$1();
  78. var parent = object, matrices = [];
  79. while (parent && parent._matrix) {
  80. matrices.push(parent._matrix);
  81. parent = parent.parent;
  82. }
  83. matrices.reverse();
  84. for (var i = 0; i < matrices.length; i++) {
  85. var m = matrices[i];
  86. var e = m.elements;
  87. matrix.multiply(
  88. e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9]);
  89. }
  90. return matrix;
  91. };
  92. /**
  93. * @name Two.Utils.lerp
  94. * @function
  95. * @param {Number} a - Start value.
  96. * @param {Number} b - End value.
  97. * @param {Number} t - Zero-to-one value describing percentage between a and b.
  98. * @returns {Number}
  99. * @description Linear interpolation between two values `a` and `b` by an amount `t`.
  100. */
  101. var lerp = function(a, b, t) {
  102. return t * (b - a) + a;
  103. };
  104. /**
  105. * @name Two.Utils.mod
  106. * @function
  107. * @param {Number} v - The value to modulo
  108. * @param {Number} l - The value to modulo by
  109. * @returns {Number}
  110. * @description Modulo with added functionality to handle negative values in a positive manner.
  111. */
  112. var mod = function(v, l) {
  113. while (v < 0) {
  114. v += l;
  115. }
  116. return v % l;
  117. };
  118. var NumArray = root$1.Float32Array || Array;
  119. /**
  120. * @name Two.Utils.toFixed
  121. * @function
  122. * @param {Number} v - Any float
  123. * @returns {Number} That float trimmed to the third decimal place.
  124. * @description A pretty fast toFixed(3) alternative.
  125. * @see {@link http://jsperf.com/parsefloat-tofixed-vs-math-round/18}
  126. */
  127. var toFixed = function(v) {
  128. return Math.floor(v * 1000000) / 1000000;
  129. };
  130. var math = /*#__PURE__*/Object.freeze({
  131. __proto__: null,
  132. decomposeMatrix: decomposeMatrix,
  133. getComputedMatrix: getComputedMatrix,
  134. setMatrix: setMatrix,
  135. lerp: lerp,
  136. mod: mod,
  137. NumArray: NumArray,
  138. toFixed: toFixed
  139. });
  140. var slice = Array.prototype.slice;
  141. var isArrayLike = function(collection) {
  142. if (collection === null || collection === undefined) return false;
  143. var length = collection.length;
  144. // Arrays cannot hold more than 2^32 - 1 items
  145. return (typeof length == 'number' && length >= 0 && length < 4294967296);
  146. };
  147. var _ = {
  148. isNaN: function(obj) {
  149. return typeof obj === 'number' && obj !== +obj;
  150. },
  151. isElement: function(obj) {
  152. return !!(obj && obj.nodeType === 1);
  153. },
  154. isObject: function(obj) {
  155. var type = typeof obj;
  156. return type === 'function' || type === 'object' && !!obj;
  157. },
  158. extend: function(base) {
  159. var sources = slice.call(arguments, 1);
  160. for (var i = 0; i < sources.length; i++) {
  161. var obj = sources[i];
  162. for (var k in obj) {
  163. base[k] = obj[k];
  164. }
  165. }
  166. return base;
  167. },
  168. defaults: function(base) {
  169. var sources = slice.call(arguments, 1);
  170. for (var i = 0; i < sources.length; i++) {
  171. var obj = sources[i];
  172. for (var k in obj) {
  173. if (base[k] === void 0) {
  174. base[k] = obj[k];
  175. }
  176. }
  177. }
  178. return base;
  179. },
  180. each: function(obj, iteratee, context) {
  181. var ctx = context || this;
  182. var keys = !isArrayLike(obj) && Object.keys(obj);
  183. var length = (keys || obj).length;
  184. for (var i = 0; i < length; i++) {
  185. var k = keys ? keys[i] : i;
  186. iteratee.call(ctx, obj[k], k, obj);
  187. }
  188. return obj;
  189. },
  190. /**
  191. * @name Two.Utils.performance
  192. * @property {Date} - A special `Date` like object to get the current millis of the session. Used internally to calculate time between frames.
  193. * e.g: `Utils.performance.now() // milliseconds since epoch`
  194. */
  195. performance: ((root$1.performance && root$1.performance.now) ? root$1.performance : Date),
  196. };
  197. /**
  198. * @name Two.Events
  199. * @class
  200. * @description Object inherited by many Two.js objects in order to facilitate custom events.
  201. */
  202. var Events = {
  203. /**
  204. * @name Two.Events#on
  205. * @function
  206. * @param {String} [name] - The name of the event to bind a function to.
  207. * @param {Function} [handler] - The function to be invoked when the event is dispatched.
  208. * @description Call to add a listener to a specific event name.
  209. */
  210. on: addEventListener,
  211. /**
  212. * @name Two.Events#off
  213. * @function
  214. * @param {String} [name] - The name of the event intended to be removed.
  215. * @param {Function} [handler] - The handler intended to be reomved.
  216. * @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.
  217. */
  218. off: removeEventListener,
  219. /**
  220. * @name Two.Events#trigger
  221. * @function
  222. * @param {String} name - The name of the event to dispatch.
  223. * @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.
  224. * @description Call to trigger a custom event. Any additional arguments passed after the name will be passed along to the attached handlers.
  225. */
  226. trigger: function(name) {
  227. var scope = this;
  228. if (!scope._events) return scope;
  229. var args = Array.prototype.slice.call(arguments, 1);
  230. var events = scope._events[name];
  231. if (events) dispatch(scope, events, args);
  232. return scope;
  233. },
  234. listen: function(obj, name, handler) {
  235. var bound = this;
  236. if (obj) {
  237. var event = function () {
  238. handler.apply(bound, arguments);
  239. };
  240. // Add references about the object that assigned this listener
  241. event.obj = obj;
  242. event.name = name;
  243. event.handler = handler;
  244. obj.on(name, event);
  245. }
  246. return bound;
  247. },
  248. ignore: function(obj, name, handler) {
  249. var scope = this;
  250. obj.off(name, handler);
  251. return scope;
  252. },
  253. /**
  254. * @name Two.Events.Types
  255. * @property {Object} - Object of different types of Two.js specific events.
  256. */
  257. Types: {
  258. play: 'play',
  259. pause: 'pause',
  260. update: 'update',
  261. render: 'render',
  262. resize: 'resize',
  263. change: 'change',
  264. remove: 'remove',
  265. insert: 'insert',
  266. order: 'order',
  267. load: 'load'
  268. }
  269. };
  270. /**
  271. * @name Two.Events.bind
  272. * @function
  273. * @description Alias for {@link Two.Events.on}.
  274. */
  275. Events.bind = addEventListener;
  276. /**
  277. * @name Two.Events.unbind
  278. * @function
  279. * @description Alias for {@link Two.Events.off}.
  280. */
  281. Events.unbind = removeEventListener;
  282. /**
  283. * @private
  284. * @returns {Two.Events} - Returns an instance of self for the purpose of chaining.
  285. */
  286. function addEventListener(name, handler) {
  287. var scope = this;
  288. scope._events || (scope._events = {});
  289. var list = scope._events[name] || (scope._events[name] = []);
  290. list.push(handler);
  291. return scope;
  292. }
  293. /**
  294. * @private
  295. * @returns {Two.Events} - Returns an instance of self for the purpose of chaining.
  296. */
  297. function removeEventListener(name, handler) {
  298. var scope = this;
  299. if (!scope._events) {
  300. return scope;
  301. }
  302. if (!name && !handler) {
  303. scope._events = {};
  304. return scope;
  305. }
  306. var names = name ? [name] : Object.keys(scope._events);
  307. for (var i = 0, l = names.length; i < l; i++) {
  308. name = names[i];
  309. var list = scope._events[name];
  310. if (list) {
  311. var events = [];
  312. if (handler) {
  313. for (var j = 0, k = list.length; j < k; j++) {
  314. var ev = list[j];
  315. ev = ev.handler ? ev.handler : ev;
  316. if (handler && handler !== ev) {
  317. events.push(ev);
  318. }
  319. }
  320. }
  321. scope._events[name] = events;
  322. }
  323. }
  324. return scope;
  325. }
  326. function dispatch(obj, events, args) {
  327. var method;
  328. switch (args.length) {
  329. case 0:
  330. method = function(i) {
  331. events[i].call(obj, args[0]);
  332. };
  333. break;
  334. case 1:
  335. method = function(i) {
  336. events[i].call(obj, args[0], args[1]);
  337. };
  338. break;
  339. case 2:
  340. method = function(i) {
  341. events[i].call(obj, args[0], args[1], args[2]);
  342. };
  343. break;
  344. case 3:
  345. method = function(i) {
  346. events[i].call(obj, args[0], args[1], args[2], args[3]);
  347. };
  348. break;
  349. default:
  350. method = function(i) {
  351. events[i].apply(obj, args);
  352. };
  353. }
  354. for (var i = 0; i < events.length; i++) {
  355. method(i);
  356. }
  357. }
  358. /**
  359. * @name Two.Vector
  360. * @class
  361. * @param {Number} [x=0] - Any number to represent the horizontal x-component of the vector.
  362. * @param {Number} [y=0] - Any number to represent the vertical y-component of the vector.
  363. * @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.
  364. */
  365. function Vector(x, y) {
  366. /**
  367. * @name Two.Vector#x
  368. * @property {Number} - The horizontal x-component of the vector.
  369. */
  370. this.x = x || 0;
  371. /**
  372. * @name Two.Vector#y
  373. * @property {Number} - The vertical y-component of the vector.
  374. */
  375. this.y = y || 0;
  376. }
  377. _.extend(Vector, {
  378. /**
  379. * @name Two.Vector.zero
  380. * @readonly
  381. * @property {Two.Vector} - Handy reference to a vector with component values 0, 0 at all times.
  382. */
  383. zero: new Vector(),
  384. /**
  385. * @name Two.Vector.add
  386. * @function
  387. * @param {Two.Vector} v1
  388. * @param {Two.Vector} v2
  389. * @returns {Two.Vector}
  390. * @description Add two vectors together.
  391. */
  392. add: function(v1, v2) {
  393. return new Vector(v1.x + v2.x, v1.y + v2.y);
  394. },
  395. /**
  396. * @name Two.Vector.sub
  397. * @function
  398. * @param {Two.Vector} v1
  399. * @param {Two.Vector} v2
  400. * @returns {Two.Vector}
  401. * @description Subtract two vectors: `v2` from `v1`.
  402. */
  403. sub: function(v1, v2) {
  404. return new Vector(v1.x - v2.x, v1.y - v2.y);
  405. },
  406. /**
  407. * @name Two.Vector.subtract
  408. * @function
  409. * @description Alias for {@link Two.Vector.sub}.
  410. */
  411. subtract: function(v1, v2) {
  412. return Vector.sub(v1, v2);
  413. },
  414. /**
  415. * @name Two.Vector.ratioBetween
  416. * @function
  417. * @param {Two.Vector} A
  418. * @param {Two.Vector} B
  419. * @returns {Number} The ratio betwen two points `v1` and `v2`.
  420. */
  421. ratioBetween: function(v1, v2) {
  422. return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length());
  423. },
  424. /**
  425. * @name Two.Vector.angleBetween
  426. * @function
  427. * @param {Two.Vector} v1
  428. * @param {Two.Vector} v2
  429. * @returns {Number} The angle between points `v1` and `v2`.
  430. */
  431. angleBetween: function(v1, v2) {
  432. var dx, dy;
  433. if (arguments.length >= 4) {
  434. dx = arguments[0] - arguments[2];
  435. dy = arguments[1] - arguments[3];
  436. return Math.atan2(dy, dx);
  437. }
  438. dx = v1.x - v2.x;
  439. dy = v1.y - v2.y;
  440. return Math.atan2(dy, dx);
  441. },
  442. /**
  443. * @name Two.Vector.distanceBetween
  444. * @function
  445. * @param {Two.Vector} v1
  446. * @param {Two.Vector} v2
  447. * @returns {Number} The distance between points `v1` and `v2`. Distance is always positive.
  448. */
  449. distanceBetween: function(v1, v2) {
  450. return Math.sqrt(Vector.distanceBetweenSquared(v1, v2));
  451. },
  452. /**
  453. * @name Two.Vector.distanceBetweenSquared
  454. * @function
  455. * @param {Two.Vector} v1
  456. * @param {Two.Vector} v2
  457. * @returns {Number} The squared distance between points `v1` and `v2`.
  458. */
  459. distanceBetweenSquared: function(v1, v2) {
  460. var dx = v1.x - v2.x;
  461. var dy = v1.y - v2.y;
  462. return dx * dx + dy * dy;
  463. },
  464. /**
  465. * @name Two.Vector.MakeObservable
  466. * @function
  467. * @param {Object} object - The object to make observable.
  468. * @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.
  469. */
  470. MakeObservable: function(object) {
  471. // /**
  472. // * Override Backbone bind / on in order to add properly broadcasting.
  473. // * This allows Two.Vector to not broadcast events unless event listeners
  474. // * are explicity bound to it.
  475. // */
  476. object.bind = object.on = function() {
  477. if (!this._bound) {
  478. this._x = this.x;
  479. this._y = this.y;
  480. Object.defineProperty(this, 'x', xgs);
  481. Object.defineProperty(this, 'y', ygs);
  482. _.extend(this, BoundProto);
  483. this._bound = true; // Reserved for event initialization check
  484. }
  485. Events.bind.apply(this, arguments);
  486. return this;
  487. };
  488. }
  489. });
  490. _.extend(Vector.prototype, Events, {
  491. constructor: Vector,
  492. /**
  493. * @name Two.Vector#set
  494. * @function
  495. * @param {Number} x
  496. * @param {Number} y
  497. * @description Set the x / y components of a vector to specific number values.
  498. */
  499. set: function(x, y) {
  500. this.x = x;
  501. this.y = y;
  502. return this;
  503. },
  504. /**
  505. * @name Two.Vector#copy
  506. * @function
  507. * @param {Two.Vector} v
  508. * @description Copy the x / y components of another object `v`.
  509. */
  510. copy: function(v) {
  511. this.x = v.x;
  512. this.y = v.y;
  513. return this;
  514. },
  515. /**
  516. * @name Two.Vector#clear
  517. * @function
  518. * @description Set the x / y component values of the vector to zero.
  519. */
  520. clear: function() {
  521. this.x = 0;
  522. this.y = 0;
  523. return this;
  524. },
  525. /**
  526. * @name Two.Vector#clone
  527. * @function
  528. * @description Create a new vector and copy the existing values onto the newly created instance.
  529. */
  530. clone: function() {
  531. return new Vector(this.x, this.y);
  532. },
  533. /**
  534. * @name Two.Vector#add
  535. * @function
  536. * @param {Two.Vector} v
  537. * @description Add an object with x / y component values to the instance.
  538. * @overloaded
  539. */
  540. /**
  541. * @name Two.Vector#add
  542. * @function
  543. * @param {Number} v
  544. * @description Add the **same** number to both x / y component values of the instance.
  545. * @overloaded
  546. */
  547. /**
  548. * @name Two.Vector#add
  549. * @function
  550. * @param {Number} x
  551. * @param {Number} y
  552. * @description Add `x` / `y` values to their respective component value on the instance.
  553. * @overloaded
  554. */
  555. add: function(x, y) {
  556. if (arguments.length <= 0) {
  557. return this;
  558. } else if (arguments.length <= 1) {
  559. if (typeof x === 'number') {
  560. this.x += x;
  561. this.y += x;
  562. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  563. this.x += x.x;
  564. this.y += x.y;
  565. }
  566. } else {
  567. this.x += x;
  568. this.y += y;
  569. }
  570. return this;
  571. },
  572. /**
  573. * @name Two.Vector#addSelf
  574. * @function
  575. * @description Alias for {@link Two.Vector.add}.
  576. */
  577. addSelf: function(v) {
  578. return this.add.apply(this, arguments);
  579. },
  580. /**
  581. * @name Two.Vector#sub
  582. * @function
  583. * @param {Two.Vector} v
  584. * @description Subtract an object with x / y component values to the instance.
  585. * @overloaded
  586. */
  587. /**
  588. * @name Two.Vector#sub
  589. * @function
  590. * @param {Number} v
  591. * @description Subtract the **same** number to both x / y component values of the instance.
  592. * @overloaded
  593. */
  594. /**
  595. * @name Two.Vector#sub
  596. * @function
  597. * @param {Number} x
  598. * @param {Number} y
  599. * @description Subtract `x` / `y` values to their respective component value on the instance.
  600. * @overloaded
  601. */
  602. sub: function(x, y) {
  603. if (arguments.length <= 0) {
  604. return this;
  605. } else if (arguments.length <= 1) {
  606. if (typeof x === 'number') {
  607. this.x -= x;
  608. this.y -= x;
  609. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  610. this.x -= x.x;
  611. this.y -= x.y;
  612. }
  613. } else {
  614. this.x -= x;
  615. this.y -= y;
  616. }
  617. return this;
  618. },
  619. /**
  620. * @name Two.Vector#subtract
  621. * @function
  622. * @description Alias for {@link Two.Vector.sub}.
  623. */
  624. subtract: function() {
  625. return this.sub.apply(this, arguments);
  626. },
  627. /**
  628. * @name Two.Vector#subSelf
  629. * @function
  630. * @description Alias for {@link Two.Vector.sub}.
  631. */
  632. subSelf: function(v) {
  633. return this.sub.apply(this, arguments);
  634. },
  635. /**
  636. * @name Two.Vector#subtractSelf
  637. * @function
  638. * @description Alias for {@link Two.Vector.sub}.
  639. */
  640. subtractSelf: function(v) {
  641. return this.sub.apply(this, arguments);
  642. },
  643. /**
  644. * @name Two.Vector#multiply
  645. * @function
  646. * @param {Two.Vector} v
  647. * @description Multiply an object with x / y component values to the instance.
  648. * @overloaded
  649. */
  650. /**
  651. * @name Two.Vector#multiply
  652. * @function
  653. * @param {Number} v
  654. * @description Multiply the **same** number to both x / y component values of the instance.
  655. * @overloaded
  656. */
  657. /**
  658. * @name Two.Vector#multiply
  659. * @function
  660. * @param {Number} x
  661. * @param {Number} y
  662. * @description Multiply `x` / `y` values to their respective component value on the instance.
  663. * @overloaded
  664. */
  665. multiply: function(x, y) {
  666. if (arguments.length <= 0) {
  667. return this;
  668. } else if (arguments.length <= 1) {
  669. if (typeof x === 'number') {
  670. this.x *= x;
  671. this.y *= x;
  672. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  673. this.x *= x.x;
  674. this.y *= x.y;
  675. }
  676. } else {
  677. this.x *= x;
  678. this.y *= y;
  679. }
  680. return this;
  681. },
  682. /**
  683. * @name Two.Vector#multiplySelf
  684. * @function
  685. * @description Alias for {@link Two.Vector.multiply}.
  686. */
  687. multiplySelf: function(v) {
  688. return this.multiply.apply(this, arguments);
  689. },
  690. /**
  691. * @name Two.Vector#multiplyScalar
  692. * @function
  693. * @param {Number} s - The scalar to multiply by.
  694. * @description Mulitiply the vector by a single number. Shorthand to call {@link Two.Vector#multiply} directly.
  695. */
  696. multiplyScalar: function(s) {
  697. return this.multiply(s);
  698. },
  699. /**
  700. * @name Two.Vector#divide
  701. * @function
  702. * @param {Two.Vector} v
  703. * @description Divide an object with x / y component values to the instance.
  704. * @overloaded
  705. */
  706. /**
  707. * @name Two.Vector#divide
  708. * @function
  709. * @param {Number} v
  710. * @description Divide the **same** number to both x / y component values of the instance.
  711. * @overloaded
  712. */
  713. /**
  714. * @name Two.Vector#divide
  715. * @function
  716. * @param {Number} x
  717. * @param {Number} y
  718. * @description Divide `x` / `y` values to their respective component value on the instance.
  719. * @overloaded
  720. */
  721. divide: function(x, y) {
  722. if (arguments.length <= 0) {
  723. return this;
  724. } else if (arguments.length <= 1) {
  725. if (typeof x === 'number') {
  726. this.x /= x;
  727. this.y /= x;
  728. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  729. this.x /= x.x;
  730. this.y /= x.y;
  731. }
  732. } else {
  733. this.x /= x;
  734. this.y /= y;
  735. }
  736. if (_.isNaN(this.x)) {
  737. this.x = 0;
  738. }
  739. if (_.isNaN(this.y)) {
  740. this.y = 0;
  741. }
  742. return this;
  743. },
  744. /**
  745. * @name Two.Vector#divideSelf
  746. * @function
  747. * @description Alias for {@link Two.Vector.divide}.
  748. */
  749. divideSelf: function(v) {
  750. return this.divide.apply(this, arguments);
  751. },
  752. /**
  753. * @name Two.Vector#divideScalar
  754. * @function
  755. * @param {Number} s - The scalar to divide by.
  756. * @description Divide the vector by a single number. Shorthand to call {@link Two.Vector#divide} directly.
  757. */
  758. divideScalar: function(s) {
  759. return this.divide(s);
  760. },
  761. /**
  762. * @name Two.Vector#negate
  763. * @function
  764. * @description Invert each component's sign value.
  765. */
  766. negate: function() {
  767. return this.multiply(-1);
  768. },
  769. /**
  770. * @name Two.Vector#negate
  771. * @function
  772. * @returns {Number}
  773. * @description Get the [dot product](https://en.wikipedia.org/wiki/Dot_product) of the vector.
  774. */
  775. dot: function(v) {
  776. return this.x * v.x + this.y * v.y;
  777. },
  778. /**
  779. * @name Two.Vector#length
  780. * @function
  781. * @returns {Number}
  782. * @description Get the length of a vector.
  783. */
  784. length: function() {
  785. return Math.sqrt(this.lengthSquared());
  786. },
  787. /**
  788. * @name Two.Vector#lengthSquared
  789. * @function
  790. * @returns {Number}
  791. * @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.
  792. */
  793. lengthSquared: function() {
  794. return this.x * this.x + this.y * this.y;
  795. },
  796. /**
  797. * @name Two.Vector#normalize
  798. * @function
  799. * @description Normalize the vector from negative one to one.
  800. */
  801. normalize: function() {
  802. return this.divideScalar(this.length());
  803. },
  804. /**
  805. * @name Two.Vector#distanceTo
  806. * @function
  807. * @returns {Number}
  808. * @description Get the distance between two vectors.
  809. */
  810. distanceTo: function(v) {
  811. return Math.sqrt(this.distanceToSquared(v));
  812. },
  813. /**
  814. * @name Two.Vector#distanceToSquared
  815. * @function
  816. * @returns {Number}
  817. * @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.
  818. */
  819. distanceToSquared: function(v) {
  820. var dx = this.x - v.x,
  821. dy = this.y - v.y;
  822. return dx * dx + dy * dy;
  823. },
  824. /**
  825. * @name Two.Vector#setLength
  826. * @function
  827. * @param {Number} l - length to set vector to.
  828. * @description Set the length of a vector.
  829. */
  830. setLength: function(l) {
  831. return this.normalize().multiplyScalar(l);
  832. },
  833. /**
  834. * @name Two.Vector#equals
  835. * @function
  836. * @param {Two.Vector} v - The vector to compare against.
  837. * @param {Number} [eps=0.0001] - An options epsilon for precision.
  838. * @returns {Boolean}
  839. * @description Qualify if one vector roughly equal another. With a margin of error defined by epsilon.
  840. */
  841. equals: function(v, eps) {
  842. eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  843. return (this.distanceTo(v) < eps);
  844. },
  845. /**
  846. * @name Two.Vector#lerp
  847. * @function
  848. * @param {Two.Vector} v - The destination vector to step towards.
  849. * @param {Number} t - The zero to one value of how close the current vector gets to the destination vector.
  850. * @description Linear interpolate one vector to another by an amount `t` defined as a zero to one number.
  851. * @see [Matt DesLauriers](https://twitter.com/mattdesl/status/1031305279227478016) has a good thread about this.
  852. */
  853. lerp: function(v, t) {
  854. var x = (v.x - this.x) * t + this.x;
  855. var y = (v.y - this.y) * t + this.y;
  856. return this.set(x, y);
  857. },
  858. /**
  859. * @name Two.Vector#isZero
  860. * @function
  861. * @param {Number} [eps=0.0001] - Optional precision amount to check against.
  862. * @returns {Boolean}
  863. * @description Check to see if vector is roughly zero, based on the `epsilon` precision value.
  864. */
  865. isZero: function(eps) {
  866. eps = (typeof eps === 'undefined') ? 0.0001 : eps;
  867. return (this.length() < eps);
  868. },
  869. /**
  870. * @name Two.Vector#toString
  871. * @function
  872. * @returns {String}
  873. * @description Return a comma-separated string of x, y value. Great for storing in a database.
  874. */
  875. toString: function() {
  876. return this.x + ', ' + this.y;
  877. },
  878. /**
  879. * @name Two.Vector#toObject
  880. * @function
  881. * @returns {Object}
  882. * @description Return a JSON compatible plain object that represents the vector.
  883. */
  884. toObject: function() {
  885. return { x: this.x, y: this.y };
  886. },
  887. /**
  888. * @name Two.Vector#rotate
  889. * @function
  890. * @param {Number} Number - The amoun to rotate the vector by.
  891. * @description Rotate a vector.
  892. */
  893. rotate: function(Number) {
  894. var cos = Math.cos(Number);
  895. var sin = Math.sin(Number);
  896. this.x = this.x * cos - this.y * sin;
  897. this.y = this.x * sin + this.y * cos;
  898. return this;
  899. }
  900. });
  901. // The same set of prototypical functions, but using the underlying
  902. // getter or setter for `x` and `y` values. This set of functions
  903. // is used instead of the previously documented ones above when
  904. // Two.Vector#bind is invoked and there is event dispatching processed
  905. // on x / y property changes.
  906. var BoundProto = {
  907. constructor: Vector,
  908. set: function(x, y) {
  909. this._x = x;
  910. this._y = y;
  911. return this.trigger(Events.Types.change);
  912. },
  913. copy: function(v) {
  914. this._x = v.x;
  915. this._y = v.y;
  916. return this.trigger(Events.Types.change);
  917. },
  918. clear: function() {
  919. this._x = 0;
  920. this._y = 0;
  921. return this.trigger(Events.Types.change);
  922. },
  923. clone: function() {
  924. return new Vector(this._x, this._y);
  925. },
  926. add: function(x, y) {
  927. if (arguments.length <= 0) {
  928. return this;
  929. } else if (arguments.length <= 1) {
  930. if (typeof x === 'number') {
  931. this._x += x;
  932. this._y += x;
  933. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  934. this._x += x.x;
  935. this._y += x.y;
  936. }
  937. } else {
  938. this._x += x;
  939. this._y += y;
  940. }
  941. return this.trigger(Events.Types.change);
  942. },
  943. sub: function(x, y) {
  944. if (arguments.length <= 0) {
  945. return this;
  946. } else if (arguments.length <= 1) {
  947. if (typeof x === 'number') {
  948. this._x -= x;
  949. this._y -= x;
  950. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  951. this._x -= x.x;
  952. this._y -= x.y;
  953. }
  954. } else {
  955. this._x -= x;
  956. this._y -= y;
  957. }
  958. return this.trigger(Events.Types.change);
  959. },
  960. multiply: function(x, y) {
  961. if (arguments.length <= 0) {
  962. return this;
  963. } else if (arguments.length <= 1) {
  964. if (typeof x === 'number') {
  965. this._x *= x;
  966. this._y *= x;
  967. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  968. this._x *= x.x;
  969. this._y *= x.y;
  970. }
  971. } else {
  972. this._x *= x;
  973. this._y *= y;
  974. }
  975. return this.trigger(Events.Types.change);
  976. },
  977. divide: function(x, y) {
  978. if (arguments.length <= 0) {
  979. return this;
  980. } else if (arguments.length <= 1) {
  981. if (typeof x === 'number') {
  982. this._x /= x;
  983. this._y /= x;
  984. } else if (x && typeof x.x === 'number' && typeof x.y === 'number') {
  985. this._x /= x.x;
  986. this._y /= x.y;
  987. }
  988. } else {
  989. this._x /= x;
  990. this._y /= y;
  991. }
  992. if (_.isNaN(this._x)) {
  993. this._x = 0;
  994. }
  995. if (_.isNaN(this._y)) {
  996. this._y = 0;
  997. }
  998. return this.trigger(Events.Types.change);
  999. },
  1000. dot: function(v) {
  1001. return this._x * v.x + this._y * v.y;
  1002. },
  1003. lengthSquared: function() {
  1004. return this._x * this._x + this._y * this._y;
  1005. },
  1006. distanceToSquared: function(v) {
  1007. var dx = this._x - v.x,
  1008. dy = this._y - v.y;
  1009. return dx * dx + dy * dy;
  1010. },
  1011. lerp: function(v, t) {
  1012. var x = (v.x - this._x) * t + this._x;
  1013. var y = (v.y - this._y) * t + this._y;
  1014. return this.set(x, y);
  1015. },
  1016. toString: function() {
  1017. return this._x + ', ' + this._y;
  1018. },
  1019. toObject: function() {
  1020. return { x: this._x, y: this._y };
  1021. },
  1022. rotate: function (Number) {
  1023. var cos = Math.cos(Number);
  1024. var sin = Math.sin(Number);
  1025. this._x = this._x * cos - this._y * sin;
  1026. this._y = this._x * sin + this._y * cos;
  1027. return this;
  1028. }
  1029. };
  1030. var xgs = {
  1031. enumerable: true,
  1032. get: function() {
  1033. return this._x;
  1034. },
  1035. set: function(v) {
  1036. this._x = v;
  1037. this.trigger(Events.Types.change, 'x');
  1038. }
  1039. };
  1040. var ygs = {
  1041. enumerable: true,
  1042. get: function() {
  1043. return this._y;
  1044. },
  1045. set: function(v) {
  1046. this._y = v;
  1047. this.trigger(Events.Types.change, 'y');
  1048. }
  1049. };
  1050. Vector.MakeObservable(Vector.prototype);
  1051. /**
  1052. * @class
  1053. * @name Two.Anchor
  1054. * @param {Number} [x=0] - The x position of the root anchor point.
  1055. * @param {Number} [y=0] - The y position of the root anchor point.
  1056. * @param {Number} [lx=0] - The x position of the left handle point.
  1057. * @param {Number} [ly=0] - The y position of the left handle point.
  1058. * @param {Number} [rx=0] - The x position of the right handle point.
  1059. * @param {Number} [ry=0] - The y position of the right handle point.
  1060. * @param {String} [command=Two.Commands.move] - The command to describe how to render. Applicable commands are {@link Two.Commands}
  1061. * @extends Two.Vector
  1062. * @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.
  1063. */
  1064. function Anchor(x, y, lx, ly, rx, ry, command) {
  1065. Vector.call(this, x, y);
  1066. this._broadcast = (function() {
  1067. this.trigger(Events.Types.change);
  1068. }).bind(this);
  1069. this._command = command || Commands.move;
  1070. this._relative = true;
  1071. var ilx = typeof lx === 'number';
  1072. var ily = typeof ly === 'number';
  1073. var irx = typeof rx === 'number';
  1074. var iry = typeof ry === 'number';
  1075. // Append the `controls` object only if control points are specified,
  1076. // keeping the Two.Anchor inline with a Two.Vector until it needs to
  1077. // evolve beyond those functions - e.g: a simple 2 component vector.
  1078. if (ilx || ily || irx || iry) {
  1079. Anchor.AppendCurveProperties(this);
  1080. }
  1081. if (ilx) {
  1082. this.controls.left.x = lx;
  1083. }
  1084. if (ily) {
  1085. this.controls.left.y = ly;
  1086. }
  1087. if (irx) {
  1088. this.controls.right.x = rx;
  1089. }
  1090. if (iry) {
  1091. this.controls.right.y = ry;
  1092. }
  1093. }
  1094. _.extend(Anchor, {
  1095. /**
  1096. * @name Two.Anchor.AppendCurveProperties
  1097. * @function
  1098. * @param {Two.Anchor} anchor - The instance to append the `control`object to.
  1099. * @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.
  1100. */
  1101. AppendCurveProperties: function(anchor) {
  1102. anchor.relative = true;
  1103. /**
  1104. * @name Two.Anchor#controls
  1105. * @property {Object} controls
  1106. * @description An plain object that holds the controls handles for a {@link Two.Anchor}.
  1107. */
  1108. anchor.controls = {};
  1109. /**
  1110. * @name Two.Anchor#controls#left
  1111. * @property {Two.Vector} left
  1112. * @description The "left" control point to define handles on a bezier curve.
  1113. */
  1114. anchor.controls.left = new Vector(0, 0);
  1115. /**
  1116. * @name Two.Anchor#controls#right
  1117. * @property {Two.Vector} right
  1118. * @description The "left" control point to define handles on a bezier curve.
  1119. */
  1120. anchor.controls.right = new Vector(0, 0);
  1121. },
  1122. /**
  1123. * @name Two.Anchor.MakeObservable
  1124. * @function
  1125. * @param {Object} object - The object to make observable.
  1126. * @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.
  1127. */
  1128. MakeObservable: function(object) {
  1129. /**
  1130. * @name Two.Anchor#command
  1131. * @property {Two.Commands}
  1132. * @description A draw command associated with the anchor point.
  1133. */
  1134. Object.defineProperty(object, 'command', {
  1135. enumerable: true,
  1136. get: function() {
  1137. return this._command;
  1138. },
  1139. set: function(c) {
  1140. this._command = c;
  1141. if (this._command === Commands.curve && !_.isObject(this.controls)) {
  1142. Anchor.AppendCurveProperties(this);
  1143. }
  1144. this.trigger(Events.Types.change);
  1145. }
  1146. });
  1147. /**
  1148. * @name Two.Anchor#relative
  1149. * @property {Boolean}
  1150. * @description A boolean to render control points relative to the root anchor point or in global coordinate-space to the rest of the scene.
  1151. */
  1152. Object.defineProperty(object, 'relative', {
  1153. enumerable: true,
  1154. get: function() {
  1155. return this._relative;
  1156. },
  1157. set: function(b) {
  1158. if (this._relative != b) {
  1159. this._relative = !!b;
  1160. this.trigger(Events.Types.change);
  1161. }
  1162. }
  1163. });
  1164. _.extend(object, Vector.prototype, AnchorProto);
  1165. // Make it possible to bind and still have the Anchor specific
  1166. // inheritance from Two.Vector. In this case relying on `Two.Vector`
  1167. // to do much of the heavy event-listener binding / unbinding.
  1168. object.bind = object.on = function() {
  1169. var bound = this._bound;
  1170. Vector.prototype.bind.apply(this, arguments);
  1171. if (!bound) {
  1172. _.extend(this, AnchorProto);
  1173. }
  1174. };
  1175. }
  1176. });
  1177. var AnchorProto = {
  1178. constructor: Anchor,
  1179. /**
  1180. * @name Two.Anchor#listen
  1181. * @function
  1182. * @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.
  1183. */
  1184. listen: function() {
  1185. if (!_.isObject(this.controls)) {
  1186. Anchor.AppendCurveProperties(this);
  1187. }
  1188. this.controls.left.bind(Events.Types.change, this._broadcast);
  1189. this.controls.right.bind(Events.Types.change, this._broadcast);
  1190. return this;
  1191. },
  1192. /**
  1193. * @name Two.Anchor#ignore
  1194. * @function
  1195. * @description Convenience method used mainly by {@link Two.Path#vertices} to ignore changes from a specific anchor's control points.
  1196. */
  1197. ignore: function() {
  1198. this.controls.left.unbind(Events.Types.change, this._broadcast);
  1199. this.controls.right.unbind(Events.Types.change, this._broadcast);
  1200. return this;
  1201. },
  1202. /**
  1203. * @name Two.Anchor#copy
  1204. * @function
  1205. * @param {Two.Anchor} v - The anchor to apply values to.
  1206. * @description Copy the properties of one {@link Two.Anchor} onto another.
  1207. */
  1208. copy: function(v) {
  1209. this.x = v.x;
  1210. this.y = v.y;
  1211. if (typeof v.command === 'string') {
  1212. this.command = v.command;
  1213. }
  1214. if (_.isObject(v.controls)) {
  1215. if (!_.isObject(this.controls)) {
  1216. Anchor.AppendCurveProperties(this);
  1217. }
  1218. // TODO: Do we need to listen here?
  1219. this.controls.left.copy(v.controls.left);
  1220. this.controls.right.copy(v.controls.right);
  1221. }
  1222. if (typeof v.relative === 'boolean') {
  1223. this.relative = v.relative;
  1224. }
  1225. // TODO: Hack for `Two.Commands.arc`
  1226. if (this.command === Commands.arc) {
  1227. this.rx = v.rx;
  1228. this.ry = v.ry;
  1229. this.xAxisRotation = v.xAxisRotation;
  1230. this.largeArcFlag = v.largeArcFlag;
  1231. this.sweepFlag = v.sweepFlag;
  1232. }
  1233. return this;
  1234. },
  1235. /**
  1236. * @name Two.Anchor#clone
  1237. * @function
  1238. * @returns {Two.Anchor}
  1239. * @description Create a new {@link Two.Anchor}, set all its values to the current instance and return it for use.
  1240. */
  1241. clone: function() {
  1242. var controls = this.controls;
  1243. var clone = new Anchor(
  1244. this.x,
  1245. this.y,
  1246. controls && controls.left.x,
  1247. controls && controls.left.y,
  1248. controls && controls.right.x,
  1249. controls && controls.right.y,
  1250. this.command
  1251. );
  1252. clone.relative = this._relative;
  1253. return clone;
  1254. },
  1255. /**
  1256. * @name Two.Anchor#toObject
  1257. * @function
  1258. * @returns {Object} - An object with properties filled out to mirror {@link Two.Anchor}.
  1259. * @description Create a JSON compatible plain object of the current instance. Intended for use with storing values in a database.
  1260. */
  1261. toObject: function() {
  1262. var o = {
  1263. x: this.x,
  1264. y: this.y
  1265. };
  1266. if (this._command) {
  1267. o.command = this._command;
  1268. }
  1269. if (this._relative) {
  1270. o.relative = this._relative;
  1271. }
  1272. if (this.controls) {
  1273. o.controls = {
  1274. left: this.controls.left.toObject(),
  1275. right: this.controls.right.toObject()
  1276. };
  1277. }
  1278. return o;
  1279. },
  1280. /**
  1281. * @name Two.Anchor#toString
  1282. * @function
  1283. * @returns {String} - A String with comma-separated values reflecting the various values on the current instance.
  1284. * @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}.
  1285. */
  1286. toString: function() {
  1287. if (!this.controls) {
  1288. return [this._x, this._y].join(', ');
  1289. }
  1290. return [this._x, this._y, this.controls.left.x, this.controls.left.y,
  1291. this.controls.right.x, this.controls.right.y, this._command,
  1292. this._relative ? 1 : 0].join(', ');
  1293. }
  1294. };
  1295. Anchor.MakeObservable(Anchor.prototype);
  1296. var count = 0;
  1297. var Constants = {
  1298. /**
  1299. * @name Two.nextFrameID
  1300. * @property {Number}
  1301. * @description The id of the next requestAnimationFrame function.
  1302. */
  1303. nextFrameID: null,
  1304. // Primitive
  1305. /**
  1306. * @name Two.Types
  1307. * @property {Object} - The different rendering types available in the library.
  1308. */
  1309. Types: {
  1310. webgl: 'WebGLRenderer',
  1311. svg: 'SVGRenderer',
  1312. canvas: 'CanvasRenderer'
  1313. },
  1314. /**
  1315. * @name Two.Version
  1316. * @property {String} - The current working version of the library.
  1317. */
  1318. Version: 'v0.7.6',
  1319. /**
  1320. * @name Two.PublishDate
  1321. * @property {String} - The automatically generated publish date in the build process to verify version release candidates.
  1322. */
  1323. PublishDate: '2021-06-08T20:19:33.699Z',
  1324. /**
  1325. * @name Two.Identifier
  1326. * @property {String} - String prefix for all Two.js object's ids. This trickles down to SVG ids.
  1327. */
  1328. Identifier: 'two-',
  1329. /**
  1330. * @name Two.Resolution
  1331. * @property {Number} - Default amount of vertices to be used for interpreting Arcs and ArcSegments.
  1332. */
  1333. Resolution: 12,
  1334. /**
  1335. * @name Two.AutoCalculateImportedMatrices
  1336. * @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.
  1337. * @nota-bene `false` copies the exact transformation matrix values, but also sets the path's `matrix.manual = true`.
  1338. */
  1339. AutoCalculateImportedMatrices: true,
  1340. /**
  1341. * @name Two.Instances
  1342. * @property {Two[]} - Registered list of all Two.js instances in the current session.
  1343. */
  1344. Instances: [],
  1345. /**
  1346. * @function Two.uniqueId
  1347. * @description Simple method to access an incrementing value. Used for `id` allocation on all Two.js objects.
  1348. * @returns {Number} Ever increasing Number.
  1349. */
  1350. uniqueId: function() {
  1351. return count++;
  1352. }
  1353. };
  1354. var HALF_PI$3 = Math.PI / 2;
  1355. /**
  1356. * @name Two.Utils.Curve
  1357. * @property {Object} - Additional utility constant variables related to curve math and calculations.
  1358. */
  1359. var Curve = {
  1360. CollinearityEpsilon: Math.pow(10, -30),
  1361. RecursionLimit: 16,
  1362. CuspLimit: 0,
  1363. Tolerance: {
  1364. distance: 0.25,
  1365. angle: 0,
  1366. epsilon: Number.EPSILON
  1367. },
  1368. // Lookup tables for abscissas and weights with values for n = 2 .. 16.
  1369. // As values are symmetric, only store half of them and adapt algorithm
  1370. // to factor in symmetry.
  1371. abscissas: [
  1372. [ 0.5773502691896257645091488],
  1373. [0,0.7745966692414833770358531],
  1374. [ 0.3399810435848562648026658,0.8611363115940525752239465],
  1375. [0,0.5384693101056830910363144,0.9061798459386639927976269],
  1376. [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016],
  1377. [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897],
  1378. [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609],
  1379. [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762],
  1380. [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640],
  1381. [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380],
  1382. [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491],
  1383. [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294],
  1384. [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973],
  1385. [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657],
  1386. [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542]
  1387. ],
  1388. weights: [
  1389. [1],
  1390. [0.8888888888888888888888889,0.5555555555555555555555556],
  1391. [0.6521451548625461426269361,0.3478548451374538573730639],
  1392. [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640],
  1393. [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961],
  1394. [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114],
  1395. [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314],
  1396. [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922],
  1397. [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688],
  1398. [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537],
  1399. [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160],
  1400. [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216],
  1401. [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329],
  1402. [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284],
  1403. [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806]
  1404. ]
  1405. };
  1406. /**
  1407. * @name Two.Utils.getComponentOnCubicBezier
  1408. * @function
  1409. * @param {Number} t - Zero-to-one value describing what percentage to calculate.
  1410. * @param {Number} a - The firt point's component value.
  1411. * @param {Number} b - The first point's bezier component value.
  1412. * @param {Number} c - The second point's bezier component value.
  1413. * @param {Number} d - The second point's component value.
  1414. * @returns {Number} The coordinate value for a specific component along a cubic bezier curve by `t`.
  1415. */
  1416. var getComponentOnCubicBezier = function(t, a, b, c, d) {
  1417. var k = 1 - t;
  1418. return (k * k * k * a) + (3 * k * k * t * b) + (3 * k * t * t * c) +
  1419. (t * t * t * d);
  1420. };
  1421. /**
  1422. * @name Two.Utils.subdivide
  1423. * @function
  1424. * @param {Number} x1 - x position of first anchor point.
  1425. * @param {Number} y1 - y position of first anchor point.
  1426. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1427. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1428. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1429. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1430. * @param {Number} x4 - x position of second anchor point.
  1431. * @param {Number} y4 - y position of second anchor point.
  1432. * @param {Number} [limit=Two.Utils.Curve.RecursionLimit] - The amount of vertices to create by subdividing.
  1433. * @returns {Anchor[]} A list of anchor points ordered in between `x1`, `y1` and `x4`, `y4`
  1434. * @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`.
  1435. */
  1436. var subdivide = function(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1437. limit = limit || Curve.RecursionLimit;
  1438. var amount = limit + 1;
  1439. // TODO: Abstract 0.001 to a limiting variable
  1440. // Don't recurse if the end points are identical
  1441. if (Math.abs(x1 - x4) < 0.001 && Math.abs(y1 - y4) < 0.001) {
  1442. return [new Anchor(x4, y4)];
  1443. }
  1444. var result = [];
  1445. for (var i = 0; i < amount; i++) {
  1446. var t = i / amount;
  1447. var x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
  1448. var y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
  1449. result.push(new Anchor(x, y));
  1450. }
  1451. return result;
  1452. };
  1453. /**
  1454. * @name Two.Utils.getCurveLength
  1455. * @function
  1456. * @param {Number} x1 - x position of first anchor point.
  1457. * @param {Number} y1 - y position of first anchor point.
  1458. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1459. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1460. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1461. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1462. * @param {Number} x4 - x position of second anchor point.
  1463. * @param {Number} y4 - y position of second anchor point.
  1464. * @param {Number} [limit=Two.Utils.Curve.RecursionLimit] - The amount of vertices to create by subdividing.
  1465. * @returns {Number} The length of a curve.
  1466. * @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`.
  1467. */
  1468. var getCurveLength$1 = function(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
  1469. // TODO: Better / fuzzier equality check
  1470. // Linear calculation
  1471. if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) {
  1472. var dx = x4 - x1;
  1473. var dy = y4 - y1;
  1474. return Math.sqrt(dx * dx + dy * dy);
  1475. }
  1476. // Calculate the coefficients of a Bezier derivative.
  1477. var ax = 9 * (x2 - x3) + 3 * (x4 - x1),
  1478. bx = 6 * (x1 + x3) - 12 * x2,
  1479. cx = 3 * (x2 - x1),
  1480. ay = 9 * (y2 - y3) + 3 * (y4 - y1),
  1481. by = 6 * (y1 + y3) - 12 * y2,
  1482. cy = 3 * (y2 - y1);
  1483. var integrand = function(t) {
  1484. // Calculate quadratic equations of derivatives for x and y
  1485. var dx = (ax * t + bx) * t + cx,
  1486. dy = (ay * t + by) * t + cy;
  1487. return Math.sqrt(dx * dx + dy * dy);
  1488. };
  1489. return integrate(
  1490. integrand, 0, 1, limit || Curve.RecursionLimit
  1491. );
  1492. };
  1493. /**
  1494. * @name Two.Utils.getCurveBoundingBox
  1495. * @function
  1496. * @param {Number} x1 - x position of first anchor point.
  1497. * @param {Number} y1 - y position of first anchor point.
  1498. * @param {Number} x2 - x position of first anchor point's "right" bezier handle.
  1499. * @param {Number} y2 - y position of first anchor point's "right" bezier handle.
  1500. * @param {Number} x3 - x position of second anchor point's "left" bezier handle.
  1501. * @param {Number} y3 - y position of second anchor point's "left" bezier handle.
  1502. * @param {Number} x4 - x position of second anchor point.
  1503. * @param {Number} y4 - y position of second anchor point.
  1504. * @returns {Object} Object contains min and max `x` / `y` bounds.
  1505. * @see {@link https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js#L856}
  1506. */
  1507. var getCurveBoundingBox = function(x1, y1, x2, y2, x3, y3, x4, y4) {
  1508. var tvalues = [];
  1509. var bounds = [[], []];
  1510. var a, b, c, t, t1, t2, b2ac, sqrtb2ac;
  1511. for (var i = 0; i < 2; ++i) {
  1512. if (i == 0) {
  1513. b = 6 * x1 - 12 * x2 + 6 * x3;
  1514. a = -3 * x1 + 9 * x2 - 9 * x3 + 3 * x4;
  1515. c = 3 * x2 - 3 * x1;
  1516. } else {
  1517. b = 6 * y1 - 12 * y2 + 6 * y3;
  1518. a = -3 * y1 + 9 * y2 - 9 * y3 + 3 * y4;
  1519. c = 3 * y2 - 3 * y1;
  1520. }
  1521. if (Math.abs(a) < 1e-12) {
  1522. if (Math.abs(b) < 1e-12) {
  1523. continue;
  1524. }
  1525. t = -c / b;
  1526. if (0 < t && t < 1) {
  1527. tvalues.push(t);
  1528. }
  1529. continue;
  1530. }
  1531. b2ac = b * b - 4 * c * a;
  1532. sqrtb2ac = Math.sqrt(b2ac);
  1533. if (b2ac < 0) {
  1534. continue;
  1535. }
  1536. t1 = (-b + sqrtb2ac) / (2 * a);
  1537. if (0 < t1 && t1 < 1) {
  1538. tvalues.push(t1);
  1539. }
  1540. t2 = (-b - sqrtb2ac) / (2 * a);
  1541. if (0 < t2 && t2 < 1) {
  1542. tvalues.push(t2);
  1543. }
  1544. }
  1545. var j = tvalues.length;
  1546. var jlen = j;
  1547. var mt;
  1548. while (j--) {
  1549. t = tvalues[j];
  1550. mt = 1 - t;
  1551. bounds[0][j] = mt * mt * mt * x1 + 3 * mt * mt * t * x2 + 3 * mt * t * t * x3 + t * t * t * x4;
  1552. bounds[1][j] = mt * mt * mt * y1 + 3 * mt * mt * t * y2 + 3 * mt * t * t * y3 + t * t * t * y4;
  1553. }
  1554. bounds[0][jlen] = x1;
  1555. bounds[1][jlen] = y1;
  1556. bounds[0][jlen + 1] = x4;
  1557. bounds[1][jlen + 1] = y4;
  1558. bounds[0].length = bounds[1].length = jlen + 2;
  1559. return {
  1560. min: { x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1]) },
  1561. max: { x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1]) }
  1562. };
  1563. };
  1564. /**
  1565. * @name Two.Utils.integrate
  1566. * @function
  1567. * @param {Function} f
  1568. * @param {Number} a
  1569. * @param {Number} b
  1570. * @param {Number} n
  1571. * @description Integration for `getCurveLength` calculations.
  1572. * @see [Paper.js](@link https://github.com/paperjs/paper.js/blob/master/src/util/Numerical.js#L101)
  1573. */
  1574. var integrate = function(f, a, b, n) {
  1575. var x = Curve.abscissas[n - 2],
  1576. w = Curve.weights[n - 2],
  1577. A = 0.5 * (b - a),
  1578. B = A + a,
  1579. i = 0,
  1580. m = (n + 1) >> 1,
  1581. sum = n & 1 ? w[i++] * f(B) : 0; // Handle odd n
  1582. while (i < m) {
  1583. var Ax = A * x[i];
  1584. sum += w[i++] * (f(B + Ax) + f(B - Ax));
  1585. }
  1586. return A * sum;
  1587. };
  1588. /**
  1589. * @name Two.Utils.getCurveFromPoints
  1590. * @function
  1591. * @param {Anchor[]} points
  1592. * @param {Boolean} closed
  1593. * @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}.
  1594. */
  1595. var getCurveFromPoints = function(points, closed) {
  1596. var l = points.length, last = l - 1;
  1597. for (var i = 0; i < l; i++) {
  1598. var point = points[i];
  1599. if (!_.isObject(point.controls)) {
  1600. Anchor.AppendCurveProperties(point);
  1601. }
  1602. var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0);
  1603. var next = closed ? mod(i + 1, l) : Math.min(i + 1, last);
  1604. var a = points[prev];
  1605. var b = point;
  1606. var c = points[next];
  1607. getControlPoints(a, b, c);
  1608. b.command = i === 0 ? Commands.move : Commands.curve;
  1609. }
  1610. };
  1611. /**
  1612. * @name Two.Utils.getControlPoints
  1613. * @function
  1614. * @param {Anchor} a
  1615. * @param {Anchor} b
  1616. * @param {Anchor} c
  1617. * @returns {Anchor} Returns the passed middle point `b`.
  1618. * @description Given three coordinates set the control points for the middle, b, vertex based on its position with the adjacent points.
  1619. */
  1620. var getControlPoints = function(a, b, c) {
  1621. var a1 = Vector.angleBetween(a, b);
  1622. var a2 = Vector.angleBetween(c, b);
  1623. var d1 = Vector.distanceBetween(a, b);
  1624. var d2 = Vector.distanceBetween(c, b);
  1625. var mid = (a1 + a2) / 2;
  1626. // TODO: Issue 73
  1627. if (d1 < 0.0001 || d2 < 0.0001) {
  1628. if (typeof b.relative === 'boolean' && !b.relative) {
  1629. b.controls.left.copy(b);
  1630. b.controls.right.copy(b);
  1631. }
  1632. return b;
  1633. }
  1634. d1 *= 0.33; // Why 0.33?
  1635. d2 *= 0.33;
  1636. if (a2 < a1) {
  1637. mid += HALF_PI$3;
  1638. } else {
  1639. mid -= HALF_PI$3;
  1640. }
  1641. b.controls.left.x = Math.cos(mid) * d1;
  1642. b.controls.left.y = Math.sin(mid) * d1;
  1643. mid -= Math.PI;
  1644. b.controls.right.x = Math.cos(mid) * d2;
  1645. b.controls.right.y = Math.sin(mid) * d2;
  1646. if (typeof b.relative === 'boolean' && !b.relative) {
  1647. b.controls.left.x += b.x;
  1648. b.controls.left.y += b.y;
  1649. b.controls.right.x += b.x;
  1650. b.controls.right.y += b.y;
  1651. }
  1652. return b;
  1653. };
  1654. /**
  1655. * @name Two.Utils.getReflection
  1656. * @function
  1657. * @param {Vector} a
  1658. * @param {Vector} b
  1659. * @param {Boolean} [relative=false]
  1660. * @returns {Vector} New {@link Vector} that represents the reflection point.
  1661. * @description Get the reflection of a point `b` about point `a`. Where `a` is in absolute space and `b` is relative to `a`.
  1662. * @see {@link http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes}
  1663. */
  1664. var getReflection = function(a, b, relative) {
  1665. return new Vector(
  1666. 2 * a.x - (b.x + a.x) - (relative ? a.x : 0),
  1667. 2 * a.y - (b.y + a.y) - (relative ? a.y : 0)
  1668. );
  1669. };
  1670. /**
  1671. * @name Two.Utils.getAnchorsFromArcData
  1672. * @function
  1673. * @param {Vector} center
  1674. * @param {Number} xAxisRotation
  1675. * @param {Number} rx - x radius
  1676. * @param {Number} ry - y radius
  1677. * @param {Number} ts
  1678. * @param {Number} td
  1679. * @param {Boolean} [ccw=false] - Set path traversal to counter-clockwise
  1680. */
  1681. var getAnchorsFromArcData = function(center, xAxisRotation, rx, ry, ts, td, ccw) {
  1682. var resolution = Constants.Resolution;
  1683. for (var i = 0; i < resolution; i++) {
  1684. var pct = (i + 1) / resolution;
  1685. if (ccw) {
  1686. pct = 1 - pct;
  1687. }
  1688. var theta = pct * td + ts;
  1689. var x = rx * Math.cos(theta);
  1690. var y = ry * Math.sin(theta);
  1691. // x += center.x;
  1692. // y += center.y;
  1693. var anchor = new Anchor(x, y);
  1694. Anchor.AppendCurveProperties(anchor);
  1695. anchor.command = Commands.line;
  1696. }
  1697. };
  1698. var Curves = /*#__PURE__*/Object.freeze({
  1699. __proto__: null,
  1700. Curve: Curve,
  1701. getComponentOnCubicBezier: getComponentOnCubicBezier,
  1702. subdivide: subdivide,
  1703. getCurveLength: getCurveLength$1,
  1704. getCurveBoundingBox: getCurveBoundingBox,
  1705. integrate: integrate,
  1706. getCurveFromPoints: getCurveFromPoints,
  1707. getControlPoints: getControlPoints,
  1708. getReflection: getReflection,
  1709. getAnchorsFromArcData: getAnchorsFromArcData
  1710. });
  1711. var devicePixelRatio = root$1.devicePixelRatio || 1;
  1712. var getBackingStoreRatio = function(ctx) {
  1713. return ctx.webkitBackingStorePixelRatio ||
  1714. ctx.mozBackingStorePixelRatio ||
  1715. ctx.msBackingStorePixelRatio ||
  1716. ctx.oBackingStorePixelRatio ||
  1717. ctx.backingStorePixelRatio || 1;
  1718. };
  1719. /**
  1720. * @name Two.Utils.getRatio
  1721. * @function
  1722. * @param {CanvasRenderingContext2D} ctx
  1723. * @returns {Number} The ratio of a unit in Two.js to the pixel density of a session's screen.
  1724. * @see [High DPI Rendering](http://www.html5rocks.com/en/tutorials/canvas/hidpi/)
  1725. */
  1726. var getRatio = function(ctx) {
  1727. return devicePixelRatio / getBackingStoreRatio(ctx);
  1728. };
  1729. // Constants
  1730. var cos$5 = Math.cos, sin$5 = Math.sin, tan = Math.tan;
  1731. var array = [];
  1732. /**
  1733. * @name Two.Matrix
  1734. * @class
  1735. * @param {Number} [a=1] - The value for element at the first column and first row.
  1736. * @param {Number} [b=0] - The value for element at the second column and first row.
  1737. * @param {Number} [c=0] - The value for element at the third column and first row.
  1738. * @param {Number} [d=0] - The value for element at the first column and second row.
  1739. * @param {Number} [e=1] - The value for element at the second column and second row.
  1740. * @param {Number} [f=0] - The value for element at the third column and second row.
  1741. * @param {Number} [g=0] - The value for element at the first column and third row.
  1742. * @param {Number} [h=0] - The value for element at the second column and third row.
  1743. * @param {Number} [i=1] - The value for element at the third column and third row.
  1744. * @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.
  1745. * @nota-bene Order is based on how to construct transformation strings for the browser.
  1746. */
  1747. function Matrix(a, b, c, d, e, f) {
  1748. /**
  1749. * @name Two.Matrix#elements
  1750. * @property {Number[]} - The underlying data stored as an array.
  1751. */
  1752. this.elements = new NumArray(9);
  1753. var elements = a;
  1754. if (!Array.isArray(elements)) {
  1755. elements = Array.prototype.slice.call(arguments);
  1756. }
  1757. // initialize the elements with default values.
  1758. this.identity();
  1759. if (elements.length > 0) {
  1760. this.set(elements);
  1761. }
  1762. }
  1763. setMatrix(Matrix);
  1764. _.extend(Matrix, {
  1765. /**
  1766. * @name Two.Matrix.Identity
  1767. * @property {Number[]} - A stored reference to the default value of a 3 x 3 matrix.
  1768. */
  1769. Identity: [
  1770. 1, 0, 0,
  1771. 0, 1, 0,
  1772. 0, 0, 1
  1773. ],
  1774. /**
  1775. * @name Two.Matrix.Multiply
  1776. * @function
  1777. * @param {Two.Matrix} A
  1778. * @param {Two.Matrix} B
  1779. * @param {Two.Matrix} [C] - An optional matrix to apply the multiplication to.
  1780. * @returns {Two.Matrix} - If an optional `C` matrix isn't passed then a new one is created and returned.
  1781. * @description Multiply two matrices together and return the result.
  1782. */
  1783. Multiply: function(A, B, C) {
  1784. if (B.length <= 3) { // Multiply Vector
  1785. var x, y, z, e = A;
  1786. var a = B[0] || 0,
  1787. b = B[1] || 0,
  1788. c = B[2] || 0;
  1789. // Go down rows first
  1790. // a, d, g, b, e, h, c, f, i
  1791. x = e[0] * a + e[1] * b + e[2] * c;
  1792. y = e[3] * a + e[4] * b + e[5] * c;
  1793. z = e[6] * a + e[7] * b + e[8] * c;
  1794. return { x: x, y: y, z: z };
  1795. }
  1796. var A0 = A[0], A1 = A[1], A2 = A[2];
  1797. var A3 = A[3], A4 = A[4], A5 = A[5];
  1798. var A6 = A[6], A7 = A[7], A8 = A[8];
  1799. var B0 = B[0], B1 = B[1], B2 = B[2];
  1800. var B3 = B[3], B4 = B[4], B5 = B[5];
  1801. var B6 = B[6], B7 = B[7], B8 = B[8];
  1802. C = C || new NumArray(9);
  1803. C[0] = A0 * B0 + A1 * B3 + A2 * B6;
  1804. C[1] = A0 * B1 + A1 * B4 + A2 * B7;
  1805. C[2] = A0 * B2 + A1 * B5 + A2 * B8;
  1806. C[3] = A3 * B0 + A4 * B3 + A5 * B6;
  1807. C[4] = A3 * B1 + A4 * B4 + A5 * B7;
  1808. C[5] = A3 * B2 + A4 * B5 + A5 * B8;
  1809. C[6] = A6 * B0 + A7 * B3 + A8 * B6;
  1810. C[7] = A6 * B1 + A7 * B4 + A8 * B7;
  1811. C[8] = A6 * B2 + A7 * B5 + A8 * B8;
  1812. return C;
  1813. }
  1814. });
  1815. _.extend(Matrix.prototype, Events, {
  1816. constructor: Matrix,
  1817. /**
  1818. * @name Two.Matrix#manual
  1819. * @property {Boolean} - Determines whether Two.js automatically calculates the values for the matrix or if the developer intends to manage the matrix.
  1820. * @nota-bene - Setting to `true` nullifies {@link Two.Shape#translation}, {@link Two.Shape#rotation}, and {@link Two.Shape#scale}.
  1821. */
  1822. manual: false,
  1823. /**
  1824. * @name Two.Matrix#set
  1825. * @function
  1826. * @param {Number} a - The value for element at the first column and first row.
  1827. * @param {Number} b - The value for element at the second column and first row.
  1828. * @param {Number} c - The value for element at the third column and first row.
  1829. * @param {Number} d - The value for element at the first column and second row.
  1830. * @param {Number} e - The value for element at the second column and second row.
  1831. * @param {Number} f - The value for element at the third column and second row.
  1832. * @param {Number} g - The value for element at the first column and third row.
  1833. * @param {Number} h - The value for element at the second column and third row.
  1834. * @param {Number} i - The value for element at the third column and third row.
  1835. * @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
  1836. */
  1837. /**
  1838. * @name Two.Matrix#set
  1839. * @function
  1840. * @param {Number[]} a - The array of elements to apply.
  1841. * @description Set an array of values onto the matrix. Order described in {@link Two.Matrix}.
  1842. */
  1843. set: function(a, b, c, d, e, f, g, h, i) {
  1844. var elements;
  1845. if (typeof b === 'undefined') {
  1846. elements = a;
  1847. a = elements[0];
  1848. b = elements[1];
  1849. c = elements[2];
  1850. d = elements[3];
  1851. e = elements[4];
  1852. f = elements[5];
  1853. g = elements[6];
  1854. h = elements[7];
  1855. i = elements[8];
  1856. }
  1857. this.elements[0] = a;
  1858. this.elements[1] = b;
  1859. this.elements[2] = c;
  1860. this.elements[3] = d;
  1861. this.elements[4] = e;
  1862. this.elements[5] = f;
  1863. this.elements[6] = g;
  1864. this.elements[7] = h;
  1865. this.elements[8] = i;
  1866. return this.trigger(Events.Types.change);
  1867. },
  1868. /**
  1869. * @name Two.Matrix#copy
  1870. * @function
  1871. * @description Copy the matrix of one to the current instance.
  1872. */
  1873. copy: function(m) {
  1874. this.elements[0] = m.elements[0];
  1875. this.elements[1] = m.elements[1];
  1876. this.elements[2] = m.elements[2];
  1877. this.elements[3] = m.elements[3];
  1878. this.elements[4] = m.elements[4];
  1879. this.elements[5] = m.elements[5];
  1880. this.elements[6] = m.elements[6];
  1881. this.elements[7] = m.elements[7];
  1882. this.elements[8] = m.elements[8];
  1883. this.manual = m.manual;
  1884. return this.trigger(Events.Types.change);
  1885. },
  1886. /**
  1887. * @name Two.Matrix#identity
  1888. * @function
  1889. * @description Turn matrix to the identity, like resetting.
  1890. */
  1891. identity: function() {
  1892. this.elements[0] = Matrix.Identity[0];
  1893. this.elements[1] = Matrix.Identity[1];
  1894. this.elements[2] = Matrix.Identity[2];
  1895. this.elements[3] = Matrix.Identity[3];
  1896. this.elements[4] = Matrix.Identity[4];
  1897. this.elements[5] = Matrix.Identity[5];
  1898. this.elements[6] = Matrix.Identity[6];
  1899. this.elements[7] = Matrix.Identity[7];
  1900. this.elements[8] = Matrix.Identity[8];
  1901. return this.trigger(Events.Types.change);
  1902. },
  1903. /**
  1904. * @name Two.Matrix#multiply
  1905. * @function
  1906. * @param {Number} a - The scalar to be multiplied.
  1907. * @description Multiply all components of the matrix against a single scalar value.
  1908. * @overloaded
  1909. */
  1910. /**
  1911. * @name Two.Matrix#multiply
  1912. * @function
  1913. * @param {Number} a - The x component to be multiplied.
  1914. * @param {Number} b - The y component to be multiplied.
  1915. * @param {Number} c - The z component to be multiplied.
  1916. * @description Multiply all components of a matrix against a 3 component vector.
  1917. * @overloaded
  1918. */
  1919. /**
  1920. * @name Two.Matrix#multiply
  1921. * @function
  1922. * @param {Number} a - The value at the first column and first row of the matrix to be multiplied.
  1923. * @param {Number} b - The value at the second column and first row of the matrix to be multiplied.
  1924. * @param {Number} c - The value at the third column and first row of the matrix to be multiplied.
  1925. * @param {Number} d - The value at the first column and second row of the matrix to be multiplied.
  1926. * @param {Number} e - The value at the second column and second row of the matrix to be multiplied.
  1927. * @param {Number} f - The value at the third column and second row of the matrix to be multiplied.
  1928. * @param {Number} g - The value at the first column and third row of the matrix to be multiplied.
  1929. * @param {Number} h - The value at the second column and third row of the matrix to be multiplied.
  1930. * @param {Number} i - The value at the third column and third row of the matrix to be multiplied.
  1931. * @description Multiply all components of a matrix against another matrix.
  1932. * @overloaded
  1933. */
  1934. multiply: function(a, b, c, d, e, f, g, h, i) {
  1935. // Multiply scalar
  1936. if (typeof b === 'undefined') {
  1937. this.elements[0] *= a;
  1938. this.elements[1] *= a;
  1939. this.elements[2] *= a;
  1940. this.elements[3] *= a;
  1941. this.elements[4] *= a;
  1942. this.elements[5] *= a;
  1943. this.elements[6] *= a;
  1944. this.elements[7] *= a;
  1945. this.elements[8] *= a;
  1946. return this.trigger(Events.Types.change);
  1947. }
  1948. if (typeof d === 'undefined') { // Multiply Vector
  1949. var x, y, z;
  1950. a = a || 0;
  1951. b = b || 0;
  1952. c = c || 0;
  1953. e = this.elements;
  1954. // Go down rows first
  1955. // a, d, g, b, e, h, c, f, i
  1956. x = e[0] * a + e[1] * b + e[2] * c;
  1957. y = e[3] * a + e[4] * b + e[5] * c;
  1958. z = e[6] * a + e[7] * b + e[8] * c;
  1959. return { x: x, y: y, z: z };
  1960. }
  1961. // Multiple matrix
  1962. var A = this.elements;
  1963. var B = [a, b, c, d, e, f, g, h, i];
  1964. var A0 = A[0], A1 = A[1], A2 = A[2];
  1965. var A3 = A[3], A4 = A[4], A5 = A[5];
  1966. var A6 = A[6], A7 = A[7], A8 = A[8];
  1967. var B0 = B[0], B1 = B[1], B2 = B[2];
  1968. var B3 = B[3], B4 = B[4], B5 = B[5];
  1969. var B6 = B[6], B7 = B[7], B8 = B[8];
  1970. this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
  1971. this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
  1972. this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;
  1973. this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
  1974. this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
  1975. this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;
  1976. this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
  1977. this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
  1978. this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;
  1979. return this.trigger(Events.Types.change);
  1980. },
  1981. /**
  1982. * @name Two.Matrix#inverse
  1983. * @function
  1984. * @param {Two.Matrix} [out] - The optional matrix to apply the inversion to.
  1985. * @description Return an inverted version of the matrix. If no optional one is passed a new matrix is created and returned.
  1986. */
  1987. inverse: function(out) {
  1988. var a = this.elements;
  1989. out = out || new Matrix();
  1990. var a00 = a[0], a01 = a[1], a02 = a[2];
  1991. var a10 = a[3], a11 = a[4], a12 = a[5];
  1992. var a20 = a[6], a21 = a[7], a22 = a[8];
  1993. var b01 = a22 * a11 - a12 * a21;
  1994. var b11 = -a22 * a10 + a12 * a20;
  1995. var b21 = a21 * a10 - a11 * a20;
  1996. // Calculate the determinant
  1997. var det = a00 * b01 + a01 * b11 + a02 * b21;
  1998. if (!det) {
  1999. return null;
  2000. }
  2001. det = 1.0 / det;
  2002. out.elements[0] = b01 * det;
  2003. out.elements[1] = (-a22 * a01 + a02 * a21) * det;
  2004. out.elements[2] = (a12 * a01 - a02 * a11) * det;
  2005. out.elements[3] = b11 * det;
  2006. out.elements[4] = (a22 * a00 - a02 * a20) * det;
  2007. out.elements[5] = (-a12 * a00 + a02 * a10) * det;
  2008. out.elements[6] = b21 * det;
  2009. out.elements[7] = (-a21 * a00 + a01 * a20) * det;
  2010. out.elements[8] = (a11 * a00 - a01 * a10) * det;
  2011. return out;
  2012. },
  2013. /**
  2014. * @name Two.Matrix#scale
  2015. * @function
  2016. * @param {Number} scale - The one dimensional scale to apply to the matrix.
  2017. * @description Uniformly scale the transformation matrix.
  2018. */
  2019. /**
  2020. * @name Two.Matrix#scale
  2021. * @function
  2022. * @param {Number} sx - The horizontal scale factor.
  2023. * @param {Number} sy - The vertical scale factor
  2024. * @description Scale the transformation matrix in two dimensions.
  2025. */
  2026. scale: function(sx, sy) {
  2027. var l = arguments.length;
  2028. if (l <= 1) {
  2029. sy = sx;
  2030. }
  2031. return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);
  2032. },
  2033. /**
  2034. * @name Two.Matrix#rotate
  2035. * @function
  2036. * @param {Number} Number - The amount to rotate in Number.
  2037. * @description Rotate the matrix.
  2038. */
  2039. rotate: function(Number) {
  2040. var c = cos$5(Number);
  2041. var s = sin$5(Number);
  2042. return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);
  2043. },
  2044. /**
  2045. * @name Two.Matrix#translate
  2046. * @function
  2047. * @param {Number} x - The horizontal translation value to apply.
  2048. * @param {Number} y - The vertical translation value to apply.
  2049. * @description Translate the matrix.
  2050. */
  2051. translate: function(x, y) {
  2052. return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);
  2053. },
  2054. /**
  2055. * @name Two.Matrix#skewX
  2056. * @function
  2057. * @param {Number} Number - The amount to skew in Number.
  2058. * @description Skew the matrix by an angle in the x axis direction.
  2059. */
  2060. skewX: function(Number) {
  2061. var a = tan(Number);
  2062. return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);
  2063. },
  2064. /**
  2065. * @name Two.Matrix#skewY
  2066. * @function
  2067. * @param {Number} Number - The amount to skew in Number.
  2068. * @description Skew the matrix by an angle in the y axis direction.
  2069. */
  2070. skewY: function(Number) {
  2071. var a = tan(Number);
  2072. return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);
  2073. },
  2074. /**
  2075. * @name Two.Matrix#toString
  2076. * @function
  2077. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
  2078. * @returns {String} - The transformation matrix as a 6 component string separated by spaces.
  2079. * @description Create a transform string. Used for the Two.js rendering APIs.
  2080. */
  2081. toString: function(fullMatrix) {
  2082. array.length = 0;
  2083. this.toTransformArray(fullMatrix, array);
  2084. return array.map(toFixed).join(' ');
  2085. },
  2086. /**
  2087. * @name Two.Matrix#toTransformArray
  2088. * @function
  2089. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 in the format for 2D transformations.
  2090. * @param {Number[]} [output] - An array empty or otherwise to apply the values to.
  2091. * @description Create a transform array. Used for the Two.js rendering APIs.
  2092. */
  2093. toTransformArray: function(fullMatrix, output) {
  2094. var elements = this.elements;
  2095. var hasOutput = !!output;
  2096. var a = elements[0];
  2097. var b = elements[1];
  2098. var c = elements[2];
  2099. var d = elements[3];
  2100. var e = elements[4];
  2101. var f = elements[5];
  2102. if (fullMatrix) {
  2103. var g = elements[6];
  2104. var h = elements[7];
  2105. var i = elements[8];
  2106. if (hasOutput) {
  2107. output[0] = a;
  2108. output[1] = d;
  2109. output[2] = g;
  2110. output[3] = b;
  2111. output[4] = e;
  2112. output[5] = h;
  2113. output[6] = c;
  2114. output[7] = f;
  2115. output[8] = i;
  2116. return;
  2117. }
  2118. return [
  2119. a, d, g, b, e, h, c, f, i
  2120. ];
  2121. }
  2122. if (hasOutput) {
  2123. output[0] = a;
  2124. output[1] = d;
  2125. output[2] = b;
  2126. output[3] = e;
  2127. output[4] = c;
  2128. output[5] = f;
  2129. return;
  2130. }
  2131. return [
  2132. a, d, b, e, c, f // Specific format see LN:19
  2133. ];
  2134. },
  2135. /**
  2136. * @name Two.Matrix#toArray
  2137. * @function
  2138. * @param {Boolean} [fullMatrix=false] - Return the full 9 elements of the matrix or just 6 for 2D transformations.
  2139. * @param {Number[]} [output] - An array empty or otherwise to apply the values to.
  2140. * @description Create a transform array. Used for the Two.js rendering APIs.
  2141. */
  2142. toArray: function(fullMatrix, output) {
  2143. var elements = this.elements;
  2144. var hasOutput = !!output;
  2145. var a = elements[0];
  2146. var b = elements[1];
  2147. var c = elements[2];
  2148. var d = elements[3];
  2149. var e = elements[4];
  2150. var f = elements[5];
  2151. if (fullMatrix) {
  2152. var g = elements[6];
  2153. var h = elements[7];
  2154. var i = elements[8];
  2155. if (hasOutput) {
  2156. output[0] = a;
  2157. output[1] = b;
  2158. output[2] = c;
  2159. output[3] = d;
  2160. output[4] = e;
  2161. output[5] = f;
  2162. output[6] = g;
  2163. output[7] = h;
  2164. output[8] = i;
  2165. return;
  2166. }
  2167. return [
  2168. a, b, c, d, e, f, g, h, i
  2169. ];
  2170. }
  2171. if (hasOutput) {
  2172. output[0] = a;
  2173. output[1] = b;
  2174. output[2] = c;
  2175. output[3] = d;
  2176. output[4] = e;
  2177. output[5] = f;
  2178. return;
  2179. }
  2180. return [
  2181. a, b, c, d, e, f
  2182. ];
  2183. },
  2184. /**
  2185. * @name Two.Matrix#toObject
  2186. * @function
  2187. * @description Create a JSON compatible object that represents information of the matrix.
  2188. */
  2189. toObject: function() {
  2190. return {
  2191. elements: this.toArray(true),
  2192. manual: !!this.manual
  2193. };
  2194. },
  2195. /**
  2196. * @name Two.Matrix#clone
  2197. * @function
  2198. * @description Clone the current matrix.
  2199. */
  2200. clone: function() {
  2201. return new Matrix().copy(this);
  2202. }
  2203. });
  2204. /**
  2205. * @name Two.Shape
  2206. * @class
  2207. * @extends Two.Events
  2208. * @description The foundational transformation object for the Two.js scenegraph.
  2209. */
  2210. function Shape() {
  2211. /**
  2212. * @name Two.Shape#renderer
  2213. * @property {Object}
  2214. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  2215. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  2216. */
  2217. this.renderer = {};
  2218. this._renderer.flagMatrix = Shape.FlagMatrix.bind(this);
  2219. this.isShape = true;
  2220. /**
  2221. * @name Two.Shape#id
  2222. * @property {String} - Session specific unique identifier.
  2223. * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
  2224. */
  2225. this.id = Constants.Identifier + Constants.uniqueId();
  2226. /**
  2227. * @name Two.Shape#classList
  2228. * @property {String[]}
  2229. * @description A list of class strings stored if imported / interpreted from an SVG element.
  2230. */
  2231. this.classList = [];
  2232. /**
  2233. * @name Two.Shape#matrix
  2234. * @property {Two.Matrix}
  2235. * @description The transformation matrix of the shape.
  2236. * @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.
  2237. */
  2238. this.matrix = new Matrix();
  2239. /**
  2240. * @name Two.Shape#translation
  2241. * @property {Two.Vector} - The x and y value for where the shape is placed relative to its parent.
  2242. */
  2243. this.translation = new Vector();
  2244. /**
  2245. * @name Two.Shape#rotation
  2246. * @property {Number} - The value in Number for how much the shape is rotated relative to its parent.
  2247. */
  2248. this.rotation = 0;
  2249. /**
  2250. * @name Two.Shape#scale
  2251. * @property {Number} - The value for how much the shape is scaled relative to its parent.
  2252. * @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);`
  2253. */
  2254. this.scale = 1;
  2255. /**
  2256. * @name Two.Shape#skewX
  2257. * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
  2258. * @description Skew the shape by an angle in the x axis direction.
  2259. */
  2260. this.skewX = 0;
  2261. /**
  2262. * @name Two.Shape#skewY
  2263. * @property {Number} - The value in Number for how much the shape is skewed relative to its parent.
  2264. * @description Skew the shape by an angle in the y axis direction.
  2265. */
  2266. this.skewY = 0;
  2267. }
  2268. _.extend(Shape, {
  2269. /**
  2270. * @name Two.Shape.FlagMatrix
  2271. * @function
  2272. * @description Utility function used in conjunction with event handlers to update the flagMatrix of a shape.
  2273. */
  2274. FlagMatrix: function() {
  2275. this._flagMatrix = true;
  2276. },
  2277. /**
  2278. * @name Two.Shape.MakeObservable
  2279. * @function
  2280. * @param {Object} object - The object to make observable.
  2281. * @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.
  2282. */
  2283. MakeObservable: function(object) {
  2284. var translation = {
  2285. enumerable: false,
  2286. get: function() {
  2287. return this._translation;
  2288. },
  2289. set: function(v) {
  2290. if (this._translation) {
  2291. this._translation.unbind(Events.Types.change, this._renderer.flagMatrix);
  2292. }
  2293. this._translation = v;
  2294. this._translation.bind(Events.Types.change, this._renderer.flagMatrix);
  2295. Shape.FlagMatrix.call(this);
  2296. }
  2297. };
  2298. Object.defineProperty(object, 'translation', translation);
  2299. Object.defineProperty(object, 'position', translation);
  2300. Object.defineProperty(object, 'rotation', {
  2301. enumerable: true,
  2302. get: function() {
  2303. return this._rotation;
  2304. },
  2305. set: function(v) {
  2306. this._rotation = v;
  2307. this._flagMatrix = true;
  2308. }
  2309. });
  2310. Object.defineProperty(object, 'scale', {
  2311. enumerable: true,
  2312. get: function() {
  2313. return this._scale;
  2314. },
  2315. set: function(v) {
  2316. if (this._scale instanceof Vector) {
  2317. this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
  2318. }
  2319. this._scale = v;
  2320. if (this._scale instanceof Vector) {
  2321. this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
  2322. }
  2323. this._flagMatrix = true;
  2324. this._flagScale = true;
  2325. }
  2326. });
  2327. Object.defineProperty(object, 'skewX', {
  2328. enumerable: true,
  2329. get: function() {
  2330. return this._skewX;
  2331. },
  2332. set: function(v) {
  2333. this._skewX = v;
  2334. this._flagMatrix = true;
  2335. }
  2336. });
  2337. Object.defineProperty(object, 'skewY', {
  2338. enumerable: true,
  2339. get: function() {
  2340. return this._skewY;
  2341. },
  2342. set: function(v) {
  2343. this._skewY = v;
  2344. this._flagMatrix = true;
  2345. }
  2346. });
  2347. Object.defineProperty(object, 'matrix', {
  2348. enumerable: true,
  2349. get: function() {
  2350. return this._matrix;
  2351. },
  2352. set: function(v) {
  2353. this._matrix = v;
  2354. this._flagMatrix = true;
  2355. }
  2356. });
  2357. Object.defineProperty(object, 'id', {
  2358. enumerable: true,
  2359. get: function() {
  2360. return this._id;
  2361. },
  2362. set: function(v) {
  2363. var id = this._id;
  2364. if (v === this._id) {
  2365. return;
  2366. }
  2367. this._id = v;
  2368. this._flagId = true;
  2369. if (this.parent) {
  2370. delete this.parent.children.ids[id];
  2371. this.parent.children.ids[this._id] = this;
  2372. }
  2373. }
  2374. });
  2375. Object.defineProperty(object, 'className', {
  2376. enumerable: true,
  2377. get: function() {
  2378. return this._className;
  2379. },
  2380. set: function(v) {
  2381. this._flagClassName = this._className !== v;
  2382. if (this._flagClassName) {
  2383. var prev = this._className.split(/\s+?/);
  2384. var dest = v.split(/\s+?/);
  2385. for (var i = 0; i < prev.length; i++) {
  2386. var className = prev[i];
  2387. var index = Array.prototype.indexOf.call(this.classList, className);
  2388. if (index >= 0) {
  2389. this.classList.splice(index, 1);
  2390. }
  2391. }
  2392. this.classList = this.classList.concat(dest);
  2393. }
  2394. this._className = v;
  2395. }
  2396. });
  2397. Object.defineProperty(object, 'renderer', {
  2398. enumerable: false,
  2399. get: function() {
  2400. return this._renderer;
  2401. },
  2402. set: function(obj) {
  2403. this._renderer = obj;
  2404. }
  2405. });
  2406. }
  2407. });
  2408. _.extend(Shape.prototype, Events, {
  2409. constructor: Shape,
  2410. // Flags
  2411. /**
  2412. * @name Two.Shape#_id
  2413. * @private
  2414. * @property {Boolean} - Determines whether the id needs updating.
  2415. */
  2416. _flagId: true,
  2417. /**
  2418. * @name Two.Shape#_flagMatrix
  2419. * @private
  2420. * @property {Boolean} - Determines whether the matrix needs updating.
  2421. */
  2422. _flagMatrix: true,
  2423. /**
  2424. * @name Two.Shape#_flagScale
  2425. * @private
  2426. * @property {Boolean} - Determines whether the scale needs updating.
  2427. */
  2428. _flagScale: false,
  2429. // _flagMask: false,
  2430. // _flagClip: false,
  2431. /**
  2432. * @name Two.Shape#_flagClassName
  2433. * @private
  2434. * @property {Boolean} - Determines whether the {@link Two.Group#className} need updating.
  2435. */
  2436. _flagClassName: false,
  2437. // Underlying Properties
  2438. _id: '',
  2439. /**
  2440. * @name Two.Shape#_translation
  2441. * @private
  2442. * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
  2443. */
  2444. _translation: null,
  2445. /**
  2446. * @name Two.Shape#_rotation
  2447. * @private
  2448. * @property {Number} - The rotation value in Number.
  2449. */
  2450. _rotation: 0,
  2451. /**
  2452. * @name Two.Shape#_translation
  2453. * @private
  2454. * @property {Two.Vector} - The translation values as a {@link Two.Vector}.
  2455. */
  2456. _scale: 1,
  2457. /**
  2458. * @name Two.Shape#_skewX
  2459. * @private
  2460. * @property {Number} - The rotation value in Number.
  2461. */
  2462. _skewX: 0,
  2463. /**
  2464. * @name Two.Shape#_skewY
  2465. * @private
  2466. * @property {Number} - The rotation value in Number.
  2467. */
  2468. _skewY: 0,
  2469. /**
  2470. * @name Two.Shape#className
  2471. * @property {String} - A class to be applied to the element to be compatible with CSS styling.
  2472. * @nota-bene Only available for the SVG renderer.
  2473. */
  2474. _className: '',
  2475. /**
  2476. * @name Two.Shape#addTo
  2477. * @function
  2478. * @param {Two.Group} group - The parent the shape adds itself to.
  2479. * @description Convenience method to add itself to the scenegraph.
  2480. */
  2481. addTo: function(group) {
  2482. group.add(this);
  2483. return this;
  2484. },
  2485. /**
  2486. * @name Two.Shape#clone
  2487. * @function
  2488. * @param {Two.Group} [parent] - Optional argument to automatically add the shape to a scenegraph.
  2489. * @returns {Two.Shape}
  2490. * @description Create a new {@link Two.Shape} with the same values as the current shape.
  2491. */
  2492. clone: function(parent) {
  2493. var clone = new Shape();
  2494. clone.translation.copy(this.translation);
  2495. clone.rotation = this.rotation;
  2496. clone.scale = this.scale;
  2497. clone.skewX = this.skewX;
  2498. clone.skewY = this.skewY;
  2499. if (this.matrix.manual) {
  2500. clone.matrix.copy(this.matrix);
  2501. }
  2502. if (parent) {
  2503. parent.add(clone);
  2504. }
  2505. return clone._update();
  2506. },
  2507. /**
  2508. * @name Two.Shape#_update
  2509. * @function
  2510. * @private
  2511. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  2512. * @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.
  2513. * @nota-bene Try not to call this method more than once a frame.
  2514. */
  2515. _update: function(bubbles) {
  2516. if (!this._matrix.manual && this._flagMatrix) {
  2517. this._matrix
  2518. .identity()
  2519. .translate(this.translation.x, this.translation.y);
  2520. if (this._scale instanceof Vector) {
  2521. this._matrix.scale(this._scale.x, this._scale.y);
  2522. } else {
  2523. this._matrix.scale(this._scale);
  2524. }
  2525. this._matrix.rotate(this.rotation);
  2526. this._matrix.skewX(this.skewX);
  2527. this._matrix.skewY(this.skewY);
  2528. }
  2529. if (bubbles) {
  2530. if (this.parent && this.parent._update) {
  2531. this.parent._update();
  2532. }
  2533. }
  2534. return this;
  2535. },
  2536. /**
  2537. * @name Two.Shape#flagReset
  2538. * @function
  2539. * @private
  2540. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  2541. */
  2542. flagReset: function() {
  2543. this._flagId = this._flagMatrix = this._flagScale =
  2544. this._flagClassName = false;
  2545. return this;
  2546. }
  2547. });
  2548. Shape.MakeObservable(Shape.prototype);
  2549. /**
  2550. * @name Two.Collection
  2551. * @class
  2552. * @extends Two.Events
  2553. * @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.
  2554. */
  2555. function Collection() {
  2556. Array.call(this);
  2557. if (arguments[0] && Array.isArray(arguments[0])) {
  2558. if (arguments[0].length > 0) {
  2559. Array.prototype.push.apply(this, arguments[0]);
  2560. }
  2561. } else if (arguments.length > 0) {
  2562. Array.prototype.push.apply(this, arguments);
  2563. }
  2564. }
  2565. Collection.prototype = new Array();
  2566. _.extend(Collection.prototype, Events, {
  2567. constructor: Collection,
  2568. pop: function() {
  2569. var popped = Array.prototype.pop.apply(this, arguments);
  2570. this.trigger(Events.Types.remove, [popped]);
  2571. return popped;
  2572. },
  2573. shift: function() {
  2574. var shifted = Array.prototype.shift.apply(this, arguments);
  2575. this.trigger(Events.Types.remove, [shifted]);
  2576. return shifted;
  2577. },
  2578. push: function() {
  2579. var pushed = Array.prototype.push.apply(this, arguments);
  2580. this.trigger(Events.Types.insert, arguments);
  2581. return pushed;
  2582. },
  2583. unshift: function() {
  2584. var unshifted = Array.prototype.unshift.apply(this, arguments);
  2585. this.trigger(Events.Types.insert, arguments);
  2586. return unshifted;
  2587. },
  2588. splice: function() {
  2589. var spliced = Array.prototype.splice.apply(this, arguments);
  2590. var inserted;
  2591. this.trigger(Events.Types.remove, spliced);
  2592. if (arguments.length > 2) {
  2593. inserted = this.slice(arguments[0], arguments[0] + arguments.length - 2);
  2594. this.trigger(Events.Types.insert, inserted);
  2595. this.trigger(Events.Types.order);
  2596. }
  2597. return spliced;
  2598. },
  2599. sort: function() {
  2600. Array.prototype.sort.apply(this, arguments);
  2601. this.trigger(Events.Types.order);
  2602. return this;
  2603. },
  2604. reverse: function() {
  2605. Array.prototype.reverse.apply(this, arguments);
  2606. this.trigger(Events.Types.order);
  2607. return this;
  2608. },
  2609. indexOf: function() {
  2610. return Array.prototype.indexOf.apply(this, arguments);
  2611. }
  2612. });
  2613. /**
  2614. * @class
  2615. * @name Two.Group.Children
  2616. * @extends Two.Collection
  2617. * @description A children collection which is accesible both by index and by object `id`.
  2618. */
  2619. function Children(children) {
  2620. Collection.apply(this, arguments);
  2621. Object.defineProperty(this, '_events', {
  2622. value : {},
  2623. enumerable: false
  2624. });
  2625. /**
  2626. * @name Two.Group.Children#ids
  2627. * @property {Object} - Map of all elements in the list keyed by `id`s.
  2628. */
  2629. this.ids = {};
  2630. this.attach(
  2631. Array.isArray(children) ? children : Array.prototype.slice.call(arguments)
  2632. );
  2633. this.on(Events.Types.insert, this.attach);
  2634. this.on(Events.Types.remove, this.detach);
  2635. }
  2636. Children.prototype = new Collection();
  2637. _.extend(Children.prototype, {
  2638. constructor: Children,
  2639. /**
  2640. * @function
  2641. * @name Two.Group.Children#attach
  2642. * @param {Two.Shape[]} children - The objects which extend {@link Two.Shape} to be added.
  2643. * @description Adds elements to the `ids` map.
  2644. */
  2645. attach: function(children) {
  2646. for (var i = 0; i < children.length; i++) {
  2647. var child = children[i];
  2648. if (child && child.id) {
  2649. this.ids[child.id] = child;
  2650. }
  2651. }
  2652. return this;
  2653. },
  2654. /**
  2655. * @function
  2656. * @name Two.Group.Children#detach
  2657. * @param {Two.Shape[]} children - The objects which extend {@link Two.Shape} to be removed.
  2658. * @description Removes elements to the `ids` map.
  2659. */
  2660. detach: function(children) {
  2661. for (var i = 0; i < children.length; i++) {
  2662. delete this.ids[children[i].id];
  2663. }
  2664. return this;
  2665. }
  2666. });
  2667. // Constants
  2668. var min$3 = Math.min, max$3 = Math.max;
  2669. /**
  2670. * @name Two.Group
  2671. * @class
  2672. * @extends Two.Shape
  2673. * @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}.
  2674. * @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.
  2675. * @nota-bene The {@link Two#scene} is an instance of `Two.Group`.
  2676. */
  2677. function Group(children) {
  2678. Shape.call(this, true);
  2679. this._renderer.type = 'group';
  2680. /**
  2681. * @name Two.Group#additions
  2682. * @property {Two.Shape[]}
  2683. * @description An automatically updated list of children that need to be appended to the renderer's scenegraph.
  2684. */
  2685. this.additions = [];
  2686. /**
  2687. * @name Two.Group#subtractions
  2688. * @property {Two.Shape[]}
  2689. * @description An automatically updated list of children that need to be removed from the renderer's scenegraph.
  2690. */
  2691. this.subtractions = [];
  2692. /**
  2693. * @name Two.Group#children
  2694. * @property {Two.Group.Children}
  2695. * @description A list of all the children in the scenegraph.
  2696. * @nota-bene Ther order of this list indicates the order each element is rendered to the screen.
  2697. */
  2698. this.children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments);
  2699. }
  2700. _.extend(Group, {
  2701. Children: Children,
  2702. /**
  2703. * @name Two.Group.InsertChildren
  2704. * @function
  2705. * @param {Two.Shape[]} children - The objects to be inserted.
  2706. * @description Cached method to let renderers know children have been added to a {@link Two.Group}.
  2707. */
  2708. InsertChildren: function(children) {
  2709. for (var i = 0; i < children.length; i++) {
  2710. replaceParent.call(this, children[i], this);
  2711. }
  2712. },
  2713. /**
  2714. * @name Two.Group.RemoveChildren
  2715. * @function
  2716. * @param {Two.Shape[]} children - The objects to be removed.
  2717. * @description Cached method to let renderers know children have been removed from a {@link Two.Group}.
  2718. */
  2719. RemoveChildren: function(children) {
  2720. for (var i = 0; i < children.length; i++) {
  2721. replaceParent.call(this, children[i]);
  2722. }
  2723. },
  2724. /**
  2725. * @name Two.Group.OrderChildren
  2726. * @function
  2727. * @description Cached method to let renderers know order has been updated on a {@link Two.Group}.
  2728. */
  2729. OrderChildren: function(children) {
  2730. this._flagOrder = true;
  2731. },
  2732. /**
  2733. * @name Two.Group.Properties
  2734. * @property {String[]} - A list of properties that are on every {@link Two.Group}.
  2735. */
  2736. Properties: [
  2737. 'fill',
  2738. 'stroke',
  2739. 'linewidth',
  2740. 'cap',
  2741. 'join',
  2742. 'miter',
  2743. 'closed',
  2744. 'curved',
  2745. 'automatic'
  2746. ],
  2747. /**
  2748. * @name Two.Group.MakeObservable
  2749. * @function
  2750. * @param {Object} object - The object to make observable.
  2751. * @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.
  2752. */
  2753. MakeObservable: function(object) {
  2754. var properties = Group.Properties;
  2755. Object.defineProperty(object, 'visible', {
  2756. enumerable: true,
  2757. get: function() {
  2758. return this._visible;
  2759. },
  2760. set: function(v) {
  2761. this._flagVisible = this._visible !== v || this._flagVisible;
  2762. this._visible = v;
  2763. }
  2764. });
  2765. Object.defineProperty(object, 'opacity', {
  2766. enumerable: true,
  2767. get: function() {
  2768. return this._opacity;
  2769. },
  2770. set: function(v) {
  2771. this._flagOpacity = this._opacity !== v || this._flagOpacity;
  2772. this._opacity = v;
  2773. }
  2774. });
  2775. Object.defineProperty(object, 'beginning', {
  2776. enumerable: true,
  2777. get: function() {
  2778. return this._beginning;
  2779. },
  2780. set: function(v) {
  2781. this._flagBeginning = this._beginning !== v || this._flagBeginning;
  2782. this._beginning = v;
  2783. }
  2784. });
  2785. Object.defineProperty(object, 'ending', {
  2786. enumerable: true,
  2787. get: function() {
  2788. return this._ending;
  2789. },
  2790. set: function(v) {
  2791. this._flagEnding = this._ending !== v || this._flagEnding;
  2792. this._ending = v;
  2793. }
  2794. });
  2795. Object.defineProperty(object, 'length', {
  2796. enumerable: true,
  2797. get: function() {
  2798. if (this._flagLength || this._length <= 0) {
  2799. this._length = 0;
  2800. if (!this.children) {
  2801. return this._length;
  2802. }
  2803. for (var i = 0; i < this.children.length; i++) {
  2804. var child = this.children[i];
  2805. this._length += child.length;
  2806. }
  2807. }
  2808. return this._length;
  2809. }
  2810. });
  2811. Shape.MakeObservable(object);
  2812. Group.MakeGetterSetters(object, properties);
  2813. Object.defineProperty(object, 'children', {
  2814. enumerable: true,
  2815. get: function() {
  2816. return this._children;
  2817. },
  2818. set: function(children) {
  2819. var insertChildren = Group.InsertChildren.bind(this);
  2820. var removeChildren = Group.RemoveChildren.bind(this);
  2821. var orderChildren = Group.OrderChildren.bind(this);
  2822. if (this._children) {
  2823. this._children.unbind();
  2824. if (this._children.length > 0) {
  2825. removeChildren(this._children);
  2826. }
  2827. }
  2828. this._children = new Children(children);
  2829. this._children.bind(Events.Types.insert, insertChildren);
  2830. this._children.bind(Events.Types.remove, removeChildren);
  2831. this._children.bind(Events.Types.order, orderChildren);
  2832. if (children.length > 0) {
  2833. insertChildren(children);
  2834. }
  2835. }
  2836. });
  2837. Object.defineProperty(object, 'mask', {
  2838. enumerable: true,
  2839. get: function() {
  2840. return this._mask;
  2841. },
  2842. set: function(v) {
  2843. this._mask = v;
  2844. this._flagMask = true;
  2845. if (!v.clip) {
  2846. v.clip = true;
  2847. }
  2848. }
  2849. });
  2850. },
  2851. /**
  2852. * @name Two.Group.MakeGetterSetters
  2853. * @function
  2854. * @param {Two.Group} group - The group to apply getters and setters.
  2855. * @param {Object} properties - A key / value object containing properties to inherit.
  2856. * @description Convenience method to apply getter / setter logic on an array of properties. Used in {@link Two.Group.MakeObservable}.
  2857. */
  2858. MakeGetterSetters: function(group, properties) {
  2859. if (!Array.isArray(properties)) {
  2860. properties = [properties];
  2861. }
  2862. _.each(properties, function(k) {
  2863. Group.MakeGetterSetter(group, k);
  2864. });
  2865. },
  2866. /**
  2867. * @name Two.Group.MakeGetterSetter
  2868. * @function
  2869. * @param {Two.Group} group - The group to apply getters and setters.
  2870. * @param {String} key - The key which will become a property on the group.
  2871. * @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}.
  2872. */
  2873. MakeGetterSetter: function(group, key) {
  2874. var secret = '_' + key;
  2875. Object.defineProperty(group, key, {
  2876. enumerable: true,
  2877. get: function() {
  2878. return this[secret];
  2879. },
  2880. set: function(v) {
  2881. this[secret] = v;
  2882. // Trickle down styles
  2883. for (var i = 0; i < this.children.length; i++) {
  2884. var child = this.children[i];
  2885. child[key] = v;
  2886. }
  2887. }
  2888. });
  2889. }
  2890. });
  2891. _.extend(Group.prototype, Shape.prototype, {
  2892. constructor: Group,
  2893. // Flags
  2894. // http://en.wikipedia.org/wiki/Flag
  2895. /**
  2896. * @name Two.Group#_flagAdditions
  2897. * @private
  2898. * @property {Boolean} - Determines whether the {@link Two.Group#additions} needs updating.
  2899. */
  2900. _flagAdditions: false,
  2901. /**
  2902. * @name Two.Group#_flagSubtractions
  2903. * @private
  2904. * @property {Boolean} - Determines whether the {@link Two.Group#subtractions} needs updating.
  2905. */
  2906. _flagSubtractions: false,
  2907. /**
  2908. * @name Two.Group#_flagOrder
  2909. * @private
  2910. * @property {Boolean} - Determines whether the {@link Two.Group#order} needs updating.
  2911. */
  2912. _flagOrder: false,
  2913. /**
  2914. * @name Two.Group#_flagVisible
  2915. * @private
  2916. * @property {Boolean} - Determines whether the {@link Two.Group#visible} needs updating.
  2917. */
  2918. /**
  2919. * @name Two.Group#_flagOpacity
  2920. * @private
  2921. * @property {Boolean} - Determines whether the {@link Two.Group#opacity} needs updating.
  2922. */
  2923. _flagOpacity: true,
  2924. /**
  2925. * @name Two.Group#_flagBeginning
  2926. * @private
  2927. * @property {Boolean} - Determines whether the {@link Two.Group#beginning} needs updating.
  2928. */
  2929. _flagBeginning: false,
  2930. /**
  2931. * @name Two.Group#_flagEnding
  2932. * @private
  2933. * @property {Boolean} - Determines whether the {@link Two.Group#ending} needs updating.
  2934. */
  2935. _flagEnding: false,
  2936. /**
  2937. * @name Two.Group#_flagLength
  2938. * @private
  2939. * @property {Boolean} - Determines whether the {@link Two.Group#length} needs updating.
  2940. */
  2941. _flagLength: false,
  2942. /**
  2943. * @name Two.Group#_flagMask
  2944. * @private
  2945. * @property {Boolean} - Determines whether the {@link Two.Group#mask} needs updating.
  2946. */
  2947. _flagMask: false,
  2948. // Underlying Properties
  2949. /**
  2950. * @name Two.Group#fill
  2951. * @property {(String|Two.Gradient|Two.Texture)} - The value of what all child shapes should be filled in with.
  2952. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  2953. */
  2954. _fill: '#fff',
  2955. /**
  2956. * @name Two.Group#stroke
  2957. * @property {(String|Two.Gradient|Two.Texture)} - The value of what all child shapes should be outlined in with.
  2958. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  2959. */
  2960. _stroke: '#000',
  2961. /**
  2962. * @name Two.Group#linewidth
  2963. * @property {Number} - The thickness in pixels of the stroke for all child shapes.
  2964. */
  2965. _linewidth: 1.0,
  2966. /**
  2967. * @name Two.Group#opacity
  2968. * @property {Number} - The opaqueness of all child shapes.
  2969. * @nota-bene Becomes multiplied by the individual child's opacity property.
  2970. */
  2971. _opacity: 1.0,
  2972. /**
  2973. * @name Two.Group#visible
  2974. * @property {Boolean} - Display the path or not.
  2975. * @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.
  2976. */
  2977. _visible: true,
  2978. /**
  2979. * @name Two.Group#cap
  2980. * @property {String}
  2981. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty}
  2982. */
  2983. _cap: 'round',
  2984. /**
  2985. * @name Two.Group#join
  2986. * @property {String}
  2987. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty}
  2988. */
  2989. _join: 'round',
  2990. /**
  2991. * @name Two.Group#miter
  2992. * @property {String}
  2993. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty}
  2994. */
  2995. _miter: 4,
  2996. /**
  2997. * @name Two.Group#closed
  2998. * @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.
  2999. */
  3000. _closed: true,
  3001. /**
  3002. * @name Two.Group#curved
  3003. * @property {Boolean} - When the child's path is `automatic = true` this boolean determines whether the lines between the points are curved or not.
  3004. */
  3005. _curved: false,
  3006. /**
  3007. * @name Two.Group#automatic
  3008. * @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.
  3009. */
  3010. _automatic: true,
  3011. /**
  3012. * @name Two.Group#beginning
  3013. * @property {Number} - Number between zero and one to state the beginning of where the path is rendered.
  3014. * @description {@link Two.Group#beginning} is a percentage value that represents at what percentage into all child shapes should the renderer start drawing.
  3015. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Group#ending}.
  3016. */
  3017. _beginning: 0,
  3018. /**
  3019. * @name Two.Group#ending
  3020. * @property {Number} - Number between zero and one to state the ending of where the path is rendered.
  3021. * @description {@link Two.Group#ending} is a percentage value that represents at what percentage into all child shapes should the renderer start drawing.
  3022. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Group#beginning}.
  3023. */
  3024. _ending: 1.0,
  3025. /**
  3026. * @name Two.Group#length
  3027. * @property {Number} - The sum of distances between all child lengths.
  3028. */
  3029. _length: 0,
  3030. /**
  3031. * @name Two.Group#mask
  3032. * @property {Two.Shape} - The Two.js object to clip from a group's rendering.
  3033. */
  3034. _mask: null,
  3035. /**
  3036. * @name Two.Group#clone
  3037. * @function
  3038. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  3039. * @returns {Two.Group}
  3040. * @description Create a new instance of {@link Two.Group} with the same properties of the current group.
  3041. */
  3042. clone: function(parent) {
  3043. // /**
  3044. // * TODO: Group has a gotcha in that it's at the moment required to be bound to
  3045. // * an instance of two in order to add elements correctly. This needs to
  3046. // * be rethought and fixed.
  3047. // */
  3048. var clone = new Group();
  3049. var children = this.children.map(function(child) {
  3050. return child.clone();
  3051. });
  3052. clone.add(children);
  3053. clone.opacity = this.opacity;
  3054. if (this.mask) {
  3055. clone.mask = this.mask;
  3056. }
  3057. clone.translation.copy(this.translation);
  3058. clone.rotation = this.rotation;
  3059. clone.scale = this.scale;
  3060. clone.className = this.className;
  3061. if (this.matrix.manual) {
  3062. clone.matrix.copy(this.matrix);
  3063. }
  3064. if (parent) {
  3065. parent.add(clone);
  3066. }
  3067. return clone._update();
  3068. },
  3069. /**
  3070. * @name Two.Group#toObject
  3071. * @function
  3072. * @returns {Object}
  3073. * @description Return a JSON compatible plain object that represents the group.
  3074. */
  3075. toObject: function() {
  3076. var result = {
  3077. children: [],
  3078. translation: this.translation.toObject(),
  3079. rotation: this.rotation,
  3080. scale: this.scale instanceof Vector ? this.scale.toObject() : this.scale,
  3081. opacity: this.opacity,
  3082. className: this.className,
  3083. mask: (this.mask ? this.mask.toObject() : null)
  3084. };
  3085. if (this.matrix.manual) {
  3086. result.matrix = this.matrix.toObject();
  3087. }
  3088. _.each(this.children, function(child, i) {
  3089. result.children[i] = child.toObject();
  3090. }, this);
  3091. return result;
  3092. },
  3093. /**
  3094. * @name Two.Group#corner
  3095. * @function
  3096. * @description Orient the children of the group to the upper left-hand corner of that group.
  3097. */
  3098. corner: function() {
  3099. var rect = this.getBoundingClientRect(true);
  3100. for (var i = 0; i < this.children.length; i++) {
  3101. var child = this.children[i];
  3102. child.translation.x -= rect.left;
  3103. child.translation.y -= rect.top;
  3104. }
  3105. return this;
  3106. },
  3107. /**
  3108. * @name Two.Group#center
  3109. * @function
  3110. * @description Orient the children of the group to the center of that group.
  3111. */
  3112. center: function() {
  3113. var rect = this.getBoundingClientRect(true);
  3114. var cx = rect.left + rect.width / 2 - this.translation.x;
  3115. var cy = rect.top + rect.height / 2 - this.translation.y;
  3116. for (var i = 0; i < this.children.length; i++) {
  3117. var child = this.children[i];
  3118. if (child.isShape) {
  3119. child.translation.x -= cx;
  3120. child.translation.y -= cy;
  3121. }
  3122. }
  3123. return this;
  3124. },
  3125. /**
  3126. * @name Two.Group#getById
  3127. * @function
  3128. * @description Recursively search for id. Returns the first element found.
  3129. * @returns {Two.Shape} - Or `null` if nothing is found.
  3130. */
  3131. getById: function (id) {
  3132. var found = null;
  3133. function search(node) {
  3134. if (node.id === id) {
  3135. return node;
  3136. } else if (node.children) {
  3137. for (var i = 0; i < node.children.length; i++) {
  3138. found = search(node.children[i]);
  3139. if (found) {
  3140. return found;
  3141. }
  3142. }
  3143. }
  3144. return null;
  3145. }
  3146. return search(this);
  3147. },
  3148. /**
  3149. * @name Two.Group#getByClassName
  3150. * @function
  3151. * @description Recursively search for classes. Returns an array of matching elements.
  3152. * @returns {Two.Shape[]} - Or empty array if nothing is found.
  3153. */
  3154. getByClassName: function(className) {
  3155. var found = [];
  3156. function search(node) {
  3157. if (Array.prototype.indexOf.call(node.classList, className) >= 0) {
  3158. found.push(node);
  3159. }
  3160. if (node.children) {
  3161. for (var i = 0; i < node.children.length; i++) {
  3162. var child = node.children[i];
  3163. search(child);
  3164. }
  3165. }
  3166. return found;
  3167. }
  3168. return search(this);
  3169. },
  3170. /**
  3171. * @name Two.Group#getByType
  3172. * @function
  3173. * @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.
  3174. * @returns {Two.Shape[]} - Empty array if nothing is found.
  3175. */
  3176. getByType: function(type) {
  3177. var found = [];
  3178. function search(node) {
  3179. if (node instanceof type) {
  3180. found.push(node);
  3181. }
  3182. if (node.children) {
  3183. for (var i = 0; i < node.children.length; i++) {
  3184. var child = node.children[i];
  3185. search(child);
  3186. }
  3187. }
  3188. return found;
  3189. }
  3190. return search(this);
  3191. },
  3192. /**
  3193. * @name Two.Group#add
  3194. * @function
  3195. * @param {Two.Shape[]} objects - An array of objects to be added. Can be also be supplied as individual arguments.
  3196. * @description Add objects to the group.
  3197. */
  3198. add: function(objects) {
  3199. // Allow to pass multiple objects either as array or as multiple arguments
  3200. // If it's an array also create copy of it in case we're getting passed
  3201. // a childrens array directly.
  3202. if (!(objects instanceof Array)) {
  3203. objects = Array.prototype.slice.call(arguments);
  3204. } else {
  3205. objects = objects.slice();
  3206. }
  3207. // Add the objects
  3208. for (var i = 0; i < objects.length; i++) {
  3209. var child = objects[i];
  3210. if (!(child && child.id)) {
  3211. continue;
  3212. }
  3213. var index = Array.prototype.indexOf.call(this.children, child);
  3214. if (index >= 0) {
  3215. this.children.splice(index, 1);
  3216. }
  3217. this.children.push(child);
  3218. }
  3219. return this;
  3220. },
  3221. /**
  3222. * @name Two.Group#add
  3223. * @function
  3224. * @param {Two.Shape[]} objects - An array of objects to be removed. Can be also removed as individual arguments.
  3225. * @description Remove objects from the group.
  3226. */
  3227. remove: function(objects) {
  3228. var l = arguments.length,
  3229. grandparent = this.parent;
  3230. // Allow to call remove without arguments
  3231. // This will detach the object from its own parent.
  3232. if (l <= 0 && grandparent) {
  3233. grandparent.remove(this);
  3234. return this;
  3235. }
  3236. // Allow to pass multiple objects either as array or as multiple arguments
  3237. // If it's an array also create copy of it in case we're getting passed
  3238. // a childrens array directly.
  3239. if (!(objects instanceof Array)) {
  3240. objects = Array.prototype.slice.call(arguments);
  3241. } else {
  3242. objects = objects.slice();
  3243. }
  3244. // Remove the objects
  3245. for (var i = 0; i < objects.length; i++) {
  3246. var object = objects[i];
  3247. if (!object || !this.children.ids[object.id]) {
  3248. continue;
  3249. }
  3250. var index = this.children.indexOf(object);
  3251. if (index >= 0) {
  3252. this.children.splice(index, 1);
  3253. }
  3254. }
  3255. return this;
  3256. },
  3257. /**
  3258. * @name Two.Group#getBoundingClientRect
  3259. * @function
  3260. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  3261. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  3262. * @description Return an object with top, left, right, bottom, width, and height parameters of the group.
  3263. */
  3264. getBoundingClientRect: function(shallow) {
  3265. var rect, matrix, a, b, c, d, tc, lc, rc, bc;
  3266. // TODO: Update this to not __always__ update. Just when it needs to.
  3267. this._update(true);
  3268. // Variables need to be defined here, because of nested nature of groups.
  3269. var left = Infinity, right = -Infinity,
  3270. top = Infinity, bottom = -Infinity;
  3271. var regex = /texture|gradient/i;
  3272. matrix = shallow ? this._matrix : getComputedMatrix(this);
  3273. for (var i = 0; i < this.children.length; i++) {
  3274. var child = this.children[i];
  3275. if (!child.visible || regex.test(child._renderer.type)) {
  3276. continue;
  3277. }
  3278. rect = child.getBoundingClientRect(shallow);
  3279. tc = typeof rect.top !== 'number' || _.isNaN(rect.top) || !isFinite(rect.top);
  3280. lc = typeof rect.left !== 'number' || _.isNaN(rect.left) || !isFinite(rect.left);
  3281. rc = typeof rect.right !== 'number' || _.isNaN(rect.right) || !isFinite(rect.right);
  3282. bc = typeof rect.bottom !== 'number' || _.isNaN(rect.bottom) || !isFinite(rect.bottom);
  3283. if (tc || lc || rc || bc) {
  3284. continue;
  3285. }
  3286. top = min$3(rect.top, top);
  3287. left = min$3(rect.left, left);
  3288. right = max$3(rect.right, right);
  3289. bottom = max$3(rect.bottom, bottom);
  3290. }
  3291. if (shallow) {
  3292. a = matrix.multiply(left, top, 1);
  3293. b = matrix.multiply(left, bottom, 1);
  3294. c = matrix.multiply(right, top, 1);
  3295. d = matrix.multiply(right, bottom, 1);
  3296. top = min$3(a.y, b.y, c.y, d.y);
  3297. left = min$3(a.x, b.x, c.x, d.x);
  3298. right = max$3(a.x, b.x, c.x, d.x);
  3299. bottom = max$3(a.y, b.y, c.y, d.y);
  3300. }
  3301. return {
  3302. top: top,
  3303. left: left,
  3304. right: right,
  3305. bottom: bottom,
  3306. width: right - left,
  3307. height: bottom - top
  3308. };
  3309. },
  3310. /**
  3311. * @name Two.Group#noFill
  3312. * @function
  3313. * @description Apply `noFill` method to all child shapes.
  3314. */
  3315. noFill: function() {
  3316. this.children.forEach(function(child) {
  3317. child.noFill();
  3318. });
  3319. return this;
  3320. },
  3321. /**
  3322. * @name Two.Group#noStroke
  3323. * @function
  3324. * @description Apply `noStroke` method to all child shapes.
  3325. */
  3326. noStroke: function() {
  3327. this.children.forEach(function(child) {
  3328. child.noStroke();
  3329. });
  3330. return this;
  3331. },
  3332. /**
  3333. * @name Two.Group#subdivide
  3334. * @function
  3335. * @description Apply `subdivide` method to all child shapes.
  3336. */
  3337. subdivide: function() {
  3338. var args = arguments;
  3339. this.children.forEach(function(child) {
  3340. child.subdivide.apply(child, args);
  3341. });
  3342. return this;
  3343. },
  3344. /**
  3345. * @name Two.Group#_update
  3346. * @function
  3347. * @private
  3348. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  3349. * @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.
  3350. * @nota-bene Try not to call this method more than once a frame.
  3351. */
  3352. _update: function() {
  3353. var i, l, child;
  3354. if (this._flagBeginning || this._flagEnding) {
  3355. var beginning = Math.min(this._beginning, this._ending);
  3356. var ending = Math.max(this._beginning, this._ending);
  3357. var length = this.length;
  3358. var sum = 0;
  3359. var bd = beginning * length;
  3360. var ed = ending * length;
  3361. for (i = 0; i < this.children.length; i++) {
  3362. child = this.children[i];
  3363. l = child.length;
  3364. if (bd > sum + l) {
  3365. child.beginning = 1;
  3366. child.ending = 1;
  3367. } else if (ed < sum) {
  3368. child.beginning = 0;
  3369. child.ending = 0;
  3370. } else if (bd > sum && bd < sum + l) {
  3371. child.beginning = (bd - sum) / l;
  3372. child.ending = 1;
  3373. } else if (ed > sum && ed < sum + l) {
  3374. child.beginning = 0;
  3375. child.ending = (ed - sum) / l;
  3376. } else {
  3377. child.beginning = 0;
  3378. child.ending = 1;
  3379. }
  3380. sum += l;
  3381. }
  3382. }
  3383. return Shape.prototype._update.apply(this, arguments);
  3384. },
  3385. /**
  3386. * @name Two.Group#flagReset
  3387. * @function
  3388. * @private
  3389. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  3390. */
  3391. flagReset: function() {
  3392. if (this._flagAdditions) {
  3393. this.additions.length = 0;
  3394. this._flagAdditions = false;
  3395. }
  3396. if (this._flagSubtractions) {
  3397. this.subtractions.length = 0;
  3398. this._flagSubtractions = false;
  3399. }
  3400. this._flagOrder = this._flagMask = this._flagOpacity =
  3401. this._flagBeginning = this._flagEnding = false;
  3402. Shape.prototype.flagReset.call(this);
  3403. return this;
  3404. }
  3405. });
  3406. Group.MakeObservable(Group.prototype);
  3407. // /**
  3408. // * Helper function used to sync parent-child relationship within the
  3409. // * `Two.Group.children` object.
  3410. // *
  3411. // * Set the parent of the passed object to another object
  3412. // * and updates parent-child relationships
  3413. // * Calling with one arguments will simply remove the parenting
  3414. // */
  3415. function replaceParent(child, newParent) {
  3416. var parent = child.parent;
  3417. var index;
  3418. if (parent === newParent) {
  3419. add();
  3420. return;
  3421. }
  3422. if (parent && parent.children.ids[child.id]) {
  3423. index = Array.prototype.indexOf.call(parent.children, child);
  3424. parent.children.splice(index, 1);
  3425. splice();
  3426. }
  3427. if (newParent) {
  3428. add();
  3429. return;
  3430. }
  3431. splice();
  3432. if (parent._flagAdditions && parent.additions.length === 0) {
  3433. parent._flagAdditions = false;
  3434. }
  3435. if (parent._flagSubtractions && parent.subtractions.length === 0) {
  3436. parent._flagSubtractions = false;
  3437. }
  3438. delete child.parent;
  3439. function add() {
  3440. if (newParent.subtractions.length > 0) {
  3441. index = Array.prototype.indexOf.call(newParent.subtractions, child);
  3442. if (index >= 0) {
  3443. newParent.subtractions.splice(index, 1);
  3444. }
  3445. }
  3446. if (newParent.additions.length > 0) {
  3447. index = Array.prototype.indexOf.call(newParent.additions, child);
  3448. if (index >= 0) {
  3449. newParent.additions.splice(index, 1);
  3450. }
  3451. }
  3452. child.parent = newParent;
  3453. newParent.additions.push(child);
  3454. newParent._flagAdditions = true;
  3455. }
  3456. function splice() {
  3457. index = Array.prototype.indexOf.call(parent.additions, child);
  3458. if (index >= 0) {
  3459. parent.additions.splice(index, 1);
  3460. }
  3461. index = Array.prototype.indexOf.call(parent.subtractions, child);
  3462. if (index < 0) {
  3463. parent.subtractions.push(child);
  3464. parent._flagSubtractions = true;
  3465. }
  3466. }
  3467. }
  3468. // Constants
  3469. var emptyArray = [];
  3470. var TWO_PI$5 = Math.PI * 2,
  3471. max$2 = Math.max,
  3472. min$2 = Math.min,
  3473. abs = Math.abs,
  3474. sin$4 = Math.sin,
  3475. cos$4 = Math.cos,
  3476. acos = Math.acos,
  3477. sqrt = Math.sqrt;
  3478. // Returns true if this is a non-transforming matrix
  3479. var isDefaultMatrix = function (m) {
  3480. return (m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0);
  3481. };
  3482. var canvas = {
  3483. isHidden: /(undefined|none|transparent)/i,
  3484. alignments: {
  3485. left: 'start',
  3486. middle: 'center',
  3487. right: 'end'
  3488. },
  3489. shim: function(elem, name) {
  3490. elem.tagName = elem.nodeName = name || 'canvas';
  3491. elem.nodeType = 1;
  3492. elem.getAttribute = function(prop) {
  3493. return this[prop];
  3494. };
  3495. elem.setAttribute = function(prop, val) {
  3496. this[prop] = val;
  3497. return this;
  3498. };
  3499. return elem;
  3500. },
  3501. group: {
  3502. renderChild: function(child) {
  3503. canvas[child._renderer.type].render.call(child, this.ctx, true, this.clip);
  3504. },
  3505. render: function(ctx) {
  3506. if (!this._visible) {
  3507. return this;
  3508. }
  3509. this._update();
  3510. var matrix = this._matrix.elements;
  3511. var parent = this.parent;
  3512. this._renderer.opacity = this._opacity
  3513. * (parent && parent._renderer ? parent._renderer.opacity : 1);
  3514. var mask = this._mask;
  3515. // var clip = this._clip;
  3516. var defaultMatrix = isDefaultMatrix(matrix);
  3517. var shouldIsolate = !defaultMatrix || !!mask;
  3518. if (!this._renderer.context) {
  3519. this._renderer.context = {};
  3520. }
  3521. this._renderer.context.ctx = ctx;
  3522. // this._renderer.context.clip = clip;
  3523. if (shouldIsolate) {
  3524. ctx.save();
  3525. if (!defaultMatrix) {
  3526. ctx.transform(matrix[0], matrix[3], matrix[1],
  3527. matrix[4], matrix[2], matrix[5]);
  3528. }
  3529. }
  3530. if (mask) {
  3531. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3532. }
  3533. if (this._opacity > 0 && this._scale !== 0) {
  3534. for (var i = 0; i < this.children.length; i++) {
  3535. var child = this.children[i];
  3536. canvas[child._renderer.type].render.call(child, ctx);
  3537. }
  3538. }
  3539. if (shouldIsolate) {
  3540. ctx.restore();
  3541. }
  3542. // Commented two-way functionality of clips / masks with groups and
  3543. // polygons. Uncomment when this bug is fixed:
  3544. // https://code.google.com/p/chromium/issues/detail?id=370951
  3545. // if (clip) {
  3546. // ctx.clip();
  3547. // }
  3548. return this.flagReset();
  3549. }
  3550. },
  3551. path: {
  3552. render: function(ctx, forced, parentClipped) {
  3553. var matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter,
  3554. closed, commands, length, last, next, prev, a, b, c, d, ux, uy, vx, vy,
  3555. ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset, dashes, po;
  3556. po = (this.parent && this.parent._renderer)
  3557. ? this.parent._renderer.opacity : 1;
  3558. mask = this._mask;
  3559. clip = this._clip;
  3560. opacity = this._opacity * (po || 1);
  3561. visible = this._visible;
  3562. if (!forced && (!visible || clip || opacity === 0)) {
  3563. return this;
  3564. }
  3565. this._update();
  3566. matrix = this._matrix.elements;
  3567. stroke = this._stroke;
  3568. linewidth = this._linewidth;
  3569. fill = this._fill;
  3570. cap = this._cap;
  3571. join = this._join;
  3572. miter = this._miter;
  3573. closed = this._closed;
  3574. commands = this._renderer.vertices; // Commands
  3575. length = commands.length;
  3576. last = length - 1;
  3577. defaultMatrix = isDefaultMatrix(matrix);
  3578. dashes = this.dashes;
  3579. // Transform
  3580. if (!defaultMatrix) {
  3581. ctx.save();
  3582. ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  3583. }
  3584. // Commented two-way functionality of clips / masks with groups and
  3585. // polygons. Uncomment when this bug is fixed:
  3586. // https://code.google.com/p/chromium/issues/detail?id=370951
  3587. if (mask) {
  3588. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3589. }
  3590. // Styles
  3591. if (fill) {
  3592. if (typeof fill === 'string') {
  3593. ctx.fillStyle = fill;
  3594. } else {
  3595. canvas[fill._renderer.type].render.call(fill, ctx);
  3596. ctx.fillStyle = fill._renderer.effect;
  3597. }
  3598. }
  3599. if (stroke) {
  3600. if (typeof stroke === 'string') {
  3601. ctx.strokeStyle = stroke;
  3602. } else {
  3603. canvas[stroke._renderer.type].render.call(stroke, ctx);
  3604. ctx.strokeStyle = stroke._renderer.effect;
  3605. }
  3606. if (linewidth) {
  3607. ctx.lineWidth = linewidth;
  3608. }
  3609. if (miter) {
  3610. ctx.miterLimit = miter;
  3611. }
  3612. if (join) {
  3613. ctx.lineJoin = join;
  3614. }
  3615. if (!closed && cap) {
  3616. ctx.lineCap = cap;
  3617. }
  3618. }
  3619. if (typeof opacity === 'number') {
  3620. ctx.globalAlpha = opacity;
  3621. }
  3622. if (dashes && dashes.length > 0) {
  3623. ctx.lineDashOffset = dashes.offset || 0;
  3624. ctx.setLineDash(dashes);
  3625. }
  3626. ctx.beginPath();
  3627. for (var i = 0; i < commands.length; i++) {
  3628. b = commands[i];
  3629. x = b.x;
  3630. y = b.y;
  3631. switch (b.command) {
  3632. case Commands.close:
  3633. ctx.closePath();
  3634. break;
  3635. case Commands.arc:
  3636. var rx = b.rx;
  3637. var ry = b.ry;
  3638. var xAxisRotation = b.xAxisRotation;
  3639. var largeArcFlag = b.largeArcFlag;
  3640. var sweepFlag = b.sweepFlag;
  3641. prev = closed ? mod(i - 1, length) : max$2(i - 1, 0);
  3642. a = commands[prev];
  3643. var ax = a.x;
  3644. var ay = a.y;
  3645. canvas.renderSvgArcCommand(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y);
  3646. break;
  3647. case Commands.curve:
  3648. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  3649. next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  3650. a = commands[prev];
  3651. c = commands[next];
  3652. ar = (a.controls && a.controls.right) || Vector.zero;
  3653. bl = (b.controls && b.controls.left) || Vector.zero;
  3654. if (a._relative) {
  3655. vx = (ar.x + a.x);
  3656. vy = (ar.y + a.y);
  3657. } else {
  3658. vx = ar.x;
  3659. vy = ar.y;
  3660. }
  3661. if (b._relative) {
  3662. ux = (bl.x + b.x);
  3663. uy = (bl.y + b.y);
  3664. } else {
  3665. ux = bl.x;
  3666. uy = bl.y;
  3667. }
  3668. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  3669. if (i >= last && closed) {
  3670. c = d;
  3671. br = (b.controls && b.controls.right) || Vector.zero;
  3672. cl = (c.controls && c.controls.left) || Vector.zero;
  3673. if (b._relative) {
  3674. vx = (br.x + b.x);
  3675. vy = (br.y + b.y);
  3676. } else {
  3677. vx = br.x;
  3678. vy = br.y;
  3679. }
  3680. if (c._relative) {
  3681. ux = (cl.x + c.x);
  3682. uy = (cl.y + c.y);
  3683. } else {
  3684. ux = cl.x;
  3685. uy = cl.y;
  3686. }
  3687. x = c.x;
  3688. y = c.y;
  3689. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  3690. }
  3691. break;
  3692. case Commands.line:
  3693. ctx.lineTo(x, y);
  3694. break;
  3695. case Commands.move:
  3696. d = b;
  3697. ctx.moveTo(x, y);
  3698. break;
  3699. }
  3700. }
  3701. // Loose ends
  3702. if (closed) {
  3703. ctx.closePath();
  3704. }
  3705. if (!clip && !parentClipped) {
  3706. if (!canvas.isHidden.test(fill)) {
  3707. isOffset = fill._renderer && fill._renderer.offset;
  3708. if (isOffset) {
  3709. ctx.save();
  3710. ctx.translate(
  3711. - fill._renderer.offset.x, - fill._renderer.offset.y);
  3712. ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  3713. }
  3714. ctx.fill();
  3715. if (isOffset) {
  3716. ctx.restore();
  3717. }
  3718. }
  3719. if (!canvas.isHidden.test(stroke)) {
  3720. isOffset = stroke._renderer && stroke._renderer.offset;
  3721. if (isOffset) {
  3722. ctx.save();
  3723. ctx.translate(
  3724. - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  3725. ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  3726. ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  3727. }
  3728. ctx.stroke();
  3729. if (isOffset) {
  3730. ctx.restore();
  3731. }
  3732. }
  3733. }
  3734. if (!defaultMatrix) {
  3735. ctx.restore();
  3736. }
  3737. if (clip && !parentClipped) {
  3738. ctx.clip();
  3739. }
  3740. if (dashes && dashes.length > 0) {
  3741. ctx.setLineDash(emptyArray);
  3742. }
  3743. return this.flagReset();
  3744. }
  3745. },
  3746. text: {
  3747. render: function(ctx, forced, parentClipped) {
  3748. var po = (this.parent && this.parent._renderer)
  3749. ? this.parent._renderer.opacity : 1;
  3750. var opacity = this._opacity * po;
  3751. var visible = this._visible;
  3752. var mask = this._mask;
  3753. var clip = this._clip;
  3754. if (!forced && (!visible || clip || opacity === 0)) {
  3755. return this;
  3756. }
  3757. this._update();
  3758. var matrix = this._matrix.elements;
  3759. var stroke = this._stroke;
  3760. var linewidth = this._linewidth;
  3761. var fill = this._fill;
  3762. var decoration = this._decoration;
  3763. var defaultMatrix = isDefaultMatrix(matrix);
  3764. var isOffset = fill._renderer && fill._renderer.offset
  3765. && stroke._renderer && stroke._renderer.offset;
  3766. var dashes = this.dashes;
  3767. var alignment = canvas.alignments[this._alignment] || this._alignment;
  3768. var baseline = this._baseline;
  3769. var a, b, c, d, e, sx, sy, x1, y1, x2, y2;
  3770. // Transform
  3771. if (!defaultMatrix) {
  3772. ctx.save();
  3773. ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]);
  3774. }
  3775. // Commented two-way functionality of clips / masks with groups and
  3776. // polygons. Uncomment when this bug is fixed:
  3777. // https://code.google.com/p/chromium/issues/detail?id=370951
  3778. if (mask) {
  3779. canvas[mask._renderer.type].render.call(mask, ctx, true);
  3780. }
  3781. if (!isOffset) {
  3782. ctx.font = [this._style, this._weight, this._size + 'px/' +
  3783. this._leading + 'px', this._family].join(' ');
  3784. }
  3785. ctx.textAlign = alignment;
  3786. ctx.textBaseline = baseline;
  3787. // Styles
  3788. if (fill) {
  3789. if (typeof fill === 'string') {
  3790. ctx.fillStyle = fill;
  3791. } else {
  3792. canvas[fill._renderer.type].render.call(fill, ctx);
  3793. ctx.fillStyle = fill._renderer.effect;
  3794. }
  3795. }
  3796. if (stroke) {
  3797. if (typeof stroke === 'string') {
  3798. ctx.strokeStyle = stroke;
  3799. } else {
  3800. canvas[stroke._renderer.type].render.call(stroke, ctx);
  3801. ctx.strokeStyle = stroke._renderer.effect;
  3802. }
  3803. if (linewidth) {
  3804. ctx.lineWidth = linewidth;
  3805. }
  3806. }
  3807. if (typeof opacity === 'number') {
  3808. ctx.globalAlpha = opacity;
  3809. }
  3810. if (dashes && dashes.length > 0) {
  3811. ctx.lineDashOffset = dashes.offset || 0;
  3812. ctx.setLineDash(dashes);
  3813. }
  3814. if (!clip && !parentClipped) {
  3815. if (!canvas.isHidden.test(fill)) {
  3816. if (fill._renderer && fill._renderer.offset) {
  3817. sx = fill._renderer.scale.x;
  3818. sy = fill._renderer.scale.y;
  3819. ctx.save();
  3820. ctx.translate( - fill._renderer.offset.x,
  3821. - fill._renderer.offset.y);
  3822. ctx.scale(sx, sy);
  3823. a = this._size / fill._renderer.scale.y;
  3824. b = this._leading / fill._renderer.scale.y;
  3825. ctx.font = [this._style, this._weight, a + 'px/',
  3826. b + 'px', this._family].join(' ');
  3827. c = fill._renderer.offset.x / fill._renderer.scale.x;
  3828. d = fill._renderer.offset.y / fill._renderer.scale.y;
  3829. ctx.fillText(this.value, c, d);
  3830. ctx.restore();
  3831. } else {
  3832. ctx.fillText(this.value, 0, 0);
  3833. }
  3834. }
  3835. if (!canvas.isHidden.test(stroke)) {
  3836. if (stroke._renderer && stroke._renderer.offset) {
  3837. sx = stroke._renderer.scale.x;
  3838. sy = stroke._renderer.scale.y;
  3839. ctx.save();
  3840. ctx.translate(- stroke._renderer.offset.x,
  3841. - stroke._renderer.offset.y);
  3842. ctx.scale(sx, sy);
  3843. a = this._size / stroke._renderer.scale.y;
  3844. b = this._leading / stroke._renderer.scale.y;
  3845. ctx.font = [this._style, this._weight, a + 'px/',
  3846. b + 'px', this._family].join(' ');
  3847. c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  3848. d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  3849. e = linewidth / stroke._renderer.scale.x;
  3850. ctx.lineWidth = e;
  3851. ctx.strokeText(this.value, c, d);
  3852. ctx.restore();
  3853. } else {
  3854. ctx.strokeText(this.value, 0, 0);
  3855. }
  3856. }
  3857. }
  3858. // Handle text-decoration
  3859. if (/(underline|strikethrough)/i.test(decoration)) {
  3860. var metrics = ctx.measureText(this.value);
  3861. var scalar = 1;
  3862. switch (decoration) {
  3863. case 'underline':
  3864. y1 = metrics.actualBoundingBoxAscent;
  3865. y2 = metrics.actualBoundingBoxAscent;
  3866. break;
  3867. case 'strikethrough':
  3868. y1 = 0;
  3869. y2 = 0;
  3870. scalar = 0.5;
  3871. break;
  3872. }
  3873. switch (baseline) {
  3874. case 'top':
  3875. y1 += this._size * scalar;
  3876. y2 += this._size * scalar;
  3877. break;
  3878. case 'baseline':
  3879. case 'bottom':
  3880. y1 -= this._size * scalar;
  3881. y2 -= this._size * scalar;
  3882. break;
  3883. }
  3884. switch (alignment) {
  3885. case 'left':
  3886. case 'start':
  3887. x1 = 0;
  3888. x2 = metrics.width;
  3889. break;
  3890. case 'right':
  3891. case 'end':
  3892. x1 = - metrics.width;
  3893. x2 = 0;
  3894. break;
  3895. default:
  3896. x1 = - metrics.width / 2;
  3897. x2 = metrics.width / 2;
  3898. }
  3899. ctx.lineWidth = Math.max(Math.floor(this._size / 15), 1);
  3900. ctx.strokeStyle = ctx.fillStyle;
  3901. ctx.beginPath();
  3902. ctx.moveTo(x1, y1);
  3903. ctx.lineTo(x2, y2);
  3904. ctx.stroke();
  3905. }
  3906. if (!defaultMatrix) {
  3907. ctx.restore();
  3908. }
  3909. // TODO: Test for text
  3910. if (clip && !parentClipped) {
  3911. ctx.clip();
  3912. }
  3913. if (dashes && dashes.length > 0) {
  3914. ctx.setLineDash(emptyArray);
  3915. }
  3916. return this.flagReset();
  3917. }
  3918. },
  3919. 'linear-gradient': {
  3920. render: function(ctx) {
  3921. this._update();
  3922. if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  3923. this._renderer.effect = ctx.createLinearGradient(
  3924. this.left._x, this.left._y,
  3925. this.right._x, this.right._y
  3926. );
  3927. for (var i = 0; i < this.stops.length; i++) {
  3928. var stop = this.stops[i];
  3929. this._renderer.effect.addColorStop(stop._offset, stop._color);
  3930. }
  3931. }
  3932. return this.flagReset();
  3933. }
  3934. },
  3935. 'radial-gradient': {
  3936. render: function(ctx) {
  3937. this._update();
  3938. if (!this._renderer.effect || this._flagCenter || this._flagFocal
  3939. || this._flagRadius || this._flagStops) {
  3940. this._renderer.effect = ctx.createRadialGradient(
  3941. this.center._x, this.center._y, 0,
  3942. this.focal._x, this.focal._y, this._radius
  3943. );
  3944. for (var i = 0; i < this.stops.length; i++) {
  3945. var stop = this.stops[i];
  3946. this._renderer.effect.addColorStop(stop._offset, stop._color);
  3947. }
  3948. }
  3949. return this.flagReset();
  3950. }
  3951. },
  3952. texture: {
  3953. render: function(ctx) {
  3954. this._update();
  3955. var image = this.image;
  3956. if (!this._renderer.effect || ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) {
  3957. this._renderer.effect = ctx.createPattern(this.image, this._repeat);
  3958. }
  3959. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  3960. if (!(this._renderer.offset instanceof Vector)) {
  3961. this._renderer.offset = new Vector();
  3962. }
  3963. this._renderer.offset.x = - this._offset.x;
  3964. this._renderer.offset.y = - this._offset.y;
  3965. if (image) {
  3966. this._renderer.offset.x += image.width / 2;
  3967. this._renderer.offset.y += image.height / 2;
  3968. if (this._scale instanceof Vector) {
  3969. this._renderer.offset.x *= this._scale.x;
  3970. this._renderer.offset.y *= this._scale.y;
  3971. } else {
  3972. this._renderer.offset.x *= this._scale;
  3973. this._renderer.offset.y *= this._scale;
  3974. }
  3975. }
  3976. }
  3977. if (this._flagScale || this._flagLoaded) {
  3978. if (!(this._renderer.scale instanceof Vector)) {
  3979. this._renderer.scale = new Vector();
  3980. }
  3981. if (this._scale instanceof Vector) {
  3982. this._renderer.scale.copy(this._scale);
  3983. } else {
  3984. this._renderer.scale.set(this._scale, this._scale);
  3985. }
  3986. }
  3987. return this.flagReset();
  3988. }
  3989. },
  3990. renderSvgArcCommand: function(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y) {
  3991. xAxisRotation = xAxisRotation * Math.PI / 180;
  3992. // Ensure radii are positive
  3993. rx = abs(rx);
  3994. ry = abs(ry);
  3995. // Compute (x1′, y1′)
  3996. var dx2 = (ax - x) / 2.0;
  3997. var dy2 = (ay - y) / 2.0;
  3998. var x1p = cos$4(xAxisRotation) * dx2 + sin$4(xAxisRotation) * dy2;
  3999. var y1p = - sin$4(xAxisRotation) * dx2 + cos$4(xAxisRotation) * dy2;
  4000. // Compute (cx′, cy′)
  4001. var rxs = rx * rx;
  4002. var rys = ry * ry;
  4003. var x1ps = x1p * x1p;
  4004. var y1ps = y1p * y1p;
  4005. // Ensure radii are large enough
  4006. var cr = x1ps / rxs + y1ps / rys;
  4007. if (cr > 1) {
  4008. // scale up rx,ry equally so cr == 1
  4009. var s = sqrt(cr);
  4010. rx = s * rx;
  4011. ry = s * ry;
  4012. rxs = rx * rx;
  4013. rys = ry * ry;
  4014. }
  4015. var dq = (rxs * y1ps + rys * x1ps);
  4016. var pq = (rxs * rys - dq) / dq;
  4017. var q = sqrt(max$2(0, pq));
  4018. if (largeArcFlag === sweepFlag) q = - q;
  4019. var cxp = q * rx * y1p / ry;
  4020. var cyp = - q * ry * x1p / rx;
  4021. // Step 3: Compute (cx, cy) from (cx′, cy′)
  4022. var cx = cos$4(xAxisRotation) * cxp
  4023. - sin$4(xAxisRotation) * cyp + (ax + x) / 2;
  4024. var cy = sin$4(xAxisRotation) * cxp
  4025. + cos$4(xAxisRotation) * cyp + (ay + y) / 2;
  4026. // Step 4: Compute θ1 and Δθ
  4027. var startAngle = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
  4028. var delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry,
  4029. (- x1p - cxp) / rx, (- y1p - cyp) / ry) % TWO_PI$5;
  4030. var endAngle = startAngle + delta;
  4031. var clockwise = sweepFlag === 0;
  4032. renderArcEstimate(ctx, cx, cy, rx, ry, startAngle, endAngle,
  4033. clockwise, xAxisRotation);
  4034. }
  4035. };
  4036. /**
  4037. * @name Two.CanvasRenderer
  4038. * @class
  4039. * @extends Two.Events
  4040. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  4041. * @param {Element} [parameters.domElement] - The `<canvas />` to draw to. If none given a new one will be constructed.
  4042. * @param {Boolean} [parameters.overdraw] - Determines whether the canvas should clear the background or not. Defaults to `true`.
  4043. * @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.
  4044. * @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 />`.
  4045. */
  4046. function Renderer$2(params) {
  4047. // It might not make a big difference on GPU backed canvases.
  4048. var smoothing = (params.smoothing !== false);
  4049. /**
  4050. * @name Two.CanvasRenderer#domElement
  4051. * @property {Element} - The `<canvas />` associated with the Two.js scene.
  4052. */
  4053. this.domElement = params.domElement || document.createElement('canvas');
  4054. /**
  4055. * @name Two.CanvasRenderer#ctx
  4056. * @property {Canvas2DContext} - Associated two dimensional context to render on the `<canvas />`.
  4057. */
  4058. this.ctx = this.domElement.getContext('2d');
  4059. /**
  4060. * @name Two.CanvasRenderer#overdraw
  4061. * @property {Boolean} - Determines whether the canvas clears the background each draw call.
  4062. * @default true
  4063. */
  4064. this.overdraw = params.overdraw || false;
  4065. if (typeof this.ctx.imageSmoothingEnabled !== 'undefined') {
  4066. this.ctx.imageSmoothingEnabled = smoothing;
  4067. }
  4068. /**
  4069. * @name Two.CanvasRenderer#scene
  4070. * @property {Two.Group} - The root group of the scenegraph.
  4071. */
  4072. this.scene = new Group();
  4073. this.scene.parent = this;
  4074. }
  4075. _.extend(Renderer$2, {
  4076. /**
  4077. * @name Two.CanvasRenderer.Utils
  4078. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<canvas />`.
  4079. */
  4080. Utils: canvas
  4081. });
  4082. _.extend(Renderer$2.prototype, Events, {
  4083. constructor: Renderer$2,
  4084. /**
  4085. * @name Two.CanvasRenderer#setSize
  4086. * @function
  4087. * @fires resize
  4088. * @param {Number} width - The new width of the renderer.
  4089. * @param {Number} height - The new height of the renderer.
  4090. * @param {Number} [ratio] - The new pixel ratio (pixel density) of the renderer. Defaults to calculate the pixel density of the user's screen.
  4091. * @description Change the size of the renderer.
  4092. */
  4093. setSize: function(width, height, ratio) {
  4094. this.width = width;
  4095. this.height = height;
  4096. this.ratio = typeof ratio === 'undefined' ? getRatio(this.ctx) : ratio;
  4097. this.domElement.width = width * this.ratio;
  4098. this.domElement.height = height * this.ratio;
  4099. if (this.domElement.style) {
  4100. _.extend(this.domElement.style, {
  4101. width: width + 'px',
  4102. height: height + 'px'
  4103. });
  4104. }
  4105. return this.trigger(Events.Types.resize, width, height, ratio);
  4106. },
  4107. /**
  4108. * @name Two.CanvasRenderer#render
  4109. * @function
  4110. * @description Render the current scene to the `<canvas />`.
  4111. */
  4112. render: function() {
  4113. var isOne = this.ratio === 1;
  4114. if (!isOne) {
  4115. this.ctx.save();
  4116. this.ctx.scale(this.ratio, this.ratio);
  4117. }
  4118. if (!this.overdraw) {
  4119. this.ctx.clearRect(0, 0, this.width, this.height);
  4120. }
  4121. canvas.group.render.call(this.scene, this.ctx);
  4122. if (!isOne) {
  4123. this.ctx.restore();
  4124. }
  4125. return this;
  4126. }
  4127. });
  4128. function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, clockwise, xAxisRotation) {
  4129. var epsilon = Curve.Tolerance.epsilon;
  4130. var deltaAngle = endAngle - startAngle;
  4131. var samePoints = Math.abs(deltaAngle) < epsilon;
  4132. // ensures that deltaAngle is 0 .. 2 PI
  4133. deltaAngle = mod(deltaAngle, TWO_PI$5);
  4134. if (deltaAngle < epsilon) {
  4135. if (samePoints) {
  4136. deltaAngle = 0;
  4137. } else {
  4138. deltaAngle = TWO_PI$5;
  4139. }
  4140. }
  4141. if (clockwise === true && ! samePoints) {
  4142. if (deltaAngle === TWO_PI$5) {
  4143. deltaAngle = - TWO_PI$5;
  4144. } else {
  4145. deltaAngle = deltaAngle - TWO_PI$5;
  4146. }
  4147. }
  4148. for (var i = 0; i < Constants.Resolution; i++) {
  4149. var t = i / (Constants.Resolution - 1);
  4150. var angle = startAngle + t * deltaAngle;
  4151. var x = ox + rx * Math.cos(angle);
  4152. var y = oy + ry * Math.sin(angle);
  4153. if (xAxisRotation !== 0) {
  4154. var cos = Math.cos(xAxisRotation);
  4155. var sin = Math.sin(xAxisRotation);
  4156. var tx = x - ox;
  4157. var ty = y - oy;
  4158. // Rotate the point about the center of the ellipse.
  4159. x = tx * cos - ty * sin + ox;
  4160. y = tx * sin + ty * cos + oy;
  4161. }
  4162. ctx.lineTo(x, y);
  4163. }
  4164. }
  4165. function svgAngle(ux, uy, vx, vy) {
  4166. var dot = ux * vx + uy * vy;
  4167. var len = sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy);
  4168. // floating point precision, slightly over values appear
  4169. var ang = acos(max$2(-1, min$2(1, dot / len)));
  4170. if ((ux * vy - uy * vx) < 0) {
  4171. ang = - ang;
  4172. }
  4173. return ang;
  4174. }
  4175. var CanvasShim = {
  4176. Image: null,
  4177. isHeadless: false,
  4178. /**
  4179. * @name Two.Utils.shim
  4180. * @function
  4181. * @param {canvas} canvas - The instanced `Canvas` object provided by `node-canvas`.
  4182. * @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.
  4183. * @returns {canvas} Returns the instanced canvas object you passed from with additional attributes needed for Two.js.
  4184. * @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.
  4185. */
  4186. shim: function(canvas, Image) {
  4187. Renderer$2.Utils.shim(canvas);
  4188. if (typeof Image !== 'undefined') {
  4189. CanvasShim.Image = Image;
  4190. }
  4191. CanvasShim.isHeadless = true;
  4192. return canvas;
  4193. }
  4194. };
  4195. var dom = {
  4196. hasEventListeners: typeof root$1.addEventListener === 'function',
  4197. bind: function(elem, event, func, bool) {
  4198. if (this.hasEventListeners) {
  4199. elem.addEventListener(event, func, !!bool);
  4200. } else {
  4201. elem.attachEvent('on' + event, func);
  4202. }
  4203. return dom;
  4204. },
  4205. unbind: function(elem, event, func, bool) {
  4206. if (dom.hasEventListeners) {
  4207. elem.removeEventListeners(event, func, !!bool);
  4208. } else {
  4209. elem.detachEvent('on' + event, func);
  4210. }
  4211. return dom;
  4212. },
  4213. getRequestAnimationFrame: function() {
  4214. var lastTime = 0;
  4215. var vendors = ['ms', 'moz', 'webkit', 'o'];
  4216. var request = root$1.requestAnimationFrame, cancel;
  4217. if(!request) {
  4218. for (var i = 0; i < vendors.length; i++) {
  4219. request = root$1[vendors[i] + 'RequestAnimationFrame'] || request;
  4220. cancel = root$1[vendors[i] + 'CancelAnimationFrame']
  4221. || root$1[vendors[i] + 'CancelRequestAnimationFrame'] || cancel;
  4222. }
  4223. request = request || function(callback, element) {
  4224. var currTime = new Date().getTime();
  4225. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  4226. var id = root$1.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
  4227. lastTime = currTime + timeToCall;
  4228. return id;
  4229. };
  4230. }
  4231. return request;
  4232. }
  4233. };
  4234. var temp = (root$1.document ? root$1.document.createElement('div') : {});
  4235. temp.id = 'help-two-load';
  4236. Object.defineProperty(dom, 'temp', {
  4237. enumerable: true,
  4238. get: function() {
  4239. if (_.isElement(temp) && !root$1.document.head.contains(temp)) {
  4240. _.extend(temp.style, {
  4241. display: 'none'
  4242. });
  4243. root$1.document.head.appendChild(temp);
  4244. }
  4245. return temp;
  4246. }
  4247. });
  4248. /**
  4249. * @name Two.Utils.Error
  4250. * @class
  4251. * @description Custom error throwing for Two.js specific identification.
  4252. */
  4253. function TwoError(message) {
  4254. this.name = 'Two.js';
  4255. this.message = message;
  4256. }
  4257. TwoError.prototype = new Error();
  4258. _.extend(TwoError.prototype, {
  4259. constructor: TwoError
  4260. });
  4261. /**
  4262. * @name Two.Utils.defineGetterSetter
  4263. * @function
  4264. * @this Two#
  4265. * @param {String} property - The property to add an enumerable getter / setter to.
  4266. * @description Convenience function to setup the flag based getter / setter that most properties are defined as in Two.js.
  4267. */
  4268. var defineGetterSetter = function(property) {
  4269. var object = this;
  4270. var secret = '_' + property;
  4271. var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  4272. Object.defineProperty(object, property, {
  4273. enumerable: true,
  4274. get: function() {
  4275. return this[secret];
  4276. },
  4277. set: function(v) {
  4278. this[secret] = v;
  4279. this[flag] = true;
  4280. }
  4281. });
  4282. };
  4283. /**
  4284. * @name Two.Registry
  4285. * @class
  4286. * @description An arbitrary class to manage a directory of things. Mainly used for keeping tabs of textures in Two.js.
  4287. */
  4288. function Registry() {
  4289. this.map = {};
  4290. }
  4291. _.extend(Registry.prototype, {
  4292. constructor: Registry,
  4293. /**
  4294. * @name Two.Registry#add
  4295. * @function
  4296. * @param {String} id - A unique identifier.
  4297. * @param value - Any type of variable to be registered to the directory.
  4298. * @description Adds any value to the directory. Assigned by the `id`.
  4299. */
  4300. add: function(id, obj) {
  4301. this.map[id] = obj;
  4302. return this;
  4303. },
  4304. /**
  4305. * @name Two.Registry#remove
  4306. * @function
  4307. * @param {String} id - A unique identifier.
  4308. * @description Remove any value from the directory by its `id`.
  4309. */
  4310. remove: function(id) {
  4311. delete this.map[id];
  4312. return this;
  4313. },
  4314. /**
  4315. * @name Two.Registry#get
  4316. * @function
  4317. * @param {String} id - A unique identifier.
  4318. * @returns {?Object} The associated value. If unavailable then `undefined` is returned.
  4319. * @description Get a registered value by its `id`.
  4320. */
  4321. get: function(id) {
  4322. return this.map[id];
  4323. },
  4324. /**
  4325. * @name Two.Registry#contains
  4326. * @function
  4327. * @param {String} id - A unique identifier.
  4328. * @returns {Boolean}
  4329. * @description Convenience method to see if a value is registered to an `id` already.
  4330. */
  4331. contains: function(id) {
  4332. return id in this.map;
  4333. }
  4334. });
  4335. /**
  4336. * @name Two.Stop
  4337. * @class
  4338. * @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.
  4339. * @param {String} [color] - The color of the stop. Default value flip flops from white to black as new stops are created.
  4340. * @param {Number} [opacity] - The opacity value. Default value is 1, cannot be lower than 0.
  4341. * @nota-bene Used specifically in conjunction with {@link Two.Gradient}s to control color graduation.
  4342. */
  4343. function Stop(offset, color, opacity) {
  4344. /**
  4345. * @name Two.Stop#renderer
  4346. * @property {Object}
  4347. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4348. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4349. */
  4350. this.renderer = {};
  4351. this._renderer.type = 'stop';
  4352. /**
  4353. * @name Two.Stop#offset
  4354. * @property {Number} - The offset percentage of the stop represented as a zero-to-one value.
  4355. */
  4356. this.offset = typeof offset === 'number' ? offset
  4357. : Stop.Index <= 0 ? 0 : 1;
  4358. /**
  4359. * @name Two.Stop#opacity
  4360. * @property {Number} - The alpha percentage of the stop represented as a zero-to-one value.
  4361. */
  4362. this.opacity = typeof opacity === 'number' ? opacity : 1;
  4363. /**
  4364. * @name Two.Stop#color
  4365. * @property {String} - The color of the stop.
  4366. */
  4367. this.color = (typeof color === 'string') ? color
  4368. : Stop.Index <= 0 ? '#fff' : '#000';
  4369. Stop.Index = (Stop.Index + 1) % 2;
  4370. }
  4371. _.extend(Stop, {
  4372. /**
  4373. * @name Two.Stop.Index
  4374. * @property {Number} - The current index being referenced for calculating a stop's default offset value.
  4375. */
  4376. Index: 0,
  4377. /**
  4378. * @name Two.Stop.Properties
  4379. * @property {String[]} - A list of properties that are on every {@link Two.Stop}.
  4380. */
  4381. Properties: [
  4382. 'offset',
  4383. 'opacity',
  4384. 'color'
  4385. ],
  4386. /**
  4387. * @name Two.Stop.MakeObservable
  4388. * @function
  4389. * @param {Object} object - The object to make observable.
  4390. * @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.
  4391. */
  4392. MakeObservable: function(object) {
  4393. _.each(Stop.Properties, function(property) {
  4394. var object = this;
  4395. var secret = '_' + property;
  4396. var flag = '_flag' + property.charAt(0).toUpperCase() + property.slice(1);
  4397. Object.defineProperty(object, property, {
  4398. enumerable: true,
  4399. get: function() {
  4400. return this[secret];
  4401. },
  4402. set: function(v) {
  4403. this[secret] = v;
  4404. this[flag] = true;
  4405. if (this.parent) {
  4406. this.parent._flagStops = true;
  4407. }
  4408. }
  4409. });
  4410. }, object);
  4411. Object.defineProperty(object, 'renderer', {
  4412. enumerable: false,
  4413. get: function() {
  4414. return this._renderer;
  4415. },
  4416. set: function(obj) {
  4417. this._renderer = obj;
  4418. }
  4419. });
  4420. }
  4421. });
  4422. _.extend(Stop.prototype, Events, {
  4423. constructor: Stop,
  4424. /**
  4425. * @name Two.Stop#clone
  4426. * @function
  4427. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4428. * @returns {Two.Stop}
  4429. * @description Create a new instance of {@link Two.Stop} with the same properties of the current path.
  4430. */
  4431. clone: function() {
  4432. var clone = new Stop();
  4433. _.each(Stop.Properties, function(property) {
  4434. clone[property] = this[property];
  4435. }, this);
  4436. return clone;
  4437. },
  4438. /**
  4439. * @name Two.Stop#toObject
  4440. * @function
  4441. * @returns {Object}
  4442. * @description Return a JSON compatible plain object that represents the path.
  4443. */
  4444. toObject: function() {
  4445. var result = {};
  4446. _.each(Stop.Properties, function(k) {
  4447. result[k] = this[k];
  4448. }, this);
  4449. return result;
  4450. },
  4451. /**
  4452. * @name Two.Stop#flagReset
  4453. * @function
  4454. * @private
  4455. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4456. */
  4457. flagReset: function() {
  4458. this._flagOffset = this._flagColor = this._flagOpacity = false;
  4459. return this;
  4460. }
  4461. });
  4462. Stop.MakeObservable(Stop.prototype);
  4463. /**
  4464. * @name Two.Gradient
  4465. * @class
  4466. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4467. * @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}.
  4468. */
  4469. function Gradient(stops) {
  4470. /**
  4471. * @name Two.Gradient#renderer
  4472. * @property {Object}
  4473. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4474. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4475. */
  4476. this.renderer = {};
  4477. this._renderer.type = 'gradient';
  4478. /**
  4479. * @name Two.Gradient#id
  4480. * @property {String} - Session specific unique identifier.
  4481. * @nota-bene In the {@link Two.SvgRenderer} change this to change the underlying SVG element's id too.
  4482. */
  4483. this.id = Constants.Identifier + Constants.uniqueId();
  4484. this.classList = [];
  4485. this._renderer.flagStops = Gradient.FlagStops.bind(this);
  4486. this._renderer.bindStops = Gradient.BindStops.bind(this);
  4487. this._renderer.unbindStops = Gradient.UnbindStops.bind(this);
  4488. /**
  4489. * @name Two.Gradient#spread
  4490. * @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'`.
  4491. * @see {@link https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementSpreadMethodAttribute} for more information
  4492. */
  4493. this.spread = 'pad';
  4494. /**
  4495. * @name Two.Gradient#stops
  4496. * @property {Two.Stop[]} - An ordered list of {@link Two.Stop}s for rendering the gradient.
  4497. */
  4498. if (stops) {
  4499. this.stops = stops;
  4500. }
  4501. }
  4502. _.extend(Gradient, {
  4503. /**
  4504. * @name Two.Gradient.Stop
  4505. * @see {@link Two.Stop}
  4506. */
  4507. Stop: Stop,
  4508. /**
  4509. * @name Two.Gradient.Properties
  4510. * @property {String[]} - A list of properties that are on every {@link Two.Gradient}.
  4511. */
  4512. Properties: [
  4513. 'spread'
  4514. ],
  4515. /**
  4516. * @name Two.Gradient.MakeObservable
  4517. * @function
  4518. * @param {Object} object - The object to make observable.
  4519. * @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.
  4520. */
  4521. MakeObservable: function(object) {
  4522. _.each(Gradient.Properties, defineGetterSetter, object);
  4523. Object.defineProperty(object, 'stops', {
  4524. enumerable: true,
  4525. get: function() {
  4526. return this._stops;
  4527. },
  4528. set: function(stops) {
  4529. var bindStops = this._renderer.bindStops;
  4530. var unbindStops = this._renderer.unbindStops;
  4531. // Remove previous listeners
  4532. if (this._stops) {
  4533. this._stops
  4534. .unbind(Events.Types.insert, bindStops)
  4535. .unbind(Events.Types.remove, unbindStops);
  4536. }
  4537. // Create new Collection with copy of Stops
  4538. this._stops = new Collection((stops || []).slice(0));
  4539. // Listen for Collection changes and bind / unbind
  4540. this._stops
  4541. .bind(Events.Types.insert, bindStops)
  4542. .bind(Events.Types.remove, unbindStops);
  4543. // Bind Initial Stops
  4544. bindStops(this._stops);
  4545. }
  4546. });
  4547. Object.defineProperty(object, 'renderer', {
  4548. enumerable: false,
  4549. get: function() {
  4550. return this._renderer;
  4551. },
  4552. set: function(obj) {
  4553. this._renderer = obj;
  4554. }
  4555. });
  4556. Object.defineProperty(object, 'id', {
  4557. enumerable: true,
  4558. get: function() {
  4559. return this._id;
  4560. },
  4561. set: function(v) {
  4562. this._id = v;
  4563. }
  4564. });
  4565. },
  4566. /**
  4567. * @name Two.Gradient.FlagStops
  4568. * @function
  4569. * @description Cached method to let renderers know stops have been updated on a {@link Two.Gradient}.
  4570. */
  4571. FlagStops: function() {
  4572. this._flagStops = true;
  4573. },
  4574. /**
  4575. * @name Two.Gradient.BindVertices
  4576. * @function
  4577. * @description Cached method to let {@link Two.Gradient} know vertices have been added to the instance.
  4578. */
  4579. BindStops: function(items) {
  4580. // This function is called a lot
  4581. // when importing a large SVG
  4582. var i = items.length;
  4583. while(i--) {
  4584. items[i].bind(Events.Types.change, this._renderer.flagStops);
  4585. items[i].parent = this;
  4586. }
  4587. this._renderer.flagStops();
  4588. },
  4589. /**
  4590. * @name Two.Gradient.UnbindStops
  4591. * @function
  4592. * @description Cached method to let {@link Two.Gradient} know vertices have been removed from the instance.
  4593. */
  4594. UnbindStops: function(items) {
  4595. var i = items.length;
  4596. while(i--) {
  4597. items[i].unbind(Events.Types.change, this._renderer.flagStops);
  4598. delete items[i].parent;
  4599. }
  4600. this._renderer.flagStops();
  4601. }
  4602. });
  4603. _.extend(Gradient.prototype, Events, {
  4604. constructor: Gradient,
  4605. /**
  4606. * @name Two.Gradient#_flagId
  4607. * @private
  4608. * @property {Boolean} - Determines whether the {@link Two.Gradient#id} needs updating.
  4609. */
  4610. _flagId: false,
  4611. /**
  4612. * @name Two.Gradient#_flagStops
  4613. * @private
  4614. * @property {Boolean} - Determines whether the {@link Two.Gradient#stops} needs updating.
  4615. */
  4616. _flagStops: false,
  4617. /**
  4618. * @name Two.Gradient#_flagSpread
  4619. * @private
  4620. * @property {Boolean} - Determines whether the {@link Two.Gradient#spread} needs updating.
  4621. */
  4622. _flagSpread: false,
  4623. _id: '',
  4624. /**
  4625. * @name Two.Gradient#clone
  4626. * @function
  4627. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4628. * @returns {Two.Gradient}
  4629. * @description Create a new instance of {@link Two.Gradient} with the same properties of the current path.
  4630. */
  4631. clone: function(parent) {
  4632. var stops = this.stops.map(function(s) {
  4633. return s.clone();
  4634. });
  4635. var clone = new Gradient(stops);
  4636. _.each(Gradient.Properties, function(k) {
  4637. clone[k] = this[k];
  4638. }, this);
  4639. if (parent) {
  4640. parent.add(clone);
  4641. }
  4642. return clone;
  4643. },
  4644. /**
  4645. * @name Two.Gradient#toObject
  4646. * @function
  4647. * @returns {Object}
  4648. * @description Return a JSON compatible plain object that represents the path.
  4649. */
  4650. toObject: function() {
  4651. var result = {
  4652. stops: this.stops.map(function(s) {
  4653. return s.toObject();
  4654. })
  4655. };
  4656. _.each(Gradient.Properties, function(k) {
  4657. result[k] = this[k];
  4658. }, this);
  4659. return result;
  4660. },
  4661. /**
  4662. * @name Two.Gradient#_update
  4663. * @function
  4664. * @private
  4665. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4666. * @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.
  4667. * @nota-bene Try not to call this method more than once a frame.
  4668. */
  4669. _update: function() {
  4670. if (this._flagSpread || this._flagStops) {
  4671. this.trigger(Events.Types.change);
  4672. }
  4673. return this;
  4674. },
  4675. /**
  4676. * @name Two.Gradient#flagReset
  4677. * @function
  4678. * @private
  4679. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4680. */
  4681. flagReset: function() {
  4682. this._flagSpread = this._flagStops = false;
  4683. return this;
  4684. }
  4685. });
  4686. Gradient.MakeObservable(Gradient.prototype);
  4687. /**
  4688. * @name Two.LinearGradient
  4689. * @class
  4690. * @extends Two.Gradient
  4691. * @param {Number} [x1=0] - The x position of the first end point of the linear gradient.
  4692. * @param {Number} [y1=0] - The y position of the first end point of the linear gradient.
  4693. * @param {Number} [x2=0] - The x position of the second end point of the linear gradient.
  4694. * @param {Number} [y2=0] - The y position of the second end point of the linear gradient.
  4695. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4696. * @nota-bene The linear gradient lives within the space of the parent object's matrix space.
  4697. */
  4698. function LinearGradient(x1, y1, x2, y2, stops) {
  4699. Gradient.call(this, stops);
  4700. this._renderer.type = 'linear-gradient';
  4701. var flagEndPoints = LinearGradient.FlagEndPoints.bind(this);
  4702. /**
  4703. * @name Two.LinearGradient#left
  4704. * @property {Two.Vector} - The x and y value for where the first end point is placed on the canvas.
  4705. */
  4706. this.left = new Vector().bind(Events.Types.change, flagEndPoints);
  4707. /**
  4708. * @name Two.LinearGradient#right
  4709. * @property {Two.Vector} - The x and y value for where the second end point is placed on the canvas.
  4710. */
  4711. this.right = new Vector().bind(Events.Types.change, flagEndPoints);
  4712. if (typeof x1 === 'number') {
  4713. this.left.x = x1;
  4714. }
  4715. if (typeof y1 === 'number') {
  4716. this.left.y = y1;
  4717. }
  4718. if (typeof x2 === 'number') {
  4719. this.right.x = x2;
  4720. }
  4721. if (typeof y2 === 'number') {
  4722. this.right.y = y2;
  4723. }
  4724. }
  4725. _.extend(LinearGradient, {
  4726. /**
  4727. * @name Two.LinearGradient.Stop
  4728. * @see {@link Two.Stop}
  4729. */
  4730. Stop: Stop,
  4731. /**
  4732. * @name Two.LinearGradient.MakeObservable
  4733. * @function
  4734. * @param {Object} object - The object to make observable.
  4735. * @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.
  4736. */
  4737. MakeObservable: function(object) {
  4738. Gradient.MakeObservable(object);
  4739. },
  4740. /**
  4741. * @name Two.LinearGradient.FlagEndPoints
  4742. * @function
  4743. * @description Cached method to let renderers know end points have been updated on a {@link Two.LinearGradient}.
  4744. */
  4745. FlagEndPoints: function() {
  4746. this._flagEndPoints = true;
  4747. }
  4748. });
  4749. _.extend(LinearGradient.prototype, Gradient.prototype, {
  4750. constructor: LinearGradient,
  4751. /**
  4752. * @name Two.LinearGradient#_flagEndPoints
  4753. * @private
  4754. * @property {Boolean} - Determines whether the {@link Two.LinearGradient#left} or {@link Two.LinearGradient#right} changed and needs to update.
  4755. */
  4756. _flagEndPoints: false,
  4757. /**
  4758. * @name Two.LinearGradient#clone
  4759. * @function
  4760. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4761. * @returns {Two.Gradient}
  4762. * @description Create a new instance of {@link Two.LinearGradient} with the same properties of the current path.
  4763. */
  4764. clone: function(parent) {
  4765. var stops = this.stops.map(function(stop) {
  4766. return stop.clone();
  4767. });
  4768. var clone = new LinearGradient(this.left._x, this.left._y,
  4769. this.right._x, this.right._y, stops);
  4770. _.each(Gradient.Properties, function(k) {
  4771. clone[k] = this[k];
  4772. }, this);
  4773. if (parent) {
  4774. parent.add(clone);
  4775. }
  4776. return clone;
  4777. },
  4778. /**
  4779. * @name Two.LinearGradient#toObject
  4780. * @function
  4781. * @returns {Object}
  4782. * @description Return a JSON compatible plain object that represents the path.
  4783. */
  4784. toObject: function() {
  4785. var result = Gradient.prototype.toObject.call(this);
  4786. result.left = this.left.toObject();
  4787. result.right = this.right.toObject();
  4788. return result;
  4789. },
  4790. /**
  4791. * @name Two.LinearGradient#_update
  4792. * @function
  4793. * @private
  4794. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4795. * @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.
  4796. * @nota-bene Try not to call this method more than once a frame.
  4797. */
  4798. _update: function() {
  4799. if (this._flagEndPoints || this._flagSpread || this._flagStops) {
  4800. this.trigger(Events.Types.change);
  4801. }
  4802. return this;
  4803. },
  4804. /**
  4805. * @name Two.LinearGradient#flagReset
  4806. * @function
  4807. * @private
  4808. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4809. */
  4810. flagReset: function() {
  4811. this._flagEndPoints = false;
  4812. Gradient.prototype.flagReset.call(this);
  4813. return this;
  4814. }
  4815. });
  4816. LinearGradient.MakeObservable(LinearGradient.prototype);
  4817. /**
  4818. * @name Two.RadialGradient
  4819. * @class
  4820. * @extends Two.Gradient
  4821. * @param {Number} [x=0] - The x position of the origin of the radial gradient.
  4822. * @param {Number} [y=0] - The y position of the origin of the radial gradient.
  4823. * @param {Number} [radius=0] - The radius of the radial gradient.
  4824. * @param {Two.Stop[]} [stops] - A list of {@link Two.Stop}s that contain the gradient fill pattern for the gradient.
  4825. * @param {Number} [focalX=0] - The x position of the focal point on the radial gradient.
  4826. * @param {Number} [focalY=0] - The y position of the focal point on the radial gradient.
  4827. * @nota-bene The radial gradient lives within the space of the parent object's matrix space.
  4828. */
  4829. function RadialGradient(cx, cy, r, stops, fx, fy) {
  4830. Gradient.call(this, stops);
  4831. this._renderer.type = 'radial-gradient';
  4832. /**
  4833. * @name Two.RadialGradient#center
  4834. * @property {Two.Vector} - The x and y value for where the origin of the radial gradient is.
  4835. */
  4836. this.center = new Vector()
  4837. .bind(Events.Types.change, (function() {
  4838. this._flagCenter = true;
  4839. }).bind(this));
  4840. this.radius = typeof r === 'number' ? r : 20;
  4841. /**
  4842. * @name Two.RadialGradient#focal
  4843. * @property {Two.Vector} - The x and y value for where the focal point of the radial gradient is.
  4844. * @nota-bene This effects the spray or spread of the radial gradient.
  4845. */
  4846. this.focal = new Vector()
  4847. .bind(Events.Types.change, (function() {
  4848. this._flagFocal = true;
  4849. }).bind(this));
  4850. if (typeof cx === 'number') {
  4851. this.center.x = cx;
  4852. }
  4853. if (typeof cy === 'number') {
  4854. this.center.y = cy;
  4855. }
  4856. this.focal.copy(this.center);
  4857. if (typeof fx === 'number') {
  4858. this.focal.x = fx;
  4859. }
  4860. if (typeof fy === 'number') {
  4861. this.focal.y = fy;
  4862. }
  4863. }
  4864. _.extend(RadialGradient, {
  4865. /**
  4866. * @name Two.RadialGradient.Stop
  4867. * @see {@link Two.Stop}
  4868. */
  4869. Stop: Stop,
  4870. /**
  4871. * @name Two.RadialGradient.Properties
  4872. * @property {String[]} - A list of properties that are on every {@link Two.RadialGradient}.
  4873. */
  4874. Properties: [
  4875. 'radius'
  4876. ],
  4877. /**
  4878. * @name Two.RadialGradient.MakeObservable
  4879. * @function
  4880. * @param {Object} object - The object to make observable.
  4881. * @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.
  4882. */
  4883. MakeObservable: function(object) {
  4884. Gradient.MakeObservable(object);
  4885. _.each(RadialGradient.Properties, defineGetterSetter, object);
  4886. }
  4887. });
  4888. _.extend(RadialGradient.prototype, Gradient.prototype, {
  4889. constructor: RadialGradient,
  4890. /**
  4891. * @name Two.RadialGradient#_flagRadius
  4892. * @private
  4893. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#radius} changed and needs to update.
  4894. */
  4895. _flagRadius: false,
  4896. /**
  4897. * @name Two.RadialGradient#_flagCenter
  4898. * @private
  4899. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#center} changed and needs to update.
  4900. */
  4901. _flagCenter: false,
  4902. /**
  4903. * @name Two.RadialGradient#_flagFocal
  4904. * @private
  4905. * @property {Boolean} - Determines whether the {@link Two.RadialGradient#focal} changed and needs to update.
  4906. */
  4907. _flagFocal: false,
  4908. /**
  4909. * @name Two.RadialGradient#clone
  4910. * @function
  4911. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  4912. * @returns {Two.Gradient}
  4913. * @description Create a new instance of {@link Two.RadialGradient} with the same properties of the current path.
  4914. */
  4915. clone: function(parent) {
  4916. var stops = this.stops.map(function(stop) {
  4917. return stop.clone();
  4918. });
  4919. var clone = new RadialGradient(this.center._x, this.center._y,
  4920. this._radius, stops, this.focal._x, this.focal._y);
  4921. _.each(Gradient.Properties.concat(RadialGradient.Properties), function(k) {
  4922. clone[k] = this[k];
  4923. }, this);
  4924. if (parent) {
  4925. parent.add(clone);
  4926. }
  4927. return clone;
  4928. },
  4929. /**
  4930. * @name Two.RadialGradient#toObject
  4931. * @function
  4932. * @returns {Object}
  4933. * @description Return a JSON compatible plain object that represents the path.
  4934. */
  4935. toObject: function() {
  4936. var result = Gradient.prototype.toObject.call(this);
  4937. _.each(RadialGradient.Properties, function(k) {
  4938. result[k] = this[k];
  4939. }, this);
  4940. result.center = this.center.toObject();
  4941. result.focal = this.focal.toObject();
  4942. return result;
  4943. },
  4944. /**
  4945. * @name Two.RadialGradient#_update
  4946. * @function
  4947. * @private
  4948. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  4949. * @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.
  4950. * @nota-bene Try not to call this method more than once a frame.
  4951. */
  4952. _update: function() {
  4953. if (this._flagRadius || this._flatCenter || this._flagFocal
  4954. || this._flagSpread || this._flagStops) {
  4955. this.trigger(Events.Types.change);
  4956. }
  4957. return this;
  4958. },
  4959. /**
  4960. * @name Two.RadialGradient#flagReset
  4961. * @function
  4962. * @private
  4963. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  4964. */
  4965. flagReset: function() {
  4966. this._flagRadius = this._flagCenter = this._flagFocal = false;
  4967. Gradient.prototype.flagReset.call(this);
  4968. return this;
  4969. }
  4970. });
  4971. RadialGradient.MakeObservable(RadialGradient.prototype);
  4972. var anchor;
  4973. var regex$1 = {
  4974. video: /\.(mp4|webm|ogg)$/i,
  4975. image: /\.(jpe?g|png|gif|tiff|webp)$/i,
  4976. effect: /texture|gradient/i
  4977. };
  4978. if (root$1.document) {
  4979. anchor = document.createElement('a');
  4980. }
  4981. /**
  4982. * @name Two.Texture
  4983. * @class
  4984. * @extends Two.Shape
  4985. * @param {String|HTMLImageElement} [src] - The URL path to an image file or an `<img />` element.
  4986. * @param {Function} [callback] - An optional callback function once the image has been loaded.
  4987. * @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.
  4988. */
  4989. function Texture(src, callback) {
  4990. /**
  4991. * @name Two.Texture#renderer
  4992. * @property {Object}
  4993. * @description Object access to store relevant renderer specific variables. Warning: manipulating this object can create unintended consequences.
  4994. * @nota-bene With the {@link Two.SvgRenderer} you can access the underlying SVG element created via `shape.renderer.elem`.
  4995. */
  4996. this.renderer = {};
  4997. this._renderer.type = 'texture';
  4998. this._renderer.flagOffset = Texture.FlagOffset.bind(this);
  4999. this._renderer.flagScale = Texture.FlagScale.bind(this);
  5000. this.id = Constants.Identifier + Constants.uniqueId();
  5001. this.classList = [];
  5002. /**
  5003. * @name Two.Texture#loaded
  5004. * @property {Boolean} - Shorthand value to determine if image has been loaded into the texture.
  5005. */
  5006. this.loaded = false;
  5007. /**
  5008. * @name Two.Texture#repeat
  5009. * @property {String} - CSS style declaration to tile {@link Two.Path}. Valid values include: `'no-repeat'`, `'repeat'`, `'repeat-x'`, `'repeat-y'`.
  5010. * @see {@link https://www.w3.org/TR/2dcontext/#dom-context-2d-createpattern}
  5011. */
  5012. this.repeat = 'no-repeat';
  5013. /**
  5014. * @name Two.Texture#offset
  5015. * @property {Two.Vector} - A two-component vector describing any pixel offset of the texture when applied to a {@link Two.Path}.
  5016. */
  5017. this.offset = new Vector();
  5018. if (typeof callback === 'function') {
  5019. var loaded = (function() {
  5020. this.unbind(Events.Types.load, loaded);
  5021. if (typeof callback === 'function') {
  5022. callback();
  5023. }
  5024. }).bind(this);
  5025. this.bind(Events.Types.load, loaded);
  5026. }
  5027. /**
  5028. * @name Two.Texture#src
  5029. * @property {String} - The URL path to the image data.
  5030. * @nota-bene This property is ultimately serialized in a {@link Two.Registry} to cache retrieval.
  5031. */
  5032. if (typeof src === 'string') {
  5033. this.src = src;
  5034. } else if (typeof src === 'object') {
  5035. var elemString = Object.prototype.toString.call(src);
  5036. if (
  5037. elemString === '[object HTMLImageElement]' ||
  5038. elemString === '[object HTMLCanvasElement]' ||
  5039. elemString === '[object HTMLVideoElement]' ||
  5040. elemString === '[object Image]'
  5041. ) {
  5042. /**
  5043. * @name Two.Texture#image
  5044. * @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.
  5045. * @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.
  5046. */
  5047. this.image = src;
  5048. }
  5049. }
  5050. this._update();
  5051. }
  5052. _.extend(Texture, {
  5053. /**
  5054. * @name Two.Texture.Properties
  5055. * @property {String[]} - A list of properties that are on every {@link Two.Texture}.
  5056. */
  5057. Properties: [
  5058. 'id',
  5059. 'src',
  5060. 'loaded',
  5061. 'repeat'
  5062. ],
  5063. /**
  5064. * @name Two.Texture.RegularExpressions
  5065. * @property {Object} - A map of compatible DOM Elements categorized by media format.
  5066. */
  5067. RegularExpressions: regex$1,
  5068. /**
  5069. * @name Two.Texture.ImageRegistry
  5070. * @property {Two.Registry} - A canonical listing of image data used in a single session of Two.js.
  5071. * @nota-bene This object is used to cache image data between different textures.
  5072. */
  5073. ImageRegistry: new Registry(),
  5074. /**
  5075. * @name Two.Texture.getAbsoluteURL
  5076. * @property {Function} - Serializes a URL as an absolute path for canonical attribution in {@link Two.ImageRegistry}.
  5077. * @param {String} path
  5078. * @returns {String} - The serialized absolute path.
  5079. */
  5080. getAbsoluteURL: function(path) {
  5081. if (!anchor) {
  5082. // TODO: Fix for headless environments
  5083. return path;
  5084. }
  5085. anchor.href = path;
  5086. return anchor.href;
  5087. },
  5088. /**
  5089. * @name Two.Texture.loadHeadlessBuffer
  5090. * @property {Function} - Loads an image as a buffer in headless environments.
  5091. * @param {Two.Texture} texture - The {@link Two.Texture} to be loaded.
  5092. * @param {Function} loaded - The callback function to be triggered once the image is loaded.
  5093. * @nota-bene - This function uses node's `fs.readFileSync` to spoof the `<img />` loading process in the browser.
  5094. */
  5095. loadHeadlessBuffer: function(texture, loaded) {
  5096. texture.image.onload = loaded;
  5097. texture.image.src = texture.src;
  5098. },
  5099. /**
  5100. * @name Two.Texture.getTag
  5101. * @property {Function} - Retrieves the tag name of an image, video, or canvas node.
  5102. * @param {HTMLImageElement} - The image to infer the tag name from.
  5103. * @returns {String} - Returns the tag name of an image, video, or canvas node.
  5104. */
  5105. getTag: function(image) {
  5106. return (image && image.nodeName && image.nodeName.toLowerCase())
  5107. // Headless environments
  5108. || 'img';
  5109. },
  5110. /**
  5111. * @name Two.Texture.getImage
  5112. * @property {Function} - Convenience function to set {@link Two.Texture#image} properties with canonincal versions set in {@link Two.Texture.ImageRegistry}.
  5113. * @param {String} src - The URL path of the image.
  5114. * @returns {HTMLImageElement} - Returns either a cached version of the image or a new one that is registered in {@link Two.Texture.ImageRegistry}.
  5115. */
  5116. getImage: function(src) {
  5117. var absoluteSrc = Texture.getAbsoluteURL(src);
  5118. if (Texture.ImageRegistry.contains(absoluteSrc)) {
  5119. return Texture.ImageRegistry.get(absoluteSrc);
  5120. }
  5121. var image;
  5122. if (CanvasShim.Image) {
  5123. // TODO: Fix for headless environments
  5124. image = new CanvasShim.Image();
  5125. Renderer$2.Utils.shim(image, 'img');
  5126. } else if (root$1.document) {
  5127. if (regex$1.video.test(absoluteSrc)) {
  5128. image = document.createElement('video');
  5129. } else {
  5130. image = document.createElement('img');
  5131. }
  5132. } else {
  5133. console.warn('Two.js: no prototypical image defined for Two.Texture');
  5134. }
  5135. image.crossOrigin = 'anonymous';
  5136. return image;
  5137. },
  5138. /**
  5139. * @name Two.Register
  5140. * @interface
  5141. * @description A collection of functions to register different types of textures. Used internally by a {@link Two.Texture}.
  5142. */
  5143. Register: {
  5144. canvas: function(texture, callback) {
  5145. texture._src = '#' + texture.id;
  5146. Texture.ImageRegistry.add(texture.src, texture.image);
  5147. if (typeof callback === 'function') {
  5148. callback();
  5149. }
  5150. },
  5151. img: function(texture, callback) {
  5152. var image = texture.image;
  5153. var loaded = function(e) {
  5154. if (!CanvasShim.isHeadless && image.removeEventListener && typeof image.removeEventListener === 'function') {
  5155. image.removeEventListener('load', loaded, false);
  5156. image.removeEventListener('error', error, false);
  5157. }
  5158. if (typeof callback === 'function') {
  5159. callback();
  5160. }
  5161. };
  5162. var error = function(e) {
  5163. if (!CanvasShim.isHeadless && typeof image.removeEventListener === 'function') {
  5164. image.removeEventListener('load', loaded, false);
  5165. image.removeEventListener('error', error, false);
  5166. }
  5167. throw new TwoError('unable to load ' + texture.src);
  5168. };
  5169. if (typeof image.width === 'number' && image.width > 0
  5170. && typeof image.height === 'number' && image.height > 0) {
  5171. loaded();
  5172. } else if (!CanvasShim.isHeadless && typeof image.addEventListener === 'function') {
  5173. image.addEventListener('load', loaded, false);
  5174. image.addEventListener('error', error, false);
  5175. }
  5176. texture._src = Texture.getAbsoluteURL(texture._src);
  5177. if (!CanvasShim.isHeadless && image && image.getAttribute('two-src')) {
  5178. return;
  5179. }
  5180. if (!CanvasShim.isHeadless) {
  5181. image.setAttribute('two-src', texture.src);
  5182. }
  5183. Texture.ImageRegistry.add(texture.src, image);
  5184. if (CanvasShim.isHeadless) {
  5185. Texture.loadHeadlessBuffer(texture, loaded);
  5186. } else {
  5187. texture.image.src = texture.src;
  5188. }
  5189. },
  5190. video: function(texture, callback) {
  5191. if (CanvasShim.isHeadless) {
  5192. throw new TwoError('video textures are not implemented in headless environments.');
  5193. }
  5194. var loaded = function(e) {
  5195. texture.image.removeEventListener('canplaythrough', loaded, false);
  5196. texture.image.removeEventListener('error', error, false);
  5197. texture.image.width = texture.image.videoWidth;
  5198. texture.image.height = texture.image.videoHeight;
  5199. if (typeof callback === 'function') {
  5200. callback();
  5201. }
  5202. };
  5203. var error = function(e) {
  5204. texture.image.removeEventListener('canplaythrough', loaded, false);
  5205. texture.image.removeEventListener('error', error, false);
  5206. throw new TwoError('unable to load ' + texture.src);
  5207. };
  5208. texture._src = Texture.getAbsoluteURL(texture._src);
  5209. if (!texture.image.getAttribute('two-src')) {
  5210. texture.image.setAttribute('two-src', texture.src);
  5211. Texture.ImageRegistry.add(texture.src, texture.image);
  5212. }
  5213. if (texture.image.readyState >= 4) {
  5214. loaded();
  5215. } else {
  5216. texture.image.addEventListener('canplaythrough', loaded, false);
  5217. texture.image.addEventListener('error', error, false);
  5218. texture.image.src = texture.src;
  5219. texture.image.load();
  5220. }
  5221. }
  5222. },
  5223. /**
  5224. * @name Two.Texture.load
  5225. * @function
  5226. * @param {Two.Texture} texture - The texture to load.
  5227. * @param {Function} callback - The function to be called once the texture is loaded.
  5228. */
  5229. load: function(texture, callback) {
  5230. var image = texture.image;
  5231. var tag = Texture.getTag(image);
  5232. if (texture._flagImage) {
  5233. if (/canvas/i.test(tag)) {
  5234. Texture.Register.canvas(texture, callback);
  5235. } else {
  5236. texture._src = (!CanvasShim.isHeadless && image.getAttribute('two-src')) || image.src;
  5237. Texture.Register[tag](texture, callback);
  5238. }
  5239. }
  5240. if (texture._flagSrc) {
  5241. if (!image) {
  5242. image = Texture.getImage(texture.src);
  5243. texture.image = image;
  5244. }
  5245. tag = Texture.getTag(image);
  5246. Texture.Register[tag](texture, callback);
  5247. }
  5248. },
  5249. /**
  5250. * @name Two.Texture.FlagOffset
  5251. * @function
  5252. * @description Cached method to let renderers know `offset` has been updated on a {@link Two.Texture}.
  5253. */
  5254. FlagOffset: function() {
  5255. this._flagOffset = true;
  5256. },
  5257. /**
  5258. * @name Two.Texture.FlagScale
  5259. * @function
  5260. * @description Cached method to let renderers know `scale` has been updated on a {@link Two.Texture}.
  5261. */
  5262. FlagScale: function() {
  5263. this._flagScale = true;
  5264. },
  5265. /**
  5266. * @name Two.Texture.MakeObservable
  5267. * @function
  5268. * @param {Object} object - The object to make observable.
  5269. * @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.
  5270. */
  5271. MakeObservable: function(object) {
  5272. _.each(Texture.Properties, defineGetterSetter, object);
  5273. Object.defineProperty(object, 'image', {
  5274. enumerable: true,
  5275. get: function() {
  5276. return this._image;
  5277. },
  5278. set: function(image) {
  5279. var tag = Texture.getTag(image);
  5280. var index;
  5281. switch (tag) {
  5282. case 'canvas':
  5283. index = '#' + image.id;
  5284. break;
  5285. default:
  5286. index = image.src;
  5287. }
  5288. if (Texture.ImageRegistry.contains(index)) {
  5289. this._image = Texture.ImageRegistry.get(image.src);
  5290. } else {
  5291. this._image = image;
  5292. }
  5293. this._flagImage = true;
  5294. }
  5295. });
  5296. Object.defineProperty(object, 'offset', {
  5297. enumerable: true,
  5298. get: function() {
  5299. return this._offset;
  5300. },
  5301. set: function(v) {
  5302. if (this._offset) {
  5303. this._offset.unbind(Events.Types.change, this._renderer.flagOffset);
  5304. }
  5305. this._offset = v;
  5306. this._offset.bind(Events.Types.change, this._renderer.flagOffset);
  5307. this._flagOffset = true;
  5308. }
  5309. });
  5310. Object.defineProperty(object, 'scale', {
  5311. enumerable: true,
  5312. get: function() {
  5313. return this._scale;
  5314. },
  5315. set: function(v) {
  5316. if (this._scale instanceof Vector) {
  5317. this._scale.unbind(Events.Types.change, this._renderer.flagScale);
  5318. }
  5319. this._scale = v;
  5320. if (this._scale instanceof Vector) {
  5321. this._scale.bind(Events.Types.change, this._renderer.flagScale);
  5322. }
  5323. this._flagScale = true;
  5324. }
  5325. });
  5326. Object.defineProperty(object, 'renderer', {
  5327. enumerable: false,
  5328. get: function() {
  5329. return this._renderer;
  5330. },
  5331. set: function(obj) {
  5332. this._renderer = obj;
  5333. }
  5334. });
  5335. }
  5336. });
  5337. _.extend(Texture.prototype, Events, Shape.prototype, {
  5338. constructor: Texture,
  5339. /**
  5340. * @name Two.Texture#_flagId
  5341. * @private
  5342. * @property {Boolean} - Determines whether the {@link Two.Texture#id} needs updating.
  5343. */
  5344. _flagId: false,
  5345. /**
  5346. * @name Two.Texture#_flagSrc
  5347. * @private
  5348. * @property {Boolean} - Determines whether the {@link Two.Texture#src} needs updating.
  5349. */
  5350. _flagSrc: false,
  5351. /**
  5352. * @name Two.Texture#_flagImage
  5353. * @private
  5354. * @property {Boolean} - Determines whether the {@link Two.Texture#image} needs updating.
  5355. */
  5356. _flagImage: false,
  5357. /**
  5358. * @name Two.Texture#_flagVideo
  5359. * @private
  5360. * @property {Boolean} - Determines whether the {@link Two.Texture#video} needs updating.
  5361. */
  5362. _flagVideo: false,
  5363. /**
  5364. * @name Two.Texture#_flagLoaded
  5365. * @private
  5366. * @property {Boolean} - Determines whether the {@link Two.Texture#loaded} needs updating.
  5367. */
  5368. _flagLoaded: false,
  5369. /**
  5370. * @name Two.Texture#_flagRepeat
  5371. * @private
  5372. * @property {Boolean} - Determines whether the {@link Two.Texture#repeat} needs updating.
  5373. */
  5374. _flagRepeat: false,
  5375. /**
  5376. * @name Two.Texture#_flagOffset
  5377. * @private
  5378. * @property {Boolean} - Determines whether the {@link Two.Texture#offset} needs updating.
  5379. */
  5380. _flagOffset: false,
  5381. /**
  5382. * @name Two.Texture#_flagScale
  5383. * @private
  5384. * @property {Boolean} - Determines whether the {@link Two.Texture#scale} needs updating.
  5385. */
  5386. _flagScale: false,
  5387. /**
  5388. * @name Two.Texture#_id
  5389. * @private
  5390. * @see {@link Two.Texture#id}
  5391. */
  5392. _id: '',
  5393. /**
  5394. * @name Two.Texture#_src
  5395. * @private
  5396. * @see {@link Two.Texture#src}
  5397. */
  5398. _src: '',
  5399. /**
  5400. * @name Two.Texture#_image
  5401. * @private
  5402. * @see {@link Two.Texture#image}
  5403. */
  5404. _image: null,
  5405. /**
  5406. * @name Two.Texture#_loaded
  5407. * @private
  5408. * @see {@link Two.Texture#loaded}
  5409. */
  5410. _loaded: false,
  5411. /**
  5412. * @name Two.Texture#_repeat
  5413. * @private
  5414. * @see {@link Two.Texture#repeat}
  5415. */
  5416. _repeat: 'no-repeat',
  5417. /**
  5418. * @name Two.Texture#_scale
  5419. * @private
  5420. * @see {@link Two.Texture#scale}
  5421. */
  5422. _scale: 1,
  5423. /**
  5424. * @name Two.Texture#_offset
  5425. * @private
  5426. * @see {@link Two.Texture#offset}
  5427. */
  5428. _offset: null,
  5429. /**
  5430. * @name Two.Texture#clone
  5431. * @function
  5432. * @returns {Two.Texture}
  5433. * @description Create a new instance of {@link Two.Texture} with the same properties of the current texture.
  5434. */
  5435. clone: function() {
  5436. var clone = new Texture(this.src);
  5437. clone.repeat = this.repeat;
  5438. clone.offset.copy(this.origin);
  5439. clone.scale = this.scale;
  5440. return clone;
  5441. },
  5442. /**
  5443. * @name Two.Texture#toObject
  5444. * @function
  5445. * @returns {Object}
  5446. * @description Return a JSON compatible plain object that represents the texture.
  5447. */
  5448. toObject: function() {
  5449. return {
  5450. src: this.src,
  5451. // image: this.image,
  5452. repeat: this.repeat,
  5453. origin: this.origin.toObject(),
  5454. scale: typeof this.scale === 'number' ? this.scale : this.scale.toObject()
  5455. };
  5456. },
  5457. /**
  5458. * @name Two.Texture#_update
  5459. * @function
  5460. * @private
  5461. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  5462. * @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.
  5463. * @nota-bene Try not to call this method more than once a frame.
  5464. */
  5465. _update: function() {
  5466. if (this._flagSrc || this._flagImage) {
  5467. this.trigger(Events.Types.change);
  5468. if (this._flagSrc || this._flagImage) {
  5469. this.loaded = false;
  5470. Texture.load(this, (function() {
  5471. this.loaded = true;
  5472. this
  5473. .trigger(Events.Types.change)
  5474. .trigger(Events.Types.load);
  5475. }).bind(this));
  5476. }
  5477. }
  5478. if (this._image && this._image.readyState >= 4) {
  5479. this._flagVideo = true;
  5480. }
  5481. return this;
  5482. },
  5483. /**
  5484. * @name Two.Texture#flagReset
  5485. * @function
  5486. * @private
  5487. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  5488. */
  5489. flagReset: function() {
  5490. this._flagSrc = this._flagImage = this._flagLoaded
  5491. = this._flagVideo = this._flagScale = this._flagOffset = false;
  5492. return this;
  5493. }
  5494. });
  5495. Texture.MakeObservable(Texture.prototype);
  5496. // Constants
  5497. var min$1 = Math.min, max$1 = Math.max,
  5498. ceil = Math.ceil, floor = Math.floor;
  5499. /**
  5500. * @name Two.Path
  5501. * @class
  5502. * @extends Two.Shape
  5503. * @param {Two.Anchor[]} [vertices] - A list of {@link Two.Anchor}s that represent the order and coordinates to construct the rendered shape.
  5504. * @param {Boolean} [closed=false] - Describes whether the shape is closed or open.
  5505. * @param {Boolean} [curved=false] - Describes whether the shape automatically calculates bezier handles for each vertex.
  5506. * @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.
  5507. * @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.
  5508. */
  5509. function Path(vertices, closed, curved, manual) {
  5510. Shape.call(this);
  5511. this._renderer.type = 'path';
  5512. this._renderer.flagVertices = Path.FlagVertices.bind(this);
  5513. this._renderer.bindVertices = Path.BindVertices.bind(this);
  5514. this._renderer.unbindVertices = Path.UnbindVertices.bind(this);
  5515. this._renderer.flagFill = Path.FlagFill.bind(this);
  5516. this._renderer.flagStroke = Path.FlagStroke.bind(this);
  5517. this._renderer.vertices = [];
  5518. this._renderer.collection = [];
  5519. /**
  5520. * @name Two.Path#closed
  5521. * @property {Boolean} - Determines whether a final line is drawn between the final point in the `vertices` array and the first point.
  5522. */
  5523. this._closed = !!closed;
  5524. /**
  5525. * @name Two.Path#curved
  5526. * @property {Boolean} - When the path is `automatic = true` this boolean determines whether the lines between the points are curved or not.
  5527. */
  5528. this._curved = !!curved;
  5529. /**
  5530. * @name Two.Path#beginning
  5531. * @property {Number} - Number between zero and one to state the beginning of where the path is rendered.
  5532. * @description {@link Two.Path#beginning} is a percentage value that represents at what percentage into the path should the renderer start drawing.
  5533. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Path#ending}.
  5534. */
  5535. this.beginning = 0;
  5536. /**
  5537. * @name Two.Path#ending
  5538. * @property {Number} - Number between zero and one to state the ending of where the path is rendered.
  5539. * @description {@link Two.Path#ending} is a percentage value that represents at what percentage into the path should the renderer start drawing.
  5540. * @nota-bene This is great for animating in and out stroked paths in conjunction with {@link Two.Path#beginning}.
  5541. */
  5542. this.ending = 1;
  5543. // Style properties
  5544. /**
  5545. * @name Two.Path#fill
  5546. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the path should be filled in with.
  5547. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  5548. */
  5549. this.fill = '#fff';
  5550. /**
  5551. * @name Two.Path#stroke
  5552. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the path should be outlined in with.
  5553. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  5554. */
  5555. this.stroke = '#000';
  5556. /**
  5557. * @name Two.Path#linewidth
  5558. * @property {Number} - The thickness in pixels of the stroke.
  5559. */
  5560. this.linewidth = 1.0;
  5561. /**
  5562. * @name Two.Path#opacity
  5563. * @property {Number} - The opaqueness of the path.
  5564. * @nota-bene Can be used in conjunction with CSS Colors that have an alpha value.
  5565. */
  5566. this.opacity = 1.0;
  5567. /**
  5568. * @name Two.Path#className
  5569. * @property {String} - A class to be applied to the element to be compatible with CSS styling.
  5570. * @nota-bene Only available for the SVG renderer.
  5571. */
  5572. this.className = '';
  5573. /**
  5574. * @name Two.Path#visible
  5575. * @property {Boolean} - Display the path or not.
  5576. * @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.
  5577. */
  5578. this.visible = true;
  5579. /**
  5580. * @name Two.Path#cap
  5581. * @property {String}
  5582. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty}
  5583. */
  5584. this.cap = 'butt'; // Default of Adobe Illustrator
  5585. /**
  5586. * @name Two.Path#join
  5587. * @property {String}
  5588. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty}
  5589. */
  5590. this.join = 'miter'; // Default of Adobe Illustrator
  5591. /**
  5592. * @name Two.Path#miter
  5593. * @property {String}
  5594. * @see {@link https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty}
  5595. */
  5596. this.miter = 4; // Default of Adobe Illustrator
  5597. /**
  5598. * @name Two.Path#vertices
  5599. * @property {Two.Anchor[]} - An ordered list of anchor points for rendering the path.
  5600. * @description A list of {@link Two.Anchor} objects that consist of what form the path takes.
  5601. * @nota-bene The array when manipulating is actually a {@link Two.Collection}.
  5602. */
  5603. this.vertices = vertices;
  5604. /**
  5605. * @name Two.Path#automatic
  5606. * @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.
  5607. */
  5608. this.automatic = !manual;
  5609. /**
  5610. * @name Two.Path#dashes
  5611. * @property {Number[]} - Array of numbers. Odd indices represent dash length. Even indices represent dash space.
  5612. * @description A list of numbers that represent the repeated dash length and dash space applied to the stroke of the text.
  5613. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray} for more information on the SVG stroke-dasharray attribute.
  5614. */
  5615. this.dashes = [];
  5616. /**
  5617. * @name Two.Path#dashes#offset
  5618. * @property {Number} - A number in pixels to offset {@link Two.Path#dashes} display.
  5619. */
  5620. this.dashes.offset = 0;
  5621. }
  5622. _.extend(Path, {
  5623. /**
  5624. * @name Two.Path.Properties
  5625. * @property {String[]} - A list of properties that are on every {@link Two.Path}.
  5626. */
  5627. Properties: [
  5628. 'fill',
  5629. 'stroke',
  5630. 'linewidth',
  5631. 'opacity',
  5632. 'visible',
  5633. 'cap',
  5634. 'join',
  5635. 'miter',
  5636. 'closed',
  5637. 'curved',
  5638. 'automatic',
  5639. 'beginning',
  5640. 'ending'
  5641. ],
  5642. Utils: {
  5643. getCurveLength: getCurveLength
  5644. },
  5645. /**
  5646. * @name Two.Path.FlagVertices
  5647. * @function
  5648. * @description Cached method to let renderers know vertices have been updated on a {@link Two.Path}.
  5649. */
  5650. FlagVertices: function() {
  5651. this._flagVertices = true;
  5652. this._flagLength = true;
  5653. if (this.parent) {
  5654. this.parent._flagLength = true;
  5655. }
  5656. },
  5657. /**
  5658. * @name Two.Path.BindVertices
  5659. * @function
  5660. * @description Cached method to let {@link Two.Path} know vertices have been added to the instance.
  5661. */
  5662. BindVertices: function(items) {
  5663. // This function is called a lot
  5664. // when importing a large SVG
  5665. var i = items.length;
  5666. while (i--) {
  5667. items[i].bind(Events.Types.change, this._renderer.flagVertices);
  5668. }
  5669. this._renderer.flagVertices();
  5670. },
  5671. /**
  5672. * @name Two.Path.UnbindVertices
  5673. * @function
  5674. * @description Cached method to let {@link Two.Path} know vertices have been removed from the instance.
  5675. */
  5676. UnbindVertices: function(items) {
  5677. var i = items.length;
  5678. while (i--) {
  5679. items[i].unbind(Events.Types.change, this._renderer.flagVertices);
  5680. }
  5681. this._renderer.flagVertices();
  5682. },
  5683. /**
  5684. * @name Two.Path.FlagFill
  5685. * @function
  5686. * @description Cached method to let {@link Two.Path} know the fill has changed.
  5687. */
  5688. FlagFill: function() {
  5689. this._flagFill = true;
  5690. },
  5691. /**
  5692. * @name Two.Path.FlagFill
  5693. * @function
  5694. * @description Cached method to let {@link Two.Path} know the stroke has changed.
  5695. */
  5696. FlagStroke: function() {
  5697. this._flagStroke = true;
  5698. },
  5699. /**
  5700. * @name Two.Path.MakeObservable
  5701. * @function
  5702. * @param {Object} object - The object to make observable.
  5703. * @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.
  5704. */
  5705. MakeObservable: function(object) {
  5706. Shape.MakeObservable(object);
  5707. // Only the 7 defined properties are flagged like this. The subsequent
  5708. // properties behave differently and need to be hand written.
  5709. _.each(Path.Properties.slice(2, 8), defineGetterSetter, object);
  5710. Object.defineProperty(object, 'fill', {
  5711. enumerable: true,
  5712. get: function() {
  5713. return this._fill;
  5714. },
  5715. set: function(f) {
  5716. if (this._fill instanceof Gradient
  5717. || this._fill instanceof LinearGradient
  5718. || this._fill instanceof RadialGradient
  5719. || this._fill instanceof Texture) {
  5720. this._fill.unbind(Events.Types.change, this._renderer.flagFill);
  5721. }
  5722. this._fill = f;
  5723. this._flagFill = true;
  5724. if (this._fill instanceof Gradient
  5725. || this._fill instanceof LinearGradient
  5726. || this._fill instanceof RadialGradient
  5727. || this._fill instanceof Texture) {
  5728. this._fill.bind(Events.Types.change, this._renderer.flagFill);
  5729. }
  5730. }
  5731. });
  5732. Object.defineProperty(object, 'stroke', {
  5733. enumerable: true,
  5734. get: function() {
  5735. return this._stroke;
  5736. },
  5737. set: function(f) {
  5738. if (this._stroke instanceof Gradient
  5739. || this._stroke instanceof LinearGradient
  5740. || this._stroke instanceof RadialGradient
  5741. || this._stroke instanceof Texture) {
  5742. this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
  5743. }
  5744. this._stroke = f;
  5745. this._flagStroke = true;
  5746. if (this._stroke instanceof Gradient
  5747. || this._stroke instanceof LinearGradient
  5748. || this._stroke instanceof RadialGradient
  5749. || this._stroke instanceof Texture) {
  5750. this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
  5751. }
  5752. }
  5753. });
  5754. /**
  5755. * @name Two.Path#length
  5756. * @property {Number} - The sum of distances between all {@link Two.Path#vertices}.
  5757. */
  5758. Object.defineProperty(object, 'length', {
  5759. get: function() {
  5760. if (this._flagLength) {
  5761. this._updateLength();
  5762. }
  5763. return this._length;
  5764. }
  5765. });
  5766. Object.defineProperty(object, 'closed', {
  5767. enumerable: true,
  5768. get: function() {
  5769. return this._closed;
  5770. },
  5771. set: function(v) {
  5772. this._closed = !!v;
  5773. this._flagVertices = true;
  5774. }
  5775. });
  5776. Object.defineProperty(object, 'curved', {
  5777. enumerable: true,
  5778. get: function() {
  5779. return this._curved;
  5780. },
  5781. set: function(v) {
  5782. this._curved = !!v;
  5783. this._flagVertices = true;
  5784. }
  5785. });
  5786. Object.defineProperty(object, 'automatic', {
  5787. enumerable: true,
  5788. get: function() {
  5789. return this._automatic;
  5790. },
  5791. set: function(v) {
  5792. if (v === this._automatic) {
  5793. return;
  5794. }
  5795. this._automatic = !!v;
  5796. var method = this._automatic ? 'ignore' : 'listen';
  5797. _.each(this.vertices, function(v) {
  5798. v[method]();
  5799. });
  5800. }
  5801. });
  5802. Object.defineProperty(object, 'beginning', {
  5803. enumerable: true,
  5804. get: function() {
  5805. return this._beginning;
  5806. },
  5807. set: function(v) {
  5808. this._beginning = v;
  5809. this._flagVertices = true;
  5810. }
  5811. });
  5812. Object.defineProperty(object, 'ending', {
  5813. enumerable: true,
  5814. get: function() {
  5815. return this._ending;
  5816. },
  5817. set: function(v) {
  5818. this._ending = v;
  5819. this._flagVertices = true;
  5820. }
  5821. });
  5822. Object.defineProperty(object, 'vertices', {
  5823. enumerable: true,
  5824. get: function() {
  5825. return this._collection;
  5826. },
  5827. set: function(vertices) {
  5828. var bindVertices = this._renderer.bindVertices;
  5829. var unbindVertices = this._renderer.unbindVertices;
  5830. // Remove previous listeners
  5831. if (this._collection) {
  5832. this._collection
  5833. .unbind(Events.Types.insert, bindVertices)
  5834. .unbind(Events.Types.remove, unbindVertices);
  5835. }
  5836. // Create new Collection with copy of vertices
  5837. if (vertices instanceof Collection) {
  5838. this._collection = vertices;
  5839. } else {
  5840. this._collection = new Collection(vertices || []);
  5841. }
  5842. // Listen for Collection changes and bind / unbind
  5843. this._collection
  5844. .bind(Events.Types.insert, bindVertices)
  5845. .bind(Events.Types.remove, unbindVertices);
  5846. // Bind Initial Vertices
  5847. bindVertices(this._collection);
  5848. }
  5849. });
  5850. /**
  5851. * @name Two.Path#mask
  5852. * @property {Two.Shape} - The shape whose alpha property becomes a clipping area for the path.
  5853. * @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}.
  5854. */
  5855. Object.defineProperty(object, 'mask', {
  5856. enumerable: true,
  5857. get: function() {
  5858. return this._mask;
  5859. },
  5860. set: function(v) {
  5861. this._mask = v;
  5862. this._flagMask = true;
  5863. if (!v.clip) {
  5864. v.clip = true;
  5865. }
  5866. }
  5867. });
  5868. /**
  5869. * @name Two.Path#clip
  5870. * @property {Boolean} - Tells Two.js renderer if this object represents a mask for another object (or not).
  5871. */
  5872. Object.defineProperty(object, 'clip', {
  5873. enumerable: true,
  5874. get: function() {
  5875. return this._clip;
  5876. },
  5877. set: function(v) {
  5878. this._clip = v;
  5879. this._flagClip = true;
  5880. }
  5881. });
  5882. Object.defineProperty(object, 'dashes', {
  5883. enumerable: true,
  5884. get: function() {
  5885. return this._dashes;
  5886. },
  5887. set: function(v) {
  5888. if (typeof v.offset !== 'number') {
  5889. v.offset = this._dashes.offset || 0;
  5890. }
  5891. this._dashes = v;
  5892. }
  5893. });
  5894. }
  5895. });
  5896. _.extend(Path.prototype, Shape.prototype, {
  5897. constructor: Path,
  5898. // Flags
  5899. // http://en.wikipedia.org/wiki/Flag
  5900. /**
  5901. * @name Two.Path#_flagVertices
  5902. * @private
  5903. * @property {Boolean} - Determines whether the {@link Two.Path#vertices} need updating.
  5904. */
  5905. _flagVertices: true,
  5906. /**
  5907. * @name Two.Path#_flagLength
  5908. * @private
  5909. * @property {Boolean} - Determines whether the {@link Two.Path#length} needs updating.
  5910. */
  5911. _flagLength: true,
  5912. /**
  5913. * @name Two.Path#_flagFill
  5914. * @private
  5915. * @property {Boolean} - Determines whether the {@link Two.Path#fill} needs updating.
  5916. */
  5917. _flagFill: true,
  5918. /**
  5919. * @name Two.Path#_flagStroke
  5920. * @private
  5921. * @property {Boolean} - Determines whether the {@link Two.Path#stroke} needs updating.
  5922. */
  5923. _flagStroke: true,
  5924. /**
  5925. * @name Two.Path#_flagLinewidth
  5926. * @private
  5927. * @property {Boolean} - Determines whether the {@link Two.Path#linewidth} needs updating.
  5928. */
  5929. _flagLinewidth: true,
  5930. /**
  5931. * @name Two.Path#_flagOpacity
  5932. * @private
  5933. * @property {Boolean} - Determines whether the {@link Two.Path#opacity} needs updating.
  5934. */
  5935. _flagOpacity: true,
  5936. /**
  5937. * @name Two.Path#_flagVisible
  5938. * @private
  5939. * @property {Boolean} - Determines whether the {@link Two.Path#visible} needs updating.
  5940. */
  5941. _flagVisible: true,
  5942. /**
  5943. * @name Two.Path#_flagCap
  5944. * @private
  5945. * @property {Boolean} - Determines whether the {@link Two.Path#cap} needs updating.
  5946. */
  5947. _flagCap: true,
  5948. /**
  5949. * @name Two.Path#_flagJoin
  5950. * @private
  5951. * @property {Boolean} - Determines whether the {@link Two.Path#join} needs updating.
  5952. */
  5953. _flagJoin: true,
  5954. /**
  5955. * @name Two.Path#_flagMiter
  5956. * @private
  5957. * @property {Boolean} - Determines whether the {@link Two.Path#miter} needs updating.
  5958. */
  5959. _flagMiter: true,
  5960. /**
  5961. * @name Two.Path#_flagMask
  5962. * @private
  5963. * @property {Boolean} - Determines whether the {@link Two.Path#mask} needs updating.
  5964. */
  5965. _flagMask: false,
  5966. /**
  5967. * @name Two.Path#_flagClip
  5968. * @private
  5969. * @property {Boolean} - Determines whether the {@link Two.Path#clip} needs updating.
  5970. */
  5971. _flagClip: false,
  5972. // Underlying Properties
  5973. /**
  5974. * @name Two.Path#_length
  5975. * @private
  5976. * @see {@link Two.Path#length}
  5977. */
  5978. _length: 0,
  5979. /**
  5980. * @name Two.Path#_fill
  5981. * @private
  5982. * @see {@link Two.Path#fill}
  5983. */
  5984. _fill: '#fff',
  5985. /**
  5986. * @name Two.Path#_stroke
  5987. * @private
  5988. * @see {@link Two.Path#stroke}
  5989. */
  5990. _stroke: '#000',
  5991. /**
  5992. * @name Two.Path#_linewidth
  5993. * @private
  5994. * @see {@link Two.Path#linewidth}
  5995. */
  5996. _linewidth: 1.0,
  5997. /**
  5998. * @name Two.Path#_opacity
  5999. * @private
  6000. * @see {@link Two.Path#opacity}
  6001. */
  6002. _opacity: 1.0,
  6003. /**
  6004. * @name Two.Path#_visible
  6005. * @private
  6006. * @see {@link Two.Path#visible}
  6007. */
  6008. _visible: true,
  6009. /**
  6010. * @name Two.Path#_cap
  6011. * @private
  6012. * @see {@link Two.Path#cap}
  6013. */
  6014. _cap: 'round',
  6015. /**
  6016. * @name Two.Path#_join
  6017. * @private
  6018. * @see {@link Two.Path#join}
  6019. */
  6020. _join: 'round',
  6021. /**
  6022. * @name Two.Path#_miter
  6023. * @private
  6024. * @see {@link Two.Path#miter}
  6025. */
  6026. _miter: 4,
  6027. /**
  6028. * @name Two.Path#_closed
  6029. * @private
  6030. * @see {@link Two.Path#closed}
  6031. */
  6032. _closed: true,
  6033. /**
  6034. * @name Two.Path#_curved
  6035. * @private
  6036. * @see {@link Two.Path#curved}
  6037. */
  6038. _curved: false,
  6039. /**
  6040. * @name Two.Path#_automatic
  6041. * @private
  6042. * @see {@link Two.Path#automatic}
  6043. */
  6044. _automatic: true,
  6045. /**
  6046. * @name Two.Path#_beginning
  6047. * @private
  6048. * @see {@link Two.Path#beginning}
  6049. */
  6050. _beginning: 0,
  6051. /**
  6052. * @name Two.Path#_ending
  6053. * @private
  6054. * @see {@link Two.Path#ending}
  6055. */
  6056. _ending: 1.0,
  6057. /**
  6058. * @name Two.Path#_mask
  6059. * @private
  6060. * @see {@link Two.Path#mask}
  6061. */
  6062. _mask: null,
  6063. /**
  6064. * @name Two.Path#_clip
  6065. * @private
  6066. * @see {@link Two.Path#clip}
  6067. */
  6068. _clip: false,
  6069. /**
  6070. * @name Two.Path#_dashes
  6071. * @private
  6072. * @see {@link Two.Path#dashes}
  6073. */
  6074. _dashes: [],
  6075. /**
  6076. * @name Two.Path#clone
  6077. * @function
  6078. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  6079. * @returns {Two.Path}
  6080. * @description Create a new instance of {@link Two.Path} with the same properties of the current path.
  6081. */
  6082. clone: function(parent) {
  6083. var clone = new Path();
  6084. for (var j = 0; j < this.vertices.length; j++) {
  6085. clone.vertices.push(this.vertices[j].clone());
  6086. }
  6087. for (var i = 0; i < Path.Properties.length; i++) {
  6088. var k = Path.Properties[i];
  6089. clone[k] = this[k];
  6090. }
  6091. clone.className = this.className;
  6092. clone.translation.copy(this.translation);
  6093. clone.rotation = this.rotation;
  6094. clone.scale = this.scale;
  6095. clone.skewX = this.skewX;
  6096. clone.skewY = this.skewY;
  6097. if (this.matrix.manual) {
  6098. clone.matrix.copy(this.matrix);
  6099. }
  6100. if (parent) {
  6101. parent.add(clone);
  6102. }
  6103. return clone._update();
  6104. },
  6105. /**
  6106. * @name Two.Path#toObject
  6107. * @function
  6108. * @returns {Object}
  6109. * @description Return a JSON compatible plain object that represents the path.
  6110. */
  6111. toObject: function() {
  6112. var result = {
  6113. vertices: this.vertices.map(function(v) {
  6114. return v.toObject();
  6115. })
  6116. };
  6117. _.each(Path.Properties, function(k) {
  6118. result[k] = this[k];
  6119. }, this);
  6120. result.className = this.className;
  6121. result.translation = this.translation.toObject();
  6122. result.rotation = this.rotation;
  6123. result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale;
  6124. result.skewX = this.skewX;
  6125. result.skewY = this.skewY;
  6126. if (this.matrix.manual) {
  6127. result.matrix = this.matrix.toObject();
  6128. }
  6129. return result;
  6130. },
  6131. /**
  6132. * @name Two.Path#noFill
  6133. * @function
  6134. * @description Short hand method to set fill to `transparent`.
  6135. */
  6136. noFill: function() {
  6137. this.fill = 'transparent';
  6138. return this;
  6139. },
  6140. /**
  6141. * @name Two.Path#noStroke
  6142. * @function
  6143. * @description Short hand method to set stroke to `transparent`.
  6144. */
  6145. noStroke: function() {
  6146. this.stroke = undefined;
  6147. return this;
  6148. },
  6149. /**
  6150. * @name Two.Path#corner
  6151. * @function
  6152. * @description Orient the vertices of the shape to the upper left-hand corner of the path.
  6153. */
  6154. corner: function() {
  6155. var rect = this.getBoundingClientRect(true);
  6156. var hw = rect.width / 2;
  6157. var hh = rect.height / 2;
  6158. var cx = rect.left + rect.width / 2;
  6159. var cy = rect.top + rect.height / 2;
  6160. for (var i = 0; i < this.vertices.length; i++) {
  6161. var v = this.vertices[i];
  6162. v.x -= cx;
  6163. v.y -= cy;
  6164. v.x += hw;
  6165. v.y += hh;
  6166. }
  6167. return this;
  6168. },
  6169. /**
  6170. * @name Two.Path#center
  6171. * @function
  6172. * @description Orient the vertices of the shape to the center of the path.
  6173. */
  6174. center: function() {
  6175. var rect = this.getBoundingClientRect(true);
  6176. var cx = rect.left + rect.width / 2 - this.translation.x;
  6177. var cy = rect.top + rect.height / 2 - this.translation.y;
  6178. for (var i = 0; i < this.vertices.length; i++) {
  6179. var v = this.vertices[i];
  6180. v.x -= cx;
  6181. v.y -= cy;
  6182. }
  6183. return this;
  6184. },
  6185. /**
  6186. * @name Two.Path#remove
  6187. * @function
  6188. * @description Remove self from the scene / parent.
  6189. */
  6190. remove: function() {
  6191. if (!this.parent) {
  6192. return this;
  6193. }
  6194. this.parent.remove(this);
  6195. return this;
  6196. },
  6197. /**
  6198. * @name Two.Path#getBoundingClientRect
  6199. * @function
  6200. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  6201. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  6202. * @description Return an object with top, left, right, bottom, width, and height parameters of the path.
  6203. */
  6204. getBoundingClientRect: function(shallow) {
  6205. var matrix, border, l, i, v0, v1, c0x, c0y, c1x, c1y, a, b, c, d;
  6206. var left = Infinity, right = -Infinity,
  6207. top = Infinity, bottom = -Infinity;
  6208. // TODO: Update this to not __always__ update. Just when it needs to.
  6209. this._update(true);
  6210. matrix = shallow ? this._matrix : getComputedMatrix(this);
  6211. border = (this.linewidth || 0) / 2;
  6212. l = this._renderer.vertices.length;
  6213. if (l <= 0) {
  6214. return {
  6215. width: 0,
  6216. height: 0
  6217. };
  6218. }
  6219. for (i = 0; i < l; i++) {
  6220. v1 = this._renderer.vertices[i];
  6221. // If i = 0, then this "wraps around" to the last vertex. Otherwise, it's the previous vertex.
  6222. // This is important for handling cyclic paths.
  6223. v0 = this._renderer.vertices[(i + l - 1) % l];
  6224. if (v0.controls && v1.controls) {
  6225. c0x = v0.controls.right.x;
  6226. c0y = v0.controls.right.y;
  6227. if (v0.relative) {
  6228. c0x += v0.x;
  6229. c0y += v0.y;
  6230. }
  6231. c1x = v1.controls.left.x;
  6232. c1y = v1.controls.left.y;
  6233. if (v1.relative) {
  6234. c1x += v1.x;
  6235. c1y += v1.y;
  6236. }
  6237. var bb = getCurveBoundingBox(v0.x, v0.y,
  6238. c0x, c0y, c1x, c1y, v1.x, v1.y);
  6239. top = min$1(bb.min.y - border, top);
  6240. left = min$1(bb.min.x - border, left);
  6241. right = max$1(bb.max.x + border, right);
  6242. bottom = max$1(bb.max.y + border, bottom);
  6243. } else {
  6244. if (i <= 1) {
  6245. top = min$1(v0.y - border, top);
  6246. left = min$1(v0.x - border, left);
  6247. right = max$1(v0.x + border, right);
  6248. bottom = max$1(v0.y + border, bottom);
  6249. }
  6250. top = min$1(v1.y - border, top);
  6251. left = min$1(v1.x - border, left);
  6252. right = max$1(v1.x + border, right);
  6253. bottom = max$1(v1.y + border, bottom);
  6254. }
  6255. }
  6256. a = matrix.multiply(left, top, 1);
  6257. b = matrix.multiply(left, bottom, 1);
  6258. c = matrix.multiply(right, top, 1);
  6259. d = matrix.multiply(right, bottom, 1);
  6260. top = min$1(a.y, b.y, c.y, d.y);
  6261. left = min$1(a.x, b.x, c.x, d.x);
  6262. right = max$1(a.x, b.x, c.x, d.x);
  6263. bottom = max$1(a.y, b.y, c.y, d.y);
  6264. return {
  6265. top: top,
  6266. left: left,
  6267. right: right,
  6268. bottom: bottom,
  6269. width: right - left,
  6270. height: bottom - top
  6271. };
  6272. },
  6273. /**
  6274. * @name Two.Path#getPointAt
  6275. * @function
  6276. * @param {Boolean} t - Percentage value describing where on the Two.Path to estimate and assign coordinate values.
  6277. * @param {Two.Vector} [obj=undefined] - Object to apply calculated x, y to. If none available returns new Object.
  6278. * @returns {Object}
  6279. * @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.
  6280. */
  6281. getPointAt: function(t, obj) {
  6282. var ia, ib, result;
  6283. var x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right;
  6284. var target = this.length * Math.min(Math.max(t, 0), 1);
  6285. var length = this.vertices.length;
  6286. var last = length - 1;
  6287. var a = null;
  6288. var b = null;
  6289. for (var i = 0, l = this._lengths.length, sum = 0; i < l; i++) {
  6290. if (sum + this._lengths[i] >= target) {
  6291. if (this._closed) {
  6292. ia = mod(i, length);
  6293. ib = mod(i - 1, length);
  6294. if (i === 0) {
  6295. ia = ib;
  6296. ib = i;
  6297. }
  6298. } else {
  6299. ia = i;
  6300. ib = Math.min(Math.max(i - 1, 0), last);
  6301. }
  6302. a = this.vertices[ia];
  6303. b = this.vertices[ib];
  6304. target -= sum;
  6305. if (this._lengths[i] !== 0) {
  6306. t = target / this._lengths[i];
  6307. } else {
  6308. t = 0;
  6309. }
  6310. break;
  6311. }
  6312. sum += this._lengths[i];
  6313. }
  6314. if (a === null || b === null) {
  6315. return null;
  6316. }
  6317. if (!a) {
  6318. return b;
  6319. } else if (!b) {
  6320. return a;
  6321. }
  6322. right = b.controls && b.controls.right;
  6323. left = a.controls && a.controls.left;
  6324. x1 = b.x;
  6325. y1 = b.y;
  6326. x2 = (right || b).x;
  6327. y2 = (right || b).y;
  6328. x3 = (left || a).x;
  6329. y3 = (left || a).y;
  6330. x4 = a.x;
  6331. y4 = a.y;
  6332. if (right && b.relative) {
  6333. x2 += b.x;
  6334. y2 += b.y;
  6335. }
  6336. if (left && a.relative) {
  6337. x3 += a.x;
  6338. y3 += a.y;
  6339. }
  6340. x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
  6341. y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
  6342. // Higher order points for control calculation.
  6343. var t1x = lerp(x1, x2, t);
  6344. var t1y = lerp(y1, y2, t);
  6345. var t2x = lerp(x2, x3, t);
  6346. var t2y = lerp(y2, y3, t);
  6347. var t3x = lerp(x3, x4, t);
  6348. var t3y = lerp(y3, y4, t);
  6349. // Calculate the returned points control points.
  6350. var brx = lerp(t1x, t2x, t);
  6351. var bry = lerp(t1y, t2y, t);
  6352. var alx = lerp(t2x, t3x, t);
  6353. var aly = lerp(t2y, t3y, t);
  6354. if (_.isObject(obj)) {
  6355. obj.x = x;
  6356. obj.y = y;
  6357. if (!_.isObject(obj.controls)) {
  6358. Anchor.AppendCurveProperties(obj);
  6359. }
  6360. obj.controls.left.x = brx;
  6361. obj.controls.left.y = bry;
  6362. obj.controls.right.x = alx;
  6363. obj.controls.right.y = aly;
  6364. if (!typeof obj.relative === 'boolean' || obj.relative) {
  6365. obj.controls.left.x -= x;
  6366. obj.controls.left.y -= y;
  6367. obj.controls.right.x -= x;
  6368. obj.controls.right.y -= y;
  6369. }
  6370. obj.t = t;
  6371. return obj;
  6372. }
  6373. result = new Anchor(
  6374. x, y, brx - x, bry - y, alx - x, aly - y,
  6375. this._curved ? Commands.curve : Commands.line
  6376. );
  6377. result.t = t;
  6378. return result;
  6379. },
  6380. /**
  6381. * @name Two.Path#plot
  6382. * @function
  6383. * @description Based on closed / curved and sorting of vertices plot where all points should be and where the respective handles should be too.
  6384. * @nota-bene While this method is public it is internally called by {@link Two.Path#_update} when `automatic = true`.
  6385. */
  6386. plot: function() {
  6387. if (this.curved) {
  6388. getCurveFromPoints(this._collection, this.closed);
  6389. return this;
  6390. }
  6391. for (var i = 0; i < this._collection.length; i++) {
  6392. this._collection[i].command = i === 0 ? Commands.move : Commands.line;
  6393. }
  6394. return this;
  6395. },
  6396. /**
  6397. * @name Two.Path#subdivide
  6398. * @function
  6399. * @param {Number} limit - How many times to recurse subdivisions.
  6400. * @description Insert a {@link Two.Anchor} at the midpoint between every item in {@link Two.Path#vertices}.
  6401. */
  6402. subdivide: function(limit) {
  6403. //TODO: DRYness (function below)
  6404. this._update();
  6405. var last = this.vertices.length - 1;
  6406. var b = this.vertices[last];
  6407. var closed = this._closed || this.vertices[last]._command === Commands.close;
  6408. var points = [];
  6409. _.each(this.vertices, function(a, i) {
  6410. if (i <= 0 && !closed) {
  6411. b = a;
  6412. return;
  6413. }
  6414. if (a.command === Commands.move) {
  6415. points.push(new Anchor(b.x, b.y));
  6416. if (i > 0) {
  6417. points[points.length - 1].command = Commands.line;
  6418. }
  6419. b = a;
  6420. return;
  6421. }
  6422. var verts = getSubdivisions(a, b, limit);
  6423. points = points.concat(verts);
  6424. // Assign commands to all the verts
  6425. _.each(verts, function(v, i) {
  6426. if (i <= 0 && b.command === Commands.move) {
  6427. v.command = Commands.move;
  6428. } else {
  6429. v.command = Commands.line;
  6430. }
  6431. });
  6432. if (i >= last) {
  6433. // TODO: Add check if the two vectors in question are the same values.
  6434. if (this._closed && this._automatic) {
  6435. b = a;
  6436. verts = getSubdivisions(a, b, limit);
  6437. points = points.concat(verts);
  6438. // Assign commands to all the verts
  6439. _.each(verts, function(v, i) {
  6440. if (i <= 0 && b.command === Commands.move) {
  6441. v.command = Commands.move;
  6442. } else {
  6443. v.command = Commands.line;
  6444. }
  6445. });
  6446. } else if (closed) {
  6447. points.push(new Anchor(a.x, a.y));
  6448. }
  6449. points[points.length - 1].command = closed
  6450. ? Commands.close : Commands.line;
  6451. }
  6452. b = a;
  6453. }, this);
  6454. this._automatic = false;
  6455. this._curved = false;
  6456. this.vertices = points;
  6457. return this;
  6458. },
  6459. /**
  6460. * @name Two.Path#_updateLength
  6461. * @function
  6462. * @private
  6463. * @param {Number} [limit=] -
  6464. * @param {Boolean} [silent=false] - If set to `true` then the path isn't updated before calculation. Useful for internal use.
  6465. * @description Recalculate the {@link Two.Path#length} value.
  6466. */
  6467. _updateLength: function(limit, silent) {
  6468. //TODO: DRYness (function above)
  6469. if (!silent) {
  6470. this._update();
  6471. }
  6472. var length = this.vertices.length;
  6473. var last = length - 1;
  6474. var b = this.vertices[last];
  6475. var closed = false;//this._closed || this.vertices[last]._command === Commands.close;
  6476. var sum = 0;
  6477. if (typeof this._lengths === 'undefined') {
  6478. this._lengths = [];
  6479. }
  6480. _.each(this.vertices, function(a, i) {
  6481. if ((i <= 0 && !closed) || a.command === Commands.move) {
  6482. b = a;
  6483. this._lengths[i] = 0;
  6484. return;
  6485. }
  6486. this._lengths[i] = getCurveLength(a, b, limit);
  6487. sum += this._lengths[i];
  6488. if (i >= last && closed) {
  6489. b = this.vertices[(i + 1) % length];
  6490. this._lengths[i + 1] = getCurveLength(a, b, limit);
  6491. sum += this._lengths[i + 1];
  6492. }
  6493. b = a;
  6494. }, this);
  6495. this._length = sum;
  6496. this._flagLength = false;
  6497. return this;
  6498. },
  6499. /**
  6500. * @name Two.Path#_update
  6501. * @function
  6502. * @private
  6503. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  6504. * @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.
  6505. * @nota-bene Try not to call this method more than once a frame.
  6506. */
  6507. _update: function() {
  6508. if (this._flagVertices) {
  6509. if (this._automatic) {
  6510. this.plot();
  6511. }
  6512. if (this._flagLength) {
  6513. this._updateLength(undefined, true);
  6514. }
  6515. var l = this._collection.length;
  6516. var closed = this._closed;
  6517. var beginning = Math.min(this._beginning, this._ending);
  6518. var ending = Math.max(this._beginning, this._ending);
  6519. var bid = getIdByLength(this, beginning * this._length);
  6520. var eid = getIdByLength(this, ending * this._length);
  6521. var low = ceil(bid);
  6522. var high = floor(eid);
  6523. var left, right, prev, next, v;
  6524. this._renderer.vertices.length = 0;
  6525. for (var i = 0; i < l; i++) {
  6526. if (this._renderer.collection.length <= i) {
  6527. // Expected to be `relative` anchor points.
  6528. this._renderer.collection.push(new Anchor());
  6529. }
  6530. if (i > high && !right) {
  6531. v = this._renderer.collection[i];
  6532. v.copy(this._collection[i]);
  6533. this.getPointAt(ending, v);
  6534. v.command = this._renderer.collection[i].command;
  6535. this._renderer.vertices.push(v);
  6536. right = v;
  6537. prev = this._collection[i - 1];
  6538. // Project control over the percentage `t`
  6539. // of the in-between point
  6540. if (prev && prev.controls) {
  6541. v.controls.right.clear();
  6542. this._renderer.collection[i - 1].controls.right
  6543. .clear()
  6544. .lerp(prev.controls.right, v.t);
  6545. }
  6546. } else if (i >= low && i <= high) {
  6547. v = this._renderer.collection[i]
  6548. .copy(this._collection[i]);
  6549. this._renderer.vertices.push(v);
  6550. if (i === high && contains(this, ending)) {
  6551. right = v;
  6552. if (!closed && right.controls) {
  6553. right.controls.right.clear();
  6554. }
  6555. } else if (i === low && contains(this, beginning)) {
  6556. left = v;
  6557. left.command = Commands.move;
  6558. if (!closed && left.controls) {
  6559. left.controls.left.clear();
  6560. }
  6561. }
  6562. }
  6563. }
  6564. // Prepend the trimmed point if necessary.
  6565. if (low > 0 && !left) {
  6566. i = low - 1;
  6567. v = this._renderer.collection[i];
  6568. v.copy(this._collection[i]);
  6569. this.getPointAt(beginning, v);
  6570. v.command = Commands.move;
  6571. this._renderer.vertices.unshift(v);
  6572. left = v;
  6573. next = this._collection[i + 1];
  6574. // Project control over the percentage `t`
  6575. // of the in-between point
  6576. if (next && next.controls) {
  6577. v.controls.left.clear();
  6578. this._renderer.collection[i + 1].controls.left
  6579. .copy(next.controls.left)
  6580. .lerp(Vector.zero, v.t);
  6581. }
  6582. }
  6583. }
  6584. Shape.prototype._update.apply(this, arguments);
  6585. return this;
  6586. },
  6587. /**
  6588. * @name Two.Path#flagReset
  6589. * @function
  6590. * @private
  6591. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  6592. */
  6593. flagReset: function() {
  6594. this._flagVertices = this._flagFill = this._flagStroke =
  6595. this._flagLinewidth = this._flagOpacity = this._flagVisible =
  6596. this._flagCap = this._flagJoin = this._flagMiter =
  6597. this._flagClip = false;
  6598. Shape.prototype.flagReset.call(this);
  6599. return this;
  6600. }
  6601. });
  6602. Path.MakeObservable(Path.prototype);
  6603. // Utility functions
  6604. function contains(path, t) {
  6605. if (t === 0 || t === 1) {
  6606. return true;
  6607. }
  6608. var length = path._length;
  6609. var target = length * t;
  6610. var elapsed = 0;
  6611. for (var i = 0; i < path._lengths.length; i++) {
  6612. var dist = path._lengths[i];
  6613. if (elapsed >= target) {
  6614. return target - elapsed >= 0;
  6615. }
  6616. elapsed += dist;
  6617. }
  6618. return false;
  6619. }
  6620. /**
  6621. * @private
  6622. * @param {Two.Path} path - The path to analyze against.
  6623. * @param {Number} target - The target length at which to find an anchor.
  6624. * @returns {Number}
  6625. * @description Return the id of an anchor based on a target length.
  6626. */
  6627. function getIdByLength(path, target) {
  6628. var total = path._length;
  6629. if (target <= 0) {
  6630. return 0;
  6631. } else if (target >= total) {
  6632. return path._lengths.length - 1;
  6633. }
  6634. for (var i = 0, sum = 0; i < path._lengths.length; i++) {
  6635. if (sum + path._lengths[i] >= target) {
  6636. target -= sum;
  6637. return Math.max(i - 1, 0) + target / path._lengths[i];
  6638. }
  6639. sum += path._lengths[i];
  6640. }
  6641. return - 1;
  6642. }
  6643. function getCurveLength(a, b, limit) {
  6644. // TODO: DRYness
  6645. var x1, x2, x3, x4, y1, y2, y3, y4;
  6646. var right = b.controls && b.controls.right;
  6647. var left = a.controls && a.controls.left;
  6648. x1 = b.x;
  6649. y1 = b.y;
  6650. x2 = (right || b).x;
  6651. y2 = (right || b).y;
  6652. x3 = (left || a).x;
  6653. y3 = (left || a).y;
  6654. x4 = a.x;
  6655. y4 = a.y;
  6656. if (right && b._relative) {
  6657. x2 += b.x;
  6658. y2 += b.y;
  6659. }
  6660. if (left && a._relative) {
  6661. x3 += a.x;
  6662. y3 += a.y;
  6663. }
  6664. return getCurveLength$1(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  6665. }
  6666. function getSubdivisions(a, b, limit) {
  6667. // TODO: DRYness
  6668. var x1, x2, x3, x4, y1, y2, y3, y4;
  6669. var right = b.controls && b.controls.right;
  6670. var left = a.controls && a.controls.left;
  6671. x1 = b.x;
  6672. y1 = b.y;
  6673. x2 = (right || b).x;
  6674. y2 = (right || b).y;
  6675. x3 = (left || a).x;
  6676. y3 = (left || a).y;
  6677. x4 = a.x;
  6678. y4 = a.y;
  6679. if (right && b._relative) {
  6680. x2 += b.x;
  6681. y2 += b.y;
  6682. }
  6683. if (left && a._relative) {
  6684. x3 += a.x;
  6685. y3 += a.y;
  6686. }
  6687. return subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  6688. }
  6689. /**
  6690. * @name Two.Rectangle
  6691. * @class
  6692. * @extends Two.Path
  6693. * @param {Number} [x=0] - The x position of the rectangle.
  6694. * @param {Number} [y=0] - The y position of the rectangle.
  6695. * @param {Number} [width] - The width value of the rectangle.
  6696. * @param {Number} [height] - The width value of the rectangle.
  6697. */
  6698. function Rectangle(x, y, width, height) {
  6699. Path.call(this, [
  6700. new Anchor(),
  6701. new Anchor(),
  6702. new Anchor(),
  6703. new Anchor()
  6704. // new Anchor() // TODO: Figure out how to handle this for `beginning` / `ending` animations
  6705. ], true, false, true);
  6706. /**
  6707. * @name Two.Rectangle#width
  6708. * @property {Number} - The size of the width of the rectangle.
  6709. */
  6710. this.width = width;
  6711. /**
  6712. * @name Two.Rectangle#height
  6713. * @property {Number} - The size of the height of the rectangle.
  6714. */
  6715. this.height = height;
  6716. /**
  6717. * @name Two.Rectangle#origin
  6718. * @property {Number} - A two-component vector describing the origin offset to draw the rectangle. Default is `0, 0`.
  6719. */
  6720. this.origin = new Vector();
  6721. this.translation.set(x, y);
  6722. this._update();
  6723. }
  6724. _.extend(Rectangle, {
  6725. /**
  6726. * @name Two.Rectangle.Properties
  6727. * @property {String[]} - A list of properties that are on every {@link Two.Rectangle}.
  6728. */
  6729. Properties: ['width', 'height'],
  6730. /**
  6731. * @name Two.Rectangle.MakeObservable
  6732. * @function
  6733. * @param {Object} object - The object to make observable.
  6734. * @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.
  6735. */
  6736. MakeObservable: function(object) {
  6737. Path.MakeObservable(object);
  6738. _.each(Rectangle.Properties, defineGetterSetter, object);
  6739. Object.defineProperty(object, 'origin', {
  6740. enumerable: true,
  6741. get: function() {
  6742. return this._origin;
  6743. },
  6744. set: function(v) {
  6745. if (this._origin) {
  6746. this._origin.unbind(Events.Types.change, this._renderer.flagVertices);
  6747. }
  6748. this._origin = v;
  6749. this._origin.bind(Events.Types.change, this._renderer.flagVertices);
  6750. this._renderer.flagVertices();
  6751. }
  6752. });
  6753. }
  6754. });
  6755. _.extend(Rectangle.prototype, Path.prototype, {
  6756. constructor: Rectangle,
  6757. /**
  6758. * @name Two.Rectangle#_flagWidth
  6759. * @private
  6760. * @property {Boolean} - Determines whether the {@link Two.Rectangle#width} needs updating.
  6761. */
  6762. _flagWidth: 0,
  6763. /**
  6764. * @name Two.Rectangle#_flagHeight
  6765. * @private
  6766. * @property {Boolean} - Determines whether the {@link Two.Rectangle#height} needs updating.
  6767. */
  6768. _flagHeight: 0,
  6769. /**
  6770. * @name Two.Rectangle#_width
  6771. * @private
  6772. * @see {@link Two.Rectangle#width}
  6773. */
  6774. _width: 0,
  6775. /**
  6776. * @name Two.Rectangle#_height
  6777. * @private
  6778. * @see {@link Two.Rectangle#height}
  6779. */
  6780. _height: 0,
  6781. _origin: null,
  6782. /**
  6783. * @name Two.Rectangle#_update
  6784. * @function
  6785. * @private
  6786. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  6787. * @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.
  6788. * @nota-bene Try not to call this method more than once a frame.
  6789. */
  6790. _update: function() {
  6791. if (this._flagVertices || this._flagWidth || this._flagHeight) {
  6792. var xr = this._width / 2;
  6793. var yr = this._height / 2;
  6794. if (!this._closed && this.vertices.length === 4) {
  6795. this.vertices.push(new Anchor());
  6796. }
  6797. this.vertices[0].set(-xr, -yr).add(this._origin).command = Commands.move;
  6798. this.vertices[1].set(xr, -yr).add(this._origin).command = Commands.line;
  6799. this.vertices[2].set(xr, yr).add(this._origin).command = Commands.line;
  6800. this.vertices[3].set(-xr, yr).add(this._origin).command = Commands.line;
  6801. // FYI: Two.Sprite and Two.ImageSequence have 4 verts
  6802. if (this.vertices[4]) {
  6803. this.vertices[4].set(-xr, -yr).add(this._origin).command = Commands.line;
  6804. }
  6805. }
  6806. Path.prototype._update.call(this);
  6807. return this;
  6808. },
  6809. /**
  6810. * @name Two.Rectangle#flagReset
  6811. * @function
  6812. * @private
  6813. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  6814. */
  6815. flagReset: function() {
  6816. this._flagWidth = this._flagHeight = false;
  6817. Path.prototype.flagReset.call(this);
  6818. return this;
  6819. },
  6820. /**
  6821. * @name Two.Rectangle#clone
  6822. * @function
  6823. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  6824. * @returns {Two.Rectangle}
  6825. * @description Create a new instance of {@link Two.Rectangle} with the same properties of the current path.
  6826. */
  6827. clone: function(parent) {
  6828. var clone = new Rectangle(0, 0, this.width, this.height);
  6829. clone.translation.copy(this.translation);
  6830. clone.rotation = this.rotation;
  6831. clone.scale = this.scale;
  6832. clone.skewX = this.skewX;
  6833. clone.skewY = this.skewY;
  6834. if (this.matrix.manual) {
  6835. clone.matrix.copy(this.matrix);
  6836. }
  6837. _.each(Path.Properties, function(k) {
  6838. clone[k] = this[k];
  6839. }, this);
  6840. if (parent) {
  6841. parent.add(clone);
  6842. }
  6843. return clone;
  6844. },
  6845. /**
  6846. * @name Two.Rectangle#toObject
  6847. * @function
  6848. * @returns {Object}
  6849. * @description Return a JSON compatible plain object that represents the path.
  6850. */
  6851. toObject: function() {
  6852. var object = Path.prototype.toObject.call(this);
  6853. object.width = this.width;
  6854. object.height = this.height;
  6855. object.origin = this.origin.toObject();
  6856. return object;
  6857. }
  6858. });
  6859. Rectangle.MakeObservable(Rectangle.prototype);
  6860. /**
  6861. * @name Two.Sprite
  6862. * @class
  6863. * @extends Two.Rectangle
  6864. * @param {String|Two.Texture} [path] - The URL path or {@link Two.Texture} to be used as the bitmap data displayed on the sprite.
  6865. * @param {Number} [ox=0] - The initial `x` position of the Two.Sprite.
  6866. * @param {Number} [oy=0] - The initial `y` position of the Two.Sprite.
  6867. * @param {Number} [cols=1] - The number of columns the sprite contains.
  6868. * @param {Number} [rows=1] - The number of rows the sprite contains.
  6869. * @param {Number} [frameRate=0] - The frame rate at which the partitions of the image should playback at.
  6870. * @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.
  6871. */
  6872. function Sprite(path, ox, oy, cols, rows, frameRate) {
  6873. // Not using default constructor of Rectangle due to odd `beginning` / `ending` behavior.
  6874. // See: https://github.com/jonobr1/two.js/issues/383
  6875. Path.call(this, [
  6876. new Anchor(),
  6877. new Anchor(),
  6878. new Anchor(),
  6879. new Anchor()
  6880. ], true);
  6881. this.noStroke();
  6882. this.noFill();
  6883. /**
  6884. * @name Two.Sprite#texture
  6885. * @property {Two.Texture} - The texture to be used as bitmap data to display image in the scene.
  6886. */
  6887. if (path instanceof Texture) {
  6888. this.texture = path;
  6889. } else if (typeof path === 'string') {
  6890. this.texture = new Texture(path);
  6891. }
  6892. this.origin = new Vector();
  6893. this._update();
  6894. this.translation.set(ox || 0, oy || 0);
  6895. /**
  6896. * @name Two.Sprite#columns
  6897. * @property {Number} - The number of columns to split the texture into. Defaults to `1`.
  6898. */
  6899. if (typeof cols === 'number') {
  6900. this.columns = cols;
  6901. }
  6902. /**
  6903. * @name Two.Sprite#rows
  6904. * @property {Number} - The number of rows to split the texture into. Defaults to `1`.
  6905. */
  6906. if (typeof rows === 'number') {
  6907. this.rows = rows;
  6908. }
  6909. /**
  6910. * @name Two.Sprite#frameRate
  6911. * @property {Number} - The number of frames to animate against per second. Defaults to `0` for non-animated sprites.
  6912. */
  6913. if (typeof frameRate === 'number') {
  6914. this.frameRate = frameRate;
  6915. }
  6916. /**
  6917. * @name Two.Sprite#index
  6918. * @property {Number} - The index of the current tile of the sprite to display. Defaults to `0`.
  6919. */
  6920. this.index = 0;
  6921. }
  6922. _.extend(Sprite, {
  6923. /**
  6924. * @name Two.Sprite.Properties
  6925. * @property {String[]} - A list of properties that are on every {@link Two.Sprite}.
  6926. */
  6927. Properties: [
  6928. 'texture', 'columns', 'rows', 'frameRate', 'index'
  6929. ],
  6930. /**
  6931. * @name Two.Sprite.MakeObservable
  6932. * @function
  6933. * @param {Object} object - The object to make observable.
  6934. * @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.
  6935. */
  6936. MakeObservable: function(obj) {
  6937. Rectangle.MakeObservable(obj);
  6938. _.each(Sprite.Properties, defineGetterSetter, obj);
  6939. }
  6940. });
  6941. _.extend(Sprite.prototype, Rectangle.prototype, {
  6942. constructor: Sprite,
  6943. /**
  6944. * @name Two.Sprite#_flagTexture
  6945. * @private
  6946. * @property {Boolean} - Determines whether the {@link Two.Sprite#texture} needs updating.
  6947. */
  6948. _flagTexture: false,
  6949. /**
  6950. * @name Two.Sprite#_flagColumns
  6951. * @private
  6952. * @property {Boolean} - Determines whether the {@link Two.Sprite#columns} need updating.
  6953. */
  6954. _flagColumns: false,
  6955. /**
  6956. * @name Two.Sprite#_flagRows
  6957. * @private
  6958. * @property {Boolean} - Determines whether the {@link Two.Sprite#rows} need updating.
  6959. */
  6960. _flagRows: false,
  6961. /**
  6962. * @name Two.Sprite#_flagFrameRate
  6963. * @private
  6964. * @property {Boolean} - Determines whether the {@link Two.Sprite#flagFrameRate} needs updating.
  6965. */
  6966. _flagFrameRate: false,
  6967. /**
  6968. * @name Two.Sprite#_flagIndex
  6969. * @private
  6970. * @property {Boolean} - Determines whether the {@link Two.Sprite#index} needs updating.
  6971. */
  6972. flagIndex: false,
  6973. // Private variables
  6974. /**
  6975. * @name Two.Sprite#_amount
  6976. * @private
  6977. * @property {Number} - Number of frames for a given {@link Two.Sprite}.
  6978. */
  6979. _amount: 1,
  6980. /**
  6981. * @name Two.Sprite#_duration
  6982. * @private
  6983. * @property {Number} - Number of milliseconds a {@link Two.Sprite}.
  6984. */
  6985. _duration: 0,
  6986. /**
  6987. * @name Two.Sprite#_startTime
  6988. * @private
  6989. * @property {Milliseconds} - Epoch time in milliseconds of when the {@link Two.Sprite} started.
  6990. */
  6991. _startTime: 0,
  6992. /**
  6993. * @name Two.Sprite#_playing
  6994. * @private
  6995. * @property {Boolean} - Dictates whether the {@link Two.Sprite} is animating or not.
  6996. */
  6997. _playing: false,
  6998. /**
  6999. * @name Two.Sprite#_firstFrame
  7000. * @private
  7001. * @property {Number} - The frame the {@link Two.Sprite} should start with.
  7002. */
  7003. _firstFrame: 0,
  7004. /**
  7005. * @name Two.Sprite#_lastFrame
  7006. * @private
  7007. * @property {Number} - The frame the {@link Two.Sprite} should end with.
  7008. */
  7009. _lastFrame: 0,
  7010. /**
  7011. * @name Two.Sprite#_playing
  7012. * @private
  7013. * @property {Boolean} - Dictates whether the {@link Two.Sprite} should loop or not.
  7014. */
  7015. _loop: true,
  7016. // Exposed through getter-setter
  7017. /**
  7018. * @name Two.Sprite#_texture
  7019. * @private
  7020. * @see {@link Two.Sprite#texture}
  7021. */
  7022. _texture: null,
  7023. /**
  7024. * @name Two.Sprite#_columns
  7025. * @private
  7026. * @see {@link Two.Sprite#columns}
  7027. */
  7028. _columns: 1,
  7029. /**
  7030. * @name Two.Sprite#_rows
  7031. * @private
  7032. * @see {@link Two.Sprite#rows}
  7033. */
  7034. _rows: 1,
  7035. /**
  7036. * @name Two.Sprite#_frameRate
  7037. * @private
  7038. * @see {@link Two.Sprite#frameRate}
  7039. */
  7040. _frameRate: 0,
  7041. /**
  7042. * @name Two.Sprite#_index
  7043. * @private
  7044. * @property {Number} - The current frame the {@link Two.Sprite} is currently displaying.
  7045. */
  7046. _index: 0,
  7047. /**
  7048. * @name Two.Sprite#_origin
  7049. * @private
  7050. * @see {@link Two.Sprite#origin}
  7051. */
  7052. _origin: null,
  7053. /**
  7054. * @name Two.Sprite#play
  7055. * @function
  7056. * @param {Number} [firstFrame=0] - The index of the frame to start the animation with.
  7057. * @param {Number} [lastFrame] - The index of the frame to end the animation with. Defaults to the last item in the {@link Two.Sprite#textures}.
  7058. * @param {Function} [onLastFrame] - Optional callback function to be triggered after playing the last frame. This fires multiple times when the sprite is looped.
  7059. * @description Initiate animation playback of a {@link Two.Sprite}.
  7060. */
  7061. play: function(firstFrame, lastFrame, onLastFrame) {
  7062. this._playing = true;
  7063. this._firstFrame = 0;
  7064. this._lastFrame = this.amount - 1;
  7065. this._startTime = _.performance.now();
  7066. if (typeof firstFrame === 'number') {
  7067. this._firstFrame = firstFrame;
  7068. }
  7069. if (typeof lastFrame === 'number') {
  7070. this._lastFrame = lastFrame;
  7071. }
  7072. if (typeof onLastFrame === 'function') {
  7073. this._onLastFrame = onLastFrame;
  7074. } else {
  7075. delete this._onLastFrame;
  7076. }
  7077. if (this._index !== this._firstFrame) {
  7078. this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  7079. / this._frameRate;
  7080. }
  7081. return this;
  7082. },
  7083. /**
  7084. * @name Two.Sprite#pause
  7085. * @function
  7086. * @description Halt animation playback of a {@link Two.Sprite}.
  7087. */
  7088. pause: function() {
  7089. this._playing = false;
  7090. return this;
  7091. },
  7092. /**
  7093. * @name Two.Sprite#stop
  7094. * @function
  7095. * @description Halt animation playback of a {@link Two.Sprite} and set the current frame back to the first frame.
  7096. */
  7097. stop: function() {
  7098. this._playing = false;
  7099. this._index = 0;
  7100. return this;
  7101. },
  7102. /**
  7103. * @name Two.Sprite#clone
  7104. * @function
  7105. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7106. * @returns {Two.Sprite}
  7107. * @description Create a new instance of {@link Two.Sprite} with the same properties of the current sprite.
  7108. */
  7109. clone: function(parent) {
  7110. var clone = new Sprite(
  7111. this.texture, this.translation.x, this.translation.y,
  7112. this.columns, this.rows, this.frameRate
  7113. );
  7114. if (this.playing) {
  7115. clone.play(this._firstFrame, this._lastFrame);
  7116. clone._loop = this._loop;
  7117. }
  7118. if (parent) {
  7119. parent.add(clone);
  7120. }
  7121. return clone;
  7122. },
  7123. /**
  7124. * @name Two.Sprite#toObject
  7125. * @function
  7126. * @returns {Object}
  7127. * @description Return a JSON compatible plain object that represents the path.
  7128. */
  7129. toObject: function() {
  7130. var object = Rectangle.prototype.toObject.call(this);
  7131. object.texture = this.texture.toObject();
  7132. object.columns = this.columns;
  7133. object.rows = this.rows;
  7134. object.frameRate = this.frameRate;
  7135. object.index = this.index;
  7136. object._firstFrame = this._firstFrame;
  7137. object._lastFrame = this._lastFrame;
  7138. object._loop = this._loop;
  7139. return object;
  7140. },
  7141. /**
  7142. * @name Two.Sprite#_update
  7143. * @function
  7144. * @private
  7145. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7146. * @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.
  7147. * @nota-bene Try not to call this method more than once a frame.
  7148. */
  7149. _update: function() {
  7150. var effect = this._texture;
  7151. var cols = this._columns;
  7152. var rows = this._rows;
  7153. var width, height, elapsed, amount, duration;
  7154. var index, iw, ih, frames;
  7155. if (this._flagColumns || this._flagRows) {
  7156. this._amount = this._columns * this._rows;
  7157. }
  7158. if (this._flagFrameRate) {
  7159. this._duration = 1000 * this._amount / this._frameRate;
  7160. }
  7161. if (this._flagTexture) {
  7162. this.fill = this._texture;
  7163. }
  7164. if (this._texture.loaded) {
  7165. iw = effect.image.width;
  7166. ih = effect.image.height;
  7167. width = iw / cols;
  7168. height = ih / rows;
  7169. amount = this._amount;
  7170. if (this.width !== width) {
  7171. this.width = width;
  7172. }
  7173. if (this.height !== height) {
  7174. this.height = height;
  7175. }
  7176. if (this._playing && this._frameRate > 0) {
  7177. if (_.isNaN(this._lastFrame)) {
  7178. this._lastFrame = amount - 1;
  7179. }
  7180. // TODO: Offload perf logic to instance of `Two`.
  7181. elapsed = _.performance.now() - this._startTime;
  7182. frames = this._lastFrame + 1;
  7183. duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  7184. if (this._loop) {
  7185. elapsed = elapsed % duration;
  7186. } else {
  7187. elapsed = Math.min(elapsed, duration);
  7188. }
  7189. index = lerp(this._firstFrame, frames, elapsed / duration);
  7190. index = Math.floor(index);
  7191. if (index !== this._index) {
  7192. this._index = index;
  7193. if (index >= this._lastFrame - 1 && this._onLastFrame) {
  7194. this._onLastFrame(); // Shortcut for chainable sprite animations
  7195. }
  7196. }
  7197. }
  7198. var col = this._index % cols;
  7199. var row = Math.floor(this._index / cols);
  7200. var ox = - width * col + (iw - width) / 2;
  7201. var oy = - height * row + (ih - height) / 2;
  7202. // TODO: Improve performance
  7203. if (ox !== effect.offset.x) {
  7204. effect.offset.x = ox;
  7205. }
  7206. if (oy !== effect.offset.y) {
  7207. effect.offset.y = oy;
  7208. }
  7209. }
  7210. Rectangle.prototype._update.call(this);
  7211. return this;
  7212. },
  7213. /**
  7214. * @name Two.Sprite#flagReset
  7215. * @function
  7216. * @private
  7217. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7218. */
  7219. flagReset: function() {
  7220. this._flagTexture = this._flagColumns = this._flagRows
  7221. = this._flagFrameRate = false;
  7222. Rectangle.prototype.flagReset.call(this);
  7223. return this;
  7224. }
  7225. });
  7226. Sprite.MakeObservable(Sprite.prototype);
  7227. var TWO_PI$4 = Math.PI * 2, HALF_PI$2 = Math.PI / 2;
  7228. var cos$3 = Math.cos, sin$3 = Math.sin;
  7229. /**
  7230. * @name Two.Circle
  7231. * @class
  7232. * @extends Two.Path
  7233. * @param {Number} [x=0] - The x position of the circle.
  7234. * @param {Number} [y=0] - The y position of the circle.
  7235. * @param {Number} [radius=0] - The radius value of the circle.
  7236. * @param {Number} [resolution=4] - The number of vertices used to construct the circle.
  7237. */
  7238. function Circle(ox, oy, r, resolution) {
  7239. // At least 2 vertices are required for proper circlage
  7240. var amount = resolution ? Math.max(resolution, 2) : 4;
  7241. var points = [];
  7242. for (var i = 0; i < amount; i++) {
  7243. points.push(new Anchor(0, 0, 0, 0, 0, 0));
  7244. }
  7245. Path.call(this, points, true, true, true);
  7246. /**
  7247. * @name Two.Circle#radius
  7248. * @property {Number} - The size of the radius of the circle.
  7249. */
  7250. if (typeof r === 'number') {
  7251. this.radius = r;
  7252. }
  7253. this._update();
  7254. if (typeof ox === 'number') {
  7255. this.translation.x = ox;
  7256. }
  7257. if (typeof oy === 'number') {
  7258. this.translation.y = oy;
  7259. }
  7260. }
  7261. _.extend(Circle, {
  7262. /**
  7263. * @name Two.Circle.Properties
  7264. * @property {String[]} - A list of properties that are on every {@link Two.Circle}.
  7265. */
  7266. Properties: ['radius'],
  7267. /**
  7268. * @name Two.Circle.MakeObservable
  7269. * @function
  7270. * @param {Object} object - The object to make observable.
  7271. * @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.
  7272. */
  7273. MakeObservable: function(obj) {
  7274. Path.MakeObservable(obj);
  7275. _.each(Circle.Properties, defineGetterSetter, obj);
  7276. }
  7277. });
  7278. _.extend(Circle.prototype, Path.prototype, {
  7279. constructor: Circle,
  7280. /**
  7281. * @name Two.Circle#_flagRadius
  7282. * @private
  7283. * @property {Boolean} - Determines whether the {@link Two.Circle#radius} needs updating.
  7284. */
  7285. _flagRadius: false,
  7286. /**
  7287. * @name Two.Circle#_radius
  7288. * @private
  7289. * @see {@link Two.Circle#radius}
  7290. */
  7291. _radius: 0,
  7292. /**
  7293. * @name Two.Circle#_update
  7294. * @function
  7295. * @private
  7296. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7297. * @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.
  7298. * @nota-bene Try not to call this method more than once a frame.
  7299. */
  7300. _update: function() {
  7301. if (this._flagVertices || this._flagRadius) {
  7302. var length = this.vertices.length;
  7303. if (!this._closed && length > 2) {
  7304. length -= 1;
  7305. }
  7306. // Coefficient for approximating circular arcs with Bezier curves
  7307. var c = (4 / 3) * Math.tan(Math.PI / (length * 2));
  7308. var radius = this._radius;
  7309. var rc = radius * c;
  7310. for (var i = 0; i < this.vertices.length; i++) {
  7311. var pct = i / length;
  7312. var theta = pct * TWO_PI$4;
  7313. var x = radius * cos$3(theta);
  7314. var y = radius * sin$3(theta);
  7315. var lx = rc * cos$3(theta - HALF_PI$2);
  7316. var ly = rc * sin$3(theta - HALF_PI$2);
  7317. var rx = rc * cos$3(theta + HALF_PI$2);
  7318. var ry = rc * sin$3(theta + HALF_PI$2);
  7319. var v = this.vertices[i];
  7320. v.command = i === 0 ? Commands.move : Commands.curve;
  7321. v.set(x, y);
  7322. v.controls.left.set(lx, ly);
  7323. v.controls.right.set(rx, ry);
  7324. }
  7325. }
  7326. Path.prototype._update.call(this);
  7327. return this;
  7328. },
  7329. /**
  7330. * @name Two.Circle#flagReset
  7331. * @function
  7332. * @private
  7333. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7334. */
  7335. flagReset: function() {
  7336. this._flagRadius = false;
  7337. Path.prototype.flagReset.call(this);
  7338. return this;
  7339. },
  7340. /**
  7341. * @name Two.Circle#clone
  7342. * @function
  7343. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7344. * @returns {Two.Circle}
  7345. * @description Create a new instance of {@link Two.Circle} with the same properties of the current path.
  7346. */
  7347. clone: function(parent) {
  7348. var clone = new Circle(0, 0, this.radius, this.vertices.length);
  7349. clone.translation.copy(this.translation);
  7350. clone.rotation = this.rotation;
  7351. clone.scale = this.scale;
  7352. clone.skewX = this.skewX;
  7353. clone.skewY = this.skewY;
  7354. if (this.matrix.manual) {
  7355. clone.matrix.copy(this.matrix);
  7356. }
  7357. _.each(Path.Properties, function(k) {
  7358. clone[k] = this[k];
  7359. }, this);
  7360. if (parent) {
  7361. parent.add(clone);
  7362. }
  7363. return clone;
  7364. },
  7365. /**
  7366. * @name Two.Circle#toObject
  7367. * @function
  7368. * @returns {Object}
  7369. * @description Return a JSON compatible plain object that represents the path.
  7370. */
  7371. toObject: function() {
  7372. var object = Path.prototype.toObject.call(this);
  7373. _.each(Circle.Properties, function(property) {
  7374. object[property] = this[property];
  7375. }, this);
  7376. return object;
  7377. }
  7378. });
  7379. Circle.MakeObservable(Circle.prototype);
  7380. var TWO_PI$3 = Math.PI * 2, HALF_PI$1 = Math.PI / 2;
  7381. var cos$2 = Math.cos, sin$2 = Math.sin;
  7382. /**
  7383. * @name Two.Ellipse
  7384. * @class
  7385. * @extends Two.Path
  7386. * @param {Number} [x=0] - The x position of the ellipse.
  7387. * @param {Number} [y=0] - The y position of the ellipse.
  7388. * @param {Number} [rx=0] - The radius value of the ellipse in the x direction.
  7389. * @param {Number} [ry=0] - The radius value of the ellipse in the y direction.
  7390. * @param {Number} [resolution=4] - The number of vertices used to construct the ellipse.
  7391. */
  7392. function Ellipse(ox, oy, rx, ry, resolution) {
  7393. if (typeof ry !== 'number' && typeof rx === 'number') {
  7394. ry = rx;
  7395. }
  7396. // At least 2 vertices are required for proper circlage
  7397. var amount = resolution ? Math.max(resolution, 2) : 4;
  7398. var points = [];
  7399. for (var i = 0; i < amount; i++) {
  7400. points.push(new Anchor());
  7401. }
  7402. Path.call(this, points, true, true, true);
  7403. /**
  7404. * @name Two.Ellipse#width
  7405. * @property {Number} - The width of the ellipse.
  7406. */
  7407. if (typeof rx === 'number') {
  7408. this.width = rx * 2;
  7409. }
  7410. /**
  7411. * @name Two.Ellipse#height
  7412. * @property {Number} - The height of the ellipse.
  7413. */
  7414. if (typeof ry === 'number') {
  7415. this.height = ry * 2;
  7416. }
  7417. this._update();
  7418. this.translation.set(ox, oy);
  7419. }
  7420. _.extend(Ellipse, {
  7421. /**
  7422. * @name Two.Ellipse.Properties
  7423. * @property {String[]} - A list of properties that are on every {@link Two.Ellipse}.
  7424. */
  7425. Properties: ['width', 'height'],
  7426. /**
  7427. * @name Two.Ellipse.MakeObservable
  7428. * @function
  7429. * @param {Object} object - The object to make observable.
  7430. * @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.
  7431. */
  7432. MakeObservable: function(obj) {
  7433. Path.MakeObservable(obj);
  7434. _.each(Ellipse.Properties, defineGetterSetter, obj);
  7435. }
  7436. });
  7437. _.extend(Ellipse.prototype, Path.prototype, {
  7438. /**
  7439. * @name Two.Ellipse#_flagWidth
  7440. * @private
  7441. * @property {Boolean} - Determines whether the {@link Two.Ellipse#width} needs updating.
  7442. */
  7443. _flagWidth: false,
  7444. /**
  7445. * @name Two.Ellipse#_flagHeight
  7446. * @private
  7447. * @property {Boolean} - Determines whether the {@link Two.Ellipse#height} needs updating.
  7448. */
  7449. _flagHeight: false,
  7450. /**
  7451. * @name Two.Polygon#_width
  7452. * @private
  7453. * @see {@link Two.Ellipse#width}
  7454. */
  7455. _width: 0,
  7456. /**
  7457. * @name Two.Polygon#_height
  7458. * @private
  7459. * @see {@link Two.Ellipse#height}
  7460. */
  7461. _height: 0,
  7462. constructor: Ellipse,
  7463. /**
  7464. * @name Two.Ellipse#_update
  7465. * @function
  7466. * @private
  7467. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7468. * @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.
  7469. * @nota-bene Try not to call this method more than once a frame.
  7470. */
  7471. _update: function() {
  7472. if (this._flagVertices || this._flagWidth || this._flagHeight) {
  7473. var length = this.vertices.length;
  7474. if (!this._closed && length > 2) {
  7475. length -= 1;
  7476. }
  7477. // Coefficient for approximating circular arcs with Bezier curves
  7478. var c = (4 / 3) * Math.tan(Math.PI / (this.vertices.length * 2));
  7479. var radiusX = this._width / 2;
  7480. var radiusY = this._height / 2;
  7481. for (var i = 0; i < this.vertices.length; i++) {
  7482. var pct = i / length;
  7483. var theta = pct * TWO_PI$3;
  7484. var x = radiusX * cos$2(theta);
  7485. var y = radiusY * sin$2(theta);
  7486. var lx = radiusX * c * cos$2(theta - HALF_PI$1);
  7487. var ly = radiusY * c * sin$2(theta - HALF_PI$1);
  7488. var rx = radiusX * c * cos$2(theta + HALF_PI$1);
  7489. var ry = radiusY * c * sin$2(theta + HALF_PI$1);
  7490. var v = this.vertices[i];
  7491. v.command = i === 0 ? Commands.move : Commands.curve;
  7492. v.set(x, y);
  7493. v.controls.left.set(lx, ly);
  7494. v.controls.right.set(rx, ry);
  7495. }
  7496. }
  7497. Path.prototype._update.call(this);
  7498. return this;
  7499. },
  7500. /**
  7501. * @name Two.Ellipse#flagReset
  7502. * @function
  7503. * @private
  7504. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7505. */
  7506. flagReset: function() {
  7507. this._flagWidth = this._flagHeight = false;
  7508. Path.prototype.flagReset.call(this);
  7509. return this;
  7510. },
  7511. /**
  7512. * @name Two.Ellipse#clone
  7513. * @function
  7514. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7515. * @returns {Two.Polygon}
  7516. * @description Create a new instance of {@link Two.Polygon} with the same properties of the current path.
  7517. */
  7518. clone: function(parent) {
  7519. var rx = this.width / 2;
  7520. var ry = this.height / 2;
  7521. var resolution = this.vertices.length;
  7522. var clone = new Ellipse(0, 0, rx, ry, resolution);
  7523. clone.translation.copy(this.translation);
  7524. clone.rotation = this.rotation;
  7525. clone.scale = this.scale;
  7526. clone.skewX = this.skewX;
  7527. clone.skewY = this.skewY;
  7528. if (this.matrix.manual) {
  7529. clone.matrix.copy(this.matrix);
  7530. }
  7531. _.each(Path.Properties, function(k) {
  7532. clone[k] = this[k];
  7533. }, this);
  7534. if (parent) {
  7535. parent.add(clone);
  7536. }
  7537. return clone;
  7538. },
  7539. /**
  7540. * @name Two.Ellipse#toObject
  7541. * @function
  7542. * @returns {Object}
  7543. * @description Return a JSON compatible plain object that represents the path.
  7544. */
  7545. toObject: function() {
  7546. var object = Path.prototype.toObject.call(this);
  7547. _.each(Ellipse.Properties, function(property) {
  7548. object[property] = this[property];
  7549. }, this);
  7550. return object;
  7551. }
  7552. });
  7553. Ellipse.MakeObservable(Ellipse.prototype);
  7554. /**
  7555. * @name Two.Line
  7556. * @class
  7557. * @extends Two.Path
  7558. * @param {Number} [x1=0] - The x position of the first vertex on the line.
  7559. * @param {Number} [y1=0] - The y position of the first vertex on the line.
  7560. * @param {Number} [x2=0] - The x position of the second vertex on the line.
  7561. * @param {Number} [y2=0] - The y position of the second vertex on the line.
  7562. */
  7563. function Line(x1, y1, x2, y2) {
  7564. Path.call(this, [
  7565. new Anchor(x1, y1),
  7566. new Anchor(x2, y2)
  7567. ]);
  7568. this.vertices[0].command = Commands.move;
  7569. this.vertices[1].command = Commands.line;
  7570. this.automatic = false;
  7571. }
  7572. _.extend(Line.prototype, Path.prototype, {
  7573. constructor: Line
  7574. });
  7575. Path.MakeObservable(Line.prototype);
  7576. /**
  7577. * @name Two.RoundedRectangle
  7578. * @class
  7579. * @extends Two.Path
  7580. * @param {Number} [x=0] - The x position of the rounded rectangle.
  7581. * @param {Number} [y=0] - The y position of the rounded rectangle.
  7582. * @param {Number} [width=0] - The width value of the rounded rectangle.
  7583. * @param {Number} [height=0] - The width value of the rounded rectangle.
  7584. * @param {Number} [radius=0] - The radius value of the rounded rectangle.
  7585. * @param {Number} [resolution=12] - The number of vertices used to construct the rounded rectangle.
  7586. */
  7587. function RoundedRectangle(ox, oy, width, height, radius) {
  7588. if (typeof radius === 'undefined' &&
  7589. typeof width === 'number' && typeof height === 'number') {
  7590. radius = Math.floor(Math.min(width, height) / 12);
  7591. }
  7592. var amount = 10;
  7593. var points = [];
  7594. for (var i = 0; i < amount; i++) {
  7595. points.push(
  7596. new Anchor(0, 0, 0, 0, 0, 0,
  7597. i === 0 ? Commands.move : Commands.curve)
  7598. );
  7599. }
  7600. // points[points.length - 1].command = Two.Commands.close;
  7601. Path.call(this, points);
  7602. this.closed = true;
  7603. this.automatic = false;
  7604. this._renderer.flagRadius = RoundedRectangle.FlagRadius.bind(this);
  7605. /**
  7606. * @name Two.RoundedRectangle#width
  7607. * @property {Number} - The width of the rounded rectangle.
  7608. */
  7609. if (typeof width === 'number') {
  7610. this.width = width;
  7611. }
  7612. /**
  7613. * @name Two.RoundedRectangle#height
  7614. * @property {Number} - The height of the rounded rectangle.
  7615. */
  7616. if (typeof height === 'number') {
  7617. this.height = height;
  7618. }
  7619. /**
  7620. * @name Two.RoundedRectangle#radius
  7621. * @property {Number} - The size of the radius of the rounded rectangle.
  7622. */
  7623. if (typeof radius === 'number') {
  7624. this.radius = radius;
  7625. }
  7626. this._update();
  7627. this.translation.set(ox, oy);
  7628. }
  7629. _.extend(RoundedRectangle, {
  7630. /**
  7631. * @name Two.RoundedRectangle.Properties
  7632. * @property {String[]} - A list of properties that are on every {@link Two.RoundedRectangle}.
  7633. */
  7634. Properties: ['width', 'height'],
  7635. /**
  7636. * @name Two.RoundedRectangle.FlagRadius
  7637. * @property {Function} - A convenience function to trigger the flag for radius changing.
  7638. */
  7639. FlagRadius: function() {
  7640. this._flagRadius = true;
  7641. },
  7642. /**
  7643. * @name Two.RoundedRectangle.MakeObservable
  7644. * @function
  7645. * @param {Object} object - The object to make observable.
  7646. * @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.
  7647. */
  7648. MakeObservable: function(object) {
  7649. Path.MakeObservable(object);
  7650. _.each(RoundedRectangle.Properties, defineGetterSetter, object);
  7651. Object.defineProperty(object, 'radius', {
  7652. enumerable: true,
  7653. get: function() {
  7654. return this._radius;
  7655. },
  7656. set: function(v) {
  7657. if (this._radius instanceof Vector) {
  7658. this._radius.unbind(Events.Types.change, this._renderer.flagRadius);
  7659. }
  7660. this._radius = v;
  7661. if (this._radius instanceof Vector) {
  7662. this._radius.bind(Events.Types.change, this._renderer.flagRadius);
  7663. }
  7664. this._flagRadius = true;
  7665. }
  7666. });
  7667. }
  7668. });
  7669. _.extend(RoundedRectangle.prototype, Path.prototype, {
  7670. constructor: RoundedRectangle,
  7671. /**
  7672. * @name Two.RoundedRectangle#_flagWidth
  7673. * @private
  7674. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#width} needs updating.
  7675. */
  7676. _flagWidth: false,
  7677. /**
  7678. * @name Two.RoundedRectangle#_flagHeight
  7679. * @private
  7680. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#height} needs updating.
  7681. */
  7682. _flagHeight: false,
  7683. /**
  7684. * @name Two.RoundedRectangle#_flagRadius
  7685. * @private
  7686. * @property {Boolean} - Determines whether the {@link Two.RoundedRectangle#radius} needs updating.
  7687. */
  7688. _flagRadius: false,
  7689. /**
  7690. * @name Two.RoundedRectangle#_width
  7691. * @private
  7692. * @see {@link Two.RoundedRectangle#width}
  7693. */
  7694. _width: 0,
  7695. /**
  7696. * @name Two.RoundedRectangle#_height
  7697. * @private
  7698. * @see {@link Two.RoundedRectangle#height}
  7699. */
  7700. _height: 0,
  7701. /**
  7702. * @name Two.RoundedRectangle#_radius
  7703. * @private
  7704. * @see {@link Two.RoundedRectangle#radius}
  7705. */
  7706. _radius: 12,
  7707. /**
  7708. * @name Two.RoundedRectangle#_update
  7709. * @function
  7710. * @private
  7711. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  7712. * @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.
  7713. * @nota-bene Try not to call this method more than once a frame.
  7714. */
  7715. _update: function() {
  7716. if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagRadius) {
  7717. var width = this._width;
  7718. var height = this._height;
  7719. var rx, ry;
  7720. if (this._radius instanceof Vector) {
  7721. rx = this._radius.x;
  7722. ry = this._radius.y;
  7723. } else {
  7724. rx = this._radius;
  7725. ry = this._radius;
  7726. }
  7727. var v;
  7728. var w = width / 2;
  7729. var h = height / 2;
  7730. v = this.vertices[0];
  7731. v.x = - (w - rx);
  7732. v.y = - h;
  7733. // Upper Right Corner
  7734. v = this.vertices[1];
  7735. v.x = (w - rx);
  7736. v.y = - h;
  7737. v.controls.left.clear();
  7738. v.controls.right.x = rx;
  7739. v.controls.right.y = 0;
  7740. v = this.vertices[2];
  7741. v.x = w;
  7742. v.y = - (h - ry);
  7743. v.controls.right.clear();
  7744. v.controls.left.clear();
  7745. // Bottom Right Corner
  7746. v = this.vertices[3];
  7747. v.x = w;
  7748. v.y = (h - ry);
  7749. v.controls.left.clear();
  7750. v.controls.right.x = 0;
  7751. v.controls.right.y = ry;
  7752. v = this.vertices[4];
  7753. v.x = (w - rx);
  7754. v.y = h;
  7755. v.controls.right.clear();
  7756. v.controls.left.clear();
  7757. // Bottom Left Corner
  7758. v = this.vertices[5];
  7759. v.x = - (w - rx);
  7760. v.y = h;
  7761. v.controls.left.clear();
  7762. v.controls.right.x = - rx;
  7763. v.controls.right.y = 0;
  7764. v = this.vertices[6];
  7765. v.x = - w;
  7766. v.y = (h - ry);
  7767. v.controls.left.clear();
  7768. v.controls.right.clear();
  7769. // Upper Left Corner
  7770. v = this.vertices[7];
  7771. v.x = - w;
  7772. v.y = - (h - ry);
  7773. v.controls.left.clear();
  7774. v.controls.right.x = 0;
  7775. v.controls.right.y = - ry;
  7776. v = this.vertices[8];
  7777. v.x = - (w - rx);
  7778. v.y = - h;
  7779. v.controls.left.clear();
  7780. v.controls.right.clear();
  7781. v = this.vertices[9];
  7782. v.copy(this.vertices[8]);
  7783. }
  7784. Path.prototype._update.call(this);
  7785. return this;
  7786. },
  7787. /**
  7788. * @name Two.RoundedRectangle#flagReset
  7789. * @function
  7790. * @private
  7791. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  7792. */
  7793. flagReset: function() {
  7794. this._flagWidth = this._flagHeight = this._flagRadius = false;
  7795. Path.prototype.flagReset.call(this);
  7796. return this;
  7797. },
  7798. /**
  7799. * @name Two.RoundedRectangle#clone
  7800. * @function
  7801. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  7802. * @returns {Two.RoundedRectangle}
  7803. * @description Create a new instance of {@link Two.RoundedRectangle} with the same properties of the current path.
  7804. */
  7805. clone: function(parent) {
  7806. var width = this.width;
  7807. var height = this.height;
  7808. var radius = this.radius;
  7809. var clone = new RoundedRectangle(0, 0, width, height, radius);
  7810. clone.translation.copy(this.translation);
  7811. clone.rotation = this.rotation;
  7812. clone.scale = this.scale;
  7813. clone.skewX = this.skewX;
  7814. clone.skewY = this.skewY;
  7815. if (this.matrix.manual) {
  7816. clone.matrix.copy(this.matrix);
  7817. }
  7818. _.each(Path.Properties, function(k) {
  7819. clone[k] = this[k];
  7820. }, this);
  7821. if (parent) {
  7822. parent.add(clone);
  7823. }
  7824. return clone;
  7825. },
  7826. /**
  7827. * @name Two.RoundedRectangle#toObject
  7828. * @function
  7829. * @returns {Object}
  7830. * @description Return a JSON compatible plain object that represents the path.
  7831. */
  7832. toObject: function() {
  7833. var object = Path.prototype.toObject.call(this);
  7834. _.each(RoundedRectangle.Properties, function(property) {
  7835. object[property] = this[property];
  7836. }, this);
  7837. object.radius = typeof this.radius === 'number'
  7838. ? this.radius : this.radius.toObject();
  7839. return object;
  7840. }
  7841. });
  7842. RoundedRectangle.MakeObservable(RoundedRectangle.prototype);
  7843. var min = Math.min, max = Math.max;
  7844. /**
  7845. * @name Two.Text
  7846. * @class
  7847. * @extends Two.Shape
  7848. * @param {String} [message] - The String to be rendered to the scene.
  7849. * @param {Number} [x=0] - The position in the x direction for the object.
  7850. * @param {Number} [y=0] - The position in the y direction for the object.
  7851. * @param {Object} [styles] - An object where styles are applied. Attribute must exist in Two.Text.Properties.
  7852. * @description This is a primitive class for creating drawable text that can be added to the scenegraph.
  7853. * @returns {Two.Text}
  7854. */
  7855. function Text(message, x, y, styles) {
  7856. Shape.call(this);
  7857. this._renderer.type = 'text';
  7858. this._renderer.flagFill = Text.FlagFill.bind(this);
  7859. this._renderer.flagStroke = Text.FlagStroke.bind(this);
  7860. this.value = message;
  7861. if (typeof x === 'number') {
  7862. this.translation.x = x;
  7863. }
  7864. if (typeof y === 'number') {
  7865. this.translation.y = y;
  7866. }
  7867. /**
  7868. * @name Two.Text#dashes
  7869. * @property {Number[]} - Array of numbers. Odd indices represent dash length. Even indices represent dash space.
  7870. * @description A list of numbers that represent the repeated dash length and dash space applied to the stroke of the text.
  7871. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray} for more information on the SVG stroke-dasharray attribute.
  7872. */
  7873. this.dashes = [];
  7874. /**
  7875. * @name Two.Text#dashes#offset
  7876. * @property {Number} - A number in pixels to offset {@link Two.Text#dashes} display.
  7877. */
  7878. this.dashes.offset = 0;
  7879. if (!_.isObject(styles)) {
  7880. return this;
  7881. }
  7882. _.each(Text.Properties, function(property) {
  7883. if (property in styles) {
  7884. this[property] = styles[property];
  7885. }
  7886. }, this);
  7887. }
  7888. _.extend(Text, {
  7889. /**
  7890. * @name Two.Text.Ratio
  7891. * @property {Number} - Approximate aspect ratio of a typeface's character width to height.
  7892. */
  7893. Ratio: 0.6,
  7894. /**
  7895. * @name Two.Text.Properties
  7896. * @property {String[]} - A list of properties that are on every {@link Two.Text}.
  7897. */
  7898. Properties: [
  7899. 'value', 'family', 'size', 'leading', 'alignment', 'linewidth', 'style',
  7900. 'weight', 'decoration', 'baseline', 'opacity', 'visible', 'className',
  7901. 'fill', 'stroke',
  7902. ],
  7903. /**
  7904. * @name Two.Text.FlagFill
  7905. * @function
  7906. * @description Cached method to let renderers know the fill property have been updated on a {@link Two.Text}.
  7907. */
  7908. FlagFill: function() {
  7909. this._flagFill = true;
  7910. },
  7911. /**
  7912. * @name Two.Text.FlagStroke
  7913. * @function
  7914. * @description Cached method to let renderers know the stroke property have been updated on a {@link Two.Text}.
  7915. */
  7916. FlagStroke: function() {
  7917. this._flagStroke = true;
  7918. },
  7919. MakeObservable: function(object) {
  7920. Shape.MakeObservable(object);
  7921. _.each(Text.Properties.slice(0, 12), defineGetterSetter, object);
  7922. Object.defineProperty(object, 'fill', {
  7923. enumerable: true,
  7924. get: function() {
  7925. return this._fill;
  7926. },
  7927. set: function(f) {
  7928. if (this._fill instanceof Gradient
  7929. || this._fill instanceof LinearGradient
  7930. || this._fill instanceof RadialGradient
  7931. || this._fill instanceof Texture) {
  7932. this._fill.unbind(Events.Types.change, this._renderer.flagFill);
  7933. }
  7934. this._fill = f;
  7935. this._flagFill = true;
  7936. if (this._fill instanceof Gradient
  7937. || this._fill instanceof LinearGradient
  7938. || this._fill instanceof RadialGradient
  7939. || this._fill instanceof Texture) {
  7940. this._fill.bind(Events.Types.change, this._renderer.flagFill);
  7941. }
  7942. }
  7943. });
  7944. Object.defineProperty(object, 'stroke', {
  7945. enumerable: true,
  7946. get: function() {
  7947. return this._stroke;
  7948. },
  7949. set: function(f) {
  7950. if (this._stroke instanceof Gradient
  7951. || this._stroke instanceof LinearGradient
  7952. || this._stroke instanceof RadialGradient
  7953. || this._stroke instanceof Texture) {
  7954. this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
  7955. }
  7956. this._stroke = f;
  7957. this._flagStroke = true;
  7958. if (this._stroke instanceof Gradient
  7959. || this._stroke instanceof LinearGradient
  7960. || this._stroke instanceof RadialGradient
  7961. || this._stroke instanceof Texture) {
  7962. this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
  7963. }
  7964. }
  7965. });
  7966. Object.defineProperty(object, 'mask', {
  7967. enumerable: true,
  7968. get: function() {
  7969. return this._mask;
  7970. },
  7971. set: function(v) {
  7972. this._mask = v;
  7973. this._flagMask = true;
  7974. if (!v.clip) {
  7975. v.clip = true;
  7976. }
  7977. }
  7978. });
  7979. Object.defineProperty(object, 'clip', {
  7980. enumerable: true,
  7981. get: function() {
  7982. return this._clip;
  7983. },
  7984. set: function(v) {
  7985. this._clip = v;
  7986. this._flagClip = true;
  7987. }
  7988. });
  7989. Object.defineProperty(object, 'dashes', {
  7990. enumerable: true,
  7991. get: function() {
  7992. return this._dashes;
  7993. },
  7994. set: function(v) {
  7995. if (typeof v.offset !== 'number') {
  7996. v.offset = this._dashes.offset || 0;
  7997. }
  7998. this._dashes = v;
  7999. }
  8000. });
  8001. }
  8002. });
  8003. _.extend(Text.prototype, Shape.prototype, {
  8004. constructor: Text,
  8005. // Flags
  8006. // http://en.wikipedia.org/wiki/Flag
  8007. /**
  8008. * @name Two.Text#_flagValue
  8009. * @private
  8010. * @property {Boolean} - Determines whether the {@link Two.Text#value} need updating.
  8011. */
  8012. _flagValue: true,
  8013. /**
  8014. * @name Two.Text#_flagFamily
  8015. * @private
  8016. * @property {Boolean} - Determines whether the {@link Two.Text#family} need updating.
  8017. */
  8018. _flagFamily: true,
  8019. /**
  8020. * @name Two.Text#_flagSize
  8021. * @private
  8022. * @property {Boolean} - Determines whether the {@link Two.Text#size} need updating.
  8023. */
  8024. _flagSize: true,
  8025. /**
  8026. * @name Two.Text#_flagLeading
  8027. * @private
  8028. * @property {Boolean} - Determines whether the {@link Two.Text#leading} need updating.
  8029. */
  8030. _flagLeading: true,
  8031. /**
  8032. * @name Two.Text#_flagAlignment
  8033. * @private
  8034. * @property {Boolean} - Determines whether the {@link Two.Text#alignment} need updating.
  8035. */
  8036. _flagAlignment: true,
  8037. /**
  8038. * @name Two.Text#_flagBaseline
  8039. * @private
  8040. * @property {Boolean} - Determines whether the {@link Two.Text#baseline} need updating.
  8041. */
  8042. _flagBaseline: true,
  8043. /**
  8044. * @name Two.Text#_flagStyle
  8045. * @private
  8046. * @property {Boolean} - Determines whether the {@link Two.Text#style} need updating.
  8047. */
  8048. _flagStyle: true,
  8049. /**
  8050. * @name Two.Text#_flagWeight
  8051. * @private
  8052. * @property {Boolean} - Determines whether the {@link Two.Text#weight} need updating.
  8053. */
  8054. _flagWeight: true,
  8055. /**
  8056. * @name Two.Text#_flagDecoration
  8057. * @private
  8058. * @property {Boolean} - Determines whether the {@link Two.Text#decoration} need updating.
  8059. */
  8060. _flagDecoration: true,
  8061. /**
  8062. * @name Two.Text#_flagFill
  8063. * @private
  8064. * @property {Boolean} - Determines whether the {@link Two.Text#fill} need updating.
  8065. */
  8066. _flagFill: true,
  8067. /**
  8068. * @name Two.Text#_flagStroke
  8069. * @private
  8070. * @property {Boolean} - Determines whether the {@link Two.Text#stroke} need updating.
  8071. */
  8072. _flagStroke: true,
  8073. /**
  8074. * @name Two.Text#_flagLinewidth
  8075. * @private
  8076. * @property {Boolean} - Determines whether the {@link Two.Text#linewidth} need updating.
  8077. */
  8078. _flagLinewidth: true,
  8079. /**
  8080. * @name Two.Text#_flagOpacity
  8081. * @private
  8082. * @property {Boolean} - Determines whether the {@link Two.Text#opacity} need updating.
  8083. */
  8084. _flagOpacity: true,
  8085. /**
  8086. * @name Two.Text#_flagClassName
  8087. * @private
  8088. * @property {Boolean} - Determines whether the {@link Two.Text#className} need updating.
  8089. */
  8090. _flagClassName: true,
  8091. /**
  8092. * @name Two.Text#_flagVisible
  8093. * @private
  8094. * @property {Boolean} - Determines whether the {@link Two.Text#visible} need updating.
  8095. */
  8096. _flagVisible: true,
  8097. /**
  8098. * @name Two.Path#_flagMask
  8099. * @private
  8100. * @property {Boolean} - Determines whether the {@link Two.Path#mask} needs updating.
  8101. */
  8102. _flagMask: false,
  8103. /**
  8104. * @name Two.Text#_flagClip
  8105. * @private
  8106. * @property {Boolean} - Determines whether the {@link Two.Text#clip} need updating.
  8107. */
  8108. _flagClip: false,
  8109. // Underlying Properties
  8110. /**
  8111. * @name Two.Text#value
  8112. * @property {String} - The characters to be rendered to the the screen. Referred to in the documentation sometimes as the `message`.
  8113. */
  8114. _value: '',
  8115. /**
  8116. * @name Two.Text#family
  8117. * @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`.
  8118. */
  8119. _family: 'sans-serif',
  8120. /**
  8121. * @name Two.Text#size
  8122. * @property {Number} - The font size in Two.js point space. Defaults to `13`.
  8123. */
  8124. _size: 13,
  8125. /**
  8126. * @name Two.Text#leading
  8127. * @property {Number} - The height between lines measured from base to base in Two.js point space. Defaults to `17`.
  8128. */
  8129. _leading: 17,
  8130. /**
  8131. * @name Two.Text#alignment
  8132. * @property {String} - Alignment of text in relation to {@link Two.Text#translation}'s coordinates. Possible values include `'left'`, `'center'`, `'right'`. Defaults to `'center'`.
  8133. */
  8134. _alignment: 'center',
  8135. /**
  8136. * @name Two.Text#baseline
  8137. * @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'`.
  8138. */
  8139. _baseline: 'middle',
  8140. /**
  8141. * @name Two.Text#style
  8142. * @property {String} - The font's style. Possible values include '`normal`', `'italic'`. Defaults to `'normal'`.
  8143. */
  8144. _style: 'normal',
  8145. /**
  8146. * @name Two.Text#weight
  8147. * @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'`.
  8148. */
  8149. _weight: 500,
  8150. /**
  8151. * @name Two.Text#decoration
  8152. * @property {String} - String to delineate whether text should be decorated with for instance an `'underline'`. Defaults to `'none'`.
  8153. */
  8154. _decoration: 'none',
  8155. /**
  8156. * @name Two.Text#fill
  8157. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the text object should be filled in with.
  8158. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  8159. */
  8160. _fill: '#000',
  8161. /**
  8162. * @name Two.Text#stroke
  8163. * @property {(String|Two.Gradient|Two.Texture)} - The value of what the text object should be filled in with.
  8164. * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for more information on CSS's colors as `String`.
  8165. */
  8166. _stroke: 'transparent',
  8167. /**
  8168. * @name Two.Text#linewidth
  8169. * @property {Number} - The thickness in pixels of the stroke.
  8170. */
  8171. _linewidth: 1,
  8172. /**
  8173. * @name Two.Text#opacity
  8174. * @property {Number} - The opaqueness of the text object.
  8175. * @nota-bene Can be used in conjunction with CSS Colors that have an alpha value.
  8176. */
  8177. _opacity: 1,
  8178. /**
  8179. * @name Two.Text#className
  8180. * @property {String} - A class to be applied to the element to be compatible with CSS styling. Only available for the {@link Two.SvgRenderer}.
  8181. */
  8182. _className: '',
  8183. /**
  8184. * @name Two.Text#visible
  8185. * @property {Boolean} - Display the text object or not.
  8186. * @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.
  8187. */
  8188. _visible: true,
  8189. /**
  8190. * @name Two.Text#mask
  8191. * @property {Two.Shape} - The shape whose alpha property becomes a clipping area for the text.
  8192. * @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}.
  8193. */
  8194. _mask: null,
  8195. /**
  8196. * @name Two.Text#clip
  8197. * @property {Two.Shape} - Object to define clipping area.
  8198. * @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}.
  8199. */
  8200. _clip: false,
  8201. /**
  8202. * @name Two.Text#_dashes
  8203. * @private
  8204. * @see {@link Two.Text#dashes}
  8205. */
  8206. _dashes: [],
  8207. /**
  8208. * @name Two.Text#remove
  8209. * @function
  8210. * @description Remove self from the scene / parent.
  8211. */
  8212. remove: function() {
  8213. if (!this.parent) {
  8214. return this;
  8215. }
  8216. this.parent.remove(this);
  8217. return this;
  8218. },
  8219. /**
  8220. * @name Two.Text#clone
  8221. * @function
  8222. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  8223. * @returns {Two.Text}
  8224. * @description Create a new instance of {@link Two.Text} with the same properties of the current text object.
  8225. */
  8226. clone: function(parent) {
  8227. var clone = new Text(this.value);
  8228. clone.translation.copy(this.translation);
  8229. clone.rotation = this.rotation;
  8230. clone.scale = this.scale;
  8231. _.each(Text.Properties, function(property) {
  8232. clone[property] = this[property];
  8233. }, this);
  8234. if (this.matrix.manual) {
  8235. clone.matrix.copy(this.matrix);
  8236. }
  8237. if (parent) {
  8238. parent.add(clone);
  8239. }
  8240. return clone._update();
  8241. },
  8242. /**
  8243. * @name Two.Text#toObject
  8244. * @function
  8245. * @returns {Object}
  8246. * @description Return a JSON compatible plain object that represents the text object.
  8247. */
  8248. toObject: function() {
  8249. var result = {
  8250. translation: this.translation.toObject(),
  8251. rotation: this.rotation,
  8252. scale: this.scale
  8253. };
  8254. if (this.matrix.manual) {
  8255. result.matrix = this.matrix.toObject();
  8256. }
  8257. _.each(Text.Properties, function(property) {
  8258. result[property] = this[property];
  8259. }, this);
  8260. return result;
  8261. },
  8262. /**
  8263. * @name Two.Text#noFill
  8264. * @function
  8265. * @description Short hand method to set fill to `transparent`.
  8266. */
  8267. noFill: function() {
  8268. this.fill = 'transparent';
  8269. return this;
  8270. },
  8271. /**
  8272. * @name Two.Text#noStroke
  8273. * @function
  8274. * @description Short hand method to set stroke to `transparent`.
  8275. */
  8276. noStroke: function() {
  8277. this.stroke = undefined;
  8278. this.linewidth = undefined;
  8279. return this;
  8280. },
  8281. // A shim to not break `getBoundingClientRect` calls.
  8282. // TODO: Implement a way to calculate proper bounding
  8283. // boxes of `Two.Text`.
  8284. /**
  8285. * @name Two.Text#getBoundingClientRect
  8286. * @function
  8287. * @param {Boolean} [shallow=false] - Describes whether to calculate off local matrix or world matrix.
  8288. * @returns {Object} - Returns object with top, left, right, bottom, width, height attributes.
  8289. * @description Return an object with top, left, right, bottom, width, and height parameters of the text object.
  8290. */
  8291. getBoundingClientRect: function(shallow) {
  8292. var matrix, a, b, c, d;
  8293. var left, right, top, bottom;
  8294. // TODO: Update this to not __always__ update. Just when it needs to.
  8295. this._update(true);
  8296. matrix = shallow ? this._matrix : getComputedMatrix(this);
  8297. var height = this.leading;
  8298. var width = this.value.length * this.size * Text.Ratio;
  8299. var border = (this._linewidth || 0) / 2;
  8300. switch (this.alignment) {
  8301. case 'left':
  8302. left = - border;
  8303. right = width + border;
  8304. break;
  8305. case 'right':
  8306. left = - (width + border);
  8307. right = border;
  8308. break;
  8309. default:
  8310. left = - (width / 2 + border);
  8311. right = width / 2 + border;
  8312. }
  8313. switch (this.baseline) {
  8314. case 'top':
  8315. top = - border;
  8316. bottom = height + border;
  8317. break;
  8318. case 'bottom':
  8319. top = - (height + border);
  8320. bottom = border;
  8321. break;
  8322. default:
  8323. top = - (height / 2 + border);
  8324. bottom = height / 2 + border;
  8325. }
  8326. a = matrix.multiply(left, top, 1);
  8327. b = matrix.multiply(left, bottom, 1);
  8328. c = matrix.multiply(right, top, 1);
  8329. d = matrix.multiply(right, bottom, 1);
  8330. top = min(a.y, b.y, c.y, d.y);
  8331. left = min(a.x, b.x, c.x, d.x);
  8332. right = max(a.x, b.x, c.x, d.x);
  8333. bottom = max(a.y, b.y, c.y, d.y);
  8334. return {
  8335. top: top,
  8336. left: left,
  8337. right: right,
  8338. bottom: bottom,
  8339. width: right - left,
  8340. height: bottom - top
  8341. };
  8342. },
  8343. /**
  8344. * @name Two.Text#flagReset
  8345. * @function
  8346. * @private
  8347. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  8348. */
  8349. flagReset: function() {
  8350. this._flagValue = this._flagFamily = this._flagSize =
  8351. this._flagLeading = this._flagAlignment = this._flagFill =
  8352. this._flagStroke = this._flagLinewidth = this._flagOpacity =
  8353. this._flagVisible = this._flagClip = this._flagDecoration =
  8354. this._flagClassName = this._flagBaseline = this._flagWeight =
  8355. this._flagStyle = false;
  8356. Shape.prototype.flagReset.call(this);
  8357. return this;
  8358. }
  8359. });
  8360. Text.MakeObservable(Text.prototype);
  8361. // https://github.com/jonobr1/two.js/issues/507#issuecomment-777159213
  8362. var regex = {
  8363. path: /[+-]?(?:\d*\.\d+|\d+)(?:[eE][+-]\d+)?/g
  8364. };
  8365. var alignments = {
  8366. start: 'left',
  8367. middle: 'center',
  8368. end: 'right'
  8369. };
  8370. /**
  8371. * @name Two.Utils.getAlignment
  8372. * @function
  8373. * @param {AlignmentString}
  8374. * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor}
  8375. */
  8376. var getAlignment = function(anchor) {
  8377. return alignments[anchor];
  8378. };
  8379. var getBaseline = function(node) {
  8380. var a = node.getAttribute('dominant-baseline');
  8381. var b = node.getAttribute('alignment-baseline');
  8382. return a || b;
  8383. };
  8384. var getTagName = function(tag) {
  8385. return tag.replace(/svg:/ig, '').toLowerCase();
  8386. };
  8387. var applyTransformsToVector = function(transforms, vector) {
  8388. vector.x += transforms.translateX;
  8389. vector.y += transforms.translateY;
  8390. vector.x *= transforms.scaleX;
  8391. vector.y *= transforms.scaleY;
  8392. if (transforms.rotation !== 0) {
  8393. // TODO: Test further
  8394. var l = vector.length();
  8395. vector.x = l * Math.cos(transforms.rotation);
  8396. vector.y = l * Math.sin(transforms.rotation);
  8397. }
  8398. };
  8399. /**
  8400. * @name Two.Utils.extractCSSText
  8401. * @function
  8402. * @param {String} text - The CSS text body to be parsed and extracted.
  8403. * @param {Object} [styles] - The styles object to apply CSS key values to.
  8404. * @returns {Object} styles
  8405. * @description Parse CSS text body and apply them as key value pairs to a JavaScript object.
  8406. */
  8407. var extractCSSText = function(text, styles) {
  8408. var commands, command, name, value;
  8409. if (!styles) {
  8410. styles = {};
  8411. }
  8412. commands = text.split(';');
  8413. for (var i = 0; i < commands.length; i++) {
  8414. command = commands[i].split(':');
  8415. name = command[0];
  8416. value = command[1];
  8417. if (typeof name === 'undefined' || typeof value === 'undefined') {
  8418. continue;
  8419. }
  8420. styles[name] = value.replace(/\s/, '');
  8421. }
  8422. return styles;
  8423. };
  8424. /**
  8425. * @name Two.Utils.getSvgStyles
  8426. * @function
  8427. * @param {SVGElement} node - The SVG node to parse.
  8428. * @returns {Object} styles
  8429. * @description Get the CSS comands from the `style` attribute of an SVG node and apply them as key value pairs to a JavaScript object.
  8430. */
  8431. var getSvgStyles = function(node) {
  8432. var styles = {};
  8433. var attributes = getSvgAttributes(node);
  8434. var length = Math.max(attributes.length, node.style.length);
  8435. for (var i = 0; i < length; i++) {
  8436. var command = node.style[i];
  8437. var attribute = attributes[i];
  8438. if (command) {
  8439. styles[command] = node.style[command];
  8440. }
  8441. if (attribute) {
  8442. styles[attribute] = node.getAttribute(attribute);
  8443. }
  8444. }
  8445. return styles;
  8446. };
  8447. var getSvgAttributes = function(node) {
  8448. var attributes = node.getAttributeNames();
  8449. // Reserved attributes to remove
  8450. var keywords = ['id', 'class', 'transform', 'xmlns', 'viewBox'];
  8451. for (var i = 0; i < keywords.length; i++) {
  8452. var keyword = keywords[i];
  8453. var index = Array.prototype.indexOf.call(attributes, keyword);
  8454. if (index >= 0) {
  8455. attributes.splice(index, 1);
  8456. }
  8457. }
  8458. return attributes;
  8459. };
  8460. /**
  8461. * @name Two.Utils.applySvgViewBox
  8462. * @function
  8463. * @param {Two.Shape} node - The Two.js object to apply viewbox matrix to
  8464. * @param {String} value - The viewBox value from the SVG attribute
  8465. * @returns {Two.Shape} node
  8466. * @description Applies the transform of the SVG Viewbox on a given node.
  8467. */
  8468. var applySvgViewBox = function(node, value) {
  8469. var elements = value.split(/\s/);
  8470. var x = parseFloat(elements[0]);
  8471. var y = parseFloat(elements[1]);
  8472. var width = parseFloat(elements[2]);
  8473. var height = parseFloat(elements[3]);
  8474. var s = Math.min(this.width / width, this.height / height);
  8475. node.translation.x -= x * s;
  8476. node.translation.y -= y * s;
  8477. node.scale = s;
  8478. return node;
  8479. };
  8480. /**
  8481. * @name Two.Utils.applySvgAttributes
  8482. * @function
  8483. * @param {SVGElement} node - An SVG Node to extrapolate attributes from.
  8484. * @param {Two.Shape} elem - The Two.js object to apply extrapolated attributes to.
  8485. * @returns {Two.Shape} The Two.js object passed now with applied attributes.
  8486. * @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.
  8487. * @TODO Reverse calculate {@link Two.Gradient}s for fill / stroke of any given path.
  8488. */
  8489. var applySvgAttributes = function(node, elem, parentStyles) {
  8490. var styles = {}, attributes = {}, extracted = {}, i, m, key, value, attr;
  8491. var transforms, x, y;
  8492. var id, scene, ref, tagName;
  8493. // Not available in non browser environments
  8494. if (root$1.getComputedStyle) {
  8495. // Convert CSSStyleDeclaration to a normal object
  8496. var computedStyles = root$1.getComputedStyle(node);
  8497. i = computedStyles.length;
  8498. while (i--) {
  8499. key = computedStyles[i];
  8500. value = computedStyles[key];
  8501. // Gecko returns undefined for unset properties
  8502. // Webkit returns the default value
  8503. if (typeof value !== 'undefined') {
  8504. styles[key] = value;
  8505. }
  8506. }
  8507. }
  8508. // Convert NodeMap to a normal object
  8509. for (i = 0; i < node.attributes.length; i++) {
  8510. attr = node.attributes[i];
  8511. if (/style/i.test(attr.nodeName)) {
  8512. extractCSSText(attr.value, extracted);
  8513. } else {
  8514. attributes[attr.nodeName] = attr.value;
  8515. }
  8516. }
  8517. // Getting the correct opacity is a bit tricky, since SVG path elements don't
  8518. // support opacity as an attribute, but you can apply it via CSS.
  8519. // So we take the opacity and set (stroke/fill)-opacity to the same value.
  8520. if (typeof styles.opacity !== 'undefined') {
  8521. styles['stroke-opacity'] = styles.opacity;
  8522. styles['fill-opacity'] = styles.opacity;
  8523. delete styles.opacity;
  8524. }
  8525. // Merge attributes and applied styles (attributes take precedence)
  8526. if (parentStyles) {
  8527. _.defaults(styles, parentStyles);
  8528. }
  8529. _.extend(styles, extracted, attributes);
  8530. // Similarly visibility is influenced by the value of both display and visibility.
  8531. // Calculate a unified value here which defaults to `true`.
  8532. styles.visible = !(typeof styles.display === 'undefined' && /none/i.test(styles.display))
  8533. || (typeof styles.visibility === 'undefined' && /hidden/i.test(styles.visibility));
  8534. // Now iterate the whole thing
  8535. for (key in styles) {
  8536. value = styles[key];
  8537. switch (key) {
  8538. case 'gradientTransform':
  8539. // TODO: Check this out https://github.com/paperjs/paper.js/blob/develop/src/svg/SvgImport.js#L315
  8540. if (/none/i.test(value)) break;
  8541. m = (node.gradientTransform && node.gradientTransform.baseVal && node.gradientTransform.baseVal.length > 0)
  8542. ? node.gradientTransform.baseVal[0].matrix
  8543. : (node.getCTM ? node.getCTM() : null);
  8544. if (m === null) break;
  8545. transforms = decomposeMatrix(m);
  8546. switch (elem._renderer.type) {
  8547. case 'linear-gradient':
  8548. applyTransformsToVector(transforms, elem.left);
  8549. applyTransformsToVector(transforms, elem.right);
  8550. break;
  8551. case 'radial-gradient':
  8552. elem.center.x += transforms.translateX;
  8553. elem.center.y += transforms.translateY;
  8554. elem.focal.x += transforms.translateX;
  8555. elem.focal.y += transforms.translateY;
  8556. elem.radius *= Math.max(transforms.scaleX, transforms.scaleY);
  8557. break;
  8558. }
  8559. break;
  8560. case 'transform':
  8561. // TODO: Check this out https://github.com/paperjs/paper.js/blob/develop/src/svg/SvgImport.js#L315
  8562. if (/none/i.test(value)) break;
  8563. m = (node.transform && node.transform.baseVal && node.transform.baseVal.length > 0)
  8564. ? node.transform.baseVal[0].matrix
  8565. : (node.getCTM ? node.getCTM() : null);
  8566. // Might happen when transform string is empty or not valid.
  8567. if (m === null) break;
  8568. if (Constants.AutoCalculateImportedMatrices) {
  8569. // Decompose and infer Two.js related properties.
  8570. transforms = decomposeMatrix(m);
  8571. elem.translation.set(transforms.translateX, transforms.translateY);
  8572. elem.rotation = Math.PI * (transforms.rotation / 180);
  8573. elem.scale = new Vector(transforms.scaleX, transforms.scaleY);
  8574. x = parseFloat((styles.x + '').replace('px'));
  8575. y = parseFloat((styles.y + '').replace('px'));
  8576. // Override based on attributes.
  8577. if (x) {
  8578. elem.translation.x = x;
  8579. }
  8580. if (y) {
  8581. elem.translation.y = y;
  8582. }
  8583. } else {
  8584. // Edit the underlying matrix and don't force an auto calc.
  8585. m = node.getCTM();
  8586. elem._matrix.manual = true;
  8587. elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f);
  8588. }
  8589. break;
  8590. case 'viewBox':
  8591. applySvgViewBox.call(this, elem, value);
  8592. break;
  8593. case 'visible':
  8594. if (elem instanceof Group) {
  8595. elem._visible = value;
  8596. break;
  8597. }
  8598. elem.visible = value;
  8599. break;
  8600. case 'stroke-linecap':
  8601. if (elem instanceof Group) {
  8602. elem._cap = value;
  8603. break;
  8604. }
  8605. elem.cap = value;
  8606. break;
  8607. case 'stroke-linejoin':
  8608. if (elem instanceof Group) {
  8609. elem._join = value;
  8610. break;
  8611. }
  8612. elem.join = value;
  8613. break;
  8614. case 'stroke-miterlimit':
  8615. if (elem instanceof Group) {
  8616. elem._miter = value;
  8617. break;
  8618. }
  8619. elem.miter = value;
  8620. break;
  8621. case 'stroke-width':
  8622. if (elem instanceof Group) {
  8623. elem._linewidth = parseFloat(value);
  8624. break;
  8625. }
  8626. elem.linewidth = parseFloat(value);
  8627. break;
  8628. case 'opacity':
  8629. case 'stroke-opacity':
  8630. case 'fill-opacity':
  8631. // Only apply styles to rendered shapes
  8632. // in the scene.
  8633. if (elem instanceof Group) {
  8634. elem._opacity = parseFloat(value);
  8635. break;
  8636. }
  8637. elem.opacity = parseFloat(value);
  8638. break;
  8639. case 'clip-path':
  8640. if (/url\(#.*\)/i.test(value)) {
  8641. id = value.replace(/url\(#(.*)\)/i, '$1');
  8642. if (read.defs.current && read.defs.current.contains(id)) {
  8643. ref = read.defs.current.get(id);
  8644. if (ref && ref.childNodes.length > 0) {
  8645. ref = ref.childNodes[0];
  8646. tagName = getTagName(ref.nodeName);
  8647. elem.mask = read[tagName].call(this, ref, {});
  8648. switch (elem._renderer.type) {
  8649. case 'path':
  8650. // The matrix here needs to change to insure that the object
  8651. // clipping is in the same coordinate space as the `elem`.
  8652. elem.position.add(elem.mask.position);
  8653. elem.mask.position.clear();
  8654. break;
  8655. }
  8656. }
  8657. }
  8658. }
  8659. break;
  8660. case 'fill':
  8661. case 'stroke':
  8662. if (elem instanceof Group) {
  8663. key = '_' + key;
  8664. }
  8665. if (/url\(#.*\)/i.test(value)) {
  8666. id = value.replace(/url\(#(.*)\)/i, '$1');
  8667. if (read.defs.current && read.defs.current.contains(id)) {
  8668. ref = read.defs.current.get(id);
  8669. tagName = getTagName(ref.nodeName);
  8670. ref = read[tagName].call(this, ref, {});
  8671. } else {
  8672. scene = getScene(this);
  8673. ref = scene.getById(id);
  8674. }
  8675. elem[key] = ref;
  8676. } else {
  8677. elem[key] = (/none/i.test(value)) ? 'transparent' : value;
  8678. }
  8679. break;
  8680. case 'id':
  8681. elem.id = value;
  8682. // Overwritten id for non-conflicts on same page SVG documents
  8683. // TODO: Make this non-descructive
  8684. node.id = value + '-' + Constants.Identifier + 'applied';
  8685. break;
  8686. case 'class':
  8687. case 'className':
  8688. elem.classList = value.split(' ');
  8689. break;
  8690. case 'x':
  8691. case 'y':
  8692. var ca = elem instanceof Gradient;
  8693. var cb = elem instanceof LinearGradient;
  8694. var cc = elem instanceof RadialGradient;
  8695. if (ca || cb || cc) {
  8696. break;
  8697. }
  8698. if (value.match('[a-z%]$') && !value.endsWith('px')) {
  8699. var error = new TwoError(
  8700. 'only pixel values are supported with the ' + key + ' attribute.');
  8701. console.warn(error.name, error.message);
  8702. }
  8703. elem.translation[key] = parseFloat(value);
  8704. break;
  8705. case 'font-family':
  8706. if (elem instanceof Text) {
  8707. elem.family = value;
  8708. }
  8709. break;
  8710. case 'font-size':
  8711. if (elem instanceof Text) {
  8712. elem.size = value;
  8713. }
  8714. break;
  8715. case 'font-weight':
  8716. if (elem instanceof Text) {
  8717. elem.weight = value;
  8718. }
  8719. break;
  8720. case 'font-style':
  8721. if (elem instanceof Text) {
  8722. elem.style = value;
  8723. }
  8724. break;
  8725. case 'text-decoration':
  8726. if (elem instanceof Text) {
  8727. elem.decoration = value;
  8728. }
  8729. break;
  8730. case 'line-height':
  8731. if (elem instanceof Text) {
  8732. elem.leading = value;
  8733. }
  8734. break;
  8735. }
  8736. }
  8737. return styles;
  8738. };
  8739. /**
  8740. * @name Two.Utils.updateDefsCache
  8741. * @function
  8742. * @param {SVGElement} node - The SVG Node with which to update the defs cache.
  8743. * @param {Object} Object - The defs cache to be updated.
  8744. * @description Update the cache of children of <defs /> tags.
  8745. */
  8746. var updateDefsCache = function(node, defsCache) {
  8747. for (var i = 0, l = node.childNodes.length; i < l; i++) {
  8748. var n = node.childNodes[i];
  8749. if (!n.id) continue;
  8750. var tagName = getTagName(node.nodeName);
  8751. if (tagName === '#text') continue;
  8752. defsCache.add(n.id, n);
  8753. }
  8754. };
  8755. /**
  8756. * @name Two.Utils.getScene
  8757. * @param {Two.Shape} node - The currently available object in the scenegraph.
  8758. * @returns {Group} - The highest order {@link Two.Group} in the scenegraph.
  8759. * @property {Function}
  8760. */
  8761. var getScene = function(node) {
  8762. while (node.parent) {
  8763. node = node.parent;
  8764. }
  8765. return node.scene;
  8766. };
  8767. /**
  8768. * @name Two.Utils.read
  8769. * @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.
  8770. */
  8771. var read = {
  8772. svg: function(node) {
  8773. var defs = read.defs.current = new Registry();
  8774. var elements = node.getElementsByTagName('defs');
  8775. for (var i = 0; i < elements.length; i++) {
  8776. updateDefsCache(elements[i], defs);
  8777. }
  8778. var svg = read.g.call(this, node);
  8779. // var viewBox = node.getAttribute('viewBox');
  8780. svg.defs = defs; // Export out the <defs /> for later use
  8781. // Utils.applySvgViewBox(svg, viewBox);
  8782. delete read.defs.current;
  8783. return svg;
  8784. },
  8785. defs: function(node) {
  8786. return null;
  8787. },
  8788. use: function(node, styles) {
  8789. var error;
  8790. var href = node.getAttribute('href') || node.getAttribute('xlink:href');
  8791. if (!href) {
  8792. error = new TwoError('encountered <use /> with no href.');
  8793. console.warn(error.name, error.message);
  8794. return null;
  8795. }
  8796. var id = href.slice(1);
  8797. if (!read.defs.current.contains(id)) {
  8798. error = new TwoError(
  8799. 'unable to find element for reference ' + href + '.');
  8800. console.warn(error.name, error.message);
  8801. return null;
  8802. }
  8803. var template = read.defs.current.get(id);
  8804. var fullNode = template.cloneNode(true);
  8805. var overwriteAttrs = ['x', 'y', 'width', 'height', 'href', 'xlink:href'];
  8806. for (var i = 0; i < node.attributes.length; i++) {
  8807. var attr = node.attributes[i];
  8808. var ca = overwriteAttrs.includes(attr.nodeName);
  8809. var cb = !fullNode.hasAttribute(attr.nodeName);
  8810. if (ca || cb) {
  8811. fullNode.setAttribute(attr.nodeName, attr.value);
  8812. }
  8813. }
  8814. var tagName = getTagName(fullNode.nodeName);
  8815. return read[tagName].call(this, fullNode, styles);
  8816. },
  8817. g: function(node, parentStyles) {
  8818. var styles;
  8819. var group = new Group();
  8820. applySvgAttributes.call(this, node, group, parentStyles);
  8821. this.add(group);
  8822. // Switched up order to inherit more specific styles
  8823. styles = getSvgStyles.call(this, node);
  8824. for (var i = 0, l = node.childNodes.length; i < l; i++) {
  8825. var n = node.childNodes[i];
  8826. var tag = n.nodeName;
  8827. if (!tag) return;
  8828. var tagName = getTagName(tag);
  8829. if (tagName in read) {
  8830. var o = read[tagName].call(group, n, styles);
  8831. if (!!o && !o.parent) {
  8832. group.add(o);
  8833. }
  8834. }
  8835. }
  8836. return group;
  8837. },
  8838. polygon: function(node, parentStyles) {
  8839. var points = node.getAttribute('points');
  8840. var verts = [];
  8841. points.replace(/(-?[\d.eE-]+)[,|\s](-?[\d.eE-]+)/g, function(match, p1, p2) {
  8842. verts.push(new Anchor(parseFloat(p1), parseFloat(p2)));
  8843. });
  8844. var poly = new Path(verts, true).noStroke();
  8845. poly.fill = 'black';
  8846. applySvgAttributes.call(this, node, poly, parentStyles);
  8847. return poly;
  8848. },
  8849. polyline: function(node, parentStyles) {
  8850. var poly = read.polygon.call(this, node, parentStyles);
  8851. poly.closed = false;
  8852. return poly;
  8853. },
  8854. path: function(node, parentStyles) {
  8855. var path = node.getAttribute('d');
  8856. var points = [];
  8857. var closed = false, relative = false;
  8858. if (path) {
  8859. // Create a Two.Path from the paths.
  8860. var coord = new Anchor();
  8861. var control, coords;
  8862. var commands = path.match(/[a-df-z][^a-df-z]*/ig);
  8863. var last = commands.length - 1;
  8864. // Split up polybeziers
  8865. _.each(commands.slice(0), function(command, i) {
  8866. var items = command.slice(1).trim().match(regex.path);
  8867. var type = command[0];
  8868. var lower = type.toLowerCase();
  8869. var bin, j, l, ct, times, result = [];
  8870. if (i === 0) {
  8871. commands = [];
  8872. }
  8873. switch (lower) {
  8874. case 'h':
  8875. case 'v':
  8876. if (items.length > 1) {
  8877. bin = 1;
  8878. }
  8879. break;
  8880. case 'm':
  8881. case 'l':
  8882. case 't':
  8883. if (items.length > 2) {
  8884. bin = 2;
  8885. }
  8886. break;
  8887. case 's':
  8888. case 'q':
  8889. if (items.length > 4) {
  8890. bin = 4;
  8891. }
  8892. break;
  8893. case 'c':
  8894. if (items.length > 6) {
  8895. bin = 6;
  8896. }
  8897. break;
  8898. case 'a':
  8899. if (items.length > 7) {
  8900. bin = 7;
  8901. }
  8902. break;
  8903. }
  8904. // This means we have a polybezier.
  8905. if (bin) {
  8906. for (j = 0, l = items.length, times = 0; j < l; j+=bin) {
  8907. ct = type;
  8908. if (times > 0) {
  8909. switch (type) {
  8910. case 'm':
  8911. ct = 'l';
  8912. break;
  8913. case 'M':
  8914. ct = 'L';
  8915. break;
  8916. }
  8917. }
  8918. result.push(ct + items.slice(j, j + bin).join(' '));
  8919. times++;
  8920. }
  8921. commands = Array.prototype.concat.apply(commands, result);
  8922. } else {
  8923. commands.push(command);
  8924. }
  8925. });
  8926. // Create the vertices for our Two.Path
  8927. _.each(commands, function(command, i) {
  8928. var result, x, y;
  8929. var type = command[0];
  8930. var lower = type.toLowerCase();
  8931. coords = command.slice(1).trim().match(regex.path);
  8932. relative = type === lower;
  8933. var x1, y1, x2, y2, x3, y3, x4, y4, reflection;
  8934. switch (lower) {
  8935. case 'z':
  8936. if (i >= last) {
  8937. closed = true;
  8938. } else {
  8939. x = coord.x;
  8940. y = coord.y;
  8941. result = new Anchor(
  8942. x, y,
  8943. undefined, undefined,
  8944. undefined, undefined,
  8945. Commands.close
  8946. );
  8947. // Make coord be the last `m` command
  8948. for (var j = points.length - 1; j >= 0; j--) {
  8949. var point = points[j];
  8950. if (/m/i.test(point.command)) {
  8951. coord = point;
  8952. break;
  8953. }
  8954. }
  8955. }
  8956. break;
  8957. case 'm':
  8958. case 'l':
  8959. control = undefined;
  8960. x = parseFloat(coords[0]);
  8961. y = parseFloat(coords[1]);
  8962. result = new Anchor(
  8963. x, y,
  8964. undefined, undefined,
  8965. undefined, undefined,
  8966. /m/i.test(lower) ? Commands.move : Commands.line
  8967. );
  8968. if (relative) {
  8969. result.addSelf(coord);
  8970. }
  8971. // result.controls.left.copy(result);
  8972. // result.controls.right.copy(result);
  8973. coord = result;
  8974. break;
  8975. case 'h':
  8976. case 'v':
  8977. var a = /h/i.test(lower) ? 'x' : 'y';
  8978. var b = /x/i.test(a) ? 'y' : 'x';
  8979. result = new Anchor(
  8980. undefined, undefined,
  8981. undefined, undefined,
  8982. undefined, undefined,
  8983. Commands.line
  8984. );
  8985. result[a] = parseFloat(coords[0]);
  8986. result[b] = coord[b];
  8987. if (relative) {
  8988. result[a] += coord[a];
  8989. }
  8990. // result.controls.left.copy(result);
  8991. // result.controls.right.copy(result);
  8992. coord = result;
  8993. break;
  8994. case 'c':
  8995. case 's':
  8996. x1 = coord.x;
  8997. y1 = coord.y;
  8998. if (!control) {
  8999. control = new Vector();//.copy(coord);
  9000. }
  9001. if (/c/i.test(lower)) {
  9002. x2 = parseFloat(coords[0]);
  9003. y2 = parseFloat(coords[1]);
  9004. x3 = parseFloat(coords[2]);
  9005. y3 = parseFloat(coords[3]);
  9006. x4 = parseFloat(coords[4]);
  9007. y4 = parseFloat(coords[5]);
  9008. } else {
  9009. // Calculate reflection control point for proper x2, y2
  9010. // inclusion.
  9011. reflection = getReflection(coord, control, relative);
  9012. x2 = reflection.x;
  9013. y2 = reflection.y;
  9014. x3 = parseFloat(coords[0]);
  9015. y3 = parseFloat(coords[1]);
  9016. x4 = parseFloat(coords[2]);
  9017. y4 = parseFloat(coords[3]);
  9018. }
  9019. if (relative) {
  9020. x2 += x1;
  9021. y2 += y1;
  9022. x3 += x1;
  9023. y3 += y1;
  9024. x4 += x1;
  9025. y4 += y1;
  9026. }
  9027. if (!_.isObject(coord.controls)) {
  9028. Anchor.AppendCurveProperties(coord);
  9029. }
  9030. coord.controls.right.set(x2 - coord.x, y2 - coord.y);
  9031. result = new Anchor(
  9032. x4, y4,
  9033. x3 - x4, y3 - y4,
  9034. undefined, undefined,
  9035. Commands.curve
  9036. );
  9037. coord = result;
  9038. control = result.controls.left;
  9039. break;
  9040. case 't':
  9041. case 'q':
  9042. x1 = coord.x;
  9043. y1 = coord.y;
  9044. if (!control) {
  9045. control = new Vector();
  9046. }
  9047. if (/q/i.test(lower)) {
  9048. x2 = parseFloat(coords[0]);
  9049. y2 = parseFloat(coords[1]);
  9050. x3 = parseFloat(coords[0]);
  9051. y3 = parseFloat(coords[1]);
  9052. x4 = parseFloat(coords[2]);
  9053. y4 = parseFloat(coords[3]);
  9054. } else {
  9055. reflection = getReflection(coord, control, relative);
  9056. x2 = reflection.x;
  9057. y2 = reflection.y;
  9058. x3 = reflection.x;
  9059. y3 = reflection.y;
  9060. x4 = parseFloat(coords[0]);
  9061. y4 = parseFloat(coords[1]);
  9062. }
  9063. if (relative) {
  9064. x2 += x1;
  9065. y2 += y1;
  9066. x3 += x1;
  9067. y3 += y1;
  9068. x4 += x1;
  9069. y4 += y1;
  9070. }
  9071. if (!_.isObject(coord.controls)) {
  9072. Anchor.AppendCurveProperties(coord);
  9073. }
  9074. coord.controls.right.set(
  9075. (x2 - coord.x) * 0.33, (y2 - coord.y) * 0.33);
  9076. result = new Anchor(
  9077. x4, y4,
  9078. x3 - x4, y3 - y4,
  9079. undefined, undefined,
  9080. Commands.curve
  9081. );
  9082. coord = result;
  9083. control = result.controls.left;
  9084. break;
  9085. case 'a':
  9086. x1 = coord.x;
  9087. y1 = coord.y;
  9088. var rx = parseFloat(coords[0]);
  9089. var ry = parseFloat(coords[1]);
  9090. var xAxisRotation = parseFloat(coords[2]);// * PI / 180;
  9091. var largeArcFlag = parseFloat(coords[3]);
  9092. var sweepFlag = parseFloat(coords[4]);
  9093. x4 = parseFloat(coords[5]);
  9094. y4 = parseFloat(coords[6]);
  9095. if (relative) {
  9096. x4 += x1;
  9097. y4 += y1;
  9098. }
  9099. var anchor = new Anchor(x4, y4);
  9100. anchor.command = Commands.arc;
  9101. anchor.rx = rx;
  9102. anchor.ry = ry;
  9103. anchor.xAxisRotation = xAxisRotation;
  9104. anchor.largeArcFlag = largeArcFlag;
  9105. anchor.sweepFlag = sweepFlag;
  9106. result = anchor;
  9107. coord = anchor;
  9108. control = undefined;
  9109. break;
  9110. }
  9111. if (result) {
  9112. if (Array.isArray(result)) {
  9113. points = points.concat(result);
  9114. } else {
  9115. points.push(result);
  9116. }
  9117. }
  9118. });
  9119. }
  9120. path = new Path(points, closed, undefined, true).noStroke();
  9121. path.fill = 'black';
  9122. var rect = path.getBoundingClientRect(true);
  9123. // Center objects to stay consistent
  9124. // with the rest of the Two.js API.
  9125. rect.centroid = {
  9126. x: rect.left + rect.width / 2,
  9127. y: rect.top + rect.height / 2
  9128. };
  9129. _.each(path.vertices, function(v) {
  9130. v.subSelf(rect.centroid);
  9131. });
  9132. applySvgAttributes.call(this, node, path, parentStyles);
  9133. path.translation.addSelf(rect.centroid);
  9134. return path;
  9135. },
  9136. circle: function(node, parentStyles) {
  9137. var x = parseFloat(node.getAttribute('cx'));
  9138. var y = parseFloat(node.getAttribute('cy'));
  9139. var r = parseFloat(node.getAttribute('r'));
  9140. var circle = new Circle(0, 0, r).noStroke();
  9141. circle.fill = 'black';
  9142. applySvgAttributes.call(this, node, circle, parentStyles);
  9143. circle.translation.x = x;
  9144. circle.translation.y = y;
  9145. return circle;
  9146. },
  9147. ellipse: function(node, parentStyles) {
  9148. var x = parseFloat(node.getAttribute('cx'));
  9149. var y = parseFloat(node.getAttribute('cy'));
  9150. var width = parseFloat(node.getAttribute('rx'));
  9151. var height = parseFloat(node.getAttribute('ry'));
  9152. var ellipse = new Ellipse(0, 0, width, height).noStroke();
  9153. ellipse.fill = 'black';
  9154. applySvgAttributes.call(this, node, ellipse, parentStyles);
  9155. ellipse.translation.x = x;
  9156. ellipse.translation.y = y;
  9157. return ellipse;
  9158. },
  9159. rect: function(node, parentStyles) {
  9160. var rx = parseFloat(node.getAttribute('rx'));
  9161. var ry = parseFloat(node.getAttribute('ry'));
  9162. if (!_.isNaN(rx) || !_.isNaN(ry)) {
  9163. return read['rounded-rect'](node);
  9164. }
  9165. var width = parseFloat(node.getAttribute('width'));
  9166. var height = parseFloat(node.getAttribute('height'));
  9167. var w2 = width / 2;
  9168. var h2 = height / 2;
  9169. var rect = new Rectangle(0, 0, width, height)
  9170. .noStroke();
  9171. rect.fill = 'black';
  9172. applySvgAttributes.call(this, node, rect, parentStyles);
  9173. // For rectangles, (x, y) is the center of the shape rather than the top
  9174. // left corner.
  9175. rect.translation.x += w2;
  9176. rect.translation.y += h2;
  9177. return rect;
  9178. },
  9179. 'rounded-rect': function(node, parentStyles) {
  9180. var rx = parseFloat(node.getAttribute('rx')) || 0;
  9181. var ry = parseFloat(node.getAttribute('ry')) || 0;
  9182. var width = parseFloat(node.getAttribute('width'));
  9183. var height = parseFloat(node.getAttribute('height'));
  9184. var w2 = width / 2;
  9185. var h2 = height / 2;
  9186. var radius = new Vector(rx, ry);
  9187. var rect = new RoundedRectangle(0, 0, width, height, radius)
  9188. .noStroke();
  9189. rect.fill = 'black';
  9190. applySvgAttributes.call(this, node, rect, parentStyles);
  9191. // For rectangles, (x, y) is the center of the shape rather than the top
  9192. // left corner.
  9193. rect.translation.x += w2;
  9194. rect.translation.y += h2;
  9195. return rect;
  9196. },
  9197. line: function(node, parentStyles) {
  9198. var x1 = parseFloat(node.getAttribute('x1'));
  9199. var y1 = parseFloat(node.getAttribute('y1'));
  9200. var x2 = parseFloat(node.getAttribute('x2'));
  9201. var y2 = parseFloat(node.getAttribute('y2'));
  9202. var line = new Line(x1, y1, x2, y2).noFill();
  9203. applySvgAttributes.call(this, node, line, parentStyles);
  9204. return line;
  9205. },
  9206. lineargradient: function(node, parentStyles) {
  9207. var x1 = parseFloat(node.getAttribute('x1'));
  9208. var y1 = parseFloat(node.getAttribute('y1'));
  9209. var x2 = parseFloat(node.getAttribute('x2'));
  9210. var y2 = parseFloat(node.getAttribute('y2'));
  9211. var ox = (x2 + x1) / 2;
  9212. var oy = (y2 + y1) / 2;
  9213. var stops = [];
  9214. for (var i = 0; i < node.children.length; i++) {
  9215. var child = node.children[i];
  9216. var offset = child.getAttribute('offset');
  9217. if (/%/ig.test(offset)) {
  9218. offset = parseFloat(offset.replace(/%/ig, '')) / 100;
  9219. }
  9220. offset = parseFloat(offset);
  9221. var color = child.getAttribute('stop-color');
  9222. var opacity = child.getAttribute('stop-opacity');
  9223. var style = child.getAttribute('style');
  9224. var matches;
  9225. if (color === null) {
  9226. matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
  9227. color = matches && matches.length > 1 ? matches[1] : undefined;
  9228. }
  9229. if (opacity === null) {
  9230. matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
  9231. opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  9232. } else {
  9233. opacity = parseFloat(opacity);
  9234. }
  9235. stops.push(new Stop(offset, color, opacity));
  9236. }
  9237. var gradient = new LinearGradient(x1 - ox, y1 - oy, x2 - ox,
  9238. y2 - oy, stops);
  9239. applySvgAttributes.call(this, node, gradient, parentStyles);
  9240. return gradient;
  9241. },
  9242. radialgradient: function(node, parentStyles) {
  9243. var cx = parseFloat(node.getAttribute('cx')) || 0;
  9244. var cy = parseFloat(node.getAttribute('cy')) || 0;
  9245. var r = parseFloat(node.getAttribute('r'));
  9246. var fx = parseFloat(node.getAttribute('fx'));
  9247. var fy = parseFloat(node.getAttribute('fy'));
  9248. if (_.isNaN(fx)) {
  9249. fx = cx;
  9250. }
  9251. if (_.isNaN(fy)) {
  9252. fy = cy;
  9253. }
  9254. var ox = Math.abs(cx + fx) / 2;
  9255. var oy = Math.abs(cy + fy) / 2;
  9256. var stops = [];
  9257. for (var i = 0; i < node.children.length; i++) {
  9258. var child = node.children[i];
  9259. var offset = child.getAttribute('offset');
  9260. if (/%/ig.test(offset)) {
  9261. offset = parseFloat(offset.replace(/%/ig, '')) / 100;
  9262. }
  9263. offset = parseFloat(offset);
  9264. var color = child.getAttribute('stop-color');
  9265. var opacity = child.getAttribute('stop-opacity');
  9266. var style = child.getAttribute('style');
  9267. var matches;
  9268. if (color === null) {
  9269. matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
  9270. color = matches && matches.length > 1 ? matches[1] : undefined;
  9271. }
  9272. if (opacity === null) {
  9273. matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
  9274. opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
  9275. } else {
  9276. opacity = parseFloat(opacity);
  9277. }
  9278. stops.push(new Stop(offset, color, opacity));
  9279. }
  9280. var gradient = new RadialGradient(cx - ox, cy - oy, r,
  9281. stops, fx - ox, fy - oy);
  9282. applySvgAttributes.call(this, node, gradient, parentStyles);
  9283. return gradient;
  9284. },
  9285. text: function(node, parentStyles) {
  9286. var alignment = getAlignment(node.getAttribute('text-anchor')) || 'left';
  9287. var baseline = getBaseline(node) || 'baseline';
  9288. var message = node.textContent;
  9289. var text = new Text(message);
  9290. applySvgAttributes.call(this, node, text, parentStyles);
  9291. text.alignment = alignment;
  9292. text.baseline = baseline;
  9293. return text;
  9294. },
  9295. clippath: function(node, parentStyles) {
  9296. if (read.defs.current && !read.defs.current.contains(node.id)) {
  9297. read.defs.current.add(node.id, node);
  9298. }
  9299. return null;
  9300. },
  9301. image: function(node, parentStyles) {
  9302. var href = node.getAttribute('href') || node.getAttribute('xlink:href');
  9303. if (!href) {
  9304. var error = new TwoError('encountered <image /> with no href.');
  9305. console.warn(error.name, error.message);
  9306. return null;
  9307. }
  9308. var x = parseFloat(node.getAttribute('x')) || 0;
  9309. var y = parseFloat(node.getAttribute('y')) || 0;
  9310. var width = parseFloat(node.getAttribute('width'));
  9311. var height = parseFloat(node.getAttribute('height'));
  9312. var sprite = new Sprite(href, x, y);
  9313. if (!_.isNaN(width)) {
  9314. sprite.width = width;
  9315. }
  9316. if (!_.isNaN(height)) {
  9317. sprite.height = height;
  9318. }
  9319. applySvgAttributes.call(this, node, sprite, parentStyles);
  9320. return sprite;
  9321. }
  9322. };
  9323. /**
  9324. * @name Two.Utils.xhr
  9325. * @function
  9326. * @param {String} path
  9327. * @param {Function} callback
  9328. * @returns {XMLHttpRequest} The constructed and called XHR request.
  9329. * @description Canonical method to initiate `GET` requests in the browser. Mainly used by {@link Two#load} method.
  9330. */
  9331. function xhr(path, callback) {
  9332. var xhr = new XMLHttpRequest();
  9333. xhr.open('GET', path);
  9334. xhr.onreadystatechange = function() {
  9335. if (xhr.readyState === 4 && xhr.status === 200) {
  9336. callback(xhr.responseText);
  9337. }
  9338. };
  9339. xhr.send();
  9340. return xhr;
  9341. }
  9342. /**
  9343. * @name Two.ImageSequence
  9344. * @class
  9345. * @extends Two.Rectangle
  9346. * @param {String|String[]|Two.Texture|Two.Texture[]} paths - A list of URLs or {@link Two.Texture}s.
  9347. * @param {Number} [ox=0] - The initial `x` position of the Two.ImageSequence.
  9348. * @param {Number} [oy=0] - The initial `y` position of the Two.ImageSequence.
  9349. * @param {Number} [frameRate=30] - The frame rate at which the images should playback at.
  9350. * @description A convenient package to display still or animated images organized as a series of still images.
  9351. */
  9352. function ImageSequence(paths, ox, oy, frameRate) {
  9353. // Not using default constructor of Rectangle due to odd `beginning` / `ending` behavior.
  9354. // See: https://github.com/jonobr1/two.js/issues/383
  9355. Path.call(this, [
  9356. new Anchor(),
  9357. new Anchor(),
  9358. new Anchor(),
  9359. new Anchor()
  9360. ], true);
  9361. this._renderer.flagTextures = ImageSequence.FlagTextures.bind(this);
  9362. this._renderer.bindTextures = ImageSequence.BindTextures.bind(this);
  9363. this._renderer.unbindTextures = ImageSequence.UnbindTextures.bind(this);
  9364. this.noStroke();
  9365. this.noFill();
  9366. /**
  9367. * @name Two.ImageSequence#textures
  9368. * @property {Two.Texture[]} - A list of textures to be used as frames for animating the {@link Two.ImageSequence}.
  9369. */
  9370. if (Array.isArray(paths)) {
  9371. this.textures = paths.map(ImageSequence.GenerateTexture.bind(this));
  9372. } else {
  9373. // If just a single path convert into a single Two.Texture
  9374. this.textures = [ImageSequence.GenerateTexture(paths)];
  9375. }
  9376. this.origin = new Vector();
  9377. this._update();
  9378. this.translation.set(ox || 0, oy || 0);
  9379. /**
  9380. * @name Two.ImageSequence#frameRate
  9381. * @property {Number} - The number of frames to animate against per second.
  9382. */
  9383. if (typeof frameRate === 'number') {
  9384. this.frameRate = frameRate;
  9385. } else {
  9386. this.frameRate = ImageSequence.DefaultFrameRate;
  9387. }
  9388. /**
  9389. * @name Two.ImageSequence#index
  9390. * @property {Number} - The index of the current tile of the sprite to display. Defaults to `0`.
  9391. */
  9392. this.index = 0;
  9393. }
  9394. _.extend(ImageSequence, {
  9395. /**
  9396. * @name Two.ImageSequence.Properties
  9397. * @property {String[]} - A list of properties that are on every {@link Two.ImageSequence}.
  9398. */
  9399. Properties: [
  9400. 'frameRate',
  9401. 'index'
  9402. ],
  9403. /**
  9404. * @name Two.ImageSequence.DefaultFrameRate
  9405. * @property The default frame rate that {@link Two.ImageSequence#frameRate} is set to when instantiated.
  9406. */
  9407. DefaultFrameRate: 30,
  9408. /**
  9409. * @name Two.ImageSequence.FlagTextures
  9410. * @function
  9411. * @description Cached method to let renderers know textures have been updated on a {@link Two.ImageSequence}.
  9412. */
  9413. FlagTextures: function() {
  9414. this._flagTextures = true;
  9415. },
  9416. /**
  9417. * @name Two.ImageSequence.BindTextures
  9418. * @function
  9419. * @description Cached method to let {@link Two.ImageSequence} know textures have been added to the instance.
  9420. */
  9421. BindTextures: function(items) {
  9422. var i = items.length;
  9423. while (i--) {
  9424. items[i].bind(Events.Types.change, this._renderer.flagTextures);
  9425. }
  9426. this._renderer.flagTextures();
  9427. },
  9428. /**
  9429. * @name Two.ImageSequence.UnbindVertices
  9430. * @function
  9431. * @description Cached method to let {@link Two.ImageSequence} know textures have been removed from the instance.
  9432. */
  9433. UnbindTextures: function(items) {
  9434. var i = items.length;
  9435. while (i--) {
  9436. items[i].unbind(Events.Types.change, this._renderer.flagTextures);
  9437. }
  9438. this._renderer.flagTextures();
  9439. },
  9440. /**
  9441. * @name Two.ImageSequence.MakeObservable
  9442. * @function
  9443. * @param {Object} object - The object to make observable.
  9444. * @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.
  9445. */
  9446. MakeObservable: function(obj) {
  9447. Rectangle.MakeObservable(obj);
  9448. _.each(ImageSequence.Properties, defineGetterSetter, obj);
  9449. Object.defineProperty(obj, 'textures', {
  9450. enumerable: true,
  9451. get: function() {
  9452. return this._textures;
  9453. },
  9454. set: function(textures) {
  9455. var bindTextures = this._renderer.bindTextures;
  9456. var unbindTextures = this._renderer.unbindTextures;
  9457. // Remove previous listeners
  9458. if (this._textures) {
  9459. this._textures
  9460. .unbind(Events.Types.insert, bindTextures)
  9461. .unbind(Events.Types.remove, unbindTextures);
  9462. }
  9463. // Create new Collection with copy of vertices
  9464. this._textures = new Collection((textures || []).slice(0));
  9465. // Listen for Collection changes and bind / unbind
  9466. this._textures
  9467. .bind(Events.Types.insert, bindTextures)
  9468. .bind(Events.Types.remove, unbindTextures);
  9469. // Bind Initial Textures
  9470. bindTextures(this._textures);
  9471. }
  9472. });
  9473. },
  9474. /**
  9475. * @name Two.ImageSequence.GenerateTexture
  9476. * @property {Function} - Shorthand function to prepare source image material into readable format by {@link Two.ImageSequence}.
  9477. * @param {String|Two.Texture} textureOrString - The texture or string to create a {@link Two.Texture} from.
  9478. * @description Function used internally by {@link Two.ImageSequence} to parse arguments and return {@link Two.Texture}s.
  9479. * @returns {Two.Texture}
  9480. */
  9481. GenerateTexture: function(obj) {
  9482. if (obj instanceof Texture) {
  9483. return obj;
  9484. } else if (typeof obj === 'string') {
  9485. return new Texture(obj);
  9486. }
  9487. }
  9488. });
  9489. _.extend(ImageSequence.prototype, Rectangle.prototype, {
  9490. constructor: ImageSequence,
  9491. /**
  9492. * @name Two.ImageSequence#_flagTextures
  9493. * @private
  9494. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#textures} need updating.
  9495. */
  9496. _flagTextures: false,
  9497. /**
  9498. * @name Two.ImageSequence#_flagFrameRate
  9499. * @private
  9500. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#frameRate} needs updating.
  9501. */
  9502. _flagFrameRate: false,
  9503. /**
  9504. * @name Two.ImageSequence#_flagIndex
  9505. * @private
  9506. * @property {Boolean} - Determines whether the {@link Two.ImageSequence#index} needs updating.
  9507. */
  9508. _flagIndex: false,
  9509. // Private variables
  9510. /**
  9511. * @name Two.ImageSequence#_amount
  9512. * @private
  9513. * @property {Number} - Number of frames for a given {@link Two.ImageSequence}.
  9514. */
  9515. _amount: 1,
  9516. /**
  9517. * @name Two.ImageSequence#_duration
  9518. * @private
  9519. * @property {Number} - Number of milliseconds a {@link Two.ImageSequence}.
  9520. */
  9521. _duration: 0,
  9522. /**
  9523. * @name Two.ImageSequence#_index
  9524. * @private
  9525. * @property {Number} - The current frame the {@link Two.ImageSequence} is currently displaying.
  9526. */
  9527. _index: 0,
  9528. /**
  9529. * @name Two.ImageSequence#_startTime
  9530. * @private
  9531. * @property {Milliseconds} - Epoch time in milliseconds of when the {@link Two.ImageSequence} started.
  9532. */
  9533. _startTime: 0,
  9534. /**
  9535. * @name Two.ImageSequence#_playing
  9536. * @private
  9537. * @property {Boolean} - Dictates whether the {@link Two.ImageSequence} is animating or not.
  9538. */
  9539. _playing: false,
  9540. /**
  9541. * @name Two.ImageSequence#_firstFrame
  9542. * @private
  9543. * @property {Number} - The frame the {@link Two.ImageSequence} should start with.
  9544. */
  9545. _firstFrame: 0,
  9546. /**
  9547. * @name Two.ImageSequence#_lastFrame
  9548. * @private
  9549. * @property {Number} - The frame the {@link Two.ImageSequence} should end with.
  9550. */
  9551. _lastFrame: 0,
  9552. /**
  9553. * @name Two.ImageSequence#_playing
  9554. * @private
  9555. * @property {Boolean} - Dictates whether the {@link Two.ImageSequence} should loop or not.
  9556. */
  9557. _loop: true,
  9558. // Exposed through getter-setter
  9559. /**
  9560. * @name Two.ImageSequence#_textures
  9561. * @private
  9562. * @see {@link Two.ImageSequence#textures}
  9563. */
  9564. _textures: null,
  9565. /**
  9566. * @name Two.ImageSequence#_frameRate
  9567. * @private
  9568. * @see {@link Two.ImageSequence#frameRate}
  9569. */
  9570. _frameRate: 0,
  9571. /**
  9572. * @name Two.ImageSequence#_origin
  9573. * @private
  9574. * @see {@link Two.ImageSequence#origin}
  9575. */
  9576. _origin: null,
  9577. /**
  9578. * @name Two.ImageSequence#play
  9579. * @function
  9580. * @param {Number} [firstFrame=0] - The index of the frame to start the animation with.
  9581. * @param {Number} [lastFrame] - The index of the frame to end the animation with. Defaults to the last item in the {@link Two.ImageSequence#textures}.
  9582. * @param {Function} [onLastFrame] - Optional callback function to be triggered after playing the last frame. This fires multiple times when the image sequence is looped.
  9583. * @description Initiate animation playback of a {@link Two.ImageSequence}.
  9584. */
  9585. play: function(firstFrame, lastFrame, onLastFrame) {
  9586. this._playing = true;
  9587. this._firstFrame = 0;
  9588. this._lastFrame = this.amount - 1;
  9589. this._startTime = _.performance.now();
  9590. if (typeof firstFrame === 'number') {
  9591. this._firstFrame = firstFrame;
  9592. }
  9593. if (typeof lastFrame === 'number') {
  9594. this._lastFrame = lastFrame;
  9595. }
  9596. if (typeof onLastFrame === 'function') {
  9597. this._onLastFrame = onLastFrame;
  9598. } else {
  9599. delete this._onLastFrame;
  9600. }
  9601. if (this._index !== this._firstFrame) {
  9602. this._startTime -= 1000 * Math.abs(this._index - this._firstFrame)
  9603. / this._frameRate;
  9604. }
  9605. return this;
  9606. },
  9607. /**
  9608. * @name Two.ImageSequence#pause
  9609. * @function
  9610. * @description Halt animation playback of a {@link Two.ImageSequence}.
  9611. */
  9612. pause: function() {
  9613. this._playing = false;
  9614. return this;
  9615. },
  9616. /**
  9617. * @name Two.ImageSequence#stop
  9618. * @function
  9619. * @description Halt animation playback of a {@link Two.ImageSequence} and set the current frame back to the first frame.
  9620. */
  9621. stop: function() {
  9622. this._playing = false;
  9623. this._index = this._firstFrame;
  9624. return this;
  9625. },
  9626. /**
  9627. * @name Two.ImageSequence#clone
  9628. * @function
  9629. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  9630. * @returns {Two.ImageSequence}
  9631. * @description Create a new instance of {@link Two.ImageSequence} with the same properties of the current image sequence.
  9632. */
  9633. clone: function(parent) {
  9634. var clone = new ImageSequence(this.textures, this.translation.x,
  9635. this.translation.y, this.frameRate);
  9636. clone._loop = this._loop;
  9637. if (this._playing) {
  9638. clone.play();
  9639. }
  9640. if (parent) {
  9641. parent.add(clone);
  9642. }
  9643. return clone;
  9644. },
  9645. /**
  9646. * @name Two.ImageSequence#toObject
  9647. * @function
  9648. * @returns {Object}
  9649. * @description Return a JSON compatible plain object that represents the path.
  9650. */
  9651. toObject: function() {
  9652. var object = Rectangle.prototype.toObject.call(this);
  9653. object.textures = this.textures.map(function(texture) {
  9654. return texture.toObject();
  9655. });
  9656. object.frameRate = this.frameRate;
  9657. object.index = this.index;
  9658. object._firstFrame = this._firstFrame;
  9659. object._lastFrame = this._lastFrame;
  9660. object._loop = this._loop;
  9661. return object;
  9662. },
  9663. /**
  9664. * @name Two.ImageSequence#_update
  9665. * @function
  9666. * @private
  9667. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  9668. * @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.
  9669. * @nota-bene Try not to call this method more than once a frame.
  9670. */
  9671. _update: function() {
  9672. var effects = this._textures;
  9673. var width, height, elapsed, amount, duration, texture;
  9674. var index, frames;
  9675. if (this._flagTextures) {
  9676. this._amount = effects.length;
  9677. }
  9678. if (this._flagFrameRate) {
  9679. this._duration = 1000 * this._amount / this._frameRate;
  9680. }
  9681. if (this._playing && this._frameRate > 0) {
  9682. amount = this._amount;
  9683. if (_.isNaN(this._lastFrame)) {
  9684. this._lastFrame = amount - 1;
  9685. }
  9686. // TODO: Offload perf logic to instance of `Two`.
  9687. elapsed = _.performance.now() - this._startTime;
  9688. frames = this._lastFrame + 1;
  9689. duration = 1000 * (frames - this._firstFrame) / this._frameRate;
  9690. if (this._loop) {
  9691. elapsed = elapsed % duration;
  9692. } else {
  9693. elapsed = Math.min(elapsed, duration);
  9694. }
  9695. index = lerp(this._firstFrame, frames, elapsed / duration);
  9696. index = Math.floor(index);
  9697. if (index !== this._index) {
  9698. this._index = index;
  9699. texture = effects[this._index];
  9700. if (texture.loaded) {
  9701. width = texture.image.width;
  9702. height = texture.image.height;
  9703. if (this.width !== width) {
  9704. this.width = width;
  9705. }
  9706. if (this.height !== height) {
  9707. this.height = height;
  9708. }
  9709. this.fill = texture;
  9710. if (index >= this._lastFrame - 1 && this._onLastFrame) {
  9711. this._onLastFrame(); // Shortcut for chainable sprite animations
  9712. }
  9713. }
  9714. }
  9715. } else if (this._flagIndex || !(this.fill instanceof Texture)) {
  9716. texture = effects[this._index];
  9717. if (texture.loaded) {
  9718. width = texture.image.width;
  9719. height = texture.image.height;
  9720. if (this.width !== width) {
  9721. this.width = width;
  9722. }
  9723. if (this.height !== height) {
  9724. this.height = height;
  9725. }
  9726. }
  9727. this.fill = texture;
  9728. }
  9729. Rectangle.prototype._update.call(this);
  9730. return this;
  9731. },
  9732. /**
  9733. * @name Two.ImageSequence#flagReset
  9734. * @function
  9735. * @private
  9736. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  9737. */
  9738. flagReset: function() {
  9739. this._flagTextures = this._flagFrameRate = false;
  9740. Rectangle.prototype.flagReset.call(this);
  9741. return this;
  9742. }
  9743. });
  9744. ImageSequence.MakeObservable(ImageSequence.prototype);
  9745. var TWO_PI$2 = Math.PI * 2, HALF_PI = Math.PI / 2;
  9746. /**
  9747. * @name Two.ArcSegment
  9748. * @class
  9749. * @extends Two.Path
  9750. * @param {Number} [x=0] - The x position of the arc segment.
  9751. * @param {Number} [y=0] - The y position of the arc segment.
  9752. * @param {Number} [innerRadius=0] - The inner radius value of the arc segment.
  9753. * @param {Number} [outerRadius=0] - The outer radius value of the arc segment.
  9754. * @param {Number} [startAngle=0] - The start angle of the arc segment in Number.
  9755. * @param {Number} [endAngle=6.2831] - The end angle of the arc segment in Number.
  9756. * @param {Number} [resolution=24] - The number of vertices used to construct the arc segment.
  9757. */
  9758. function ArcSegment(ox, oy, ir, or, sa, ea, res) {
  9759. var amount = res || (Constants.Resolution * 3);
  9760. var points = [];
  9761. for (var i = 0; i < amount; i++) {
  9762. points.push(new Anchor());
  9763. }
  9764. Path.call(this, points, true, false, true);
  9765. /**
  9766. * @name Two.ArcSegment#innerRadius
  9767. * @property {Number} - The size of the inner radius of the arc segment.
  9768. */
  9769. if (typeof ir === 'number') {
  9770. this.innerRadius = ir;
  9771. }
  9772. /**
  9773. * @name Two.ArcSegment#outerRadius
  9774. * @property {Number} - The size of the outer radius of the arc segment.
  9775. */
  9776. if (typeof or === 'number') {
  9777. this.outerRadius = or;
  9778. }
  9779. /**
  9780. * @name Two.ArcSegment#startRadius
  9781. * @property {Number} - The angle of one side for the arc segment.
  9782. */
  9783. if (typeof sa === 'number') {
  9784. this.startAngle = sa;
  9785. }
  9786. /**
  9787. * @name Two.ArcSegment#endAngle
  9788. * @property {Number} - The angle of the other side for the arc segment.
  9789. */
  9790. if (typeof ea === 'number') {
  9791. this.endAngle = ea;
  9792. }
  9793. this._update();
  9794. if (typeof ox === 'number') {
  9795. this.translation.x = ox;
  9796. }
  9797. if (typeof oy === 'number') {
  9798. this.translation.y = oy;
  9799. }
  9800. }
  9801. _.extend(ArcSegment, {
  9802. /**
  9803. * @name Two.ArcSegment.Properties
  9804. * @property {String[]} - A list of properties that are on every {@link Two.ArcSegment}.
  9805. */
  9806. Properties: ['startAngle', 'endAngle', 'innerRadius', 'outerRadius'],
  9807. /**
  9808. * @name Two.ArcSegment.MakeObservable
  9809. * @function
  9810. * @param {Object} object - The object to make observable.
  9811. * @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.
  9812. */
  9813. MakeObservable: function(obj) {
  9814. Path.MakeObservable(obj);
  9815. _.each(ArcSegment.Properties, defineGetterSetter, obj);
  9816. }
  9817. });
  9818. _.extend(ArcSegment.prototype, Path.prototype, {
  9819. constructor: ArcSegment,
  9820. /**
  9821. * @name Two.ArcSegment#_flagStartAngle
  9822. * @private
  9823. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#startAngle} needs updating.
  9824. */
  9825. _flagStartAngle: false,
  9826. /**
  9827. * @name Two.ArcSegment#_flagEndAngle
  9828. * @private
  9829. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#endAngle} needs updating.
  9830. */
  9831. _flagEndAngle: false,
  9832. /**
  9833. * @name Two.ArcSegment#_flagInnerRadius
  9834. * @private
  9835. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#innerRadius} needs updating.
  9836. */
  9837. _flagInnerRadius: false,
  9838. /**
  9839. * @name Two.ArcSegment#_flagOuterRadius
  9840. * @private
  9841. * @property {Boolean} - Determines whether the {@link Two.ArcSegment#outerRadius} needs updating.
  9842. */
  9843. _flagOuterRadius: false,
  9844. /**
  9845. * @name Two.ArcSegment#_startAngle
  9846. * @private
  9847. * @see {@link Two.ArcSegment#startAngle}
  9848. */
  9849. _startAngle: 0,
  9850. /**
  9851. * @name Two.ArcSegment#_endAngle
  9852. * @private
  9853. * @see {@link Two.ArcSegment#endAngle}
  9854. */
  9855. _endAngle: TWO_PI$2,
  9856. /**
  9857. * @name Two.ArcSegment#_innerRadius
  9858. * @private
  9859. * @see {@link Two.ArcSegment#innerRadius}
  9860. */
  9861. _innerRadius: 0,
  9862. /**
  9863. * @name Two.ArcSegment#_outerRadius
  9864. * @private
  9865. * @see {@link Two.ArcSegment#outerRadius}
  9866. */
  9867. _outerRadius: 0,
  9868. /**
  9869. * @name Two.ArcSegment#_update
  9870. * @function
  9871. * @private
  9872. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  9873. * @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.
  9874. * @nota-bene Try not to call this method more than once a frame.
  9875. */
  9876. _update: function() {
  9877. if (this._flagVertices || this._flagStartAngle || this._flagEndAngle
  9878. || this._flagInnerRadius || this._flagOuterRadius) {
  9879. var sa = this._startAngle;
  9880. var ea = this._endAngle;
  9881. var ir = this._innerRadius;
  9882. var or = this._outerRadius;
  9883. var connected = mod(sa, TWO_PI$2) === mod(ea, TWO_PI$2);
  9884. var punctured = ir > 0;
  9885. var vertices = this.vertices;
  9886. var length = (punctured ? vertices.length / 2 : vertices.length);
  9887. var command, id = 0;
  9888. if (connected) {
  9889. length--;
  9890. } else if (!punctured) {
  9891. length -= 2;
  9892. }
  9893. /**
  9894. * Outer Circle
  9895. */
  9896. for (var i = 0, last = length - 1; i < length; i++) {
  9897. var pct = i / last;
  9898. var v = vertices[id];
  9899. var theta = pct * (ea - sa) + sa;
  9900. var step = (ea - sa) / length;
  9901. var x = or * Math.cos(theta);
  9902. var y = or * Math.sin(theta);
  9903. switch (i) {
  9904. case 0:
  9905. command = Commands.move;
  9906. break;
  9907. default:
  9908. command = Commands.curve;
  9909. }
  9910. v.command = command;
  9911. v.x = x;
  9912. v.y = y;
  9913. v.controls.left.clear();
  9914. v.controls.right.clear();
  9915. if (v.command === Commands.curve) {
  9916. var amp = or * step / Math.PI;
  9917. v.controls.left.x = amp * Math.cos(theta - HALF_PI);
  9918. v.controls.left.y = amp * Math.sin(theta - HALF_PI);
  9919. v.controls.right.x = amp * Math.cos(theta + HALF_PI);
  9920. v.controls.right.y = amp * Math.sin(theta + HALF_PI);
  9921. if (i === 1) {
  9922. v.controls.left.multiplyScalar(2);
  9923. }
  9924. if (i === last) {
  9925. v.controls.right.multiplyScalar(2);
  9926. }
  9927. }
  9928. id++;
  9929. }
  9930. if (punctured) {
  9931. if (connected) {
  9932. vertices[id].command = Commands.close;
  9933. id++;
  9934. } else {
  9935. length--;
  9936. last = length - 1;
  9937. }
  9938. /**
  9939. * Inner Circle
  9940. */
  9941. for (i = 0; i < length; i++) {
  9942. pct = i / last;
  9943. v = vertices[id];
  9944. theta = (1 - pct) * (ea - sa) + sa;
  9945. step = (ea - sa) / length;
  9946. x = ir * Math.cos(theta);
  9947. y = ir * Math.sin(theta);
  9948. command = Commands.curve;
  9949. if (i <= 0) {
  9950. command = connected ? Commands.move : Commands.line;
  9951. }
  9952. v.command = command;
  9953. v.x = x;
  9954. v.y = y;
  9955. v.controls.left.clear();
  9956. v.controls.right.clear();
  9957. if (v.command === Commands.curve) {
  9958. amp = ir * step / Math.PI;
  9959. v.controls.left.x = amp * Math.cos(theta + HALF_PI);
  9960. v.controls.left.y = amp * Math.sin(theta + HALF_PI);
  9961. v.controls.right.x = amp * Math.cos(theta - HALF_PI);
  9962. v.controls.right.y = amp * Math.sin(theta - HALF_PI);
  9963. if (i === 1) {
  9964. v.controls.left.multiplyScalar(2);
  9965. }
  9966. if (i === last) {
  9967. v.controls.right.multiplyScalar(2);
  9968. }
  9969. }
  9970. id++;
  9971. }
  9972. // Final Point
  9973. vertices[id].copy(vertices[0]);
  9974. vertices[id].command = Commands.line;
  9975. } else if (!connected) {
  9976. vertices[id].command = Commands.line;
  9977. vertices[id].x = 0;
  9978. vertices[id].y = 0;
  9979. id++;
  9980. // Final Point
  9981. vertices[id].copy(vertices[0]);
  9982. vertices[id].command = Commands.line;
  9983. }
  9984. }
  9985. Path.prototype._update.call(this);
  9986. return this;
  9987. },
  9988. /**
  9989. * @name Two.ArcSegment#flagReset
  9990. * @function
  9991. * @private
  9992. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  9993. */
  9994. flagReset: function() {
  9995. Path.prototype.flagReset.call(this);
  9996. this._flagStartAngle = this._flagEndAngle
  9997. = this._flagInnerRadius = this._flagOuterRadius = false;
  9998. return this;
  9999. },
  10000. /**
  10001. * @name Two.ArcSegment#clone
  10002. * @function
  10003. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  10004. * @returns {Two.ArcSegment}
  10005. * @description Create a new instance of {@link Two.ArcSegment} with the same properties of the current path.
  10006. */
  10007. clone: function(parent) {
  10008. var ir = this.innerRadius;
  10009. var or = this.outerRadius;
  10010. var sa = this.startAngle;
  10011. var ea = this.endAngle;
  10012. var resolution = this.vertices.length;
  10013. var clone = new ArcSegment(0, 0, ir, or, sa, ea, resolution);
  10014. clone.translation.copy(this.translation);
  10015. clone.rotation = this.rotation;
  10016. clone.scale = this.scale;
  10017. clone.skewX = this.skewX;
  10018. clone.skewY = this.skewY;
  10019. if (this.matrix.manual) {
  10020. clone.matrix.copy(this.matrix);
  10021. }
  10022. _.each(Path.Properties, function(k) {
  10023. clone[k] = this[k];
  10024. }, this);
  10025. if (parent) {
  10026. parent.add(clone);
  10027. }
  10028. return clone;
  10029. },
  10030. /**
  10031. * @name Two.ArcSegment#toObject
  10032. * @function
  10033. * @returns {Object}
  10034. * @description Return a JSON compatible plain object that represents the path.
  10035. */
  10036. toObject: function() {
  10037. var object = Path.prototype.toObject.call(this);
  10038. _.each(ArcSegment.Properties, function(property) {
  10039. object[property] = this[property];
  10040. }, this);
  10041. return object;
  10042. }
  10043. });
  10044. ArcSegment.MakeObservable(ArcSegment.prototype);
  10045. var TWO_PI$1 = Math.PI * 2, cos$1 = Math.cos, sin$1 = Math.sin;
  10046. /**
  10047. * @name Two.Polygon
  10048. * @class
  10049. * @extends Two.Path
  10050. * @param {Number} [x=0] - The x position of the polygon.
  10051. * @param {Number} [y=0] - The y position of the polygon.
  10052. * @param {Number} [radius=0] - The radius value of the polygon.
  10053. * @param {Number} [sides=12] - The number of vertices used to construct the polygon.
  10054. */
  10055. function Polygon(ox, oy, r, sides) {
  10056. sides = Math.max(sides || 0, 3);
  10057. Path.call(this);
  10058. this.closed = true;
  10059. this.automatic = false;
  10060. /**
  10061. * @name Two.Polygon#width
  10062. * @property {Number} - The size of the width of the polygon.
  10063. */
  10064. if (typeof r === 'number') {
  10065. this.width = r * 2;
  10066. }
  10067. /**
  10068. * @name Two.Polygon#height
  10069. * @property {Number} - The size of the height of the polygon.
  10070. */
  10071. if (typeof r === 'number') {
  10072. this.height = r * 2;
  10073. }
  10074. /**
  10075. * @name Two.Polygon#sides
  10076. * @property {Number} - The amount of sides the polyogn has.
  10077. */
  10078. if (typeof sides === 'number') {
  10079. this.sides = sides;
  10080. }
  10081. this._update();
  10082. if (typeof ox === 'number') {
  10083. this.translation.x = ox;
  10084. }
  10085. if (typeof oy === 'number') {
  10086. this.translation.y = oy;
  10087. }
  10088. }
  10089. _.extend(Polygon, {
  10090. /**
  10091. * @name Two.Polygon.Properties
  10092. * @property {String[]} - A list of properties that are on every {@link Two.Polygon}.
  10093. */
  10094. Properties: ['width', 'height', 'sides'],
  10095. /**
  10096. * @name Two.Polygon.MakeObservable
  10097. * @function
  10098. * @param {Object} object - The object to make observable.
  10099. * @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.
  10100. */
  10101. MakeObservable: function(obj) {
  10102. Path.MakeObservable(obj);
  10103. _.each(Polygon.Properties, defineGetterSetter, obj);
  10104. }
  10105. });
  10106. _.extend(Polygon.prototype, Path.prototype, {
  10107. constructor: Polygon,
  10108. /**
  10109. * @name Two.Polygon#_flagWidth
  10110. * @private
  10111. * @property {Boolean} - Determines whether the {@link Two.Polygon#width} needs updating.
  10112. */
  10113. _flagWidth: false,
  10114. /**
  10115. * @name Two.Polygon#_flagHeight
  10116. * @private
  10117. * @property {Boolean} - Determines whether the {@link Two.Polygon#height} needs updating.
  10118. */
  10119. _flagHeight: false,
  10120. /**
  10121. * @name Two.Polygon#_flagSides
  10122. * @private
  10123. * @property {Boolean} - Determines whether the {@link Two.Polygon#sides} needs updating.
  10124. */
  10125. _flagSides: false,
  10126. /**
  10127. * @name Two.Polygon#_width
  10128. * @private
  10129. * @see {@link Two.Polygon#width}
  10130. */
  10131. _width: 0,
  10132. /**
  10133. * @name Two.Polygon#_height
  10134. * @private
  10135. * @see {@link Two.Polygon#height}
  10136. */
  10137. _height: 0,
  10138. /**
  10139. * @name Two.Polygon#_sides
  10140. * @private
  10141. * @see {@link Two.Polygon#sides}
  10142. */
  10143. _sides: 0,
  10144. /**
  10145. * @name Two.Polygon#_update
  10146. * @function
  10147. * @private
  10148. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  10149. * @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.
  10150. * @nota-bene Try not to call this method more than once a frame.
  10151. */
  10152. _update: function() {
  10153. if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagSides) {
  10154. var sides = this._sides;
  10155. var amount = sides + 1;
  10156. var length = this.vertices.length;
  10157. if (length > sides) {
  10158. this.vertices.splice(sides - 1, length - sides);
  10159. length = sides;
  10160. }
  10161. for (var i = 0; i < amount; i++) {
  10162. var pct = (i + 0.5) / sides;
  10163. var theta = TWO_PI$1 * pct + Math.PI / 2;
  10164. var x = this._width * cos$1(theta) / 2;
  10165. var y = this._height * sin$1(theta) / 2;
  10166. if (i >= length) {
  10167. this.vertices.push(new Anchor(x, y));
  10168. } else {
  10169. this.vertices[i].set(x, y);
  10170. }
  10171. this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
  10172. }
  10173. }
  10174. Path.prototype._update.call(this);
  10175. return this;
  10176. },
  10177. /**
  10178. * @name Two.Polygon#flagReset
  10179. * @function
  10180. * @private
  10181. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  10182. */
  10183. flagReset: function() {
  10184. this._flagWidth = this._flagHeight = this._flagSides = false;
  10185. Path.prototype.flagReset.call(this);
  10186. return this;
  10187. },
  10188. /**
  10189. * @name Two.Polygon#clone
  10190. * @function
  10191. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  10192. * @returns {Two.Polygon}
  10193. * @description Create a new instance of {@link Two.Polygon} with the same properties of the current path.
  10194. */
  10195. clone: function(parent) {
  10196. var clone = new Polygon(0, 0, this.radius, this.sides);
  10197. clone.translation.copy(this.translation);
  10198. clone.rotation = this.rotation;
  10199. clone.scale = this.scale;
  10200. clone.skewX = this.skewX;
  10201. clone.skewY = this.skewY;
  10202. if (this.matrix.manual) {
  10203. clone.matrix.copy(this.matrix);
  10204. }
  10205. _.each(Path.Properties, function(k) {
  10206. clone[k] = this[k];
  10207. }, this);
  10208. if (parent) {
  10209. parent.add(clone);
  10210. }
  10211. return clone;
  10212. },
  10213. /**
  10214. * @name Two.Polygon#toObject
  10215. * @function
  10216. * @returns {Object}
  10217. * @description Return a JSON compatible plain object that represents the path.
  10218. */
  10219. toObject: function() {
  10220. var object = Path.prototype.toObject.call(this);
  10221. _.each(Polygon.Properties, function(property) {
  10222. object[property] = this[property];
  10223. }, this);
  10224. return object;
  10225. }
  10226. });
  10227. Polygon.MakeObservable(Polygon.prototype);
  10228. var TWO_PI = Math.PI * 2, cos = Math.cos, sin = Math.sin;
  10229. /**
  10230. * @name Two.Star
  10231. * @class
  10232. * @extends Two.Path
  10233. * @param {Number} [x=0] - The x position of the star.
  10234. * @param {Number} [y=0] - The y position of the star.
  10235. * @param {Number} [innerRadius=0] - The inner radius value of the star.
  10236. * @param {Number} [outerRadius=0] - The outer radius value of the star.
  10237. * @param {Number} [sides=5] - The number of sides used to construct the star.
  10238. */
  10239. function Star(ox, oy, ir, or, sides) {
  10240. if (arguments.length <= 3) {
  10241. or = ir;
  10242. ir = or / 2;
  10243. }
  10244. if (typeof sides !== 'number' || sides <= 0) {
  10245. sides = 5;
  10246. }
  10247. Path.call(this);
  10248. this.closed = true;
  10249. this.automatic = false;
  10250. /**
  10251. * @name Two.Star#innerRadius
  10252. * @property {Number} - The size of the inner radius of the star.
  10253. */
  10254. if (typeof ir === 'number') {
  10255. this.innerRadius = ir;
  10256. }
  10257. /**
  10258. * @name Two.Star#outerRadius
  10259. * @property {Number} - The size of the outer radius of the star.
  10260. */
  10261. if (typeof or === 'number') {
  10262. this.outerRadius = or;
  10263. }
  10264. /**
  10265. * @name Two.Star#sides
  10266. * @property {Number} - The amount of sides the star has.
  10267. */
  10268. if (typeof sides === 'number') {
  10269. this.sides = sides;
  10270. }
  10271. this._update();
  10272. if (typeof ox === 'number') {
  10273. this.translation.x = ox;
  10274. }
  10275. if (typeof oy === 'number') {
  10276. this.translation.y = oy;
  10277. }
  10278. }
  10279. _.extend(Star, {
  10280. /**
  10281. * @name Two.Star.Properties
  10282. * @property {String[]} - A list of properties that are on every {@link Two.Star}.
  10283. */
  10284. Properties: ['innerRadius', 'outerRadius', 'sides'],
  10285. /**
  10286. * @name Two.Star.MakeObservable
  10287. * @function
  10288. * @param {Object} object - The object to make observable.
  10289. * @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.
  10290. */
  10291. MakeObservable: function(obj) {
  10292. Path.MakeObservable(obj);
  10293. _.each(Star.Properties, defineGetterSetter, obj);
  10294. }
  10295. });
  10296. _.extend(Star.prototype, Path.prototype, {
  10297. constructor: Star,
  10298. /**
  10299. * @name Two.Star#_flagInnerRadius
  10300. * @private
  10301. * @property {Boolean} - Determines whether the {@link Two.Star#innerRadius} needs updating.
  10302. */
  10303. _flagInnerRadius: false,
  10304. /**
  10305. * @name Two.Star#_flagOuterRadius
  10306. * @private
  10307. * @property {Boolean} - Determines whether the {@link Two.Star#outerRadius} needs updating.
  10308. */
  10309. _flagOuterRadius: false,
  10310. /**
  10311. * @name Two.Star#_flagSides
  10312. * @private
  10313. * @property {Boolean} - Determines whether the {@link Two.Star#sides} needs updating.
  10314. */
  10315. _flagSides: false,
  10316. /**
  10317. * @name Two.Star#_innerRadius
  10318. * @private
  10319. * @see {@link Two.Star#innerRadius}
  10320. */
  10321. _innerRadius: 0,
  10322. /**
  10323. * @name Two.Star#_outerRadius
  10324. * @private
  10325. * @see {@link Two.Star#outerRadius}
  10326. */
  10327. _outerRadius: 0,
  10328. /**
  10329. * @name Two.Star#_sides
  10330. * @private
  10331. * @see {@link Two.Star#sides}
  10332. */
  10333. _sides: 0,
  10334. /**
  10335. * @name Two.Star#_update
  10336. * @function
  10337. * @private
  10338. * @param {Boolean} [bubbles=false] - Force the parent to `_update` as well.
  10339. * @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.
  10340. * @nota-bene Try not to call this method more than once a frame.
  10341. */
  10342. _update: function() {
  10343. if (this._flagVertices || this._flagInnerRadius || this._flagOuterRadius || this._flagSides) {
  10344. var sides = this._sides * 2;
  10345. var amount = sides + 1;
  10346. var length = this.vertices.length;
  10347. if (length > sides) {
  10348. this.vertices.splice(sides - 1, length - sides);
  10349. length = sides;
  10350. }
  10351. for (var i = 0; i < amount; i++) {
  10352. var pct = (i + 0.5) / sides;
  10353. var theta = TWO_PI * pct;
  10354. var r = (!(i % 2) ? this._innerRadius : this._outerRadius) / 2;
  10355. var x = r * cos(theta);
  10356. var y = r * sin(theta);
  10357. if (i >= length) {
  10358. this.vertices.push(new Anchor(x, y));
  10359. } else {
  10360. this.vertices[i].set(x, y);
  10361. }
  10362. this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
  10363. }
  10364. }
  10365. Path.prototype._update.call(this);
  10366. return this;
  10367. },
  10368. /**
  10369. * @name Two.Star#flagReset
  10370. * @function
  10371. * @private
  10372. * @description Called internally to reset all flags. Ensures that only properties that change are updated before being sent to the renderer.
  10373. */
  10374. flagReset: function() {
  10375. this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false;
  10376. Path.prototype.flagReset.call(this);
  10377. return this;
  10378. },
  10379. /**
  10380. * @name Two.Star#clone
  10381. * @function
  10382. * @param {Two.Group} [parent] - The parent group or scene to add the clone to.
  10383. * @returns {Two.Star}
  10384. * @description Create a new instance of {@link Two.Star} with the same properties of the current path.
  10385. */
  10386. clone: function(parent) {
  10387. var ir = this.innerRadius;
  10388. var or = this.outerRadius;
  10389. var sides = this.sides;
  10390. var clone = new Star(0, 0, ir, or, sides);
  10391. clone.translation.copy(this.translation);
  10392. clone.rotation = this.rotation;
  10393. clone.scale = this.scale;
  10394. clone.skewX = this.skewX;
  10395. clone.skewY = this.skewY;
  10396. if (this.matrix.manual) {
  10397. clone.matrix.copy(this.matrix);
  10398. }
  10399. _.each(Path.Properties, function(k) {
  10400. clone[k] = this[k];
  10401. }, this);
  10402. if (parent) {
  10403. parent.add(clone);
  10404. }
  10405. return clone;
  10406. },
  10407. /**
  10408. * @name Two.Star#toObject
  10409. * @function
  10410. * @returns {Object}
  10411. * @description Return a JSON compatible plain object that represents the path.
  10412. */
  10413. toObject: function() {
  10414. var object = Path.prototype.toObject.call(this);
  10415. _.each(Star.Properties, function(property) {
  10416. object[property] = this[property];
  10417. }, this);
  10418. return object;
  10419. }
  10420. });
  10421. Star.MakeObservable(Star.prototype);
  10422. var svg = {
  10423. version: 1.1,
  10424. ns: 'http://www.w3.org/2000/svg',
  10425. xlink: 'http://www.w3.org/1999/xlink',
  10426. alignments: {
  10427. left: 'start',
  10428. center: 'middle',
  10429. right: 'end'
  10430. },
  10431. // Create an svg namespaced element.
  10432. createElement: function(name, attrs) {
  10433. var tag = name;
  10434. var elem = document.createElementNS(svg.ns, tag);
  10435. if (tag === 'svg') {
  10436. attrs = _.defaults(attrs || {}, {
  10437. version: svg.version
  10438. });
  10439. }
  10440. if (attrs && Object.keys(attrs).length > 0) {
  10441. svg.setAttributes(elem, attrs);
  10442. }
  10443. return elem;
  10444. },
  10445. // Add attributes from an svg element.
  10446. setAttributes: function(elem, attrs) {
  10447. var keys = Object.keys(attrs);
  10448. for (var i = 0; i < keys.length; i++) {
  10449. if (/href/.test(keys[i])) {
  10450. elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]);
  10451. } else {
  10452. elem.setAttribute(keys[i], attrs[keys[i]]);
  10453. }
  10454. }
  10455. return this;
  10456. },
  10457. // Remove attributes from an svg element.
  10458. removeAttributes: function(elem, attrs) {
  10459. for (var key in attrs) {
  10460. elem.removeAttribute(key);
  10461. }
  10462. return this;
  10463. },
  10464. // Turn a set of vertices into a string for the d property of a path
  10465. // element. It is imperative that the string collation is as fast as
  10466. // possible, because this call will be happening multiple times a
  10467. // second.
  10468. toString: function(points, closed) {
  10469. var l = points.length,
  10470. last = l - 1,
  10471. d, // The elusive last Commands.move point
  10472. string = '';
  10473. for (var i = 0; i < l; i++) {
  10474. var b = points[i];
  10475. var command;
  10476. var prev = closed ? mod(i - 1, l) : Math.max(i - 1, 0);
  10477. var next = closed ? mod(i + 1, l) : Math.min(i + 1, last);
  10478. var a = points[prev];
  10479. var c = points[next];
  10480. var vx, vy, ux, uy, ar, bl, br, cl;
  10481. var rx, ry, xAxisRotation, largeArcFlag, sweepFlag;
  10482. // Access x and y directly,
  10483. // bypassing the getter
  10484. var x = toFixed(b.x);
  10485. var y = toFixed(b.y);
  10486. switch (b.command) {
  10487. case Commands.close:
  10488. command = Commands.close;
  10489. break;
  10490. case Commands.arc:
  10491. rx = b.rx;
  10492. ry = b.ry;
  10493. xAxisRotation = b.xAxisRotation;
  10494. largeArcFlag = b.largeArcFlag;
  10495. sweepFlag = b.sweepFlag;
  10496. command = Commands.arc + ' ' + rx + ' ' + ry + ' '
  10497. + xAxisRotation + ' ' + largeArcFlag + ' ' + sweepFlag + ' '
  10498. + x + ' ' + y;
  10499. break;
  10500. case Commands.curve:
  10501. ar = (a.controls && a.controls.right) || Vector.zero;
  10502. bl = (b.controls && b.controls.left) || Vector.zero;
  10503. if (a.relative) {
  10504. vx = toFixed((ar.x + a.x));
  10505. vy = toFixed((ar.y + a.y));
  10506. } else {
  10507. vx = toFixed(ar.x);
  10508. vy = toFixed(ar.y);
  10509. }
  10510. if (b.relative) {
  10511. ux = toFixed((bl.x + b.x));
  10512. uy = toFixed((bl.y + b.y));
  10513. } else {
  10514. ux = toFixed(bl.x);
  10515. uy = toFixed(bl.y);
  10516. }
  10517. command = ((i === 0) ? Commands.move : Commands.curve) +
  10518. ' ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  10519. break;
  10520. case Commands.move:
  10521. d = b;
  10522. command = Commands.move + ' ' + x + ' ' + y;
  10523. break;
  10524. default:
  10525. command = b.command + ' ' + x + ' ' + y;
  10526. }
  10527. // Add a final point and close it off
  10528. if (i >= last && closed) {
  10529. if (b.command === Commands.curve) {
  10530. // Make sure we close to the most previous Commands.move
  10531. c = d;
  10532. br = (b.controls && b.controls.right) || b;
  10533. cl = (c.controls && c.controls.left) || c;
  10534. if (b.relative) {
  10535. vx = toFixed((br.x + b.x));
  10536. vy = toFixed((br.y + b.y));
  10537. } else {
  10538. vx = toFixed(br.x);
  10539. vy = toFixed(br.y);
  10540. }
  10541. if (c.relative) {
  10542. ux = toFixed((cl.x + c.x));
  10543. uy = toFixed((cl.y + c.y));
  10544. } else {
  10545. ux = toFixed(cl.x);
  10546. uy = toFixed(cl.y);
  10547. }
  10548. x = toFixed(c.x);
  10549. y = toFixed(c.y);
  10550. command +=
  10551. ' C ' + vx + ' ' + vy + ' ' + ux + ' ' + uy + ' ' + x + ' ' + y;
  10552. }
  10553. if (b.command !== Commands.close) {
  10554. command += ' Z';
  10555. }
  10556. }
  10557. string += command + ' ';
  10558. }
  10559. return string;
  10560. },
  10561. getClip: function(shape, domElement) {
  10562. var clip = shape._renderer.clip;
  10563. if (!clip) {
  10564. clip = shape._renderer.clip = svg.createElement('clipPath', {
  10565. 'clip-rule': 'nonzero'
  10566. });
  10567. domElement.defs.appendChild(clip);
  10568. }
  10569. return clip;
  10570. },
  10571. group: {
  10572. // TODO: Can speed up.
  10573. // TODO: How does this effect a f
  10574. appendChild: function(object) {
  10575. var elem = object._renderer.elem;
  10576. if (!elem) {
  10577. return;
  10578. }
  10579. var tag = elem.nodeName;
  10580. if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) {
  10581. return;
  10582. }
  10583. this.elem.appendChild(elem);
  10584. },
  10585. removeChild: function(object) {
  10586. var elem = object._renderer.elem;
  10587. if (!elem || elem.parentNode != this.elem) {
  10588. return;
  10589. }
  10590. var tag = elem.nodeName;
  10591. if (!tag) {
  10592. return;
  10593. }
  10594. // Defer subtractions while clipping.
  10595. if (object._clip) {
  10596. return;
  10597. }
  10598. this.elem.removeChild(elem);
  10599. },
  10600. orderChild: function(object) {
  10601. this.elem.appendChild(object._renderer.elem);
  10602. },
  10603. renderChild: function(child) {
  10604. svg[child._renderer.type].render.call(child, this);
  10605. },
  10606. render: function(domElement) {
  10607. // Shortcut for hidden objects.
  10608. // Doesn't reset the flags, so changes are stored and
  10609. // applied once the object is visible again
  10610. if ((!this._visible && !this._flagVisible)
  10611. || (this._opacity === 0 && !this._flagOpacity)) {
  10612. return this;
  10613. }
  10614. this._update();
  10615. if (!this._renderer.elem) {
  10616. this._renderer.elem = svg.createElement('g', {
  10617. id: this.id
  10618. });
  10619. domElement.appendChild(this._renderer.elem);
  10620. }
  10621. // _Update styles for the <g>
  10622. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10623. var context = {
  10624. domElement: domElement,
  10625. elem: this._renderer.elem
  10626. };
  10627. if (flagMatrix) {
  10628. this._renderer.elem.setAttribute('transform', 'matrix(' + this._matrix.toString() + ')');
  10629. }
  10630. for (var i = 0; i < this.children.length; i++) {
  10631. var child = this.children[i];
  10632. svg[child._renderer.type].render.call(child, domElement);
  10633. }
  10634. if (this._flagId) {
  10635. this._renderer.elem.setAttribute('id', this._id);
  10636. }
  10637. if (this._flagOpacity) {
  10638. this._renderer.elem.setAttribute('opacity', this._opacity);
  10639. }
  10640. if (this._flagVisible) {
  10641. this._renderer.elem.setAttribute('display', this._visible ? 'inline' : 'none');
  10642. }
  10643. if (this._flagClassName) {
  10644. this._renderer.elem.setAttribute('class', this.classList.join(' '));
  10645. }
  10646. if (this._flagAdditions) {
  10647. this.additions.forEach(svg.group.appendChild, context);
  10648. }
  10649. if (this._flagSubtractions) {
  10650. this.subtractions.forEach(svg.group.removeChild, context);
  10651. }
  10652. if (this._flagOrder) {
  10653. this.children.forEach(svg.group.orderChild, context);
  10654. }
  10655. // Commented two-way functionality of clips / masks with groups and
  10656. // polygons. Uncomment when this bug is fixed:
  10657. // https://code.google.com/p/chromium/issues/detail?id=370951
  10658. // if (this._flagClip) {
  10659. // clip = svg.getClip(this, domElement);
  10660. // elem = this._renderer.elem;
  10661. // if (this._clip) {
  10662. // elem.removeAttribute('id');
  10663. // clip.setAttribute('id', this.id);
  10664. // clip.appendChild(elem);
  10665. // } else {
  10666. // clip.removeAttribute('id');
  10667. // elem.setAttribute('id', this.id);
  10668. // this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10669. // }
  10670. // }
  10671. if (this._flagMask) {
  10672. if (this._mask) {
  10673. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10674. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10675. } else {
  10676. this._renderer.elem.removeAttribute('clip-path');
  10677. }
  10678. }
  10679. return this.flagReset();
  10680. }
  10681. },
  10682. path: {
  10683. render: function(domElement) {
  10684. // Shortcut for hidden objects.
  10685. // Doesn't reset the flags, so changes are stored and
  10686. // applied once the object is visible again
  10687. if (this._opacity === 0 && !this._flagOpacity) {
  10688. return this;
  10689. }
  10690. this._update();
  10691. // Collect any attribute that needs to be changed here
  10692. var changed = {};
  10693. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10694. if (flagMatrix) {
  10695. changed.transform = 'matrix(' + this._matrix.toString() + ')';
  10696. }
  10697. if (this._flagId) {
  10698. changed.id = this._id;
  10699. }
  10700. if (this._flagVertices) {
  10701. var vertices = svg.toString(this._renderer.vertices, this._closed);
  10702. changed.d = vertices;
  10703. }
  10704. if (this._fill && this._fill._renderer) {
  10705. this._fill._update();
  10706. svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  10707. }
  10708. if (this._flagFill) {
  10709. changed.fill = this._fill && this._fill.id
  10710. ? 'url(#' + this._fill.id + ')' : this._fill;
  10711. }
  10712. if (this._stroke && this._stroke._renderer) {
  10713. this._stroke._update();
  10714. svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  10715. }
  10716. if (this._flagStroke) {
  10717. changed.stroke = this._stroke && this._stroke.id
  10718. ? 'url(#' + this._stroke.id + ')' : this._stroke;
  10719. }
  10720. if (this._flagLinewidth) {
  10721. changed['stroke-width'] = this._linewidth;
  10722. }
  10723. if (this._flagOpacity) {
  10724. changed['stroke-opacity'] = this._opacity;
  10725. changed['fill-opacity'] = this._opacity;
  10726. }
  10727. if (this._flagClassName) {
  10728. changed['class'] = this.classList.join(' ');
  10729. }
  10730. if (this._flagVisible) {
  10731. changed.visibility = this._visible ? 'visible' : 'hidden';
  10732. }
  10733. if (this._flagCap) {
  10734. changed['stroke-linecap'] = this._cap;
  10735. }
  10736. if (this._flagJoin) {
  10737. changed['stroke-linejoin'] = this._join;
  10738. }
  10739. if (this._flagMiter) {
  10740. changed['stroke-miterlimit'] = this._miter;
  10741. }
  10742. if (this.dashes && this.dashes.length > 0) {
  10743. changed['stroke-dasharray'] = this.dashes.join(' ');
  10744. changed['stroke-dashoffset'] = this.dashes.offset || 0;
  10745. }
  10746. // If there is no attached DOM element yet,
  10747. // create it with all necessary attributes.
  10748. if (!this._renderer.elem) {
  10749. changed.id = this._id;
  10750. this._renderer.elem = svg.createElement('path', changed);
  10751. domElement.appendChild(this._renderer.elem);
  10752. // Otherwise apply all pending attributes
  10753. } else {
  10754. svg.setAttributes(this._renderer.elem, changed);
  10755. }
  10756. if (this._flagClip) {
  10757. var clip = svg.getClip(this, domElement);
  10758. var elem = this._renderer.elem;
  10759. if (this._clip) {
  10760. elem.removeAttribute('id');
  10761. clip.setAttribute('id', this.id);
  10762. clip.appendChild(elem);
  10763. } else {
  10764. clip.removeAttribute('id');
  10765. elem.setAttribute('id', this.id);
  10766. this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10767. }
  10768. }
  10769. // Commented two-way functionality of clips / masks with groups and
  10770. // polygons. Uncomment when this bug is fixed:
  10771. // https://code.google.com/p/chromium/issues/detail?id=370951
  10772. if (this._flagMask) {
  10773. if (this._mask) {
  10774. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10775. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10776. } else {
  10777. this._renderer.elem.removeAttribute('clip-path');
  10778. }
  10779. }
  10780. return this.flagReset();
  10781. }
  10782. },
  10783. text: {
  10784. render: function(domElement) {
  10785. this._update();
  10786. var changed = {};
  10787. var flagMatrix = this._matrix.manual || this._flagMatrix;
  10788. if (flagMatrix) {
  10789. changed.transform = 'matrix(' + this._matrix.toString() + ')';
  10790. }
  10791. if (this._flagId) {
  10792. changed.id = this._id;
  10793. }
  10794. if (this._flagFamily) {
  10795. changed['font-family'] = this._family;
  10796. }
  10797. if (this._flagSize) {
  10798. changed['font-size'] = this._size;
  10799. }
  10800. if (this._flagLeading) {
  10801. changed['line-height'] = this._leading;
  10802. }
  10803. if (this._flagAlignment) {
  10804. changed['text-anchor'] = svg.alignments[this._alignment] || this._alignment;
  10805. }
  10806. if (this._flagBaseline) {
  10807. changed['alignment-baseline'] = changed['dominant-baseline'] = this._baseline;
  10808. }
  10809. if (this._flagStyle) {
  10810. changed['font-style'] = this._style;
  10811. }
  10812. if (this._flagWeight) {
  10813. changed['font-weight'] = this._weight;
  10814. }
  10815. if (this._flagDecoration) {
  10816. changed['text-decoration'] = this._decoration;
  10817. }
  10818. if (this._fill && this._fill._renderer) {
  10819. this._fill._update();
  10820. svg[this._fill._renderer.type].render.call(this._fill, domElement, true);
  10821. }
  10822. if (this._flagFill) {
  10823. changed.fill = this._fill && this._fill.id
  10824. ? 'url(#' + this._fill.id + ')' : this._fill;
  10825. }
  10826. if (this._stroke && this._stroke._renderer) {
  10827. this._stroke._update();
  10828. svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true);
  10829. }
  10830. if (this._flagStroke) {
  10831. changed.stroke = this._stroke && this._stroke.id
  10832. ? 'url(#' + this._stroke.id + ')' : this._stroke;
  10833. }
  10834. if (this._flagLinewidth) {
  10835. changed['stroke-width'] = this._linewidth;
  10836. }
  10837. if (this._flagOpacity) {
  10838. changed.opacity = this._opacity;
  10839. }
  10840. if (this._flagClassName) {
  10841. changed['class'] = this.classList.join(' ');
  10842. }
  10843. if (this._flagVisible) {
  10844. changed.visibility = this._visible ? 'visible' : 'hidden';
  10845. }
  10846. if (this.dashes && this.dashes.length > 0) {
  10847. changed['stroke-dasharray'] = this.dashes.join(' ');
  10848. changed['stroke-dashoffset'] = this.dashes.offset || 0;
  10849. }
  10850. if (!this._renderer.elem) {
  10851. changed.id = this._id;
  10852. this._renderer.elem = svg.createElement('text', changed);
  10853. domElement.defs.appendChild(this._renderer.elem);
  10854. } else {
  10855. svg.setAttributes(this._renderer.elem, changed);
  10856. }
  10857. if (this._flagClip) {
  10858. var clip = svg.getClip(this, domElement);
  10859. var elem = this._renderer.elem;
  10860. if (this._clip) {
  10861. elem.removeAttribute('id');
  10862. clip.setAttribute('id', this.id);
  10863. clip.appendChild(elem);
  10864. } else {
  10865. clip.removeAttribute('id');
  10866. elem.setAttribute('id', this.id);
  10867. this.parent._renderer.elem.appendChild(elem); // TODO: should be insertBefore
  10868. }
  10869. }
  10870. // Commented two-way functionality of clips / masks with groups and
  10871. // polygons. Uncomment when this bug is fixed:
  10872. // https://code.google.com/p/chromium/issues/detail?id=370951
  10873. if (this._flagMask) {
  10874. if (this._mask) {
  10875. svg[this._mask._renderer.type].render.call(this._mask, domElement);
  10876. this._renderer.elem.setAttribute('clip-path', 'url(#' + this._mask.id + ')');
  10877. } else {
  10878. this._renderer.elem.removeAttribute('clip-path');
  10879. }
  10880. }
  10881. if (this._flagValue) {
  10882. this._renderer.elem.textContent = this._value;
  10883. }
  10884. return this.flagReset();
  10885. }
  10886. },
  10887. 'linear-gradient': {
  10888. render: function(domElement, silent) {
  10889. if (!silent) {
  10890. this._update();
  10891. }
  10892. var changed = {};
  10893. if (this._flagId) {
  10894. changed.id = this._id;
  10895. }
  10896. if (this._flagEndPoints) {
  10897. changed.x1 = this.left._x;
  10898. changed.y1 = this.left._y;
  10899. changed.x2 = this.right._x;
  10900. changed.y2 = this.right._y;
  10901. }
  10902. if (this._flagSpread) {
  10903. changed.spreadMethod = this._spread;
  10904. }
  10905. // If there is no attached DOM element yet,
  10906. // create it with all necessary attributes.
  10907. if (!this._renderer.elem) {
  10908. changed.id = this._id;
  10909. changed.gradientUnits = 'userSpaceOnUse';
  10910. this._renderer.elem = svg.createElement('linearGradient', changed);
  10911. domElement.defs.appendChild(this._renderer.elem);
  10912. // Otherwise apply all pending attributes
  10913. } else {
  10914. svg.setAttributes(this._renderer.elem, changed);
  10915. }
  10916. if (this._flagStops) {
  10917. var lengthChanged = this._renderer.elem.childNodes.length
  10918. !== this.stops.length;
  10919. if (lengthChanged) {
  10920. while (this._renderer.elem.lastChild) {
  10921. this._renderer.elem.removeChild(this._renderer.elem.lastChild);
  10922. }
  10923. }
  10924. for (var i = 0; i < this.stops.length; i++) {
  10925. var stop = this.stops[i];
  10926. var attrs = {};
  10927. if (stop._flagOffset) {
  10928. attrs.offset = 100 * stop._offset + '%';
  10929. }
  10930. if (stop._flagColor) {
  10931. attrs['stop-color'] = stop._color;
  10932. }
  10933. if (stop._flagOpacity) {
  10934. attrs['stop-opacity'] = stop._opacity;
  10935. }
  10936. if (!stop._renderer.elem) {
  10937. stop._renderer.elem = svg.createElement('stop', attrs);
  10938. } else {
  10939. svg.setAttributes(stop._renderer.elem, attrs);
  10940. }
  10941. if (lengthChanged) {
  10942. this._renderer.elem.appendChild(stop._renderer.elem);
  10943. }
  10944. stop.flagReset();
  10945. }
  10946. }
  10947. return this.flagReset();
  10948. }
  10949. },
  10950. 'radial-gradient': {
  10951. render: function(domElement, silent) {
  10952. if (!silent) {
  10953. this._update();
  10954. }
  10955. var changed = {};
  10956. if (this._flagId) {
  10957. changed.id = this._id;
  10958. }
  10959. if (this._flagCenter) {
  10960. changed.cx = this.center._x;
  10961. changed.cy = this.center._y;
  10962. }
  10963. if (this._flagFocal) {
  10964. changed.fx = this.focal._x;
  10965. changed.fy = this.focal._y;
  10966. }
  10967. if (this._flagRadius) {
  10968. changed.r = this._radius;
  10969. }
  10970. if (this._flagSpread) {
  10971. changed.spreadMethod = this._spread;
  10972. }
  10973. // If there is no attached DOM element yet,
  10974. // create it with all necessary attributes.
  10975. if (!this._renderer.elem) {
  10976. changed.id = this._id;
  10977. changed.gradientUnits = 'userSpaceOnUse';
  10978. this._renderer.elem = svg.createElement('radialGradient', changed);
  10979. domElement.defs.appendChild(this._renderer.elem);
  10980. // Otherwise apply all pending attributes
  10981. } else {
  10982. svg.setAttributes(this._renderer.elem, changed);
  10983. }
  10984. if (this._flagStops) {
  10985. var lengthChanged = this._renderer.elem.childNodes.length
  10986. !== this.stops.length;
  10987. if (lengthChanged) {
  10988. while (this._renderer.elem.lastChild) {
  10989. this._renderer.elem.removeChild(this._renderer.elem.lastChild);
  10990. }
  10991. }
  10992. for (var i = 0; i < this.stops.length; i++) {
  10993. var stop = this.stops[i];
  10994. var attrs = {};
  10995. if (stop._flagOffset) {
  10996. attrs.offset = 100 * stop._offset + '%';
  10997. }
  10998. if (stop._flagColor) {
  10999. attrs['stop-color'] = stop._color;
  11000. }
  11001. if (stop._flagOpacity) {
  11002. attrs['stop-opacity'] = stop._opacity;
  11003. }
  11004. if (!stop._renderer.elem) {
  11005. stop._renderer.elem = svg.createElement('stop', attrs);
  11006. } else {
  11007. svg.setAttributes(stop._renderer.elem, attrs);
  11008. }
  11009. if (lengthChanged) {
  11010. this._renderer.elem.appendChild(stop._renderer.elem);
  11011. }
  11012. stop.flagReset();
  11013. }
  11014. }
  11015. return this.flagReset();
  11016. }
  11017. },
  11018. texture: {
  11019. render: function(domElement, silent) {
  11020. if (!silent) {
  11021. this._update();
  11022. }
  11023. var changed = {};
  11024. var styles = { x: 0, y: 0 };
  11025. var image = this.image;
  11026. if (this._flagId) {
  11027. changed.id = this._id;
  11028. }
  11029. if (this._flagLoaded && this.loaded) {
  11030. switch (image.nodeName.toLowerCase()) {
  11031. case 'canvas':
  11032. styles.href = styles['xlink:href'] = image.toDataURL('image/png');
  11033. break;
  11034. case 'img':
  11035. case 'image':
  11036. styles.href = styles['xlink:href'] = this.src;
  11037. break;
  11038. }
  11039. }
  11040. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  11041. changed.x = this._offset.x;
  11042. changed.y = this._offset.y;
  11043. if (image) {
  11044. changed.x -= image.width / 2;
  11045. changed.y -= image.height / 2;
  11046. if (this._scale instanceof Vector) {
  11047. changed.x *= this._scale.x;
  11048. changed.y *= this._scale.y;
  11049. } else {
  11050. changed.x *= this._scale;
  11051. changed.y *= this._scale;
  11052. }
  11053. }
  11054. if (changed.x > 0) {
  11055. changed.x *= - 1;
  11056. }
  11057. if (changed.y > 0) {
  11058. changed.y *= - 1;
  11059. }
  11060. }
  11061. if (this._flagScale || this._flagLoaded || this._flagRepeat) {
  11062. changed.width = 0;
  11063. changed.height = 0;
  11064. if (image) {
  11065. styles.width = changed.width = image.width;
  11066. styles.height = changed.height = image.height;
  11067. // TODO: Hack / Band-aid
  11068. switch (this._repeat) {
  11069. case 'no-repeat':
  11070. changed.width += 1;
  11071. changed.height += 1;
  11072. break;
  11073. }
  11074. if (this._scale instanceof Vector) {
  11075. changed.width *= this._scale.x;
  11076. changed.height *= this._scale.y;
  11077. } else {
  11078. changed.width *= this._scale;
  11079. changed.height *= this._scale;
  11080. }
  11081. }
  11082. }
  11083. if (this._flagScale || this._flagLoaded) {
  11084. if (!this._renderer.image) {
  11085. this._renderer.image = svg.createElement('image', styles);
  11086. } else {
  11087. svg.setAttributes(this._renderer.image, styles);
  11088. }
  11089. }
  11090. if (!this._renderer.elem) {
  11091. changed.id = this._id;
  11092. changed.patternUnits = 'userSpaceOnUse';
  11093. this._renderer.elem = svg.createElement('pattern', changed);
  11094. domElement.defs.appendChild(this._renderer.elem);
  11095. } else if (Object.keys(changed).length !== 0) {
  11096. svg.setAttributes(this._renderer.elem, changed);
  11097. }
  11098. if (this._renderer.elem && this._renderer.image && !this._renderer.appended) {
  11099. this._renderer.elem.appendChild(this._renderer.image);
  11100. this._renderer.appended = true;
  11101. }
  11102. return this.flagReset();
  11103. }
  11104. }
  11105. };
  11106. /**
  11107. * @name Two.SVGRenderer
  11108. * @class
  11109. * @extends Two.Events
  11110. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  11111. * @param {Element} [parameters.domElement] - The `<svg />` to draw to. If none given a new one will be constructed.
  11112. * @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 />`.
  11113. */
  11114. function Renderer$1(params) {
  11115. /**
  11116. * @name Two.SVGRenderer#domElement
  11117. * @property {Element} - The `<svg />` associated with the Two.js scene.
  11118. */
  11119. this.domElement = params.domElement || svg.createElement('svg');
  11120. /**
  11121. * @name Two.SVGRenderer#scene
  11122. * @property {Two.Group} - The root group of the scenegraph.
  11123. */
  11124. this.scene = new Group();
  11125. this.scene.parent = this;
  11126. /**
  11127. * @name Two.SVGRenderer#defs
  11128. * @property {SvgDefintionsElement} - The `<defs />` to apply gradients, patterns, and bitmap imagery.
  11129. */
  11130. this.defs = svg.createElement('defs');
  11131. this.domElement.appendChild(this.defs);
  11132. this.domElement.defs = this.defs;
  11133. this.domElement.style.overflow = 'hidden';
  11134. }
  11135. _.extend(Renderer$1, {
  11136. /**
  11137. * @name Two.SVGRenderer.Utils
  11138. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<svg />`.
  11139. */
  11140. Utils: svg
  11141. });
  11142. _.extend(Renderer$1.prototype, Events, {
  11143. constructor: Renderer$1,
  11144. /**
  11145. * @name Two.SVGRenderer#setSize
  11146. * @function
  11147. * @param {Number} width - The new width of the renderer.
  11148. * @param {Number} height - The new height of the renderer.
  11149. * @description Change the size of the renderer.
  11150. * @nota-bene Triggers a `Two.Events.resize`.
  11151. */
  11152. setSize: function(width, height) {
  11153. this.width = width;
  11154. this.height = height;
  11155. svg.setAttributes(this.domElement, {
  11156. width: width,
  11157. height: height
  11158. });
  11159. return this.trigger(Events.Types.resize, width, height);
  11160. },
  11161. /**
  11162. * @name Two.SVGRenderer#render
  11163. * @function
  11164. * @description Render the current scene to the `<svg />`.
  11165. */
  11166. render: function() {
  11167. svg.group.render.call(this.scene, this.domElement);
  11168. return this;
  11169. }
  11170. });
  11171. // Constants
  11172. var multiplyMatrix = Matrix.Multiply,
  11173. identity = [1, 0, 0, 0, 1, 0, 0, 0, 1],
  11174. transformation = new NumArray(9),
  11175. CanvasUtils = Renderer$2.Utils;
  11176. var webgl = {
  11177. isHidden: /(undefined|none|transparent)/i,
  11178. canvas: (root$1.document ? root$1.document.createElement('canvas') : { getContext: function() {} }),
  11179. alignments: {
  11180. left: 'start',
  11181. middle: 'center',
  11182. right: 'end'
  11183. },
  11184. matrix: new Matrix(),
  11185. group: {
  11186. removeChild: function(child, gl) {
  11187. if (child.children) {
  11188. for (var i = 0; i < child.children.length; i++) {
  11189. webgl.group.removeChild(child.children[i], gl);
  11190. }
  11191. return;
  11192. }
  11193. // Deallocate texture to free up gl memory.
  11194. gl.deleteTexture(child._renderer.texture);
  11195. delete child._renderer.texture;
  11196. },
  11197. render: function(gl, program) {
  11198. if (!this._visible) {
  11199. return;
  11200. }
  11201. this._update();
  11202. var parent = this.parent;
  11203. var flagParentMatrix = (parent._matrix && parent._matrix.manual) || parent._flagMatrix;
  11204. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11205. if (flagParentMatrix || flagMatrix) {
  11206. if (!this._renderer.matrix) {
  11207. this._renderer.matrix = new NumArray(9);
  11208. }
  11209. // Reduce amount of object / array creation / deletion
  11210. this._matrix.toTransformArray(true, transformation);
  11211. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11212. if (!(this._renderer.scale instanceof Vector)) {
  11213. this._renderer.scale = new Vector();
  11214. }
  11215. if (this._scale instanceof Vector) {
  11216. this._renderer.scale.x = this._scale.x;
  11217. this._renderer.scale.y = this._scale.y;
  11218. } else {
  11219. this._renderer.scale.x = this._scale;
  11220. this._renderer.scale.y = this._scale;
  11221. }
  11222. if (!(/renderer/i.test(parent._renderer.type))) {
  11223. this._renderer.scale.x *= parent._renderer.scale.x;
  11224. this._renderer.scale.y *= parent._renderer.scale.y;
  11225. }
  11226. if (flagParentMatrix) {
  11227. this._flagMatrix = true;
  11228. }
  11229. }
  11230. if (this._mask) {
  11231. // Stencil away everything that isn't rendered by the mask
  11232. gl.clear(gl.STENCIL_BUFFER_BIT);
  11233. gl.enable(gl.STENCIL_TEST);
  11234. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11235. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11236. // Don't draw the element onto the canvas, only onto the stencil buffer
  11237. gl.colorMask(false, false, false, false);
  11238. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11239. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11240. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11241. gl.colorMask(true, true, true, true);
  11242. }
  11243. this._flagOpacity = parent._flagOpacity || this._flagOpacity;
  11244. this._renderer.opacity = this._opacity
  11245. * (parent && parent._renderer ? parent._renderer.opacity : 1);
  11246. var i;
  11247. if (this._flagSubtractions) {
  11248. for (i = 0; i < this.subtractions.length; i++) {
  11249. webgl.group.removeChild(this.subtractions[i], gl);
  11250. }
  11251. }
  11252. for (i = 0; i < this.children.length; i++) {
  11253. var child = this.children[i];
  11254. webgl[child._renderer.type].render.call(child, gl, program);
  11255. }
  11256. if (this._mask) {
  11257. gl.disable(gl.STENCIL_TEST);
  11258. }
  11259. return this.flagReset();
  11260. }
  11261. },
  11262. path: {
  11263. updateCanvas: function(elem) {
  11264. var next, prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
  11265. var isOffset;
  11266. var commands = elem._renderer.vertices;
  11267. var canvas = this.canvas;
  11268. var ctx = this.ctx;
  11269. // Styles
  11270. var scale = elem._renderer.scale;
  11271. var stroke = elem._stroke;
  11272. var linewidth = elem._linewidth;
  11273. var fill = elem._fill;
  11274. var opacity = elem._renderer.opacity || elem._opacity;
  11275. var cap = elem._cap;
  11276. var join = elem._join;
  11277. var miter = elem._miter;
  11278. var closed = elem._closed;
  11279. var dashes = elem.dashes;
  11280. var length = commands.length;
  11281. var last = length - 1;
  11282. canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
  11283. canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
  11284. var centroid = elem._renderer.rect.centroid;
  11285. var cx = centroid.x;
  11286. var cy = centroid.y;
  11287. ctx.clearRect(0, 0, canvas.width, canvas.height);
  11288. if (fill) {
  11289. if (typeof fill === 'string') {
  11290. ctx.fillStyle = fill;
  11291. } else {
  11292. webgl[fill._renderer.type].render.call(fill, ctx, elem);
  11293. ctx.fillStyle = fill._renderer.effect;
  11294. }
  11295. }
  11296. if (stroke) {
  11297. if (typeof stroke === 'string') {
  11298. ctx.strokeStyle = stroke;
  11299. } else {
  11300. webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  11301. ctx.strokeStyle = stroke._renderer.effect;
  11302. }
  11303. if (linewidth) {
  11304. ctx.lineWidth = linewidth;
  11305. }
  11306. if (miter) {
  11307. ctx.miterLimit = miter;
  11308. }
  11309. if (join) {
  11310. ctx.lineJoin = join;
  11311. }
  11312. if (!closed && cap) {
  11313. ctx.lineCap = cap;
  11314. }
  11315. }
  11316. if (typeof opacity === 'number') {
  11317. ctx.globalAlpha = opacity;
  11318. }
  11319. if (dashes && dashes.length > 0) {
  11320. ctx.lineDashOffset = dashes.offset || 0;
  11321. ctx.setLineDash(dashes);
  11322. }
  11323. var d;
  11324. ctx.save();
  11325. ctx.scale(scale.x, scale.y);
  11326. ctx.translate(cx, cy);
  11327. ctx.beginPath();
  11328. for (var i = 0; i < commands.length; i++) {
  11329. var b = commands[i];
  11330. x = b.x;
  11331. y = b.y;
  11332. switch (b.command) {
  11333. case Commands.close:
  11334. ctx.closePath();
  11335. break;
  11336. case Commands.arc:
  11337. var rx = b.rx;
  11338. var ry = b.ry;
  11339. var xAxisRotation = b.xAxisRotation;
  11340. var largeArcFlag = b.largeArcFlag;
  11341. var sweepFlag = b.sweepFlag;
  11342. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  11343. a = commands[prev];
  11344. var ax = a.x;
  11345. var ay = a.y;
  11346. CanvasUtils.renderSvgArcCommand(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y);
  11347. break;
  11348. case Commands.curve:
  11349. prev = closed ? mod(i - 1, length) : Math.max(i - 1, 0);
  11350. next = closed ? mod(i + 1, length) : Math.min(i + 1, last);
  11351. a = commands[prev];
  11352. c = commands[next];
  11353. ar = (a.controls && a.controls.right) || Vector.zero;
  11354. bl = (b.controls && b.controls.left) || Vector.zero;
  11355. if (a._relative) {
  11356. vx = ar.x + a.x;
  11357. vy = ar.y + a.y;
  11358. } else {
  11359. vx = ar.x;
  11360. vy = ar.y;
  11361. }
  11362. if (b._relative) {
  11363. ux = bl.x + b.x;
  11364. uy = bl.y + b.y;
  11365. } else {
  11366. ux = bl.x;
  11367. uy = bl.y;
  11368. }
  11369. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  11370. if (i >= last && closed) {
  11371. c = d;
  11372. br = (b.controls && b.controls.right) || Vector.zero;
  11373. cl = (c.controls && c.controls.left) || Vector.zero;
  11374. if (b._relative) {
  11375. vx = br.x + b.x;
  11376. vy = br.y + b.y;
  11377. } else {
  11378. vx = br.x;
  11379. vy = br.y;
  11380. }
  11381. if (c._relative) {
  11382. ux = cl.x + c.x;
  11383. uy = cl.y + c.y;
  11384. } else {
  11385. ux = cl.x;
  11386. uy = cl.y;
  11387. }
  11388. x = c.x;
  11389. y = c.y;
  11390. ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
  11391. }
  11392. break;
  11393. case Commands.line:
  11394. ctx.lineTo(x, y);
  11395. break;
  11396. case Commands.move:
  11397. d = b;
  11398. ctx.moveTo(x, y);
  11399. break;
  11400. }
  11401. }
  11402. // Loose ends
  11403. if (closed) {
  11404. ctx.closePath();
  11405. }
  11406. if (!webgl.isHidden.test(fill)) {
  11407. isOffset = fill._renderer && fill._renderer.offset;
  11408. if (isOffset) {
  11409. ctx.save();
  11410. ctx.translate(
  11411. - fill._renderer.offset.x, - fill._renderer.offset.y);
  11412. ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
  11413. }
  11414. ctx.fill();
  11415. if (isOffset) {
  11416. ctx.restore();
  11417. }
  11418. }
  11419. if (!webgl.isHidden.test(stroke)) {
  11420. isOffset = stroke._renderer && stroke._renderer.offset;
  11421. if (isOffset) {
  11422. ctx.save();
  11423. ctx.translate(
  11424. - stroke._renderer.offset.x, - stroke._renderer.offset.y);
  11425. ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
  11426. ctx.lineWidth = linewidth / stroke._renderer.scale.x;
  11427. }
  11428. ctx.stroke();
  11429. if (isOffset) {
  11430. ctx.restore();
  11431. }
  11432. }
  11433. ctx.restore();
  11434. },
  11435. // Returns the rect of a set of verts. Typically takes vertices that are
  11436. // "centered" around 0 and returns them to be anchored upper-left.
  11437. getBoundingClientRect: function(vertices, border, rect) {
  11438. var left = Infinity, right = -Infinity,
  11439. top = Infinity, bottom = -Infinity,
  11440. width, height;
  11441. vertices.forEach(function(v) {
  11442. var x = v.x, y = v.y, controls = v.controls;
  11443. var a, b, c, d, cl, cr;
  11444. top = Math.min(y, top);
  11445. left = Math.min(x, left);
  11446. right = Math.max(x, right);
  11447. bottom = Math.max(y, bottom);
  11448. if (!v.controls) {
  11449. return;
  11450. }
  11451. cl = controls.left;
  11452. cr = controls.right;
  11453. if (!cl || !cr) {
  11454. return;
  11455. }
  11456. a = v._relative ? cl.x + x : cl.x;
  11457. b = v._relative ? cl.y + y : cl.y;
  11458. c = v._relative ? cr.x + x : cr.x;
  11459. d = v._relative ? cr.y + y : cr.y;
  11460. if (!a || !b || !c || !d) {
  11461. return;
  11462. }
  11463. top = Math.min(b, d, top);
  11464. left = Math.min(a, c, left);
  11465. right = Math.max(a, c, right);
  11466. bottom = Math.max(b, d, bottom);
  11467. });
  11468. // Expand borders
  11469. if (typeof border === 'number') {
  11470. top -= border;
  11471. left -= border;
  11472. right += border;
  11473. bottom += border;
  11474. }
  11475. width = right - left;
  11476. height = bottom - top;
  11477. rect.top = top;
  11478. rect.left = left;
  11479. rect.right = right;
  11480. rect.bottom = bottom;
  11481. rect.width = width;
  11482. rect.height = height;
  11483. if (!rect.centroid) {
  11484. rect.centroid = {};
  11485. }
  11486. rect.centroid.x = - left;
  11487. rect.centroid.y = - top;
  11488. },
  11489. render: function(gl, program, forcedParent) {
  11490. if (!this._visible || !this._opacity) {
  11491. return this;
  11492. }
  11493. this._update();
  11494. // Calculate what changed
  11495. var parent = forcedParent || this.parent;
  11496. var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  11497. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11498. var parentChanged = this._renderer.parent !== parent;
  11499. var flagTexture = this._flagVertices || this._flagFill
  11500. || (this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  11501. || (this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  11502. || (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))
  11503. || (this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  11504. || (this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  11505. || (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))
  11506. || this._flagStroke || this._flagLinewidth || this._flagOpacity
  11507. || parent._flagOpacity || this._flagVisible || this._flagCap
  11508. || this._flagJoin || this._flagMiter || this._flagScale
  11509. || (this.dashes && this.dashes.length > 0)
  11510. || !this._renderer.texture;
  11511. if (flagParentMatrix || flagMatrix || parentChanged) {
  11512. if (!this._renderer.matrix) {
  11513. this._renderer.matrix = new NumArray(9);
  11514. }
  11515. // Reduce amount of object / array creation / deletion
  11516. this._matrix.toTransformArray(true, transformation);
  11517. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11518. if (!(this._renderer.scale instanceof Vector)) {
  11519. this._renderer.scale = new Vector();
  11520. }
  11521. if (this._scale instanceof Vector) {
  11522. this._renderer.scale.x = this._scale.x * parent._renderer.scale.x;
  11523. this._renderer.scale.y = this._scale.y * parent._renderer.scale.y;
  11524. } else {
  11525. this._renderer.scale.x = this._scale * parent._renderer.scale.x;
  11526. this._renderer.scale.y = this._scale * parent._renderer.scale.y;
  11527. }
  11528. if (parentChanged) {
  11529. this._renderer.parent = parent;
  11530. }
  11531. }
  11532. if (this._mask) {
  11533. // Stencil away everything that isn't rendered by the mask
  11534. gl.clear(gl.STENCIL_BUFFER_BIT);
  11535. gl.enable(gl.STENCIL_TEST);
  11536. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11537. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11538. // Don't draw the element onto the canvas, only onto the stencil buffer
  11539. gl.colorMask(false, false, false, false);
  11540. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11541. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11542. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11543. gl.colorMask(true, true, true, true);
  11544. }
  11545. if (flagTexture) {
  11546. if (!this._renderer.rect) {
  11547. this._renderer.rect = {};
  11548. }
  11549. this._renderer.opacity = this._opacity * parent._renderer.opacity;
  11550. webgl.path.getBoundingClientRect(this._renderer.vertices, this._linewidth, this._renderer.rect);
  11551. webgl.updateTexture.call(webgl, gl, this);
  11552. } else {
  11553. // We still need to update child Two elements on the fill and
  11554. // stroke properties.
  11555. if (this._fill && this._fill._update) {
  11556. this._fill._update();
  11557. }
  11558. if (this._stroke && this._stroke._update) {
  11559. this._stroke._update();
  11560. }
  11561. }
  11562. if (this._clip && !forcedParent) {
  11563. return;
  11564. }
  11565. // Draw Texture
  11566. gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  11567. // Draw Rect
  11568. var rect = this._renderer.rect;
  11569. gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  11570. gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
  11571. gl.drawArrays(gl.TRIANGLES, 0, 6);
  11572. if (this._mask) {
  11573. gl.disable(gl.STENCIL_TEST);
  11574. }
  11575. return this.flagReset();
  11576. }
  11577. },
  11578. text: {
  11579. updateCanvas: function(elem) {
  11580. var canvas = this.canvas;
  11581. var ctx = this.ctx;
  11582. // Styles
  11583. var scale = elem._renderer.scale;
  11584. var stroke = elem._stroke;
  11585. var linewidth = elem._linewidth * scale;
  11586. var fill = elem._fill;
  11587. var opacity = elem._renderer.opacity || elem._opacity;
  11588. var dashes = elem.dashes;
  11589. var decoration = elem._decoration;
  11590. canvas.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1);
  11591. canvas.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1);
  11592. var centroid = elem._renderer.rect.centroid;
  11593. var cx = centroid.x;
  11594. var cy = centroid.y;
  11595. var a, b, c, d, e, sx, sy, x1, y1, x2, y2;
  11596. var isOffset = fill._renderer && fill._renderer.offset
  11597. && stroke._renderer && stroke._renderer.offset;
  11598. ctx.clearRect(0, 0, canvas.width, canvas.height);
  11599. if (!isOffset) {
  11600. ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  11601. elem._leading + 'px', elem._family].join(' ');
  11602. }
  11603. ctx.textAlign = 'center';
  11604. ctx.textBaseline = 'middle';
  11605. // Styles
  11606. if (fill) {
  11607. if (typeof fill === 'string') {
  11608. ctx.fillStyle = fill;
  11609. } else {
  11610. webgl[fill._renderer.type].render.call(fill, ctx, elem);
  11611. ctx.fillStyle = fill._renderer.effect;
  11612. }
  11613. }
  11614. if (stroke) {
  11615. if (typeof stroke === 'string') {
  11616. ctx.strokeStyle = stroke;
  11617. } else {
  11618. webgl[stroke._renderer.type].render.call(stroke, ctx, elem);
  11619. ctx.strokeStyle = stroke._renderer.effect;
  11620. }
  11621. if (linewidth) {
  11622. ctx.lineWidth = linewidth;
  11623. }
  11624. }
  11625. if (typeof opacity === 'number') {
  11626. ctx.globalAlpha = opacity;
  11627. }
  11628. if (dashes && dashes.length > 0) {
  11629. ctx.lineDashOffset = dashes.offset || 0;
  11630. ctx.setLineDash(dashes);
  11631. }
  11632. ctx.save();
  11633. ctx.scale(scale.x, scale.y);
  11634. ctx.translate(cx, cy);
  11635. if (!webgl.isHidden.test(fill)) {
  11636. if (fill._renderer && fill._renderer.offset) {
  11637. sx = fill._renderer.scale.x;
  11638. sy = fill._renderer.scale.y;
  11639. ctx.save();
  11640. ctx.translate( - fill._renderer.offset.x,
  11641. - fill._renderer.offset.y);
  11642. ctx.scale(sx, sy);
  11643. a = elem._size / fill._renderer.scale.y;
  11644. b = elem._leading / fill._renderer.scale.y;
  11645. ctx.font = [elem._style, elem._weight, a + 'px/',
  11646. b + 'px', elem._family].join(' ');
  11647. c = fill._renderer.offset.x / fill._renderer.scale.x;
  11648. d = fill._renderer.offset.y / fill._renderer.scale.y;
  11649. ctx.fillText(elem.value, c, d);
  11650. ctx.restore();
  11651. } else {
  11652. ctx.fillText(elem.value, 0, 0);
  11653. }
  11654. }
  11655. if (!webgl.isHidden.test(stroke)) {
  11656. if (stroke._renderer && stroke._renderer.offset) {
  11657. sx = stroke._renderer.scale.x;
  11658. sy = stroke._renderer.scale.y;
  11659. ctx.save();
  11660. ctx.translate(- stroke._renderer.offset.x,
  11661. - stroke._renderer.offset.y);
  11662. ctx.scale(sx, sy);
  11663. a = elem._size / stroke._renderer.scale.y;
  11664. b = elem._leading / stroke._renderer.scale.y;
  11665. ctx.font = [elem._style, elem._weight, a + 'px/',
  11666. b + 'px', elem._family].join(' ');
  11667. c = stroke._renderer.offset.x / stroke._renderer.scale.x;
  11668. d = stroke._renderer.offset.y / stroke._renderer.scale.y;
  11669. e = linewidth / stroke._renderer.scale.x;
  11670. ctx.lineWidth = e;
  11671. ctx.strokeText(elem.value, c, d);
  11672. ctx.restore();
  11673. } else {
  11674. ctx.strokeText(elem.value, 0, 0);
  11675. }
  11676. }
  11677. // Handle text-decoration
  11678. if (/(underline|strikethrough)/i.test(decoration)) {
  11679. var metrics = ctx.measureText(elem.value);
  11680. switch (decoration) {
  11681. case 'underline':
  11682. y1 = metrics.actualBoundingBoxAscent;
  11683. y2 = metrics.actualBoundingBoxAscent;
  11684. break;
  11685. case 'strikethrough':
  11686. y1 = 0;
  11687. y2 = 0;
  11688. break;
  11689. }
  11690. x1 = - metrics.width / 2;
  11691. x2 = metrics.width / 2;
  11692. ctx.lineWidth = Math.max(Math.floor(elem._size / 15), 1);
  11693. ctx.strokeStyle = ctx.fillStyle;
  11694. ctx.beginPath();
  11695. ctx.moveTo(x1, y1);
  11696. ctx.lineTo(x2, y2);
  11697. ctx.stroke();
  11698. }
  11699. ctx.restore();
  11700. },
  11701. getBoundingClientRect: function(elem, rect) {
  11702. var ctx = webgl.ctx;
  11703. ctx.font = [elem._style, elem._weight, elem._size + 'px/' +
  11704. elem._leading + 'px', elem._family].join(' ');
  11705. ctx.textAlign = 'center';
  11706. ctx.textBaseline = elem._baseline;
  11707. // TODO: Estimate this better
  11708. var width = ctx.measureText(elem._value).width * 1.25;
  11709. var height = Math.max(elem._size, elem._leading) * 1.25;
  11710. if (this._linewidth && !webgl.isHidden.test(this._stroke)) {
  11711. width += this._linewidth * 2;
  11712. height += this._linewidth * 2;
  11713. }
  11714. var w = width / 2;
  11715. var h = height / 2;
  11716. switch (webgl.alignments[elem._alignment] || elem._alignment) {
  11717. case webgl.alignments.left:
  11718. rect.left = 0;
  11719. rect.right = width;
  11720. break;
  11721. case webgl.alignments.right:
  11722. rect.left = - width;
  11723. rect.right = 0;
  11724. break;
  11725. default:
  11726. rect.left = - w;
  11727. rect.right = w;
  11728. }
  11729. // TODO: Gradients aren't inherited...
  11730. switch (elem._baseline) {
  11731. case 'bottom':
  11732. rect.top = - height;
  11733. rect.bottom = 0;
  11734. break;
  11735. case 'top':
  11736. rect.top = 0;
  11737. rect.bottom = height;
  11738. break;
  11739. default:
  11740. rect.top = - h;
  11741. rect.bottom = h;
  11742. }
  11743. rect.width = width;
  11744. rect.height = height;
  11745. if (!rect.centroid) {
  11746. rect.centroid = {};
  11747. }
  11748. // TODO:
  11749. rect.centroid.x = w;
  11750. rect.centroid.y = h;
  11751. },
  11752. render: function(gl, program, forcedParent) {
  11753. if (!this._visible || !this._opacity) {
  11754. return this;
  11755. }
  11756. this._update();
  11757. // Calculate what changed
  11758. var parent = forcedParent || this.parent;
  11759. var flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
  11760. var flagMatrix = this._matrix.manual || this._flagMatrix;
  11761. var parentChanged = this._renderer.parent !== parent;
  11762. var flagTexture = this._flagVertices || this._flagFill
  11763. || (this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints))
  11764. || (this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal))
  11765. || (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))
  11766. || (this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints))
  11767. || (this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal))
  11768. || (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))
  11769. || this._flagStroke || this._flagLinewidth || this._flagOpacity
  11770. || parent._flagOpacity || this._flagVisible || this._flagScale
  11771. || this._flagValue || this._flagFamily || this._flagSize
  11772. || this._flagLeading || this._flagAlignment || this._flagBaseline
  11773. || this._flagStyle || this._flagWeight || this._flagDecoration
  11774. || (this.dashes && this.dashes.length > 0)
  11775. || !this._renderer.texture;
  11776. if (flagParentMatrix || flagMatrix || parentChanged) {
  11777. if (!this._renderer.matrix) {
  11778. this._renderer.matrix = new NumArray(9);
  11779. }
  11780. // Reduce amount of object / array creation / deletion
  11781. this._matrix.toTransformArray(true, transformation);
  11782. multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix);
  11783. if (!(this._renderer.scale instanceof Vector)) {
  11784. this._renderer.scale = new Vector();
  11785. }
  11786. if (this._scale instanceof Vector) {
  11787. this._renderer.scale.x = this._scale.x * parent._renderer.scale.x;
  11788. this._renderer.scale.y = this._scale.y * parent._renderer.scale.y;
  11789. } else {
  11790. this._renderer.scale.x = this._scale * parent._renderer.scale.x;
  11791. this._renderer.scale.y = this._scale * parent._renderer.scale.y;
  11792. }
  11793. if (parentChanged) {
  11794. this._renderer.parent = parent;
  11795. }
  11796. }
  11797. if (this._mask) {
  11798. // Stencil away everything that isn't rendered by the mask
  11799. gl.clear(gl.STENCIL_BUFFER_BIT);
  11800. gl.enable(gl.STENCIL_TEST);
  11801. gl.stencilFunc(gl.ALWAYS, 1, 0);
  11802. gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  11803. // Don't draw the element onto the canvas, only onto the stencil buffer
  11804. gl.colorMask(false, false, false, false);
  11805. webgl[this._mask._renderer.type].render.call(this._mask, gl, program, this);
  11806. gl.stencilFunc(gl.EQUAL, 1, 0xff);
  11807. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  11808. gl.colorMask(true, true, true, true);
  11809. }
  11810. if (flagTexture) {
  11811. if (!this._renderer.rect) {
  11812. this._renderer.rect = {};
  11813. }
  11814. this._renderer.opacity = this._opacity * parent._renderer.opacity;
  11815. webgl.text.getBoundingClientRect(this, this._renderer.rect);
  11816. webgl.updateTexture.call(webgl, gl, this);
  11817. } else {
  11818. // We still need to update child Two elements on the fill and
  11819. // stroke properties.
  11820. if (this._fill && this._fill._update) {
  11821. this._fill._update();
  11822. }
  11823. if (this._stroke && this._stroke._update) {
  11824. this._stroke._update();
  11825. }
  11826. }
  11827. if (this._clip && !forcedParent) {
  11828. return;
  11829. }
  11830. // Draw Texture
  11831. gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
  11832. // Draw Rect
  11833. var rect = this._renderer.rect;
  11834. gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
  11835. gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
  11836. gl.drawArrays(gl.TRIANGLES, 0, 6);
  11837. if (this._mask) {
  11838. gl.disable(gl.STENCIL_TEST);
  11839. }
  11840. return this.flagReset();
  11841. }
  11842. },
  11843. 'linear-gradient': {
  11844. render: function(ctx, elem) {
  11845. if (!ctx.canvas.getContext('2d')) {
  11846. return;
  11847. }
  11848. this._update();
  11849. if (!this._renderer.effect || this._flagEndPoints || this._flagStops) {
  11850. this._renderer.effect = ctx.createLinearGradient(
  11851. this.left._x, this.left._y,
  11852. this.right._x, this.right._y
  11853. );
  11854. for (var i = 0; i < this.stops.length; i++) {
  11855. var stop = this.stops[i];
  11856. this._renderer.effect.addColorStop(stop._offset, stop._color);
  11857. }
  11858. }
  11859. return this.flagReset();
  11860. }
  11861. },
  11862. 'radial-gradient': {
  11863. render: function(ctx, elem) {
  11864. if (!ctx.canvas.getContext('2d')) {
  11865. return;
  11866. }
  11867. this._update();
  11868. if (!this._renderer.effect || this._flagCenter || this._flagFocal
  11869. || this._flagRadius || this._flagStops) {
  11870. this._renderer.effect = ctx.createRadialGradient(
  11871. this.center._x, this.center._y, 0,
  11872. this.focal._x, this.focal._y, this._radius
  11873. );
  11874. for (var i = 0; i < this.stops.length; i++) {
  11875. var stop = this.stops[i];
  11876. this._renderer.effect.addColorStop(stop._offset, stop._color);
  11877. }
  11878. }
  11879. return this.flagReset();
  11880. }
  11881. },
  11882. texture: {
  11883. render: function(ctx, elem) {
  11884. if (!ctx.canvas.getContext('2d')) {
  11885. return;
  11886. }
  11887. this._update();
  11888. var image = this.image;
  11889. if (((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded)) {
  11890. this._renderer.effect = ctx.createPattern(image, this._repeat);
  11891. } else if (!this._renderer.effect) {
  11892. return this.flagReset();
  11893. }
  11894. if (this._flagOffset || this._flagLoaded || this._flagScale) {
  11895. if (!(this._renderer.offset instanceof Vector)) {
  11896. this._renderer.offset = new Vector();
  11897. }
  11898. this._renderer.offset.x = - this._offset.x;
  11899. this._renderer.offset.y = - this._offset.y;
  11900. if (image) {
  11901. this._renderer.offset.x += image.width / 2;
  11902. this._renderer.offset.y += image.height / 2;
  11903. if (this._scale instanceof Vector) {
  11904. this._renderer.offset.x *= this._scale.x;
  11905. this._renderer.offset.y *= this._scale.y;
  11906. } else {
  11907. this._renderer.offset.x *= this._scale;
  11908. this._renderer.offset.y *= this._scale;
  11909. }
  11910. }
  11911. }
  11912. if (this._flagScale || this._flagLoaded) {
  11913. if (!(this._renderer.scale instanceof Vector)) {
  11914. this._renderer.scale = new Vector();
  11915. }
  11916. if (this._scale instanceof Vector) {
  11917. this._renderer.scale.copy(this._scale);
  11918. } else {
  11919. this._renderer.scale.set(this._scale, this._scale);
  11920. }
  11921. }
  11922. return this.flagReset();
  11923. }
  11924. },
  11925. updateTexture: function(gl, elem) {
  11926. this[elem._renderer.type].updateCanvas.call(webgl, elem);
  11927. if (!elem._renderer.texture) {
  11928. elem._renderer.texture = gl.createTexture();
  11929. }
  11930. gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture);
  11931. // Set the parameters so we can render any size image.
  11932. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  11933. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  11934. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  11935. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  11936. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  11937. // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  11938. if (this.canvas.width <= 0 || this.canvas.height <= 0) {
  11939. return;
  11940. }
  11941. // Upload the image into the texture.
  11942. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
  11943. },
  11944. program: {
  11945. create: function(gl, shaders) {
  11946. var program, linked, error;
  11947. program = gl.createProgram();
  11948. _.each(shaders, function(s) {
  11949. gl.attachShader(program, s);
  11950. });
  11951. gl.linkProgram(program);
  11952. linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  11953. if (!linked) {
  11954. error = gl.getProgramInfoLog(program);
  11955. gl.deleteProgram(program);
  11956. throw new TwoError('unable to link program: ' + error);
  11957. }
  11958. return program;
  11959. }
  11960. },
  11961. shaders: {
  11962. create: function(gl, source, type) {
  11963. var shader, compiled, error;
  11964. shader = gl.createShader(gl[type]);
  11965. gl.shaderSource(shader, source);
  11966. gl.compileShader(shader);
  11967. compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  11968. if (!compiled) {
  11969. error = gl.getShaderInfoLog(shader);
  11970. gl.deleteShader(shader);
  11971. throw new TwoError('unable to compile shader ' + shader + ': ' + error);
  11972. }
  11973. return shader;
  11974. },
  11975. types: {
  11976. vertex: 'VERTEX_SHADER',
  11977. fragment: 'FRAGMENT_SHADER'
  11978. },
  11979. vertex: [
  11980. 'precision mediump float;',
  11981. 'attribute vec2 a_position;',
  11982. '',
  11983. 'uniform mat3 u_matrix;',
  11984. 'uniform vec2 u_resolution;',
  11985. 'uniform vec4 u_rect;',
  11986. '',
  11987. 'varying vec2 v_textureCoords;',
  11988. '',
  11989. 'void main() {',
  11990. ' vec2 rectCoords = (a_position * (u_rect.zw - u_rect.xy)) + u_rect.xy;',
  11991. ' vec2 projected = (u_matrix * vec3(rectCoords, 1.0)).xy;',
  11992. ' vec2 normal = projected / u_resolution;',
  11993. ' vec2 clipspace = (normal * 2.0) - 1.0;',
  11994. '',
  11995. ' gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);',
  11996. ' v_textureCoords = a_position;',
  11997. '}'
  11998. ].join('\n'),
  11999. fragment: [
  12000. 'precision mediump float;',
  12001. '',
  12002. 'uniform sampler2D u_image;',
  12003. 'varying vec2 v_textureCoords;',
  12004. '',
  12005. 'void main() {',
  12006. ' vec4 texel = texture2D(u_image, v_textureCoords);',
  12007. ' if (texel.a == 0.0) {',
  12008. ' discard;',
  12009. ' }',
  12010. ' gl_FragColor = texel;',
  12011. '}'
  12012. ].join('\n')
  12013. },
  12014. TextureRegistry: new Registry()
  12015. };
  12016. webgl.ctx = webgl.canvas.getContext('2d');
  12017. /**
  12018. * @name Two.WebGLRenderer
  12019. * @class
  12020. * @extends Two.Events
  12021. * @param {Object} [parameters] - This object is inherited when constructing a new instance of {@link Two}.
  12022. * @param {Element} [parameters.domElement] - The `<canvas />` to draw to. If none given a new one will be constructed.
  12023. * @param {HTMLCanvasElement} [parameters.offscreenElement] - The offscreen two dimensional `<canvas />` to render each element on WebGL texture updates.
  12024. * @param {Boolean} [parameters.antialias] - Determines whether the canvas should clear render with antialias on.
  12025. * @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.
  12026. * @see {@link https://www.khronos.org/registry/webgl/specs/latest/1.0/}
  12027. */
  12028. function Renderer(params) {
  12029. var gl, vs, fs;
  12030. /**
  12031. * @name Two.WebGLRenderer#domElement
  12032. * @property {Element} - The `<canvas />` associated with the Two.js scene.
  12033. */
  12034. this.domElement = params.domElement || document.createElement('canvas');
  12035. if (typeof params.offscreenElement !== 'undefined') {
  12036. webgl.canvas = params.offscreenElement;
  12037. webgl.ctx = webgl.canvas.getContext('2d');
  12038. }
  12039. /**
  12040. * @name Two.WebGLRenderer#scene
  12041. * @property {Two.Group} - The root group of the scenegraph.
  12042. */
  12043. this.scene = new Group();
  12044. this.scene.parent = this;
  12045. this._renderer = {
  12046. type: 'renderer',
  12047. matrix: new NumArray(identity),
  12048. scale: 1,
  12049. opacity: 1
  12050. };
  12051. this._flagMatrix = true;
  12052. // http://games.greggman.com/game/webgl-and-alpha/
  12053. // http://www.khronos.org/registry/webgl/specs/latest/#5.2
  12054. params = _.defaults(params || {}, {
  12055. antialias: false,
  12056. alpha: true,
  12057. premultipliedAlpha: true,
  12058. stencil: true,
  12059. preserveDrawingBuffer: true,
  12060. overdraw: false
  12061. });
  12062. /**
  12063. * @name Two.WebGLRenderer#overdraw
  12064. * @property {Boolean} - Determines whether the canvas clears the background each draw call.
  12065. * @default true
  12066. */
  12067. this.overdraw = params.overdraw;
  12068. /**
  12069. * @name Two.WebGLRenderer#ctx
  12070. * @property {WebGLContext} - Associated two dimensional context to render on the `<canvas />`.
  12071. */
  12072. gl = this.ctx = this.domElement.getContext('webgl', params) ||
  12073. this.domElement.getContext('experimental-webgl', params);
  12074. if (!this.ctx) {
  12075. throw new TwoError(
  12076. 'unable to create a webgl context. Try using another renderer.');
  12077. }
  12078. // Compile Base Shaders to draw in pixel space.
  12079. vs = webgl.shaders.create(
  12080. gl, webgl.shaders.vertex, webgl.shaders.types.vertex);
  12081. fs = webgl.shaders.create(
  12082. gl, webgl.shaders.fragment, webgl.shaders.types.fragment);
  12083. /**
  12084. * @name Two.WebGLRenderer#program
  12085. * @property {WebGLProgram} - Associated WebGL program to render all elements from the scenegraph.
  12086. */
  12087. this.program = webgl.program.create(gl, [vs, fs]);
  12088. gl.useProgram(this.program);
  12089. // Create and bind the drawing buffer
  12090. // look up where the vertex data needs to go.
  12091. this.program.position = gl.getAttribLocation(this.program, 'a_position');
  12092. this.program.matrix = gl.getUniformLocation(this.program, 'u_matrix');
  12093. this.program.rect = gl.getUniformLocation(this.program, 'u_rect');
  12094. // Bind the vertex buffer
  12095. var positionBuffer = gl.createBuffer();
  12096. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  12097. gl.vertexAttribPointer(this.program.position, 2, gl.FLOAT, false, 0, 0);
  12098. gl.enableVertexAttribArray(this.program.position);
  12099. gl.bufferData(
  12100. gl.ARRAY_BUFFER,
  12101. new NumArray([
  12102. 0, 0,
  12103. 1, 0,
  12104. 0, 1,
  12105. 0, 1,
  12106. 1, 0,
  12107. 1, 1
  12108. ]),
  12109. gl.STATIC_DRAW);
  12110. // Setup some initial statements of the gl context
  12111. gl.enable(gl.BLEND);
  12112. gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  12113. gl.blendEquation(gl.FUNC_ADD);
  12114. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  12115. }
  12116. _.extend(Renderer, {
  12117. /**
  12118. * @name Two.WebGLRenderer.Utils
  12119. * @property {Object} - A massive object filled with utility functions and properties to render Two.js objects to a `<canvas />` through the WebGL API.
  12120. */
  12121. Utils: webgl
  12122. });
  12123. _.extend(Renderer.prototype, Events, {
  12124. constructor: Renderer,
  12125. /**
  12126. * @name Two.WebGLRenderer#setSize
  12127. * @function
  12128. * @fires resize
  12129. * @param {Number} width - The new width of the renderer.
  12130. * @param {Number} height - The new height of the renderer.
  12131. * @param {Number} [ratio] - The new pixel ratio (pixel density) of the renderer. Defaults to calculate the pixel density of the user's screen.
  12132. * @description Change the size of the renderer.
  12133. */
  12134. setSize: function(width, height, ratio) {
  12135. this.width = width;
  12136. this.height = height;
  12137. this.ratio = typeof ratio === 'undefined' ? getRatio(this.ctx) : ratio;
  12138. this.domElement.width = width * this.ratio;
  12139. this.domElement.height = height * this.ratio;
  12140. if (_.isObject(this.domElement.style)) {
  12141. _.extend(this.domElement.style, {
  12142. width: width + 'px',
  12143. height: height + 'px'
  12144. });
  12145. }
  12146. // Set for this.stage parent scaling to account for HDPI
  12147. this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio;
  12148. this._flagMatrix = true;
  12149. this.ctx.viewport(0, 0, width * this.ratio, height * this.ratio);
  12150. var resolutionLocation = this.ctx.getUniformLocation(
  12151. this.program, 'u_resolution');
  12152. this.ctx.uniform2f(resolutionLocation, width * this.ratio, height * this.ratio);
  12153. return this.trigger(Events.Types.resize, width, height, ratio);
  12154. },
  12155. /**
  12156. * @name Two.WebGLRenderer#render
  12157. * @function
  12158. * @description Render the current scene to the `<canvas />`.
  12159. */
  12160. render: function() {
  12161. var gl = this.ctx;
  12162. if (!this.overdraw) {
  12163. gl.clear(gl.COLOR_BUFFER_BIT);
  12164. }
  12165. webgl.group.render.call(this.scene, gl, this.program);
  12166. this._flagMatrix = false;
  12167. return this;
  12168. }
  12169. });
  12170. // Utils
  12171. /**
  12172. * @name Two
  12173. * @class
  12174. * @global
  12175. * @param {Object} [options]
  12176. * @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.
  12177. * @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`.
  12178. * @param {Number} [options.width=640] - The width of the stage on construction. This can be set at a later time.
  12179. * @param {Number} [options.height=480] - The height of the stage on construction. This can be set at a later time.
  12180. * @param {String} [options.type=Two.Types.svg] - The type of renderer to setup drawing with. See {@link Two.Types} for available options.
  12181. * @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}.
  12182. * @param {Element} [options.domElement] - The canvas or SVG element to draw into. This overrides the `options.type` argument.
  12183. * @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.
  12184. */
  12185. function Two(options) {
  12186. // Determine what Renderer to use and setup a scene.
  12187. var params = _.defaults(options || {}, {
  12188. fullscreen: false,
  12189. fitted: false,
  12190. width: 640,
  12191. height: 480,
  12192. type: Two.Types.svg,
  12193. autostart: false
  12194. });
  12195. _.each(params, function(v, k) {
  12196. if (/fullscreen/i.test(k) || /autostart/i.test(k)) {
  12197. return;
  12198. }
  12199. this[k] = v;
  12200. }, this);
  12201. // Specified domElement overrides type declaration only if the element does not support declared renderer type.
  12202. if (_.isElement(params.domElement)) {
  12203. var tagName = params.domElement.tagName.toLowerCase();
  12204. // TODO: Reconsider this if statement's logic.
  12205. if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(this.type+'-'+tagName)) {
  12206. this.type = Two.Types[tagName];
  12207. }
  12208. }
  12209. this.renderer = new Two[this.type](this);
  12210. this.setPlaying(params.autostart);
  12211. this.frameCount = 0;
  12212. /**
  12213. * @name Two#fit
  12214. * @function
  12215. * @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.
  12216. */
  12217. if (params.fullscreen) {
  12218. this.fit = fitToWindow.bind(this);
  12219. this.fit.domElement = window;
  12220. this.fit.attached = true;
  12221. _.extend(document.body.style, {
  12222. overflow: 'hidden',
  12223. margin: 0,
  12224. padding: 0,
  12225. top: 0,
  12226. left: 0,
  12227. right: 0,
  12228. bottom: 0,
  12229. position: 'fixed'
  12230. });
  12231. _.extend(this.renderer.domElement.style, {
  12232. display: 'block',
  12233. top: 0,
  12234. left: 0,
  12235. right: 0,
  12236. bottom: 0,
  12237. position: 'fixed'
  12238. });
  12239. dom.bind(this.fit.domElement, 'resize', this.fit);
  12240. this.fit();
  12241. } else if (params.fitted) {
  12242. this.fit = fitToParent.bind(this);
  12243. _.extend(this.renderer.domElement.style, {
  12244. display: 'block'
  12245. });
  12246. } else if (!_.isElement(params.domElement)) {
  12247. this.renderer.setSize(params.width, params.height, this.ratio);
  12248. this.width = params.width;
  12249. this.height = params.height;
  12250. }
  12251. this.renderer.bind(Events.Types.resize, updateDimensions.bind(this));
  12252. this.scene = this.renderer.scene;
  12253. Two.Instances.push(this);
  12254. if (params.autostart) {
  12255. raf.init();
  12256. }
  12257. }
  12258. _.extend(Two, Constants);
  12259. _.extend(Two.prototype, Events, {
  12260. constructor: Two,
  12261. /**
  12262. * @name Two#type
  12263. * @property {String} - A string representing which type of renderer the instance has instantiated.
  12264. */
  12265. type: '',
  12266. /**
  12267. * @name Two#renderer
  12268. * @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.
  12269. */
  12270. renderer: null,
  12271. /**
  12272. * @name Two#scene
  12273. * @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.
  12274. */
  12275. scene: null,
  12276. /**
  12277. * @name Two#width
  12278. * @property {Number} - The width of the instance's dom element.
  12279. */
  12280. width: 0,
  12281. /**
  12282. * @name Two#height
  12283. * @property {Number} - The height of the instance's dom element.
  12284. */
  12285. height: 0,
  12286. /**
  12287. * @name Two#frameCount
  12288. * @property {Number} - An integer representing how many frames have elapsed.
  12289. */
  12290. frameCount: 0,
  12291. /**
  12292. * @name Two#timeDelta
  12293. * @property {Number} - A number representing how much time has elapsed since the last frame in milliseconds.
  12294. */
  12295. timeDelta: 0,
  12296. /**
  12297. * @name Two#playing
  12298. * @property {Boolean} - A boolean representing whether or not the instance is being updated through the automatic `requestAnimationFrame`.
  12299. */
  12300. playing: false,
  12301. /**
  12302. * @name Two#appendTo
  12303. * @function
  12304. * @param {Element} elem - The DOM element to append the Two.js stage to.
  12305. * @description Shorthand method to append your instance of Two.js to the `document`.
  12306. */
  12307. appendTo: function(elem) {
  12308. elem.appendChild(this.renderer.domElement);
  12309. if (this.fit) {
  12310. if (this.fit.domElement !== window) {
  12311. this.fit.domElement = elem;
  12312. this.fit.attached = false;
  12313. }
  12314. this.update();
  12315. }
  12316. return this;
  12317. },
  12318. /**
  12319. * @name Two#play
  12320. * @function
  12321. * @fires Two.Events.Types.play event
  12322. * @description Call to start an internal animation loop.
  12323. * @nota-bene This function initiates a `requestAnimationFrame` loop.
  12324. */
  12325. play: function() {
  12326. this.playing = true;
  12327. raf.init();
  12328. return this.trigger(Events.Types.play);
  12329. },
  12330. /**
  12331. * @name Two#pause
  12332. * @function
  12333. * @fires Two.Events.Types.pause event
  12334. * @description Call to stop the internal animation loop for a specific instance of Two.js.
  12335. */
  12336. pause: function() {
  12337. this.playing = false;
  12338. return this.trigger(Events.Types.pause);
  12339. },
  12340. setPlaying: function(p) {
  12341. this.playing = p;
  12342. },
  12343. /**
  12344. * @name Two#release
  12345. * @function
  12346. * @param {Object} obj
  12347. * @returns {Object} The object passed for event deallocation.
  12348. * @description Release an arbitrary class' events from the Two.js corpus and recurse through its children and or vertices.
  12349. */
  12350. release: function(obj) {
  12351. var i, v, child;
  12352. if (!_.isObject(obj)) {
  12353. return;
  12354. }
  12355. if (typeof obj.unbind === 'function') {
  12356. obj.unbind();
  12357. }
  12358. if (obj.vertices) {
  12359. if (typeof obj.vertices.unbind === 'function') {
  12360. obj.vertices.unbind();
  12361. }
  12362. for (i = 0; i < obj.vertices.length; i++) {
  12363. v = obj.vertices[i];
  12364. if (typeof v.unbind === 'function') {
  12365. v.unbind();
  12366. }
  12367. }
  12368. }
  12369. if (obj.children) {
  12370. for (i = 0; i < obj.children.length; i++) {
  12371. child = obj.children[i];
  12372. this.release(child);
  12373. }
  12374. }
  12375. return obj;
  12376. },
  12377. /**
  12378. * @name Two#update
  12379. * @function
  12380. * @fires Two.Events.Types.update event
  12381. * @description Update positions and calculations in one pass before rendering. Then render to the canvas.
  12382. * @nota-bene This function is called automatically if using {@link Two#play} or the `autostart` parameter in construction.
  12383. */
  12384. update: function() {
  12385. var animated = !!this._lastFrame;
  12386. var now = _.performance.now();
  12387. if (animated) {
  12388. this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3));
  12389. }
  12390. this._lastFrame = now;
  12391. if (this.fit && this.fit.domElement && !this.fit.attached) {
  12392. dom.bind(this.fit.domElement, 'resize', this.fit);
  12393. this.fit.attached = true;
  12394. this.fit();
  12395. }
  12396. var width = this.width;
  12397. var height = this.height;
  12398. var renderer = this.renderer;
  12399. // Update width / height for the renderer
  12400. if (width !== renderer.width || height !== renderer.height) {
  12401. renderer.setSize(width, height, this.ratio);
  12402. }
  12403. this.trigger(Events.Types.update, this.frameCount, this.timeDelta);
  12404. return this.render();
  12405. },
  12406. /**
  12407. * @name Two#render
  12408. * @function
  12409. * @fires render
  12410. * @description Render all drawable and visible objects of the scene.
  12411. */
  12412. render: function() {
  12413. this.renderer.render();
  12414. return this.trigger(Events.Types.render, this.frameCount++);
  12415. },
  12416. // Convenience Methods
  12417. /**
  12418. * @name Two#add
  12419. * @function
  12420. * @param {(Two.Shape[]|...Two.Shape)} [objects] - An array of Two.js objects. Alternatively can add objects as individual arguments.
  12421. * @description A shorthand method to add specific Two.js objects to the scene.
  12422. */
  12423. add: function(o) {
  12424. var objects = o;
  12425. if (!(objects instanceof Array)) {
  12426. objects = Array.prototype.slice.call(arguments);
  12427. }
  12428. this.scene.add(objects);
  12429. return this;
  12430. },
  12431. /**
  12432. * @name Two#remove
  12433. * @function
  12434. * @param {(Two.Shape[]|...Two.Shape)} [objects] - An array of Two.js objects.
  12435. * @description A shorthand method to remove specific Two.js objects from the scene.
  12436. */
  12437. remove: function(o) {
  12438. var objects = o;
  12439. if (!(objects instanceof Array)) {
  12440. objects = Array.prototype.slice.call(arguments);
  12441. }
  12442. this.scene.remove(objects);
  12443. return this;
  12444. },
  12445. /**
  12446. * @name Two#clear
  12447. * @function
  12448. * @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.
  12449. */
  12450. clear: function() {
  12451. this.scene.remove(this.scene.children);
  12452. return this;
  12453. },
  12454. /**
  12455. * @name Two#makeLine
  12456. * @function
  12457. * @param {Number} x1
  12458. * @param {Number} y1
  12459. * @param {Number} x2
  12460. * @param {Number} y2
  12461. * @returns {Two.Line}
  12462. * @description Creates a Two.js line and adds it to the scene.
  12463. */
  12464. makeLine: function(x1, y1, x2, y2) {
  12465. var line = new Line(x1, y1, x2, y2);
  12466. this.scene.add(line);
  12467. return line;
  12468. },
  12469. /**
  12470. * @name Two#makeArrow
  12471. * @function
  12472. * @param {Number} x1
  12473. * @param {Number} y1
  12474. * @param {Number} x2
  12475. * @param {Number} y2
  12476. * @returns {Two.Path}
  12477. * @description Creates a Two.js arrow and adds it to the scene.
  12478. */
  12479. makeArrow: function(x1, y1, x2, y2, size) {
  12480. var headlen = typeof size === 'number' ? size : 10;
  12481. var angle = Math.atan2(y2 - y1, x2 - x1);
  12482. var vertices = [
  12483. new Anchor(x1, y1, undefined, undefined, undefined, undefined, Commands.move),
  12484. new Anchor(x2, y2, undefined, undefined, undefined, undefined, Commands.line),
  12485. new Anchor(
  12486. x2 - headlen * Math.cos(angle - Math.PI / 4),
  12487. y2 - headlen * Math.sin(angle - Math.PI / 4),
  12488. undefined, undefined, undefined, undefined, Commands.line
  12489. ),
  12490. new Anchor(x2, y2, undefined, undefined, undefined, undefined, Commands.move),
  12491. new Anchor(
  12492. x2 - headlen * Math.cos(angle + Math.PI / 4),
  12493. y2 - headlen * Math.sin(angle + Math.PI / 4),
  12494. undefined, undefined, undefined, undefined, Commands.line
  12495. )
  12496. ];
  12497. var path = new Path(vertices, false, false, true);
  12498. path.noFill();
  12499. path.cap = 'round';
  12500. path.join = 'round';
  12501. this.scene.add(path);
  12502. return path;
  12503. },
  12504. /**
  12505. * @name Two#makeRectangle
  12506. * @function
  12507. * @param {Number} x
  12508. * @param {Number} y
  12509. * @param {Number} width
  12510. * @param {Number} height
  12511. * @returns {Two.Rectangle}
  12512. * @description Creates a Two.js rectangle and adds it to the scene.
  12513. */
  12514. makeRectangle: function(x, y, width, height) {
  12515. var rect = new Rectangle(x, y, width, height);
  12516. this.scene.add(rect);
  12517. return rect;
  12518. },
  12519. /**
  12520. * @name Two#makeRoundedRectangle
  12521. * @function
  12522. * @param {Number} x
  12523. * @param {Number} y
  12524. * @param {Number} width
  12525. * @param {Number} height
  12526. * @param {Number} sides
  12527. * @returns {Two.Rectangle}
  12528. * @description Creates a Two.js rounded rectangle and adds it to the scene.
  12529. */
  12530. makeRoundedRectangle: function(x, y, width, height, sides) {
  12531. var rect = new RoundedRectangle(x, y, width, height, sides);
  12532. this.scene.add(rect);
  12533. return rect;
  12534. },
  12535. /**
  12536. * @name Two#makeCircle
  12537. * @function
  12538. * @param {Number} x
  12539. * @param {Number} y
  12540. * @param {Number} radius
  12541. * @param {Number} [resolution=4]
  12542. * @returns {Two.Circle}
  12543. * @description Creates a Two.js circle and adds it to the scene.
  12544. */
  12545. makeCircle: function(x, y, radius, resolution) {
  12546. var circle = new Circle(x, y, radius, resolution);
  12547. this.scene.add(circle);
  12548. return circle;
  12549. },
  12550. /**
  12551. * @name Two#makeEllipse
  12552. * @function
  12553. * @param {Number} x
  12554. * @param {Number} y
  12555. * @param {Number} rx
  12556. * @param {Number} ry
  12557. * @param {Number} [resolution=4]
  12558. * @returns {Two.Ellipse}
  12559. * @description Creates a Two.js ellipse and adds it to the scene.
  12560. */
  12561. makeEllipse: function(x, y, rx, ry, resolution) {
  12562. var ellipse = new Ellipse(x, y, rx, ry, resolution);
  12563. this.scene.add(ellipse);
  12564. return ellipse;
  12565. },
  12566. /**
  12567. * @name Two#makeStar
  12568. * @function
  12569. * @param {Number} x
  12570. * @param {Number} y
  12571. * @param {Number} outerRadius
  12572. * @param {Number} innerRadius
  12573. * @param {Number} sides
  12574. * @returns {Two.Star}
  12575. * @description Creates a Two.js star and adds it to the scene.
  12576. */
  12577. makeStar: function(ox, oy, outerRadius, innerRadius, sides) {
  12578. var star = new Star(ox, oy, outerRadius, innerRadius, sides);
  12579. this.scene.add(star);
  12580. return star;
  12581. },
  12582. /**
  12583. * @name Two#makeCurve
  12584. * @function
  12585. * @param {Two.Anchor[]} [points] - An array of {@link Two.Anchor} points.
  12586. * @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.
  12587. * @returns {Two.Path} - Where `path.curved` is set to `true`.
  12588. * @description Creates a Two.js path that is curved and adds it to the scene.
  12589. * @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.
  12590. */
  12591. makeCurve: function(p) {
  12592. var l = arguments.length, points = p;
  12593. if (!Array.isArray(p)) {
  12594. points = [];
  12595. for (var i = 0; i < l; i+=2) {
  12596. var x = arguments[i];
  12597. if (typeof x !== 'number') {
  12598. break;
  12599. }
  12600. var y = arguments[i + 1];
  12601. points.push(new Anchor(x, y));
  12602. }
  12603. }
  12604. var last = arguments[l - 1];
  12605. var curve = new Path(points, !(typeof last === 'boolean' ? last : undefined), true);
  12606. var rect = curve.getBoundingClientRect();
  12607. curve.center().translation
  12608. .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  12609. this.scene.add(curve);
  12610. return curve;
  12611. },
  12612. /**
  12613. * @name Two#makePolygon
  12614. * @function
  12615. * @param {Number} x
  12616. * @param {Number} y
  12617. * @param {Number} radius
  12618. * @param {Number} sides
  12619. * @returns {Two.Polygon}
  12620. * @description Creates a Two.js polygon and adds it to the scene.
  12621. */
  12622. makePolygon: function(x, y, radius, sides) {
  12623. var poly = new Polygon(x, y, radius, sides);
  12624. this.scene.add(poly);
  12625. return poly;
  12626. },
  12627. /**
  12628. * @name Two#makeArcSegment
  12629. * @function
  12630. * @param {Number} x
  12631. * @param {Number} y
  12632. * @param {Number} innerRadius
  12633. * @param {Number} outerRadius
  12634. * @param {Number} startAngle
  12635. * @param {Number} endAngle
  12636. * @param {Number} [resolution=Two.Resolution] - The number of vertices that should comprise the arc segment.
  12637. */
  12638. makeArcSegment: function(ox, oy, ir, or, sa, ea, res) {
  12639. var arcSegment = new ArcSegment(ox, oy, ir, or, sa, ea, res);
  12640. this.scene.add(arcSegment);
  12641. return arcSegment;
  12642. },
  12643. /**
  12644. * @name Two#makePath
  12645. * @function
  12646. * @param {Two.Anchor[]} [points] - An array of {@link Two.Anchor} points.
  12647. * @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.
  12648. * @returns {Two.Path}
  12649. * @description Creates a Two.js path and adds it to the scene.
  12650. * @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.
  12651. */
  12652. makePath: function(p) {
  12653. var l = arguments.length, points = p;
  12654. if (!Array.isArray(p)) {
  12655. points = [];
  12656. for (var i = 0; i < l; i+=2) {
  12657. var x = arguments[i];
  12658. if (typeof x !== 'number') {
  12659. break;
  12660. }
  12661. var y = arguments[i + 1];
  12662. points.push(new Anchor(x, y));
  12663. }
  12664. }
  12665. var last = arguments[l - 1];
  12666. var path = new Path(points, !(typeof last === 'boolean' ? last : undefined));
  12667. var rect = path.getBoundingClientRect();
  12668. if (typeof rect.top === 'number' && typeof rect.left === 'number' &&
  12669. typeof rect.right === 'number' && typeof rect.bottom === 'number') {
  12670. path.center().translation
  12671. .set(rect.left + rect.width / 2, rect.top + rect.height / 2);
  12672. }
  12673. this.scene.add(path);
  12674. return path;
  12675. },
  12676. /**
  12677. * @name Two#makeText
  12678. * @function
  12679. * @param {String} message
  12680. * @param {Number} x
  12681. * @param {Number} y
  12682. * @param {Object} [styles] - An object to describe any of the {@link Two.Text.Properties} including `fill`, `stroke`, `linewidth`, `family`, `alignment`, `leading`, `opacity`, etc..
  12683. * @returns {Two.Text}
  12684. * @description Creates a Two.js text object and adds it to the scene.
  12685. */
  12686. makeText: function(message, x, y, styles) {
  12687. var text = new Text(message, x, y, styles);
  12688. this.add(text);
  12689. return text;
  12690. },
  12691. /**
  12692. * @name Two#makeLinearGradient
  12693. * @function
  12694. * @param {Number} x1
  12695. * @param {Number} y1
  12696. * @param {Number} x2
  12697. * @param {Number} y2
  12698. * @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.
  12699. * @returns {Two.LinearGradient}
  12700. * @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.
  12701. */
  12702. makeLinearGradient: function(x1, y1, x2, y2 /* stops */) {
  12703. var stops = Array.prototype.slice.call(arguments, 4);
  12704. var gradient = new LinearGradient(x1, y1, x2, y2, stops);
  12705. this.add(gradient);
  12706. return gradient;
  12707. },
  12708. /**
  12709. * @name Two#makeRadialGradient
  12710. * @function
  12711. * @param {Number} x1
  12712. * @param {Number} y1
  12713. * @param {Number} radius
  12714. * @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.
  12715. * @returns {Two.RadialGradient}
  12716. * @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.
  12717. */
  12718. makeRadialGradient: function(x1, y1, r /* stops */) {
  12719. var stops = Array.prototype.slice.call(arguments, 3);
  12720. var gradient = new RadialGradient(x1, y1, r, stops);
  12721. this.add(gradient);
  12722. return gradient;
  12723. },
  12724. /**
  12725. * @name Two#makeSprite
  12726. * @function
  12727. * @param {(String|Two.Texture)} pathOrTexture - The URL path to an image or an already created {@link Two.Texture}.
  12728. * @param {Number} x
  12729. * @param {Number} y
  12730. * @param {Number} [columns=1]
  12731. * @param {Number} [rows=1]
  12732. * @param {Number} [frameRate=0]
  12733. * @param {Boolean} [autostart=false]
  12734. * @returns {Two.Sprite}
  12735. * @description Creates a Two.js sprite object and adds it to the scene. Sprites can be used for still images as well as animations.
  12736. */
  12737. makeSprite: function(path, x, y, cols, rows, frameRate, autostart) {
  12738. var sprite = new Sprite(path, x, y, cols, rows, frameRate);
  12739. if (autostart) {
  12740. sprite.play();
  12741. }
  12742. this.add(sprite);
  12743. return sprite;
  12744. },
  12745. /**
  12746. * @name Two#makeImageSequence
  12747. * @function
  12748. * @param {(String[]|Two.Texture[])} pathsOrTextures - An array of paths or of {@link Two.Textures}.
  12749. * @param {Number} x
  12750. * @param {Number} y
  12751. * @param {Number} [frameRate=0]
  12752. * @param {Boolean} [autostart=false]
  12753. * @returns {Two.ImageSequence}
  12754. * @description Creates a Two.js image sequence object and adds it to the scene.
  12755. */
  12756. makeImageSequence: function(paths, x, y, frameRate, autostart) {
  12757. var imageSequence = new ImageSequence(paths, x, y, frameRate);
  12758. if (autostart) {
  12759. imageSequence.play();
  12760. }
  12761. this.add(imageSequence);
  12762. return imageSequence;
  12763. },
  12764. /**
  12765. * @name Two#makeTexture
  12766. * @function
  12767. * @param {(String|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement)} [pathOrSource] - The URL path to an image or a DOM image-like element.
  12768. * @param {Function} [callback] - Function to be invoked when the image is loaded.
  12769. * @returns {Two.Texture}
  12770. * @description Creates a Two.js texture object.
  12771. */
  12772. makeTexture: function(path, callback) {
  12773. var texture = new Texture(path, callback);
  12774. return texture;
  12775. },
  12776. /**
  12777. * @name Two#makeGroup
  12778. * @function
  12779. * @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.
  12780. * @returns {Two.Group}
  12781. * @description Creates a Two.js group object and adds it to the scene.
  12782. */
  12783. makeGroup: function(o) {
  12784. var objects = o;
  12785. if (!(objects instanceof Array)) {
  12786. objects = Array.prototype.slice.call(arguments);
  12787. }
  12788. var group = new Group();
  12789. this.scene.add(group);
  12790. group.add(objects);
  12791. return group;
  12792. },
  12793. /**
  12794. * @name Two#interpret
  12795. * @function
  12796. * @param {SVGElement} SVGElement - The SVG node to be parsed.
  12797. * @param {Boolean} shallow - Don't create a top-most group but append all content directly.
  12798. * @param {Boolean} add – Automatically add the reconstructed SVG node to scene.
  12799. * @returns {Two.Group}
  12800. * @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.
  12801. */
  12802. interpret: function(SVGElement, shallow, add) {
  12803. var tag = SVGElement.tagName.toLowerCase();
  12804. add = (typeof add !== 'undefined') ? add : true;
  12805. if (!(tag in read)) {
  12806. return null;
  12807. }
  12808. var node = read[tag].call(this, SVGElement);
  12809. if (add) {
  12810. this.add(shallow && node instanceof Group ? node.children : node);
  12811. } else if (node.parent) {
  12812. // Remove `g` tags that have been added to scenegraph / DOM
  12813. // in order to be compatible with `getById` methods.
  12814. node.remove();
  12815. }
  12816. return node;
  12817. },
  12818. /**
  12819. * @name Two#load
  12820. * @function
  12821. * @param {String|SVGElement} pathOrSVGContent - The URL path of an SVG file or an SVG document as text.
  12822. * @param {Function} callback - Function to call once loading has completed.
  12823. * @returns {Two.Group}
  12824. * @description Load an SVG file or SVG text and interpret it into Two.js legible objects.
  12825. */
  12826. load: function(text, callback) {
  12827. var group = new Group();
  12828. var elem, i, j, child;
  12829. var attach = (function(data) {
  12830. dom.temp.innerHTML = data;
  12831. for (i = 0; i < dom.temp.children.length; i++) {
  12832. elem = dom.temp.children[i];
  12833. if (/svg/i.test(elem.nodeName)) {
  12834. child = this.interpret(elem);
  12835. // Two.Utils.applySvgViewBox.call(this, group, elem.getAttribute('viewBox'));
  12836. for (j = 0; j < child.children.length; j++) {
  12837. group.add(child.children[j]);
  12838. }
  12839. } else {
  12840. group.add(this.interpret(elem));
  12841. }
  12842. }
  12843. if (typeof callback === 'function') {
  12844. var svg = dom.temp.children.length <= 1
  12845. ? dom.temp.children[0] : dom.temp.children;
  12846. callback(group, svg);
  12847. }
  12848. }).bind(this);
  12849. if (/.*\.svg/ig.test(text)) {
  12850. xhr(text, attach);
  12851. return group;
  12852. }
  12853. attach(text);
  12854. return group;
  12855. }
  12856. });
  12857. function fitToWindow() {
  12858. var wr = document.body.getBoundingClientRect();
  12859. var width = this.width = wr.width;
  12860. var height = this.height = wr.height;
  12861. this.renderer.setSize(width, height, this.ratio);
  12862. }
  12863. function fitToParent() {
  12864. var parent = this.renderer.domElement.parentElement;
  12865. if (!parent) {
  12866. console.warn('Two.js: Attempting to fit to parent, but no parent found.');
  12867. return;
  12868. }
  12869. var wr = parent.getBoundingClientRect();
  12870. var width = this.width = wr.width;
  12871. var height = this.height = wr.height;
  12872. this.renderer.setSize(width, height, this.ratio);
  12873. }
  12874. function updateDimensions(width, height) {
  12875. this.width = width;
  12876. this.height = height;
  12877. this.trigger(Events.Types.resize, width, height);
  12878. }
  12879. // Request Animation Frame
  12880. var raf = dom.getRequestAnimationFrame();
  12881. function loop() {
  12882. for (var i = 0; i < Two.Instances.length; i++) {
  12883. var t = Two.Instances[i];
  12884. if (t.playing) {
  12885. t.update();
  12886. }
  12887. }
  12888. Two.nextFrameID = raf(loop);
  12889. }
  12890. raf.init = function() {
  12891. loop();
  12892. raf.init = function() {};
  12893. };
  12894. _.extend(Two, {
  12895. Anchor: Anchor,
  12896. Collection: Collection,
  12897. Events: Events,
  12898. Group: Group,
  12899. Matrix: Matrix,
  12900. Path: Path,
  12901. Registry: Registry,
  12902. Shape: Shape,
  12903. Text: Text,
  12904. Vector: Vector,
  12905. Gradient: Gradient,
  12906. ImageSequence: ImageSequence,
  12907. LinearGradient: LinearGradient,
  12908. RadialGradient: RadialGradient,
  12909. Sprite: Sprite,
  12910. Stop: Stop,
  12911. Texture: Texture,
  12912. ArcSegment: ArcSegment,
  12913. Circle: Circle,
  12914. Ellipse: Ellipse,
  12915. Line: Line,
  12916. Polygon: Polygon,
  12917. Rectangle: Rectangle,
  12918. RoundedRectangle: RoundedRectangle,
  12919. Star: Star,
  12920. CanvasRenderer: Renderer$2,
  12921. SVGRenderer: Renderer$1,
  12922. WebGLRenderer: Renderer,
  12923. Commands: Commands,
  12924. /**
  12925. * @name Two.Utils
  12926. * @property {Object} - A massive object filled with utility functions and properties.
  12927. */
  12928. Utils: _.extend({
  12929. Error: TwoError,
  12930. getRatio: getRatio,
  12931. defineGetterSetter: defineGetterSetter,
  12932. read: read,
  12933. xhr: xhr
  12934. }, _, CanvasShim, Curves, math)
  12935. });
  12936. return Two;
  12937. })));