snap.svg.js 219 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925
  1. // Snap.svg 0.2.0
  2. //
  3. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. // build: 2013-12-23
  18. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  19. //
  20. // Licensed under the Apache License, Version 2.0 (the "License");
  21. // you may not use this file except in compliance with the License.
  22. // You may obtain a copy of the License at
  23. //
  24. // http://www.apache.org/licenses/LICENSE-2.0
  25. //
  26. // Unless required by applicable law or agreed to in writing, software
  27. // distributed under the License is distributed on an "AS IS" BASIS,
  28. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  29. // See the License for the specific language governing permissions and
  30. // limitations under the License.
  31. // ┌────────────────────────────────────────────────────────────┐ \\
  32. // │ Eve 0.4.2 - JavaScript Events Library │ \\
  33. // ├────────────────────────────────────────────────────────────┤ \\
  34. // │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\
  35. // └────────────────────────────────────────────────────────────┘ \\
  36. (function (glob) {
  37. var version = "0.4.2",
  38. has = "hasOwnProperty",
  39. separator = /[\.\/]/,
  40. wildcard = "*",
  41. fun = function () {},
  42. numsort = function (a, b) {
  43. return a - b;
  44. },
  45. current_event,
  46. stop,
  47. events = {n: {}},
  48. /*\
  49. * eve
  50. [ method ]
  51. * Fires event with given `name`, given scope and other parameters.
  52. > Arguments
  53. - name (string) name of the *event*, dot (`.`) or slash (`/`) separated
  54. - scope (object) context for the event handlers
  55. - varargs (...) the rest of arguments will be sent to event handlers
  56. = (object) array of returned values from the listeners
  57. \*/
  58. eve = function (name, scope) {
  59. name = String(name);
  60. var e = events,
  61. oldstop = stop,
  62. args = Array.prototype.slice.call(arguments, 2),
  63. listeners = eve.listeners(name),
  64. z = 0,
  65. f = false,
  66. l,
  67. indexed = [],
  68. queue = {},
  69. out = [],
  70. ce = current_event,
  71. errors = [];
  72. current_event = name;
  73. stop = 0;
  74. for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) {
  75. indexed.push(listeners[i].zIndex);
  76. if (listeners[i].zIndex < 0) {
  77. queue[listeners[i].zIndex] = listeners[i];
  78. }
  79. }
  80. indexed.sort(numsort);
  81. while (indexed[z] < 0) {
  82. l = queue[indexed[z++]];
  83. out.push(l.apply(scope, args));
  84. if (stop) {
  85. stop = oldstop;
  86. return out;
  87. }
  88. }
  89. for (i = 0; i < ii; i++) {
  90. l = listeners[i];
  91. if ("zIndex" in l) {
  92. if (l.zIndex == indexed[z]) {
  93. out.push(l.apply(scope, args));
  94. if (stop) {
  95. break;
  96. }
  97. do {
  98. z++;
  99. l = queue[indexed[z]];
  100. l && out.push(l.apply(scope, args));
  101. if (stop) {
  102. break;
  103. }
  104. } while (l)
  105. } else {
  106. queue[l.zIndex] = l;
  107. }
  108. } else {
  109. out.push(l.apply(scope, args));
  110. if (stop) {
  111. break;
  112. }
  113. }
  114. }
  115. stop = oldstop;
  116. current_event = ce;
  117. return out.length ? out : null;
  118. };
  119. // Undocumented. Debug only.
  120. eve._events = events;
  121. /*\
  122. * eve.listeners
  123. [ method ]
  124. * Internal method which gives you array of all event handlers that will be triggered by the given `name`.
  125. > Arguments
  126. - name (string) name of the event, dot (`.`) or slash (`/`) separated
  127. = (array) array of event handlers
  128. \*/
  129. eve.listeners = function (name) {
  130. var names = name.split(separator),
  131. e = events,
  132. item,
  133. items,
  134. k,
  135. i,
  136. ii,
  137. j,
  138. jj,
  139. nes,
  140. es = [e],
  141. out = [];
  142. for (i = 0, ii = names.length; i < ii; i++) {
  143. nes = [];
  144. for (j = 0, jj = es.length; j < jj; j++) {
  145. e = es[j].n;
  146. items = [e[names[i]], e[wildcard]];
  147. k = 2;
  148. while (k--) {
  149. item = items[k];
  150. if (item) {
  151. nes.push(item);
  152. out = out.concat(item.f || []);
  153. }
  154. }
  155. }
  156. es = nes;
  157. }
  158. return out;
  159. };
  160. /*\
  161. * eve.on
  162. [ method ]
  163. **
  164. * Binds given event handler with a given name. You can use wildcards “`*`” for the names:
  165. | eve.on("*.under.*", f);
  166. | eve("mouse.under.floor"); // triggers f
  167. * Use @eve to trigger the listener.
  168. **
  169. > Arguments
  170. **
  171. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  172. - f (function) event handler function
  173. **
  174. = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment.
  175. > Example:
  176. | eve.on("mouse", eatIt)(2);
  177. | eve.on("mouse", scream);
  178. | eve.on("mouse", catchIt)(1);
  179. * This will ensure that `catchIt()` function will be called before `eatIt()`.
  180. *
  181. * If you want to put your handler before non-indexed handlers, specify a negative value.
  182. * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”.
  183. \*/
  184. eve.on = function (name, f) {
  185. name = String(name);
  186. if (typeof f != "function") {
  187. return function () {};
  188. }
  189. var names = name.split(separator),
  190. e = events;
  191. for (var i = 0, ii = names.length; i < ii; i++) {
  192. e = e.n;
  193. e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}});
  194. }
  195. e.f = e.f || [];
  196. for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) {
  197. return fun;
  198. }
  199. e.f.push(f);
  200. return function (zIndex) {
  201. if (+zIndex == +zIndex) {
  202. f.zIndex = +zIndex;
  203. }
  204. };
  205. };
  206. /*\
  207. * eve.f
  208. [ method ]
  209. **
  210. * Returns function that will fire given event with optional arguments.
  211. * Arguments that will be passed to the result function will be also
  212. * concated to the list of final arguments.
  213. | el.onclick = eve.f("click", 1, 2);
  214. | eve.on("click", function (a, b, c) {
  215. | console.log(a, b, c); // 1, 2, [event object]
  216. | });
  217. > Arguments
  218. - event (string) event name
  219. - varargs (…) and any other arguments
  220. = (function) possible event handler function
  221. \*/
  222. eve.f = function (event) {
  223. var attrs = [].slice.call(arguments, 1);
  224. return function () {
  225. eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0)));
  226. };
  227. };
  228. /*\
  229. * eve.stop
  230. [ method ]
  231. **
  232. * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing.
  233. \*/
  234. eve.stop = function () {
  235. stop = 1;
  236. };
  237. /*\
  238. * eve.nt
  239. [ method ]
  240. **
  241. * Could be used inside event handler to figure out actual name of the event.
  242. **
  243. > Arguments
  244. **
  245. - subname (string) #optional subname of the event
  246. **
  247. = (string) name of the event, if `subname` is not specified
  248. * or
  249. = (boolean) `true`, if current event’s name contains `subname`
  250. \*/
  251. eve.nt = function (subname) {
  252. if (subname) {
  253. return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event);
  254. }
  255. return current_event;
  256. };
  257. /*\
  258. * eve.nts
  259. [ method ]
  260. **
  261. * Could be used inside event handler to figure out actual name of the event.
  262. **
  263. **
  264. = (array) names of the event
  265. \*/
  266. eve.nts = function () {
  267. return current_event.split(separator);
  268. };
  269. /*\
  270. * eve.off
  271. [ method ]
  272. **
  273. * Removes given function from the list of event listeners assigned to given name.
  274. * If no arguments specified all the events will be cleared.
  275. **
  276. > Arguments
  277. **
  278. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  279. - f (function) event handler function
  280. \*/
  281. /*\
  282. * eve.unbind
  283. [ method ]
  284. **
  285. * See @eve.off
  286. \*/
  287. eve.off = eve.unbind = function (name, f) {
  288. if (!name) {
  289. eve._events = events = {n: {}};
  290. return;
  291. }
  292. var names = name.split(separator),
  293. e,
  294. key,
  295. splice,
  296. i, ii, j, jj,
  297. cur = [events];
  298. for (i = 0, ii = names.length; i < ii; i++) {
  299. for (j = 0; j < cur.length; j += splice.length - 2) {
  300. splice = [j, 1];
  301. e = cur[j].n;
  302. if (names[i] != wildcard) {
  303. if (e[names[i]]) {
  304. splice.push(e[names[i]]);
  305. }
  306. } else {
  307. for (key in e) if (e[has](key)) {
  308. splice.push(e[key]);
  309. }
  310. }
  311. cur.splice.apply(cur, splice);
  312. }
  313. }
  314. for (i = 0, ii = cur.length; i < ii; i++) {
  315. e = cur[i];
  316. while (e.n) {
  317. if (f) {
  318. if (e.f) {
  319. for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) {
  320. e.f.splice(j, 1);
  321. break;
  322. }
  323. !e.f.length && delete e.f;
  324. }
  325. for (key in e.n) if (e.n[has](key) && e.n[key].f) {
  326. var funcs = e.n[key].f;
  327. for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) {
  328. funcs.splice(j, 1);
  329. break;
  330. }
  331. !funcs.length && delete e.n[key].f;
  332. }
  333. } else {
  334. delete e.f;
  335. for (key in e.n) if (e.n[has](key) && e.n[key].f) {
  336. delete e.n[key].f;
  337. }
  338. }
  339. e = e.n;
  340. }
  341. }
  342. };
  343. /*\
  344. * eve.once
  345. [ method ]
  346. **
  347. * Binds given event handler with a given name to only run once then unbind itself.
  348. | eve.once("login", f);
  349. | eve("login"); // triggers f
  350. | eve("login"); // no listeners
  351. * Use @eve to trigger the listener.
  352. **
  353. > Arguments
  354. **
  355. - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards
  356. - f (function) event handler function
  357. **
  358. = (function) same return function as @eve.on
  359. \*/
  360. eve.once = function (name, f) {
  361. var f2 = function () {
  362. eve.unbind(name, f2);
  363. return f.apply(this, arguments);
  364. };
  365. return eve.on(name, f2);
  366. };
  367. /*\
  368. * eve.version
  369. [ property (string) ]
  370. **
  371. * Current version of the library.
  372. \*/
  373. eve.version = version;
  374. eve.toString = function () {
  375. return "You are running Eve " + version;
  376. };
  377. (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve));
  378. })(this);
  379. (function (glob, factory) {
  380. // AMD support
  381. if (typeof define === "function" && define.amd) {
  382. // Define as an anonymous module
  383. define(["eve"], function( eve ) {
  384. return factory(glob, eve);
  385. });
  386. } else {
  387. // Browser globals (glob is window)
  388. // Snap adds itself to window
  389. factory(glob, glob.eve);
  390. }
  391. }(this, function (window, eve) {
  392. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  393. //
  394. // Licensed under the Apache License, Version 2.0 (the "License");
  395. // you may not use this file except in compliance with the License.
  396. // You may obtain a copy of the License at
  397. //
  398. // http://www.apache.org/licenses/LICENSE-2.0
  399. //
  400. // Unless required by applicable law or agreed to in writing, software
  401. // distributed under the License is distributed on an "AS IS" BASIS,
  402. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  403. // See the License for the specific language governing permissions and
  404. // limitations under the License.
  405. var mina = (function (eve) {
  406. var animations = {},
  407. requestAnimFrame = window.requestAnimationFrame ||
  408. window.webkitRequestAnimationFrame ||
  409. window.mozRequestAnimationFrame ||
  410. window.oRequestAnimationFrame ||
  411. window.msRequestAnimationFrame ||
  412. function (callback) {
  413. setTimeout(callback, 16);
  414. },
  415. isArray = Array.isArray || function (a) {
  416. return a instanceof Array ||
  417. Object.prototype.toString.call(a) == "[object Array]";
  418. },
  419. idgen = 0,
  420. idprefix = "M" + (+new Date).toString(36),
  421. ID = function () {
  422. return idprefix + (idgen++).toString(36);
  423. },
  424. diff = function (a, b, A, B) {
  425. if (isArray(a)) {
  426. res = [];
  427. for (var i = 0, ii = a.length; i < ii; i++) {
  428. res[i] = diff(a[i], b, A[i], B);
  429. }
  430. return res;
  431. }
  432. var dif = (A - a) / (B - b);
  433. return function (bb) {
  434. return a + dif * (bb - b);
  435. };
  436. },
  437. timer = Date.now || function () {
  438. return +new Date;
  439. },
  440. sta = function (val) {
  441. var a = this;
  442. if (val == null) {
  443. return a.s;
  444. }
  445. var ds = a.s - val;
  446. a.b += a.dur * ds;
  447. a.B += a.dur * ds;
  448. a.s = val;
  449. },
  450. speed = function (val) {
  451. var a = this;
  452. if (val == null) {
  453. return a.spd;
  454. }
  455. a.spd = val;
  456. },
  457. duration = function (val) {
  458. var a = this;
  459. if (val == null) {
  460. return a.dur;
  461. }
  462. a.s = a.s * val / a.dur;
  463. a.dur = val;
  464. },
  465. stopit = function () {
  466. var a = this;
  467. delete animations[a.id];
  468. eve("mina.stop." + a.id, a);
  469. },
  470. pause = function () {
  471. var a = this;
  472. if (a.pdif) {
  473. return;
  474. }
  475. delete animations[a.id];
  476. a.pdif = a.get() - a.b;
  477. },
  478. resume = function () {
  479. var a = this;
  480. if (!a.pdif) {
  481. return;
  482. }
  483. a.b = a.get() - a.pdif;
  484. delete a.pdif;
  485. animations[a.id] = a;
  486. },
  487. frame = function () {
  488. var len = 0;
  489. for (var i in animations) if (animations.hasOwnProperty(i)) {
  490. var a = animations[i],
  491. b = a.get(),
  492. res;
  493. len++;
  494. a.s = (b - a.b) / (a.dur / a.spd);
  495. if (a.s >= 1) {
  496. delete animations[i];
  497. a.s = 1;
  498. len--;
  499. (function (a) {
  500. setTimeout(function () {
  501. eve("mina.finish." + a.id, a);
  502. });
  503. }(a));
  504. }
  505. if (isArray(a.start)) {
  506. res = [];
  507. for (var j = 0, jj = a.start.length; j < jj; j++) {
  508. res[j] = +a.start[j] +
  509. (a.end[j] - a.start[j]) * a.easing(a.s);
  510. }
  511. } else {
  512. res = +a.start + (a.end - a.start) * a.easing(a.s);
  513. }
  514. a.set(res);
  515. }
  516. len && requestAnimFrame(frame);
  517. },
  518. // SIERRA Unfamiliar with the word _slave_ in this context. Also, I don't know what _gereal_ means. Do you mean _general_?
  519. /*\
  520. * mina
  521. [ method ]
  522. **
  523. * Generic animation of numbers
  524. **
  525. - a (number) start _slave_ number
  526. - A (number) end _slave_ number
  527. - b (number) start _master_ number (start time in general case)
  528. - B (number) end _master_ number (end time in gereal case)
  529. - get (function) getter of _master_ number (see @mina.time)
  530. - set (function) setter of _slave_ number
  531. - easing (function) #optional easing function, default is @mina.linear
  532. = (object) animation descriptor
  533. o {
  534. o id (string) animation id,
  535. o start (number) start _slave_ number,
  536. o end (number) end _slave_ number,
  537. o b (number) start _master_ number,
  538. o s (number) animation status (0..1),
  539. o dur (number) animation duration,
  540. o spd (number) animation speed,
  541. o get (function) getter of _master_ number (see @mina.time),
  542. o set (function) setter of _slave_ number,
  543. o easing (function) easing function, default is @mina.linear,
  544. o status (function) status getter/setter,
  545. o speed (function) speed getter/setter,
  546. o duration (function) duration getter/setter,
  547. o stop (function) animation stopper
  548. o }
  549. \*/
  550. mina = function (a, A, b, B, get, set, easing) {
  551. var anim = {
  552. id: ID(),
  553. start: a,
  554. end: A,
  555. b: b,
  556. s: 0,
  557. dur: B - b,
  558. spd: 1,
  559. get: get,
  560. set: set,
  561. easing: easing || mina.linear,
  562. status: sta,
  563. speed: speed,
  564. duration: duration,
  565. stop: stopit,
  566. pause: pause,
  567. resume: resume
  568. };
  569. animations[anim.id] = anim;
  570. var len = 0, i;
  571. for (i in animations) if (animations.hasOwnProperty(i)) {
  572. len++;
  573. if (len == 2) {
  574. break;
  575. }
  576. }
  577. len == 1 && requestAnimFrame(frame);
  578. return anim;
  579. };
  580. /*\
  581. * mina.time
  582. [ method ]
  583. **
  584. * Returns the current time. Equivalent to:
  585. | function () {
  586. | return (new Date).getTime();
  587. | }
  588. \*/
  589. mina.time = timer;
  590. /*\
  591. * mina.getById
  592. [ method ]
  593. **
  594. * Returns an animation by its id
  595. - id (string) animation's id
  596. = (object) See @mina
  597. \*/
  598. mina.getById = function (id) {
  599. return animations[id] || null;
  600. };
  601. /*\
  602. * mina.linear
  603. [ method ]
  604. **
  605. * Default linear easing
  606. - n (number) input 0..1
  607. = (number) output 0..1
  608. \*/
  609. mina.linear = function (n) {
  610. return n;
  611. };
  612. /*\
  613. * mina.easeout
  614. [ method ]
  615. **
  616. * Easeout easing
  617. - n (number) input 0..1
  618. = (number) output 0..1
  619. \*/
  620. mina.easeout = function (n) {
  621. return Math.pow(n, 1.7);
  622. };
  623. /*\
  624. * mina.easein
  625. [ method ]
  626. **
  627. * Easein easing
  628. - n (number) input 0..1
  629. = (number) output 0..1
  630. \*/
  631. mina.easein = function (n) {
  632. return Math.pow(n, .48);
  633. };
  634. /*\
  635. * mina.easeinout
  636. [ method ]
  637. **
  638. * Easeinout easing
  639. - n (number) input 0..1
  640. = (number) output 0..1
  641. \*/
  642. mina.easeinout = function (n) {
  643. if (n == 1) {
  644. return 1;
  645. }
  646. if (n == 0) {
  647. return 0;
  648. }
  649. var q = .48 - n / 1.04,
  650. Q = Math.sqrt(.1734 + q * q),
  651. x = Q - q,
  652. X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1),
  653. y = -Q - q,
  654. Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1),
  655. t = X + Y + .5;
  656. return (1 - t) * 3 * t * t + t * t * t;
  657. };
  658. /*\
  659. * mina.backin
  660. [ method ]
  661. **
  662. * Backin easing
  663. - n (number) input 0..1
  664. = (number) output 0..1
  665. \*/
  666. mina.backin = function (n) {
  667. if (n == 1) {
  668. return 1;
  669. }
  670. var s = 1.70158;
  671. return n * n * ((s + 1) * n - s);
  672. };
  673. /*\
  674. * mina.backout
  675. [ method ]
  676. **
  677. * Backout easing
  678. - n (number) input 0..1
  679. = (number) output 0..1
  680. \*/
  681. mina.backout = function (n) {
  682. if (n == 0) {
  683. return 0;
  684. }
  685. n = n - 1;
  686. var s = 1.70158;
  687. return n * n * ((s + 1) * n + s) + 1;
  688. };
  689. /*\
  690. * mina.elastic
  691. [ method ]
  692. **
  693. * Elastic easing
  694. - n (number) input 0..1
  695. = (number) output 0..1
  696. \*/
  697. mina.elastic = function (n) {
  698. if (n == !!n) {
  699. return n;
  700. }
  701. return Math.pow(2, -10 * n) * Math.sin((n - .075) *
  702. (2 * Math.PI) / .3) + 1;
  703. };
  704. /*\
  705. * mina.bounce
  706. [ method ]
  707. **
  708. * Bounce easing
  709. - n (number) input 0..1
  710. = (number) output 0..1
  711. \*/
  712. mina.bounce = function (n) {
  713. var s = 7.5625,
  714. p = 2.75,
  715. l;
  716. if (n < (1 / p)) {
  717. l = s * n * n;
  718. } else {
  719. if (n < (2 / p)) {
  720. n -= (1.5 / p);
  721. l = s * n * n + .75;
  722. } else {
  723. if (n < (2.5 / p)) {
  724. n -= (2.25 / p);
  725. l = s * n * n + .9375;
  726. } else {
  727. n -= (2.625 / p);
  728. l = s * n * n + .984375;
  729. }
  730. }
  731. }
  732. return l;
  733. };
  734. window.mina = mina;
  735. return mina;
  736. })(typeof eve == "undefined" ? function () {} : eve);
  737. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  738. //
  739. // Licensed under the Apache License, Version 2.0 (the "License");
  740. // you may not use this file except in compliance with the License.
  741. // You may obtain a copy of the License at
  742. //
  743. // http://www.apache.org/licenses/LICENSE-2.0
  744. //
  745. // Unless required by applicable law or agreed to in writing, software
  746. // distributed under the License is distributed on an "AS IS" BASIS,
  747. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  748. // See the License for the specific language governing permissions and
  749. // limitations under the License.
  750. var Snap = (function() {
  751. Snap.version = "0.2.0";
  752. /*\
  753. * Snap
  754. [ method ]
  755. **
  756. * Creates a drawing surface or wraps existing SVG element.
  757. **
  758. - width (number|string) width of surface
  759. - height (number|string) height of surface
  760. * or
  761. - DOM (SVGElement) element to be wrapped into Snap structure
  762. * or
  763. - query (string) CSS query selector
  764. = (object) @Element
  765. \*/
  766. function Snap(w, h) {
  767. if (w) {
  768. if (w.tagName) {
  769. return wrap(w);
  770. }
  771. if (w instanceof Element) {
  772. return w;
  773. }
  774. if (h == null) {
  775. w = glob.doc.querySelector(w);
  776. return wrap(w);
  777. }
  778. }
  779. w = w == null ? "100%" : w;
  780. h = h == null ? "100%" : h;
  781. return new Paper(w, h);
  782. }
  783. Snap.toString = function () {
  784. return "Snap v" + this.version;
  785. };
  786. Snap._ = {};
  787. var glob = {
  788. win: window,
  789. doc: window.document
  790. };
  791. Snap._.glob = glob;
  792. var has = "hasOwnProperty",
  793. Str = String,
  794. toFloat = parseFloat,
  795. toInt = parseInt,
  796. math = Math,
  797. mmax = math.max,
  798. mmin = math.min,
  799. abs = math.abs,
  800. pow = math.pow,
  801. PI = math.PI,
  802. round = math.round,
  803. E = "",
  804. S = " ",
  805. objectToString = Object.prototype.toString,
  806. ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
  807. colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,
  808. bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
  809. reURLValue = /^url\(#?([^)]+)\)$/,
  810. spaces = "\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029",
  811. separator = new RegExp("[," + spaces + "]+"),
  812. whitespace = new RegExp("[" + spaces + "]", "g"),
  813. commaSpaces = new RegExp("[" + spaces + "]*,[" + spaces + "]*"),
  814. hsrg = {hs: 1, rg: 1},
  815. pathCommand = new RegExp("([a-z])[" + spaces + ",]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[" + spaces + "]*,?[" + spaces + "]*)+)", "ig"),
  816. tCommand = new RegExp("([rstm])[" + spaces + ",]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[" + spaces + "]*,?[" + spaces + "]*)+)", "ig"),
  817. pathValues = new RegExp("(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[" + spaces + "]*,?[" + spaces + "]*", "ig"),
  818. idgen = 0,
  819. idprefix = "S" + (+new Date).toString(36),
  820. ID = function () {
  821. return idprefix + (idgen++).toString(36);
  822. },
  823. xlink = "http://www.w3.org/1999/xlink",
  824. xmlns = "http://www.w3.org/2000/svg",
  825. hub = {},
  826. URL = Snap.url = function (url) {
  827. return "url('#" + url + "')";
  828. };
  829. function $(el, attr) {
  830. if (attr) {
  831. if (typeof el == "string") {
  832. el = $(el);
  833. }
  834. if (typeof attr == "string") {
  835. if (attr.substring(0, 6) == "xlink:") {
  836. return el.getAttributeNS(xlink, attr.substring(6));
  837. }
  838. if (attr.substring(0, 4) == "xml:") {
  839. return el.getAttributeNS(xmlns, attr.substring(4));
  840. }
  841. return el.getAttribute(attr);
  842. }
  843. for (var key in attr) if (attr[has](key)) {
  844. var val = Str(attr[key]);
  845. if (val) {
  846. if (key.substring(0, 6) == "xlink:") {
  847. el.setAttributeNS(xlink, key.substring(6), val);
  848. } else if (key.substring(0, 4) == "xml:") {
  849. el.setAttributeNS(xmlns, key.substring(4), val);
  850. } else {
  851. el.setAttribute(key, val);
  852. }
  853. } else {
  854. el.removeAttribute(key);
  855. }
  856. }
  857. } else {
  858. el = glob.doc.createElementNS(xmlns, el);
  859. // el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
  860. }
  861. return el;
  862. }
  863. Snap._.$ = $;
  864. Snap._.id = ID;
  865. function getAttrs(el) {
  866. var attrs = el.attributes,
  867. name,
  868. out = {};
  869. for (var i = 0; i < attrs.length; i++) {
  870. if (attrs[i].namespaceURI == xlink) {
  871. name = "xlink:";
  872. } else {
  873. name = "";
  874. }
  875. name += attrs[i].name;
  876. out[name] = attrs[i].textContent;
  877. }
  878. return out;
  879. }
  880. function is(o, type) {
  881. type = Str.prototype.toLowerCase.call(type);
  882. if (type == "finite") {
  883. return isFinite(o);
  884. }
  885. if (type == "array" &&
  886. (o instanceof Array || Array.isArray && Array.isArray(o))) {
  887. return true;
  888. }
  889. return (type == "null" && o === null) ||
  890. (type == typeof o && o !== null) ||
  891. (type == "object" && o === Object(o)) ||
  892. objectToString.call(o).slice(8, -1).toLowerCase() == type;
  893. }
  894. /*\
  895. * Snap.format
  896. [ method ]
  897. **
  898. * Replaces construction of type `{<name>}` to the corresponding argument
  899. **
  900. - token (string) string to format
  901. - json (object) object which properties are used as a replacement
  902. = (string) formatted string
  903. > Usage
  904. | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z"
  905. | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", {
  906. | x: 10,
  907. | y: 20,
  908. | dim: {
  909. | width: 40,
  910. | height: 50,
  911. | "negative width": -40
  912. | }
  913. | }));
  914. \*/
  915. Snap.format = (function () {
  916. var tokenRegex = /\{([^\}]+)\}/g,
  917. objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties
  918. replacer = function (all, key, obj) {
  919. var res = obj;
  920. key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) {
  921. name = name || quotedName;
  922. if (res) {
  923. if (name in res) {
  924. res = res[name];
  925. }
  926. typeof res == "function" && isFunc && (res = res());
  927. }
  928. });
  929. res = (res == null || res == obj ? all : res) + "";
  930. return res;
  931. };
  932. return function (str, obj) {
  933. return Str(str).replace(tokenRegex, function (all, key) {
  934. return replacer(all, key, obj);
  935. });
  936. };
  937. })();
  938. var preload = (function () {
  939. function onerror() {
  940. this.parentNode.removeChild(this);
  941. }
  942. return function (src, f) {
  943. var img = glob.doc.createElement("img"),
  944. body = glob.doc.body;
  945. img.style.cssText = "position:absolute;left:-9999em;top:-9999em";
  946. img.onload = function () {
  947. f.call(img);
  948. img.onload = img.onerror = null;
  949. body.removeChild(img);
  950. };
  951. img.onerror = onerror;
  952. body.appendChild(img);
  953. img.src = src;
  954. };
  955. }());
  956. function clone(obj) {
  957. if (typeof obj == "function" || Object(obj) !== obj) {
  958. return obj;
  959. }
  960. var res = new obj.constructor;
  961. for (var key in obj) if (obj[has](key)) {
  962. res[key] = clone(obj[key]);
  963. }
  964. return res;
  965. }
  966. Snap._.clone = clone;
  967. function repush(array, item) {
  968. for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
  969. return array.push(array.splice(i, 1)[0]);
  970. }
  971. }
  972. function cacher(f, scope, postprocessor) {
  973. function newf() {
  974. var arg = Array.prototype.slice.call(arguments, 0),
  975. args = arg.join("\u2400"),
  976. cache = newf.cache = newf.cache || {},
  977. count = newf.count = newf.count || [];
  978. if (cache[has](args)) {
  979. repush(count, args);
  980. return postprocessor ? postprocessor(cache[args]) : cache[args];
  981. }
  982. count.length >= 1e3 && delete cache[count.shift()];
  983. count.push(args);
  984. cache[args] = f.apply(scope, arg);
  985. return postprocessor ? postprocessor(cache[args]) : cache[args];
  986. }
  987. return newf;
  988. }
  989. Snap._.cacher = cacher;
  990. function angle(x1, y1, x2, y2, x3, y3) {
  991. if (x3 == null) {
  992. var x = x1 - x2,
  993. y = y1 - y2;
  994. if (!x && !y) {
  995. return 0;
  996. }
  997. return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360;
  998. } else {
  999. return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3);
  1000. }
  1001. }
  1002. function rad(deg) {
  1003. return deg % 360 * PI / 180;
  1004. }
  1005. function deg(rad) {
  1006. return rad * 180 / PI % 360;
  1007. }
  1008. function x_y() {
  1009. return this.x + S + this.y;
  1010. }
  1011. function x_y_w_h() {
  1012. return this.x + S + this.y + S + this.width + " \xd7 " + this.height;
  1013. }
  1014. /*\
  1015. * Snap.rad
  1016. [ method ]
  1017. **
  1018. * Transform angle to radians
  1019. - deg (number) angle in degrees
  1020. = (number) angle in radians
  1021. \*/
  1022. Snap.rad = rad;
  1023. /*\
  1024. * Snap.deg
  1025. [ method ]
  1026. **
  1027. * Transform angle to degrees
  1028. - rad (number) angle in radians
  1029. = (number) angle in degrees
  1030. \*/
  1031. Snap.deg = deg;
  1032. // SIERRA for which point is the angle calculated?
  1033. /*\
  1034. * Snap.angle
  1035. [ method ]
  1036. **
  1037. * Returns an angle between two or three points
  1038. > Parameters
  1039. - x1 (number) x coord of first point
  1040. - y1 (number) y coord of first point
  1041. - x2 (number) x coord of second point
  1042. - y2 (number) y coord of second point
  1043. - x3 (number) #optional x coord of third point
  1044. - y3 (number) #optional y coord of third point
  1045. = (number) angle in degrees
  1046. \*/
  1047. Snap.angle = angle;
  1048. /*\
  1049. * Snap.is
  1050. [ method ]
  1051. **
  1052. * Handy replacement for the `typeof` operator
  1053. - o (…) any object or primitive
  1054. - type (string) name of the type, e.g., `string`, `function`, `number`, etc.
  1055. = (boolean) `true` if given value is of given type
  1056. \*/
  1057. Snap.is = is;
  1058. /*\
  1059. * Snap.snapTo
  1060. [ method ]
  1061. **
  1062. * Snaps given value to given grid
  1063. - values (array|number) given array of values or step of the grid
  1064. - value (number) value to adjust
  1065. - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`.
  1066. = (number) adjusted value
  1067. \*/
  1068. Snap.snapTo = function (values, value, tolerance) {
  1069. tolerance = is(tolerance, "finite") ? tolerance : 10;
  1070. if (is(values, "array")) {
  1071. var i = values.length;
  1072. while (i--) if (abs(values[i] - value) <= tolerance) {
  1073. return values[i];
  1074. }
  1075. } else {
  1076. values = +values;
  1077. var rem = value % values;
  1078. if (rem < tolerance) {
  1079. return value - rem;
  1080. }
  1081. if (rem > values - tolerance) {
  1082. return value - rem + values;
  1083. }
  1084. }
  1085. return value;
  1086. };
  1087. // MATRIX
  1088. function Matrix(a, b, c, d, e, f) {
  1089. if (b == null && objectToString.call(a) == "[object SVGMatrix]") {
  1090. this.a = a.a;
  1091. this.b = a.b;
  1092. this.c = a.c;
  1093. this.d = a.d;
  1094. this.e = a.e;
  1095. this.f = a.f;
  1096. return;
  1097. }
  1098. if (a != null) {
  1099. this.a = +a;
  1100. this.b = +b;
  1101. this.c = +c;
  1102. this.d = +d;
  1103. this.e = +e;
  1104. this.f = +f;
  1105. } else {
  1106. this.a = 1;
  1107. this.b = 0;
  1108. this.c = 0;
  1109. this.d = 1;
  1110. this.e = 0;
  1111. this.f = 0;
  1112. }
  1113. }
  1114. (function (matrixproto) {
  1115. /*\
  1116. * Matrix.add
  1117. [ method ]
  1118. **
  1119. * Adds the given matrix to existing one
  1120. - a (number)
  1121. - b (number)
  1122. - c (number)
  1123. - d (number)
  1124. - e (number)
  1125. - f (number)
  1126. * or
  1127. - matrix (object) @Matrix
  1128. \*/
  1129. matrixproto.add = function (a, b, c, d, e, f) {
  1130. var out = [[], [], []],
  1131. m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]],
  1132. matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
  1133. x, y, z, res;
  1134. if (a && a instanceof Matrix) {
  1135. matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]];
  1136. }
  1137. for (x = 0; x < 3; x++) {
  1138. for (y = 0; y < 3; y++) {
  1139. res = 0;
  1140. for (z = 0; z < 3; z++) {
  1141. res += m[x][z] * matrix[z][y];
  1142. }
  1143. out[x][y] = res;
  1144. }
  1145. }
  1146. this.a = out[0][0];
  1147. this.b = out[1][0];
  1148. this.c = out[0][1];
  1149. this.d = out[1][1];
  1150. this.e = out[0][2];
  1151. this.f = out[1][2];
  1152. return this;
  1153. };
  1154. /*\
  1155. * Matrix.invert
  1156. [ method ]
  1157. **
  1158. * Returns an inverted version of the matrix
  1159. = (object) @Matrix
  1160. \*/
  1161. matrixproto.invert = function () {
  1162. var me = this,
  1163. x = me.a * me.d - me.b * me.c;
  1164. return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x);
  1165. };
  1166. /*\
  1167. * Matrix.clone
  1168. [ method ]
  1169. **
  1170. * Returns a copy of the matrix
  1171. = (object) @Matrix
  1172. \*/
  1173. matrixproto.clone = function () {
  1174. return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
  1175. };
  1176. /*\
  1177. * Matrix.translate
  1178. [ method ]
  1179. **
  1180. * Translate the matrix
  1181. - x (number) horizontal offset distance
  1182. - y (number) vertical offset distance
  1183. \*/
  1184. matrixproto.translate = function (x, y) {
  1185. return this.add(1, 0, 0, 1, x, y);
  1186. };
  1187. /*\
  1188. * Matrix.scale
  1189. [ method ]
  1190. **
  1191. * Scales the matrix
  1192. - x (number) amount to be scaled, with `1` resulting in no change
  1193. - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.)
  1194. - cx (number) #optional horizontal origin point from which to scale
  1195. - cy (number) #optional vertical origin point from which to scale
  1196. * Default cx, cy is the middle point of the element.
  1197. \*/
  1198. matrixproto.scale = function (x, y, cx, cy) {
  1199. y == null && (y = x);
  1200. (cx || cy) && this.add(1, 0, 0, 1, cx, cy);
  1201. this.add(x, 0, 0, y, 0, 0);
  1202. (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy);
  1203. return this;
  1204. };
  1205. /*\
  1206. * Matrix.rotate
  1207. [ method ]
  1208. **
  1209. * Rotates the matrix
  1210. - a (number) angle of rotation, in degrees
  1211. - x (number) horizontal origin point from which to rotate
  1212. - y (number) vertical origin point from which to rotate
  1213. \*/
  1214. matrixproto.rotate = function (a, x, y) {
  1215. a = rad(a);
  1216. x = x || 0;
  1217. y = y || 0;
  1218. var cos = +math.cos(a).toFixed(9),
  1219. sin = +math.sin(a).toFixed(9);
  1220. this.add(cos, sin, -sin, cos, x, y);
  1221. return this.add(1, 0, 0, 1, -x, -y);
  1222. };
  1223. /*\
  1224. * Matrix.x
  1225. [ method ]
  1226. **
  1227. * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y
  1228. - x (number)
  1229. - y (number)
  1230. = (number) x
  1231. \*/
  1232. matrixproto.x = function (x, y) {
  1233. return x * this.a + y * this.c + this.e;
  1234. };
  1235. /*\
  1236. * Matrix.y
  1237. [ method ]
  1238. **
  1239. * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x
  1240. - x (number)
  1241. - y (number)
  1242. = (number) y
  1243. \*/
  1244. matrixproto.y = function (x, y) {
  1245. return x * this.b + y * this.d + this.f;
  1246. };
  1247. matrixproto.get = function (i) {
  1248. return +this[Str.fromCharCode(97 + i)].toFixed(4);
  1249. };
  1250. matrixproto.toString = function () {
  1251. return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")";
  1252. };
  1253. matrixproto.offset = function () {
  1254. return [this.e.toFixed(4), this.f.toFixed(4)];
  1255. };
  1256. function norm(a) {
  1257. return a[0] * a[0] + a[1] * a[1];
  1258. }
  1259. function normalize(a) {
  1260. var mag = math.sqrt(norm(a));
  1261. a[0] && (a[0] /= mag);
  1262. a[1] && (a[1] /= mag);
  1263. }
  1264. /*\
  1265. * Matrix.split
  1266. [ method ]
  1267. **
  1268. * Splits matrix into primitive transformations
  1269. = (object) in format:
  1270. o dx (number) translation by x
  1271. o dy (number) translation by y
  1272. o scalex (number) scale by x
  1273. o scaley (number) scale by y
  1274. o shear (number) shear
  1275. o rotate (number) rotation in deg
  1276. o isSimple (boolean) could it be represented via simple transformations
  1277. \*/
  1278. matrixproto.split = function () {
  1279. var out = {};
  1280. // translation
  1281. out.dx = this.e;
  1282. out.dy = this.f;
  1283. // scale and shear
  1284. var row = [[this.a, this.c], [this.b, this.d]];
  1285. out.scalex = math.sqrt(norm(row[0]));
  1286. normalize(row[0]);
  1287. out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
  1288. row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
  1289. out.scaley = math.sqrt(norm(row[1]));
  1290. normalize(row[1]);
  1291. out.shear /= out.scaley;
  1292. // rotation
  1293. var sin = -row[0][1],
  1294. cos = row[1][1];
  1295. if (cos < 0) {
  1296. out.rotate = deg(math.acos(cos));
  1297. if (sin < 0) {
  1298. out.rotate = 360 - out.rotate;
  1299. }
  1300. } else {
  1301. out.rotate = deg(math.asin(sin));
  1302. }
  1303. out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
  1304. out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate;
  1305. out.noRotation = !+out.shear.toFixed(9) && !out.rotate;
  1306. return out;
  1307. };
  1308. /*\
  1309. * Matrix.toTransformString
  1310. [ method ]
  1311. **
  1312. * Returns transform string that represents given matrix
  1313. = (string) transform string
  1314. \*/
  1315. matrixproto.toTransformString = function (shorter) {
  1316. var s = shorter || this.split();
  1317. if (s.isSimple) {
  1318. s.scalex = +s.scalex.toFixed(4);
  1319. s.scaley = +s.scaley.toFixed(4);
  1320. s.rotate = +s.rotate.toFixed(4);
  1321. return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) +
  1322. (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) +
  1323. (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E);
  1324. } else {
  1325. return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)];
  1326. }
  1327. };
  1328. })(Matrix.prototype);
  1329. /*\
  1330. * Snap.Matrix
  1331. [ method ]
  1332. **
  1333. * Utility method
  1334. **
  1335. * Returns a matrix based on the given parameters
  1336. - a (number)
  1337. - b (number)
  1338. - c (number)
  1339. - d (number)
  1340. - e (number)
  1341. - f (number)
  1342. * or
  1343. - svgMatrix (SVGMatrix)
  1344. = (object) @Matrix
  1345. \*/
  1346. Snap.Matrix = Matrix;
  1347. // Colour
  1348. /*\
  1349. * Snap.getRGB
  1350. [ method ]
  1351. **
  1352. * Parses color string as RGB object
  1353. - color (string) color string in one of the following formats:
  1354. # <ul>
  1355. # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li>
  1356. # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li>
  1357. # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li>
  1358. # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200,&nbsp;100,&nbsp;0)</code>)</li>
  1359. # <li>rgba(•••, •••, •••, •••) — also with opacity</li>
  1360. # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%,&nbsp;175%,&nbsp;0%)</code>)</li>
  1361. # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li>
  1362. # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5,&nbsp;0.25,&nbsp;1)</code>)</li>
  1363. # <li>hsba(•••, •••, •••, •••) — also with opacity</li>
  1364. # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
  1365. # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li>
  1366. # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5,&nbsp;0.25,&nbsp;0.5)</code>)</li>
  1367. # <li>hsla(•••, •••, •••, •••) — also with opacity</li>
  1368. # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
  1369. # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li>
  1370. # </ul>
  1371. * Note that `%` can be used any time: `rgb(20%, 255, 50%)`.
  1372. = (object) RGB object in the following format:
  1373. o {
  1374. o r (number) red,
  1375. o g (number) green,
  1376. o b (number) blue,
  1377. o hex (string) color in HTML/CSS format: #••••••,
  1378. o error (boolean) true if string can't be parsed
  1379. o }
  1380. \*/
  1381. Snap.getRGB = cacher(function (colour) {
  1382. if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
  1383. return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
  1384. }
  1385. if (colour == "none") {
  1386. return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString};
  1387. }
  1388. !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
  1389. if (!colour) {
  1390. return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
  1391. }
  1392. var res,
  1393. red,
  1394. green,
  1395. blue,
  1396. opacity,
  1397. t,
  1398. values,
  1399. rgb = colour.match(colourRegExp);
  1400. if (rgb) {
  1401. if (rgb[2]) {
  1402. blue = toInt(rgb[2].substring(5), 16);
  1403. green = toInt(rgb[2].substring(3, 5), 16);
  1404. red = toInt(rgb[2].substring(1, 3), 16);
  1405. }
  1406. if (rgb[3]) {
  1407. blue = toInt((t = rgb[3].charAt(3)) + t, 16);
  1408. green = toInt((t = rgb[3].charAt(2)) + t, 16);
  1409. red = toInt((t = rgb[3].charAt(1)) + t, 16);
  1410. }
  1411. if (rgb[4]) {
  1412. values = rgb[4].split(commaSpaces);
  1413. red = toFloat(values[0]);
  1414. values[0].slice(-1) == "%" && (red *= 2.55);
  1415. green = toFloat(values[1]);
  1416. values[1].slice(-1) == "%" && (green *= 2.55);
  1417. blue = toFloat(values[2]);
  1418. values[2].slice(-1) == "%" && (blue *= 2.55);
  1419. rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3]));
  1420. values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
  1421. }
  1422. if (rgb[5]) {
  1423. values = rgb[5].split(commaSpaces);
  1424. red = toFloat(values[0]);
  1425. values[0].slice(-1) == "%" && (red /= 100);
  1426. green = toFloat(values[1]);
  1427. values[1].slice(-1) == "%" && (green /= 100);
  1428. blue = toFloat(values[2]);
  1429. values[2].slice(-1) == "%" && (blue /= 100);
  1430. (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
  1431. rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3]));
  1432. values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
  1433. return Snap.hsb2rgb(red, green, blue, opacity);
  1434. }
  1435. if (rgb[6]) {
  1436. values = rgb[6].split(commaSpaces);
  1437. red = toFloat(values[0]);
  1438. values[0].slice(-1) == "%" && (red /= 100);
  1439. green = toFloat(values[1]);
  1440. values[1].slice(-1) == "%" && (green /= 100);
  1441. blue = toFloat(values[2]);
  1442. values[2].slice(-1) == "%" && (blue /= 100);
  1443. (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360);
  1444. rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3]));
  1445. values[3] && values[3].slice(-1) == "%" && (opacity /= 100);
  1446. return Snap.hsl2rgb(red, green, blue, opacity);
  1447. }
  1448. red = mmin(math.round(red), 255);
  1449. green = mmin(math.round(green), 255);
  1450. blue = mmin(math.round(blue), 255);
  1451. opacity = mmin(mmax(opacity, 0), 1);
  1452. rgb = {r: red, g: green, b: blue, toString: rgbtoString};
  1453. rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1);
  1454. rgb.opacity = is(opacity, "finite") ? opacity : 1;
  1455. return rgb;
  1456. }
  1457. return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString};
  1458. }, Snap);
  1459. // SIERRA It seems odd that the following 3 conversion methods are not expressed as .this2that(), like the others.
  1460. /*\
  1461. * Snap.hsb
  1462. [ method ]
  1463. **
  1464. * Converts HSB values to a hex representation of the color
  1465. - h (number) hue
  1466. - s (number) saturation
  1467. - b (number) value or brightness
  1468. = (string) hex representation of the color
  1469. \*/
  1470. Snap.hsb = cacher(function (h, s, b) {
  1471. return Snap.hsb2rgb(h, s, b).hex;
  1472. });
  1473. /*\
  1474. * Snap.hsl
  1475. [ method ]
  1476. **
  1477. * Converts HSL values to a hex representation of the color
  1478. - h (number) hue
  1479. - s (number) saturation
  1480. - l (number) luminosity
  1481. = (string) hex representation of the color
  1482. \*/
  1483. Snap.hsl = cacher(function (h, s, l) {
  1484. return Snap.hsl2rgb(h, s, l).hex;
  1485. });
  1486. /*\
  1487. * Snap.rgb
  1488. [ method ]
  1489. **
  1490. * Converts RGB values to a hex representation of the color
  1491. - r (number) red
  1492. - g (number) green
  1493. - b (number) blue
  1494. = (string) hex representation of the color
  1495. \*/
  1496. Snap.rgb = cacher(function (r, g, b, o) {
  1497. if (is(o, "finite")) {
  1498. var round = math.round;
  1499. return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")";
  1500. }
  1501. return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
  1502. });
  1503. var toHex = function (color) {
  1504. var i = glob.doc.getElementsByTagName("head")[0],
  1505. red = "rgb(255, 0, 0)";
  1506. toHex = cacher(function (color) {
  1507. if (color.toLowerCase() == "red") {
  1508. return red;
  1509. }
  1510. i.style.color = red;
  1511. i.style.color = color;
  1512. var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
  1513. return out == red ? null : out;
  1514. });
  1515. return toHex(color);
  1516. },
  1517. hsbtoString = function () {
  1518. return "hsb(" + [this.h, this.s, this.b] + ")";
  1519. },
  1520. hsltoString = function () {
  1521. return "hsl(" + [this.h, this.s, this.l] + ")";
  1522. },
  1523. rgbtoString = function () {
  1524. return this.opacity == 1 || this.opacity == null ?
  1525. this.hex :
  1526. "rgba(" + [this.r, this.g, this.b, this.opacity] + ")";
  1527. },
  1528. prepareRGB = function (r, g, b) {
  1529. if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) {
  1530. b = r.b;
  1531. g = r.g;
  1532. r = r.r;
  1533. }
  1534. if (g == null && is(r, string)) {
  1535. var clr = Snap.getRGB(r);
  1536. r = clr.r;
  1537. g = clr.g;
  1538. b = clr.b;
  1539. }
  1540. if (r > 1 || g > 1 || b > 1) {
  1541. r /= 255;
  1542. g /= 255;
  1543. b /= 255;
  1544. }
  1545. return [r, g, b];
  1546. },
  1547. packageRGB = function (r, g, b, o) {
  1548. r = math.round(r * 255);
  1549. g = math.round(g * 255);
  1550. b = math.round(b * 255);
  1551. var rgb = {
  1552. r: r,
  1553. g: g,
  1554. b: b,
  1555. opacity: is(o, "finite") ? o : 1,
  1556. hex: Snap.rgb(r, g, b),
  1557. toString: rgbtoString
  1558. };
  1559. is(o, "finite") && (rgb.opacity = o);
  1560. return rgb;
  1561. };
  1562. // SIERRA Clarify if Snap does not support consolidated HSLA/RGBA colors. E.g., can you specify a semi-transparent value for Snap.filter.shadow()?
  1563. /*\
  1564. * Snap.color
  1565. [ method ]
  1566. **
  1567. * Parses the color string and returns an object featuring the color's component values
  1568. - clr (string) color string in one of the supported formats (see @Snap.getRGB)
  1569. = (object) Combined RGB/HSB object in the following format:
  1570. o {
  1571. o r (number) red,
  1572. o g (number) green,
  1573. o b (number) blue,
  1574. o hex (string) color in HTML/CSS format: #••••••,
  1575. o error (boolean) `true` if string can't be parsed,
  1576. o h (number) hue,
  1577. o s (number) saturation,
  1578. o v (number) value (brightness),
  1579. o l (number) lightness
  1580. o }
  1581. \*/
  1582. Snap.color = function (clr) {
  1583. var rgb;
  1584. if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) {
  1585. rgb = Snap.hsb2rgb(clr);
  1586. clr.r = rgb.r;
  1587. clr.g = rgb.g;
  1588. clr.b = rgb.b;
  1589. clr.opacity = 1;
  1590. clr.hex = rgb.hex;
  1591. } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) {
  1592. rgb = Snap.hsl2rgb(clr);
  1593. clr.r = rgb.r;
  1594. clr.g = rgb.g;
  1595. clr.b = rgb.b;
  1596. clr.opacity = 1;
  1597. clr.hex = rgb.hex;
  1598. } else {
  1599. if (is(clr, "string")) {
  1600. clr = Snap.getRGB(clr);
  1601. }
  1602. if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) {
  1603. rgb = Snap.rgb2hsl(clr);
  1604. clr.h = rgb.h;
  1605. clr.s = rgb.s;
  1606. clr.l = rgb.l;
  1607. rgb = Snap.rgb2hsb(clr);
  1608. clr.v = rgb.b;
  1609. } else {
  1610. clr = {hex: "none"};
  1611. clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1;
  1612. clr.error = 1;
  1613. }
  1614. }
  1615. clr.toString = rgbtoString;
  1616. return clr;
  1617. };
  1618. /*\
  1619. * Snap.hsb2rgb
  1620. [ method ]
  1621. **
  1622. * Converts HSB values to an RGB object
  1623. - h (number) hue
  1624. - s (number) saturation
  1625. - v (number) value or brightness
  1626. = (object) RGB object in the following format:
  1627. o {
  1628. o r (number) red,
  1629. o g (number) green,
  1630. o b (number) blue,
  1631. o hex (string) color in HTML/CSS format: #••••••
  1632. o }
  1633. \*/
  1634. Snap.hsb2rgb = function (h, s, v, o) {
  1635. if (is(h, "object") && "h" in h && "s" in h && "b" in h) {
  1636. v = h.b;
  1637. s = h.s;
  1638. h = h.h;
  1639. o = h.o;
  1640. }
  1641. h *= 360;
  1642. var R, G, B, X, C;
  1643. h = (h % 360) / 60;
  1644. C = v * s;
  1645. X = C * (1 - abs(h % 2 - 1));
  1646. R = G = B = v - C;
  1647. h = ~~h;
  1648. R += [C, X, 0, 0, X, C][h];
  1649. G += [X, C, C, X, 0, 0][h];
  1650. B += [0, 0, X, C, C, X][h];
  1651. return packageRGB(R, G, B, o);
  1652. };
  1653. /*\
  1654. * Snap.hsl2rgb
  1655. [ method ]
  1656. **
  1657. * Converts HSL values to an RGB object
  1658. - h (number) hue
  1659. - s (number) saturation
  1660. - l (number) luminosity
  1661. = (object) RGB object in the following format:
  1662. o {
  1663. o r (number) red,
  1664. o g (number) green,
  1665. o b (number) blue,
  1666. o hex (string) color in HTML/CSS format: #••••••
  1667. o }
  1668. \*/
  1669. Snap.hsl2rgb = function (h, s, l, o) {
  1670. if (is(h, "object") && "h" in h && "s" in h && "l" in h) {
  1671. l = h.l;
  1672. s = h.s;
  1673. h = h.h;
  1674. }
  1675. if (h > 1 || s > 1 || l > 1) {
  1676. h /= 360;
  1677. s /= 100;
  1678. l /= 100;
  1679. }
  1680. h *= 360;
  1681. var R, G, B, X, C;
  1682. h = (h % 360) / 60;
  1683. C = 2 * s * (l < .5 ? l : 1 - l);
  1684. X = C * (1 - abs(h % 2 - 1));
  1685. R = G = B = l - C / 2;
  1686. h = ~~h;
  1687. R += [C, X, 0, 0, X, C][h];
  1688. G += [X, C, C, X, 0, 0][h];
  1689. B += [0, 0, X, C, C, X][h];
  1690. return packageRGB(R, G, B, o);
  1691. };
  1692. /*\
  1693. * Snap.rgb2hsb
  1694. [ method ]
  1695. **
  1696. * Converts RGB values to an HSB object
  1697. - r (number) red
  1698. - g (number) green
  1699. - b (number) blue
  1700. = (object) HSB object in the following format:
  1701. o {
  1702. o h (number) hue,
  1703. o s (number) saturation,
  1704. o b (number) brightness
  1705. o }
  1706. \*/
  1707. Snap.rgb2hsb = function (r, g, b) {
  1708. b = prepareRGB(r, g, b);
  1709. r = b[0];
  1710. g = b[1];
  1711. b = b[2];
  1712. var H, S, V, C;
  1713. V = mmax(r, g, b);
  1714. C = V - mmin(r, g, b);
  1715. H = (C == 0 ? null :
  1716. V == r ? (g - b) / C :
  1717. V == g ? (b - r) / C + 2 :
  1718. (r - g) / C + 4
  1719. );
  1720. H = ((H + 360) % 6) * 60 / 360;
  1721. S = C == 0 ? 0 : C / V;
  1722. return {h: H, s: S, b: V, toString: hsbtoString};
  1723. };
  1724. /*\
  1725. * Snap.rgb2hsl
  1726. [ method ]
  1727. **
  1728. * Converts RGB values to an HSL object
  1729. - r (number) red
  1730. - g (number) green
  1731. - b (number) blue
  1732. = (object) HSL object in the following format:
  1733. o {
  1734. o h (number) hue,
  1735. o s (number) saturation,
  1736. o l (number) luminosity
  1737. o }
  1738. \*/
  1739. Snap.rgb2hsl = function (r, g, b) {
  1740. b = prepareRGB(r, g, b);
  1741. r = b[0];
  1742. g = b[1];
  1743. b = b[2];
  1744. var H, S, L, M, m, C;
  1745. M = mmax(r, g, b);
  1746. m = mmin(r, g, b);
  1747. C = M - m;
  1748. H = (C == 0 ? null :
  1749. M == r ? (g - b) / C :
  1750. M == g ? (b - r) / C + 2 :
  1751. (r - g) / C + 4);
  1752. H = ((H + 360) % 6) * 60 / 360;
  1753. L = (M + m) / 2;
  1754. S = (C == 0 ? 0 :
  1755. L < .5 ? C / (2 * L) :
  1756. C / (2 - 2 * L));
  1757. return {h: H, s: S, l: L, toString: hsltoString};
  1758. };
  1759. // Transformations
  1760. // SIERRA Snap.parsePathString(): By _array of arrays,_ I assume you mean a format like this for two separate segments? [ ["M10,10","L90,90"], ["M90,10","L10,90"] ] Otherwise how is each command structured?
  1761. /*\
  1762. * Snap.parsePathString
  1763. [ method ]
  1764. **
  1765. * Utility method
  1766. **
  1767. * Parses given path string into an array of arrays of path segments
  1768. - pathString (string|array) path string or array of segments (in the last case it is returned straight away)
  1769. = (array) array of segments
  1770. \*/
  1771. Snap.parsePathString = function (pathString) {
  1772. if (!pathString) {
  1773. return null;
  1774. }
  1775. var pth = Snap.path(pathString);
  1776. if (pth.arr) {
  1777. return Snap.path.clone(pth.arr);
  1778. }
  1779. var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
  1780. data = [];
  1781. if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption
  1782. data = Snap.path.clone(pathString);
  1783. }
  1784. if (!data.length) {
  1785. Str(pathString).replace(pathCommand, function (a, b, c) {
  1786. var params = [],
  1787. name = b.toLowerCase();
  1788. c.replace(pathValues, function (a, b) {
  1789. b && params.push(+b);
  1790. });
  1791. if (name == "m" && params.length > 2) {
  1792. data.push([b].concat(params.splice(0, 2)));
  1793. name = "l";
  1794. b = b == "m" ? "l" : "L";
  1795. }
  1796. if (name == "o" && params.length == 1) {
  1797. data.push([b, params[0]]);
  1798. }
  1799. if (name == "r") {
  1800. data.push([b].concat(params));
  1801. } else while (params.length >= paramCounts[name]) {
  1802. data.push([b].concat(params.splice(0, paramCounts[name])));
  1803. if (!paramCounts[name]) {
  1804. break;
  1805. }
  1806. }
  1807. });
  1808. }
  1809. data.toString = Snap.path.toString;
  1810. pth.arr = Snap.path.clone(data);
  1811. return data;
  1812. };
  1813. /*\
  1814. * Snap.parseTransformString
  1815. [ method ]
  1816. **
  1817. * Utility method
  1818. **
  1819. * Parses given transform string into an array of transformations
  1820. - TString (string|array) transform string or array of transformations (in the last case it is returned straight away)
  1821. = (array) array of transformations
  1822. \*/
  1823. var parseTransformString = Snap.parseTransformString = function (TString) {
  1824. if (!TString) {
  1825. return null;
  1826. }
  1827. var paramCounts = {r: 3, s: 4, t: 2, m: 6},
  1828. data = [];
  1829. if (is(TString, "array") && is(TString[0], "array")) { // rough assumption
  1830. data = Snap.path.clone(TString);
  1831. }
  1832. if (!data.length) {
  1833. Str(TString).replace(tCommand, function (a, b, c) {
  1834. var params = [],
  1835. name = b.toLowerCase();
  1836. c.replace(pathValues, function (a, b) {
  1837. b && params.push(+b);
  1838. });
  1839. data.push([b].concat(params));
  1840. });
  1841. }
  1842. data.toString = Snap.path.toString;
  1843. return data;
  1844. };
  1845. function svgTransform2string(tstr) {
  1846. var res = [];
  1847. tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) {
  1848. params = params.split(/\s*,\s*|\s+/);
  1849. if (name == "rotate" && params.length == 1) {
  1850. params.push(0, 0);
  1851. }
  1852. if (name == "scale") {
  1853. if (params.length == 2) {
  1854. params.push(0, 0);
  1855. }
  1856. if (params.length == 1) {
  1857. params.push(params[0], 0, 0);
  1858. }
  1859. }
  1860. if (name == "skewX") {
  1861. res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]);
  1862. } else if (name == "skewY") {
  1863. res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]);
  1864. } else {
  1865. res.push([name.charAt(0)].concat(params));
  1866. }
  1867. return all;
  1868. });
  1869. return res;
  1870. }
  1871. Snap._.svgTransform2string = svgTransform2string;
  1872. Snap._.rgTransform = new RegExp("^[a-z][" + spaces + "]*-?\\.?\\d", "i");
  1873. function transform2matrix(tstr, bbox) {
  1874. var tdata = parseTransformString(tstr),
  1875. m = new Matrix;
  1876. if (tdata) {
  1877. for (var i = 0, ii = tdata.length; i < ii; i++) {
  1878. var t = tdata[i],
  1879. tlen = t.length,
  1880. command = Str(t[0]).toLowerCase(),
  1881. absolute = t[0] != command,
  1882. inver = absolute ? m.invert() : 0,
  1883. x1,
  1884. y1,
  1885. x2,
  1886. y2,
  1887. bb;
  1888. if (command == "t" && tlen == 2){
  1889. m.translate(t[1], 0);
  1890. } else if (command == "t" && tlen == 3) {
  1891. if (absolute) {
  1892. x1 = inver.x(0, 0);
  1893. y1 = inver.y(0, 0);
  1894. x2 = inver.x(t[1], t[2]);
  1895. y2 = inver.y(t[1], t[2]);
  1896. m.translate(x2 - x1, y2 - y1);
  1897. } else {
  1898. m.translate(t[1], t[2]);
  1899. }
  1900. } else if (command == "r") {
  1901. if (tlen == 2) {
  1902. bb = bb || bbox;
  1903. m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2);
  1904. } else if (tlen == 4) {
  1905. if (absolute) {
  1906. x2 = inver.x(t[2], t[3]);
  1907. y2 = inver.y(t[2], t[3]);
  1908. m.rotate(t[1], x2, y2);
  1909. } else {
  1910. m.rotate(t[1], t[2], t[3]);
  1911. }
  1912. }
  1913. } else if (command == "s") {
  1914. if (tlen == 2 || tlen == 3) {
  1915. bb = bb || bbox;
  1916. m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2);
  1917. } else if (tlen == 4) {
  1918. if (absolute) {
  1919. x2 = inver.x(t[2], t[3]);
  1920. y2 = inver.y(t[2], t[3]);
  1921. m.scale(t[1], t[1], x2, y2);
  1922. } else {
  1923. m.scale(t[1], t[1], t[2], t[3]);
  1924. }
  1925. } else if (tlen == 5) {
  1926. if (absolute) {
  1927. x2 = inver.x(t[3], t[4]);
  1928. y2 = inver.y(t[3], t[4]);
  1929. m.scale(t[1], t[2], x2, y2);
  1930. } else {
  1931. m.scale(t[1], t[2], t[3], t[4]);
  1932. }
  1933. }
  1934. } else if (command == "m" && tlen == 7) {
  1935. m.add(t[1], t[2], t[3], t[4], t[5], t[6]);
  1936. }
  1937. }
  1938. }
  1939. return m;
  1940. }
  1941. Snap._.transform2matrix = transform2matrix;
  1942. function extractTransform(el, tstr) {
  1943. if (tstr == null) {
  1944. var doReturn = true;
  1945. if (el.type == "linearGradient" || el.type == "radialGradient") {
  1946. tstr = el.node.getAttribute("gradientTransform");
  1947. } else if (el.type == "pattern") {
  1948. tstr = el.node.getAttribute("patternTransform");
  1949. } else {
  1950. tstr = el.node.getAttribute("transform");
  1951. }
  1952. if (!tstr) {
  1953. return new Matrix;
  1954. }
  1955. tstr = svgTransform2string(tstr);
  1956. } else {
  1957. if (!Snap._.rgTransform.test(tstr)) {
  1958. tstr = svgTransform2string(tstr);
  1959. } else {
  1960. tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E);
  1961. }
  1962. if (is(tstr, "array")) {
  1963. tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr);
  1964. }
  1965. el._.transform = tstr;
  1966. }
  1967. var m = transform2matrix(tstr, el.getBBox(1));
  1968. if (doReturn) {
  1969. return m;
  1970. } else {
  1971. el.matrix = m;
  1972. }
  1973. }
  1974. Snap._unit2px = unit2px;
  1975. var contains = glob.doc.contains || glob.doc.compareDocumentPosition ?
  1976. function (a, b) {
  1977. var adown = a.nodeType == 9 ? a.documentElement : a,
  1978. bup = b && b.parentNode;
  1979. return a == bup || !!(bup && bup.nodeType == 1 && (
  1980. adown.contains ?
  1981. adown.contains(bup) :
  1982. a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
  1983. ));
  1984. } :
  1985. function (a, b) {
  1986. if (b) {
  1987. while (b) {
  1988. b = b.parentNode;
  1989. if (b == a) {
  1990. return true;
  1991. }
  1992. }
  1993. }
  1994. return false;
  1995. };
  1996. function getSomeDefs(el) {
  1997. var cache = Snap._.someDefs;
  1998. if (cache && contains(cache.ownerDocument.documentElement, cache)) {
  1999. return cache;
  2000. }
  2001. var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) ||
  2002. (el.node.parentNode && wrap(el.node.parentNode)) ||
  2003. Snap.select("svg") ||
  2004. Snap(0, 0),
  2005. pdefs = p.select("defs"),
  2006. defs = pdefs == null ? false : pdefs.node;
  2007. if (!defs) {
  2008. defs = make("defs", p.node).node;
  2009. }
  2010. Snap._.someDefs = defs;
  2011. return defs;
  2012. }
  2013. Snap._.getSomeDefs = getSomeDefs;
  2014. function unit2px(el, name, value) {
  2015. var defs = getSomeDefs(el),
  2016. out = {},
  2017. mgr = defs.querySelector(".svg---mgr");
  2018. if (!mgr) {
  2019. mgr = $("rect");
  2020. $(mgr, {width: 10, height: 10, "class": "svg---mgr"});
  2021. defs.appendChild(mgr);
  2022. }
  2023. function getW(val) {
  2024. if (val == null) {
  2025. return E;
  2026. }
  2027. if (val == +val) {
  2028. return val;
  2029. }
  2030. $(mgr, {width: val});
  2031. return mgr.getBBox().width;
  2032. }
  2033. function getH(val) {
  2034. if (val == null) {
  2035. return E;
  2036. }
  2037. if (val == +val) {
  2038. return val;
  2039. }
  2040. $(mgr, {height: val});
  2041. return mgr.getBBox().height;
  2042. }
  2043. function set(nam, f) {
  2044. if (name == null) {
  2045. out[nam] = f(el.attr(nam));
  2046. } else if (nam == name) {
  2047. out = f(value == null ? el.attr(nam) : value);
  2048. }
  2049. }
  2050. switch (el.type) {
  2051. case "rect":
  2052. set("rx", getW);
  2053. set("ry", getH);
  2054. case "image":
  2055. set("width", getW);
  2056. set("height", getH);
  2057. case "text":
  2058. set("x", getW);
  2059. set("y", getH);
  2060. break;
  2061. case "circle":
  2062. set("cx", getW);
  2063. set("cy", getH);
  2064. set("r", getW);
  2065. break;
  2066. case "ellipse":
  2067. set("cx", getW);
  2068. set("cy", getH);
  2069. set("rx", getW);
  2070. set("ry", getH);
  2071. break;
  2072. case "line":
  2073. set("x1", getW);
  2074. set("x2", getW);
  2075. set("y1", getH);
  2076. set("y2", getH);
  2077. break;
  2078. case "marker":
  2079. set("refX", getW);
  2080. set("markerWidth", getW);
  2081. set("refY", getH);
  2082. set("markerHeight", getH);
  2083. break;
  2084. case "radialGradient":
  2085. set("fx", getW);
  2086. set("fy", getH);
  2087. break;
  2088. case "tspan":
  2089. set("dx", getW);
  2090. set("dy", getH);
  2091. break;
  2092. default:
  2093. set(name, getW);
  2094. }
  2095. return out;
  2096. }
  2097. /*\
  2098. * Snap.select
  2099. [ method ]
  2100. **
  2101. * Wraps a DOM element specified by CSS selector as @Element
  2102. - query (string) CSS selector of the element
  2103. = (Element) the current element
  2104. \*/
  2105. Snap.select = function (query) {
  2106. return wrap(glob.doc.querySelector(query));
  2107. };
  2108. /*\
  2109. * Snap.selectAll
  2110. [ method ]
  2111. **
  2112. * Wraps DOM elements specified by CSS selector as set or array of @Element
  2113. - query (string) CSS selector of the element
  2114. = (Element) the current element
  2115. \*/
  2116. Snap.selectAll = function (query) {
  2117. var nodelist = glob.doc.querySelectorAll(query),
  2118. set = (Snap.set || Array)();
  2119. for (var i = 0; i < nodelist.length; i++) {
  2120. set.push(wrap(nodelist[i]));
  2121. }
  2122. return set;
  2123. };
  2124. function add2group(list) {
  2125. if (!is(list, "array")) {
  2126. list = Array.prototype.slice.call(arguments, 0);
  2127. }
  2128. var i = 0,
  2129. j = 0,
  2130. node = this.node;
  2131. while (this[i]) delete this[i++];
  2132. for (i = 0; i < list.length; i++) {
  2133. if (list[i].type == "set") {
  2134. list[i].forEach(function (el) {
  2135. node.appendChild(el.node);
  2136. });
  2137. } else {
  2138. node.appendChild(list[i].node);
  2139. }
  2140. }
  2141. var children = node.childNodes;
  2142. for (i = 0; i < children.length; i++) {
  2143. this[j++] = wrap(children[i]);
  2144. }
  2145. return this;
  2146. }
  2147. function Element(el) {
  2148. if (el.snap in hub) {
  2149. return hub[el.snap];
  2150. }
  2151. var id = this.id = ID(),
  2152. svg;
  2153. try {
  2154. svg = el.ownerSVGElement;
  2155. } catch(e) {}
  2156. this.node = el;
  2157. if (svg) {
  2158. this.paper = new Paper(svg);
  2159. }
  2160. this.type = el.tagName;
  2161. this.anims = {};
  2162. this._ = {
  2163. transform: []
  2164. };
  2165. el.snap = id;
  2166. hub[id] = this;
  2167. if (this.type == "g") {
  2168. this.add = add2group;
  2169. for (var method in Paper.prototype) if (Paper.prototype[has](method)) {
  2170. this[method] = Paper.prototype[method];
  2171. }
  2172. }
  2173. }
  2174. function arrayFirstValue(arr) {
  2175. var res;
  2176. for (var i = 0, ii = arr.length; i < ii; i++) {
  2177. res = res || arr[i];
  2178. if (res) {
  2179. return res;
  2180. }
  2181. }
  2182. }
  2183. (function (elproto) {
  2184. /*\
  2185. * Element.attr
  2186. [ method ]
  2187. **
  2188. * Gets or sets given attributes of the element
  2189. **
  2190. - params (object) contains key-value pairs of attributes you want to set
  2191. * or
  2192. - param (string) name of the attribute
  2193. = (Element) the current element
  2194. * or
  2195. = (string) value of attribute
  2196. > Usage
  2197. | el.attr({
  2198. | fill: "#fc0",
  2199. | stroke: "#000",
  2200. | strokeWidth: 2, // CamelCase...
  2201. | "fill-opacity": 0.5 // or dash-separated names
  2202. | });
  2203. | console.log(el.attr("fill")); // #fc0
  2204. \*/
  2205. elproto.attr = function (params, value) {
  2206. var el = this,
  2207. node = el.node;
  2208. if (!params) {
  2209. return el;
  2210. }
  2211. if (is(params, "string")) {
  2212. if (arguments.length > 1) {
  2213. var json = {};
  2214. json[params] = value;
  2215. params = json;
  2216. } else {
  2217. return arrayFirstValue(eve("snap.util.getattr."+params, el));
  2218. }
  2219. }
  2220. for (var att in params) {
  2221. if (params[has](att)) {
  2222. eve("snap.util.attr." + att, el, params[att]);
  2223. }
  2224. }
  2225. return el;
  2226. };
  2227. // SIERRA Element.getBBox(): Unclear why you would want to express the dimension of the box as a path.
  2228. // SIERRA Element.getBBox(): Unclear why you would want to use r0/r1/r2. Also, basic definitions: wouldn't the _smallest circle that can be enclosed_ be a zero-radius point?
  2229. /*\
  2230. * Element.getBBox
  2231. [ method ]
  2232. **
  2233. * Returns the bounding box descriptor for the given element
  2234. **
  2235. = (object) bounding box descriptor:
  2236. o {
  2237. o cx: (number) x of the center,
  2238. o cy: (number) x of the center,
  2239. o h: (number) height,
  2240. o height: (number) height,
  2241. o path: (string) path command for the box,
  2242. o r0: (number) radius of a circle that fully encloses the box,
  2243. o r1: (number) radius of the smallest circle that can be enclosed,
  2244. o r2: (number) radius of the largest circle that can be enclosed,
  2245. o vb: (string) box as a viewbox command,
  2246. o w: (number) width,
  2247. o width: (number) width,
  2248. o x2: (number) x of the right side,
  2249. o x: (number) x of the left side,
  2250. o y2: (number) y of the bottom edge,
  2251. o y: (number) y of the top edge
  2252. o }
  2253. \*/
  2254. elproto.getBBox = function (isWithoutTransform) {
  2255. var el = this;
  2256. if (el.type == "use") {
  2257. el = el.original;
  2258. }
  2259. if (el.removed) {
  2260. return {};
  2261. }
  2262. var _ = el._;
  2263. if (isWithoutTransform) {
  2264. _.bboxwt = Snap.path.get[el.type] ? Snap.path.getBBox(el.realPath = Snap.path.get[el.type](el)) : Snap._.box(el.node.getBBox());
  2265. return Snap._.box(_.bboxwt);
  2266. } else {
  2267. el.realPath = (Snap.path.get[el.type] || Snap.path.get.deflt)(el);
  2268. _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, el.matrix));
  2269. }
  2270. return Snap._.box(_.bbox);
  2271. };
  2272. var propString = function () {
  2273. return this.string;
  2274. };
  2275. // SIERRA Element.transform(): seems to allow two return values, one of which (_Element_) is undefined.
  2276. // SIERRA Element.transform(): if this only accepts one argument, it's unclear how it can both _get_ and _set_ a transform.
  2277. // SIERRA Element.transform(): Unclear how Snap transform string format differs from SVG's.
  2278. /*\
  2279. * Element.transform
  2280. [ method ]
  2281. **
  2282. * Gets or sets transformation of the element
  2283. **
  2284. - tstr (string) transform string in Snap or SVG format
  2285. = (Element) the current element
  2286. * or
  2287. = (object) transformation descriptor:
  2288. o {
  2289. o string (string) transform string,
  2290. o globalMatrix (Matrix) matrix of all transformations applied to element or its parents,
  2291. o localMatrix (Matrix) matrix of transformations applied only to the element,
  2292. o diffMatrix (Matrix) matrix of difference between global and local transformations,
  2293. o global (string) global transformation as string,
  2294. o local (string) local transformation as string,
  2295. o toString (function) returns `string` property
  2296. o }
  2297. \*/
  2298. elproto.transform = function (tstr) {
  2299. var _ = this._;
  2300. if (tstr == null) {
  2301. var global = new Matrix(this.node.getCTM()),
  2302. local = extractTransform(this),
  2303. localString = local.toTransformString(),
  2304. string = Str(local) == Str(this.matrix) ?
  2305. _.transform : localString;
  2306. return {
  2307. string: string,
  2308. globalMatrix: global,
  2309. localMatrix: local,
  2310. diffMatrix: global.clone().add(local.invert()),
  2311. global: global.toTransformString(),
  2312. local: localString,
  2313. toString: propString
  2314. };
  2315. }
  2316. if (tstr instanceof Matrix) {
  2317. // may be need to apply it directly
  2318. // TODO: investigate
  2319. tstr = tstr.toTransformString();
  2320. }
  2321. extractTransform(this, tstr);
  2322. if (this.node) {
  2323. if (this.type == "linearGradient" || this.type == "radialGradient") {
  2324. $(this.node, {gradientTransform: this.matrix});
  2325. } else if (this.type == "pattern") {
  2326. $(this.node, {patternTransform: this.matrix});
  2327. } else {
  2328. $(this.node, {transform: this.matrix});
  2329. }
  2330. }
  2331. return this;
  2332. };
  2333. /*\
  2334. * Element.parent
  2335. [ method ]
  2336. **
  2337. * Returns the element's parent
  2338. **
  2339. = (Element) the parent element
  2340. \*/
  2341. elproto.parent = function () {
  2342. return wrap(this.node.parentNode);
  2343. };
  2344. /*\
  2345. * Element.append
  2346. [ method ]
  2347. **
  2348. * Appends the given element to current one
  2349. **
  2350. - el (Element|Set) element to append
  2351. = (Element) the parent element
  2352. \*/
  2353. /*\
  2354. * Element.add
  2355. [ method ]
  2356. **
  2357. * See @Element.append
  2358. \*/
  2359. elproto.append = elproto.add = function (el) {
  2360. if (el) {
  2361. if (el.type == "set") {
  2362. var it = this;
  2363. el.forEach(function (el) {
  2364. it.add(el);
  2365. });
  2366. return this;
  2367. }
  2368. el = wrap(el);
  2369. this.node.appendChild(el.node);
  2370. el.paper = this.paper;
  2371. }
  2372. return this;
  2373. };
  2374. /*\
  2375. * Element.appendTo
  2376. [ method ]
  2377. **
  2378. * Appends the current element to the given one
  2379. **
  2380. - el (Element) parent element to append to
  2381. = (Element) the child element
  2382. \*/
  2383. elproto.appendTo = function (el) {
  2384. if (el) {
  2385. el = wrap(el);
  2386. el.append(this);
  2387. }
  2388. return this;
  2389. };
  2390. /*\
  2391. * Element.prepend
  2392. [ method ]
  2393. **
  2394. * Prepends the given element to the current one
  2395. **
  2396. - el (Element) element to prepend
  2397. = (Element) the parent element
  2398. \*/
  2399. elproto.prepend = function (el) {
  2400. if (el) {
  2401. el = wrap(el);
  2402. var parent = el.parent();
  2403. this.node.insertBefore(el.node, this.node.firstChild);
  2404. this.add && this.add();
  2405. el.paper = this.paper;
  2406. this.parent() && this.parent().add();
  2407. parent && parent.add();
  2408. }
  2409. return this;
  2410. };
  2411. /*\
  2412. * Element.prependTo
  2413. [ method ]
  2414. **
  2415. * Prepends the current element to the given one
  2416. **
  2417. - el (Element) parent element to prepend to
  2418. = (Element) the child element
  2419. \*/
  2420. elproto.prependTo = function (el) {
  2421. el = wrap(el);
  2422. el.prepend(this);
  2423. return this;
  2424. };
  2425. /*\
  2426. * Element.before
  2427. [ method ]
  2428. **
  2429. * Inserts given element before the current one
  2430. **
  2431. - el (Element) element to insert
  2432. = (Element) the parent element
  2433. \*/
  2434. elproto.before = function (el) {
  2435. if (el.type == "set") {
  2436. var it = this;
  2437. el.forEach(function (el) {
  2438. var parent = el.parent();
  2439. it.node.parentNode.insertBefore(el.node, it.node);
  2440. parent && parent.add();
  2441. });
  2442. this.parent().add();
  2443. return this;
  2444. }
  2445. el = wrap(el);
  2446. var parent = el.parent();
  2447. this.node.parentNode.insertBefore(el.node, this.node);
  2448. this.parent() && this.parent().add();
  2449. parent && parent.add();
  2450. el.paper = this.paper;
  2451. return this;
  2452. };
  2453. /*\
  2454. * Element.after
  2455. [ method ]
  2456. **
  2457. * Inserts given element after the current one
  2458. **
  2459. - el (Element) element to insert
  2460. = (Element) the parent element
  2461. \*/
  2462. elproto.after = function (el) {
  2463. el = wrap(el);
  2464. var parent = el.parent();
  2465. if (this.node.nextSibling) {
  2466. this.node.parentNode.insertBefore(el.node, this.node.nextSibling);
  2467. } else {
  2468. this.node.parentNode.appendChild(el.node);
  2469. }
  2470. this.parent() && this.parent().add();
  2471. parent && parent.add();
  2472. el.paper = this.paper;
  2473. return this;
  2474. };
  2475. /*\
  2476. * Element.insertBefore
  2477. [ method ]
  2478. **
  2479. * Inserts the element after the given one
  2480. **
  2481. - el (Element) element next to whom insert to
  2482. = (Element) the parent element
  2483. \*/
  2484. elproto.insertBefore = function (el) {
  2485. el = wrap(el);
  2486. var parent = this.parent();
  2487. el.node.parentNode.insertBefore(this.node, el.node);
  2488. this.paper = el.paper;
  2489. parent && parent.add();
  2490. el.parent() && el.parent().add();
  2491. return this;
  2492. };
  2493. /*\
  2494. * Element.insertAfter
  2495. [ method ]
  2496. **
  2497. * Inserts the element after the given one
  2498. **
  2499. - el (Element) element next to whom insert to
  2500. = (Element) the parent element
  2501. \*/
  2502. elproto.insertAfter = function (el) {
  2503. el = wrap(el);
  2504. var parent = this.parent();
  2505. el.node.parentNode.insertBefore(this.node, el.node.nextSibling);
  2506. this.paper = el.paper;
  2507. parent && parent.add();
  2508. el.parent() && el.parent().add();
  2509. return this;
  2510. };
  2511. /*\
  2512. * Element.remove
  2513. [ method ]
  2514. **
  2515. * Removes element from the DOM
  2516. = (Element) the detached element
  2517. \*/
  2518. elproto.remove = function () {
  2519. var parent = this.parent();
  2520. this.node.parentNode && this.node.parentNode.removeChild(this.node);
  2521. delete this.paper;
  2522. this.removed = true;
  2523. parent && parent.add();
  2524. return this;
  2525. };
  2526. /*\
  2527. * Element.select
  2528. [ method ]
  2529. **
  2530. * Gathers the nested @Element matching the given set of CSS selectors
  2531. **
  2532. - query (string) CSS selector
  2533. = (Element) result of query selection
  2534. \*/
  2535. elproto.select = function (query) {
  2536. return wrap(this.node.querySelector(query));
  2537. };
  2538. /*\
  2539. * Element.selectAll
  2540. [ method ]
  2541. **
  2542. * Gathers nested @Element objects matching the given set of CSS selectors
  2543. **
  2544. - query (string) CSS selector
  2545. = (Set|array) result of query selection
  2546. \*/
  2547. elproto.selectAll = function (query) {
  2548. var nodelist = this.node.querySelectorAll(query),
  2549. set = (Snap.set || Array)();
  2550. for (var i = 0; i < nodelist.length; i++) {
  2551. set.push(wrap(nodelist[i]));
  2552. }
  2553. return set;
  2554. };
  2555. /*\
  2556. * Element.asPX
  2557. [ method ]
  2558. **
  2559. * Returns given attribute of the element as a `px` value (not %, em, etc.)
  2560. **
  2561. - attr (string) attribute name
  2562. - value (string) #optional attribute value
  2563. = (Element) result of query selection
  2564. \*/
  2565. elproto.asPX = function (attr, value) {
  2566. if (value == null) {
  2567. value = this.attr(attr);
  2568. }
  2569. return +unit2px(this, attr, value);
  2570. };
  2571. // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar.
  2572. /*\
  2573. * Element.use
  2574. [ method ]
  2575. **
  2576. * Creates a `<use>` element linked to the current element
  2577. **
  2578. = (Element) the `<use>` element
  2579. \*/
  2580. elproto.use = function () {
  2581. var use,
  2582. id = this.node.id;
  2583. if (!id) {
  2584. id = this.id;
  2585. $(this.node, {
  2586. id: id
  2587. });
  2588. }
  2589. if (this.type == "linearGradient" || this.type == "radialGradient" ||
  2590. this.type == "pattern") {
  2591. use = make(this.type, this.node.parentNode);
  2592. } else {
  2593. use = make("use", this.node.parentNode);
  2594. }
  2595. $(use.node, {
  2596. "xlink:href": "#" + id
  2597. });
  2598. use.original = this;
  2599. return use;
  2600. };
  2601. /*\
  2602. * Element.clone
  2603. [ method ]
  2604. **
  2605. * Creates a clone of the element and inserts it after the element
  2606. **
  2607. = (Element) the clone
  2608. \*/
  2609. function fixids(el) {
  2610. var els = el.selectAll("*"),
  2611. it,
  2612. url = /^\s*url\(("|'|)(.*)\1\)\s*$/,
  2613. ids = [],
  2614. uses = {};
  2615. function urltest(it, name) {
  2616. var val = $(it.node, name);
  2617. val = val && val.match(url);
  2618. val = val && val[2];
  2619. if (val && val.charAt() == "#") {
  2620. val = val.substring(1);
  2621. } else {
  2622. return;
  2623. }
  2624. if (val) {
  2625. uses[val] = (uses[val] || []).concat(function (id) {
  2626. var attr = {};
  2627. attr[name] = URL(id);
  2628. $(it.node, attr);
  2629. });
  2630. }
  2631. }
  2632. function linktest(it) {
  2633. var val = $(it.node, "xlink:href");
  2634. if (val && val.charAt() == "#") {
  2635. val = val.substring(1);
  2636. } else {
  2637. return;
  2638. }
  2639. if (val) {
  2640. uses[val] = (uses[val] || []).concat(function (id) {
  2641. it.attr("xlink:href", "#" + id);
  2642. });
  2643. }
  2644. }
  2645. for (var i = 0, ii = els.length; i < ii; i++) {
  2646. it = els[i];
  2647. urltest(it, "fill");
  2648. urltest(it, "stroke");
  2649. urltest(it, "filter");
  2650. urltest(it, "mask");
  2651. urltest(it, "clip-path");
  2652. linktest(it);
  2653. var oldid = $(it.node, "id");
  2654. if (oldid) {
  2655. $(it.node, {id: it.id});
  2656. ids.push({
  2657. old: oldid,
  2658. id: it.id
  2659. });
  2660. }
  2661. }
  2662. for (i = 0, ii = ids.length; i < ii; i++) {
  2663. var fs = uses[ids[i].old];
  2664. if (fs) {
  2665. for (var j = 0, jj = fs.length; j < jj; j++) {
  2666. fs[j](ids[i].id);
  2667. }
  2668. }
  2669. }
  2670. }
  2671. elproto.clone = function () {
  2672. var clone = wrap(this.node.cloneNode(true));
  2673. if ($(clone.node, "id")) {
  2674. $(clone.node, {id: clone.id});
  2675. }
  2676. fixids(clone);
  2677. clone.insertAfter(this);
  2678. return clone;
  2679. };
  2680. // SIERRA Element.toDefs(): If this _moves_ an element to the <defs> region, why is the return value a _clone_? Also unclear why it's called the _relative_ <defs> section. Perhaps _shared_?
  2681. /*\
  2682. * Element.toDefs
  2683. [ method ]
  2684. **
  2685. * Moves element to the shared `<defs>` area
  2686. **
  2687. = (Element) the clone
  2688. \*/
  2689. elproto.toDefs = function () {
  2690. var defs = getSomeDefs(this);
  2691. defs.appendChild(this.node);
  2692. return this;
  2693. };
  2694. // SIERRA Element.pattern(): x/y/width/height data types are listed as both String and Number. Is that an error, or does it mean strings are coerced?
  2695. // SIERRA Element.pattern(): clarify that x/y are offsets that e.g., may add gutters between the tiles.
  2696. /*\
  2697. * Element.pattern
  2698. [ method ]
  2699. **
  2700. * Creates a `<pattern>` element from the current element
  2701. **
  2702. * To create a pattern you have to specify the pattern rect:
  2703. - x (string|number)
  2704. - y (string|number)
  2705. - width (string|number)
  2706. - height (string|number)
  2707. = (Element) the `<pattern>` element
  2708. * You can use pattern later on as an argument for `fill` attribute:
  2709. | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({
  2710. | fill: "none",
  2711. | stroke: "#bada55",
  2712. | strokeWidth: 5
  2713. | }).pattern(0, 0, 10, 10),
  2714. | c = paper.circle(200, 200, 100);
  2715. | c.attr({
  2716. | fill: p
  2717. | });
  2718. \*/
  2719. elproto.pattern = function (x, y, width, height) {
  2720. var p = make("pattern", getSomeDefs(this));
  2721. if (x == null) {
  2722. x = this.getBBox();
  2723. }
  2724. if (is(x, "object") && "x" in x) {
  2725. y = x.y;
  2726. width = x.width;
  2727. height = x.height;
  2728. x = x.x;
  2729. }
  2730. $(p.node, {
  2731. x: x,
  2732. y: y,
  2733. width: width,
  2734. height: height,
  2735. patternUnits: "userSpaceOnUse",
  2736. id: p.id,
  2737. viewBox: [x, y, width, height].join(" ")
  2738. });
  2739. p.node.appendChild(this.node);
  2740. return p;
  2741. };
  2742. // SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path.
  2743. // SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values?
  2744. /*\
  2745. * Element.marker
  2746. [ method ]
  2747. **
  2748. * Creates a `<marker>` element from the current element
  2749. **
  2750. * To create a marker you have to specify the bounding rect and reference point:
  2751. - x (number)
  2752. - y (number)
  2753. - width (number)
  2754. - height (number)
  2755. - refX (number)
  2756. - refY (number)
  2757. = (Element) the `<marker>` element
  2758. * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end.
  2759. \*/
  2760. // TODO add usage for markers
  2761. elproto.marker = function (x, y, width, height, refX, refY) {
  2762. var p = make("marker", getSomeDefs(this));
  2763. if (x == null) {
  2764. x = this.getBBox();
  2765. }
  2766. if (is(x, "object") && "x" in x) {
  2767. y = x.y;
  2768. width = x.width;
  2769. height = x.height;
  2770. refX = x.refX || x.cx;
  2771. refY = x.refY || x.cy;
  2772. x = x.x;
  2773. }
  2774. $(p.node, {
  2775. viewBox: [x, y, width, height].join(S),
  2776. markerWidth: width,
  2777. markerHeight: height,
  2778. orient: "auto",
  2779. refX: refX || 0,
  2780. refY: refY || 0,
  2781. id: p.id
  2782. });
  2783. p.node.appendChild(this.node);
  2784. return p;
  2785. };
  2786. // animation
  2787. function slice(from, to, f) {
  2788. return function (arr) {
  2789. var res = arr.slice(from, to);
  2790. if (res.length == 1) {
  2791. res = res[0];
  2792. }
  2793. return f ? f(res) : res;
  2794. };
  2795. }
  2796. var Animation = function (attr, ms, easing, callback) {
  2797. if (typeof easing == "function" && !easing.length) {
  2798. callback = easing;
  2799. easing = mina.linear;
  2800. }
  2801. this.attr = attr;
  2802. this.dur = ms;
  2803. easing && (this.easing = easing);
  2804. callback && (this.callback = callback);
  2805. };
  2806. // SIERRA All object methods should feature sample code. This is just one instance.
  2807. /*\
  2808. * Snap.animation
  2809. [ method ]
  2810. **
  2811. * Creates an animation object
  2812. **
  2813. - attr (object) attributes of final destination
  2814. - duration (number) duration of the animation, in milliseconds
  2815. - easing (function) #optional one of easing functions of @mina or custom one
  2816. - callback (function) #optional callback function that fires when animation ends
  2817. = (object) animation object
  2818. \*/
  2819. Snap.animation = function (attr, ms, easing, callback) {
  2820. return new Animation(attr, ms, easing, callback);
  2821. };
  2822. /*\
  2823. * Element.inAnim
  2824. [ method ]
  2825. **
  2826. * Returns a set of animations that may be able to manipulate the current element
  2827. **
  2828. = (object) in format:
  2829. o {
  2830. o anim (object) animation object,
  2831. o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished,
  2832. o status (function) gets or sets the status of the animation,
  2833. o stop (function) stops the animation
  2834. o }
  2835. \*/
  2836. elproto.inAnim = function () {
  2837. var el = this,
  2838. res = [];
  2839. for (var id in el.anims) if (el.anims[has](id)) {
  2840. (function (a) {
  2841. res.push({
  2842. anim: new Animation(a._attrs, a.dur, a.easing, a._callback),
  2843. curStatus: a.status(),
  2844. status: function (val) {
  2845. return a.status(val);
  2846. },
  2847. stop: function () {
  2848. a.stop();
  2849. }
  2850. });
  2851. }(el.anims[id]));
  2852. }
  2853. return res;
  2854. };
  2855. /*\
  2856. * Snap.animate
  2857. [ method ]
  2858. **
  2859. * Runs generic animation of one number into another with a caring function
  2860. **
  2861. - from (number|array) number or array of numbers
  2862. - to (number|array) number or array of numbers
  2863. - setter (function) caring function that accepts one number argument
  2864. - duration (number) duration, in milliseconds
  2865. - easing (function) #optional easing function from @mina or custom
  2866. - callback (function) #optional callback function to execute when animation ends
  2867. = (object) animation object in @mina format
  2868. o {
  2869. o id (string) animation id, consider it read-only,
  2870. o duration (function) gets or sets the duration of the animation,
  2871. o easing (function) easing,
  2872. o speed (function) gets or sets the speed of the animation,
  2873. o status (function) gets or sets the status of the animation,
  2874. o stop (function) stops the animation
  2875. o }
  2876. | var rect = Snap().rect(0, 0, 10, 10);
  2877. | Snap.animate(0, 10, function (val) {
  2878. | rect.attr({
  2879. | x: val
  2880. | });
  2881. | }, 1000);
  2882. | // in given context is equivalent to
  2883. | rect.animate({x: 10}, 1000);
  2884. \*/
  2885. Snap.animate = function (from, to, setter, ms, easing, callback) {
  2886. if (typeof easing == "function" && !easing.length) {
  2887. callback = easing;
  2888. easing = mina.linear;
  2889. }
  2890. var now = mina.time(),
  2891. anim = mina(from, to, now, now + ms, mina.time, setter, easing);
  2892. callback && eve.once("mina.finish." + anim.id, callback);
  2893. return anim;
  2894. };
  2895. /*\
  2896. * Element.stop
  2897. [ method ]
  2898. **
  2899. * Stops all the animations for the current element
  2900. **
  2901. = (Element) the current element
  2902. \*/
  2903. elproto.stop = function () {
  2904. var anims = this.inAnim();
  2905. for (var i = 0, ii = anims.length; i < ii; i++) {
  2906. anims[i].stop();
  2907. }
  2908. return this;
  2909. };
  2910. // SIERRA Element.animate(): For _attrs_, clarify if they represent the destination values, and if the animation executes relative to the element's current attribute values.
  2911. // SIERRA would a _custom_ animation function be an SVG keySplines value?
  2912. /*\
  2913. * Element.animate
  2914. [ method ]
  2915. **
  2916. * Animates the given attributes of the element
  2917. **
  2918. - attrs (object) key-value pairs of destination attributes
  2919. - duration (number) duration of the animation in milliseconds
  2920. - easing (function) #optional easing function from @mina or custom
  2921. - callback (function) #optional callback function that executes when the animation ends
  2922. = (Element) the current element
  2923. \*/
  2924. elproto.animate = function (attrs, ms, easing, callback) {
  2925. if (typeof easing == "function" && !easing.length) {
  2926. callback = easing;
  2927. easing = mina.linear;
  2928. }
  2929. if (attrs instanceof Animation) {
  2930. callback = attrs.callback;
  2931. easing = attrs.easing;
  2932. ms = easing.dur;
  2933. attrs = attrs.attr;
  2934. }
  2935. var fkeys = [], tkeys = [], keys = {}, from, to, f, eq,
  2936. el = this;
  2937. for (var key in attrs) if (attrs[has](key)) {
  2938. if (el.equal) {
  2939. eq = el.equal(key, Str(attrs[key]));
  2940. from = eq.from;
  2941. to = eq.to;
  2942. f = eq.f;
  2943. } else {
  2944. from = +el.attr(key);
  2945. to = +attrs[key];
  2946. }
  2947. var len = is(from, "array") ? from.length : 1;
  2948. keys[key] = slice(fkeys.length, fkeys.length + len, f);
  2949. fkeys = fkeys.concat(from);
  2950. tkeys = tkeys.concat(to);
  2951. }
  2952. var now = mina.time(),
  2953. anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) {
  2954. var attr = {};
  2955. for (var key in keys) if (keys[has](key)) {
  2956. attr[key] = keys[key](val);
  2957. }
  2958. el.attr(attr);
  2959. }, easing);
  2960. el.anims[anim.id] = anim;
  2961. anim._attrs = attrs;
  2962. anim._callback = callback;
  2963. eve.once("mina.finish." + anim.id, function () {
  2964. delete el.anims[anim.id];
  2965. callback && callback.call(el);
  2966. });
  2967. eve.once("mina.stop." + anim.id, function () {
  2968. delete el.anims[anim.id];
  2969. });
  2970. return el;
  2971. };
  2972. var eldata = {};
  2973. /*\
  2974. * Element.data
  2975. [ method ]
  2976. **
  2977. * Adds or retrieves given value associated with given key. (Don’t confuse
  2978. * with `data-` attributes)
  2979. *
  2980. * See also @Element.removeData
  2981. - key (string) key to store data
  2982. - value (any) #optional value to store
  2983. = (object) @Element
  2984. * or, if value is not specified:
  2985. = (any) value
  2986. > Usage
  2987. | for (var i = 0, i < 5, i++) {
  2988. | paper.circle(10 + 15 * i, 10, 10)
  2989. | .attr({fill: "#000"})
  2990. | .data("i", i)
  2991. | .click(function () {
  2992. | alert(this.data("i"));
  2993. | });
  2994. | }
  2995. \*/
  2996. elproto.data = function (key, value) {
  2997. var data = eldata[this.id] = eldata[this.id] || {};
  2998. if (arguments.length == 0){
  2999. eve("snap.data.get." + this.id, this, data, null);
  3000. return data;
  3001. }
  3002. if (arguments.length == 1) {
  3003. if (Snap.is(key, "object")) {
  3004. for (var i in key) if (key[has](i)) {
  3005. this.data(i, key[i]);
  3006. }
  3007. return this;
  3008. }
  3009. eve("snap.data.get." + this.id, this, data[key], key);
  3010. return data[key];
  3011. }
  3012. data[key] = value;
  3013. eve("snap.data.set." + this.id, this, value, key);
  3014. return this;
  3015. };
  3016. /*\
  3017. * Element.removeData
  3018. [ method ]
  3019. **
  3020. * Removes value associated with an element by given key.
  3021. * If key is not provided, removes all the data of the element.
  3022. - key (string) #optional key
  3023. = (object) @Element
  3024. \*/
  3025. elproto.removeData = function (key) {
  3026. if (key == null) {
  3027. eldata[this.id] = {};
  3028. } else {
  3029. eldata[this.id] && delete eldata[this.id][key];
  3030. }
  3031. return this;
  3032. };
  3033. /*\
  3034. * Element.outerSVG
  3035. [ method ]
  3036. **
  3037. * Returns SVG code for the element, equivalent to HTML's `outerHTML`.
  3038. *
  3039. * See also @Element.innerSVG
  3040. = (string) SVG code for the element
  3041. \*/
  3042. /*\
  3043. * Element.toString
  3044. [ method ]
  3045. **
  3046. * See @Element.outerSVG
  3047. \*/
  3048. elproto.outerSVG = elproto.toString = toString(1);
  3049. /*\
  3050. * Element.innerSVG
  3051. [ method ]
  3052. **
  3053. * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML`
  3054. = (string) SVG code for the element
  3055. \*/
  3056. elproto.innerSVG = toString();
  3057. function toString(type) {
  3058. return function () {
  3059. var res = type ? "<" + this.type : "",
  3060. attr = this.node.attributes,
  3061. chld = this.node.childNodes;
  3062. if (type) {
  3063. for (var i = 0, ii = attr.length; i < ii; i++) {
  3064. res += " " + attr[i].name + '="' +
  3065. attr[i].value.replace(/"/g, '\\"') + '"';
  3066. }
  3067. }
  3068. if (chld.length) {
  3069. type && (res += ">");
  3070. for (i = 0, ii = chld.length; i < ii; i++) {
  3071. if (chld[i].nodeType == 3) {
  3072. res += chld[i].nodeValue;
  3073. } else if (chld[i].nodeType == 1) {
  3074. res += wrap(chld[i]).toString();
  3075. }
  3076. }
  3077. type && (res += "</" + this.type + ">");
  3078. } else {
  3079. type && (res += "/>");
  3080. }
  3081. return res;
  3082. };
  3083. }
  3084. }(Element.prototype));
  3085. // SIERRA Snap.parse() accepts & returns a fragment, but there's no info on what it does in between. What if it doesn't parse?
  3086. /*\
  3087. * Snap.parse
  3088. [ method ]
  3089. **
  3090. * Parses SVG fragment and converts it into a @Fragment
  3091. **
  3092. - svg (string) SVG string
  3093. = (Fragment) the @Fragment
  3094. \*/
  3095. Snap.parse = function (svg) {
  3096. var f = glob.doc.createDocumentFragment(),
  3097. full = true,
  3098. div = glob.doc.createElement("div");
  3099. svg = Str(svg);
  3100. if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) {
  3101. svg = "<svg>" + svg + "</svg>";
  3102. full = false;
  3103. }
  3104. div.innerHTML = svg;
  3105. svg = div.getElementsByTagName("svg")[0];
  3106. if (svg) {
  3107. if (full) {
  3108. f = svg;
  3109. } else {
  3110. while (svg.firstChild) {
  3111. f.appendChild(svg.firstChild);
  3112. }
  3113. }
  3114. }
  3115. div.innerHTML = E;
  3116. return new Fragment(f);
  3117. };
  3118. function Fragment(frag) {
  3119. this.node = frag;
  3120. }
  3121. /*\
  3122. * Fragment.select
  3123. [ method ]
  3124. **
  3125. * See @Element.select
  3126. \*/
  3127. Fragment.prototype.select = Element.prototype.select;
  3128. /*\
  3129. * Fragment.selectAll
  3130. [ method ]
  3131. **
  3132. * See @Element.selectAll
  3133. \*/
  3134. Fragment.prototype.selectAll = Element.prototype.selectAll;
  3135. // SIERRA Snap.fragment() could especially use a code example
  3136. /*\
  3137. * Snap.fragment
  3138. [ method ]
  3139. **
  3140. * Creates a DOM fragment from a given list of elements or strings
  3141. **
  3142. - varargs (…) SVG string
  3143. = (Fragment) the @Fragment
  3144. \*/
  3145. Snap.fragment = function () {
  3146. var args = Array.prototype.slice.call(arguments, 0),
  3147. f = glob.doc.createDocumentFragment();
  3148. for (var i = 0, ii = args.length; i < ii; i++) {
  3149. var item = args[i];
  3150. if (item.node && item.node.nodeType) {
  3151. f.appendChild(item.node);
  3152. }
  3153. if (item.nodeType) {
  3154. f.appendChild(item);
  3155. }
  3156. if (typeof item == "string") {
  3157. f.appendChild(Snap.parse(item).node);
  3158. }
  3159. }
  3160. return new Fragment(f);
  3161. };
  3162. function make(name, parent) {
  3163. var res = $(name);
  3164. parent.appendChild(res);
  3165. var el = wrap(res);
  3166. el.type = name;
  3167. return el;
  3168. }
  3169. function Paper(w, h) {
  3170. var res,
  3171. desc,
  3172. defs,
  3173. proto = Paper.prototype;
  3174. if (w && w.tagName == "svg") {
  3175. if (w.snap in hub) {
  3176. return hub[w.snap];
  3177. }
  3178. res = new Element(w);
  3179. desc = w.getElementsByTagName("desc")[0];
  3180. defs = w.getElementsByTagName("defs")[0];
  3181. if (!desc) {
  3182. desc = $("desc");
  3183. desc.appendChild(glob.doc.createTextNode("Created with Snap"));
  3184. res.node.appendChild(desc);
  3185. }
  3186. if (!defs) {
  3187. defs = $("defs");
  3188. res.node.appendChild(defs);
  3189. }
  3190. res.defs = defs;
  3191. for (var key in proto) if (proto[has](key)) {
  3192. res[key] = proto[key];
  3193. }
  3194. res.paper = res.root = res;
  3195. } else {
  3196. res = make("svg", glob.doc.body);
  3197. $(res.node, {
  3198. height: h,
  3199. version: 1.1,
  3200. width: w,
  3201. xmlns: xmlns
  3202. });
  3203. }
  3204. return res;
  3205. }
  3206. function wrap(dom) {
  3207. if (!dom) {
  3208. return dom;
  3209. }
  3210. if (dom instanceof Element || dom instanceof Fragment) {
  3211. return dom;
  3212. }
  3213. if (dom.tagName == "svg") {
  3214. return new Paper(dom);
  3215. }
  3216. return new Element(dom);
  3217. }
  3218. // gradients' helpers
  3219. function Gstops() {
  3220. return this.selectAll("stop");
  3221. }
  3222. function GaddStop(color, offset) {
  3223. var stop = $("stop"),
  3224. attr = {
  3225. offset: +offset + "%"
  3226. };
  3227. color = Snap.color(color);
  3228. attr["stop-color"] = color.hex;
  3229. if (color.opacity < 1) {
  3230. attr["stop-opacity"] = color.opacity;
  3231. }
  3232. $(stop, attr);
  3233. this.node.appendChild(stop);
  3234. return this;
  3235. }
  3236. function GgetBBox() {
  3237. if (this.type == "linearGradient") {
  3238. var x1 = $(this.node, "x1") || 0,
  3239. x2 = $(this.node, "x2") || 1,
  3240. y1 = $(this.node, "y1") || 0,
  3241. y2 = $(this.node, "y2") || 0;
  3242. return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1));
  3243. } else {
  3244. var cx = this.node.cx || .5,
  3245. cy = this.node.cy || .5,
  3246. r = this.node.r || 0;
  3247. return Snap._.box(cx - r, cy - r, r * 2, r * 2);
  3248. }
  3249. }
  3250. function gradient(defs, str) {
  3251. var grad = arrayFirstValue(eve("snap.util.grad.parse", null, str)),
  3252. el;
  3253. if (!grad) {
  3254. return null;
  3255. }
  3256. grad.params.unshift(defs);
  3257. if (grad.type.toLowerCase() == "l") {
  3258. el = gradientLinear.apply(0, grad.params);
  3259. } else {
  3260. el = gradientRadial.apply(0, grad.params);
  3261. }
  3262. if (grad.type != grad.type.toLowerCase()) {
  3263. $(el.node, {
  3264. gradientUnits: "userSpaceOnUse"
  3265. });
  3266. }
  3267. var stops = grad.stops,
  3268. len = stops.length,
  3269. start = 0,
  3270. j = 0;
  3271. function seed(i, end) {
  3272. var step = (end - start) / (i - j);
  3273. for (var k = j; k < i; k++) {
  3274. stops[k].offset = +(+start + step * (k - j)).toFixed(2);
  3275. }
  3276. j = i;
  3277. start = end;
  3278. }
  3279. len--;
  3280. for (var i = 0; i < len; i++) if ("offset" in stops[i]) {
  3281. seed(i, stops[i].offset);
  3282. }
  3283. stops[len].offset = stops[len].offset || 100;
  3284. seed(len, stops[len].offset);
  3285. for (i = 0; i <= len; i++) {
  3286. var stop = stops[i];
  3287. el.addStop(stop.color, stop.offset);
  3288. }
  3289. return el;
  3290. }
  3291. function gradientLinear(defs, x1, y1, x2, y2) {
  3292. var el = make("linearGradient", defs);
  3293. el.stops = Gstops;
  3294. el.addStop = GaddStop;
  3295. el.getBBox = GgetBBox;
  3296. if (x1 != null) {
  3297. $(el.node, {
  3298. x1: x1,
  3299. y1: y1,
  3300. x2: x2,
  3301. y2: y2
  3302. });
  3303. }
  3304. return el;
  3305. }
  3306. function gradientRadial(defs, cx, cy, r, fx, fy) {
  3307. var el = make("radialGradient", defs);
  3308. el.stops = Gstops;
  3309. el.addStop = GaddStop;
  3310. el.getBBox = GgetBBox;
  3311. if (cx != null) {
  3312. $(el.node, {
  3313. cx: cx,
  3314. cy: cy,
  3315. r: r
  3316. });
  3317. }
  3318. if (fx != null && fy != null) {
  3319. $(el.node, {
  3320. fx: fx,
  3321. fy: fy
  3322. });
  3323. }
  3324. return el;
  3325. }
  3326. // Paper prototype methods
  3327. (function (proto) {
  3328. /*\
  3329. * Paper.el
  3330. [ method ]
  3331. **
  3332. * Creates an element on paper with a given name and no attributes
  3333. **
  3334. - name (string) tag name
  3335. - attr (object) attributes
  3336. = (Element) the current element
  3337. > Usage
  3338. | var c = paper.circle(10, 10, 10); // is the same as...
  3339. | var c = paper.el("circle").attr({
  3340. | cx: 10,
  3341. | cy: 10,
  3342. | r: 10
  3343. | });
  3344. | // and the same as
  3345. | var c = paper.el("circle", {
  3346. | cx: 10,
  3347. | cy: 10,
  3348. | r: 10
  3349. | });
  3350. \*/
  3351. proto.el = function (name, attr) {
  3352. return make(name, this.node).attr(attr);
  3353. };
  3354. /*\
  3355. * Paper.rect
  3356. [ method ]
  3357. *
  3358. * Draws a rectangle
  3359. **
  3360. - x (number) x coordinate of the top left corner
  3361. - y (number) y coordinate of the top left corner
  3362. - width (number) width
  3363. - height (number) height
  3364. - rx (number) #optional horizontal radius for rounded corners, default is 0
  3365. - ry (number) #optional vertical radius for rounded corners, default is rx or 0
  3366. = (object) the `rect` element
  3367. **
  3368. > Usage
  3369. | // regular rectangle
  3370. | var c = paper.rect(10, 10, 50, 50);
  3371. | // rectangle with rounded corners
  3372. | var c = paper.rect(40, 40, 50, 50, 10);
  3373. \*/
  3374. proto.rect = function (x, y, w, h, rx, ry) {
  3375. var attr;
  3376. if (ry == null) {
  3377. ry = rx;
  3378. }
  3379. if (is(x, "object") && "x" in x) {
  3380. attr = x;
  3381. } else if (x != null) {
  3382. attr = {
  3383. x: x,
  3384. y: y,
  3385. width: w,
  3386. height: h
  3387. };
  3388. if (rx != null) {
  3389. attr.rx = rx;
  3390. attr.ry = ry;
  3391. }
  3392. }
  3393. return this.el("rect", attr);
  3394. };
  3395. /*\
  3396. * Paper.circle
  3397. [ method ]
  3398. **
  3399. * Draws a circle
  3400. **
  3401. - x (number) x coordinate of the centre
  3402. - y (number) y coordinate of the centre
  3403. - r (number) radius
  3404. = (object) the `circle` element
  3405. **
  3406. > Usage
  3407. | var c = paper.circle(50, 50, 40);
  3408. \*/
  3409. proto.circle = function (cx, cy, r) {
  3410. var attr;
  3411. if (is(cx, "object") && "cx" in cx) {
  3412. attr = cx;
  3413. } else if (cx != null) {
  3414. attr = {
  3415. cx: cx,
  3416. cy: cy,
  3417. r: r
  3418. };
  3419. }
  3420. return this.el("circle", attr);
  3421. };
  3422. /*\
  3423. * Paper.image
  3424. [ method ]
  3425. **
  3426. * Places an image on the surface
  3427. **
  3428. - src (string) URI of the source image
  3429. - x (number) x offset position
  3430. - y (number) y offset position
  3431. - width (number) width of the image
  3432. - height (number) height of the image
  3433. = (object) the `image` element
  3434. * or
  3435. = (object) Snap element object with type `image`
  3436. **
  3437. > Usage
  3438. | var c = paper.image("apple.png", 10, 10, 80, 80);
  3439. \*/
  3440. proto.image = function (src, x, y, width, height) {
  3441. var el = make("image", this.node);
  3442. if (is(src, "object") && "src" in src) {
  3443. el.attr(src);
  3444. } else if (src != null) {
  3445. var set = {
  3446. "xlink:href": src,
  3447. preserveAspectRatio: "none"
  3448. };
  3449. if (x != null && y != null) {
  3450. set.x = x;
  3451. set.y = y;
  3452. }
  3453. if (width != null && height != null) {
  3454. set.width = width;
  3455. set.height = height;
  3456. } else {
  3457. preload(src, function () {
  3458. $(el.node, {
  3459. width: this.offsetWidth,
  3460. height: this.offsetHeight
  3461. });
  3462. });
  3463. }
  3464. $(el.node, set);
  3465. }
  3466. return el;
  3467. };
  3468. /*\
  3469. * Paper.ellipse
  3470. [ method ]
  3471. **
  3472. * Draws an ellipse
  3473. **
  3474. - x (number) x coordinate of the centre
  3475. - y (number) y coordinate of the centre
  3476. - rx (number) horizontal radius
  3477. - ry (number) vertical radius
  3478. = (object) the `ellipse` element
  3479. **
  3480. > Usage
  3481. | var c = paper.ellipse(50, 50, 40, 20);
  3482. \*/
  3483. proto.ellipse = function (cx, cy, rx, ry) {
  3484. var el = make("ellipse", this.node);
  3485. if (is(cx, "object") && "cx" in cx) {
  3486. el.attr(cx);
  3487. } else if (cx != null) {
  3488. el.attr({
  3489. cx: cx,
  3490. cy: cy,
  3491. rx: rx,
  3492. ry: ry
  3493. });
  3494. }
  3495. return el;
  3496. };
  3497. // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier.
  3498. /*\
  3499. * Paper.path
  3500. [ method ]
  3501. **
  3502. * Creates a `<path>` element using the given string as the path's definition
  3503. - pathString (string) #optional path string in SVG format
  3504. * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example:
  3505. | "M10,20L30,40"
  3506. * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates.
  3507. *
  3508. # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p>
  3509. # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody>
  3510. # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr>
  3511. # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr>
  3512. # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr>
  3513. # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr>
  3514. # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr>
  3515. # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr>
  3516. # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr>
  3517. # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr>
  3518. # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr>
  3519. # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr>
  3520. # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table>
  3521. * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier.
  3522. * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point.
  3523. > Usage
  3524. | var c = paper.path("M10 10L90 90");
  3525. | // draw a diagonal line:
  3526. | // move to 10,10, line to 90,90
  3527. \*/
  3528. proto.path = function (d) {
  3529. var el = make("path", this.node);
  3530. if (is(d, "object") && !is(d, "array")) {
  3531. el.attr(d);
  3532. } else if (d) {
  3533. el.attr({
  3534. d: d
  3535. });
  3536. }
  3537. return el;
  3538. };
  3539. // SIERRA Paper.g(): Don't understand the code comment about the order being _different._ Wouldn't it be a rect followed by a circle?
  3540. /*\
  3541. * Paper.g
  3542. [ method ]
  3543. **
  3544. * Creates a group element
  3545. **
  3546. - varargs (…) #optional elements to nest within the group
  3547. = (object) the `g` element
  3548. **
  3549. > Usage
  3550. | var c1 = paper.circle(),
  3551. | c2 = paper.rect(),
  3552. | g = paper.g(c2, c1); // note that the order of elements is different
  3553. * or
  3554. | var c1 = paper.circle(),
  3555. | c2 = paper.rect(),
  3556. | g = paper.g();
  3557. | g.add(c2, c1);
  3558. \*/
  3559. /*\
  3560. * Paper.group
  3561. [ method ]
  3562. **
  3563. * See @Paper.g
  3564. \*/
  3565. proto.group = proto.g = function (first) {
  3566. var el = make("g", this.node);
  3567. el.add = add2group;
  3568. for (var method in proto) if (proto[has](method)) {
  3569. el[method] = proto[method];
  3570. }
  3571. if (arguments.length == 1 && first && !first.type) {
  3572. el.attr(first);
  3573. } else if (arguments.length) {
  3574. el.add(Array.prototype.slice.call(arguments, 0));
  3575. }
  3576. return el;
  3577. };
  3578. /*\
  3579. * Paper.text
  3580. [ method ]
  3581. **
  3582. * Draws a text string
  3583. **
  3584. - x (number) x coordinate position
  3585. - y (number) y coordinate position
  3586. - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements
  3587. = (object) the `text` element
  3588. **
  3589. > Usage
  3590. | var t1 = paper.text(50, 50, "Snap");
  3591. | var t2 = paper.text(50, 50, ["S","n","a","p"]);
  3592. | // Text path usage
  3593. | t1.attr({textpath: "M10,10L100,100"});
  3594. | // or
  3595. | var pth = paper.path("M10,10L100,100");
  3596. | t1.attr({textpath: pth});
  3597. \*/
  3598. proto.text = function (x, y, text) {
  3599. var el = make("text", this.node);
  3600. if (is(x, "object")) {
  3601. el.attr(x);
  3602. } else if (x != null) {
  3603. el.attr({
  3604. x: x,
  3605. y: y,
  3606. text: text || ""
  3607. });
  3608. }
  3609. return el;
  3610. };
  3611. /*\
  3612. * Paper.line
  3613. [ method ]
  3614. **
  3615. * Draws a line
  3616. **
  3617. - x1 (number) x coordinate position of the start
  3618. - y1 (number) y coordinate position of the start
  3619. - x2 (number) x coordinate position of the end
  3620. - y2 (number) y coordinate position of the end
  3621. = (object) the `line` element
  3622. **
  3623. > Usage
  3624. | var t1 = paper.line(50, 50, 100, 100);
  3625. \*/
  3626. proto.line = function (x1, y1, x2, y2) {
  3627. var el = make("line", this.node);
  3628. if (is(x1, "object")) {
  3629. el.attr(x1);
  3630. } else if (x1 != null) {
  3631. el.attr({
  3632. x1: x1,
  3633. x2: x2,
  3634. y1: y1,
  3635. y2: y2
  3636. });
  3637. }
  3638. return el;
  3639. };
  3640. /*\
  3641. * Paper.polyline
  3642. [ method ]
  3643. **
  3644. * Draws a polyline
  3645. **
  3646. - points (array) array of points
  3647. * or
  3648. - varargs (…) points
  3649. = (object) the `polyline` element
  3650. **
  3651. > Usage
  3652. | var p1 = paper.polyline([10, 10, 100, 100]);
  3653. | var p2 = paper.polyline(10, 10, 100, 100);
  3654. \*/
  3655. proto.polyline = function (points) {
  3656. if (arguments.length > 1) {
  3657. points = Array.prototype.slice.call(arguments, 0);
  3658. }
  3659. var el = make("polyline", this.node);
  3660. if (is(points, "object") && !is(points, "array")) {
  3661. el.attr(points);
  3662. } else if (points != null) {
  3663. el.attr({
  3664. points: points
  3665. });
  3666. }
  3667. return el;
  3668. };
  3669. /*\
  3670. * Paper.polygon
  3671. [ method ]
  3672. **
  3673. * Draws a polygon. See @Paper.polyline
  3674. \*/
  3675. proto.polygon = function (points) {
  3676. if (arguments.length > 1) {
  3677. points = Array.prototype.slice.call(arguments, 0);
  3678. }
  3679. var el = make("polygon", this.node);
  3680. if (is(points, "object") && !is(points, "array")) {
  3681. el.attr(points);
  3682. } else if (points != null) {
  3683. el.attr({
  3684. points: points
  3685. });
  3686. }
  3687. return el;
  3688. };
  3689. // gradients
  3690. (function () {
  3691. /*\
  3692. * Paper.gradient
  3693. [ method ]
  3694. **
  3695. * Creates a gradient element
  3696. **
  3697. - gradient (string) gradient descriptor
  3698. > Gradient Descriptor
  3699. * The gradient descriptor is an expression formatted as
  3700. * follows: `<type>(<coords>)<colors>`. The `<type>` can be
  3701. * either linear or radial. The uppercase `L` or `R` letters
  3702. * indicate absolute coordinates offset from the SVG surface.
  3703. * Lowercase `l` or `r` letters indicate coordinates
  3704. * calculated relative to the element to which the gradient is
  3705. * applied. Coordinates specify a linear gradient vector as
  3706. * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`,
  3707. * `r` and optional `fx`, `fy` specifying a focal point away
  3708. * from the center of the circle. Specify `<colors>` as a list
  3709. * of dash-separated CSS color values. Each color may be
  3710. * followed by a custom offset value, separated with a colon
  3711. * character.
  3712. > Examples
  3713. * Linear gradient, relative from top-left corner to bottom-right
  3714. * corner, from black through red to white:
  3715. | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff");
  3716. * Linear gradient, absolute from (0, 0) to (100, 100), from black
  3717. * through red at 25% to white:
  3718. | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25%-#fff");
  3719. * Radial gradient, relative from the center of the element with radius
  3720. * half the width, from black to white:
  3721. | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff");
  3722. * To apply the gradient:
  3723. | paper.circle(50, 50, 40).attr({
  3724. | fill: g
  3725. | });
  3726. = (object) the `gradient` element
  3727. \*/
  3728. proto.gradient = function (str) {
  3729. return gradient(this.defs, str);
  3730. };
  3731. proto.gradientLinear = function (x1, y1, x2, y2) {
  3732. return gradientLinear(this.defs, x1, y1, x2, y2);
  3733. };
  3734. proto.gradientRadial = function (cx, cy, r, fx, fy) {
  3735. return gradientRadial(this.defs, cx, cy, r, fx, fy);
  3736. };
  3737. /*\
  3738. * Paper.toString
  3739. [ method ]
  3740. **
  3741. * Returns SVG code for the @Paper
  3742. = (string) SVG code for the @Paper
  3743. \*/
  3744. proto.toString = function () {
  3745. var f = glob.doc.createDocumentFragment(),
  3746. d = glob.doc.createElement("div"),
  3747. svg = this.node.cloneNode(true),
  3748. res;
  3749. f.appendChild(d);
  3750. d.appendChild(svg);
  3751. $(svg, {xmlns: xmlns});
  3752. res = d.innerHTML;
  3753. f.removeChild(f.firstChild);
  3754. return res;
  3755. };
  3756. /*\
  3757. * Paper.clear
  3758. [ method ]
  3759. **
  3760. * Removes all child nodes of the paper, except <defs>.
  3761. \*/
  3762. proto.clear = function () {
  3763. var node = this.node.firstChild,
  3764. next;
  3765. while (node) {
  3766. next = node.nextSibling;
  3767. if (node.tagName != "defs") {
  3768. node.parentNode.removeChild(node);
  3769. }
  3770. node = next;
  3771. }
  3772. };
  3773. }());
  3774. }(Paper.prototype));
  3775. // simple ajax
  3776. /*\
  3777. * Snap.ajax
  3778. [ method ]
  3779. **
  3780. * Simple implementation of Ajax
  3781. **
  3782. - url (string) URL
  3783. - postData (object|string) data for post request
  3784. - callback (function) callback
  3785. - scope (object) #optional scope of callback
  3786. * or
  3787. - url (string) URL
  3788. - callback (function) callback
  3789. - scope (object) #optional scope of callback
  3790. = (XMLHttpRequest) the XMLHttpRequest object, just in case
  3791. \*/
  3792. Snap.ajax = function (url, postData, callback, scope){
  3793. var req = new XMLHttpRequest,
  3794. id = ID();
  3795. if (req) {
  3796. if (is(postData, "function")) {
  3797. scope = callback;
  3798. callback = postData;
  3799. postData = null;
  3800. } else if (is(postData, "object")) {
  3801. var pd = [];
  3802. for (var key in postData) if (postData.hasOwnProperty(key)) {
  3803. pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key]));
  3804. }
  3805. postData = pd.join("&");
  3806. }
  3807. req.open((postData ? "POST" : "GET"), url, true);
  3808. req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  3809. if (postData) {
  3810. req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  3811. }
  3812. if (callback) {
  3813. eve.once("snap.ajax." + id + ".0", callback);
  3814. eve.once("snap.ajax." + id + ".200", callback);
  3815. eve.once("snap.ajax." + id + ".304", callback);
  3816. }
  3817. req.onreadystatechange = function() {
  3818. if (req.readyState != 4) return;
  3819. eve("snap.ajax." + id + "." + req.status, scope, req);
  3820. };
  3821. if (req.readyState == 4) {
  3822. return req;
  3823. }
  3824. req.send(postData);
  3825. return req;
  3826. }
  3827. };
  3828. /*\
  3829. * Snap.load
  3830. [ method ]
  3831. **
  3832. * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX)
  3833. **
  3834. - url (string) URL
  3835. - callback (function) callback
  3836. - scope (object) #optional scope of callback
  3837. \*/
  3838. Snap.load = function (url, callback, scope) {
  3839. Snap.ajax(url, function (req) {
  3840. var f = Snap.parse(req.responseText);
  3841. scope ? callback.call(scope, f) : callback(f);
  3842. });
  3843. };
  3844. // Attributes event handlers
  3845. eve.on("snap.util.attr.mask", function (value) {
  3846. if (value instanceof Element || value instanceof Fragment) {
  3847. eve.stop();
  3848. if (value instanceof Fragment && value.node.childNodes.length == 1) {
  3849. value = value.node.firstChild;
  3850. getSomeDefs(this).appendChild(value);
  3851. value = wrap(value);
  3852. }
  3853. if (value.type == "mask") {
  3854. var mask = value;
  3855. } else {
  3856. mask = make("mask", getSomeDefs(this));
  3857. mask.node.appendChild(value.node);
  3858. !mask.node.id && $(mask.node, {
  3859. id: mask.id
  3860. });
  3861. }
  3862. $(this.node, {
  3863. mask: URL(mask.id)
  3864. });
  3865. }
  3866. });
  3867. (function (clipIt) {
  3868. eve.on("snap.util.attr.clip", clipIt);
  3869. eve.on("snap.util.attr.clip-path", clipIt);
  3870. eve.on("snap.util.attr.clipPath", clipIt);
  3871. }(function (value) {
  3872. if (value instanceof Element || value instanceof Fragment) {
  3873. eve.stop();
  3874. if (value.type == "clipPath") {
  3875. var clip = value;
  3876. } else {
  3877. clip = make("clipPath", getSomeDefs(this));
  3878. clip.node.appendChild(value.node);
  3879. !clip.node.id && $(clip.node, {
  3880. id: clip.id
  3881. });
  3882. }
  3883. $(this.node, {
  3884. "clip-path": URL(clip.id)
  3885. });
  3886. }
  3887. }));
  3888. function fillStroke(name) {
  3889. return function (value) {
  3890. eve.stop();
  3891. if (value instanceof Fragment && value.node.childNodes.length == 1 &&
  3892. (value.node.firstChild.tagName == "radialGradient" ||
  3893. value.node.firstChild.tagName == "linearGradient" ||
  3894. value.node.firstChild.tagName == "pattern")) {
  3895. value = value.node.firstChild;
  3896. getSomeDefs(this).appendChild(value);
  3897. value = wrap(value);
  3898. }
  3899. if (value instanceof Element) {
  3900. if (value.type == "radialGradient" || value.type == "linearGradient"
  3901. || value.type == "pattern") {
  3902. if (!value.node.id) {
  3903. $(value.node, {
  3904. id: value.id
  3905. });
  3906. }
  3907. var fill = URL(value.node.id);
  3908. } else {
  3909. fill = value.attr(name);
  3910. }
  3911. } else {
  3912. fill = Snap.color(value);
  3913. if (fill.error) {
  3914. var grad = gradient(getSomeDefs(this), value);
  3915. if (grad) {
  3916. if (!grad.node.id) {
  3917. $(grad.node, {
  3918. id: grad.id
  3919. });
  3920. }
  3921. fill = URL(grad.node.id);
  3922. } else {
  3923. fill = value;
  3924. }
  3925. } else {
  3926. fill = Str(fill);
  3927. }
  3928. }
  3929. var attrs = {};
  3930. attrs[name] = fill;
  3931. $(this.node, attrs);
  3932. this.node.style[name] = E;
  3933. };
  3934. }
  3935. eve.on("snap.util.attr.fill", fillStroke("fill"));
  3936. eve.on("snap.util.attr.stroke", fillStroke("stroke"));
  3937. var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i;
  3938. eve.on("snap.util.grad.parse", function parseGrad(string) {
  3939. string = Str(string);
  3940. var tokens = string.match(gradrg);
  3941. if (!tokens) {
  3942. return null;
  3943. }
  3944. var type = tokens[1],
  3945. params = tokens[2],
  3946. stops = tokens[3];
  3947. params = params.split(/\s*,\s*/).map(function (el) {
  3948. return +el == el ? +el : el;
  3949. });
  3950. if (params.length == 1 && params[0] == 0) {
  3951. params = [];
  3952. }
  3953. stops = stops.split("-");
  3954. stops = stops.map(function (el) {
  3955. el = el.split(":");
  3956. var out = {
  3957. color: el[0]
  3958. };
  3959. if (el[1]) {
  3960. out.offset = el[1];
  3961. }
  3962. return out;
  3963. });
  3964. return {
  3965. type: type,
  3966. params: params,
  3967. stops: stops
  3968. };
  3969. });
  3970. eve.on("snap.util.attr.d", function (value) {
  3971. eve.stop();
  3972. if (is(value, "array") && is(value[0], "array")) {
  3973. value = Snap.path.toString.call(value);
  3974. }
  3975. value = Str(value);
  3976. if (value.match(/[ruo]/i)) {
  3977. value = Snap.path.toAbsolute(value);
  3978. }
  3979. $(this.node, {d: value});
  3980. })(-1);
  3981. eve.on("snap.util.attr.#text", function (value) {
  3982. eve.stop();
  3983. value = Str(value);
  3984. var txt = glob.doc.createTextNode(value);
  3985. while (this.node.firstChild) {
  3986. this.node.removeChild(this.node.firstChild);
  3987. }
  3988. this.node.appendChild(txt);
  3989. })(-1);
  3990. eve.on("snap.util.attr.path", function (value) {
  3991. eve.stop();
  3992. this.attr({d: value});
  3993. })(-1);
  3994. eve.on("snap.util.attr.viewBox", function (value) {
  3995. var vb;
  3996. if (is(value, "object") && "x" in value) {
  3997. vb = [value.x, value.y, value.width, value.height].join(" ");
  3998. } else if (is(value, "array")) {
  3999. vb = value.join(" ");
  4000. } else {
  4001. vb = value;
  4002. }
  4003. $(this.node, {
  4004. viewBox: vb
  4005. });
  4006. eve.stop();
  4007. })(-1);
  4008. eve.on("snap.util.attr.transform", function (value) {
  4009. this.transform(value);
  4010. eve.stop();
  4011. })(-1);
  4012. eve.on("snap.util.attr.r", function (value) {
  4013. if (this.type == "rect") {
  4014. eve.stop();
  4015. $(this.node, {
  4016. rx: value,
  4017. ry: value
  4018. });
  4019. }
  4020. })(-1);
  4021. eve.on("snap.util.attr.textpath", function (value) {
  4022. eve.stop();
  4023. if (this.type == "text") {
  4024. var id, tp, node;
  4025. if (!value && this.textPath) {
  4026. tp = this.textPath;
  4027. while (tp.node.firstChild) {
  4028. this.node.appendChild(tp.node.firstChild);
  4029. }
  4030. tp.remove();
  4031. delete this.textPath;
  4032. return;
  4033. }
  4034. if (is(value, "string")) {
  4035. var defs = getSomeDefs(this),
  4036. path = wrap(defs.parentNode).path(value);
  4037. defs.appendChild(path.node);
  4038. id = path.id;
  4039. path.attr({id: id});
  4040. } else {
  4041. value = wrap(value);
  4042. if (value instanceof Element) {
  4043. id = value.attr("id");
  4044. if (!id) {
  4045. id = value.id;
  4046. value.attr({id: id});
  4047. }
  4048. }
  4049. }
  4050. if (id) {
  4051. tp = this.textPath;
  4052. node = this.node;
  4053. if (tp) {
  4054. tp.attr({"xlink:href": "#" + id});
  4055. } else {
  4056. tp = $("textPath", {
  4057. "xlink:href": "#" + id
  4058. });
  4059. while (node.firstChild) {
  4060. tp.appendChild(node.firstChild);
  4061. }
  4062. node.appendChild(tp);
  4063. this.textPath = wrap(tp);
  4064. }
  4065. }
  4066. }
  4067. })(-1);
  4068. eve.on("snap.util.attr.text", function (value) {
  4069. if (this.type == "text") {
  4070. var i = 0,
  4071. node = this.node,
  4072. tuner = function (chunk) {
  4073. var out = $("tspan");
  4074. if (is(chunk, "array")) {
  4075. for (var i = 0; i < chunk.length; i++) {
  4076. out.appendChild(tuner(chunk[i]));
  4077. }
  4078. } else {
  4079. out.appendChild(glob.doc.createTextNode(chunk));
  4080. }
  4081. out.normalize && out.normalize();
  4082. return out;
  4083. };
  4084. while (node.firstChild) {
  4085. node.removeChild(node.firstChild);
  4086. }
  4087. var tuned = tuner(value);
  4088. while (tuned.firstChild) {
  4089. node.appendChild(tuned.firstChild);
  4090. }
  4091. }
  4092. eve.stop();
  4093. })(-1);
  4094. // default
  4095. var cssAttr = {
  4096. "alignment-baseline": 0,
  4097. "baseline-shift": 0,
  4098. "clip": 0,
  4099. "clip-path": 0,
  4100. "clip-rule": 0,
  4101. "color": 0,
  4102. "color-interpolation": 0,
  4103. "color-interpolation-filters": 0,
  4104. "color-profile": 0,
  4105. "color-rendering": 0,
  4106. "cursor": 0,
  4107. "direction": 0,
  4108. "display": 0,
  4109. "dominant-baseline": 0,
  4110. "enable-background": 0,
  4111. "fill": 0,
  4112. "fill-opacity": 0,
  4113. "fill-rule": 0,
  4114. "filter": 0,
  4115. "flood-color": 0,
  4116. "flood-opacity": 0,
  4117. "font": 0,
  4118. "font-family": 0,
  4119. "font-size": 0,
  4120. "font-size-adjust": 0,
  4121. "font-stretch": 0,
  4122. "font-style": 0,
  4123. "font-variant": 0,
  4124. "font-weight": 0,
  4125. "glyph-orientation-horizontal": 0,
  4126. "glyph-orientation-vertical": 0,
  4127. "image-rendering": 0,
  4128. "kerning": 0,
  4129. "letter-spacing": 0,
  4130. "lighting-color": 0,
  4131. "marker": 0,
  4132. "marker-end": 0,
  4133. "marker-mid": 0,
  4134. "marker-start": 0,
  4135. "mask": 0,
  4136. "opacity": 0,
  4137. "overflow": 0,
  4138. "pointer-events": 0,
  4139. "shape-rendering": 0,
  4140. "stop-color": 0,
  4141. "stop-opacity": 0,
  4142. "stroke": 0,
  4143. "stroke-dasharray": 0,
  4144. "stroke-dashoffset": 0,
  4145. "stroke-linecap": 0,
  4146. "stroke-linejoin": 0,
  4147. "stroke-miterlimit": 0,
  4148. "stroke-opacity": 0,
  4149. "stroke-width": 0,
  4150. "text-anchor": 0,
  4151. "text-decoration": 0,
  4152. "text-rendering": 0,
  4153. "unicode-bidi": 0,
  4154. "visibility": 0,
  4155. "word-spacing": 0,
  4156. "writing-mode": 0
  4157. };
  4158. eve.on("snap.util.attr", function (value) {
  4159. var att = eve.nt(),
  4160. attr = {};
  4161. att = att.substring(att.lastIndexOf(".") + 1);
  4162. attr[att] = value;
  4163. var style = att.replace(/-(\w)/gi, function (all, letter) {
  4164. return letter.toUpperCase();
  4165. }),
  4166. css = att.replace(/[A-Z]/g, function (letter) {
  4167. return "-" + letter.toLowerCase();
  4168. });
  4169. if (cssAttr[has](css)) {
  4170. this.node.style[style] = value == null ? E : value;
  4171. } else {
  4172. $(this.node, attr);
  4173. }
  4174. });
  4175. eve.on("snap.util.getattr.transform", function () {
  4176. eve.stop();
  4177. return this.transform();
  4178. })(-1);
  4179. eve.on("snap.util.getattr.textpath", function () {
  4180. eve.stop();
  4181. return this.textPath;
  4182. })(-1);
  4183. // Markers
  4184. (function () {
  4185. function getter(end) {
  4186. return function () {
  4187. eve.stop();
  4188. var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end);
  4189. if (style == "none") {
  4190. return style;
  4191. } else {
  4192. return Snap(glob.doc.getElementById(style.match(reURLValue)[1]));
  4193. }
  4194. };
  4195. }
  4196. function setter(end) {
  4197. return function (value) {
  4198. eve.stop();
  4199. var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1);
  4200. if (value == "" || !value) {
  4201. this.node.style[name] = "none";
  4202. return;
  4203. }
  4204. if (value.type == "marker") {
  4205. var id = value.node.id;
  4206. if (!id) {
  4207. $(value.node, {id: value.id});
  4208. }
  4209. this.node.style[name] = URL(id);
  4210. return;
  4211. }
  4212. };
  4213. }
  4214. eve.on("snap.util.getattr.marker-end", getter("end"))(-1);
  4215. eve.on("snap.util.getattr.markerEnd", getter("end"))(-1);
  4216. eve.on("snap.util.getattr.marker-start", getter("start"))(-1);
  4217. eve.on("snap.util.getattr.markerStart", getter("start"))(-1);
  4218. eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1);
  4219. eve.on("snap.util.getattr.markerMid", getter("mid"))(-1);
  4220. eve.on("snap.util.attr.marker-end", setter("end"))(-1);
  4221. eve.on("snap.util.attr.markerEnd", setter("end"))(-1);
  4222. eve.on("snap.util.attr.marker-start", setter("start"))(-1);
  4223. eve.on("snap.util.attr.markerStart", setter("start"))(-1);
  4224. eve.on("snap.util.attr.marker-mid", setter("mid"))(-1);
  4225. eve.on("snap.util.attr.markerMid", setter("mid"))(-1);
  4226. }());
  4227. eve.on("snap.util.getattr.r", function () {
  4228. if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) {
  4229. eve.stop();
  4230. return $(this.node, "rx");
  4231. }
  4232. })(-1);
  4233. function textExtract(node) {
  4234. var out = [];
  4235. var children = node.childNodes;
  4236. for (var i = 0, ii = children.length; i < ii; i++) {
  4237. var chi = children[i];
  4238. if (chi.nodeType == 3) {
  4239. out.push(chi.nodeValue);
  4240. }
  4241. if (chi.tagName == "tspan") {
  4242. if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) {
  4243. out.push(chi.firstChild.nodeValue);
  4244. } else {
  4245. out.push(textExtract(chi));
  4246. }
  4247. }
  4248. }
  4249. return out;
  4250. }
  4251. eve.on("snap.util.getattr.text", function () {
  4252. if (this.type == "text" || this.type == "tspan") {
  4253. eve.stop();
  4254. var out = textExtract(this.node);
  4255. return out.length == 1 ? out[0] : out;
  4256. }
  4257. })(-1);
  4258. eve.on("snap.util.getattr.#text", function () {
  4259. return this.node.textContent;
  4260. })(-1);
  4261. eve.on("snap.util.getattr.viewBox", function () {
  4262. eve.stop();
  4263. var vb = $(this.node, "viewBox").split(separator);
  4264. return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]);
  4265. // TODO: investigate why I need to z-index it
  4266. })(-1);
  4267. eve.on("snap.util.getattr.points", function () {
  4268. var p = $(this.node, "points");
  4269. eve.stop();
  4270. return p.split(separator);
  4271. });
  4272. eve.on("snap.util.getattr.path", function () {
  4273. var p = $(this.node, "d");
  4274. eve.stop();
  4275. return p;
  4276. });
  4277. // default
  4278. eve.on("snap.util.getattr", function () {
  4279. var att = eve.nt();
  4280. att = att.substring(att.lastIndexOf(".") + 1);
  4281. var css = att.replace(/[A-Z]/g, function (letter) {
  4282. return "-" + letter.toLowerCase();
  4283. });
  4284. if (cssAttr[has](css)) {
  4285. return glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue(css);
  4286. } else {
  4287. return $(this.node, att);
  4288. }
  4289. });
  4290. var getOffset = function (elem) {
  4291. var box = elem.getBoundingClientRect(),
  4292. doc = elem.ownerDocument,
  4293. body = doc.body,
  4294. docElem = doc.documentElement,
  4295. clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
  4296. top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop,
  4297. left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft;
  4298. return {
  4299. y: top,
  4300. x: left
  4301. };
  4302. };
  4303. /*\
  4304. * Snap.getElementByPoint
  4305. [ method ]
  4306. **
  4307. * Returns you topmost element under given point.
  4308. **
  4309. = (object) Snap element object
  4310. - x (number) x coordinate from the top left corner of the window
  4311. - y (number) y coordinate from the top left corner of the window
  4312. > Usage
  4313. | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
  4314. \*/
  4315. Snap.getElementByPoint = function (x, y) {
  4316. var paper = this,
  4317. svg = paper.canvas,
  4318. target = glob.doc.elementFromPoint(x, y);
  4319. if (glob.win.opera && target.tagName == "svg") {
  4320. var so = getOffset(target),
  4321. sr = target.createSVGRect();
  4322. sr.x = x - so.x;
  4323. sr.y = y - so.y;
  4324. sr.width = sr.height = 1;
  4325. var hits = target.getIntersectionList(sr, null);
  4326. if (hits.length) {
  4327. target = hits[hits.length - 1];
  4328. }
  4329. }
  4330. if (!target) {
  4331. return null;
  4332. }
  4333. return wrap(target);
  4334. };
  4335. /*\
  4336. * Snap.plugin
  4337. [ method ]
  4338. **
  4339. * Let you write plugins. You pass in a function with four arguments, like this:
  4340. | Snap.plugin(function (Snap, Element, Paper, global) {
  4341. | Snap.newmethod = function () {};
  4342. | Element.prototype.newmethod = function () {};
  4343. | Paper.prototype.newmethod = function () {};
  4344. | });
  4345. * Inside the function you have access to all main objects (and their
  4346. * prototypes). This allow you to extend anything you want.
  4347. **
  4348. - f (function) your plugin body
  4349. \*/
  4350. Snap.plugin = function (f) {
  4351. f(Snap, Element, Paper, glob);
  4352. };
  4353. glob.win.Snap = Snap;
  4354. return Snap;
  4355. }());
  4356. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  4357. //
  4358. // Licensed under the Apache License, Version 2.0 (the "License");
  4359. // you may not use this file except in compliance with the License.
  4360. // You may obtain a copy of the License at
  4361. //
  4362. // http://www.apache.org/licenses/LICENSE-2.0
  4363. //
  4364. // Unless required by applicable law or agreed to in writing, software
  4365. // distributed under the License is distributed on an "AS IS" BASIS,
  4366. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4367. // See the License for the specific language governing permissions and
  4368. // limitations under the License.
  4369. Snap.plugin(function (Snap, Element, Paper, glob) {
  4370. var elproto = Element.prototype,
  4371. is = Snap.is,
  4372. clone = Snap._.clone,
  4373. has = "hasOwnProperty",
  4374. p2s = /,?([a-z]),?/gi,
  4375. toFloat = parseFloat,
  4376. math = Math,
  4377. PI = math.PI,
  4378. mmin = math.min,
  4379. mmax = math.max,
  4380. pow = math.pow,
  4381. abs = math.abs;
  4382. function paths(ps) {
  4383. var p = paths.ps = paths.ps || {};
  4384. if (p[ps]) {
  4385. p[ps].sleep = 100;
  4386. } else {
  4387. p[ps] = {
  4388. sleep: 100
  4389. };
  4390. }
  4391. setTimeout(function () {
  4392. for (var key in p) if (p[has](key) && key != ps) {
  4393. p[key].sleep--;
  4394. !p[key].sleep && delete p[key];
  4395. }
  4396. });
  4397. return p[ps];
  4398. }
  4399. function box(x, y, width, height) {
  4400. if (x == null) {
  4401. x = y = width = height = 0;
  4402. }
  4403. if (y == null) {
  4404. y = x.y;
  4405. width = x.width;
  4406. height = x.height;
  4407. x = x.x;
  4408. }
  4409. return {
  4410. x: x,
  4411. y: y,
  4412. width: width,
  4413. w: width,
  4414. height: height,
  4415. h: height,
  4416. x2: x + width,
  4417. y2: y + height,
  4418. cx: x + width / 2,
  4419. cy: y + height / 2,
  4420. r1: math.min(width, height) / 2,
  4421. r2: math.max(width, height) / 2,
  4422. r0: math.sqrt(width * width + height * height) / 2,
  4423. path: rectPath(x, y, width, height),
  4424. vb: [x, y, width, height].join(" ")
  4425. };
  4426. }
  4427. function toString() {
  4428. return this.join(",").replace(p2s, "$1");
  4429. }
  4430. function pathClone(pathArray) {
  4431. var res = clone(pathArray);
  4432. res.toString = toString;
  4433. return res;
  4434. }
  4435. function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
  4436. if (length == null) {
  4437. return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y);
  4438. } else {
  4439. return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y,
  4440. getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length));
  4441. }
  4442. }
  4443. function getLengthFactory(istotal, subpath) {
  4444. function O(val) {
  4445. return +(+val).toFixed(3);
  4446. }
  4447. return Snap._.cacher(function (path, length, onlystart) {
  4448. if (path instanceof Element) {
  4449. path = path.attr("d");
  4450. }
  4451. path = path2curve(path);
  4452. var x, y, p, l, sp = "", subpaths = {}, point,
  4453. len = 0;
  4454. for (var i = 0, ii = path.length; i < ii; i++) {
  4455. p = path[i];
  4456. if (p[0] == "M") {
  4457. x = +p[1];
  4458. y = +p[2];
  4459. } else {
  4460. l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
  4461. if (len + l > length) {
  4462. if (subpath && !subpaths.start) {
  4463. point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
  4464. sp += [
  4465. "C" + O(point.start.x),
  4466. O(point.start.y),
  4467. O(point.m.x),
  4468. O(point.m.y),
  4469. O(point.x),
  4470. O(point.y)
  4471. ];
  4472. if (onlystart) {return sp;}
  4473. subpaths.start = sp;
  4474. sp = [
  4475. "M" + O(point.x),
  4476. O(point.y) + "C" + O(point.n.x),
  4477. O(point.n.y),
  4478. O(point.end.x),
  4479. O(point.end.y),
  4480. O(p[5]),
  4481. O(p[6])
  4482. ].join();
  4483. len += l;
  4484. x = +p[5];
  4485. y = +p[6];
  4486. continue;
  4487. }
  4488. if (!istotal && !subpath) {
  4489. point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
  4490. return point;
  4491. }
  4492. }
  4493. len += l;
  4494. x = +p[5];
  4495. y = +p[6];
  4496. }
  4497. sp += p.shift() + p;
  4498. }
  4499. subpaths.end = sp;
  4500. point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1);
  4501. return point;
  4502. }, null, Snap._.clone);
  4503. }
  4504. var getTotalLength = getLengthFactory(1),
  4505. getPointAtLength = getLengthFactory(),
  4506. getSubpathsAtLength = getLengthFactory(0, 1);
  4507. function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
  4508. var t1 = 1 - t,
  4509. t13 = pow(t1, 3),
  4510. t12 = pow(t1, 2),
  4511. t2 = t * t,
  4512. t3 = t2 * t,
  4513. x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x,
  4514. y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y,
  4515. mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x),
  4516. my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y),
  4517. nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x),
  4518. ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y),
  4519. ax = t1 * p1x + t * c1x,
  4520. ay = t1 * p1y + t * c1y,
  4521. cx = t1 * c2x + t * p2x,
  4522. cy = t1 * c2y + t * p2y,
  4523. alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI);
  4524. // (mx > nx || my < ny) && (alpha += 180);
  4525. return {
  4526. x: x,
  4527. y: y,
  4528. m: {x: mx, y: my},
  4529. n: {x: nx, y: ny},
  4530. start: {x: ax, y: ay},
  4531. end: {x: cx, y: cy},
  4532. alpha: alpha
  4533. };
  4534. }
  4535. function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
  4536. if (!Snap.is(p1x, "array")) {
  4537. p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y];
  4538. }
  4539. var bbox = curveDim.apply(null, p1x);
  4540. return box(
  4541. bbox.min.x,
  4542. bbox.min.y,
  4543. bbox.max.x - bbox.min.x,
  4544. bbox.max.y - bbox.min.y
  4545. );
  4546. }
  4547. function isPointInsideBBox(bbox, x, y) {
  4548. return x >= bbox.x &&
  4549. x <= bbox.x + bbox.width &&
  4550. y >= bbox.y &&
  4551. y <= bbox.y + bbox.height;
  4552. }
  4553. function isBBoxIntersect(bbox1, bbox2) {
  4554. bbox1 = box(bbox1);
  4555. bbox2 = box(bbox2);
  4556. return isPointInsideBBox(bbox2, bbox1.x, bbox1.y)
  4557. || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y)
  4558. || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2)
  4559. || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2)
  4560. || isPointInsideBBox(bbox1, bbox2.x, bbox2.y)
  4561. || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y)
  4562. || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2)
  4563. || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2)
  4564. || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x
  4565. || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x)
  4566. && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y
  4567. || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y);
  4568. }
  4569. function base3(t, p1, p2, p3, p4) {
  4570. var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4,
  4571. t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
  4572. return t * t2 - 3 * p1 + 3 * p2;
  4573. }
  4574. function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) {
  4575. if (z == null) {
  4576. z = 1;
  4577. }
  4578. z = z > 1 ? 1 : z < 0 ? 0 : z;
  4579. var z2 = z / 2,
  4580. n = 12,
  4581. Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],
  4582. Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472],
  4583. sum = 0;
  4584. for (var i = 0; i < n; i++) {
  4585. var ct = z2 * Tvalues[i] + z2,
  4586. xbase = base3(ct, x1, x2, x3, x4),
  4587. ybase = base3(ct, y1, y2, y3, y4),
  4588. comb = xbase * xbase + ybase * ybase;
  4589. sum += Cvalues[i] * math.sqrt(comb);
  4590. }
  4591. return z2 * sum;
  4592. }
  4593. function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) {
  4594. if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) {
  4595. return;
  4596. }
  4597. var t = 1,
  4598. step = t / 2,
  4599. t2 = t - step,
  4600. l,
  4601. e = .01;
  4602. l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
  4603. while (abs(l - ll) > e) {
  4604. step /= 2;
  4605. t2 += (l < ll ? 1 : -1) * step;
  4606. l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2);
  4607. }
  4608. return t2;
  4609. }
  4610. function intersect(x1, y1, x2, y2, x3, y3, x4, y4) {
  4611. if (
  4612. mmax(x1, x2) < mmin(x3, x4) ||
  4613. mmin(x1, x2) > mmax(x3, x4) ||
  4614. mmax(y1, y2) < mmin(y3, y4) ||
  4615. mmin(y1, y2) > mmax(y3, y4)
  4616. ) {
  4617. return;
  4618. }
  4619. var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4),
  4620. ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4),
  4621. denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
  4622. if (!denominator) {
  4623. return;
  4624. }
  4625. var px = nx / denominator,
  4626. py = ny / denominator,
  4627. px2 = +px.toFixed(2),
  4628. py2 = +py.toFixed(2);
  4629. if (
  4630. px2 < +mmin(x1, x2).toFixed(2) ||
  4631. px2 > +mmax(x1, x2).toFixed(2) ||
  4632. px2 < +mmin(x3, x4).toFixed(2) ||
  4633. px2 > +mmax(x3, x4).toFixed(2) ||
  4634. py2 < +mmin(y1, y2).toFixed(2) ||
  4635. py2 > +mmax(y1, y2).toFixed(2) ||
  4636. py2 < +mmin(y3, y4).toFixed(2) ||
  4637. py2 > +mmax(y3, y4).toFixed(2)
  4638. ) {
  4639. return;
  4640. }
  4641. return {x: px, y: py};
  4642. }
  4643. function inter(bez1, bez2) {
  4644. return interHelper(bez1, bez2);
  4645. }
  4646. function interCount(bez1, bez2) {
  4647. return interHelper(bez1, bez2, 1);
  4648. }
  4649. function interHelper(bez1, bez2, justCount) {
  4650. var bbox1 = bezierBBox(bez1),
  4651. bbox2 = bezierBBox(bez2);
  4652. if (!isBBoxIntersect(bbox1, bbox2)) {
  4653. return justCount ? 0 : [];
  4654. }
  4655. var l1 = bezlen.apply(0, bez1),
  4656. l2 = bezlen.apply(0, bez2),
  4657. n1 = ~~(l1 / 5),
  4658. n2 = ~~(l2 / 5),
  4659. dots1 = [],
  4660. dots2 = [],
  4661. xy = {},
  4662. res = justCount ? 0 : [];
  4663. for (var i = 0; i < n1 + 1; i++) {
  4664. var p = findDotsAtSegment.apply(0, bez1.concat(i / n1));
  4665. dots1.push({x: p.x, y: p.y, t: i / n1});
  4666. }
  4667. for (i = 0; i < n2 + 1; i++) {
  4668. p = findDotsAtSegment.apply(0, bez2.concat(i / n2));
  4669. dots2.push({x: p.x, y: p.y, t: i / n2});
  4670. }
  4671. for (i = 0; i < n1; i++) {
  4672. for (var j = 0; j < n2; j++) {
  4673. var di = dots1[i],
  4674. di1 = dots1[i + 1],
  4675. dj = dots2[j],
  4676. dj1 = dots2[j + 1],
  4677. ci = abs(di1.x - di.x) < .001 ? "y" : "x",
  4678. cj = abs(dj1.x - dj.x) < .001 ? "y" : "x",
  4679. is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y);
  4680. if (is) {
  4681. if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) {
  4682. continue;
  4683. }
  4684. xy[is.x.toFixed(4)] = is.y.toFixed(4);
  4685. var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t),
  4686. t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t);
  4687. if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
  4688. if (justCount) {
  4689. res++;
  4690. } else {
  4691. res.push({
  4692. x: is.x,
  4693. y: is.y,
  4694. t1: t1,
  4695. t2: t2
  4696. });
  4697. }
  4698. }
  4699. }
  4700. }
  4701. }
  4702. return res;
  4703. }
  4704. function pathIntersection(path1, path2) {
  4705. return interPathHelper(path1, path2);
  4706. }
  4707. function pathIntersectionNumber(path1, path2) {
  4708. return interPathHelper(path1, path2, 1);
  4709. }
  4710. function interPathHelper(path1, path2, justCount) {
  4711. path1 = path2curve(path1);
  4712. path2 = path2curve(path2);
  4713. var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2,
  4714. res = justCount ? 0 : [];
  4715. for (var i = 0, ii = path1.length; i < ii; i++) {
  4716. var pi = path1[i];
  4717. if (pi[0] == "M") {
  4718. x1 = x1m = pi[1];
  4719. y1 = y1m = pi[2];
  4720. } else {
  4721. if (pi[0] == "C") {
  4722. bez1 = [x1, y1].concat(pi.slice(1));
  4723. x1 = bez1[6];
  4724. y1 = bez1[7];
  4725. } else {
  4726. bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m];
  4727. x1 = x1m;
  4728. y1 = y1m;
  4729. }
  4730. for (var j = 0, jj = path2.length; j < jj; j++) {
  4731. var pj = path2[j];
  4732. if (pj[0] == "M") {
  4733. x2 = x2m = pj[1];
  4734. y2 = y2m = pj[2];
  4735. } else {
  4736. if (pj[0] == "C") {
  4737. bez2 = [x2, y2].concat(pj.slice(1));
  4738. x2 = bez2[6];
  4739. y2 = bez2[7];
  4740. } else {
  4741. bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m];
  4742. x2 = x2m;
  4743. y2 = y2m;
  4744. }
  4745. var intr = interHelper(bez1, bez2, justCount);
  4746. if (justCount) {
  4747. res += intr;
  4748. } else {
  4749. for (var k = 0, kk = intr.length; k < kk; k++) {
  4750. intr[k].segment1 = i;
  4751. intr[k].segment2 = j;
  4752. intr[k].bez1 = bez1;
  4753. intr[k].bez2 = bez2;
  4754. }
  4755. res = res.concat(intr);
  4756. }
  4757. }
  4758. }
  4759. }
  4760. }
  4761. return res;
  4762. }
  4763. function isPointInsidePath(path, x, y) {
  4764. var bbox = pathBBox(path);
  4765. return isPointInsideBBox(bbox, x, y) &&
  4766. interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1;
  4767. }
  4768. function pathBBox(path) {
  4769. var pth = paths(path);
  4770. if (pth.bbox) {
  4771. return clone(pth.bbox);
  4772. }
  4773. if (!path) {
  4774. return box();
  4775. }
  4776. path = path2curve(path);
  4777. var x = 0,
  4778. y = 0,
  4779. X = [],
  4780. Y = [],
  4781. p;
  4782. for (var i = 0, ii = path.length; i < ii; i++) {
  4783. p = path[i];
  4784. if (p[0] == "M") {
  4785. x = p[1];
  4786. y = p[2];
  4787. X.push(x);
  4788. Y.push(y);
  4789. } else {
  4790. var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
  4791. X = X.concat(dim.min.x, dim.max.x);
  4792. Y = Y.concat(dim.min.y, dim.max.y);
  4793. x = p[5];
  4794. y = p[6];
  4795. }
  4796. }
  4797. var xmin = mmin.apply(0, X),
  4798. ymin = mmin.apply(0, Y),
  4799. xmax = mmax.apply(0, X),
  4800. ymax = mmax.apply(0, Y),
  4801. bb = box(xmin, ymin, xmax - xmin, ymax - ymin);
  4802. pth.bbox = clone(bb);
  4803. return bb;
  4804. }
  4805. function rectPath(x, y, w, h, r) {
  4806. if (r) {
  4807. return [
  4808. ["M", x + r, y],
  4809. ["l", w - r * 2, 0],
  4810. ["a", r, r, 0, 0, 1, r, r],
  4811. ["l", 0, h - r * 2],
  4812. ["a", r, r, 0, 0, 1, -r, r],
  4813. ["l", r * 2 - w, 0],
  4814. ["a", r, r, 0, 0, 1, -r, -r],
  4815. ["l", 0, r * 2 - h],
  4816. ["a", r, r, 0, 0, 1, r, -r],
  4817. ["z"]
  4818. ];
  4819. }
  4820. var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
  4821. res.toString = toString;
  4822. return res;
  4823. }
  4824. function ellipsePath(x, y, rx, ry, a) {
  4825. if (a == null && ry == null) {
  4826. ry = rx;
  4827. }
  4828. if (a != null) {
  4829. var rad = Math.PI / 180,
  4830. x1 = x + rx * Math.cos(-ry * rad),
  4831. x2 = x + rx * Math.cos(-a * rad),
  4832. y1 = y + rx * Math.sin(-ry * rad),
  4833. y2 = y + rx * Math.sin(-a * rad),
  4834. res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
  4835. } else {
  4836. res = [
  4837. ["M", x, y],
  4838. ["m", 0, -ry],
  4839. ["a", rx, ry, 0, 1, 1, 0, 2 * ry],
  4840. ["a", rx, ry, 0, 1, 1, 0, -2 * ry],
  4841. ["z"]
  4842. ];
  4843. }
  4844. res.toString = toString;
  4845. return res;
  4846. }
  4847. var unit2px = Snap._unit2px,
  4848. getPath = {
  4849. path: function (el) {
  4850. return el.attr("path");
  4851. },
  4852. circle: function (el) {
  4853. var attr = unit2px(el);
  4854. return ellipsePath(attr.cx, attr.cy, attr.r);
  4855. },
  4856. ellipse: function (el) {
  4857. var attr = unit2px(el);
  4858. return ellipsePath(attr.cx, attr.cy, attr.rx, attr.ry);
  4859. },
  4860. rect: function (el) {
  4861. var attr = unit2px(el);
  4862. return rectPath(attr.x, attr.y, attr.width, attr.height, attr.rx, attr.ry);
  4863. },
  4864. image: function (el) {
  4865. var attr = unit2px(el);
  4866. return rectPath(attr.x, attr.y, attr.width, attr.height);
  4867. },
  4868. text: function (el) {
  4869. var bbox = el.node.getBBox();
  4870. return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  4871. },
  4872. g: function (el) {
  4873. var bbox = el.node.getBBox();
  4874. return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  4875. },
  4876. symbol: function (el) {
  4877. var bbox = el.getBBox();
  4878. return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  4879. },
  4880. line: function (el) {
  4881. return "M" + [el.attr("x1"), el.attr("y1"), el.attr("x2"), el.attr("y2")];
  4882. },
  4883. polyline: function (el) {
  4884. return "M" + el.attr("points");
  4885. },
  4886. polygon: function (el) {
  4887. return "M" + el.attr("points") + "z";
  4888. },
  4889. svg: function (el) {
  4890. var bbox = el.node.getBBox();
  4891. return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  4892. },
  4893. deflt: function (el) {
  4894. var bbox = el.node.getBBox();
  4895. return rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  4896. }
  4897. };
  4898. function pathToRelative(pathArray) {
  4899. var pth = paths(pathArray),
  4900. lowerCase = String.prototype.toLowerCase;
  4901. if (pth.rel) {
  4902. return pathClone(pth.rel);
  4903. }
  4904. if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) {
  4905. pathArray = Snap.parsePathString(pathArray);
  4906. }
  4907. var res = [],
  4908. x = 0,
  4909. y = 0,
  4910. mx = 0,
  4911. my = 0,
  4912. start = 0;
  4913. if (pathArray[0][0] == "M") {
  4914. x = pathArray[0][1];
  4915. y = pathArray[0][2];
  4916. mx = x;
  4917. my = y;
  4918. start++;
  4919. res.push(["M", x, y]);
  4920. }
  4921. for (var i = start, ii = pathArray.length; i < ii; i++) {
  4922. var r = res[i] = [],
  4923. pa = pathArray[i];
  4924. if (pa[0] != lowerCase.call(pa[0])) {
  4925. r[0] = lowerCase.call(pa[0]);
  4926. switch (r[0]) {
  4927. case "a":
  4928. r[1] = pa[1];
  4929. r[2] = pa[2];
  4930. r[3] = pa[3];
  4931. r[4] = pa[4];
  4932. r[5] = pa[5];
  4933. r[6] = +(pa[6] - x).toFixed(3);
  4934. r[7] = +(pa[7] - y).toFixed(3);
  4935. break;
  4936. case "v":
  4937. r[1] = +(pa[1] - y).toFixed(3);
  4938. break;
  4939. case "m":
  4940. mx = pa[1];
  4941. my = pa[2];
  4942. default:
  4943. for (var j = 1, jj = pa.length; j < jj; j++) {
  4944. r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
  4945. }
  4946. }
  4947. } else {
  4948. r = res[i] = [];
  4949. if (pa[0] == "m") {
  4950. mx = pa[1] + x;
  4951. my = pa[2] + y;
  4952. }
  4953. for (var k = 0, kk = pa.length; k < kk; k++) {
  4954. res[i][k] = pa[k];
  4955. }
  4956. }
  4957. var len = res[i].length;
  4958. switch (res[i][0]) {
  4959. case "z":
  4960. x = mx;
  4961. y = my;
  4962. break;
  4963. case "h":
  4964. x += +res[i][len - 1];
  4965. break;
  4966. case "v":
  4967. y += +res[i][len - 1];
  4968. break;
  4969. default:
  4970. x += +res[i][len - 2];
  4971. y += +res[i][len - 1];
  4972. }
  4973. }
  4974. res.toString = toString;
  4975. pth.rel = pathClone(res);
  4976. return res;
  4977. }
  4978. function pathToAbsolute(pathArray) {
  4979. var pth = paths(pathArray);
  4980. if (pth.abs) {
  4981. return pathClone(pth.abs);
  4982. }
  4983. if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption
  4984. pathArray = Snap.parsePathString(pathArray);
  4985. }
  4986. if (!pathArray || !pathArray.length) {
  4987. return [["M", 0, 0]];
  4988. }
  4989. var res = [],
  4990. x = 0,
  4991. y = 0,
  4992. mx = 0,
  4993. my = 0,
  4994. start = 0,
  4995. pa0;
  4996. if (pathArray[0][0] == "M") {
  4997. x = +pathArray[0][1];
  4998. y = +pathArray[0][2];
  4999. mx = x;
  5000. my = y;
  5001. start++;
  5002. res[0] = ["M", x, y];
  5003. }
  5004. var crz = pathArray.length == 3 &&
  5005. pathArray[0][0] == "M" &&
  5006. pathArray[1][0].toUpperCase() == "R" &&
  5007. pathArray[2][0].toUpperCase() == "Z";
  5008. for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
  5009. res.push(r = []);
  5010. pa = pathArray[i];
  5011. pa0 = pa[0];
  5012. if (pa0 != pa0.toUpperCase()) {
  5013. r[0] = pa0.toUpperCase();
  5014. switch (r[0]) {
  5015. case "A":
  5016. r[1] = pa[1];
  5017. r[2] = pa[2];
  5018. r[3] = pa[3];
  5019. r[4] = pa[4];
  5020. r[5] = pa[5];
  5021. r[6] = +(pa[6] + x);
  5022. r[7] = +(pa[7] + y);
  5023. break;
  5024. case "V":
  5025. r[1] = +pa[1] + y;
  5026. break;
  5027. case "H":
  5028. r[1] = +pa[1] + x;
  5029. break;
  5030. case "R":
  5031. var dots = [x, y].concat(pa.slice(1));
  5032. for (var j = 2, jj = dots.length; j < jj; j++) {
  5033. dots[j] = +dots[j] + x;
  5034. dots[++j] = +dots[j] + y;
  5035. }
  5036. res.pop();
  5037. res = res.concat(catmullRom2bezier(dots, crz));
  5038. break;
  5039. case "O":
  5040. res.pop();
  5041. dots = ellipsePath(x, y, pa[1], pa[2]);
  5042. dots.push(dots[0]);
  5043. res = res.concat(dots);
  5044. break;
  5045. case "U":
  5046. res.pop();
  5047. res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
  5048. r = ["U"].concat(res[res.length - 1].slice(-2));
  5049. break;
  5050. case "M":
  5051. mx = +pa[1] + x;
  5052. my = +pa[2] + y;
  5053. default:
  5054. for (j = 1, jj = pa.length; j < jj; j++) {
  5055. r[j] = +pa[j] + ((j % 2) ? x : y);
  5056. }
  5057. }
  5058. } else if (pa0 == "R") {
  5059. dots = [x, y].concat(pa.slice(1));
  5060. res.pop();
  5061. res = res.concat(catmullRom2bezier(dots, crz));
  5062. r = ["R"].concat(pa.slice(-2));
  5063. } else if (pa0 == "O") {
  5064. res.pop();
  5065. dots = ellipsePath(x, y, pa[1], pa[2]);
  5066. dots.push(dots[0]);
  5067. res = res.concat(dots);
  5068. } else if (pa0 == "U") {
  5069. res.pop();
  5070. res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
  5071. r = ["U"].concat(res[res.length - 1].slice(-2));
  5072. } else {
  5073. for (var k = 0, kk = pa.length; k < kk; k++) {
  5074. r[k] = pa[k];
  5075. }
  5076. }
  5077. pa0 = pa0.toUpperCase();
  5078. if (pa0 != "O") {
  5079. switch (r[0]) {
  5080. case "Z":
  5081. x = mx;
  5082. y = my;
  5083. break;
  5084. case "H":
  5085. x = r[1];
  5086. break;
  5087. case "V":
  5088. y = r[1];
  5089. break;
  5090. case "M":
  5091. mx = r[r.length - 2];
  5092. my = r[r.length - 1];
  5093. default:
  5094. x = r[r.length - 2];
  5095. y = r[r.length - 1];
  5096. }
  5097. }
  5098. }
  5099. res.toString = toString;
  5100. pth.abs = pathClone(res);
  5101. return res;
  5102. }
  5103. function l2c(x1, y1, x2, y2) {
  5104. return [x1, y1, x2, y2, x2, y2];
  5105. }
  5106. function q2c(x1, y1, ax, ay, x2, y2) {
  5107. var _13 = 1 / 3,
  5108. _23 = 2 / 3;
  5109. return [
  5110. _13 * x1 + _23 * ax,
  5111. _13 * y1 + _23 * ay,
  5112. _13 * x2 + _23 * ax,
  5113. _13 * y2 + _23 * ay,
  5114. x2,
  5115. y2
  5116. ];
  5117. }
  5118. function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
  5119. // for more information of where this math came from visit:
  5120. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
  5121. var _120 = PI * 120 / 180,
  5122. rad = PI / 180 * (+angle || 0),
  5123. res = [],
  5124. xy,
  5125. rotate = Snap._.cacher(function (x, y, rad) {
  5126. var X = x * math.cos(rad) - y * math.sin(rad),
  5127. Y = x * math.sin(rad) + y * math.cos(rad);
  5128. return {x: X, y: Y};
  5129. });
  5130. if (!recursive) {
  5131. xy = rotate(x1, y1, -rad);
  5132. x1 = xy.x;
  5133. y1 = xy.y;
  5134. xy = rotate(x2, y2, -rad);
  5135. x2 = xy.x;
  5136. y2 = xy.y;
  5137. var cos = math.cos(PI / 180 * angle),
  5138. sin = math.sin(PI / 180 * angle),
  5139. x = (x1 - x2) / 2,
  5140. y = (y1 - y2) / 2;
  5141. var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
  5142. if (h > 1) {
  5143. h = math.sqrt(h);
  5144. rx = h * rx;
  5145. ry = h * ry;
  5146. }
  5147. var rx2 = rx * rx,
  5148. ry2 = ry * ry,
  5149. k = (large_arc_flag == sweep_flag ? -1 : 1) *
  5150. math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
  5151. cx = k * rx * y / ry + (x1 + x2) / 2,
  5152. cy = k * -ry * x / rx + (y1 + y2) / 2,
  5153. f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
  5154. f2 = math.asin(((y2 - cy) / ry).toFixed(9));
  5155. f1 = x1 < cx ? PI - f1 : f1;
  5156. f2 = x2 < cx ? PI - f2 : f2;
  5157. f1 < 0 && (f1 = PI * 2 + f1);
  5158. f2 < 0 && (f2 = PI * 2 + f2);
  5159. if (sweep_flag && f1 > f2) {
  5160. f1 = f1 - PI * 2;
  5161. }
  5162. if (!sweep_flag && f2 > f1) {
  5163. f2 = f2 - PI * 2;
  5164. }
  5165. } else {
  5166. f1 = recursive[0];
  5167. f2 = recursive[1];
  5168. cx = recursive[2];
  5169. cy = recursive[3];
  5170. }
  5171. var df = f2 - f1;
  5172. if (abs(df) > _120) {
  5173. var f2old = f2,
  5174. x2old = x2,
  5175. y2old = y2;
  5176. f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
  5177. x2 = cx + rx * math.cos(f2);
  5178. y2 = cy + ry * math.sin(f2);
  5179. res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
  5180. }
  5181. df = f2 - f1;
  5182. var c1 = math.cos(f1),
  5183. s1 = math.sin(f1),
  5184. c2 = math.cos(f2),
  5185. s2 = math.sin(f2),
  5186. t = math.tan(df / 4),
  5187. hx = 4 / 3 * rx * t,
  5188. hy = 4 / 3 * ry * t,
  5189. m1 = [x1, y1],
  5190. m2 = [x1 + hx * s1, y1 - hy * c1],
  5191. m3 = [x2 + hx * s2, y2 - hy * c2],
  5192. m4 = [x2, y2];
  5193. m2[0] = 2 * m1[0] - m2[0];
  5194. m2[1] = 2 * m1[1] - m2[1];
  5195. if (recursive) {
  5196. return [m2, m3, m4].concat(res);
  5197. } else {
  5198. res = [m2, m3, m4].concat(res).join().split(",");
  5199. var newres = [];
  5200. for (var i = 0, ii = res.length; i < ii; i++) {
  5201. newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
  5202. }
  5203. return newres;
  5204. }
  5205. }
  5206. function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
  5207. var t1 = 1 - t;
  5208. return {
  5209. x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
  5210. y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
  5211. };
  5212. }
  5213. function curveDim(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
  5214. var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
  5215. b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
  5216. c = p1x - c1x,
  5217. t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
  5218. t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
  5219. y = [p1y, p2y],
  5220. x = [p1x, p2x],
  5221. dot;
  5222. abs(t1) > "1e12" && (t1 = .5);
  5223. abs(t2) > "1e12" && (t2 = .5);
  5224. if (t1 > 0 && t1 < 1) {
  5225. dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
  5226. x.push(dot.x);
  5227. y.push(dot.y);
  5228. }
  5229. if (t2 > 0 && t2 < 1) {
  5230. dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
  5231. x.push(dot.x);
  5232. y.push(dot.y);
  5233. }
  5234. a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
  5235. b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
  5236. c = p1y - c1y;
  5237. t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
  5238. t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
  5239. abs(t1) > "1e12" && (t1 = .5);
  5240. abs(t2) > "1e12" && (t2 = .5);
  5241. if (t1 > 0 && t1 < 1) {
  5242. dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
  5243. x.push(dot.x);
  5244. y.push(dot.y);
  5245. }
  5246. if (t2 > 0 && t2 < 1) {
  5247. dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
  5248. x.push(dot.x);
  5249. y.push(dot.y);
  5250. }
  5251. return {
  5252. min: {x: mmin.apply(0, x), y: mmin.apply(0, y)},
  5253. max: {x: mmax.apply(0, x), y: mmax.apply(0, y)}
  5254. };
  5255. }
  5256. function path2curve(path, path2) {
  5257. var pth = !path2 && paths(path);
  5258. if (!path2 && pth.curve) {
  5259. return pathClone(pth.curve);
  5260. }
  5261. var p = pathToAbsolute(path),
  5262. p2 = path2 && pathToAbsolute(path2),
  5263. attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
  5264. attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
  5265. processPath = function (path, d) {
  5266. var nx, ny;
  5267. if (!path) {
  5268. return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
  5269. }
  5270. !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
  5271. switch (path[0]) {
  5272. case "M":
  5273. d.X = path[1];
  5274. d.Y = path[2];
  5275. break;
  5276. case "A":
  5277. path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
  5278. break;
  5279. case "S":
  5280. nx = d.x + (d.x - (d.bx || d.x));
  5281. ny = d.y + (d.y - (d.by || d.y));
  5282. path = ["C", nx, ny].concat(path.slice(1));
  5283. break;
  5284. case "T":
  5285. d.qx = d.x + (d.x - (d.qx || d.x));
  5286. d.qy = d.y + (d.y - (d.qy || d.y));
  5287. path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
  5288. break;
  5289. case "Q":
  5290. d.qx = path[1];
  5291. d.qy = path[2];
  5292. path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
  5293. break;
  5294. case "L":
  5295. path = ["C"].concat(l2c(d.x, d.y, path[1], path[2]));
  5296. break;
  5297. case "H":
  5298. path = ["C"].concat(l2c(d.x, d.y, path[1], d.y));
  5299. break;
  5300. case "V":
  5301. path = ["C"].concat(l2c(d.x, d.y, d.x, path[1]));
  5302. break;
  5303. case "Z":
  5304. path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
  5305. break;
  5306. }
  5307. return path;
  5308. },
  5309. fixArc = function (pp, i) {
  5310. if (pp[i].length > 7) {
  5311. pp[i].shift();
  5312. var pi = pp[i];
  5313. while (pi.length) {
  5314. pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
  5315. }
  5316. pp.splice(i, 1);
  5317. ii = mmax(p.length, p2 && p2.length || 0);
  5318. }
  5319. },
  5320. fixM = function (path1, path2, a1, a2, i) {
  5321. if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
  5322. path2.splice(i, 0, ["M", a2.x, a2.y]);
  5323. a1.bx = 0;
  5324. a1.by = 0;
  5325. a1.x = path1[i][1];
  5326. a1.y = path1[i][2];
  5327. ii = mmax(p.length, p2 && p2.length || 0);
  5328. }
  5329. };
  5330. for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
  5331. p[i] = processPath(p[i], attrs);
  5332. fixArc(p, i);
  5333. p2 && (p2[i] = processPath(p2[i], attrs2));
  5334. p2 && fixArc(p2, i);
  5335. fixM(p, p2, attrs, attrs2, i);
  5336. fixM(p2, p, attrs2, attrs, i);
  5337. var seg = p[i],
  5338. seg2 = p2 && p2[i],
  5339. seglen = seg.length,
  5340. seg2len = p2 && seg2.length;
  5341. attrs.x = seg[seglen - 2];
  5342. attrs.y = seg[seglen - 1];
  5343. attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
  5344. attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
  5345. attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
  5346. attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
  5347. attrs2.x = p2 && seg2[seg2len - 2];
  5348. attrs2.y = p2 && seg2[seg2len - 1];
  5349. }
  5350. if (!p2) {
  5351. pth.curve = pathClone(p);
  5352. }
  5353. return p2 ? [p, p2] : p;
  5354. }
  5355. function mapPath(path, matrix) {
  5356. if (!matrix) {
  5357. return path;
  5358. }
  5359. var x, y, i, j, ii, jj, pathi;
  5360. path = path2curve(path);
  5361. for (i = 0, ii = path.length; i < ii; i++) {
  5362. pathi = path[i];
  5363. for (j = 1, jj = pathi.length; j < jj; j += 2) {
  5364. x = matrix.x(pathi[j], pathi[j + 1]);
  5365. y = matrix.y(pathi[j], pathi[j + 1]);
  5366. pathi[j] = x;
  5367. pathi[j + 1] = y;
  5368. }
  5369. }
  5370. return path;
  5371. }
  5372. // http://schepers.cc/getting-to-the-point
  5373. function catmullRom2bezier(crp, z) {
  5374. var d = [];
  5375. for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
  5376. var p = [
  5377. {x: +crp[i - 2], y: +crp[i - 1]},
  5378. {x: +crp[i], y: +crp[i + 1]},
  5379. {x: +crp[i + 2], y: +crp[i + 3]},
  5380. {x: +crp[i + 4], y: +crp[i + 5]}
  5381. ];
  5382. if (z) {
  5383. if (!i) {
  5384. p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
  5385. } else if (iLen - 4 == i) {
  5386. p[3] = {x: +crp[0], y: +crp[1]};
  5387. } else if (iLen - 2 == i) {
  5388. p[2] = {x: +crp[0], y: +crp[1]};
  5389. p[3] = {x: +crp[2], y: +crp[3]};
  5390. }
  5391. } else {
  5392. if (iLen - 4 == i) {
  5393. p[3] = p[2];
  5394. } else if (!i) {
  5395. p[0] = {x: +crp[i], y: +crp[i + 1]};
  5396. }
  5397. }
  5398. d.push(["C",
  5399. (-p[0].x + 6 * p[1].x + p[2].x) / 6,
  5400. (-p[0].y + 6 * p[1].y + p[2].y) / 6,
  5401. (p[1].x + 6 * p[2].x - p[3].x) / 6,
  5402. (p[1].y + 6*p[2].y - p[3].y) / 6,
  5403. p[2].x,
  5404. p[2].y
  5405. ]);
  5406. }
  5407. return d;
  5408. }
  5409. // export
  5410. Snap.path = paths;
  5411. /*\
  5412. * Snap.path.getTotalLength
  5413. [ method ]
  5414. **
  5415. * Returns the length of the given path in pixels
  5416. **
  5417. - path (string) SVG path string
  5418. **
  5419. = (number) length
  5420. \*/
  5421. Snap.path.getTotalLength = getTotalLength;
  5422. /*\
  5423. * Snap.path.getPointAtLength
  5424. [ method ]
  5425. **
  5426. * Returns the coordinates of the point located at the given length along the given path
  5427. **
  5428. - path (string) SVG path string
  5429. - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
  5430. **
  5431. = (object) representation of the point:
  5432. o {
  5433. o x: (number) x coordinate,
  5434. o y: (number) y coordinate,
  5435. o alpha: (number) angle of derivative
  5436. o }
  5437. \*/
  5438. Snap.path.getPointAtLength = getPointAtLength;
  5439. /*\
  5440. * Snap.path.getSubpath
  5441. [ method ]
  5442. **
  5443. * Returns the subpath of a given path between given start and end lengths
  5444. **
  5445. - path (string) SVG path string
  5446. - from (number) length, in pixels, from the start of the path to the start of the segment
  5447. - to (number) length, in pixels, from the start of the path to the end of the segment
  5448. **
  5449. = (string) path string definition for the segment
  5450. \*/
  5451. Snap.path.getSubpath = function (path, from, to) {
  5452. if (this.getTotalLength(path) - to < 1e-6) {
  5453. return getSubpathsAtLength(path, from).end;
  5454. }
  5455. var a = getSubpathsAtLength(path, to, 1);
  5456. return from ? getSubpathsAtLength(a, from).end : a;
  5457. };
  5458. /*\
  5459. * Element.getTotalLength
  5460. [ method ]
  5461. **
  5462. * Returns the length of the path in pixels (only works for `path` elements)
  5463. = (number) length
  5464. \*/
  5465. elproto.getTotalLength = function () {
  5466. if (this.node.getTotalLength) {
  5467. return this.node.getTotalLength();
  5468. }
  5469. };
  5470. // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length?
  5471. /*\
  5472. * Element.getPointAtLength
  5473. [ method ]
  5474. **
  5475. * Returns coordinates of the point located at the given length on the given path (only works for `path` elements)
  5476. **
  5477. - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps
  5478. **
  5479. = (object) representation of the point:
  5480. o {
  5481. o x: (number) x coordinate,
  5482. o y: (number) y coordinate,
  5483. o alpha: (number) angle of derivative
  5484. o }
  5485. \*/
  5486. elproto.getPointAtLength = function (length) {
  5487. return getPointAtLength(this.attr("d"), length);
  5488. };
  5489. // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear.
  5490. /*\
  5491. * Element.getSubpath
  5492. [ method ]
  5493. **
  5494. * Returns subpath of a given element from given start and end lengths (only works for `path` elements)
  5495. **
  5496. - from (number) length, in pixels, from the start of the path to the start of the segment
  5497. - to (number) length, in pixels, from the start of the path to the end of the segment
  5498. **
  5499. = (string) path string definition for the segment
  5500. \*/
  5501. elproto.getSubpath = function (from, to) {
  5502. return Snap.path.getSubpath(this.attr("d"), from, to);
  5503. };
  5504. Snap._.box = box;
  5505. /*\
  5506. * Snap.path.findDotsAtSegment
  5507. [ method ]
  5508. **
  5509. * Utility method
  5510. **
  5511. * Finds dot coordinates on the given cubic beziér curve at the given t
  5512. - p1x (number) x of the first point of the curve
  5513. - p1y (number) y of the first point of the curve
  5514. - c1x (number) x of the first anchor of the curve
  5515. - c1y (number) y of the first anchor of the curve
  5516. - c2x (number) x of the second anchor of the curve
  5517. - c2y (number) y of the second anchor of the curve
  5518. - p2x (number) x of the second point of the curve
  5519. - p2y (number) y of the second point of the curve
  5520. - t (number) position on the curve (0..1)
  5521. = (object) point information in format:
  5522. o {
  5523. o x: (number) x coordinate of the point,
  5524. o y: (number) y coordinate of the point,
  5525. o m: {
  5526. o x: (number) x coordinate of the left anchor,
  5527. o y: (number) y coordinate of the left anchor
  5528. o },
  5529. o n: {
  5530. o x: (number) x coordinate of the right anchor,
  5531. o y: (number) y coordinate of the right anchor
  5532. o },
  5533. o start: {
  5534. o x: (number) x coordinate of the start of the curve,
  5535. o y: (number) y coordinate of the start of the curve
  5536. o },
  5537. o end: {
  5538. o x: (number) x coordinate of the end of the curve,
  5539. o y: (number) y coordinate of the end of the curve
  5540. o },
  5541. o alpha: (number) angle of the curve derivative at the point
  5542. o }
  5543. \*/
  5544. Snap.path.findDotsAtSegment = findDotsAtSegment;
  5545. /*\
  5546. * Snap.path.bezierBBox
  5547. [ method ]
  5548. **
  5549. * Utility method
  5550. **
  5551. * Returns the bounding box of a given cubic beziér curve
  5552. - p1x (number) x of the first point of the curve
  5553. - p1y (number) y of the first point of the curve
  5554. - c1x (number) x of the first anchor of the curve
  5555. - c1y (number) y of the first anchor of the curve
  5556. - c2x (number) x of the second anchor of the curve
  5557. - c2y (number) y of the second anchor of the curve
  5558. - p2x (number) x of the second point of the curve
  5559. - p2y (number) y of the second point of the curve
  5560. * or
  5561. - bez (array) array of six points for beziér curve
  5562. = (object) bounding box
  5563. o {
  5564. o x: (number) x coordinate of the left top point of the box,
  5565. o y: (number) y coordinate of the left top point of the box,
  5566. o x2: (number) x coordinate of the right bottom point of the box,
  5567. o y2: (number) y coordinate of the right bottom point of the box,
  5568. o width: (number) width of the box,
  5569. o height: (number) height of the box
  5570. o }
  5571. \*/
  5572. Snap.path.bezierBBox = bezierBBox;
  5573. /*\
  5574. * Snap.path.isPointInsideBBox
  5575. [ method ]
  5576. **
  5577. * Utility method
  5578. **
  5579. * Returns `true` if given point is inside bounding box
  5580. - bbox (string) bounding box
  5581. - x (string) x coordinate of the point
  5582. - y (string) y coordinate of the point
  5583. = (boolean) `true` if point is inside
  5584. \*/
  5585. Snap.path.isPointInsideBBox = isPointInsideBBox;
  5586. /*\
  5587. * Snap.path.isBBoxIntersect
  5588. [ method ]
  5589. **
  5590. * Utility method
  5591. **
  5592. * Returns `true` if two bounding boxes intersect
  5593. - bbox1 (string) first bounding box
  5594. - bbox2 (string) second bounding box
  5595. = (boolean) `true` if bounding boxes intersect
  5596. \*/
  5597. Snap.path.isBBoxIntersect = isBBoxIntersect;
  5598. /*\
  5599. * Snap.path.intersection
  5600. [ method ]
  5601. **
  5602. * Utility method
  5603. **
  5604. * Finds intersections of two paths
  5605. - path1 (string) path string
  5606. - path2 (string) path string
  5607. = (array) dots of intersection
  5608. o [
  5609. o {
  5610. o x: (number) x coordinate of the point,
  5611. o y: (number) y coordinate of the point,
  5612. o t1: (number) t value for segment of path1,
  5613. o t2: (number) t value for segment of path2,
  5614. o segment1: (number) order number for segment of path1,
  5615. o segment2: (number) order number for segment of path2,
  5616. o bez1: (array) eight coordinates representing beziér curve for the segment of path1,
  5617. o bez2: (array) eight coordinates representing beziér curve for the segment of path2
  5618. o }
  5619. o ]
  5620. \*/
  5621. Snap.path.intersection = pathIntersection;
  5622. Snap.path.intersectionNumber = pathIntersectionNumber;
  5623. /*\
  5624. * Snap.path.isPointInside
  5625. [ method ]
  5626. **
  5627. * Utility method
  5628. **
  5629. * Returns `true` if given point is inside a given closed path.
  5630. *
  5631. * Note: fill mode doesn’t affect the result of this method.
  5632. - path (string) path string
  5633. - x (number) x of the point
  5634. - y (number) y of the point
  5635. = (boolean) `true` if point is inside the path
  5636. \*/
  5637. Snap.path.isPointInside = isPointInsidePath;
  5638. /*\
  5639. * Snap.path.getBBox
  5640. [ method ]
  5641. **
  5642. * Utility method
  5643. **
  5644. * Returns the bounding box of a given path
  5645. - path (string) path string
  5646. = (object) bounding box
  5647. o {
  5648. o x: (number) x coordinate of the left top point of the box,
  5649. o y: (number) y coordinate of the left top point of the box,
  5650. o x2: (number) x coordinate of the right bottom point of the box,
  5651. o y2: (number) y coordinate of the right bottom point of the box,
  5652. o width: (number) width of the box,
  5653. o height: (number) height of the box
  5654. o }
  5655. \*/
  5656. Snap.path.getBBox = pathBBox;
  5657. Snap.path.get = getPath;
  5658. /*\
  5659. * Snap.path.toRelative
  5660. [ method ]
  5661. **
  5662. * Utility method
  5663. **
  5664. * Converts path coordinates into relative values
  5665. - path (string) path string
  5666. = (array) path string
  5667. \*/
  5668. Snap.path.toRelative = pathToRelative;
  5669. /*\
  5670. * Snap.path.toAbsolute
  5671. [ method ]
  5672. **
  5673. * Utility method
  5674. **
  5675. * Converts path coordinates into absolute values
  5676. - path (string) path string
  5677. = (array) path string
  5678. \*/
  5679. Snap.path.toAbsolute = pathToAbsolute;
  5680. /*\
  5681. * Snap.path.toCubic
  5682. [ method ]
  5683. **
  5684. * Utility method
  5685. **
  5686. * Converts path to a new path where all segments are cubic beziér curves
  5687. - pathString (string|array) path string or array of segments
  5688. = (array) array of segments
  5689. \*/
  5690. Snap.path.toCubic = path2curve;
  5691. /*\
  5692. * Snap.path.map
  5693. [ method ]
  5694. **
  5695. * Transform the path string with the given matrix
  5696. - path (string) path string
  5697. - matrix (object) see @Matrix
  5698. = (string) transformed path string
  5699. \*/
  5700. Snap.path.map = mapPath;
  5701. Snap.path.toString = toString;
  5702. Snap.path.clone = pathClone;
  5703. });
  5704. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  5705. //
  5706. // Licensed under the Apache License, Version 2.0 (the "License");
  5707. // you may not use this file except in compliance with the License.
  5708. // You may obtain a copy of the License at
  5709. //
  5710. // http://www.apache.org/licenses/LICENSE-2.0
  5711. //
  5712. // Unless required by applicable law or agreed to in writing, software
  5713. // distributed under the License is distributed on an "AS IS" BASIS,
  5714. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5715. // See the License for the specific language governing permissions and
  5716. // limitations under the License.
  5717. Snap.plugin(function (Snap, Element, Paper, glob) {
  5718. var mmax = Math.max,
  5719. mmin = Math.min;
  5720. // Set
  5721. var Set = function (items) {
  5722. this.items = [];
  5723. this.length = 0;
  5724. this.type = "set";
  5725. if (items) {
  5726. for (var i = 0, ii = items.length; i < ii; i++) {
  5727. if (items[i]) {
  5728. this[this.items.length] = this.items[this.items.length] = items[i];
  5729. this.length++;
  5730. }
  5731. }
  5732. }
  5733. },
  5734. setproto = Set.prototype;
  5735. /*\
  5736. * Set.push
  5737. [ method ]
  5738. **
  5739. * Adds each argument to the current set
  5740. = (object) original element
  5741. \*/
  5742. setproto.push = function () {
  5743. var item,
  5744. len;
  5745. for (var i = 0, ii = arguments.length; i < ii; i++) {
  5746. item = arguments[i];
  5747. if (item) {
  5748. len = this.items.length;
  5749. this[len] = this.items[len] = item;
  5750. this.length++;
  5751. }
  5752. }
  5753. return this;
  5754. };
  5755. /*\
  5756. * Set.pop
  5757. [ method ]
  5758. **
  5759. * Removes last element and returns it
  5760. = (object) element
  5761. \*/
  5762. setproto.pop = function () {
  5763. this.length && delete this[this.length--];
  5764. return this.items.pop();
  5765. };
  5766. /*\
  5767. * Set.forEach
  5768. [ method ]
  5769. **
  5770. * Executes given function for each element in the set
  5771. *
  5772. * If the function returns `false`, the loop stops running.
  5773. **
  5774. - callback (function) function to run
  5775. - thisArg (object) context object for the callback
  5776. = (object) Set object
  5777. \*/
  5778. setproto.forEach = function (callback, thisArg) {
  5779. for (var i = 0, ii = this.items.length; i < ii; i++) {
  5780. if (callback.call(thisArg, this.items[i], i) === false) {
  5781. return this;
  5782. }
  5783. }
  5784. return this;
  5785. };
  5786. setproto.remove = function () {
  5787. while (this.length) {
  5788. this.pop().remove();
  5789. }
  5790. return this;
  5791. };
  5792. setproto.attr = function (value) {
  5793. for (var i = 0, ii = this.items.length; i < ii; i++) {
  5794. this.items[i].attr(value);
  5795. }
  5796. return this;
  5797. };
  5798. /*\
  5799. * Set.clear
  5800. [ method ]
  5801. **
  5802. * Removes all elements from the set
  5803. \*/
  5804. setproto.clear = function () {
  5805. while (this.length) {
  5806. this.pop();
  5807. }
  5808. };
  5809. /*\
  5810. * Set.splice
  5811. [ method ]
  5812. **
  5813. * Removes range of elements from the set
  5814. **
  5815. - index (number) position of the deletion
  5816. - count (number) number of element to remove
  5817. - insertion… (object) #optional elements to insert
  5818. = (object) set elements that were deleted
  5819. \*/
  5820. setproto.splice = function (index, count, insertion) {
  5821. index = index < 0 ? mmax(this.length + index, 0) : index;
  5822. count = mmax(0, mmin(this.length - index, count));
  5823. var tail = [],
  5824. todel = [],
  5825. args = [],
  5826. i;
  5827. for (i = 2; i < arguments.length; i++) {
  5828. args.push(arguments[i]);
  5829. }
  5830. for (i = 0; i < count; i++) {
  5831. todel.push(this[index + i]);
  5832. }
  5833. for (; i < this.length - index; i++) {
  5834. tail.push(this[index + i]);
  5835. }
  5836. var arglen = args.length;
  5837. for (i = 0; i < arglen + tail.length; i++) {
  5838. this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen];
  5839. }
  5840. i = this.items.length = this.length -= count - arglen;
  5841. while (this[i]) {
  5842. delete this[i++];
  5843. }
  5844. return new Set(todel);
  5845. };
  5846. /*\
  5847. * Set.exclude
  5848. [ method ]
  5849. **
  5850. * Removes given element from the set
  5851. **
  5852. - element (object) element to remove
  5853. = (boolean) `true` if object was found and removed from the set
  5854. \*/
  5855. setproto.exclude = function (el) {
  5856. for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
  5857. this.splice(i, 1);
  5858. return true;
  5859. }
  5860. return false;
  5861. };
  5862. setproto.insertAfter = function (el) {
  5863. var i = this.items.length;
  5864. while (i--) {
  5865. this.items[i].insertAfter(el);
  5866. }
  5867. return this;
  5868. };
  5869. setproto.getBBox = function () {
  5870. var x = [],
  5871. y = [],
  5872. x2 = [],
  5873. y2 = [];
  5874. for (var i = this.items.length; i--;) if (!this.items[i].removed) {
  5875. var box = this.items[i].getBBox();
  5876. x.push(box.x);
  5877. y.push(box.y);
  5878. x2.push(box.x + box.width);
  5879. y2.push(box.y + box.height);
  5880. }
  5881. x = mmin.apply(0, x);
  5882. y = mmin.apply(0, y);
  5883. x2 = mmax.apply(0, x2);
  5884. y2 = mmax.apply(0, y2);
  5885. return {
  5886. x: x,
  5887. y: y,
  5888. x2: x2,
  5889. y2: y2,
  5890. width: x2 - x,
  5891. height: y2 - y,
  5892. cx: x + (x2 - x) / 2,
  5893. cy: y + (y2 - y) / 2
  5894. };
  5895. };
  5896. setproto.clone = function (s) {
  5897. s = new Set;
  5898. for (var i = 0, ii = this.items.length; i < ii; i++) {
  5899. s.push(this.items[i].clone());
  5900. }
  5901. return s;
  5902. };
  5903. setproto.toString = function () {
  5904. return "Snap\u2018s set";
  5905. };
  5906. setproto.type = "set";
  5907. // export
  5908. Snap.set = function () {
  5909. var set = new Set;
  5910. if (arguments.length) {
  5911. set.push.apply(set, Array.prototype.slice.call(arguments, 0));
  5912. }
  5913. return set;
  5914. };
  5915. });
  5916. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  5917. //
  5918. // Licensed under the Apache License, Version 2.0 (the "License");
  5919. // you may not use this file except in compliance with the License.
  5920. // You may obtain a copy of the License at
  5921. //
  5922. // http://www.apache.org/licenses/LICENSE-2.0
  5923. //
  5924. // Unless required by applicable law or agreed to in writing, software
  5925. // distributed under the License is distributed on an "AS IS" BASIS,
  5926. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5927. // See the License for the specific language governing permissions and
  5928. // limitations under the License.
  5929. Snap.plugin(function (Snap, Element, Paper, glob) {
  5930. var names = {},
  5931. reUnit = /[a-z]+$/i,
  5932. Str = String;
  5933. names.stroke = names.fill = "colour";
  5934. function getEmpty(item) {
  5935. var l = item[0];
  5936. switch (l.toLowerCase()) {
  5937. case "t": return [l, 0, 0];
  5938. case "m": return [l, 1, 0, 0, 1, 0, 0];
  5939. case "r": if (item.length == 4) {
  5940. return [l, 0, item[2], item[3]];
  5941. } else {
  5942. return [l, 0];
  5943. }
  5944. case "s": if (item.length == 5) {
  5945. return [l, 1, 1, item[3], item[4]];
  5946. } else if (item.length == 3) {
  5947. return [l, 1, 1];
  5948. } else {
  5949. return [l, 1];
  5950. }
  5951. }
  5952. }
  5953. function equaliseTransform(t1, t2, getBBox) {
  5954. t2 = Str(t2).replace(/\.{3}|\u2026/g, t1);
  5955. t1 = Snap.parseTransformString(t1) || [];
  5956. t2 = Snap.parseTransformString(t2) || [];
  5957. var maxlength = Math.max(t1.length, t2.length),
  5958. from = [],
  5959. to = [],
  5960. i = 0, j, jj,
  5961. tt1, tt2;
  5962. for (; i < maxlength; i++) {
  5963. tt1 = t1[i] || getEmpty(t2[i]);
  5964. tt2 = t2[i] || getEmpty(tt1);
  5965. if ((tt1[0] != tt2[0]) ||
  5966. (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) ||
  5967. (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4]))
  5968. ) {
  5969. t1 = Snap._.transform2matrix(t1, getBBox());
  5970. t2 = Snap._.transform2matrix(t2, getBBox());
  5971. from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]];
  5972. to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]];
  5973. break;
  5974. }
  5975. from[i] = [];
  5976. to[i] = [];
  5977. for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) {
  5978. j in tt1 && (from[i][j] = tt1[j]);
  5979. j in tt2 && (to[i][j] = tt2[j]);
  5980. }
  5981. }
  5982. return {
  5983. from: path2array(from),
  5984. to: path2array(to),
  5985. f: getPath(from)
  5986. };
  5987. }
  5988. function getNumber(val) {
  5989. return val;
  5990. }
  5991. function getUnit(unit) {
  5992. return function (val) {
  5993. return +val.toFixed(3) + unit;
  5994. };
  5995. }
  5996. function getColour(clr) {
  5997. return Snap.rgb(clr[0], clr[1], clr[2]);
  5998. }
  5999. function getPath(path) {
  6000. var k = 0, i, ii, j, jj, out, a, b = [];
  6001. for (i = 0, ii = path.length; i < ii; i++) {
  6002. out = "[";
  6003. a = ['"' + path[i][0] + '"'];
  6004. for (j = 1, jj = path[i].length; j < jj; j++) {
  6005. a[j] = "val[" + (k++) + "]";
  6006. }
  6007. out += a + "]";
  6008. b[i] = out;
  6009. }
  6010. return Function("val", "return Snap.path.toString.call([" + b + "])");
  6011. }
  6012. function path2array(path) {
  6013. var out = [];
  6014. for (var i = 0, ii = path.length; i < ii; i++) {
  6015. for (var j = 1, jj = path[i].length; j < jj; j++) {
  6016. out.push(path[i][j]);
  6017. }
  6018. }
  6019. return out;
  6020. }
  6021. Element.prototype.equal = function (name, b) {
  6022. var A, B, a = Str(this.attr(name) || ""),
  6023. el = this;
  6024. if (a == +a && b == +b) {
  6025. return {
  6026. from: +a,
  6027. to: +b,
  6028. f: getNumber
  6029. };
  6030. }
  6031. if (names[name] == "colour") {
  6032. A = Snap.color(a);
  6033. B = Snap.color(b);
  6034. return {
  6035. from: [A.r, A.g, A.b, A.opacity],
  6036. to: [B.r, B.g, B.b, B.opacity],
  6037. f: getColour
  6038. };
  6039. }
  6040. if (name == "transform" || name == "gradientTransform" || name == "patternTransform") {
  6041. if (b instanceof Snap.Matrix) {
  6042. b = b.toTransformString();
  6043. }
  6044. if (!Snap._.rgTransform.test(b)) {
  6045. b = Snap._.svgTransform2string(b);
  6046. }
  6047. return equaliseTransform(a, b, function () {
  6048. return el.getBBox(1);
  6049. });
  6050. }
  6051. if (name == "d" || name == "path") {
  6052. A = Snap.path.toCubic(a, b);
  6053. return {
  6054. from: path2array(A[0]),
  6055. to: path2array(A[1]),
  6056. f: getPath(A[0])
  6057. };
  6058. }
  6059. if (name == "points") {
  6060. A = Str(a).split(",");
  6061. B = Str(b).split(",");
  6062. return {
  6063. from: A,
  6064. to: B,
  6065. f: function (val) { return val; }
  6066. };
  6067. }
  6068. var aUnit = a.match(reUnit),
  6069. bUnit = Str(b).match(reUnit);
  6070. if (aUnit && aUnit == bUnit) {
  6071. return {
  6072. from: parseFloat(a),
  6073. to: parseFloat(b),
  6074. f: getUnit(aUnit)
  6075. };
  6076. } else {
  6077. return {
  6078. from: this.asPX(name),
  6079. to: this.asPX(name, b),
  6080. f: getNumber
  6081. };
  6082. }
  6083. };
  6084. });
  6085. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  6086. //
  6087. // Licensed under the Apache License, Version 2.0 (the "License");
  6088. // you may not use this file except in compliance with the License.
  6089. // You may obtain a copy of the License at
  6090. //
  6091. // http://www.apache.org/licenses/LICENSE-2.0
  6092. //
  6093. // Unless required by applicable law or agreed to in writing, software
  6094. // distributed under the License is distributed on an "AS IS" BASIS,
  6095. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6096. // See the License for the specific language governing permissions and
  6097. // limitations under the License.
  6098. Snap.plugin(function (Snap, Element, Paper, glob) {
  6099. var elproto = Element.prototype,
  6100. has = "hasOwnProperty",
  6101. supportsTouch = "createTouch" in glob.doc,
  6102. events = [
  6103. "click", "dblclick", "mousedown", "mousemove", "mouseout",
  6104. "mouseover", "mouseup", "touchstart", "touchmove", "touchend",
  6105. "touchcancel"
  6106. ],
  6107. touchMap = {
  6108. mousedown: "touchstart",
  6109. mousemove: "touchmove",
  6110. mouseup: "touchend"
  6111. },
  6112. getScroll = function (xy) {
  6113. var name = xy == "y" ? "scrollTop" : "scrollLeft";
  6114. return glob.doc.documentElement[name] || glob.doc.body[name];
  6115. },
  6116. preventDefault = function () {
  6117. this.returnValue = false;
  6118. },
  6119. preventTouch = function () {
  6120. return this.originalEvent.preventDefault();
  6121. },
  6122. stopPropagation = function () {
  6123. this.cancelBubble = true;
  6124. },
  6125. stopTouch = function () {
  6126. return this.originalEvent.stopPropagation();
  6127. },
  6128. addEvent = (function () {
  6129. if (glob.doc.addEventListener) {
  6130. return function (obj, type, fn, element) {
  6131. var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
  6132. f = function (e) {
  6133. var scrollY = getScroll("y"),
  6134. scrollX = getScroll("x");
  6135. if (supportsTouch && touchMap[has](type)) {
  6136. for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
  6137. if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
  6138. var olde = e;
  6139. e = e.targetTouches[i];
  6140. e.originalEvent = olde;
  6141. e.preventDefault = preventTouch;
  6142. e.stopPropagation = stopTouch;
  6143. break;
  6144. }
  6145. }
  6146. }
  6147. var x = e.clientX + scrollX,
  6148. y = e.clientY + scrollY;
  6149. return fn.call(element, e, x, y);
  6150. };
  6151. if (type !== realName) {
  6152. obj.addEventListener(type, f, false);
  6153. }
  6154. obj.addEventListener(realName, f, false);
  6155. return function () {
  6156. if (type !== realName) {
  6157. obj.removeEventListener(type, f, false);
  6158. }
  6159. obj.removeEventListener(realName, f, false);
  6160. return true;
  6161. };
  6162. };
  6163. } else if (glob.doc.attachEvent) {
  6164. return function (obj, type, fn, element) {
  6165. var f = function (e) {
  6166. e = e || glob.win.event;
  6167. var scrollY = getScroll("y"),
  6168. scrollX = getScroll("x"),
  6169. x = e.clientX + scrollX,
  6170. y = e.clientY + scrollY;
  6171. e.preventDefault = e.preventDefault || preventDefault;
  6172. e.stopPropagation = e.stopPropagation || stopPropagation;
  6173. return fn.call(element, e, x, y);
  6174. };
  6175. obj.attachEvent("on" + type, f);
  6176. var detacher = function () {
  6177. obj.detachEvent("on" + type, f);
  6178. return true;
  6179. };
  6180. return detacher;
  6181. };
  6182. }
  6183. })(),
  6184. drag = [],
  6185. dragMove = function (e) {
  6186. var x = e.clientX,
  6187. y = e.clientY,
  6188. scrollY = getScroll("y"),
  6189. scrollX = getScroll("x"),
  6190. dragi,
  6191. j = drag.length;
  6192. while (j--) {
  6193. dragi = drag[j];
  6194. if (supportsTouch) {
  6195. var i = e.touches && e.touches.length,
  6196. touch;
  6197. while (i--) {
  6198. touch = e.touches[i];
  6199. if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) {
  6200. x = touch.clientX;
  6201. y = touch.clientY;
  6202. (e.originalEvent ? e.originalEvent : e).preventDefault();
  6203. break;
  6204. }
  6205. }
  6206. } else {
  6207. e.preventDefault();
  6208. }
  6209. var node = dragi.el.node,
  6210. o,
  6211. glob = Snap._.glob,
  6212. next = node.nextSibling,
  6213. parent = node.parentNode,
  6214. display = node.style.display;
  6215. // glob.win.opera && parent.removeChild(node);
  6216. // node.style.display = "none";
  6217. // o = dragi.el.paper.getElementByPoint(x, y);
  6218. // node.style.display = display;
  6219. // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
  6220. // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o);
  6221. x += scrollX;
  6222. y += scrollY;
  6223. eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
  6224. }
  6225. },
  6226. dragUp = function (e) {
  6227. Snap.unmousemove(dragMove).unmouseup(dragUp);
  6228. var i = drag.length,
  6229. dragi;
  6230. while (i--) {
  6231. dragi = drag[i];
  6232. dragi.el._drag = {};
  6233. eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
  6234. }
  6235. drag = [];
  6236. };
  6237. /*\
  6238. * Element.click
  6239. [ method ]
  6240. **
  6241. * Adds a click event handler to the element
  6242. - handler (function) handler for the event
  6243. = (object) @Element
  6244. \*/
  6245. /*\
  6246. * Element.unclick
  6247. [ method ]
  6248. **
  6249. * Removes a click event handler from the element
  6250. - handler (function) handler for the event
  6251. = (object) @Element
  6252. \*/
  6253. /*\
  6254. * Element.dblclick
  6255. [ method ]
  6256. **
  6257. * Adds a double click event handler to the element
  6258. - handler (function) handler for the event
  6259. = (object) @Element
  6260. \*/
  6261. /*\
  6262. * Element.undblclick
  6263. [ method ]
  6264. **
  6265. * Removes a double click event handler from the element
  6266. - handler (function) handler for the event
  6267. = (object) @Element
  6268. \*/
  6269. /*\
  6270. * Element.mousedown
  6271. [ method ]
  6272. **
  6273. * Adds a mousedown event handler to the element
  6274. - handler (function) handler for the event
  6275. = (object) @Element
  6276. \*/
  6277. /*\
  6278. * Element.unmousedown
  6279. [ method ]
  6280. **
  6281. * Removes a mousedown event handler from the element
  6282. - handler (function) handler for the event
  6283. = (object) @Element
  6284. \*/
  6285. /*\
  6286. * Element.mousemove
  6287. [ method ]
  6288. **
  6289. * Adds a mousemove event handler to the element
  6290. - handler (function) handler for the event
  6291. = (object) @Element
  6292. \*/
  6293. /*\
  6294. * Element.unmousemove
  6295. [ method ]
  6296. **
  6297. * Removes a mousemove event handler from the element
  6298. - handler (function) handler for the event
  6299. = (object) @Element
  6300. \*/
  6301. /*\
  6302. * Element.mouseout
  6303. [ method ]
  6304. **
  6305. * Adds a mouseout event handler to the element
  6306. - handler (function) handler for the event
  6307. = (object) @Element
  6308. \*/
  6309. /*\
  6310. * Element.unmouseout
  6311. [ method ]
  6312. **
  6313. * Removes a mouseout event handler from the element
  6314. - handler (function) handler for the event
  6315. = (object) @Element
  6316. \*/
  6317. /*\
  6318. * Element.mouseover
  6319. [ method ]
  6320. **
  6321. * Adds a mouseover event handler to the element
  6322. - handler (function) handler for the event
  6323. = (object) @Element
  6324. \*/
  6325. /*\
  6326. * Element.unmouseover
  6327. [ method ]
  6328. **
  6329. * Removes a mouseover event handler from the element
  6330. - handler (function) handler for the event
  6331. = (object) @Element
  6332. \*/
  6333. /*\
  6334. * Element.mouseup
  6335. [ method ]
  6336. **
  6337. * Adds a mouseup event handler to the element
  6338. - handler (function) handler for the event
  6339. = (object) @Element
  6340. \*/
  6341. /*\
  6342. * Element.unmouseup
  6343. [ method ]
  6344. **
  6345. * Removes a mouseup event handler from the element
  6346. - handler (function) handler for the event
  6347. = (object) @Element
  6348. \*/
  6349. /*\
  6350. * Element.touchstart
  6351. [ method ]
  6352. **
  6353. * Adds a touchstart event handler to the element
  6354. - handler (function) handler for the event
  6355. = (object) @Element
  6356. \*/
  6357. /*\
  6358. * Element.untouchstart
  6359. [ method ]
  6360. **
  6361. * Removes a touchstart event handler from the element
  6362. - handler (function) handler for the event
  6363. = (object) @Element
  6364. \*/
  6365. /*\
  6366. * Element.touchmove
  6367. [ method ]
  6368. **
  6369. * Adds a touchmove event handler to the element
  6370. - handler (function) handler for the event
  6371. = (object) @Element
  6372. \*/
  6373. /*\
  6374. * Element.untouchmove
  6375. [ method ]
  6376. **
  6377. * Removes a touchmove event handler from the element
  6378. - handler (function) handler for the event
  6379. = (object) @Element
  6380. \*/
  6381. /*\
  6382. * Element.touchend
  6383. [ method ]
  6384. **
  6385. * Adds a touchend event handler to the element
  6386. - handler (function) handler for the event
  6387. = (object) @Element
  6388. \*/
  6389. /*\
  6390. * Element.untouchend
  6391. [ method ]
  6392. **
  6393. * Removes a touchend event handler from the element
  6394. - handler (function) handler for the event
  6395. = (object) @Element
  6396. \*/
  6397. /*\
  6398. * Element.touchcancel
  6399. [ method ]
  6400. **
  6401. * Adds a touchcancel event handler to the element
  6402. - handler (function) handler for the event
  6403. = (object) @Element
  6404. \*/
  6405. /*\
  6406. * Element.untouchcancel
  6407. [ method ]
  6408. **
  6409. * Removes a touchcancel event handler from the element
  6410. - handler (function) handler for the event
  6411. = (object) @Element
  6412. \*/
  6413. for (var i = events.length; i--;) {
  6414. (function (eventName) {
  6415. Snap[eventName] = elproto[eventName] = function (fn, scope) {
  6416. if (Snap.is(fn, "function")) {
  6417. this.events = this.events || [];
  6418. this.events.push({
  6419. name: eventName,
  6420. f: fn,
  6421. unbind: addEvent(this.shape || this.node || glob.doc, eventName, fn, scope || this)
  6422. });
  6423. }
  6424. return this;
  6425. };
  6426. Snap["un" + eventName] =
  6427. elproto["un" + eventName] = function (fn) {
  6428. var events = this.events || [],
  6429. l = events.length;
  6430. while (l--) if (events[l].name == eventName &&
  6431. (events[l].f == fn || !fn)) {
  6432. events[l].unbind();
  6433. events.splice(l, 1);
  6434. !events.length && delete this.events;
  6435. return this;
  6436. }
  6437. return this;
  6438. };
  6439. })(events[i]);
  6440. }
  6441. /*\
  6442. * Element.hover
  6443. [ method ]
  6444. **
  6445. * Adds hover event handlers to the element
  6446. - f_in (function) handler for hover in
  6447. - f_out (function) handler for hover out
  6448. - icontext (object) #optional context for hover in handler
  6449. - ocontext (object) #optional context for hover out handler
  6450. = (object) @Element
  6451. \*/
  6452. elproto.hover = function (f_in, f_out, scope_in, scope_out) {
  6453. return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
  6454. };
  6455. /*\
  6456. * Element.unhover
  6457. [ method ]
  6458. **
  6459. * Removes hover event handlers from the element
  6460. - f_in (function) handler for hover in
  6461. - f_out (function) handler for hover out
  6462. = (object) @Element
  6463. \*/
  6464. elproto.unhover = function (f_in, f_out) {
  6465. return this.unmouseover(f_in).unmouseout(f_out);
  6466. };
  6467. var draggable = [];
  6468. // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture.
  6469. // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from?
  6470. // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason.
  6471. // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID?
  6472. /*\
  6473. * Element.drag
  6474. [ method ]
  6475. **
  6476. * Adds event handlers for an element's drag gesture
  6477. **
  6478. - onmove (function) handler for moving
  6479. - onstart (function) handler for drag start
  6480. - onend (function) handler for drag end
  6481. - mcontext (object) #optional context for moving handler
  6482. - scontext (object) #optional context for drag start handler
  6483. - econtext (object) #optional context for drag end handler
  6484. * Additionaly following `drag` events are triggered: `drag.start.<id>` on start,
  6485. * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element
  6486. * `drag.over.<id>` fires as well.
  6487. *
  6488. * Start event and start handler are called in specified context or in context of the element with following parameters:
  6489. o x (number) x position of the mouse
  6490. o y (number) y position of the mouse
  6491. o event (object) DOM event object
  6492. * Move event and move handler are called in specified context or in context of the element with following parameters:
  6493. o dx (number) shift by x from the start point
  6494. o dy (number) shift by y from the start point
  6495. o x (number) x position of the mouse
  6496. o y (number) y position of the mouse
  6497. o event (object) DOM event object
  6498. * End event and end handler are called in specified context or in context of the element with following parameters:
  6499. o event (object) DOM event object
  6500. = (object) @Element
  6501. \*/
  6502. elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
  6503. if (!arguments.length) {
  6504. var origTransform;
  6505. return this.drag(function (dx, dy) {
  6506. this.attr({
  6507. transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
  6508. });
  6509. }, function () {
  6510. origTransform = this.transform().local;
  6511. });
  6512. }
  6513. function start(e, x, y) {
  6514. (e.originalEvent || e).preventDefault();
  6515. this._drag.x = x;
  6516. this._drag.y = y;
  6517. this._drag.id = e.identifier;
  6518. !drag.length && Snap.mousemove(dragMove).mouseup(dragUp);
  6519. drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
  6520. onstart && eve.on("snap.drag.start." + this.id, onstart);
  6521. onmove && eve.on("snap.drag.move." + this.id, onmove);
  6522. onend && eve.on("snap.drag.end." + this.id, onend);
  6523. eve("snap.drag.start." + this.id, start_scope || move_scope || this, x, y, e);
  6524. }
  6525. this._drag = {};
  6526. draggable.push({el: this, start: start});
  6527. this.mousedown(start);
  6528. return this;
  6529. };
  6530. /*
  6531. * Element.onDragOver
  6532. [ method ]
  6533. **
  6534. * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id)
  6535. - f (function) handler for event, first argument would be the element you are dragging over
  6536. \*/
  6537. // elproto.onDragOver = function (f) {
  6538. // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id);
  6539. // };
  6540. /*\
  6541. * Element.undrag
  6542. [ method ]
  6543. **
  6544. * Removes all drag event handlers from the given element
  6545. \*/
  6546. elproto.undrag = function () {
  6547. var i = draggable.length;
  6548. while (i--) if (draggable[i].el == this) {
  6549. this.unmousedown(draggable[i].start);
  6550. draggable.splice(i, 1);
  6551. eve.unbind("snap.drag.*." + this.id);
  6552. }
  6553. !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp);
  6554. return this;
  6555. };
  6556. });
  6557. // Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
  6558. //
  6559. // Licensed under the Apache License, Version 2.0 (the "License");
  6560. // you may not use this file except in compliance with the License.
  6561. // You may obtain a copy of the License at
  6562. //
  6563. // http://www.apache.org/licenses/LICENSE-2.0
  6564. //
  6565. // Unless required by applicable law or agreed to in writing, software
  6566. // distributed under the License is distributed on an "AS IS" BASIS,
  6567. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6568. // See the License for the specific language governing permissions and
  6569. // limitations under the License.
  6570. Snap.plugin(function (Snap, Element, Paper, glob) {
  6571. var elproto = Element.prototype,
  6572. pproto = Paper.prototype,
  6573. rgurl = /^\s*url\((.+)\)/,
  6574. Str = String,
  6575. $ = Snap._.$;
  6576. Snap.filter = {};
  6577. // SIERRA Paper.filter(): I don't understand the note. Does that mean an HTML should dedicate a separate SVG region for a filter definition? What's the advantage over a DEFS?
  6578. /*\
  6579. * Paper.filter
  6580. [ method ]
  6581. **
  6582. * Creates a `<filter>` element
  6583. **
  6584. - filstr (string) SVG fragment of filter provided as a string
  6585. = (object) @Element
  6586. * Note: It is recommended to use filters embedded into the page inside an empty SVG element.
  6587. > Usage
  6588. | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'),
  6589. | c = paper.circle(10, 10, 10).attr({
  6590. | filter: f
  6591. | });
  6592. \*/
  6593. pproto.filter = function (filstr) {
  6594. var paper = this;
  6595. if (paper.type != "svg") {
  6596. paper = paper.paper;
  6597. }
  6598. var f = Snap.parse(Str(filstr)),
  6599. id = Snap._.id(),
  6600. width = paper.node.offsetWidth,
  6601. height = paper.node.offsetHeight,
  6602. filter = $("filter");
  6603. $(filter, {
  6604. id: id,
  6605. filterUnits: "userSpaceOnUse"
  6606. });
  6607. filter.appendChild(f.node);
  6608. paper.defs.appendChild(filter);
  6609. return new Element(filter);
  6610. };
  6611. eve.on("snap.util.getattr.filter", function () {
  6612. eve.stop();
  6613. var p = $(this.node, "filter");
  6614. if (p) {
  6615. var match = Str(p).match(rgurl);
  6616. return match && Snap.select(match[1]);
  6617. }
  6618. });
  6619. eve.on("snap.util.attr.filter", function (value) {
  6620. if (value instanceof Element && value.type == "filter") {
  6621. eve.stop();
  6622. var id = value.node.id;
  6623. if (!id) {
  6624. $(value.node, {id: value.id});
  6625. id = value.id;
  6626. }
  6627. $(this.node, {
  6628. filter: Snap.url(id)
  6629. });
  6630. }
  6631. if (!value || value == "none") {
  6632. eve.stop();
  6633. this.node.removeAttribute("filter");
  6634. }
  6635. });
  6636. /*\
  6637. * Snap.filter.blur
  6638. [ method ]
  6639. **
  6640. * Returns an SVG markup string for the blur filter
  6641. **
  6642. - x (number) amount of horizontal blur, in pixels
  6643. - y (number) #optional amount of vertical blur, in pixels
  6644. = (string) filter representation
  6645. > Usage
  6646. | var f = paper.filter(Snap.filter.blur(5, 10)),
  6647. | c = paper.circle(10, 10, 10).attr({
  6648. | filter: f
  6649. | });
  6650. \*/
  6651. Snap.filter.blur = function (x, y) {
  6652. if (x == null) {
  6653. x = 2;
  6654. }
  6655. var def = y == null ? x : [x, y];
  6656. return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', {
  6657. def: def
  6658. });
  6659. };
  6660. Snap.filter.blur.toString = function () {
  6661. return this();
  6662. };
  6663. /*\
  6664. * Snap.filter.shadow
  6665. [ method ]
  6666. **
  6667. * Returns an SVG markup string for the shadow filter
  6668. **
  6669. - dx (number) horizontal shift of the shadow, in pixels
  6670. - dy (number) vertical shift of the shadow, in pixels
  6671. - blur (number) #optional amount of blur
  6672. - color (string) #optional color of the shadow
  6673. = (string) filter representation
  6674. > Usage
  6675. | var f = paper.filter(Snap.filter.shadow(0, 2, 3)),
  6676. | c = paper.circle(10, 10, 10).attr({
  6677. | filter: f
  6678. | });
  6679. \*/
  6680. Snap.filter.shadow = function (dx, dy, blur, color) {
  6681. color = color || "#000";
  6682. if (blur == null) {
  6683. blur = 4;
  6684. }
  6685. if (typeof blur == "string") {
  6686. color = blur;
  6687. blur = 4;
  6688. }
  6689. if (dx == null) {
  6690. dx = 0;
  6691. dy = 2;
  6692. }
  6693. if (dy == null) {
  6694. dy = dx;
  6695. }
  6696. color = Snap.color(color);
  6697. return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
  6698. color: color,
  6699. dx: dx,
  6700. dy: dy,
  6701. blur: blur
  6702. });
  6703. };
  6704. Snap.filter.shadow.toString = function () {
  6705. return this();
  6706. };
  6707. /*\
  6708. * Snap.filter.grayscale
  6709. [ method ]
  6710. **
  6711. * Returns an SVG markup string for the grayscale filter
  6712. **
  6713. - amount (number) amount of filter (`0..1`)
  6714. = (string) filter representation
  6715. \*/
  6716. Snap.filter.grayscale = function (amount) {
  6717. if (amount == null) {
  6718. amount = 1;
  6719. }
  6720. return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', {
  6721. a: 0.2126 + 0.7874 * (1 - amount),
  6722. b: 0.7152 - 0.7152 * (1 - amount),
  6723. c: 0.0722 - 0.0722 * (1 - amount),
  6724. d: 0.2126 - 0.2126 * (1 - amount),
  6725. e: 0.7152 + 0.2848 * (1 - amount),
  6726. f: 0.0722 - 0.0722 * (1 - amount),
  6727. g: 0.2126 - 0.2126 * (1 - amount),
  6728. h: 0.0722 + 0.9278 * (1 - amount)
  6729. });
  6730. };
  6731. Snap.filter.grayscale.toString = function () {
  6732. return this();
  6733. };
  6734. /*\
  6735. * Snap.filter.sepia
  6736. [ method ]
  6737. **
  6738. * Returns an SVG markup string for the sepia filter
  6739. **
  6740. - amount (number) amount of filter (`0..1`)
  6741. = (string) filter representation
  6742. \*/
  6743. Snap.filter.sepia = function (amount) {
  6744. if (amount == null) {
  6745. amount = 1;
  6746. }
  6747. return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', {
  6748. a: 0.393 + 0.607 * (1 - amount),
  6749. b: 0.769 - 0.769 * (1 - amount),
  6750. c: 0.189 - 0.189 * (1 - amount),
  6751. d: 0.349 - 0.349 * (1 - amount),
  6752. e: 0.686 + 0.314 * (1 - amount),
  6753. f: 0.168 - 0.168 * (1 - amount),
  6754. g: 0.272 - 0.272 * (1 - amount),
  6755. h: 0.534 - 0.534 * (1 - amount),
  6756. i: 0.131 + 0.869 * (1 - amount)
  6757. });
  6758. };
  6759. Snap.filter.sepia.toString = function () {
  6760. return this();
  6761. };
  6762. /*\
  6763. * Snap.filter.saturate
  6764. [ method ]
  6765. **
  6766. * Returns an SVG markup string for the saturate filter
  6767. **
  6768. - amount (number) amount of filter (`0..1`)
  6769. = (string) filter representation
  6770. \*/
  6771. Snap.filter.saturate = function (amount) {
  6772. if (amount == null) {
  6773. amount = 1;
  6774. }
  6775. return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', {
  6776. amount: 1 - amount
  6777. });
  6778. };
  6779. Snap.filter.saturate.toString = function () {
  6780. return this();
  6781. };
  6782. /*\
  6783. * Snap.filter.hueRotate
  6784. [ method ]
  6785. **
  6786. * Returns an SVG markup string for the hue-rotate filter
  6787. **
  6788. - angle (number) angle of rotation
  6789. = (string) filter representation
  6790. \*/
  6791. Snap.filter.hueRotate = function (angle) {
  6792. angle = angle || 0;
  6793. return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', {
  6794. angle: angle
  6795. });
  6796. };
  6797. Snap.filter.hueRotate.toString = function () {
  6798. return this();
  6799. };
  6800. /*\
  6801. * Snap.filter.invert
  6802. [ method ]
  6803. **
  6804. * Returns an SVG markup string for the invert filter
  6805. **
  6806. - amount (number) amount of filter (`0..1`)
  6807. = (string) filter representation
  6808. \*/
  6809. Snap.filter.invert = function (amount) {
  6810. if (amount == null) {
  6811. amount = 1;
  6812. }
  6813. return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', {
  6814. amount: amount,
  6815. amount2: 1 - amount
  6816. });
  6817. };
  6818. Snap.filter.invert.toString = function () {
  6819. return this();
  6820. };
  6821. /*\
  6822. * Snap.filter.brightness
  6823. [ method ]
  6824. **
  6825. * Returns an SVG markup string for the brightness filter
  6826. **
  6827. - amount (number) amount of filter (`0..1`)
  6828. = (string) filter representation
  6829. \*/
  6830. Snap.filter.brightness = function (amount) {
  6831. if (amount == null) {
  6832. amount = 1;
  6833. }
  6834. return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', {
  6835. amount: amount
  6836. });
  6837. };
  6838. Snap.filter.brightness.toString = function () {
  6839. return this();
  6840. };
  6841. /*\
  6842. * Snap.filter.contrast
  6843. [ method ]
  6844. **
  6845. * Returns an SVG markup string for the contrast filter
  6846. **
  6847. - amount (number) amount of filter (`0..1`)
  6848. = (string) filter representation
  6849. \*/
  6850. Snap.filter.contrast = function (amount) {
  6851. if (amount == null) {
  6852. amount = 1;
  6853. }
  6854. return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', {
  6855. amount: amount,
  6856. amount2: .5 - amount / 2
  6857. });
  6858. };
  6859. Snap.filter.contrast.toString = function () {
  6860. return this();
  6861. };
  6862. });
  6863. return Snap;
  6864. }));