vega.js 177 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970
  1. vg = (function(d3, topojson) { // take d3 & topojson as imports
  2. var vg = {
  3. version: "1.3.2", // semantic versioning
  4. d3: d3, // stash d3 for use in property functions
  5. topojson: topojson // stash topojson similarly
  6. };
  7. // type checking functions
  8. var toString = Object.prototype.toString;
  9. vg.isObject = function(obj) {
  10. return obj === Object(obj);
  11. };
  12. vg.isFunction = function(obj) {
  13. return toString.call(obj) == '[object Function]';
  14. };
  15. vg.isString = function(obj) {
  16. return toString.call(obj) == '[object String]';
  17. };
  18. vg.isArray = Array.isArray || function(obj) {
  19. return toString.call(obj) == '[object Array]';
  20. };
  21. vg.isNumber = function(obj) {
  22. return toString.call(obj) == '[object Number]';
  23. };
  24. vg.isBoolean = function(obj) {
  25. return toString.call(obj) == '[object Boolean]';
  26. };
  27. vg.isTree = function(obj) {
  28. return vg.isArray(obj) && obj.__vgtree__;
  29. };
  30. vg.number = function(s) { return +s; };
  31. vg.boolean = function(s) { return !!s; };
  32. // utility functions
  33. vg.identity = function(x) { return x; };
  34. vg.extend = function(obj) {
  35. for (var x, name, i=1, len=arguments.length; i<len; ++i) {
  36. x = arguments[i];
  37. for (name in x) { obj[name] = x[name]; }
  38. }
  39. return obj;
  40. };
  41. vg.duplicate = function(obj) {
  42. return JSON.parse(JSON.stringify(obj));
  43. };
  44. vg.field = function(f) {
  45. return f.split("\\.")
  46. .map(function(d) { return d.split("."); })
  47. .reduce(function(a, b) {
  48. if (a.length) { a[a.length-1] += "." + b.shift(); }
  49. a.push.apply(a, b);
  50. return a;
  51. }, []);
  52. };
  53. vg.accessor = function(f) {
  54. var s;
  55. return (vg.isFunction(f) || f==null)
  56. ? f : vg.isString(f) && (s=vg.field(f)).length > 1
  57. ? function(x) { return s.reduce(function(x,f) { return x[f]; }, x); }
  58. : function(x) { return x[f]; };
  59. };
  60. vg.comparator = function(sort) {
  61. var sign = [];
  62. if (sort === undefined) sort = [];
  63. sort = vg.array(sort).map(function(f) {
  64. var s = 1;
  65. if (f[0] === "-") { s = -1; f = f.slice(1); }
  66. else if (f[0] === "+") { s = +1; f = f.slice(1); }
  67. sign.push(s);
  68. return vg.accessor(f);
  69. });
  70. return function(a,b) {
  71. var i, n, f, x, y;
  72. for (i=0, n=sort.length; i<n; ++i) {
  73. f = sort[i]; x = f(a); y = f(b);
  74. if (x < y) return -1 * sign[i];
  75. if (x > y) return sign[i];
  76. }
  77. return 0;
  78. };
  79. };
  80. vg.cmp = function(a, b) { return a<b ? -1 : a>b ? 1 : 0; };
  81. vg.numcmp = function(a, b) { return a - b; };
  82. vg.array = function(x) {
  83. return x != null ? (vg.isArray(x) ? x : [x]) : [];
  84. };
  85. vg.values = function(x) {
  86. return (vg.isObject(x) && !vg.isArray(x) && x.values) ? x.values : x;
  87. };
  88. vg.str = function(x) {
  89. return vg.isArray(x) ? "[" + x.map(vg.str) + "]"
  90. : vg.isObject(x) ? JSON.stringify(x)
  91. : vg.isString(x) ? ("'"+vg_escape_str(x)+"'") : x;
  92. };
  93. var escape_str_re = /(^|[^\\])'/g;
  94. function vg_escape_str(x) {
  95. return x.replace(escape_str_re, "$1\\'");
  96. }
  97. vg.keys = function(x) {
  98. var keys = [];
  99. for (var key in x) keys.push(key);
  100. return keys;
  101. };
  102. vg.unique = function(data, f, results) {
  103. if (!vg.isArray(data) || data.length==0) return [];
  104. f = f || vg.identity;
  105. results = results || [];
  106. for (var v, i=0, n=data.length; i<n; ++i) {
  107. v = f(data[i]);
  108. if (results.indexOf(v) < 0) results.push(v);
  109. }
  110. return results;
  111. };
  112. vg.minIndex = function(data, f) {
  113. if (!vg.isArray(data) || data.length==0) return -1;
  114. f = f || vg.identity;
  115. var idx = 0, min = f(data[0]), v = min;
  116. for (var i=1, n=data.length; i<n; ++i) {
  117. v = f(data[i]);
  118. if (v < min) { min = v; idx = i; }
  119. }
  120. return idx;
  121. };
  122. vg.maxIndex = function(data, f) {
  123. if (!vg.isArray(data) || data.length==0) return -1;
  124. f = f || vg.identity;
  125. var idx = 0, max = f(data[0]), v = max;
  126. for (var i=1, n=data.length; i<n; ++i) {
  127. v = f(data[i]);
  128. if (v > max) { max = v; idx = i; }
  129. }
  130. return idx;
  131. };
  132. vg.truncate = function(s, length, pos, word, ellipsis) {
  133. var len = s.length;
  134. if (len <= length) return s;
  135. ellipsis = ellipsis || "...";
  136. var l = Math.max(0, length - ellipsis.length);
  137. switch (pos) {
  138. case "left":
  139. return ellipsis + (word ? vg_truncateOnWord(s,l,1) : s.slice(len-l));
  140. case "middle":
  141. case "center":
  142. var l1 = Math.ceil(l/2), l2 = Math.floor(l/2);
  143. return (word ? vg_truncateOnWord(s,l1) : s.slice(0,l1)) + ellipsis
  144. + (word ? vg_truncateOnWord(s,l2,1) : s.slice(len-l2));
  145. default:
  146. return (word ? vg_truncateOnWord(s,l) : s.slice(0,l)) + ellipsis;
  147. }
  148. }
  149. function vg_truncateOnWord(s, len, rev) {
  150. var cnt = 0, tok = s.split(vg_truncate_word_re);
  151. if (rev) {
  152. s = (tok = tok.reverse())
  153. .filter(function(w) { cnt += w.length; return cnt <= len; })
  154. .reverse();
  155. } else {
  156. s = tok.filter(function(w) { cnt += w.length; return cnt <= len; });
  157. }
  158. return s.length ? s.join("").trim() : tok[0].slice(0, len);
  159. }
  160. var vg_truncate_word_re = /([\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF])/;
  161. // Logging
  162. function vg_write(msg) {
  163. vg.config.isNode
  164. ? process.stderr.write(msg + "\n")
  165. : console.log(msg);
  166. }
  167. vg.log = function(msg) {
  168. vg_write("[Vega Log] " + msg);
  169. };
  170. vg.error = function(msg) {
  171. msg = "[Vega Err] " + msg;
  172. vg_write(msg);
  173. if (typeof alert !== "undefined") alert(msg);
  174. };vg.config = {};
  175. // are we running in node.js?
  176. // via timetler.com/2012/10/13/environment-detection-in-javascript/
  177. vg.config.isNode = typeof exports !== 'undefined' && this.exports !== exports;
  178. // base url for loading external data files
  179. // used only for server-side operation
  180. vg.config.baseURL = "";
  181. // version and namepsaces for exported svg
  182. vg.config.svgNamespace =
  183. 'version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
  184. 'xmlns:xlink="http://www.w3.org/1999/xlink"';
  185. // inset padding for automatic padding calculation
  186. vg.config.autopadInset = 5;
  187. // extensible scale lookup table
  188. // all d3.scale.* instances also supported
  189. vg.config.scale = {
  190. time: d3.time.scale,
  191. utc: d3.time.scale.utc
  192. };
  193. // default rendering settings
  194. vg.config.render = {
  195. lineWidth: 1,
  196. lineCap: "butt",
  197. font: "sans-serif",
  198. fontSize: 11
  199. };
  200. // default axis properties
  201. vg.config.axis = {
  202. orient: "bottom",
  203. ticks: 10,
  204. padding: 3,
  205. axisColor: "#000",
  206. gridColor: "#d8d8d8",
  207. tickColor: "#000",
  208. tickLabelColor: "#000",
  209. axisWidth: 1,
  210. tickWidth: 1,
  211. tickSize: 6,
  212. tickLabelFontSize: 11,
  213. tickLabelFont: "sans-serif",
  214. titleColor: "#000",
  215. titleFont: "sans-serif",
  216. titleFontSize: 11,
  217. titleFontWeight: "bold",
  218. titleOffset: 35
  219. };
  220. // default legend properties
  221. vg.config.legend = {
  222. orient: "right",
  223. offset: 10,
  224. padding: 3,
  225. gradientStrokeColor: "#888",
  226. gradientStrokeWidth: 1,
  227. gradientHeight: 16,
  228. gradientWidth: 100,
  229. labelColor: "#000",
  230. labelFontSize: 10,
  231. labelFont: "sans-serif",
  232. labelAlign: "left",
  233. labelBaseline: "middle",
  234. labelOffset: 8,
  235. symbolShape: "circle",
  236. symbolSize: 50,
  237. symbolColor: "#888",
  238. symbolStrokeWidth: 1,
  239. titleColor: "#000",
  240. titleFont: "sans-serif",
  241. titleFontSize: 11,
  242. titleFontWeight: "bold"
  243. };
  244. // default color values
  245. vg.config.color = {
  246. rgb: [128, 128, 128],
  247. lab: [50, 0, 0],
  248. hcl: [0, 0, 50],
  249. hsl: [0, 0, 0.5]
  250. };
  251. // default scale ranges
  252. vg.config.range = {
  253. category10: [
  254. "#1f77b4",
  255. "#ff7f0e",
  256. "#2ca02c",
  257. "#d62728",
  258. "#9467bd",
  259. "#8c564b",
  260. "#e377c2",
  261. "#7f7f7f",
  262. "#bcbd22",
  263. "#17becf"
  264. ],
  265. category20: [
  266. "#1f77b4",
  267. "#aec7e8",
  268. "#ff7f0e",
  269. "#ffbb78",
  270. "#2ca02c",
  271. "#98df8a",
  272. "#d62728",
  273. "#ff9896",
  274. "#9467bd",
  275. "#c5b0d5",
  276. "#8c564b",
  277. "#c49c94",
  278. "#e377c2",
  279. "#f7b6d2",
  280. "#7f7f7f",
  281. "#c7c7c7",
  282. "#bcbd22",
  283. "#dbdb8d",
  284. "#17becf",
  285. "#9edae5"
  286. ],
  287. shapes: [
  288. "circle",
  289. "cross",
  290. "diamond",
  291. "square",
  292. "triangle-down",
  293. "triangle-up"
  294. ]
  295. };vg.Bounds = (function() {
  296. var bounds = function(b) {
  297. this.clear();
  298. if (b) this.union(b);
  299. };
  300. var prototype = bounds.prototype;
  301. prototype.clear = function() {
  302. this.x1 = +Number.MAX_VALUE;
  303. this.y1 = +Number.MAX_VALUE;
  304. this.x2 = -Number.MAX_VALUE;
  305. this.y2 = -Number.MAX_VALUE;
  306. return this;
  307. };
  308. prototype.set = function(x1, y1, x2, y2) {
  309. this.x1 = x1;
  310. this.y1 = y1;
  311. this.x2 = x2;
  312. this.y2 = y2;
  313. return this;
  314. };
  315. prototype.add = function(x, y) {
  316. if (x < this.x1) this.x1 = x;
  317. if (y < this.y1) this.y1 = y;
  318. if (x > this.x2) this.x2 = x;
  319. if (y > this.y2) this.y2 = y;
  320. return this;
  321. };
  322. prototype.expand = function(d) {
  323. this.x1 -= d;
  324. this.y1 -= d;
  325. this.x2 += d;
  326. this.y2 += d;
  327. return this;
  328. };
  329. prototype.round = function() {
  330. this.x1 = Math.floor(this.x1);
  331. this.y1 = Math.floor(this.y1);
  332. this.x2 = Math.ceil(this.x2);
  333. this.y2 = Math.ceil(this.y2);
  334. return this;
  335. };
  336. prototype.translate = function(dx, dy) {
  337. this.x1 += dx;
  338. this.x2 += dx;
  339. this.y1 += dy;
  340. this.y2 += dy;
  341. return this;
  342. };
  343. prototype.rotate = function(angle, x, y) {
  344. var cos = Math.cos(angle),
  345. sin = Math.sin(angle),
  346. cx = x - x*cos + y*sin,
  347. cy = y - x*sin - y*cos,
  348. x1 = this.x1, x2 = this.x2,
  349. y1 = this.y1, y2 = this.y2;
  350. return this.clear()
  351. .add(cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy)
  352. .add(cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy)
  353. .add(cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy)
  354. .add(cos*x2 - sin*y2 + cx, sin*x2 + cos*y2 + cy);
  355. }
  356. prototype.union = function(b) {
  357. if (b.x1 < this.x1) this.x1 = b.x1;
  358. if (b.y1 < this.y1) this.y1 = b.y1;
  359. if (b.x2 > this.x2) this.x2 = b.x2;
  360. if (b.y2 > this.y2) this.y2 = b.y2;
  361. return this;
  362. };
  363. prototype.encloses = function(b) {
  364. return b && (
  365. this.x1 <= b.x1 &&
  366. this.x2 >= b.x2 &&
  367. this.y1 <= b.y1 &&
  368. this.y2 >= b.y2
  369. );
  370. };
  371. prototype.intersects = function(b) {
  372. return b && !(
  373. this.x2 < b.x1 ||
  374. this.x1 > b.x2 ||
  375. this.y2 < b.y1 ||
  376. this.y1 > b.y2
  377. );
  378. };
  379. prototype.contains = function(x, y) {
  380. return !(
  381. x < this.x1 ||
  382. x > this.x2 ||
  383. y < this.y1 ||
  384. y > this.y2
  385. );
  386. };
  387. prototype.width = function() {
  388. return this.x2 - this.x1;
  389. };
  390. prototype.height = function() {
  391. return this.y2 - this.y1;
  392. };
  393. return bounds;
  394. })();vg.Gradient = (function() {
  395. function gradient(type) {
  396. this.id = "grad_" + (vg_gradient_id++);
  397. this.type = type || "linear";
  398. this.stops = [];
  399. this.x1 = 0;
  400. this.x2 = 1;
  401. this.y1 = 0;
  402. this.y2 = 0;
  403. };
  404. var prototype = gradient.prototype;
  405. prototype.stop = function(offset, color) {
  406. this.stops.push({
  407. offset: offset,
  408. color: color
  409. });
  410. return this;
  411. };
  412. return gradient;
  413. })();
  414. var vg_gradient_id = 0;vg.canvas = {};vg.canvas.path = (function() {
  415. // Path parsing and rendering code taken from fabric.js -- Thanks!
  416. var cmdLength = { m:2, l:2, h:1, v:1, c:6, s:4, q:4, t:2, a:7 },
  417. re = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)-/g, /\s|,|###/];
  418. function parse(path) {
  419. var result = [],
  420. currentPath,
  421. chunks,
  422. parsed;
  423. // First, break path into command sequence
  424. path = path.slice().replace(re[0], '###$1').split(re[1]).slice(1);
  425. // Next, parse each command in turn
  426. for (var i=0, j, chunksParsed, len=path.length; i<len; i++) {
  427. currentPath = path[i];
  428. chunks = currentPath.slice(1).trim().replace(re[2],'$1###-').split(re[3]);
  429. chunksParsed = [currentPath.charAt(0)];
  430. for (var j = 0, jlen = chunks.length; j < jlen; j++) {
  431. parsed = parseFloat(chunks[j]);
  432. if (!isNaN(parsed)) {
  433. chunksParsed.push(parsed);
  434. }
  435. }
  436. var command = chunksParsed[0].toLowerCase(),
  437. commandLength = cmdLength[command];
  438. if (chunksParsed.length - 1 > commandLength) {
  439. for (var k = 1, klen = chunksParsed.length; k < klen; k += commandLength) {
  440. result.push([ chunksParsed[0] ].concat(chunksParsed.slice(k, k + commandLength)));
  441. }
  442. }
  443. else {
  444. result.push(chunksParsed);
  445. }
  446. }
  447. return result;
  448. }
  449. function drawArc(g, x, y, coords, bounds, l, t) {
  450. var rx = coords[0];
  451. var ry = coords[1];
  452. var rot = coords[2];
  453. var large = coords[3];
  454. var sweep = coords[4];
  455. var ex = coords[5];
  456. var ey = coords[6];
  457. var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
  458. for (var i=0; i<segs.length; i++) {
  459. var bez = segmentToBezier.apply(null, segs[i]);
  460. g.bezierCurveTo.apply(g, bez);
  461. bounds.add(bez[0]-l, bez[1]-t);
  462. bounds.add(bez[2]-l, bez[3]-t);
  463. bounds.add(bez[4]-l, bez[5]-t);
  464. }
  465. }
  466. function boundArc(x, y, coords, bounds) {
  467. var rx = coords[0];
  468. var ry = coords[1];
  469. var rot = coords[2];
  470. var large = coords[3];
  471. var sweep = coords[4];
  472. var ex = coords[5];
  473. var ey = coords[6];
  474. var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
  475. for (var i=0; i<segs.length; i++) {
  476. var bez = segmentToBezier.apply(null, segs[i]);
  477. bounds.add(bez[0]-l, bez[1]-t);
  478. bounds.add(bez[2]-l, bez[3]-t);
  479. bounds.add(bez[4]-l, bez[5]-t);
  480. }
  481. }
  482. var arcToSegmentsCache = { },
  483. segmentToBezierCache = { },
  484. join = Array.prototype.join,
  485. argsStr;
  486. // Copied from Inkscape svgtopdf, thanks!
  487. function arcToSegments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
  488. argsStr = join.call(arguments);
  489. if (arcToSegmentsCache[argsStr]) {
  490. return arcToSegmentsCache[argsStr];
  491. }
  492. var th = rotateX * (Math.PI/180);
  493. var sin_th = Math.sin(th);
  494. var cos_th = Math.cos(th);
  495. rx = Math.abs(rx);
  496. ry = Math.abs(ry);
  497. var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
  498. var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
  499. var pl = (px*px) / (rx*rx) + (py*py) / (ry*ry);
  500. if (pl > 1) {
  501. pl = Math.sqrt(pl);
  502. rx *= pl;
  503. ry *= pl;
  504. }
  505. var a00 = cos_th / rx;
  506. var a01 = sin_th / rx;
  507. var a10 = (-sin_th) / ry;
  508. var a11 = (cos_th) / ry;
  509. var x0 = a00 * ox + a01 * oy;
  510. var y0 = a10 * ox + a11 * oy;
  511. var x1 = a00 * x + a01 * y;
  512. var y1 = a10 * x + a11 * y;
  513. var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0);
  514. var sfactor_sq = 1 / d - 0.25;
  515. if (sfactor_sq < 0) sfactor_sq = 0;
  516. var sfactor = Math.sqrt(sfactor_sq);
  517. if (sweep == large) sfactor = -sfactor;
  518. var xc = 0.5 * (x0 + x1) - sfactor * (y1-y0);
  519. var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0);
  520. var th0 = Math.atan2(y0-yc, x0-xc);
  521. var th1 = Math.atan2(y1-yc, x1-xc);
  522. var th_arc = th1-th0;
  523. if (th_arc < 0 && sweep == 1){
  524. th_arc += 2*Math.PI;
  525. } else if (th_arc > 0 && sweep == 0) {
  526. th_arc -= 2 * Math.PI;
  527. }
  528. var segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
  529. var result = [];
  530. for (var i=0; i<segments; i++) {
  531. var th2 = th0 + i * th_arc / segments;
  532. var th3 = th0 + (i+1) * th_arc / segments;
  533. result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
  534. }
  535. return (arcToSegmentsCache[argsStr] = result);
  536. }
  537. function segmentToBezier(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
  538. argsStr = join.call(arguments);
  539. if (segmentToBezierCache[argsStr]) {
  540. return segmentToBezierCache[argsStr];
  541. }
  542. var a00 = cos_th * rx;
  543. var a01 = -sin_th * ry;
  544. var a10 = sin_th * rx;
  545. var a11 = cos_th * ry;
  546. var cos_th0 = Math.cos(th0);
  547. var sin_th0 = Math.sin(th0);
  548. var cos_th1 = Math.cos(th1);
  549. var sin_th1 = Math.sin(th1);
  550. var th_half = 0.5 * (th1 - th0);
  551. var sin_th_h2 = Math.sin(th_half * 0.5);
  552. var t = (8/3) * sin_th_h2 * sin_th_h2 / Math.sin(th_half);
  553. var x1 = cx + cos_th0 - t * sin_th0;
  554. var y1 = cy + sin_th0 + t * cos_th0;
  555. var x3 = cx + cos_th1;
  556. var y3 = cy + sin_th1;
  557. var x2 = x3 + t * sin_th1;
  558. var y2 = y3 - t * cos_th1;
  559. return (segmentToBezierCache[argsStr] = [
  560. a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
  561. a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
  562. a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
  563. ]);
  564. }
  565. function render(g, path, l, t) {
  566. var current, // current instruction
  567. previous = null,
  568. x = 0, // current x
  569. y = 0, // current y
  570. controlX = 0, // current control point x
  571. controlY = 0, // current control point y
  572. tempX,
  573. tempY,
  574. tempControlX,
  575. tempControlY,
  576. bounds = new vg.Bounds();
  577. if (l == undefined) l = 0;
  578. if (t == undefined) t = 0;
  579. g.beginPath();
  580. for (var i=0, len=path.length; i<len; ++i) {
  581. current = path[i];
  582. switch (current[0]) { // first letter
  583. case 'l': // lineto, relative
  584. x += current[1];
  585. y += current[2];
  586. g.lineTo(x + l, y + t);
  587. bounds.add(x, y);
  588. break;
  589. case 'L': // lineto, absolute
  590. x = current[1];
  591. y = current[2];
  592. g.lineTo(x + l, y + t);
  593. bounds.add(x, y);
  594. break;
  595. case 'h': // horizontal lineto, relative
  596. x += current[1];
  597. g.lineTo(x + l, y + t);
  598. bounds.add(x, y);
  599. break;
  600. case 'H': // horizontal lineto, absolute
  601. x = current[1];
  602. g.lineTo(x + l, y + t);
  603. bounds.add(x, y);
  604. break;
  605. case 'v': // vertical lineto, relative
  606. y += current[1];
  607. g.lineTo(x + l, y + t);
  608. bounds.add(x, y);
  609. break;
  610. case 'V': // verical lineto, absolute
  611. y = current[1];
  612. g.lineTo(x + l, y + t);
  613. bounds.add(x, y);
  614. break;
  615. case 'm': // moveTo, relative
  616. x += current[1];
  617. y += current[2];
  618. g.moveTo(x + l, y + t);
  619. bounds.add(x, y);
  620. break;
  621. case 'M': // moveTo, absolute
  622. x = current[1];
  623. y = current[2];
  624. g.moveTo(x + l, y + t);
  625. bounds.add(x, y);
  626. break;
  627. case 'c': // bezierCurveTo, relative
  628. tempX = x + current[5];
  629. tempY = y + current[6];
  630. controlX = x + current[3];
  631. controlY = y + current[4];
  632. g.bezierCurveTo(
  633. x + current[1] + l, // x1
  634. y + current[2] + t, // y1
  635. controlX + l, // x2
  636. controlY + t, // y2
  637. tempX + l,
  638. tempY + t
  639. );
  640. bounds.add(x + current[1], y + current[2]);
  641. bounds.add(controlX, controlY);
  642. bounds.add(tempX, tempY);
  643. x = tempX;
  644. y = tempY;
  645. break;
  646. case 'C': // bezierCurveTo, absolute
  647. x = current[5];
  648. y = current[6];
  649. controlX = current[3];
  650. controlY = current[4];
  651. g.bezierCurveTo(
  652. current[1] + l,
  653. current[2] + t,
  654. controlX + l,
  655. controlY + t,
  656. x + l,
  657. y + t
  658. );
  659. bounds.add(current[1], current[2]);
  660. bounds.add(controlX, controlY);
  661. bounds.add(x, y);
  662. break;
  663. case 's': // shorthand cubic bezierCurveTo, relative
  664. // transform to absolute x,y
  665. tempX = x + current[3];
  666. tempY = y + current[4];
  667. // calculate reflection of previous control points
  668. controlX = 2 * x - controlX;
  669. controlY = 2 * y - controlY;
  670. g.bezierCurveTo(
  671. controlX + l,
  672. controlY + t,
  673. x + current[1] + l,
  674. y + current[2] + t,
  675. tempX + l,
  676. tempY + t
  677. );
  678. bounds.add(controlX, controlY);
  679. bounds.add(x + current[1], y + current[2]);
  680. bounds.add(tempX, tempY);
  681. // set control point to 2nd one of this command
  682. // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
  683. controlX = x + current[1];
  684. controlY = y + current[2];
  685. x = tempX;
  686. y = tempY;
  687. break;
  688. case 'S': // shorthand cubic bezierCurveTo, absolute
  689. tempX = current[3];
  690. tempY = current[4];
  691. // calculate reflection of previous control points
  692. controlX = 2*x - controlX;
  693. controlY = 2*y - controlY;
  694. g.bezierCurveTo(
  695. controlX + l,
  696. controlY + t,
  697. current[1] + l,
  698. current[2] + t,
  699. tempX + l,
  700. tempY + t
  701. );
  702. x = tempX;
  703. y = tempY;
  704. bounds.add(current[1], current[2]);
  705. bounds.add(controlX, controlY);
  706. bounds.add(tempX, tempY);
  707. // set control point to 2nd one of this command
  708. // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
  709. controlX = current[1];
  710. controlY = current[2];
  711. break;
  712. case 'q': // quadraticCurveTo, relative
  713. // transform to absolute x,y
  714. tempX = x + current[3];
  715. tempY = y + current[4];
  716. controlX = x + current[1];
  717. controlY = y + current[2];
  718. g.quadraticCurveTo(
  719. controlX + l,
  720. controlY + t,
  721. tempX + l,
  722. tempY + t
  723. );
  724. x = tempX;
  725. y = tempY;
  726. bounds.add(controlX, controlY);
  727. bounds.add(tempX, tempY);
  728. break;
  729. case 'Q': // quadraticCurveTo, absolute
  730. tempX = current[3];
  731. tempY = current[4];
  732. g.quadraticCurveTo(
  733. current[1] + l,
  734. current[2] + t,
  735. tempX + l,
  736. tempY + t
  737. );
  738. x = tempX;
  739. y = tempY;
  740. controlX = current[1];
  741. controlY = current[2];
  742. bounds.add(controlX, controlY);
  743. bounds.add(tempX, tempY);
  744. break;
  745. case 't': // shorthand quadraticCurveTo, relative
  746. // transform to absolute x,y
  747. tempX = x + current[1];
  748. tempY = y + current[2];
  749. if (previous[0].match(/[QqTt]/) === null) {
  750. // If there is no previous command or if the previous command was not a Q, q, T or t,
  751. // assume the control point is coincident with the current point
  752. controlX = x;
  753. controlY = y;
  754. }
  755. else if (previous[0] === 't') {
  756. // calculate reflection of previous control points for t
  757. controlX = 2 * x - tempControlX;
  758. controlY = 2 * y - tempControlY;
  759. }
  760. else if (previous[0] === 'q') {
  761. // calculate reflection of previous control points for q
  762. controlX = 2 * x - controlX;
  763. controlY = 2 * y - controlY;
  764. }
  765. tempControlX = controlX;
  766. tempControlY = controlY;
  767. g.quadraticCurveTo(
  768. controlX + l,
  769. controlY + t,
  770. tempX + l,
  771. tempY + t
  772. );
  773. x = tempX;
  774. y = tempY;
  775. controlX = x + current[1];
  776. controlY = y + current[2];
  777. bounds.add(controlX, controlY);
  778. bounds.add(tempX, tempY);
  779. break;
  780. case 'T':
  781. tempX = current[1];
  782. tempY = current[2];
  783. // calculate reflection of previous control points
  784. controlX = 2 * x - controlX;
  785. controlY = 2 * y - controlY;
  786. g.quadraticCurveTo(
  787. controlX + l,
  788. controlY + t,
  789. tempX + l,
  790. tempY + t
  791. );
  792. x = tempX;
  793. y = tempY;
  794. bounds.add(controlX, controlY);
  795. bounds.add(tempX, tempY);
  796. break;
  797. case 'a':
  798. drawArc(g, x + l, y + t, [
  799. current[1],
  800. current[2],
  801. current[3],
  802. current[4],
  803. current[5],
  804. current[6] + x + l,
  805. current[7] + y + t
  806. ], bounds, l, t);
  807. x += current[6];
  808. y += current[7];
  809. break;
  810. case 'A':
  811. drawArc(g, x + l, y + t, [
  812. current[1],
  813. current[2],
  814. current[3],
  815. current[4],
  816. current[5],
  817. current[6] + l,
  818. current[7] + t
  819. ], bounds, l, t);
  820. x = current[6];
  821. y = current[7];
  822. break;
  823. case 'z':
  824. case 'Z':
  825. g.closePath();
  826. break;
  827. }
  828. previous = current;
  829. }
  830. return bounds.translate(l, t);
  831. }
  832. function bounds(path, bounds) {
  833. var current, // current instruction
  834. previous = null,
  835. x = 0, // current x
  836. y = 0, // current y
  837. controlX = 0, // current control point x
  838. controlY = 0, // current control point y
  839. tempX,
  840. tempY,
  841. tempControlX,
  842. tempControlY;
  843. for (var i=0, len=path.length; i<len; ++i) {
  844. current = path[i];
  845. switch (current[0]) { // first letter
  846. case 'l': // lineto, relative
  847. x += current[1];
  848. y += current[2];
  849. bounds.add(x, y);
  850. break;
  851. case 'L': // lineto, absolute
  852. x = current[1];
  853. y = current[2];
  854. bounds.add(x, y);
  855. break;
  856. case 'h': // horizontal lineto, relative
  857. x += current[1];
  858. bounds.add(x, y);
  859. break;
  860. case 'H': // horizontal lineto, absolute
  861. x = current[1];
  862. bounds.add(x, y);
  863. break;
  864. case 'v': // vertical lineto, relative
  865. y += current[1];
  866. bounds.add(x, y);
  867. break;
  868. case 'V': // verical lineto, absolute
  869. y = current[1];
  870. bounds.add(x, y);
  871. break;
  872. case 'm': // moveTo, relative
  873. x += current[1];
  874. y += current[2];
  875. bounds.add(x, y);
  876. break;
  877. case 'M': // moveTo, absolute
  878. x = current[1];
  879. y = current[2];
  880. bounds.add(x, y);
  881. break;
  882. case 'c': // bezierCurveTo, relative
  883. tempX = x + current[5];
  884. tempY = y + current[6];
  885. controlX = x + current[3];
  886. controlY = y + current[4];
  887. bounds.add(x + current[1], y + current[2]);
  888. bounds.add(controlX, controlY);
  889. bounds.add(tempX, tempY);
  890. x = tempX;
  891. y = tempY;
  892. break;
  893. case 'C': // bezierCurveTo, absolute
  894. x = current[5];
  895. y = current[6];
  896. controlX = current[3];
  897. controlY = current[4];
  898. bounds.add(current[1], current[2]);
  899. bounds.add(controlX, controlY);
  900. bounds.add(x, y);
  901. break;
  902. case 's': // shorthand cubic bezierCurveTo, relative
  903. // transform to absolute x,y
  904. tempX = x + current[3];
  905. tempY = y + current[4];
  906. // calculate reflection of previous control points
  907. controlX = 2 * x - controlX;
  908. controlY = 2 * y - controlY;
  909. bounds.add(controlX, controlY);
  910. bounds.add(x + current[1], y + current[2]);
  911. bounds.add(tempX, tempY);
  912. // set control point to 2nd one of this command
  913. // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
  914. controlX = x + current[1];
  915. controlY = y + current[2];
  916. x = tempX;
  917. y = tempY;
  918. break;
  919. case 'S': // shorthand cubic bezierCurveTo, absolute
  920. tempX = current[3];
  921. tempY = current[4];
  922. // calculate reflection of previous control points
  923. controlX = 2*x - controlX;
  924. controlY = 2*y - controlY;
  925. x = tempX;
  926. y = tempY;
  927. bounds.add(current[1], current[2]);
  928. bounds.add(controlX, controlY);
  929. bounds.add(tempX, tempY);
  930. // set control point to 2nd one of this command
  931. // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
  932. controlX = current[1];
  933. controlY = current[2];
  934. break;
  935. case 'q': // quadraticCurveTo, relative
  936. // transform to absolute x,y
  937. tempX = x + current[3];
  938. tempY = y + current[4];
  939. controlX = x + current[1];
  940. controlY = y + current[2];
  941. x = tempX;
  942. y = tempY;
  943. bounds.add(controlX, controlY);
  944. bounds.add(tempX, tempY);
  945. break;
  946. case 'Q': // quadraticCurveTo, absolute
  947. tempX = current[3];
  948. tempY = current[4];
  949. x = tempX;
  950. y = tempY;
  951. controlX = current[1];
  952. controlY = current[2];
  953. bounds.add(controlX, controlY);
  954. bounds.add(tempX, tempY);
  955. break;
  956. case 't': // shorthand quadraticCurveTo, relative
  957. // transform to absolute x,y
  958. tempX = x + current[1];
  959. tempY = y + current[2];
  960. if (previous[0].match(/[QqTt]/) === null) {
  961. // If there is no previous command or if the previous command was not a Q, q, T or t,
  962. // assume the control point is coincident with the current point
  963. controlX = x;
  964. controlY = y;
  965. }
  966. else if (previous[0] === 't') {
  967. // calculate reflection of previous control points for t
  968. controlX = 2 * x - tempControlX;
  969. controlY = 2 * y - tempControlY;
  970. }
  971. else if (previous[0] === 'q') {
  972. // calculate reflection of previous control points for q
  973. controlX = 2 * x - controlX;
  974. controlY = 2 * y - controlY;
  975. }
  976. tempControlX = controlX;
  977. tempControlY = controlY;
  978. x = tempX;
  979. y = tempY;
  980. controlX = x + current[1];
  981. controlY = y + current[2];
  982. bounds.add(controlX, controlY);
  983. bounds.add(tempX, tempY);
  984. break;
  985. case 'T':
  986. tempX = current[1];
  987. tempY = current[2];
  988. // calculate reflection of previous control points
  989. controlX = 2 * x - controlX;
  990. controlY = 2 * y - controlY;
  991. x = tempX;
  992. y = tempY;
  993. bounds.add(controlX, controlY);
  994. bounds.add(tempX, tempY);
  995. break;
  996. case 'a':
  997. boundArc(x, y, [
  998. current[1],
  999. current[2],
  1000. current[3],
  1001. current[4],
  1002. current[5],
  1003. current[6] + x,
  1004. current[7] + y
  1005. ], bounds);
  1006. x += current[6];
  1007. y += current[7];
  1008. break;
  1009. case 'A':
  1010. boundArc(x, y, [
  1011. current[1],
  1012. current[2],
  1013. current[3],
  1014. current[4],
  1015. current[5],
  1016. current[6],
  1017. current[7]
  1018. ], bounds);
  1019. x = current[6];
  1020. y = current[7];
  1021. break;
  1022. case 'z':
  1023. case 'Z':
  1024. break;
  1025. }
  1026. previous = current;
  1027. }
  1028. return bounds;
  1029. }
  1030. function area(items) {
  1031. var o = items[0];
  1032. var area = d3.svg.area()
  1033. .x(function(d) { return d.x; })
  1034. .y1(function(d) { return d.y; })
  1035. .y0(function(d) { return d.y + d.height; });
  1036. if (o.interpolate) area.interpolate(o.interpolate);
  1037. if (o.tension != null) area.tension(o.tension);
  1038. return area(items);
  1039. }
  1040. function line(items) {
  1041. var o = items[0];
  1042. var line = d3.svg.line()
  1043. .x(function(d) { return d.x; })
  1044. .y(function(d) { return d.y; });
  1045. if (o.interpolate) line.interpolate(o.interpolate);
  1046. if (o.tension != null) line.tension(o.tension);
  1047. return line(items);
  1048. }
  1049. return {
  1050. parse: parse,
  1051. render: render,
  1052. bounds: bounds,
  1053. area: area,
  1054. line: line
  1055. };
  1056. })();vg.canvas.marks = (function() {
  1057. var parsePath = vg.canvas.path.parse,
  1058. renderPath = vg.canvas.path.render,
  1059. halfpi = Math.PI / 2,
  1060. sqrt3 = Math.sqrt(3),
  1061. tan30 = Math.tan(30 * Math.PI / 180),
  1062. tmpBounds = new vg.Bounds();
  1063. // path generators
  1064. function arcPath(g, o) {
  1065. var x = o.x || 0,
  1066. y = o.y || 0,
  1067. ir = o.innerRadius || 0,
  1068. or = o.outerRadius || 0,
  1069. sa = (o.startAngle || 0) - Math.PI/2,
  1070. ea = (o.endAngle || 0) - Math.PI/2;
  1071. g.beginPath();
  1072. if (ir === 0) g.moveTo(x, y);
  1073. else g.arc(x, y, ir, sa, ea, 0);
  1074. g.arc(x, y, or, ea, sa, 1);
  1075. g.closePath();
  1076. }
  1077. function pathPath(g, o) {
  1078. if (o.path == null) return;
  1079. if (!o["path:parsed"]) {
  1080. o["path:parsed"] = parsePath(o.path);
  1081. }
  1082. return renderPath(g, o["path:parsed"], o.x, o.y);
  1083. }
  1084. function symbolPath(g, o) {
  1085. g.beginPath();
  1086. var size = o.size != null ? o.size : 100,
  1087. x = o.x, y = o.y, r, t, rx, ry;
  1088. if (o.shape == null || o.shape === "circle") {
  1089. r = Math.sqrt(size/Math.PI);
  1090. g.arc(x, y, r, 0, 2*Math.PI, 0);
  1091. g.closePath();
  1092. return;
  1093. }
  1094. switch (o.shape) {
  1095. case "cross":
  1096. r = Math.sqrt(size / 5) / 2;
  1097. t = 3*r;
  1098. g.moveTo(x-t, y-r);
  1099. g.lineTo(x-r, y-r);
  1100. g.lineTo(x-r, y-t);
  1101. g.lineTo(x+r, y-t);
  1102. g.lineTo(x+r, y-r);
  1103. g.lineTo(x+t, y-r);
  1104. g.lineTo(x+t, y+r);
  1105. g.lineTo(x+r, y+r);
  1106. g.lineTo(x+r, y+t);
  1107. g.lineTo(x-r, y+t);
  1108. g.lineTo(x-r, y+r);
  1109. g.lineTo(x-t, y+r);
  1110. break;
  1111. case "diamond":
  1112. ry = Math.sqrt(size / (2 * tan30));
  1113. rx = ry * tan30;
  1114. g.moveTo(x, y-ry);
  1115. g.lineTo(x+rx, y);
  1116. g.lineTo(x, y+ry);
  1117. g.lineTo(x-rx, y);
  1118. break;
  1119. case "square":
  1120. t = Math.sqrt(size);
  1121. r = t / 2;
  1122. g.rect(x-r, y-r, t, t);
  1123. break;
  1124. case "triangle-down":
  1125. rx = Math.sqrt(size / sqrt3);
  1126. ry = rx * sqrt3 / 2;
  1127. g.moveTo(x, y+ry);
  1128. g.lineTo(x+rx, y-ry);
  1129. g.lineTo(x-rx, y-ry);
  1130. break;
  1131. case "triangle-up":
  1132. rx = Math.sqrt(size / sqrt3);
  1133. ry = rx * sqrt3 / 2;
  1134. g.moveTo(x, y-ry);
  1135. g.lineTo(x+rx, y+ry);
  1136. g.lineTo(x-rx, y+ry);
  1137. }
  1138. g.closePath();
  1139. }
  1140. function areaPath(g, items) {
  1141. var o = items[0],
  1142. p = o["path:parsed"] ||
  1143. (o["path:parsed"] = parsePath(vg.canvas.path.area(items)));
  1144. renderPath(g, p);
  1145. }
  1146. function linePath(g, items) {
  1147. var o = items[0],
  1148. p = o["path:parsed"] ||
  1149. (o["path:parsed"] = parsePath(vg.canvas.path.line(items)));
  1150. renderPath(g, p);
  1151. }
  1152. function lineStroke(g, items) {
  1153. var o = items[0],
  1154. lw = o.strokeWidth,
  1155. lc = o.strokeCap;
  1156. g.lineWidth = lw != null ? lw : vg.config.render.lineWidth;
  1157. g.lineCap = lc != null ? lc : vg.config.render.lineCap;
  1158. linePath(g, items);
  1159. }
  1160. function ruleStroke(g, o) {
  1161. var x1 = o.x || 0,
  1162. y1 = o.y || 0,
  1163. x2 = o.x2 != null ? o.x2 : x1,
  1164. y2 = o.y2 != null ? o.y2 : y1,
  1165. lw = o.strokeWidth,
  1166. lc = o.strokeCap;
  1167. g.lineWidth = lw != null ? lw : vg.config.render.lineWidth;
  1168. g.lineCap = lc != null ? lc : vg.config.render.lineCap;
  1169. g.beginPath();
  1170. g.moveTo(x1, y1);
  1171. g.lineTo(x2, y2);
  1172. }
  1173. // drawing functions
  1174. function drawPathOne(path, g, o, items) {
  1175. var fill = o.fill, stroke = o.stroke, opac, lc, lw;
  1176. path(g, items);
  1177. opac = o.opacity == null ? 1 : o.opacity;
  1178. if (opac == 0 || !fill && !stroke) return;
  1179. if (fill) {
  1180. g.globalAlpha = opac * (o.fillOpacity==null ? 1 : o.fillOpacity);
  1181. g.fillStyle = color(g, o, fill);
  1182. g.fill();
  1183. }
  1184. if (stroke) {
  1185. lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
  1186. if (lw > 0) {
  1187. g.globalAlpha = opac * (o.strokeOpacity==null ? 1 : o.strokeOpacity);
  1188. g.strokeStyle = color(g, o, stroke);
  1189. g.lineWidth = lw;
  1190. g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
  1191. g.vgLineDash(o.strokeDash || null);
  1192. g.vgLineDashOffset(o.strokeDashOffset || 0);
  1193. g.stroke();
  1194. }
  1195. }
  1196. }
  1197. function drawPathAll(path, g, scene, bounds) {
  1198. var i, len, item;
  1199. for (i=0, len=scene.items.length; i<len; ++i) {
  1200. item = scene.items[i];
  1201. if (bounds && !bounds.intersects(item.bounds))
  1202. continue; // bounds check
  1203. drawPathOne(path, g, item, item);
  1204. }
  1205. }
  1206. function drawRect(g, scene, bounds) {
  1207. if (!scene.items.length) return;
  1208. var items = scene.items,
  1209. o, fill, stroke, opac, lc, lw, x, y, w, h;
  1210. for (var i=0, len=items.length; i<len; ++i) {
  1211. o = items[i];
  1212. if (bounds && !bounds.intersects(o.bounds))
  1213. continue; // bounds check
  1214. x = o.x || 0;
  1215. y = o.y || 0;
  1216. w = o.width || 0;
  1217. h = o.height || 0;
  1218. opac = o.opacity == null ? 1 : o.opacity;
  1219. if (opac == 0) return;
  1220. if (fill = o.fill) {
  1221. g.globalAlpha = opac * (o.fillOpacity==null ? 1 : o.fillOpacity);
  1222. g.fillStyle = color(g, o, fill);
  1223. g.fillRect(x, y, w, h);
  1224. }
  1225. if (stroke = o.stroke) {
  1226. lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
  1227. if (lw > 0) {
  1228. g.globalAlpha = opac * (o.strokeOpacity==null ? 1 : o.strokeOpacity);
  1229. g.strokeStyle = color(g, o, stroke);
  1230. g.lineWidth = lw;
  1231. g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
  1232. g.vgLineDash(o.strokeDash || null);
  1233. g.vgLineDashOffset(o.strokeDashOffset || 0);
  1234. g.strokeRect(x, y, w, h);
  1235. }
  1236. }
  1237. }
  1238. }
  1239. function drawRule(g, scene, bounds) {
  1240. if (!scene.items.length) return;
  1241. var items = scene.items,
  1242. o, stroke, opac, lc, lw, x1, y1, x2, y2;
  1243. for (var i=0, len=items.length; i<len; ++i) {
  1244. o = items[i];
  1245. if (bounds && !bounds.intersects(o.bounds))
  1246. continue; // bounds check
  1247. x1 = o.x || 0;
  1248. y1 = o.y || 0;
  1249. x2 = o.x2 != null ? o.x2 : x1;
  1250. y2 = o.y2 != null ? o.y2 : y1;
  1251. opac = o.opacity == null ? 1 : o.opacity;
  1252. if (opac == 0) return;
  1253. if (stroke = o.stroke) {
  1254. lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
  1255. if (lw > 0) {
  1256. g.globalAlpha = opac * (o.strokeOpacity==null ? 1 : o.strokeOpacity);
  1257. g.strokeStyle = color(g, o, stroke);
  1258. g.lineWidth = lw;
  1259. g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
  1260. g.vgLineDash(o.strokeDash || null);
  1261. g.vgLineDashOffset(o.strokeDashOffset || 0);
  1262. g.beginPath();
  1263. g.moveTo(x1, y1);
  1264. g.lineTo(x2, y2);
  1265. g.stroke();
  1266. }
  1267. }
  1268. }
  1269. }
  1270. function drawImage(g, scene, bounds) {
  1271. if (!scene.items.length) return;
  1272. var renderer = this,
  1273. items = scene.items, o;
  1274. for (var i=0, len=items.length; i<len; ++i) {
  1275. o = items[i];
  1276. if (bounds && !bounds.intersects(o.bounds))
  1277. continue; // bounds check
  1278. if (!(o.image && o.image.url === o.url)) {
  1279. o.image = renderer.loadImage(o.url);
  1280. o.image.url = o.url;
  1281. }
  1282. var x, y, w, h, opac;
  1283. w = o.width || (o.image && o.image.width) || 0;
  1284. h = o.height || (o.image && o.image.height) || 0;
  1285. x = (o.x||0) - (o.align === "center"
  1286. ? w/2 : (o.align === "right" ? w : 0));
  1287. y = (o.y||0) - (o.baseline === "middle"
  1288. ? h/2 : (o.baseline === "bottom" ? h : 0));
  1289. if (o.image.loaded) {
  1290. g.globalAlpha = (opac = o.opacity) != null ? opac : 1;
  1291. g.drawImage(o.image, x, y, w, h);
  1292. }
  1293. }
  1294. }
  1295. function drawText(g, scene, bounds) {
  1296. if (!scene.items.length) return;
  1297. var items = scene.items,
  1298. o, fill, stroke, opac, lw, text, ta, tb;
  1299. for (var i=0, len=items.length; i<len; ++i) {
  1300. o = items[i];
  1301. if (bounds && !bounds.intersects(o.bounds))
  1302. continue; // bounds check
  1303. g.font = vg.scene.fontString(o);
  1304. g.textAlign = o.align || "left";
  1305. g.textBaseline = o.baseline || "alphabetic";
  1306. opac = o.opacity == null ? 1 : o.opacity;
  1307. if (opac == 0) return;
  1308. if (o.angle) {
  1309. g.save();
  1310. g.translate(o.x || 0, o.y || 0);
  1311. g.rotate(o.angle * Math.PI/180);
  1312. x = o.dx || 0;
  1313. y = o.dy || 0;
  1314. } else {
  1315. x = (o.x || 0) + (o.dx || 0);
  1316. y = (o.y || 0) + (o.dy || 0);
  1317. }
  1318. if (fill = o.fill) {
  1319. g.globalAlpha = opac * (o.fillOpacity==null ? 1 : o.fillOpacity);
  1320. g.fillStyle = color(g, o, fill);
  1321. g.fillText(o.text, x, y);
  1322. }
  1323. if (stroke = o.stroke) {
  1324. lw = (lw = o.strokeWidth) != null ? lw : 1;
  1325. if (lw > 0) {
  1326. g.globalAlpha = opac * (o.strokeOpacity==null ? 1 : o.strokeOpacity);
  1327. g.strokeStyle = color(o, stroke);
  1328. g.lineWidth = lw;
  1329. g.strokeText(o.text, x, y);
  1330. }
  1331. }
  1332. if (o.angle) g.restore();
  1333. }
  1334. }
  1335. function drawAll(pathFunc) {
  1336. return function(g, scene, bounds) {
  1337. drawPathAll(pathFunc, g, scene, bounds);
  1338. }
  1339. }
  1340. function drawOne(pathFunc) {
  1341. return function(g, scene, bounds) {
  1342. if (!scene.items.length) return;
  1343. if (bounds && !bounds.intersects(scene.items[0].bounds))
  1344. return; // bounds check
  1345. drawPathOne(pathFunc, g, scene.items[0], scene.items);
  1346. }
  1347. }
  1348. function drawGroup(g, scene, bounds) {
  1349. if (!scene.items.length) return;
  1350. var items = scene.items, group, axes, legends,
  1351. renderer = this, gx, gy, gb, i, n, j, m;
  1352. drawRect(g, scene, bounds);
  1353. for (i=0, n=items.length; i<n; ++i) {
  1354. group = items[i];
  1355. axes = group.axisItems || [];
  1356. legends = group.legendItems || [];
  1357. gx = group.x || 0;
  1358. gy = group.y || 0;
  1359. // render group contents
  1360. g.save();
  1361. g.translate(gx, gy);
  1362. if (bounds) bounds.translate(-gx, -gy);
  1363. for (j=0, m=axes.length; j<m; ++j) {
  1364. if (axes[j].def.layer === "back") {
  1365. renderer.draw(g, axes[j], bounds);
  1366. }
  1367. }
  1368. for (j=0, m=group.items.length; j<m; ++j) {
  1369. renderer.draw(g, group.items[j], bounds);
  1370. }
  1371. for (j=0, m=axes.length; j<m; ++j) {
  1372. if (axes[j].def.layer !== "back") {
  1373. renderer.draw(g, axes[j], bounds);
  1374. }
  1375. }
  1376. for (j=0, m=legends.length; j<m; ++j) {
  1377. renderer.draw(g, legends[j], bounds);
  1378. }
  1379. if (bounds) bounds.translate(gx, gy);
  1380. g.restore();
  1381. }
  1382. }
  1383. function color(g, o, value) {
  1384. return (value.id)
  1385. ? gradient(g, value, o.bounds)
  1386. : value;
  1387. }
  1388. function gradient(g, p, b) {
  1389. var w = b.width(),
  1390. h = b.height(),
  1391. x1 = b.x1 + p.x1 * w,
  1392. y1 = b.y1 + p.y1 * h,
  1393. x2 = b.x1 + p.x2 * w,
  1394. y2 = b.y1 + p.y2 * h,
  1395. grad = g.createLinearGradient(x1, y1, x2, y2),
  1396. stop = p.stops,
  1397. i, n;
  1398. for (i=0, n=stop.length; i<n; ++i) {
  1399. grad.addColorStop(stop[i].offset, stop[i].color);
  1400. }
  1401. return grad;
  1402. }
  1403. // hit testing
  1404. function pickGroup(g, scene, x, y, gx, gy) {
  1405. if (scene.items.length === 0 ||
  1406. scene.bounds && !scene.bounds.contains(gx, gy)) {
  1407. return false;
  1408. }
  1409. var items = scene.items, subscene, group, hit, dx, dy,
  1410. handler = this, i, j;
  1411. for (i=items.length; --i>=0;) {
  1412. group = items[i];
  1413. dx = group.x || 0;
  1414. dy = group.y || 0;
  1415. g.save();
  1416. g.translate(dx, dy);
  1417. for (j=group.items.length; --j >= 0;) {
  1418. subscene = group.items[j];
  1419. if (subscene.interactive === false) continue;
  1420. hit = handler.pick(subscene, x, y, gx-dx, gy-dy);
  1421. if (hit) {
  1422. g.restore();
  1423. return hit;
  1424. }
  1425. }
  1426. g.restore();
  1427. }
  1428. return scene.interactive
  1429. ? pickAll(hitTests.rect, g, scene, x, y, gx, gy)
  1430. : false;
  1431. }
  1432. function pickAll(test, g, scene, x, y, gx, gy) {
  1433. if (!scene.items.length) return false;
  1434. var o, b, i;
  1435. if (g._ratio !== 1) {
  1436. x *= g._ratio;
  1437. y *= g._ratio;
  1438. }
  1439. for (i=scene.items.length; --i >= 0;) {
  1440. o = scene.items[i]; b = o.bounds;
  1441. // first hit test against bounding box
  1442. if ((b && !b.contains(gx, gy)) || !b) continue;
  1443. // if in bounding box, perform more careful test
  1444. if (test(g, o, x, y, gx, gy)) return o;
  1445. }
  1446. return false;
  1447. }
  1448. function pickArea(g, scene, x, y, gx, gy) {
  1449. if (!scene.items.length) return false;
  1450. var items = scene.items,
  1451. o, b, i, di, dd, od, dx, dy;
  1452. b = items[0].bounds;
  1453. if (b && !b.contains(gx, gy)) return false;
  1454. if (g._ratio !== 1) {
  1455. x *= g._ratio;
  1456. y *= g._ratio;
  1457. }
  1458. if (!hitTests.area(g, items, x, y)) return false;
  1459. return items[0];
  1460. }
  1461. function pickLine(g, scene, x, y, gx, gy) {
  1462. if (!scene.items.length) return false;
  1463. var items = scene.items,
  1464. o, b, i, di, dd, od, dx, dy;
  1465. b = items[0].bounds;
  1466. if (b && !b.contains(gx, gy)) return false;
  1467. if (g._ratio !== 1) {
  1468. x *= g._ratio;
  1469. y *= g._ratio;
  1470. }
  1471. if (!hitTests.line(g, items, x, y)) return false;
  1472. return items[0];
  1473. }
  1474. function pick(test) {
  1475. return function (g, scene, x, y, gx, gy) {
  1476. return pickAll(test, g, scene, x, y, gx, gy);
  1477. };
  1478. }
  1479. function textHit(g, o, x, y, gx, gy) {
  1480. if (!o.fontSize) return false;
  1481. if (!o.angle) return true; // bounds sufficient if no rotation
  1482. var b = vg.scene.bounds.text(o, tmpBounds, true),
  1483. a = -o.angle * Math.PI / 180,
  1484. cos = Math.cos(a),
  1485. sin = Math.sin(a),
  1486. x = o.x,
  1487. y = o.y,
  1488. px = cos*gx - sin*gy + (x - x*cos + y*sin),
  1489. py = sin*gx + cos*gy + (y - x*sin - y*cos);
  1490. return b.contains(px, py);
  1491. }
  1492. var hitTests = {
  1493. text: textHit,
  1494. rect: function(g,o,x,y) { return true; }, // bounds test is sufficient
  1495. image: function(g,o,x,y) { return true; }, // bounds test is sufficient
  1496. rule: function(g,o,x,y) {
  1497. if (!g.isPointInStroke) return false;
  1498. ruleStroke(g,o); return g.isPointInStroke(x,y);
  1499. },
  1500. line: function(g,s,x,y) {
  1501. if (!g.isPointInStroke) return false;
  1502. lineStroke(g,s); return g.isPointInStroke(x,y);
  1503. },
  1504. arc: function(g,o,x,y) { arcPath(g,o); return g.isPointInPath(x,y); },
  1505. area: function(g,s,x,y) { areaPath(g,s); return g.isPointInPath(x,y); },
  1506. path: function(g,o,x,y) { pathPath(g,o); return g.isPointInPath(x,y); },
  1507. symbol: function(g,o,x,y) { symbolPath(g,o); return g.isPointInPath(x,y); }
  1508. };
  1509. return {
  1510. draw: {
  1511. group: drawGroup,
  1512. area: drawOne(areaPath),
  1513. line: drawOne(linePath),
  1514. arc: drawAll(arcPath),
  1515. path: drawAll(pathPath),
  1516. symbol: drawAll(symbolPath),
  1517. rect: drawRect,
  1518. rule: drawRule,
  1519. text: drawText,
  1520. image: drawImage,
  1521. drawOne: drawOne, // expose for extensibility
  1522. drawAll: drawAll // expose for extensibility
  1523. },
  1524. pick: {
  1525. group: pickGroup,
  1526. area: pickArea,
  1527. line: pickLine,
  1528. arc: pick(hitTests.arc),
  1529. path: pick(hitTests.path),
  1530. symbol: pick(hitTests.symbol),
  1531. rect: pick(hitTests.rect),
  1532. rule: pick(hitTests.rule),
  1533. text: pick(hitTests.text),
  1534. image: pick(hitTests.image),
  1535. pickAll: pickAll // expose for extensibility
  1536. }
  1537. };
  1538. })();vg.canvas.Renderer = (function() {
  1539. var renderer = function() {
  1540. this._ctx = null;
  1541. this._el = null;
  1542. this._imgload = 0;
  1543. };
  1544. var prototype = renderer.prototype;
  1545. prototype.initialize = function(el, width, height, pad) {
  1546. this._el = el;
  1547. if (!el) return this; // early exit if no DOM element
  1548. // select canvas element
  1549. var canvas = d3.select(el)
  1550. .selectAll("canvas.marks")
  1551. .data([1]);
  1552. // create new canvas element if needed
  1553. canvas.enter()
  1554. .append("canvas")
  1555. .attr("class", "marks");
  1556. // remove extraneous canvas if needed
  1557. canvas.exit().remove();
  1558. return this.resize(width, height, pad);
  1559. };
  1560. prototype.resize = function(width, height, pad) {
  1561. this._width = width;
  1562. this._height = height;
  1563. this._padding = pad;
  1564. if (this._el) {
  1565. var canvas = d3.select(this._el).select("canvas.marks");
  1566. // initialize canvas attributes
  1567. canvas
  1568. .attr("width", width + pad.left + pad.right)
  1569. .attr("height", height + pad.top + pad.bottom);
  1570. // get the canvas graphics context
  1571. var s;
  1572. this._ctx = canvas.node().getContext("2d");
  1573. this._ctx._ratio = (s = scaleCanvas(canvas.node(), this._ctx) || 1);
  1574. this._ctx.setTransform(s, 0, 0, s, s*pad.left, s*pad.top);
  1575. }
  1576. initializeLineDash(this._ctx);
  1577. return this;
  1578. };
  1579. function scaleCanvas(canvas, ctx) {
  1580. // get canvas pixel data
  1581. var devicePixelRatio = window.devicePixelRatio || 1,
  1582. backingStoreRatio = (
  1583. ctx.webkitBackingStorePixelRatio ||
  1584. ctx.mozBackingStorePixelRatio ||
  1585. ctx.msBackingStorePixelRatio ||
  1586. ctx.oBackingStorePixelRatio ||
  1587. ctx.backingStorePixelRatio) || 1,
  1588. ratio = devicePixelRatio / backingStoreRatio;
  1589. if (devicePixelRatio !== backingStoreRatio) {
  1590. var w = canvas.width, h = canvas.height;
  1591. // set actual and visible canvas size
  1592. canvas.setAttribute("width", w * ratio);
  1593. canvas.setAttribute("height", h * ratio);
  1594. canvas.style.width = w + 'px';
  1595. canvas.style.height = h + 'px';
  1596. }
  1597. return ratio;
  1598. }
  1599. function initializeLineDash(ctx) {
  1600. if (ctx.vgLineDash) return; // already set
  1601. var NODASH = [];
  1602. if (ctx.setLineDash) {
  1603. ctx.vgLineDash = function(dash) { this.setLineDash(dash || NODASH); };
  1604. ctx.vgLineDashOffset = function(off) { this.lineDashOffset = off; };
  1605. } else if (ctx.webkitLineDash !== undefined) {
  1606. ctx.vgLineDash = function(dash) { this.webkitLineDash = dash || NODASH; };
  1607. ctx.vgLineDashOffset = function(off) { this.webkitLineDashOffset = off; };
  1608. } else if (ctx.mozDash !== undefined) {
  1609. ctx.vgLineDash = function(dash) { this.mozDash = dash; };
  1610. ctx.vgLineDashOffset = function(off) { /* unsupported */ };
  1611. } else {
  1612. ctx.vgLineDash = function(dash) { /* unsupported */ };
  1613. ctx.vgLineDashOffset = function(off) { /* unsupported */ };
  1614. }
  1615. }
  1616. prototype.context = function(ctx) {
  1617. if (ctx) { this._ctx = ctx; return this; }
  1618. else return this._ctx;
  1619. };
  1620. prototype.element = function() {
  1621. return this._el;
  1622. };
  1623. prototype.pendingImages = function() {
  1624. return this._imgload;
  1625. };
  1626. function translatedBounds(item, bounds) {
  1627. var b = new vg.Bounds(bounds);
  1628. while ((item = item.mark.group) != null) {
  1629. b.translate(item.x || 0, item.y || 0);
  1630. }
  1631. return b;
  1632. }
  1633. function getBounds(items) {
  1634. return !items ? null :
  1635. vg.array(items).reduce(function(b, item) {
  1636. return b.union(translatedBounds(item, item.bounds))
  1637. .union(translatedBounds(item, item['bounds:prev']));
  1638. }, new vg.Bounds());
  1639. }
  1640. function setBounds(g, bounds) {
  1641. var bbox = null;
  1642. if (bounds) {
  1643. bbox = (new vg.Bounds(bounds)).round();
  1644. g.beginPath();
  1645. g.rect(bbox.x1, bbox.y1, bbox.width(), bbox.height());
  1646. g.clip();
  1647. }
  1648. return bbox;
  1649. }
  1650. prototype.render = function(scene, items) {
  1651. var g = this._ctx,
  1652. pad = this._padding,
  1653. w = this._width + pad.left + pad.right,
  1654. h = this._height + pad.top + pad.bottom,
  1655. bb = null, bb2;
  1656. // setup
  1657. this._scene = scene;
  1658. g.save();
  1659. bb = setBounds(g, getBounds(items));
  1660. g.clearRect(-pad.left, -pad.top, w, h);
  1661. // render
  1662. this.draw(g, scene, bb);
  1663. // render again to handle possible bounds change
  1664. if (items) {
  1665. g.restore();
  1666. g.save();
  1667. bb2 = setBounds(g, getBounds(items));
  1668. if (!bb.encloses(bb2)) {
  1669. g.clearRect(-pad.left, -pad.top, w, h);
  1670. this.draw(g, scene, bb2);
  1671. }
  1672. }
  1673. // takedown
  1674. g.restore();
  1675. this._scene = null;
  1676. };
  1677. prototype.draw = function(ctx, scene, bounds) {
  1678. var marktype = scene.marktype,
  1679. renderer = vg.canvas.marks.draw[marktype];
  1680. renderer.call(this, ctx, scene, bounds);
  1681. // compute mark-level bounds
  1682. scene.bounds = scene.items.reduce(function(b, item) {
  1683. return item.bounds ? b.union(item.bounds) : b;
  1684. }, scene.bounds || new vg.Bounds());
  1685. };
  1686. prototype.renderAsync = function(scene) {
  1687. // TODO make safe for multiple scene rendering?
  1688. var renderer = this;
  1689. if (renderer._async_id) {
  1690. clearTimeout(renderer._async_id);
  1691. }
  1692. renderer._async_id = setTimeout(function() {
  1693. renderer.render(scene);
  1694. delete renderer._async_id;
  1695. }, 50);
  1696. };
  1697. prototype.loadImage = function(uri) {
  1698. var renderer = this,
  1699. scene = renderer._scene,
  1700. image = null, url;
  1701. renderer._imgload += 1;
  1702. if (vg.config.isNode) {
  1703. image = new (require("canvas").Image)();
  1704. vg.data.load(uri, function(err, data) {
  1705. if (err) { vg.error(err); return; }
  1706. image.src = data;
  1707. image.loaded = true;
  1708. renderer._imgload -= 1;
  1709. });
  1710. } else {
  1711. image = new Image();
  1712. url = vg.config.baseURL + uri;
  1713. image.onload = function() {
  1714. vg.log("LOAD IMAGE: "+url);
  1715. image.loaded = true;
  1716. renderer._imgload -= 1;
  1717. renderer.renderAsync(scene);
  1718. };
  1719. image.src = url;
  1720. }
  1721. return image;
  1722. };
  1723. return renderer;
  1724. })();vg.canvas.Handler = (function() {
  1725. var handler = function(el, model) {
  1726. this._active = null;
  1727. this._handlers = {};
  1728. if (el) this.initialize(el);
  1729. if (model) this.model(model);
  1730. };
  1731. var prototype = handler.prototype;
  1732. prototype.initialize = function(el, pad, obj) {
  1733. this._el = d3.select(el).node();
  1734. this._canvas = d3.select(el).select("canvas.marks").node();
  1735. this._padding = pad;
  1736. this._obj = obj || null;
  1737. // add event listeners
  1738. var canvas = this._canvas, that = this;
  1739. events.forEach(function(type) {
  1740. canvas.addEventListener(type, function(evt) {
  1741. prototype[type].call(that, evt);
  1742. });
  1743. });
  1744. return this;
  1745. };
  1746. prototype.padding = function(pad) {
  1747. this._padding = pad;
  1748. return this;
  1749. };
  1750. prototype.model = function(model) {
  1751. if (!arguments.length) return this._model;
  1752. this._model = model;
  1753. return this;
  1754. };
  1755. prototype.handlers = function() {
  1756. var h = this._handlers;
  1757. return vg.keys(h).reduce(function(a, k) {
  1758. return h[k].reduce(function(a, x) { return (a.push(x), a); }, a);
  1759. }, []);
  1760. };
  1761. // setup events
  1762. var events = [
  1763. "mousedown",
  1764. "mouseup",
  1765. "click",
  1766. "dblclick",
  1767. "wheel",
  1768. "keydown",
  1769. "keypress",
  1770. "keyup",
  1771. "mousewheel"
  1772. ];
  1773. events.forEach(function(type) {
  1774. prototype[type] = function(evt) {
  1775. this.fire(type, evt);
  1776. };
  1777. });
  1778. events.push("mousemove");
  1779. events.push("mouseout");
  1780. function eventName(name) {
  1781. var i = name.indexOf(".");
  1782. return i < 0 ? name : name.slice(0,i);
  1783. }
  1784. prototype.mousemove = function(evt) {
  1785. var pad = this._padding,
  1786. b = evt.target.getBoundingClientRect(),
  1787. x = evt.clientX - b.left,
  1788. y = evt.clientY - b.top,
  1789. a = this._active,
  1790. p = this.pick(this._model.scene(), x, y, x-pad.left, y-pad.top);
  1791. if (p === a) {
  1792. this.fire("mousemove", evt);
  1793. return;
  1794. } else if (a) {
  1795. this.fire("mouseout", evt);
  1796. }
  1797. this._active = p;
  1798. if (p) {
  1799. this.fire("mouseover", evt);
  1800. }
  1801. };
  1802. prototype.mouseout = function(evt) {
  1803. if (this._active) {
  1804. this.fire("mouseout", evt);
  1805. }
  1806. this._active = null;
  1807. };
  1808. // to keep firefox happy
  1809. prototype.DOMMouseScroll = function(evt) {
  1810. this.fire("mousewheel", evt);
  1811. };
  1812. // fire an event
  1813. prototype.fire = function(type, evt) {
  1814. var a = this._active,
  1815. h = this._handlers[type];
  1816. if (a && h) {
  1817. for (var i=0, len=h.length; i<len; ++i) {
  1818. h[i].handler.call(this._obj, evt, a);
  1819. }
  1820. }
  1821. };
  1822. // add an event handler
  1823. prototype.on = function(type, handler) {
  1824. var name = eventName(type),
  1825. h = this._handlers;
  1826. h = h[name] || (h[name] = []);
  1827. h.push({
  1828. type: type,
  1829. handler: handler
  1830. });
  1831. return this;
  1832. };
  1833. // remove an event handler
  1834. prototype.off = function(type, handler) {
  1835. var name = eventName(type),
  1836. h = this._handlers[name];
  1837. if (!h) return;
  1838. for (var i=h.length; --i>=0;) {
  1839. if (h[i].type !== type) continue;
  1840. if (!handler || h[i].handler === handler) h.splice(i, 1);
  1841. }
  1842. return this;
  1843. };
  1844. // retrieve the current canvas context
  1845. prototype.context = function() {
  1846. return this._canvas.getContext("2d");
  1847. };
  1848. // find the scenegraph item at the current mouse position
  1849. // returns an array of scenegraph items, from leaf node up to the root
  1850. // x, y -- the absolute x, y mouse coordinates on the canvas element
  1851. // gx, gy -- the relative coordinates within the current group
  1852. prototype.pick = function(scene, x, y, gx, gy) {
  1853. var g = this.context(),
  1854. marktype = scene.marktype,
  1855. picker = vg.canvas.marks.pick[marktype];
  1856. return picker.call(this, g, scene, x, y, gx, gy);
  1857. };
  1858. return handler;
  1859. })();vg.svg = {};vg.svg.marks = (function() {
  1860. function x(o) { return o.x || 0; }
  1861. function y(o) { return o.y || 0; }
  1862. function yh(o) { return o.y + o.height || 0; }
  1863. function key(o) { return o.key; }
  1864. function size(o) { return o.size==null ? 100 : o.size; }
  1865. function shape(o) { return o.shape || "circle"; }
  1866. var arc_path = d3.svg.arc(),
  1867. area_path = d3.svg.area().x(x).y1(y).y0(yh),
  1868. line_path = d3.svg.line().x(x).y(y),
  1869. symbol_path = d3.svg.symbol().type(shape).size(size);
  1870. var mark_id = 0;
  1871. var textAlign = {
  1872. "left": "start",
  1873. "center": "middle",
  1874. "right": "end"
  1875. };
  1876. var styles = {
  1877. "fill": "fill",
  1878. "fillOpacity": "fill-opacity",
  1879. "stroke": "stroke",
  1880. "strokeWidth": "stroke-width",
  1881. "strokeOpacity": "stroke-opacity",
  1882. "strokeCap": "stroke-linecap",
  1883. "strokeDash": "stroke-dasharray",
  1884. "strokeDashOffset": "stroke-dashoffset",
  1885. "opacity": "opacity"
  1886. };
  1887. var styleProps = vg.keys(styles);
  1888. function style(d) {
  1889. var i, n, prop, name, value,
  1890. o = d.mark ? d : d.length ? d[0] : null;
  1891. if (o === null) return;
  1892. for (i=0, n=styleProps.length; i<n; ++i) {
  1893. prop = styleProps[i];
  1894. name = styles[prop];
  1895. value = o[prop];
  1896. if (value == null) {
  1897. if (name === "fill") this.style.setProperty(name, "none", null);
  1898. else this.style.removeProperty(name);
  1899. } else {
  1900. if (value.id) {
  1901. // ensure definition is included
  1902. vg.svg._cur._defs[value.id] = value;
  1903. value = "url(#" + value.id + ")";
  1904. }
  1905. this.style.setProperty(name, value+"", null);
  1906. }
  1907. }
  1908. }
  1909. function arc(o) {
  1910. var x = o.x || 0,
  1911. y = o.y || 0;
  1912. this.setAttribute("transform", "translate("+x+","+y+")");
  1913. this.setAttribute("d", arc_path(o));
  1914. }
  1915. function area(items) {
  1916. if (!items.length) return;
  1917. var o = items[0];
  1918. area_path
  1919. .interpolate(o.interpolate || "linear")
  1920. .tension(o.tension == null ? 0.7 : o.tension);
  1921. this.setAttribute("d", area_path(items));
  1922. }
  1923. function line(items) {
  1924. if (!items.length) return;
  1925. var o = items[0];
  1926. line_path
  1927. .interpolate(o.interpolate || "linear")
  1928. .tension(o.tension == null ? 0.7 : o.tension);
  1929. this.setAttribute("d", line_path(items));
  1930. }
  1931. function path(o) {
  1932. var x = o.x || 0,
  1933. y = o.y || 0;
  1934. this.setAttribute("transform", "translate("+x+","+y+")");
  1935. if (o.path != null) this.setAttribute("d", o.path);
  1936. }
  1937. function rect(o) {
  1938. this.setAttribute("x", o.x || 0);
  1939. this.setAttribute("y", o.y || 0);
  1940. this.setAttribute("width", o.width || 0);
  1941. this.setAttribute("height", o.height || 0);
  1942. }
  1943. function rule(o) {
  1944. var x1 = o.x || 0,
  1945. y1 = o.y || 0;
  1946. this.setAttribute("x1", x1);
  1947. this.setAttribute("y1", y1);
  1948. this.setAttribute("x2", o.x2 != null ? o.x2 : x1);
  1949. this.setAttribute("y2", o.y2 != null ? o.y2 : y1);
  1950. }
  1951. function symbol(o) {
  1952. var x = o.x || 0,
  1953. y = o.y || 0;
  1954. this.setAttribute("transform", "translate("+x+","+y+")");
  1955. this.setAttribute("d", symbol_path(o));
  1956. }
  1957. function image(o) {
  1958. var w = o.width || (o.image && o.image.width) || 0,
  1959. h = o.height || (o.image && o.image.height) || 0,
  1960. x = o.x - (o.align === "center"
  1961. ? w/2 : (o.align === "right" ? w : 0)),
  1962. y = o.y - (o.baseline === "middle"
  1963. ? h/2 : (o.baseline === "bottom" ? h : 0)),
  1964. url = vg.config.baseURL + o.url;
  1965. this.setAttributeNS("http://www.w3.org/1999/xlink", "href", url);
  1966. this.setAttribute("x", x);
  1967. this.setAttribute("y", y);
  1968. this.setAttribute("width", w);
  1969. this.setAttribute("height", h);
  1970. }
  1971. function fontString(o) {
  1972. return (o.fontStyle ? o.fontStyle + " " : "")
  1973. + (o.fontVariant ? o.fontVariant + " " : "")
  1974. + (o.fontWeight ? o.fontWeight + " " : "")
  1975. + (o.fontSize != null ? o.fontSize : vg.config.render.fontSize) + "px "
  1976. + (o.font || vg.config.render.font);
  1977. }
  1978. function text(o) {
  1979. var x = o.x || 0,
  1980. y = o.y || 0,
  1981. dx = o.dx || 0,
  1982. dy = o.dy || 0,
  1983. a = o.angle || 0,
  1984. align = textAlign[o.align || "left"],
  1985. base = o.baseline==="top" ? ".9em"
  1986. : o.baseline==="middle" ? ".35em" : 0;
  1987. this.setAttribute("x", x + dx);
  1988. this.setAttribute("y", y + dy);
  1989. this.setAttribute("dy", dy);
  1990. this.setAttribute("text-anchor", align);
  1991. if (a) this.setAttribute("transform", "rotate("+a+" "+x+","+y+")");
  1992. else this.removeAttribute("transform");
  1993. if (base) this.setAttribute("dy", base);
  1994. else this.removeAttribute("dy");
  1995. this.textContent = o.text;
  1996. this.style.setProperty("font", fontString(o), null);
  1997. }
  1998. function group(o) {
  1999. var x = o.x || 0,
  2000. y = o.y || 0;
  2001. this.setAttribute("transform", "translate("+x+","+y+")");
  2002. }
  2003. function group_bg(o) {
  2004. var w = o.width || 0,
  2005. h = o.height || 0;
  2006. this.setAttribute("width", w);
  2007. this.setAttribute("height", h);
  2008. }
  2009. function draw(tag, attr, nest) {
  2010. return function(g, scene, index) {
  2011. drawMark(g, scene, index, "mark_", tag, attr, nest);
  2012. };
  2013. }
  2014. function drawMark(g, scene, index, prefix, tag, attr, nest) {
  2015. var data = nest ? [scene.items] : scene.items,
  2016. evts = scene.interactive===false ? "none" : null,
  2017. grps = g.node().childNodes,
  2018. notG = (tag !== "g"),
  2019. p = (p = grps[index+1]) // +1 to skip group background rect
  2020. ? d3.select(p)
  2021. : g.append("g").attr("id", "g"+(++mark_id));
  2022. var id = "#" + p.attr("id"),
  2023. s = id + " > " + tag,
  2024. m = p.selectAll(s).data(data),
  2025. e = m.enter().append(tag);
  2026. if (notG) {
  2027. p.style("pointer-events", evts);
  2028. e.each(function(d) {
  2029. if (d.mark) d._svg = this;
  2030. else if (d.length) d[0]._svg = this;
  2031. });
  2032. } else {
  2033. e.append("rect").attr("class","background").style("pointer-events",evts);
  2034. }
  2035. m.exit().remove();
  2036. m.each(attr);
  2037. if (notG) m.each(style);
  2038. else p.selectAll(s+" > rect.background").each(group_bg).each(style);
  2039. return p;
  2040. }
  2041. function drawGroup(g, scene, index, prefix) {
  2042. var p = drawMark(g, scene, index, prefix || "group_", "g", group),
  2043. c = p.node().childNodes, n = c.length, i, j, m;
  2044. for (i=0; i<n; ++i) {
  2045. var items = c[i].__data__.items,
  2046. legends = c[i].__data__.legendItems || [],
  2047. axes = c[i].__data__.axisItems || [],
  2048. sel = d3.select(c[i]),
  2049. idx = 0;
  2050. for (j=0, m=axes.length; j<m; ++j) {
  2051. if (axes[j].def.layer === "back") {
  2052. drawGroup.call(this, sel, axes[j], idx++, "axis_");
  2053. }
  2054. }
  2055. for (j=0, m=items.length; j<m; ++j) {
  2056. this.draw(sel, items[j], idx++);
  2057. }
  2058. for (j=0, m=axes.length; j<m; ++j) {
  2059. if (axes[j].def.layer !== "back") {
  2060. drawGroup.call(this, sel, axes[j], idx++, "axis_");
  2061. }
  2062. }
  2063. for (j=0, m=legends.length; j<m; ++j) {
  2064. drawGroup.call(this, sel, legends[j], idx++, "legend_");
  2065. }
  2066. }
  2067. }
  2068. return {
  2069. update: {
  2070. group: rect,
  2071. area: area,
  2072. line: line,
  2073. arc: arc,
  2074. path: path,
  2075. symbol: symbol,
  2076. rect: rect,
  2077. rule: rule,
  2078. text: text,
  2079. image: image
  2080. },
  2081. nested: {
  2082. "area": true,
  2083. "line": true
  2084. },
  2085. style: style,
  2086. draw: {
  2087. group: drawGroup,
  2088. area: draw("path", area, true),
  2089. line: draw("path", line, true),
  2090. arc: draw("path", arc),
  2091. path: draw("path", path),
  2092. symbol: draw("path", symbol),
  2093. rect: draw("rect", rect),
  2094. rule: draw("line", rule),
  2095. text: draw("text", text),
  2096. image: draw("image", image),
  2097. draw: draw // expose for extensibility
  2098. }
  2099. };
  2100. })();vg.svg.Renderer = (function() {
  2101. var renderer = function() {
  2102. this._svg = null;
  2103. this._ctx = null;
  2104. this._el = null;
  2105. this._defs = {};
  2106. };
  2107. var prototype = renderer.prototype;
  2108. prototype.initialize = function(el, width, height, pad) {
  2109. this._el = el;
  2110. // remove any existing svg element
  2111. d3.select(el).select("svg.marks").remove();
  2112. // create svg element and initialize attributes
  2113. this._svg = d3.select(el)
  2114. .append("svg")
  2115. .attr("class", "marks");
  2116. // set the svg root group
  2117. this._ctx = this._svg.append("g");
  2118. return this.resize(width, height, pad);
  2119. };
  2120. prototype.resize = function(width, height, pad) {
  2121. this._width = width;
  2122. this._height = height;
  2123. this._padding = pad;
  2124. this._svg
  2125. .attr("width", width + pad.left + pad.right)
  2126. .attr("height", height + pad.top + pad.bottom);
  2127. this._ctx
  2128. .attr("transform", "translate("+pad.left+","+pad.top+")");
  2129. return this;
  2130. };
  2131. prototype.context = function() {
  2132. return this._ctx;
  2133. };
  2134. prototype.element = function() {
  2135. return this._el;
  2136. };
  2137. prototype.updateDefs = function() {
  2138. var svg = this._svg,
  2139. all = this._defs,
  2140. ids = vg.keys(all),
  2141. defs = svg.select("defs"), grds;
  2142. // get or create svg defs block
  2143. if (ids.length===0) { defs.remove(); return; }
  2144. if (defs.empty()) defs = svg.insert("defs", ":first-child");
  2145. grds = defs.selectAll("linearGradient").data(ids, vg.identity);
  2146. grds.enter().append("linearGradient").attr("id", vg.identity);
  2147. grds.exit().remove();
  2148. grds.each(function(id) {
  2149. var def = all[id],
  2150. grd = d3.select(this);
  2151. // set gradient coordinates
  2152. grd.attr({x1: def.x1, x2: def.x2, y1: def.y1, y2: def.y2});
  2153. // set gradient stops
  2154. stop = grd.selectAll("stop").data(def.stops);
  2155. stop.enter().append("stop");
  2156. stop.exit().remove();
  2157. stop.attr("offset", function(d) { return d.offset; })
  2158. .attr("stop-color", function(d) { return d.color; });
  2159. });
  2160. };
  2161. prototype.render = function(scene, items) {
  2162. vg.svg._cur = this;
  2163. if (items) this.renderItems(vg.array(items));
  2164. else this.draw(this._ctx, scene, -1);
  2165. this.updateDefs();
  2166. delete vg.svg._cur;
  2167. };
  2168. prototype.renderItems = function(items) {
  2169. var item, node, type, nest, i, n,
  2170. marks = vg.svg.marks;
  2171. for (i=0, n=items.length; i<n; ++i) {
  2172. item = items[i];
  2173. node = item._svg;
  2174. type = item.mark.marktype;
  2175. item = marks.nested[type] ? item.mark.items : item;
  2176. marks.update[type].call(node, item);
  2177. marks.style.call(node, item);
  2178. }
  2179. }
  2180. prototype.draw = function(ctx, scene, index) {
  2181. var marktype = scene.marktype,
  2182. renderer = vg.svg.marks.draw[marktype];
  2183. renderer.call(this, ctx, scene, index);
  2184. };
  2185. return renderer;
  2186. })();vg.svg.Handler = (function() {
  2187. var handler = function(el, model) {
  2188. this._active = null;
  2189. this._handlers = {};
  2190. if (el) this.initialize(el);
  2191. if (model) this.model(model);
  2192. };
  2193. function svgHandler(handler) {
  2194. var that = this;
  2195. return function(evt) {
  2196. var target = evt.target,
  2197. item = target.__data__;
  2198. if (item) {
  2199. item = item.mark ? item : item[0];
  2200. handler.call(that._obj, evt, item);
  2201. }
  2202. };
  2203. }
  2204. function eventName(name) {
  2205. var i = name.indexOf(".");
  2206. return i < 0 ? name : name.slice(0,i);
  2207. }
  2208. var prototype = handler.prototype;
  2209. prototype.initialize = function(el, pad, obj) {
  2210. this._el = d3.select(el).node();
  2211. this._svg = d3.select(el).select("svg.marks").node();
  2212. this._padding = pad;
  2213. this._obj = obj || null;
  2214. return this;
  2215. };
  2216. prototype.padding = function(pad) {
  2217. this._padding = pad;
  2218. return this;
  2219. };
  2220. prototype.model = function(model) {
  2221. if (!arguments.length) return this._model;
  2222. this._model = model;
  2223. return this;
  2224. };
  2225. prototype.handlers = function() {
  2226. var h = this._handlers;
  2227. return vg.keys(h).reduce(function(a, k) {
  2228. return h[k].reduce(function(a, x) { return (a.push(x), a); }, a);
  2229. }, []);
  2230. };
  2231. // add an event handler
  2232. prototype.on = function(type, handler) {
  2233. var name = eventName(type),
  2234. h = this._handlers,
  2235. dom = d3.select(this._svg).node();
  2236. var x = {
  2237. type: type,
  2238. handler: handler,
  2239. svg: svgHandler.call(this, handler)
  2240. };
  2241. h = h[name] || (h[name] = []);
  2242. h.push(x);
  2243. dom.addEventListener(name, x.svg);
  2244. return this;
  2245. };
  2246. // remove an event handler
  2247. prototype.off = function(type, handler) {
  2248. var name = eventName(type),
  2249. h = this._handlers[name],
  2250. dom = d3.select(this._svg).node();
  2251. if (!h) return;
  2252. for (var i=h.length; --i>=0;) {
  2253. if (h[i].type !== type) continue;
  2254. if (!handler || h[i].handler === handler) {
  2255. dom.removeEventListener(name, h[i].svg);
  2256. h.splice(i, 1);
  2257. }
  2258. }
  2259. return this;
  2260. };
  2261. return handler;
  2262. })();vg.data = {};
  2263. vg.data.ingestAll = function(data) {
  2264. return vg.isTree(data)
  2265. ? vg_make_tree(vg.data.ingestTree(data[0], data.children))
  2266. : data.map(vg.data.ingest);
  2267. };
  2268. vg.data.ingest = function(datum, index) {
  2269. return {
  2270. data: datum,
  2271. index: index
  2272. };
  2273. };
  2274. vg.data.ingestTree = function(node, children) {
  2275. var d = vg.data.ingest(node),
  2276. c = node[children], n, i;
  2277. if (c && (n = c.length)) {
  2278. d.values = Array(n);
  2279. for (i=0; i<n; ++i) {
  2280. d.values[i] = vg.data.ingestTree(c[i], children);
  2281. }
  2282. }
  2283. return d;
  2284. };
  2285. function vg_make_tree(d) {
  2286. d.__vgtree__ = true;
  2287. d.nodes = function() { return vg_tree_nodes(this, []); };
  2288. return d;
  2289. }
  2290. function vg_tree_nodes(root, nodes) {
  2291. var c = root.values,
  2292. n = c ? c.length : 0, i;
  2293. nodes.push(root);
  2294. for (i=0; i<n; ++i) { vg_tree_nodes(c[i], nodes); }
  2295. return nodes;
  2296. }
  2297. function vg_data_duplicate(d) {
  2298. var x=d, i, n;
  2299. if (vg.isArray(d)) {
  2300. x = [];
  2301. for (i=0, n=d.length; i<n; ++i) {
  2302. x.push(vg_data_duplicate(d[i]));
  2303. }
  2304. } else if (vg.isObject(d)) {
  2305. x = {};
  2306. for (i in d) {
  2307. x[i] = vg_data_duplicate(d[i]);
  2308. }
  2309. }
  2310. return x;
  2311. }
  2312. vg.data.mapper = function(func) {
  2313. return function(data) {
  2314. data.forEach(func);
  2315. return data;
  2316. }
  2317. };
  2318. vg.data.size = function(size, group) {
  2319. size = vg.isArray(size) ? size : [0, size];
  2320. size = size.map(function(d) {
  2321. return (typeof d === 'string') ? group[d] : d;
  2322. });
  2323. return size;
  2324. };vg.data.load = function(uri, callback) {
  2325. var url = vg_load_hasProtocol(uri) ? uri : vg.config.baseURL + uri;
  2326. if (vg.config.isNode) {
  2327. // in node.js, consult url and select file or http
  2328. var get = vg_load_isFile(url) ? vg_load_file : vg_load_http;
  2329. get(url, callback);
  2330. } else {
  2331. // in browser, use xhr
  2332. vg_load_xhr(url, callback);
  2333. }
  2334. };
  2335. var vg_load_protocolRE = /^[A-Za-z]+\:\/\//;
  2336. var vg_load_fileProtocol = "file://";
  2337. function vg_load_hasProtocol(url) {
  2338. return vg_load_protocolRE.test(url);
  2339. }
  2340. function vg_load_isFile(url) {
  2341. return url.indexOf(vg_load_fileProtocol) === 0;
  2342. }
  2343. function vg_load_xhr(url, callback) {
  2344. vg.log("LOAD: " + url);
  2345. d3.xhr(url, function(err, resp) {
  2346. if (resp) resp = resp.responseText;
  2347. callback(err, resp);
  2348. });
  2349. }
  2350. function vg_load_file(file, callback) {
  2351. vg.log("LOAD FILE: " + file);
  2352. var idx = file.indexOf(vg_load_fileProtocol);
  2353. if (idx >= 0) file = file.slice(vg_load_fileProtocol.length);
  2354. require("fs").readFile(file, callback);
  2355. }
  2356. function vg_load_http(url, callback) {
  2357. vg.log("LOAD HTTP: " + url);
  2358. var req = require("http").request(url, function(res) {
  2359. var pos=0, data = new Buffer(parseInt(res.headers['content-length'],10));
  2360. res.on("error", function(err) { callback(err, null); });
  2361. res.on("data", function(x) { x.copy(data, pos); pos += x.length; });
  2362. res.on("end", function() { callback(null, data); });
  2363. });
  2364. req.on("error", function(err) { callback(err); });
  2365. req.end();
  2366. }vg.data.read = (function() {
  2367. var formats = {},
  2368. parsers = {
  2369. "number": vg.number,
  2370. "boolean": vg.boolean,
  2371. "date": Date.parse
  2372. };
  2373. function read(data, format) {
  2374. var type = (format && format.type) || "json";
  2375. data = formats[type](data, format);
  2376. if (format && format.parse) parseValues(data, format.parse);
  2377. return data;
  2378. }
  2379. formats.json = function(data, format) {
  2380. var d = JSON.parse(data);
  2381. if (format && format.property) {
  2382. d = vg.accessor(format.property)(d);
  2383. }
  2384. return d;
  2385. };
  2386. formats.csv = function(data, format) {
  2387. var d = d3.csv.parse(data);
  2388. return d;
  2389. };
  2390. formats.tsv = function(data, format) {
  2391. var d = d3.tsv.parse(data);
  2392. return d;
  2393. };
  2394. formats.topojson = function(data, format) {
  2395. if (topojson == null) {
  2396. vg.error("TopoJSON library not loaded.");
  2397. return [];
  2398. }
  2399. var t = JSON.parse(data), obj = [];
  2400. if (format && format.feature) {
  2401. obj = (obj = t.objects[format.feature])
  2402. ? topojson.feature(t, obj).features
  2403. : (vg.error("Invalid TopoJSON object: "+format.feature), []);
  2404. } else if (format && format.mesh) {
  2405. obj = (obj = t.objects[format.mesh])
  2406. ? [topojson.mesh(t, t.objects[format.mesh])]
  2407. : (vg.error("Invalid TopoJSON object: " + format.mesh), []);
  2408. }
  2409. else { vg.error("Missing TopoJSON feature or mesh parameter."); }
  2410. return obj;
  2411. };
  2412. formats.treejson = function(data, format) {
  2413. var d = [JSON.parse(data)];
  2414. d.__vgtree__ = true;
  2415. d.children = format.children || "children";
  2416. return d;
  2417. };
  2418. function parseValues(data, types) {
  2419. var cols = vg.keys(types),
  2420. p = cols.map(function(col) { return parsers[types[col]]; }),
  2421. tree = vg.isTree(data);
  2422. vg_parseArray(tree ? [data] : data, cols, p, tree);
  2423. }
  2424. function vg_parseArray(data, cols, p, tree) {
  2425. var d, i, j, len, clen;
  2426. for (i=0, len=data.length; i<len; ++i) {
  2427. d = data[i];
  2428. for (j=0, clen=cols.length; j<clen; ++j) {
  2429. d[cols[j]] = p[j](d[cols[j]]);
  2430. }
  2431. if (tree && d.values) parseCollection(d, cols, p, true);
  2432. }
  2433. }
  2434. read.formats = formats;
  2435. read.parse = parseValues;
  2436. return read;
  2437. })();vg.data.array = function() {
  2438. var fields = [];
  2439. function array(data) {
  2440. return data.map(function(d) {
  2441. var list = [];
  2442. for (var i=0, len=fields.length; i<len; ++i) {
  2443. list.push(fields[i](d));
  2444. }
  2445. return list;
  2446. });
  2447. }
  2448. array.fields = function(fieldList) {
  2449. fields = vg.array(fieldList).map(vg.accessor);
  2450. return array;
  2451. };
  2452. return array;
  2453. };vg.data.copy = function() {
  2454. var from = vg.accessor("data"),
  2455. fields = [],
  2456. as = null;
  2457. var copy = vg.data.mapper(function(d) {
  2458. var src = from(d), i, len,
  2459. source = fields,
  2460. target = as || fields;
  2461. for (i=0, len=fields.length; i<len; ++i) {
  2462. d[target[i]] = src[fields[i]];
  2463. }
  2464. return d;
  2465. });
  2466. copy.from = function(field) {
  2467. from = vg.accessor(field);
  2468. return copy;
  2469. };
  2470. copy.fields = function(fieldList) {
  2471. fields = vg.array(fieldList);
  2472. return copy;
  2473. };
  2474. copy.as = function(fieldList) {
  2475. as = vg.array(fieldList);
  2476. return copy;
  2477. };
  2478. return copy;
  2479. };vg.data.cross = function() {
  2480. var other = null,
  2481. nodiag = false,
  2482. output = {left:"a", right:"b"};
  2483. function cross(data) {
  2484. var result = [],
  2485. data2 = other || data,
  2486. o, i, j, n = data.length;
  2487. for (i=0; i<n; ++i) {
  2488. for (j=0; j<n; ++j) {
  2489. if (nodiag && i===j) continue;
  2490. o = {};
  2491. o[output.left] = data[i];
  2492. o[output.right] = data2[j];
  2493. result.push(o);
  2494. }
  2495. }
  2496. return result;
  2497. }
  2498. cross["with"] = function(d) {
  2499. other = d;
  2500. return cross;
  2501. };
  2502. cross.diagonal = function(x) {
  2503. nodiag = !x;
  2504. return cross;
  2505. };
  2506. cross.output = function(map) {
  2507. vg.keys(output).forEach(function(k) {
  2508. if (map[k] !== undefined) { output[k] = map[k]; }
  2509. });
  2510. return cross;
  2511. };
  2512. return cross;
  2513. };
  2514. vg.data.facet = function() {
  2515. var keys = [],
  2516. sort = null;
  2517. function facet(data) {
  2518. var result = {
  2519. key: "",
  2520. keys: [],
  2521. values: []
  2522. },
  2523. map = {},
  2524. vals = result.values,
  2525. obj, klist, kstr, len, i, j, k, kv, cmp;
  2526. if (keys.length === 0) {
  2527. // if no keys, skip collation step
  2528. vals.push(obj = {
  2529. key: "", keys: [], index: 0,
  2530. values: sort ? data.slice() : data
  2531. });
  2532. if (sort) sort(obj.values);
  2533. return result;
  2534. }
  2535. for (i=0, len=data.length; i<len; ++i) {
  2536. for (k=0, klist=[], kstr=""; k<keys.length; ++k) {
  2537. kv = keys[k](data[i]);
  2538. klist.push(kv);
  2539. kstr += (k>0 ? "|" : "") + String(kv);
  2540. }
  2541. obj = map[kstr];
  2542. if (obj === undefined) {
  2543. vals.push(obj = map[kstr] = {
  2544. key: kstr,
  2545. keys: klist,
  2546. index: vals.length,
  2547. values: []
  2548. });
  2549. }
  2550. obj.values.push(data[i]);
  2551. }
  2552. if (sort) {
  2553. for (i=0, len=vals.length; i<len; ++i) {
  2554. sort(vals[i].values);
  2555. }
  2556. }
  2557. return result;
  2558. }
  2559. facet.keys = function(k) {
  2560. keys = vg.array(k).map(vg.accessor);
  2561. return facet;
  2562. };
  2563. facet.sort = function(s) {
  2564. sort = vg.data.sort().by(s);
  2565. return facet;
  2566. };
  2567. return facet;
  2568. };vg.data.filter = function() {
  2569. var test = null;
  2570. function filter(data) {
  2571. return test ? data.filter(test) : data;
  2572. }
  2573. filter.test = function(func) {
  2574. test = vg.isFunction(func) ? func : vg.parse.expr(func);
  2575. return filter;
  2576. };
  2577. return filter;
  2578. };vg.data.flatten = function() {
  2579. function flatten(data) {
  2580. return flat(data, []);
  2581. }
  2582. function flat(data, list) {
  2583. if (data.values) {
  2584. for (var i=0, n=data.values.length; i<n; ++i) {
  2585. flat(data.values[i], list);
  2586. }
  2587. } else {
  2588. list.push(data);
  2589. }
  2590. return list;
  2591. }
  2592. return flatten;
  2593. };vg.data.fold = function() {
  2594. var fields = [],
  2595. accessors = [],
  2596. output = {
  2597. key: "key",
  2598. value: "value"
  2599. };
  2600. function fold(data) {
  2601. var values = [],
  2602. item, i, j, n, m = fields.length;
  2603. for (i=0, n=data.length; i<n; ++i) {
  2604. item = data[i];
  2605. for (j=0; j<m; ++j) {
  2606. var o = {
  2607. index: values.length,
  2608. data: item.data
  2609. };
  2610. o[output.key] = fields[j];
  2611. o[output.value] = accessors[j](item);
  2612. values.push(o);
  2613. }
  2614. }
  2615. return values;
  2616. }
  2617. fold.fields = function(f) {
  2618. fields = vg.array(f);
  2619. accessors = fields.map(vg.accessor);
  2620. return fold;
  2621. };
  2622. fold.output = function(map) {
  2623. vg.keys(output).forEach(function(k) {
  2624. if (map[k] !== undefined) {
  2625. output[k] = map[k];
  2626. }
  2627. });
  2628. return fold;
  2629. };
  2630. return fold;
  2631. };vg.data.force = function() {
  2632. var layout = d3.layout.force(),
  2633. links = null,
  2634. linkDistance = 20,
  2635. linkStrength = 1,
  2636. charge = -30,
  2637. iterations = 500,
  2638. size = ["width", "height"],
  2639. params = [
  2640. "friction",
  2641. "theta",
  2642. "gravity",
  2643. "alpha"
  2644. ];
  2645. function force(data, db, group) {
  2646. layout
  2647. .size(vg.data.size(size, group))
  2648. .nodes(data);
  2649. if (links && db[links]) {
  2650. layout.links(db[links]);
  2651. }
  2652. layout.start();
  2653. for (var i=0; i<iterations; ++i) {
  2654. layout.tick();
  2655. }
  2656. layout.stop();
  2657. return data;
  2658. }
  2659. force.links = function(dataSetName) {
  2660. links = dataSetName;
  2661. return force;
  2662. };
  2663. force.size = function(sz) {
  2664. size = sz;
  2665. return force;
  2666. };
  2667. force.linkDistance = function(field) {
  2668. linkDistance = typeof field === 'number'
  2669. ? field
  2670. : vg.accessor(field);
  2671. layout.linkDistance(linkDistance);
  2672. return force;
  2673. };
  2674. force.linkStrength = function(field) {
  2675. linkStrength = typeof field === 'number'
  2676. ? field
  2677. : vg.accessor(field);
  2678. layout.linkStrength(linkStrength);
  2679. return force;
  2680. };
  2681. force.charge = function(field) {
  2682. charge = typeof field === 'number'
  2683. ? field
  2684. : vg.accessor(field);
  2685. layout.charge(charge);
  2686. return force;
  2687. };
  2688. force.iterations = function(iter) {
  2689. iterations = iter;
  2690. return force;
  2691. };
  2692. params.forEach(function(name) {
  2693. force[name] = function(x) {
  2694. layout[name](x);
  2695. return force;
  2696. }
  2697. });
  2698. return force;
  2699. };vg.data.formula = (function() {
  2700. return function() {
  2701. var field = null,
  2702. expr = vg.identity;
  2703. var formula = vg.data.mapper(function(d, i, list) {
  2704. if (field) d[field] = expr.call(null, d, i, list);
  2705. return d;
  2706. });
  2707. formula.field = function(name) {
  2708. field = name;
  2709. return formula;
  2710. };
  2711. formula.expr = function(func) {
  2712. expr = vg.isFunction(func) ? func : vg.parse.expr(func);
  2713. return formula;
  2714. };
  2715. return formula;
  2716. };
  2717. })();vg.data.geo = (function() {
  2718. var params = [
  2719. "center",
  2720. "scale",
  2721. "translate",
  2722. "rotate",
  2723. "precision",
  2724. "clipAngle"
  2725. ];
  2726. function geo() {
  2727. var opt = {},
  2728. projection = "mercator",
  2729. func = d3.geo[projection](),
  2730. lat = vg.identity,
  2731. lon = vg.identity,
  2732. output = {
  2733. "x": "x",
  2734. "y": "y"
  2735. };
  2736. var map = vg.data.mapper(function(d) {
  2737. var ll = [lon(d), lat(d)],
  2738. xy = func(ll);
  2739. d[output.x] = xy[0];
  2740. d[output.y] = xy[1];
  2741. return d;
  2742. });
  2743. map.func = function() {
  2744. return func;
  2745. };
  2746. map.projection = function(p) {
  2747. if (projection !== p) {
  2748. projection = p;
  2749. func = d3.geo[projection]();
  2750. for (var name in opt) {
  2751. func[name](opt[name]);
  2752. }
  2753. }
  2754. return map;
  2755. };
  2756. params.forEach(function(name) {
  2757. map[name] = function(x) {
  2758. opt[name] = x;
  2759. func[name](x);
  2760. return map;
  2761. }
  2762. });
  2763. map.lon = function(field) {
  2764. lon = vg.accessor(field);
  2765. return map;
  2766. };
  2767. map.lat = function(field) {
  2768. lat = vg.accessor(field);
  2769. return map;
  2770. };
  2771. map.output = function(map) {
  2772. vg.keys(output).forEach(function(k) {
  2773. if (map[k] !== undefined) {
  2774. output[k] = map[k];
  2775. }
  2776. });
  2777. return map;
  2778. };
  2779. return map;
  2780. };
  2781. geo.params = params;
  2782. return geo;
  2783. })();vg.data.geopath = function() {
  2784. var geopath = d3.geo.path().projection(d3.geo.mercator()),
  2785. projection = "mercator",
  2786. geojson = vg.identity,
  2787. opt = {},
  2788. output = {"path": "path"};
  2789. var map = vg.data.mapper(function(d) {
  2790. d[output.path] = geopath(geojson(d));
  2791. return d;
  2792. });
  2793. map.projection = function(proj) {
  2794. if (projection !== proj) {
  2795. projection = proj;
  2796. var p = d3.geo[projection]();
  2797. for (var name in opt) {
  2798. p[name](opt[name]);
  2799. }
  2800. geopath.projection(p);
  2801. }
  2802. return map;
  2803. };
  2804. vg.data.geo.params.forEach(function(name) {
  2805. map[name] = function(x) {
  2806. opt[name] = x;
  2807. (geopath.projection())[name](x);
  2808. return map;
  2809. }
  2810. });
  2811. map.value = function(field) {
  2812. geojson = vg.accessor(field);
  2813. return map;
  2814. };
  2815. map.output = function(map) {
  2816. vg.keys(output).forEach(function(k) {
  2817. if (map[k] !== undefined) {
  2818. output[k] = map[k];
  2819. }
  2820. });
  2821. return map;
  2822. };
  2823. return map;
  2824. };vg.data.link = function() {
  2825. var shape = "line",
  2826. source = vg.accessor("source"),
  2827. target = vg.accessor("target"),
  2828. tension = 0.2,
  2829. output = {"path": "path"};
  2830. function line(d) {
  2831. var s = source(d),
  2832. t = target(d);
  2833. return "M" + s.x + "," + s.y
  2834. + "L" + t.x + "," + t.y;
  2835. }
  2836. function curve(d) {
  2837. var s = source(d),
  2838. t = target(d),
  2839. dx = t.x - s.x,
  2840. dy = t.y - s.y,
  2841. ix = tension * (dx + dy),
  2842. iy = tension * (dy - dx);
  2843. return "M" + s.x + "," + s.y
  2844. + "C" + (s.x+ix) + "," + (s.y+iy)
  2845. + " " + (t.x+iy) + "," + (t.y-ix)
  2846. + " " + t.x + "," + t.y;
  2847. }
  2848. function diagonalX(d) {
  2849. var s = source(d),
  2850. t = target(d),
  2851. m = (s.x + t.x) / 2;
  2852. return "M" + s.x + "," + s.y
  2853. + "C" + m + "," + s.y
  2854. + " " + m + "," + t.y
  2855. + " " + t.x + "," + t.y;
  2856. }
  2857. function diagonalY(d) {
  2858. var s = source(d),
  2859. t = target(d),
  2860. m = (s.y + t.y) / 2;
  2861. return "M" + s.x + "," + s.y
  2862. + "C" + s.x + "," + m
  2863. + " " + t.x + "," + m
  2864. + " " + t.x + "," + t.y;
  2865. }
  2866. var shapes = {
  2867. line: line,
  2868. curve: curve,
  2869. diagonal: diagonalX,
  2870. diagonalX: diagonalX,
  2871. diagonalY: diagonalY
  2872. };
  2873. function link(data) {
  2874. var path = shapes[shape];
  2875. data.forEach(function(d) {
  2876. d[output.path] = path(d);
  2877. });
  2878. return data;
  2879. }
  2880. link.shape = function(val) {
  2881. shape = val;
  2882. return link;
  2883. };
  2884. link.tension = function(val) {
  2885. tension = val;
  2886. return link;
  2887. };
  2888. link.source = function(field) {
  2889. source = vg.accessor(field);
  2890. return link;
  2891. };
  2892. link.target = function(field) {
  2893. target = vg.accessor(field);
  2894. return link;
  2895. };
  2896. link.output = function(map) {
  2897. vg.keys(output).forEach(function(k) {
  2898. if (map[k] !== undefined) {
  2899. output[k] = map[k];
  2900. }
  2901. });
  2902. return link;
  2903. };
  2904. return link;
  2905. };vg.data.pie = function() {
  2906. var one = function() { return 1; },
  2907. value = one,
  2908. start = 0,
  2909. end = 2 * Math.PI,
  2910. sort = false,
  2911. output = {
  2912. "startAngle": "startAngle",
  2913. "endAngle": "endAngle"
  2914. };
  2915. function pie(data) {
  2916. var values = data.map(function(d, i) { return +value(d); }),
  2917. a = start,
  2918. k = (end - start) / d3.sum(values),
  2919. index = d3.range(data.length);
  2920. if (sort) {
  2921. index.sort(function(a, b) {
  2922. return values[a] - values[b];
  2923. });
  2924. }
  2925. index.forEach(function(i) {
  2926. var d;
  2927. data[i].value = (d = values[i]);
  2928. data[i][output.startAngle] = a;
  2929. data[i][output.endAngle] = (a += d * k);
  2930. });
  2931. return data;
  2932. }
  2933. pie.sort = function(b) {
  2934. sort = b;
  2935. return pie;
  2936. };
  2937. pie.value = function(field) {
  2938. value = field ? vg.accessor(field) : one;
  2939. return pie;
  2940. };
  2941. pie.startAngle = function(startAngle) {
  2942. start = Math.PI * startAngle / 180;
  2943. return pie;
  2944. };
  2945. pie.endAngle = function(endAngle) {
  2946. end = Math.PI * endAngle / 180;
  2947. return pie;
  2948. };
  2949. pie.output = function(map) {
  2950. vg.keys(output).forEach(function(k) {
  2951. if (map[k] !== undefined) {
  2952. output[k] = map[k];
  2953. }
  2954. });
  2955. return pie;
  2956. };
  2957. return pie;
  2958. };vg.data.slice = function() {
  2959. var by = null,
  2960. field = vg.accessor("data");
  2961. function slice(data) {
  2962. data = vg.values(data);
  2963. if (by === "min") {
  2964. data = [data[vg.minIndex(data, field)]];
  2965. } else if (by === "max") {
  2966. data = [data[vg.maxIndex(data, field)]];
  2967. } else if (by === "median") {
  2968. var list = data.slice().sort(function(a,b) {
  2969. a = field(a); b = field(b);
  2970. return a < b ? -1 : a > b ? 1 : 0;
  2971. });
  2972. data = [data[~~(list.length/2)]];
  2973. } else {
  2974. var idx = vg.array(by);
  2975. data = data.slice(idx[0], idx[1]);
  2976. }
  2977. return data;
  2978. }
  2979. slice.by = function(x) {
  2980. by = x;
  2981. return slice;
  2982. };
  2983. slice.field = function(f) {
  2984. field = vg.accessor(f);
  2985. return slice;
  2986. };
  2987. return slice;
  2988. };vg.data.sort = function() {
  2989. var by = null;
  2990. function sort(data) {
  2991. data = (vg.isArray(data) ? data : data.values || []);
  2992. data.sort(by);
  2993. for (var i=0, n=data.length; i<n; ++i) data[i].index = i; // re-index
  2994. return data;
  2995. }
  2996. sort.by = function(s) {
  2997. by = vg.comparator(s);
  2998. return sort;
  2999. };
  3000. return sort;
  3001. };vg.data.stack = function() {
  3002. var layout = d3.layout.stack(),
  3003. point = vg.accessor("index"),
  3004. height = vg.accessor("data"),
  3005. params = ["offset", "order"],
  3006. output = {
  3007. "y0": "y2",
  3008. "y1": "y",
  3009. "cy": "cy"
  3010. };
  3011. function stack(data) {
  3012. var out_y0 = output["y0"],
  3013. out_y1 = output["y1"],
  3014. out_cy = output["cy"];
  3015. var series = stacks(data);
  3016. if (series.length === 0) return data;
  3017. layout.out(function(d, y0, y) {
  3018. if (d.datum) {
  3019. d.datum[out_y0] = y0;
  3020. d.datum[out_y1] = y + y0;
  3021. d.datum[out_cy] = y0 + y/2;
  3022. }
  3023. })(series);
  3024. return data;
  3025. }
  3026. function stacks(data) {
  3027. var values = vg.values(data),
  3028. points = [], series = [],
  3029. a, i, n, j, m, k, p, v, x;
  3030. // exit early if no data
  3031. if (values.length === 0) return series;
  3032. // collect and sort data points
  3033. for (i=0, n=values.length; i<n; ++i) {
  3034. a = vg.values(values[i]);
  3035. for (j=0, m=a.length; j<m; ++j) {
  3036. points.push({x:point(a[j]), y:height(a[j]), z:i, datum:a[j]});
  3037. }
  3038. series.push([]);
  3039. }
  3040. points.sort(function(a,b) {
  3041. return a.x<b.x ? -1 : a.x>b.x ? 1 : (a.z<b.z ? -1 : a.z>b.z ? 1 : 0);
  3042. });
  3043. // emit data series for stack layout
  3044. for (x=points[0].x, i=0, j=0, k=0, n=points.length; k<n; ++k) {
  3045. p = points[k];
  3046. if (p.x !== x) {
  3047. while (i < series.length) series[i++].push({x:j, y:0});
  3048. x = p.x; i = 0; j += 1;
  3049. }
  3050. while (p.z > i) series[i++].push({x:j, y:0});
  3051. p.x = j;
  3052. series[i++].push(p);
  3053. }
  3054. while (i < series.length) series[i++].push({x:j, y:0});
  3055. return series;
  3056. }
  3057. stack.point = function(field) {
  3058. point = vg.accessor(field);
  3059. return stack;
  3060. };
  3061. stack.height = function(field) {
  3062. height = vg.accessor(field);
  3063. return stack;
  3064. };
  3065. params.forEach(function(name) {
  3066. stack[name] = function(x) {
  3067. layout[name](x);
  3068. return stack;
  3069. }
  3070. });
  3071. stack.output = function(map) {
  3072. d3.keys(output).forEach(function(k) {
  3073. if (map[k] !== undefined) {
  3074. output[k] = map[k];
  3075. }
  3076. });
  3077. return stack;
  3078. };
  3079. return stack;
  3080. };vg.data.stats = function() {
  3081. var value = vg.accessor("data"),
  3082. assign = false,
  3083. median = false,
  3084. output = {
  3085. "count": "count",
  3086. "min": "min",
  3087. "max": "max",
  3088. "sum": "sum",
  3089. "mean": "mean",
  3090. "variance": "variance",
  3091. "stdev": "stdev",
  3092. "median": "median"
  3093. };
  3094. function reduce(data) {
  3095. var min = +Infinity,
  3096. max = -Infinity,
  3097. sum = 0,
  3098. mean = 0,
  3099. M2 = 0,
  3100. i, len, v, delta;
  3101. var list = (vg.isArray(data) ? data : data.values || []).map(value);
  3102. // compute aggregates
  3103. for (i=0, len=list.length; i<len; ++i) {
  3104. v = list[i];
  3105. if (v < min) min = v;
  3106. if (v > max) max = v;
  3107. sum += v;
  3108. delta = v - mean;
  3109. mean = mean + delta / (i+1);
  3110. M2 = M2 + delta * (v - mean);
  3111. }
  3112. M2 = M2 / (len - 1);
  3113. var o = vg.isArray(data) ? {} : data;
  3114. if (median) {
  3115. list.sort(vg.numcmp);
  3116. i = list.length >> 1;
  3117. o[output.median] = list.length % 2
  3118. ? list[i]
  3119. : (list[i-1] + list[i])/2;
  3120. }
  3121. o[output.count] = len;
  3122. o[output.min] = min;
  3123. o[output.max] = max;
  3124. o[output.sum] = sum;
  3125. o[output.mean] = mean;
  3126. o[output.variance] = M2;
  3127. o[output.stdev] = Math.sqrt(M2);
  3128. if (assign) {
  3129. list = (vg.isArray(data) ? data : data.values);
  3130. v = {};
  3131. v[output.count] = len;
  3132. v[output.min] = min;
  3133. v[output.max] = max;
  3134. v[output.sum] = sum;
  3135. v[output.mean] = mean;
  3136. v[output.variance] = M2;
  3137. v[output.stdev] = Math.sqrt(M2);
  3138. if (median) v[output.median] = o[output.median];
  3139. for (i=0, len=list.length; i<len; ++i) {
  3140. list[i].stats = v;
  3141. }
  3142. }
  3143. return o;
  3144. }
  3145. function stats(data) {
  3146. return (vg.isArray(data) ? [data] : data.values || [])
  3147. .map(reduce); // no pun intended
  3148. }
  3149. stats.median = function(bool) {
  3150. median = bool || false;
  3151. return stats;
  3152. };
  3153. stats.value = function(field) {
  3154. value = vg.accessor(field);
  3155. return stats;
  3156. };
  3157. stats.assign = function(b) {
  3158. assign = b;
  3159. return stats;
  3160. };
  3161. stats.output = function(map) {
  3162. vg.keys(output).forEach(function(k) {
  3163. if (map[k] !== undefined) {
  3164. output[k] = map[k];
  3165. }
  3166. });
  3167. return stats;
  3168. };
  3169. return stats;
  3170. };vg.data.treemap = function() {
  3171. var layout = d3.layout.treemap()
  3172. .children(function(d) { return d.values; }),
  3173. value = vg.accessor("data"),
  3174. size = ["width", "height"],
  3175. params = ["round", "sticky", "ratio", "padding"],
  3176. output = {
  3177. "x": "x",
  3178. "y": "y",
  3179. "dx": "width",
  3180. "dy": "height"
  3181. };
  3182. function treemap(data, db, group) {
  3183. data = layout
  3184. .size(vg.data.size(size, group))
  3185. .value(value)
  3186. .nodes(vg.isTree(data) ? data.nodes() : data);
  3187. var keys = vg.keys(output),
  3188. len = keys.length;
  3189. data.forEach(function(d) {
  3190. var key, val;
  3191. for (var i=0; i<len; ++i) {
  3192. key = keys[i];
  3193. if (key !== output[key]) {
  3194. val = d[key];
  3195. delete d[key];
  3196. d[output[key]] = val;
  3197. }
  3198. }
  3199. });
  3200. return data;
  3201. }
  3202. treemap.size = function(sz) {
  3203. size = sz;
  3204. return treemap;
  3205. };
  3206. treemap.value = function(field) {
  3207. value = vg.accessor(field);
  3208. return treemap;
  3209. };
  3210. params.forEach(function(name) {
  3211. treemap[name] = function(x) {
  3212. layout[name](x);
  3213. return treemap;
  3214. }
  3215. });
  3216. treemap.output = function(map) {
  3217. vg.keys(output).forEach(function(k) {
  3218. if (map[k] !== undefined) {
  3219. output[k] = map[k];
  3220. }
  3221. });
  3222. return treemap;
  3223. };
  3224. return treemap;
  3225. };vg.data.truncate = function() {
  3226. var value = vg.accessor("data"),
  3227. as = "truncate",
  3228. position = "right",
  3229. ellipsis = "...",
  3230. wordBreak = true,
  3231. limit = 100;
  3232. var truncate = vg.data.mapper(function(d) {
  3233. var text = vg.truncate(value(d), limit, position, wordBreak, ellipsis);
  3234. return (d[as] = text, d);
  3235. });
  3236. truncate.value = function(field) {
  3237. value = vg.accessor(field);
  3238. return truncate;
  3239. };
  3240. truncate.output = function(field) {
  3241. as = field;
  3242. return truncate;
  3243. };
  3244. truncate.limit = function(len) {
  3245. limit = +len;
  3246. return truncate;
  3247. };
  3248. truncate.position = function(pos) {
  3249. position = pos;
  3250. return truncate;
  3251. };
  3252. truncate.ellipsis = function(str) {
  3253. ellipsis = str+"";
  3254. return truncate;
  3255. };
  3256. truncate.wordbreak = function(b) {
  3257. wordBreak = !!b;
  3258. return truncate;
  3259. };
  3260. return truncate;
  3261. };vg.data.unique = function() {
  3262. var field = null,
  3263. as = "field";
  3264. function unique(data) {
  3265. return vg.unique(data, field)
  3266. .map(function(x) {
  3267. var o = {};
  3268. o[as] = x;
  3269. return o;
  3270. });
  3271. }
  3272. unique.field = function(f) {
  3273. field = vg.accessor(f);
  3274. return unique;
  3275. };
  3276. unique.as = function(x) {
  3277. as = x;
  3278. return unique;
  3279. };
  3280. return unique;
  3281. };vg.data.window = function() {
  3282. var size = 2,
  3283. step = 1;
  3284. function win(data) {
  3285. data = vg.isArray(data) ? data : data.values || [];
  3286. var runs = [], i, j, n=data.length-size, curr;
  3287. for (i=0; i<=n; i+=step) {
  3288. for (j=0, curr=[]; j<size; ++j) curr.push(data[i+j]);
  3289. runs.push({key: i, values: curr});
  3290. }
  3291. return {values: runs};
  3292. }
  3293. win.size = function(n) {
  3294. size = n;
  3295. return win;
  3296. };
  3297. win.step = function(n) {
  3298. step = n;
  3299. return win;
  3300. };
  3301. return win;
  3302. };vg.data.wordcloud = function() {
  3303. var layout = d3.layout.cloud().size([900, 500]),
  3304. text = vg.accessor("data"),
  3305. size = ["width", "height"],
  3306. fontSize = function() { return 14; },
  3307. rotate = function() { return 0; },
  3308. params = ["font", "fontStyle", "fontWeight", "padding"];
  3309. var output = {
  3310. "x": "x",
  3311. "y": "y",
  3312. "size": "fontSize",
  3313. "font": "font",
  3314. "rotate": "angle"
  3315. };
  3316. function cloud(data, db, group) {
  3317. function finish(tags, bounds) {
  3318. var size = layout.size(),
  3319. dx = size[0] / 2,
  3320. dy = size[1] / 2,
  3321. keys = vg.keys(output),
  3322. key, d, i, n, k, m = keys.length;
  3323. // sort data to match wordcloud order
  3324. data.sort(function(a,b) {
  3325. return fontSize(b) - fontSize(a);
  3326. });
  3327. for (i=0, n=tags.length; i<n; ++i) {
  3328. d = data[i];
  3329. for (k=0; k<m; ++k) {
  3330. key = keys[k];
  3331. d[output[key]] = tags[i][key];
  3332. if (key === "x") d[output.x] += dx;
  3333. if (key === "y") d[output.y] += dy;
  3334. }
  3335. }
  3336. }
  3337. layout
  3338. .size(vg.data.size(size, group))
  3339. .text(text)
  3340. .fontSize(fontSize)
  3341. .rotate(rotate)
  3342. .words(data)
  3343. .on("end", finish)
  3344. .start();
  3345. return data;
  3346. }
  3347. cloud.text = function(field) {
  3348. text = vg.accessor(field);
  3349. return cloud;
  3350. };
  3351. cloud.size = function(sz) {
  3352. size = sz;
  3353. return cloud;
  3354. };
  3355. cloud.fontSize = function(field) {
  3356. fontSize = vg.accessor(field);
  3357. return cloud;
  3358. };
  3359. cloud.rotate = function(x) {
  3360. var v;
  3361. if (vg.isObject(x) && !Array.isArray(x)) {
  3362. if (x.random !== undefined) {
  3363. v = (v = x.random) ? vg.array(v) : [0];
  3364. rotate = function() {
  3365. return v[~~(Math.random()*v.length-0.00001)];
  3366. };
  3367. } else if (x.alternate !== undefined) {
  3368. v = (v = x.alternate) ? vg.array(v) : [0];
  3369. rotate = function(d, i) {
  3370. return v[i % v.length];
  3371. };
  3372. }
  3373. } else {
  3374. rotate = vg.accessor(field);
  3375. }
  3376. return cloud;
  3377. };
  3378. params.forEach(function(name) {
  3379. cloud[name] = function(x) {
  3380. layout[name](x);
  3381. return cloud;
  3382. }
  3383. });
  3384. cloud.output = function(map) {
  3385. vg.keys(output).forEach(function(k) {
  3386. if (map[k] !== undefined) {
  3387. output[k] = map[k];
  3388. }
  3389. });
  3390. return cloud;
  3391. };
  3392. return cloud;
  3393. };vg.data.zip = function() {
  3394. var z = null,
  3395. as = "zip",
  3396. key = vg.accessor("data"),
  3397. defaultValue = undefined,
  3398. withKey = null;
  3399. function zip(data, db) {
  3400. var zdata = db[z], zlen = zdata.length, v, d, i, len, map;
  3401. if (withKey) {
  3402. map = {};
  3403. zdata.forEach(function(s) { map[withKey(s)] = s; });
  3404. }
  3405. for (i=0, len=data.length; i<len; ++i) {
  3406. d = data[i];
  3407. d[as] = map
  3408. ? ((v=map[key(d)]) != null ? v : defaultValue)
  3409. : zdata[i % zlen];
  3410. }
  3411. return data;
  3412. }
  3413. zip["with"] = function(d) {
  3414. z = d;
  3415. return zip;
  3416. };
  3417. zip["default"] = function(d) {
  3418. defaultValue = d;
  3419. return zip;
  3420. };
  3421. zip.as = function(name) {
  3422. as = name;
  3423. return zip;
  3424. };
  3425. zip.key = function(k) {
  3426. key = vg.accessor(k);
  3427. return zip;
  3428. };
  3429. zip.withKey = function(k) {
  3430. withKey = vg.accessor(k);
  3431. return zip;
  3432. };
  3433. return zip;
  3434. };vg.parse = {};vg.parse.axes = (function() {
  3435. var ORIENT = {
  3436. "x": "bottom",
  3437. "y": "left",
  3438. "top": "top",
  3439. "bottom": "bottom",
  3440. "left": "left",
  3441. "right": "right"
  3442. };
  3443. function axes(spec, axes, scales) {
  3444. (spec || []).forEach(function(def, index) {
  3445. axes[index] = axes[index] || vg.scene.axis();
  3446. axis(def, index, axes[index], scales);
  3447. });
  3448. };
  3449. function axis(def, index, axis, scales) {
  3450. // axis scale
  3451. if (def.scale !== undefined) {
  3452. axis.scale(scales[def.scale]);
  3453. }
  3454. // axis orientation
  3455. axis.orient(def.orient || ORIENT[def.type]);
  3456. // axis offset
  3457. axis.offset(def.offset || 0);
  3458. // axis layer
  3459. axis.layer(def.layer || "front");
  3460. // axis grid lines
  3461. axis.grid(def.grid || false);
  3462. // axis title
  3463. axis.title(def.title || null);
  3464. // axis title offset
  3465. axis.titleOffset(def.titleOffset != null
  3466. ? def.titleOffset : vg.config.axis.titleOffset);
  3467. // axis values
  3468. axis.tickValues(def.values || null);
  3469. // axis label formatting
  3470. axis.tickFormat(def.format ? d3.format(def.format) : null);
  3471. // axis tick subdivision
  3472. axis.tickSubdivide(def.subdivide || 0);
  3473. // axis tick padding
  3474. axis.tickPadding(def.tickPadding || vg.config.axis.padding);
  3475. // axis tick size(s)
  3476. var size = [];
  3477. if (def.tickSize !== undefined) {
  3478. for (var i=0; i<3; ++i) size.push(def.tickSize);
  3479. } else {
  3480. var ts = vg.config.axis.tickSize;
  3481. size = [ts, ts, ts];
  3482. }
  3483. if (def.tickSizeMajor != null) size[0] = def.tickSizeMajor;
  3484. if (def.tickSizeMinor != null) size[1] = def.tickSizeMinor;
  3485. if (def.tickSizeEnd != null) size[2] = def.tickSizeEnd;
  3486. if (size.length) {
  3487. axis.tickSize.apply(axis, size);
  3488. }
  3489. // tick arguments
  3490. if (def.ticks != null) {
  3491. var ticks = vg.isArray(def.ticks) ? def.ticks : [def.ticks];
  3492. axis.ticks.apply(axis, ticks);
  3493. } else {
  3494. axis.ticks(vg.config.axis.ticks);
  3495. }
  3496. // style properties
  3497. var p = def.properties;
  3498. if (p && p.ticks) {
  3499. axis.majorTickProperties(p.majorTicks
  3500. ? vg.extend({}, p.ticks, p.majorTicks) : p.ticks);
  3501. axis.minorTickProperties(p.minorTicks
  3502. ? vg.extend({}, p.ticks, p.minorTicks) : p.ticks);
  3503. } else {
  3504. axis.majorTickProperties(p && p.majorTicks || {});
  3505. axis.minorTickProperties(p && p.minorTicks || {});
  3506. }
  3507. axis.tickLabelProperties(p && p.labels || {});
  3508. axis.titleProperties(p && p.title || {});
  3509. axis.gridLineProperties(p && p.grid || {});
  3510. axis.domainProperties(p && p.axis || {});
  3511. }
  3512. return axes;
  3513. })();vg.parse.data = function(spec, callback) {
  3514. var model = {
  3515. defs: spec,
  3516. load: {},
  3517. flow: {},
  3518. source: {}
  3519. };
  3520. var count = 0;
  3521. function load(d) {
  3522. return function(error, data) {
  3523. if (error) {
  3524. vg.error("LOADING FAILED: " + d.url);
  3525. } else {
  3526. model.load[d.name] = vg.data.read(data.toString(), d.format);
  3527. }
  3528. if (--count === 0) callback();
  3529. }
  3530. }
  3531. (spec || []).forEach(function(d) {
  3532. if (d.url) {
  3533. count += 1;
  3534. vg.data.load(d.url, load(d));
  3535. }
  3536. if (d.values) {
  3537. if (d.format && d.format.parse) {
  3538. // run specified value parsers
  3539. vg.data.read.parse(d.values, d.format.parse);
  3540. }
  3541. model.load[d.name] = d.values;
  3542. }
  3543. if (d.source) {
  3544. var list = model.source[d.source] || (model.source[d.source] = []);
  3545. list.push(d.name);
  3546. }
  3547. if (d.transform) {
  3548. model.flow[d.name] = vg.parse.dataflow(d);
  3549. }
  3550. });
  3551. if (count === 0) setTimeout(callback, 1);
  3552. return model;
  3553. };vg.parse.dataflow = function(def) {
  3554. var tx = (def.transform || []).map(vg.parse.transform);
  3555. return !tx.length ? vg.identity :
  3556. function(data, db, group) {
  3557. return tx.reduce(function(d,t) { return t(d, db, group); }, data);
  3558. };
  3559. };vg.parse.expr = (function() {
  3560. var CONSTANT = {
  3561. "E": "Math.E",
  3562. "LN2": "Math.LN2",
  3563. "LN10": "Math.LN10",
  3564. "LOG2E": "Math.LOG2E",
  3565. "LOG10E": "Math.LOG10E",
  3566. "PI": "Math.PI",
  3567. "SQRT1_2": "Math.SQRT1_2",
  3568. "SQRT2": "Math.SQRT2"
  3569. };
  3570. var FUNCTION = {
  3571. "abs": "Math.abs",
  3572. "acos": "Math.acos",
  3573. "asin": "Math.asin",
  3574. "atan": "Math.atan",
  3575. "atan2": "Math.atan2",
  3576. "ceil": "Math.ceil",
  3577. "cos": "Math.cos",
  3578. "exp": "Math.exp",
  3579. "floor": "Math.floor",
  3580. "log": "Math.log",
  3581. "max": "Math.max",
  3582. "min": "Math.min",
  3583. "pow": "Math.pow",
  3584. "random": "Math.random",
  3585. "round": "Math.round",
  3586. "sin": "Math.sin",
  3587. "sqrt": "Math.sqrt",
  3588. "tan": "Math.tan"
  3589. };
  3590. var lexer = /([\"\']|[\=\<\>\~\&\|\?\:\+\-\/\*\%\!\^\,\;\[\]\{\}\(\) ]+)/;
  3591. return function(x) {
  3592. var tokens = x.split(lexer),
  3593. t, v, i, n, sq, dq;
  3594. for (sq=0, dq=0, i=0, n=tokens.length; i<n; ++i) {
  3595. var t = tokens[i];
  3596. if (t==="'") { if (!dq) sq = !sq; continue; }
  3597. if (t==='"') { if (!sq) dq = !dq; continue; }
  3598. if (dq || sq) continue;
  3599. if (CONSTANT[t]) {
  3600. tokens[i] = CONSTANT[t];
  3601. }
  3602. if (FUNCTION[t] && (v=tokens[i+1]) && v[0]==="(") {
  3603. tokens[i] = FUNCTION[t];
  3604. }
  3605. }
  3606. return Function("d", "index", "data", "return ("+tokens.join("")+");");
  3607. };
  3608. })();vg.parse.legends = (function() {
  3609. function legends(spec, legends, scales) {
  3610. (spec || []).forEach(function(def, index) {
  3611. legends[index] = legends[index] || vg.scene.legend();
  3612. legend(def, index, legends[index], scales);
  3613. });
  3614. };
  3615. function legend(def, index, legend, scales) {
  3616. // legend scales
  3617. legend.size (def.size ? scales[def.size] : null);
  3618. legend.shape (def.shape ? scales[def.shape] : null);
  3619. legend.fill (def.fill ? scales[def.fill] : null);
  3620. legend.stroke(def.stroke ? scales[def.stroke] : null);
  3621. // legend orientation
  3622. if (def.orient) legend.orient(def.orient);
  3623. // legend offset
  3624. if (def.offset != null) legend.offset(def.offset);
  3625. // legend title
  3626. legend.title(def.title || null);
  3627. // legend values
  3628. legend.values(def.values || null);
  3629. // legend label formatting
  3630. legend.format(def.format !== undefined ? d3.format(def.format) : null);
  3631. // style properties
  3632. var p = def.properties;
  3633. legend.titleProperties(p && p.title || {});
  3634. legend.labelProperties(p && p.labels || {});
  3635. legend.legendProperties(p && p.legend || {});
  3636. legend.symbolProperties(p && p.symbols || {});
  3637. legend.gradientProperties(p && p.gradient || {});
  3638. }
  3639. return legends;
  3640. })();vg.parse.mark = function(mark) {
  3641. var props = mark.properties,
  3642. group = mark.marks;
  3643. // parse mark property definitions
  3644. vg.keys(props).forEach(function(k) {
  3645. props[k] = vg.parse.properties(mark.type, props[k]);
  3646. });
  3647. // parse delay function
  3648. if (mark.delay) {
  3649. mark.delay = vg.parse.properties(mark.type, {delay: mark.delay});
  3650. }
  3651. // parse mark data definition
  3652. if (mark.from) {
  3653. var name = mark.from.data,
  3654. tx = vg.parse.dataflow(mark.from);
  3655. mark.from = function(db, group, parentData) {
  3656. var data = vg.scene.data(name ? db[name] : null, parentData);
  3657. return tx(data, db, group);
  3658. };
  3659. }
  3660. // recurse if group type
  3661. if (group) {
  3662. mark.marks = group.map(vg.parse.mark);
  3663. }
  3664. return mark;
  3665. };vg.parse.marks = function(spec, width, height) {
  3666. return {
  3667. type: "group",
  3668. width: width,
  3669. height: height,
  3670. scales: spec.scales || [],
  3671. axes: spec.axes || [],
  3672. legends: spec.legends || [],
  3673. marks: (spec.marks || []).map(vg.parse.mark)
  3674. };
  3675. };vg.parse.padding = function(pad) {
  3676. if (pad == null) return "auto";
  3677. else if (vg.isString(pad)) return pad==="strict" ? "strict" : "auto";
  3678. else if (vg.isObject(pad)) return pad;
  3679. var p = vg.isNumber(pad) ? pad : 20;
  3680. return {top:p, left:p, right:p, bottom:p};
  3681. };
  3682. vg.parse.properties = (function() {
  3683. function compile(mark, spec) {
  3684. var code = "",
  3685. names = vg.keys(spec),
  3686. i, len, name, ref, vars = {};
  3687. code += "var o = trans ? {} : item;\n"
  3688. for (i=0, len=names.length; i<len; ++i) {
  3689. ref = spec[name = names[i]];
  3690. code += (i > 0) ? "\n " : " ";
  3691. code += "o."+name+" = "+valueRef(name, ref)+";";
  3692. vars[name] = true;
  3693. }
  3694. if (vars.x2) {
  3695. if (vars.x) {
  3696. code += "\n if (o.x > o.x2) { "
  3697. + "var t = o.x; o.x = o.x2; o.x2 = t; };";
  3698. code += "\n o.width = (o.x2 - o.x);";
  3699. } else if (vars.width && !vars.x1) {
  3700. code += "\n o.x = (o.x2 - o.width);";
  3701. }
  3702. }
  3703. if (vars.y2) {
  3704. if (vars.y) {
  3705. code += "\n if (o.y > o.y2) { "
  3706. + "var t = o.y; o.y = o.y2; o.y2 = t; };";
  3707. code += "\n o.height = (o.y2 - o.y);";
  3708. } else if (vars.height && !vars.y1) {
  3709. code += "\n o.y = (o.y2 - o.height);";
  3710. }
  3711. }
  3712. if (hasPath(mark, vars)) {
  3713. code += "\n if (o['path:parsed']) o['path:parsed'] = null;"
  3714. }
  3715. code += "\n if (trans) trans.interpolate(item, o);";
  3716. try {
  3717. return Function("item", "group", "trans", code);
  3718. } catch (e) {
  3719. vg.error(e);
  3720. vg.log(code);
  3721. }
  3722. }
  3723. function hasPath(mark, vars) {
  3724. return vars.path ||
  3725. ((mark==="area" || mark==="line") &&
  3726. (vars.x || vars.x2 || vars.width ||
  3727. vars.y || vars.y2 || vars.height ||
  3728. vars.tension || vars.interpolate));
  3729. }
  3730. var GROUP_VARS = {
  3731. "width": 1,
  3732. "height": 1,
  3733. "mark.group.width": 1,
  3734. "mark.group.height": 1
  3735. };
  3736. function valueRef(name, ref) {
  3737. if (ref == null) return null;
  3738. var isColor = name==="fill" || name==="stroke";
  3739. if (isColor) {
  3740. if (ref.c) {
  3741. return colorRef("hcl", ref.h, ref.c, ref.l);
  3742. } else if (ref.h || ref.s) {
  3743. return colorRef("hsl", ref.h, ref.s, ref.l);
  3744. } else if (ref.l || ref.a) {
  3745. return colorRef("lab", ref.l, ref.a, ref.b);
  3746. } else if (ref.r || ref.g || ref.b) {
  3747. return colorRef("rgb", ref.r, ref.g, ref.b);
  3748. }
  3749. }
  3750. // initialize value
  3751. var val = "item.datum.data";
  3752. if (ref.value !== undefined) {
  3753. val = vg.str(ref.value);
  3754. }
  3755. // get field reference for enclosing group
  3756. if (ref.group != null) {
  3757. var grp = "";
  3758. if (vg.isString(ref.group)) {
  3759. grp = GROUP_VARS[ref.group]
  3760. ? "group." + ref.group
  3761. : "group.datum["+vg.field(ref.group).map(vg.str).join("][")+"]";
  3762. }
  3763. }
  3764. // get data field value
  3765. if (ref.field != null) {
  3766. if (vg.isString(ref.field)) {
  3767. val = "item.datum["+vg.field(ref.field).map(vg.str).join("][")+"]";
  3768. if (ref.group != null) { val = grp+"["+val+"]"; }
  3769. } else {
  3770. val = "this.accessor(group.datum["
  3771. + vg.field(ref.field.group).map(vg.str).join("][")
  3772. + "])(item.datum.data)";
  3773. }
  3774. } else if (ref.group != null) {
  3775. val = grp;
  3776. }
  3777. // run through scale function
  3778. if (ref.scale != null) {
  3779. var scale = vg.isString(ref.scale)
  3780. ? vg.str(ref.scale)
  3781. : (ref.scale.group ? "group" : "item")
  3782. + ".datum[" + vg.str(ref.scale.group || ref.scale.field) + "]";
  3783. scale = "group.scales[" + scale + "]";
  3784. val = scale + (ref.band ? ".rangeBand()" : "("+val+")");
  3785. }
  3786. // multiply, offset, return value
  3787. val = "(" + (ref.mult?(vg.number(ref.mult)+" * "):"") + val + ")"
  3788. + (ref.offset ? " + " + vg.number(ref.offset) : "");
  3789. if (isColor) val = '('+val+')+""';
  3790. return val;
  3791. }
  3792. function colorRef(type, x, y, z) {
  3793. var xx = x ? valueRef("", x) : vg.config.color[type][0],
  3794. yy = y ? valueRef("", y) : vg.config.color[type][1],
  3795. zz = z ? valueRef("", z) : vg.config.color[type][2];
  3796. return "(this.d3." + type + "(" + [xx,yy,zz].join(",") + ') + "")';
  3797. }
  3798. return compile;
  3799. })();vg.parse.scales = (function() {
  3800. var LINEAR = "linear",
  3801. ORDINAL = "ordinal",
  3802. LOG = "log",
  3803. POWER = "pow",
  3804. TIME = "time",
  3805. GROUP_PROPERTY = {width: 1, height: 1};
  3806. function scales(spec, scales, db, group) {
  3807. return (spec || []).reduce(function(o, def) {
  3808. var name = def.name, prev = name + ":prev";
  3809. o[name] = scale(def, o[name], db, group);
  3810. o[prev] = o[prev] || o[name];
  3811. return o;
  3812. }, scales || {});
  3813. }
  3814. function scale(def, scale, db, group) {
  3815. var s = instance(def, scale),
  3816. m = s.type===ORDINAL ? ordinal : quantitative,
  3817. rng = range(def, group),
  3818. data = vg.values(group.datum);
  3819. m(def, s, rng, db, data);
  3820. return s;
  3821. }
  3822. function instance(def, scale) {
  3823. var type = def.type || LINEAR;
  3824. if (!scale || type !== scale.type) {
  3825. var ctor = vg.config.scale[type] || d3.scale[type];
  3826. if (!ctor) vg.error("Unrecognized scale type: " + type);
  3827. (scale = ctor()).type = scale.type || type;
  3828. scale.scaleName = def.name;
  3829. }
  3830. return scale;
  3831. }
  3832. function ordinal(def, scale, rng, db, data) {
  3833. var domain, refs, values, str;
  3834. // domain
  3835. domain = def.domain;
  3836. if (vg.isArray(domain)) {
  3837. scale.domain(domain);
  3838. } else if (vg.isObject(domain)) {
  3839. refs = def.domain.fields || vg.array(def.domain);
  3840. values = refs.reduce(function(values, r) {
  3841. var dat = vg.values(db[r.data] || data),
  3842. get = vg.accessor(vg.isString(r.field)
  3843. ? r.field : "data." + vg.accessor(r.field.group)(data));
  3844. return vg.unique(dat, get, values);
  3845. }, []);
  3846. if (def.sort) values.sort(vg.cmp);
  3847. scale.domain(values);
  3848. }
  3849. // range
  3850. str = typeof rng[0] === 'string';
  3851. if (str || rng.length > 2) {
  3852. scale.range(rng); // color or shape values
  3853. } else if (def.points) {
  3854. scale.rangePoints(rng, def.padding||0);
  3855. } else if (def.round || def.round===undefined) {
  3856. scale.rangeRoundBands(rng, def.padding||0);
  3857. } else {
  3858. scale.rangeBands(rng, def.padding||0);
  3859. }
  3860. }
  3861. function quantitative(def, scale, rng, db, data) {
  3862. var domain, refs, interval, z;
  3863. // domain
  3864. domain = [null, null];
  3865. function extract(ref, min, max, z) {
  3866. var dat = vg.values(db[ref.data] || data);
  3867. var fields = vg.array(ref.field).map(function(f) {
  3868. return vg.isString(f) ? f
  3869. : "data." + vg.accessor(f.group)(data);
  3870. });
  3871. fields.forEach(function(f,i) {
  3872. f = vg.accessor(f);
  3873. if (min) domain[0] = d3.min([domain[0], d3.min(dat, f)]);
  3874. if (max) domain[z] = d3.max([domain[z], d3.max(dat, f)]);
  3875. });
  3876. }
  3877. if (def.domain !== undefined) {
  3878. if (vg.isArray(def.domain)) {
  3879. domain = def.domain.slice();
  3880. } else if (vg.isObject(def.domain)) {
  3881. refs = def.domain.fields || vg.array(def.domain);
  3882. refs.forEach(function(r) { extract(r,1,1,1); });
  3883. } else {
  3884. domain = def.domain;
  3885. }
  3886. }
  3887. z = domain.length - 1;
  3888. if (def.domainMin !== undefined) {
  3889. if (vg.isObject(def.domainMin)) {
  3890. domain[0] = null;
  3891. refs = def.domainMin.fields || vg.array(def.domainMin);
  3892. refs.forEach(function(r) { extract(r,1,0,z); });
  3893. } else {
  3894. domain[0] = def.domainMin;
  3895. }
  3896. }
  3897. if (def.domainMax !== undefined) {
  3898. if (vg.isObject(def.domainMax)) {
  3899. domain[z] = null;
  3900. refs = def.domainMax.fields || vg.array(def.domainMax);
  3901. refs.forEach(function(r) { extract(r,0,1,z); });
  3902. } else {
  3903. domain[z] = def.domainMax;
  3904. }
  3905. }
  3906. if (def.type !== LOG && def.type !== TIME && (def.zero || def.zero===undefined)) {
  3907. domain[0] = Math.min(0, domain[0]);
  3908. domain[z] = Math.max(0, domain[z]);
  3909. }
  3910. scale.domain(domain);
  3911. // range
  3912. // vertical scales should flip by default, so use XOR here
  3913. if (def.range === "height") rng = rng.reverse();
  3914. scale[def.round && scale.rangeRound ? "rangeRound" : "range"](rng);
  3915. if (def.exponent && def.type===POWER) scale.exponent(def.exponent);
  3916. if (def.clamp) scale.clamp(true);
  3917. if (def.nice) {
  3918. if (def.type === TIME) {
  3919. interval = d3.time[def.nice];
  3920. if (!interval) vg.error("Unrecognized interval: " + interval);
  3921. scale.nice(interval);
  3922. } else {
  3923. scale.nice();
  3924. }
  3925. }
  3926. }
  3927. function range(def, group) {
  3928. var rng = [null, null];
  3929. if (def.range !== undefined) {
  3930. if (typeof def.range === 'string') {
  3931. if (GROUP_PROPERTY[def.range]) {
  3932. rng = [0, group[def.range]];
  3933. } else if (vg.config.range[def.range]) {
  3934. rng = vg.config.range[def.range];
  3935. } else {
  3936. vg.error("Unrecogized range: "+def.range);
  3937. return rng;
  3938. }
  3939. } else if (vg.isArray(def.range)) {
  3940. rng = def.range;
  3941. } else {
  3942. rng = [0, def.range];
  3943. }
  3944. }
  3945. if (def.rangeMin !== undefined) {
  3946. rng[0] = def.rangeMin;
  3947. }
  3948. if (def.rangeMax !== undefined) {
  3949. rng[rng.length-1] = def.rangeMax;
  3950. }
  3951. if (def.reverse !== undefined) {
  3952. var rev = def.reverse;
  3953. if (vg.isObject(rev)) {
  3954. rev = vg.accessor(rev.field)(group.datum);
  3955. }
  3956. if (rev) rng = rng.reverse();
  3957. }
  3958. return rng;
  3959. }
  3960. return scales;
  3961. })();
  3962. vg.parse.spec = function(spec, callback, viewFactory) {
  3963. viewFactory = viewFactory || vg.ViewFactory;
  3964. function parse(spec) {
  3965. // protect against subsequent spec modification
  3966. spec = vg.duplicate(spec);
  3967. var width = spec.width || 500,
  3968. height = spec.height || 500,
  3969. viewport = spec.viewport || null;
  3970. var defs = {
  3971. width: width,
  3972. height: height,
  3973. viewport: viewport,
  3974. padding: vg.parse.padding(spec.padding),
  3975. marks: vg.parse.marks(spec, width, height),
  3976. data: vg.parse.data(spec.data, function() { callback(viewConstructor); })
  3977. };
  3978. var viewConstructor = viewFactory(defs);
  3979. }
  3980. vg.isObject(spec) ? parse(spec) :
  3981. d3.json(spec, function(error, json) {
  3982. error ? vg.error(error) : parse(json);
  3983. });
  3984. };vg.parse.transform = function(def) {
  3985. var tx = vg.data[def.type]();
  3986. vg.keys(def).forEach(function(k) {
  3987. if (k === 'type') return;
  3988. (tx[k])(def[k]);
  3989. });
  3990. return tx;
  3991. };vg.scene = {};
  3992. vg.scene.GROUP = "group",
  3993. vg.scene.ENTER = 0,
  3994. vg.scene.UPDATE = 1,
  3995. vg.scene.EXIT = 2;
  3996. vg.scene.DEFAULT_DATA = {"sentinel":1}
  3997. vg.scene.data = function(data, parentData) {
  3998. var DEFAULT = vg.scene.DEFAULT_DATA;
  3999. // if data is undefined, inherit or use default
  4000. data = vg.values(data || parentData || [DEFAULT]);
  4001. // if inheriting default data, ensure its in an array
  4002. if (data === DEFAULT) data = [DEFAULT];
  4003. return data;
  4004. };
  4005. vg.scene.fontString = function(o) {
  4006. return (o.fontStyle ? o.fontStyle + " " : "")
  4007. + (o.fontVariant ? o.fontVariant + " " : "")
  4008. + (o.fontWeight ? o.fontWeight + " " : "")
  4009. + (o.fontSize != null ? o.fontSize : vg.config.render.fontSize) + "px "
  4010. + (o.font || vg.config.render.font);
  4011. };vg.scene.Item = (function() {
  4012. function item(mark) {
  4013. this.mark = mark;
  4014. }
  4015. var prototype = item.prototype;
  4016. prototype.hasPropertySet = function(name) {
  4017. var props = this.mark.def.properties;
  4018. return props && props[name] != null;
  4019. };
  4020. prototype.cousin = function(offset, index) {
  4021. if (offset === 0) return this;
  4022. offset = offset || -1;
  4023. var mark = this.mark,
  4024. group = mark.group,
  4025. iidx = index==null ? mark.items.indexOf(this) : index,
  4026. midx = group.items.indexOf(mark) + offset;
  4027. return group.items[midx].items[iidx];
  4028. };
  4029. prototype.sibling = function(offset) {
  4030. if (offset === 0) return this;
  4031. offset = offset || -1;
  4032. var mark = this.mark,
  4033. iidx = mark.items.indexOf(this) + offset;
  4034. return mark.items[iidx];
  4035. };
  4036. prototype.remove = function() {
  4037. var item = this,
  4038. list = item.mark.items,
  4039. i = list.indexOf(item);
  4040. if (i >= 0) (i===list.length-1) ? list.pop() : list.splice(i, 1);
  4041. return item;
  4042. };
  4043. return item;
  4044. })();
  4045. vg.scene.item = function(mark) {
  4046. return new vg.scene.Item(mark);
  4047. };vg.scene.visit = function(node, func) {
  4048. var i, n, items;
  4049. if (func(node)) return true;
  4050. if (items = node.items) {
  4051. for (i=0, n=items.length; i<n; ++i) {
  4052. if (vg.scene.visit(items[i], func)) return true;
  4053. }
  4054. }
  4055. };vg.scene.build = (function() {
  4056. var GROUP = vg.scene.GROUP,
  4057. ENTER = vg.scene.ENTER,
  4058. UPDATE = vg.scene.UPDATE,
  4059. EXIT = vg.scene.EXIT,
  4060. DEFAULT= {"sentinel":1};
  4061. function build(def, db, node, parentData) {
  4062. var data = vg.scene.data(
  4063. def.from ? def.from(db, node, parentData) : null,
  4064. parentData);
  4065. // build node and items
  4066. node = buildNode(def, node);
  4067. node.items = buildItems(def, data, node);
  4068. buildTrans(def, node);
  4069. // recurse if group
  4070. if (def.type === GROUP) {
  4071. buildGroup(def, db, node);
  4072. }
  4073. return node;
  4074. };
  4075. function buildNode(def, node) {
  4076. node = node || {};
  4077. node.def = def;
  4078. node.marktype = def.type;
  4079. node.interactive = !(def.interactive === false);
  4080. return node;
  4081. }
  4082. function buildItems(def, data, node) {
  4083. var keyf = keyFunction(def.key),
  4084. prev = node.items || [],
  4085. next = [],
  4086. map = {},
  4087. i, key, len, item, datum, enter;
  4088. for (i=0, len=prev.length; i<len; ++i) {
  4089. item = prev[i];
  4090. item.status = EXIT;
  4091. if (keyf) map[item.key] = item;
  4092. }
  4093. for (i=0, len=data.length; i<len; ++i) {
  4094. datum = data[i];
  4095. key = i;
  4096. item = keyf ? map[key = keyf(datum)] : prev[i];
  4097. enter = item ? false : (item = vg.scene.item(node), true);
  4098. item.status = enter ? ENTER : UPDATE;
  4099. item.datum = datum;
  4100. item.key = key;
  4101. next.push(item);
  4102. }
  4103. for (i=0, len=prev.length; i<len; ++i) {
  4104. item = prev[i];
  4105. if (item.status === EXIT) {
  4106. item.key = keyf ? item.key : next.length;
  4107. next.push(item);
  4108. }
  4109. }
  4110. return next;
  4111. }
  4112. function buildGroup(def, db, node) {
  4113. var groups = node.items,
  4114. marks = def.marks,
  4115. i, len, m, mlen, name, group;
  4116. for (i=0, len=groups.length; i<len; ++i) {
  4117. group = groups[i];
  4118. // update scales
  4119. if (group.scales) for (name in group.scales) {
  4120. if (name.indexOf(":prev") < 0) {
  4121. group.scales[name+":prev"] = group.scales[name].copy();
  4122. }
  4123. }
  4124. // build items
  4125. group.items = group.items || [];
  4126. for (m=0, mlen=marks.length; m<mlen; ++m) {
  4127. group.items[m] = build(marks[m], db, group.items[m], group.datum);
  4128. group.items[m].group = group;
  4129. }
  4130. }
  4131. }
  4132. function buildTrans(def, node) {
  4133. if (def.duration) node.duration = def.duration;
  4134. if (def.ease) node.ease = d3.ease(def.ease)
  4135. if (def.delay) {
  4136. var items = node.items, group = node.group, n = items.length, i;
  4137. for (i=0; i<n; ++i) def.delay.call(this, items[i], group);
  4138. }
  4139. }
  4140. function keyFunction(key) {
  4141. if (key == null) return null;
  4142. var f = vg.array(key).map(vg.accessor);
  4143. return function(d) {
  4144. for (var s="", i=0, n=f.length; i<n; ++i) {
  4145. if (i>0) s += "|";
  4146. s += String(f[i](d));
  4147. }
  4148. return s;
  4149. }
  4150. }
  4151. return build;
  4152. })();vg.scene.bounds = (function() {
  4153. var parse = vg.canvas.path.parse,
  4154. boundPath = vg.canvas.path.bounds,
  4155. areaPath = vg.canvas.path.area,
  4156. linePath = vg.canvas.path.line,
  4157. halfpi = Math.PI / 2,
  4158. sqrt3 = Math.sqrt(3),
  4159. tan30 = Math.tan(30 * Math.PI / 180),
  4160. gfx = null;
  4161. function context() {
  4162. return gfx || (gfx = (vg.config.isNode
  4163. ? new (require("canvas"))(1,1)
  4164. : d3.select("body").append("canvas")
  4165. .attr("class", "vega_hidden")
  4166. .attr("width", 1)
  4167. .attr("height", 1)
  4168. .style("display", "none")
  4169. .node())
  4170. .getContext("2d"));
  4171. }
  4172. function pathBounds(o, path, bounds) {
  4173. if (path == null) {
  4174. bounds.set(0, 0, 0, 0);
  4175. } else {
  4176. boundPath(path, bounds);
  4177. if (o.stroke && o.opacity !== 0 && o.strokeWidth > 0) {
  4178. bounds.expand(o.strokeWidth);
  4179. }
  4180. }
  4181. return bounds;
  4182. }
  4183. function path(o, bounds) {
  4184. var p = o.path
  4185. ? o["path:parsed"] || (o["path:parsed"] = parse(o.path))
  4186. : null;
  4187. return pathBounds(o, p, bounds);
  4188. }
  4189. function area(o, bounds) {
  4190. var items = o.mark.items, o = items[0];
  4191. var p = o["path:parsed"] || (o["path:parsed"]=parse(areaPath(items)));
  4192. return pathBounds(items[0], p, bounds);
  4193. }
  4194. function line(o, bounds) {
  4195. var items = o.mark.items, o = items[0];
  4196. var p = o["path:parsed"] || (o["path:parsed"]=parse(linePath(items)));
  4197. return pathBounds(items[0], p, bounds);
  4198. }
  4199. function rect(o, bounds) {
  4200. var x = o.x || 0,
  4201. y = o.y || 0,
  4202. w = (x + o.width) || 0,
  4203. h = (y + o.height) || 0;
  4204. bounds.set(x, y, w, h);
  4205. if (o.stroke && o.opacity !== 0 && o.strokeWidth > 0) {
  4206. bounds.expand(o.strokeWidth);
  4207. }
  4208. return bounds;
  4209. }
  4210. function image(o, bounds) {
  4211. var w = o.width || 0,
  4212. h = o.height || 0,
  4213. x = (o.x||0) - (o.align === "center"
  4214. ? w/2 : (o.align === "right" ? w : 0)),
  4215. y = (o.y||0) - (o.baseline === "middle"
  4216. ? h/2 : (o.baseline === "bottom" ? h : 0));
  4217. return bounds.set(x, y, x+w, y+h);
  4218. }
  4219. function rule(o, bounds) {
  4220. var x1, y1;
  4221. bounds.set(
  4222. x1 = o.x || 0,
  4223. y1 = o.y || 0,
  4224. o.x2 != null ? o.x2 : x1,
  4225. o.y2 != null ? o.y2 : y1
  4226. );
  4227. if (o.stroke && o.opacity !== 0 && o.strokeWidth > 0) {
  4228. bounds.expand(o.strokeWidth);
  4229. }
  4230. return bounds;
  4231. }
  4232. function arc(o, bounds) {
  4233. var cx = o.x || 0,
  4234. cy = o.y || 0,
  4235. ir = o.innerRadius || 0,
  4236. or = o.outerRadius || 0,
  4237. sa = (o.startAngle || 0) - halfpi,
  4238. ea = (o.endAngle || 0) - halfpi,
  4239. xmin = Infinity, xmax = -Infinity,
  4240. ymin = Infinity, ymax = -Infinity,
  4241. a, i, n, x, y, ix, iy, ox, oy;
  4242. var angles = [sa, ea],
  4243. s = sa - (sa%halfpi);
  4244. for (i=0; i<4 && s<ea; ++i, s+=halfpi) {
  4245. angles.push(s);
  4246. }
  4247. for (i=0, n=angles.length; i<n; ++i) {
  4248. a = angles[i];
  4249. x = Math.cos(a); ix = ir*x; ox = or*x;
  4250. y = Math.sin(a); iy = ir*y; oy = or*y;
  4251. xmin = Math.min(xmin, ix, ox);
  4252. xmax = Math.max(xmax, ix, ox);
  4253. ymin = Math.min(ymin, iy, oy);
  4254. ymax = Math.max(ymax, iy, oy);
  4255. }
  4256. bounds.set(cx+xmin, cy+ymin, cx+xmax, cy+ymax);
  4257. if (o.stroke && o.opacity !== 0 && o.strokeWidth > 0) {
  4258. bounds.expand(o.strokeWidth);
  4259. }
  4260. return bounds;
  4261. }
  4262. function symbol(o, bounds) {
  4263. var size = o.size != null ? o.size : 100,
  4264. x = o.x || 0,
  4265. y = o.y || 0,
  4266. r, t, rx, ry;
  4267. switch (o.shape) {
  4268. case "cross":
  4269. r = Math.sqrt(size / 5) / 2;
  4270. t = 3*r;
  4271. bounds.set(x-t, y-t, x+y, y+t);
  4272. break;
  4273. case "diamond":
  4274. ry = Math.sqrt(size / (2 * tan30));
  4275. rx = ry * tan30;
  4276. bounds.set(x-rx, y-ry, x+rx, y+ry);
  4277. break;
  4278. case "square":
  4279. t = Math.sqrt(size);
  4280. r = t / 2;
  4281. bounds.set(x-r, y-r, x+r, y+r);
  4282. break;
  4283. case "triangle-down":
  4284. rx = Math.sqrt(size / sqrt3);
  4285. ry = rx * sqrt3 / 2;
  4286. bounds.set(x-rx, y-ry, x+rx, y+ry);
  4287. break;
  4288. case "triangle-up":
  4289. rx = Math.sqrt(size / sqrt3);
  4290. ry = rx * sqrt3 / 2;
  4291. bounds.set(x-rx, y-ry, x+rx, y+ry);
  4292. break;
  4293. default:
  4294. r = Math.sqrt(size/Math.PI);
  4295. bounds.set(x-r, y-r, x+r, y+r);
  4296. }
  4297. if (o.stroke && o.opacity !== 0 && o.strokeWidth > 0) {
  4298. bounds.expand(o.strokeWidth);
  4299. }
  4300. return bounds;
  4301. }
  4302. function text(o, bounds, noRotate) {
  4303. var x = (o.x || 0) + (o.dx || 0),
  4304. y = (o.y || 0) + (o.dy || 0),
  4305. h = o.fontSize || vg.config.render.fontSize,
  4306. a = o.align,
  4307. b = o.baseline,
  4308. g = context(), w;
  4309. g.font = vg.scene.fontString(o);
  4310. g.textAlign = a || "left";
  4311. g.textBaseline = b || "alphabetic";
  4312. w = g.measureText(o.text || "").width;
  4313. // horizontal
  4314. if (a === "center") {
  4315. x = x - (w / 2);
  4316. } else if (a === "right") {
  4317. x = x - w;
  4318. } else {
  4319. // left by default, do nothing
  4320. }
  4321. /// TODO find a robust solution for heights.
  4322. /// These offsets work for some but not all fonts.
  4323. // vertical
  4324. if (b === "top") {
  4325. y = y + (h/5);
  4326. } else if (b === "bottom") {
  4327. y = y - h;
  4328. } else if (b === "middle") {
  4329. y = y - (h/2) + (h/10);
  4330. } else {
  4331. y = y - 4*h/5; // alphabetic by default
  4332. }
  4333. bounds.set(x, y, x+w, y+h);
  4334. if (o.angle && !noRotate) {
  4335. bounds.rotate(o.angle*Math.PI/180, o.x||0, o.y||0);
  4336. }
  4337. return bounds.expand(noRotate ? 0 : 1);
  4338. }
  4339. function group(g, bounds, includeLegends) {
  4340. var axes = g.axisItems || [],
  4341. legends = g.legendItems || [], j, m;
  4342. for (j=0, m=axes.length; j<m; ++j) {
  4343. bounds.union(axes[j].bounds);
  4344. }
  4345. for (j=0, m=g.items.length; j<m; ++j) {
  4346. bounds.union(g.items[j].bounds);
  4347. }
  4348. if (includeLegends) {
  4349. for (j=0, m=legends.length; j<m; ++j) {
  4350. bounds.union(legends[j].bounds);
  4351. }
  4352. if (g.width != null && g.height != null) {
  4353. bounds.add(g.width, g.height);
  4354. }
  4355. if (g.x != null && g.y != null) {
  4356. bounds.add(0, 0);
  4357. }
  4358. }
  4359. bounds.translate(g.x||0, g.y||0);
  4360. return bounds;
  4361. }
  4362. var methods = {
  4363. group: group,
  4364. symbol: symbol,
  4365. image: image,
  4366. rect: rect,
  4367. rule: rule,
  4368. arc: arc,
  4369. text: text,
  4370. path: path,
  4371. area: area,
  4372. line: line
  4373. };
  4374. function itemBounds(item, func, opt) {
  4375. func = func || methods[item.mark.marktype];
  4376. if (!item.bounds_prev) item['bounds:prev'] = new vg.Bounds();
  4377. var b = item.bounds, pb = item['bounds:prev'];
  4378. if (b) pb.clear().union(b);
  4379. item.bounds = func(item, b ? b.clear() : new vg.Bounds(), opt);
  4380. if (!b) pb.clear().union(item.bounds);
  4381. return item.bounds;
  4382. }
  4383. function markBounds(mark, bounds, opt) {
  4384. bounds = bounds || mark.bounds && mark.bounds.clear() || new vg.Bounds();
  4385. var type = mark.marktype,
  4386. func = methods[type],
  4387. items = mark.items,
  4388. item, i, len;
  4389. if (type==="area" || type==="line") {
  4390. items[0].bounds = func(items[0], bounds);
  4391. } else {
  4392. for (i=0, len=items.length; i<len; ++i) {
  4393. bounds.union(itemBounds(items[i], func, opt));
  4394. }
  4395. }
  4396. mark.bounds = bounds;
  4397. }
  4398. return {
  4399. mark: markBounds,
  4400. item: itemBounds,
  4401. text: text,
  4402. group: group
  4403. };
  4404. })();vg.scene.encode = (function() {
  4405. var GROUP = vg.scene.GROUP,
  4406. ENTER = vg.scene.ENTER,
  4407. UPDATE = vg.scene.UPDATE,
  4408. EXIT = vg.scene.EXIT,
  4409. EMPTY = {};
  4410. function main(scene, def, trans, request, items) {
  4411. (request && items)
  4412. ? update.call(this, scene, def, trans, request, items)
  4413. : encode.call(this, scene, scene, def, trans, request);
  4414. return scene;
  4415. }
  4416. function update(scene, def, trans, request, items) {
  4417. items = vg.array(items);
  4418. var i, len, item, group, props, prop;
  4419. for (i=0, len=items.length; i<len; ++i) {
  4420. item = items[i];
  4421. group = item.mark.group || null;
  4422. props = item.mark.def.properties;
  4423. prop = props && props[request];
  4424. if (prop) {
  4425. prop.call(vg, item, group, trans);
  4426. vg.scene.bounds.item(item);
  4427. }
  4428. }
  4429. }
  4430. function encode(group, scene, def, trans, request) {
  4431. encodeItems.call(this, group, scene.items, def, trans, request);
  4432. if (scene.marktype === GROUP) {
  4433. encodeGroup.call(this, scene, def, group, trans, request);
  4434. } else {
  4435. vg.scene.bounds.mark(scene);
  4436. }
  4437. }
  4438. function encodeLegend(group, scene, def, trans, request) {
  4439. encodeGroup.call(this, scene, def, group, trans, request);
  4440. encodeItems.call(this, group, scene.items, def, trans, request);
  4441. vg.scene.bounds.mark(scene, null, true);
  4442. }
  4443. function encodeGroup(scene, def, parent, trans, request) {
  4444. var i, len, m, mlen, group, scales,
  4445. axes, axisItems, axisDef, leg, legItems, legDef;
  4446. for (i=0, len=scene.items.length; i<len; ++i) {
  4447. group = scene.items[i];
  4448. // cascade scales recursively
  4449. // use parent scales if there are no group-level scale defs
  4450. scales = group.scales || (group.scales =
  4451. def.scales ? vg.extend({}, parent.scales) : parent.scales);
  4452. // update group-level scales
  4453. if (def.scales) {
  4454. vg.parse.scales(def.scales, scales, this._data, group);
  4455. }
  4456. // update group-level axes
  4457. if (def.axes) {
  4458. axes = group.axes || (group.axes = []);
  4459. axisItems = group.axisItems || (group.axisItems = []);
  4460. vg.parse.axes(def.axes, axes, group.scales);
  4461. axes.forEach(function(a, i) {
  4462. axisDef = a.def();
  4463. axisItems[i] = vg.scene.build(axisDef, this._data, axisItems[i]);
  4464. axisItems[i].group = group;
  4465. encode.call(this, group, group.axisItems[i], axisDef, trans);
  4466. });
  4467. }
  4468. // encode children marks
  4469. for (m=0, mlen=group.items.length; m<mlen; ++m) {
  4470. encode.call(this, group, group.items[m], def.marks[m], trans, request);
  4471. }
  4472. }
  4473. // compute bounds (without legend)
  4474. vg.scene.bounds.mark(scene, null, !def.legends);
  4475. // update legends
  4476. if (def.legends) {
  4477. for (i=0, len=scene.items.length; i<len; ++i) {
  4478. group = scene.items[i];
  4479. leg = group.legends || (group.legends = []);
  4480. legItems = group.legendItems || (group.legendItems = []);
  4481. vg.parse.legends(def.legends, leg, group.scales);
  4482. leg.forEach(function(l, i) {
  4483. legDef = l.def();
  4484. legItems[i] = vg.scene.build(legDef, this._data, legItems[i]);
  4485. legItems[i].group = group;
  4486. encodeLegend.call(this, group, group.legendItems[i], legDef, trans);
  4487. });
  4488. }
  4489. vg.scene.bounds.mark(scene, null, true);
  4490. }
  4491. }
  4492. function encodeItems(group, items, def, trans, request) {
  4493. var props = def.properties || EMPTY,
  4494. enter = props.enter,
  4495. update = props.update,
  4496. exit = props.exit,
  4497. i, len, item, prop;
  4498. if (request) {
  4499. if (prop = props[request]) {
  4500. for (i=0, len=items.length; i<len; ++i) {
  4501. prop.call(vg, items[i], group, trans);
  4502. }
  4503. }
  4504. return; // exit early if given request
  4505. }
  4506. for (i=0; i<items.length; ++i) {
  4507. item = items[i];
  4508. // enter set
  4509. if (item.status === ENTER) {
  4510. if (enter) enter.call(vg, item, group);
  4511. item.status = UPDATE;
  4512. }
  4513. // update set
  4514. if (item.status !== EXIT && update) {
  4515. update.call(vg, item, group, trans);
  4516. }
  4517. // exit set
  4518. if (item.status === EXIT) {
  4519. if (exit) exit.call(vg, item, group, trans);
  4520. if (trans && !exit) trans.interpolate(item, EMPTY);
  4521. else if (!trans) items[i--].remove();
  4522. }
  4523. }
  4524. }
  4525. return main;
  4526. })();vg.scene.Transition = (function() {
  4527. function trans(duration, ease) {
  4528. this.duration = duration || 500;
  4529. this.ease = ease && d3.ease(ease) || d3.ease("cubic-in-out");
  4530. this.updates = {next: null};
  4531. }
  4532. var prototype = trans.prototype;
  4533. prototype.interpolate = function(item, values) {
  4534. var key, curr, next, interp, list = null;
  4535. for (key in values) {
  4536. curr = item[key];
  4537. next = values[key];
  4538. if (curr !== next) {
  4539. if (key === "text") {
  4540. // skip interpolation for text labels
  4541. item[key] = next;
  4542. } else {
  4543. // otherwise lookup interpolator
  4544. interp = d3.interpolate(curr, next);
  4545. interp.property = key;
  4546. (list || (list=[])).push(interp);
  4547. }
  4548. }
  4549. }
  4550. if (list === null && item.status === vg.scene.EXIT) {
  4551. list = []; // ensure exiting items are included
  4552. }
  4553. if (list != null) {
  4554. list.item = item;
  4555. list.ease = item.mark.ease || this.ease;
  4556. list.next = this.updates.next;
  4557. this.updates.next = list;
  4558. }
  4559. return this;
  4560. };
  4561. prototype.start = function(callback) {
  4562. var t = this, prev = t.updates, curr = prev.next;
  4563. for (; curr!=null; prev=curr, curr=prev.next) {
  4564. if (curr.item.status === vg.scene.EXIT) curr.remove = true;
  4565. }
  4566. t.callback = callback;
  4567. d3.timer(function(elapsed) { return step.call(t, elapsed); });
  4568. };
  4569. function step(elapsed) {
  4570. var list = this.updates, prev = list, curr = prev.next,
  4571. duration = this.duration,
  4572. item, delay, f, e, i, n, stop = true;
  4573. for (; curr!=null; prev=curr, curr=prev.next) {
  4574. item = curr.item;
  4575. delay = item.delay || 0;
  4576. f = (elapsed - delay) / duration;
  4577. if (f < 0) { stop = false; continue; }
  4578. if (f > 1) f = 1;
  4579. e = curr.ease(f);
  4580. for (i=0, n=curr.length; i<n; ++i) {
  4581. item[curr[i].property] = curr[i](e);
  4582. vg.scene.bounds.item(item);
  4583. }
  4584. if (f === 1) {
  4585. if (curr.remove) item.remove();
  4586. prev.next = curr.next;
  4587. curr = prev;
  4588. } else {
  4589. stop = false;
  4590. }
  4591. }
  4592. this.callback();
  4593. return stop;
  4594. };
  4595. return trans;
  4596. })();
  4597. vg.scene.transition = function(dur, ease) {
  4598. return new vg.scene.Transition(dur, ease);
  4599. };vg.scene.axis = function() {
  4600. var scale,
  4601. orient = vg.config.axis.orient,
  4602. offset = 0,
  4603. titleOffset = vg.config.axis.titleOffset,
  4604. axisDef = null,
  4605. layer = "front",
  4606. grid = false,
  4607. title = null,
  4608. tickMajorSize = vg.config.axis.tickSize,
  4609. tickMinorSize = vg.config.axis.tickSize,
  4610. tickEndSize = vg.config.axis.tickSize,
  4611. tickPadding = vg.config.axis.padding,
  4612. tickValues = null,
  4613. tickFormat = null,
  4614. tickSubdivide = 0,
  4615. tickArguments = [vg.config.axis.ticks],
  4616. gridLineStyle = {},
  4617. tickLabelStyle = {},
  4618. majorTickStyle = {},
  4619. minorTickStyle = {},
  4620. titleStyle = {},
  4621. domainStyle = {};
  4622. var axis = {};
  4623. function reset() { axisDef = null; }
  4624. axis.def = function() {
  4625. var def = axisDef ? axisDef : (axisDef = axis_def(scale));
  4626. // generate data
  4627. var major = tickValues == null
  4628. ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain())
  4629. : tickValues;
  4630. var minor = vg_axisSubdivide(scale, major, tickSubdivide).map(vg.data.ingest);
  4631. major = major.map(vg.data.ingest);
  4632. var fmt = tickFormat==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : tickFormat;
  4633. major.forEach(function(d) { d.label = fmt(d.data); });
  4634. var tdata = title ? [title].map(vg.data.ingest) : [];
  4635. // update axis def
  4636. def.marks[0].from = function() { return grid ? major : []; };
  4637. def.marks[1].from = function() { return major; };
  4638. def.marks[2].from = function() { return minor; };
  4639. def.marks[3].from = def.marks[1].from;
  4640. def.marks[4].from = function() { return [1]; };
  4641. def.marks[5].from = function() { return tdata; };
  4642. def.offset = offset;
  4643. def.orient = orient;
  4644. def.layer = layer;
  4645. return def;
  4646. };
  4647. function axis_def(scale) {
  4648. // setup scale mapping
  4649. var newScale, oldScale, range;
  4650. if (scale.type === "ordinal") {
  4651. newScale = {scale: scale.scaleName, offset: 0.5 + scale.rangeBand()/2};
  4652. oldScale = newScale;
  4653. } else {
  4654. newScale = {scale: scale.scaleName, offset: 0.5};
  4655. oldScale = {scale: scale.scaleName+":prev", offset: 0.5};
  4656. }
  4657. range = vg_axisScaleRange(scale);
  4658. // setup axis marks
  4659. var gridLines = vg_axisTicks();
  4660. var majorTicks = vg_axisTicks();
  4661. var minorTicks = vg_axisTicks();
  4662. var tickLabels = vg_axisTickLabels();
  4663. var domain = vg_axisDomain();
  4664. var title = vg_axisTitle();
  4665. gridLines.properties.enter.stroke = {value: vg.config.axis.gridColor};
  4666. // extend axis marks based on axis orientation
  4667. vg_axisTicksExtend(orient, gridLines, oldScale, newScale, Infinity);
  4668. vg_axisTicksExtend(orient, majorTicks, oldScale, newScale, tickMajorSize);
  4669. vg_axisTicksExtend(orient, minorTicks, oldScale, newScale, tickMinorSize);
  4670. vg_axisLabelExtend(orient, tickLabels, oldScale, newScale, tickMajorSize, tickPadding);
  4671. vg_axisDomainExtend(orient, domain, range, tickEndSize);
  4672. vg_axisTitleExtend(orient, title, range, titleOffset); // TODO get offset
  4673. // add / override custom style properties
  4674. vg.extend(gridLines.properties.update, gridLineStyle);
  4675. vg.extend(majorTicks.properties.update, majorTickStyle);
  4676. vg.extend(minorTicks.properties.update, minorTickStyle);
  4677. vg.extend(tickLabels.properties.update, tickLabelStyle);
  4678. vg.extend(domain.properties.update, domainStyle);
  4679. vg.extend(title.properties.update, titleStyle);
  4680. var marks = [gridLines, majorTicks, minorTicks, tickLabels, domain, title];
  4681. return {
  4682. type: "group",
  4683. interactive: false,
  4684. properties: { enter: vg_axisUpdate, update: vg_axisUpdate },
  4685. marks: marks.map(vg.parse.mark)
  4686. };
  4687. }
  4688. axis.scale = function(x) {
  4689. if (!arguments.length) return scale;
  4690. if (scale !== x) { scale = x; reset(); }
  4691. return axis;
  4692. };
  4693. axis.orient = function(x) {
  4694. if (!arguments.length) return orient;
  4695. if (orient !== x) {
  4696. orient = x in vg_axisOrients ? x + "" : vg.config.axis.orient;
  4697. reset();
  4698. }
  4699. return axis;
  4700. };
  4701. axis.title = function(x) {
  4702. if (!arguments.length) return title;
  4703. if (title !== x) { title = x; reset(); }
  4704. return axis;
  4705. };
  4706. axis.ticks = function() {
  4707. if (!arguments.length) return tickArguments;
  4708. tickArguments = arguments;
  4709. return axis;
  4710. };
  4711. axis.tickValues = function(x) {
  4712. if (!arguments.length) return tickValues;
  4713. tickValues = x;
  4714. return axis;
  4715. };
  4716. axis.tickFormat = function(x) {
  4717. if (!arguments.length) return tickFormat;
  4718. tickFormat = x;
  4719. return axis;
  4720. };
  4721. axis.tickSize = function(x, y) {
  4722. if (!arguments.length) return tickMajorSize;
  4723. var n = arguments.length - 1,
  4724. major = +x,
  4725. minor = n > 1 ? +y : tickMajorSize,
  4726. end = n > 0 ? +arguments[n] : tickMajorSize;
  4727. if (tickMajorSize !== major ||
  4728. tickMinorSize !== minor ||
  4729. tickEndSize !== end) {
  4730. reset();
  4731. }
  4732. tickMajorSize = major;
  4733. tickMinorSize = minor;
  4734. tickEndSize = end;
  4735. return axis;
  4736. };
  4737. axis.tickSubdivide = function(x) {
  4738. if (!arguments.length) return tickSubdivide;
  4739. tickSubdivide = +x;
  4740. return axis;
  4741. };
  4742. axis.offset = function(x) {
  4743. if (!arguments.length) return offset;
  4744. offset = vg.isObject(x) ? x : +x;
  4745. return axis;
  4746. };
  4747. axis.tickPadding = function(x) {
  4748. if (!arguments.length) return tickPadding;
  4749. if (tickPadding !== +x) { tickPadding = +x; reset(); }
  4750. return axis;
  4751. };
  4752. axis.titleOffset = function(x) {
  4753. if (!arguments.length) return titleOffset;
  4754. if (titleOffset !== +x) { titleOffset = +x; reset(); }
  4755. return axis;
  4756. };
  4757. axis.layer = function(x) {
  4758. if (!arguments.length) return layer;
  4759. if (layer !== x) { layer = x; reset(); }
  4760. return axis;
  4761. };
  4762. axis.grid = function(x) {
  4763. if (!arguments.length) return grid;
  4764. if (grid !== x) { grid = x; reset(); }
  4765. return axis;
  4766. };
  4767. axis.gridLineProperties = function(x) {
  4768. if (!arguments.length) return gridLineStyle;
  4769. if (gridLineStyle !== x) { gridLineStyle = x; }
  4770. return axis;
  4771. };
  4772. axis.majorTickProperties = function(x) {
  4773. if (!arguments.length) return majorTickStyle;
  4774. if (majorTickStyle !== x) { majorTickStyle = x; }
  4775. return axis;
  4776. };
  4777. axis.minorTickProperties = function(x) {
  4778. if (!arguments.length) return minorTickStyle;
  4779. if (minorTickStyle !== x) { minorTickStyle = x; }
  4780. return axis;
  4781. };
  4782. axis.tickLabelProperties = function(x) {
  4783. if (!arguments.length) return tickLabelStyle;
  4784. if (tickLabelStyle !== x) { tickLabelStyle = x; }
  4785. return axis;
  4786. };
  4787. axis.titleProperties = function(x) {
  4788. if (!arguments.length) return titleStyle;
  4789. if (titleStyle !== x) { titleStyle = x; }
  4790. return axis;
  4791. };
  4792. axis.domainProperties = function(x) {
  4793. if (!arguments.length) return domainStyle;
  4794. if (domainStyle !== x) { domainStyle = x; }
  4795. return axis;
  4796. };
  4797. axis.reset = function() { reset(); };
  4798. return axis;
  4799. };
  4800. var vg_axisOrients = {top: 1, right: 1, bottom: 1, left: 1};
  4801. function vg_axisSubdivide(scale, ticks, m) {
  4802. subticks = [];
  4803. if (m && ticks.length > 1) {
  4804. var extent = vg_axisScaleExtent(scale.domain()),
  4805. subticks,
  4806. i = -1,
  4807. n = ticks.length,
  4808. d = (ticks[1] - ticks[0]) / ++m,
  4809. j,
  4810. v;
  4811. while (++i < n) {
  4812. for (j = m; --j > 0;) {
  4813. if ((v = +ticks[i] - j * d) >= extent[0]) {
  4814. subticks.push(v);
  4815. }
  4816. }
  4817. }
  4818. for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
  4819. subticks.push(v);
  4820. }
  4821. }
  4822. return subticks;
  4823. }
  4824. function vg_axisScaleExtent(domain) {
  4825. var start = domain[0], stop = domain[domain.length - 1];
  4826. return start < stop ? [start, stop] : [stop, start];
  4827. }
  4828. function vg_axisScaleRange(scale) {
  4829. return scale.rangeExtent
  4830. ? scale.rangeExtent()
  4831. : vg_axisScaleExtent(scale.range());
  4832. }
  4833. var vg_axisAlign = {
  4834. bottom: "center",
  4835. top: "center",
  4836. left: "right",
  4837. right: "left"
  4838. };
  4839. var vg_axisBaseline = {
  4840. bottom: "top",
  4841. top: "bottom",
  4842. left: "middle",
  4843. right: "middle"
  4844. };
  4845. function vg_axisLabelExtend(orient, labels, oldScale, newScale, size, pad) {
  4846. size = Math.max(size, 0) + pad;
  4847. if (orient === "left" || orient === "top") {
  4848. size *= -1;
  4849. }
  4850. if (orient === "top" || orient === "bottom") {
  4851. vg.extend(labels.properties.enter, {
  4852. x: oldScale,
  4853. y: {value: size},
  4854. });
  4855. vg.extend(labels.properties.update, {
  4856. x: newScale,
  4857. y: {value: size},
  4858. align: {value: "center"},
  4859. baseline: {value: vg_axisBaseline[orient]}
  4860. });
  4861. } else {
  4862. vg.extend(labels.properties.enter, {
  4863. x: {value: size},
  4864. y: oldScale,
  4865. });
  4866. vg.extend(labels.properties.update, {
  4867. x: {value: size},
  4868. y: newScale,
  4869. align: {value: vg_axisAlign[orient]},
  4870. baseline: {value: "middle"}
  4871. });
  4872. }
  4873. }
  4874. function vg_axisTicksExtend(orient, ticks, oldScale, newScale, size) {
  4875. var sign = (orient === "left" || orient === "top") ? -1 : 1;
  4876. if (size === Infinity) {
  4877. size = (orient === "top" || orient === "bottom")
  4878. ? {group: "mark.group.height", mult: -sign}
  4879. : {group: "mark.group.width", mult: -sign};
  4880. } else {
  4881. size = {value: sign * size};
  4882. }
  4883. if (orient === "top" || orient === "bottom") {
  4884. vg.extend(ticks.properties.enter, {
  4885. x: oldScale,
  4886. y: {value: 0},
  4887. y2: size
  4888. });
  4889. vg.extend(ticks.properties.update, {
  4890. x: newScale,
  4891. y: {value: 0},
  4892. y2: size
  4893. });
  4894. vg.extend(ticks.properties.exit, {
  4895. x: newScale,
  4896. });
  4897. } else {
  4898. vg.extend(ticks.properties.enter, {
  4899. x: {value: 0},
  4900. x2: size,
  4901. y: oldScale
  4902. });
  4903. vg.extend(ticks.properties.update, {
  4904. x: {value: 0},
  4905. x2: size,
  4906. y: newScale
  4907. });
  4908. vg.extend(ticks.properties.exit, {
  4909. y: newScale,
  4910. });
  4911. }
  4912. }
  4913. function vg_axisTitleExtend(orient, title, range, offset) {
  4914. var mid = ~~((range[1] - range[0]) / 2),
  4915. sign = (orient === "top" || orient === "left") ? -1 : 1;
  4916. if (orient === "bottom" || orient === "top") {
  4917. vg.extend(title.properties.update, {
  4918. x: {value: mid},
  4919. y: {value: sign*offset},
  4920. angle: {value: 0}
  4921. });
  4922. } else {
  4923. vg.extend(title.properties.update, {
  4924. x: {value: sign*offset},
  4925. y: {value: mid},
  4926. angle: {value: -90}
  4927. });
  4928. }
  4929. }
  4930. function vg_axisDomainExtend(orient, domain, range, size) {
  4931. var path;
  4932. if (orient === "top" || orient === "left") {
  4933. size = -1 * size;
  4934. }
  4935. if (orient === "bottom" || orient === "top") {
  4936. path = "M" + range[0] + "," + size + "V0H" + range[1] + "V" + size;
  4937. } else {
  4938. path = "M" + size + "," + range[0] + "H0V" + range[1] + "H" + size;
  4939. }
  4940. domain.properties.update.path = {value: path};
  4941. }
  4942. function vg_axisUpdate(item, group, trans) {
  4943. var o = trans ? {} : item,
  4944. offset = item.mark.def.offset,
  4945. orient = item.mark.def.orient,
  4946. width = group.width,
  4947. height = group.height; // TODO fallback to global w,h?
  4948. if (vg.isObject(offset)) {
  4949. offset = -group.scales[offset.scale](offset.value);
  4950. }
  4951. switch (orient) {
  4952. case "left": { o.x = -offset; o.y = 0; break; }
  4953. case "right": { o.x = width + offset; o.y = 0; break; }
  4954. case "bottom": { o.x = 0; o.y = height + offset; break; }
  4955. case "top": { o.x = 0; o.y = -offset; break; }
  4956. default: { o.x = 0; o.y = 0; }
  4957. }
  4958. if (trans) trans.interpolate(item, o);
  4959. }
  4960. function vg_axisTicks() {
  4961. return {
  4962. type: "rule",
  4963. interactive: false,
  4964. key: "data",
  4965. properties: {
  4966. enter: {
  4967. stroke: {value: vg.config.axis.tickColor},
  4968. strokeWidth: {value: vg.config.axis.tickWidth},
  4969. opacity: {value: 1e-6}
  4970. },
  4971. exit: { opacity: {value: 1e-6} },
  4972. update: { opacity: {value: 1} }
  4973. }
  4974. };
  4975. }
  4976. function vg_axisTickLabels() {
  4977. return {
  4978. type: "text",
  4979. interactive: true,
  4980. key: "data",
  4981. properties: {
  4982. enter: {
  4983. fill: {value: vg.config.axis.tickLabelColor},
  4984. font: {value: vg.config.axis.tickLabelFont},
  4985. fontSize: {value: vg.config.axis.tickLabelFontSize},
  4986. opacity: {value: 1e-6},
  4987. text: {field: "label"}
  4988. },
  4989. exit: { opacity: {value: 1e-6} },
  4990. update: { opacity: {value: 1} }
  4991. }
  4992. };
  4993. }
  4994. function vg_axisTitle() {
  4995. return {
  4996. type: "text",
  4997. interactive: true,
  4998. properties: {
  4999. enter: {
  5000. font: {value: vg.config.axis.titleFont},
  5001. fontSize: {value: vg.config.axis.titleFontSize},
  5002. fontWeight: {value: vg.config.axis.titleFontWeight},
  5003. fill: {value: vg.config.axis.titleColor},
  5004. align: {value: "center"},
  5005. baseline: {value: "middle"},
  5006. text: {field: "data"}
  5007. },
  5008. update: {}
  5009. }
  5010. };
  5011. }
  5012. function vg_axisDomain() {
  5013. return {
  5014. type: "path",
  5015. interactive: false,
  5016. properties: {
  5017. enter: {
  5018. x: {value: 0.5},
  5019. y: {value: 0.5},
  5020. stroke: {value: vg.config.axis.axisColor},
  5021. strokeWidth: {value: vg.config.axis.axisWidth}
  5022. },
  5023. update: {}
  5024. }
  5025. };
  5026. }
  5027. vg.scene.legend = function() {
  5028. var size = null,
  5029. shape = null,
  5030. fill = null,
  5031. stroke = null,
  5032. spacing = null,
  5033. values = null,
  5034. format = null,
  5035. title = undefined,
  5036. orient = "right",
  5037. offset = vg.config.legend.offset,
  5038. padding = vg.config.legend.padding,
  5039. legendDef,
  5040. tickArguments = [5],
  5041. legendStyle = {},
  5042. symbolStyle = {},
  5043. gradientStyle = {},
  5044. titleStyle = {},
  5045. labelStyle = {};
  5046. var legend = {},
  5047. legendDef = null;
  5048. function reset() { legendDef = null; }
  5049. legend.def = function() {
  5050. var scale = size || shape || fill || stroke;
  5051. if (!legendDef) {
  5052. legendDef = (scale===fill || scale===stroke) && !discrete(scale.type)
  5053. ? quantDef(scale)
  5054. : ordinalDef(scale);
  5055. }
  5056. legendDef.orient = orient;
  5057. legendDef.offset = offset;
  5058. legendDef.padding = padding;
  5059. return legendDef;
  5060. };
  5061. function discrete(type) {
  5062. return type==="ordinal" || type==="quantize"
  5063. || type==="quantile" || type==="threshold";
  5064. }
  5065. function ordinalDef(scale) {
  5066. var def = o_legend_def(size, shape, fill, stroke);
  5067. // generate data
  5068. var data = (values == null
  5069. ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain())
  5070. : values).map(vg.data.ingest);
  5071. var fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
  5072. // determine spacing between legend entries
  5073. var fs, range, offset, pad=5, domain = d3.range(data.length);
  5074. if (size) {
  5075. range = data.map(function(x) { return Math.sqrt(size(x.data)); });
  5076. offset = d3.max(range);
  5077. range = range.reduce(function(a,b,i,z) {
  5078. if (i > 0) a[i] = a[i-1] + z[i-1]/2 + pad;
  5079. return (a[i] += b/2, a); }, [0]).map(Math.round);
  5080. } else {
  5081. offset = Math.round(Math.sqrt(vg.config.legend.symbolSize));
  5082. range = spacing
  5083. || (fs = labelStyle.fontSize) && (fs.value + pad)
  5084. || (vg.config.legend.labelFontSize + pad);
  5085. range = domain.map(function(d,i) {
  5086. return Math.round(offset/2 + i*range);
  5087. });
  5088. }
  5089. // account for padding and title size
  5090. var sz = padding, ts;
  5091. if (title) {
  5092. ts = titleStyle.fontSize;
  5093. sz += 5 + ((ts && ts.value) || vg.config.legend.titleFontSize);
  5094. }
  5095. for (var i=0, n=range.length; i<n; ++i) range[i] += sz;
  5096. // build scale for label layout
  5097. var scale = {
  5098. name: "legend",
  5099. type: "ordinal",
  5100. points: true,
  5101. domain: domain,
  5102. range: range
  5103. };
  5104. // update legend def
  5105. var tdata = (title ? [title] : []).map(vg.data.ingest);
  5106. data.forEach(function(d) {
  5107. d.label = fmt(d.data);
  5108. d.offset = offset;
  5109. });
  5110. def.scales = [ scale ];
  5111. def.marks[0].from = function() { return tdata; };
  5112. def.marks[1].from = function() { return data; };
  5113. def.marks[2].from = def.marks[1].from;
  5114. return def;
  5115. }
  5116. function o_legend_def(size, shape, fill, stroke) {
  5117. // setup legend marks
  5118. var titles = vg_legendTitle(),
  5119. symbols = vg_legendSymbols(),
  5120. labels = vg_vLegendLabels();
  5121. // extend legend marks
  5122. vg_legendSymbolExtend(symbols, size, shape, fill, stroke);
  5123. // add / override custom style properties
  5124. vg.extend(titles.properties.update, titleStyle);
  5125. vg.extend(symbols.properties.update, symbolStyle);
  5126. vg.extend(labels.properties.update, labelStyle);
  5127. // padding from legend border
  5128. titles.properties.enter.x.value += padding;
  5129. titles.properties.enter.y.value += padding;
  5130. labels.properties.enter.x.offset += padding + 1;
  5131. symbols.properties.enter.x.offset = padding + 1;
  5132. return {
  5133. type: "group",
  5134. interactive: false,
  5135. properties: {
  5136. enter: vg.parse.properties("group", legendStyle),
  5137. update: vg_legendUpdate
  5138. },
  5139. marks: [titles, symbols, labels].map(vg.parse.mark)
  5140. };
  5141. }
  5142. function quantDef(scale) {
  5143. var def = q_legend_def(scale),
  5144. dom = scale.domain(),
  5145. data = dom.map(vg.data.ingest),
  5146. width = (gradientStyle.width && gradientStyle.width.value) || vg.config.legend.gradientWidth,
  5147. fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
  5148. // build scale for label layout
  5149. var layout = {
  5150. name: "legend",
  5151. type: scale.type,
  5152. round: true,
  5153. zero: false,
  5154. domain: [dom[0], dom[dom.length-1]],
  5155. range: [padding, width+padding]
  5156. };
  5157. if (scale.type==="pow") layout.exponent = scale.exponent();
  5158. // update legend def
  5159. var tdata = (title ? [title] : []).map(vg.data.ingest);
  5160. data.forEach(function(d,i) {
  5161. d.label = fmt(d.data);
  5162. d.align = i==(data.length-1) ? "right" : i==0 ? "left" : "center";
  5163. });
  5164. def.scales = [ layout ];
  5165. def.marks[0].from = function() { return tdata; };
  5166. def.marks[1].from = function() { return [1]; };
  5167. def.marks[2].from = function() { return data; };
  5168. return def;
  5169. }
  5170. function q_legend_def(scale) {
  5171. // setup legend marks
  5172. var titles = vg_legendTitle(),
  5173. gradient = vg_legendGradient(),
  5174. labels = vg_hLegendLabels(),
  5175. grad = new vg.Gradient();
  5176. // setup color gradient
  5177. var dom = scale.domain(),
  5178. min = dom[0],
  5179. max = dom[dom.length-1],
  5180. f = scale.copy().domain([min, max]).range([0,1]);
  5181. var stops = (scale.type !== "linear" && scale.ticks)
  5182. ? scale.ticks.call(scale, 15) : dom;
  5183. if (min !== stops[0]) stops.unshift(min);
  5184. if (max !== stops[stops.length-1]) stops.push(max);
  5185. for (var i=0, n=stops.length; i<n; ++i) {
  5186. grad.stop(f(stops[i]), scale(stops[i]));
  5187. }
  5188. gradient.properties.enter.fill = {value: grad};
  5189. // add / override custom style properties
  5190. vg.extend(titles.properties.update, titleStyle);
  5191. vg.extend(gradient.properties.update, gradientStyle);
  5192. vg.extend(labels.properties.update, labelStyle);
  5193. // account for gradient size
  5194. var gp = gradient.properties, gh = gradientStyle.height,
  5195. hh = (gh && gh.value) || gp.enter.height.value;
  5196. labels.properties.enter.y.value = hh;
  5197. // account for title size as needed
  5198. if (title) {
  5199. var tp = titles.properties, fs = titleStyle.fontSize,
  5200. sz = 4 + ((fs && fs.value) || tp.enter.fontSize.value);
  5201. gradient.properties.enter.y.value += sz;
  5202. labels.properties.enter.y.value += sz;
  5203. }
  5204. // padding from legend border
  5205. titles.properties.enter.x.value += padding;
  5206. titles.properties.enter.y.value += padding;
  5207. gradient.properties.enter.x.value += padding;
  5208. gradient.properties.enter.y.value += padding;
  5209. labels.properties.enter.y.value += padding;
  5210. return {
  5211. type: "group",
  5212. interactive: false,
  5213. properties: {
  5214. enter: vg.parse.properties("group", legendStyle),
  5215. update: vg_legendUpdate
  5216. },
  5217. marks: [titles, gradient, labels].map(vg.parse.mark)
  5218. };
  5219. }
  5220. legend.size = function(x) {
  5221. if (!arguments.length) return size;
  5222. if (size !== x) { size = x; reset(); }
  5223. return legend;
  5224. };
  5225. legend.shape = function(x) {
  5226. if (!arguments.length) return shape;
  5227. if (shape !== x) { shape = x; reset(); }
  5228. return legend;
  5229. };
  5230. legend.fill = function(x) {
  5231. if (!arguments.length) return fill;
  5232. if (fill !== x) { fill = x; reset(); }
  5233. return legend;
  5234. };
  5235. legend.stroke = function(x) {
  5236. if (!arguments.length) return stroke;
  5237. if (stroke !== x) { stroke = x; reset(); }
  5238. return legend;
  5239. };
  5240. legend.title = function(x) {
  5241. if (!arguments.length) return title;
  5242. if (title !== x) { title = x; reset(); }
  5243. return legend;
  5244. };
  5245. legend.format = function(x) {
  5246. if (!arguments.length) return format;
  5247. if (format !== x) { format = x; reset(); }
  5248. return legend;
  5249. };
  5250. legend.spacing = function(x) {
  5251. if (!arguments.length) return spacing;
  5252. if (spacing !== +x) { spacing = +x; reset(); }
  5253. return legend;
  5254. };
  5255. legend.orient = function(x) {
  5256. if (!arguments.length) return orient;
  5257. orient = x in vg_legendOrients ? x + "" : vg.config.legend.orient;
  5258. return legend;
  5259. };
  5260. legend.offset = function(x) {
  5261. if (!arguments.length) return offset;
  5262. offset = +x;
  5263. return legend;
  5264. };
  5265. legend.values = function(x) {
  5266. if (!arguments.length) return values;
  5267. values = x;
  5268. return legend;
  5269. };
  5270. legend.legendProperties = function(x) {
  5271. if (!arguments.length) return legendStyle;
  5272. legendStyle = x;
  5273. return legend;
  5274. };
  5275. legend.symbolProperties = function(x) {
  5276. if (!arguments.length) return symbolStyle;
  5277. symbolStyle = x;
  5278. return legend;
  5279. };
  5280. legend.gradientProperties = function(x) {
  5281. if (!arguments.length) return gradientStyle;
  5282. gradientStyle = x;
  5283. return legend;
  5284. };
  5285. legend.labelProperties = function(x) {
  5286. if (!arguments.length) return labelStyle;
  5287. labelStyle = x;
  5288. return legend;
  5289. };
  5290. legend.titleProperties = function(x) {
  5291. if (!arguments.length) return titleStyle;
  5292. titleStyle = x;
  5293. return legend;
  5294. };
  5295. legend.reset = function() { reset(); };
  5296. return legend;
  5297. };
  5298. var vg_legendOrients = {right: 1, left: 1};
  5299. function vg_legendUpdate(item, group, trans) {
  5300. var o = trans ? {} : item,
  5301. offset = item.mark.def.offset,
  5302. orient = item.mark.def.orient,
  5303. pad = item.mark.def.padding * 2,
  5304. gx1 = group.bounds ? group.bounds.x1 : 0,
  5305. gx2 = group.bounds ? group.bounds.x2 : group.width,
  5306. lw = ~~item.bounds.width() + (o.width ? 0 : pad),
  5307. lh = ~~item.bounds.height() + (o.height ? 0 : pad);
  5308. o.x = 0.5;
  5309. o.y = 0.5;
  5310. o.width = lw;
  5311. o.height = lh;
  5312. switch (orient) {
  5313. case "left": { o.x += gx1 - offset - lw; break; };
  5314. case "right": { o.x += gx2 + offset; break; };
  5315. }
  5316. item.mark.def.properties.enter(item, group, trans);
  5317. }
  5318. function vg_legendSymbolExtend(mark, size, shape, fill, stroke) {
  5319. var props = mark.properties.enter;
  5320. if (size) props.size = {scale: size.scaleName, field: "data"};
  5321. if (shape) props.shape = {scale: shape.scaleName, field: "data"};
  5322. if (fill) props.fill = {scale: fill.scaleName, field: "data"};
  5323. if (stroke) props.stroke = {scale: stroke.scaleName, field: "data"};
  5324. }
  5325. function vg_legendTitle() {
  5326. var cfg = vg.config.legend;
  5327. return {
  5328. type: "text",
  5329. interactive: false,
  5330. key: "data",
  5331. properties: {
  5332. enter: {
  5333. x: {value: 0},
  5334. y: {value: 0},
  5335. fill: {value: cfg.titleColor},
  5336. font: {value: cfg.titleFont},
  5337. fontSize: {value: cfg.titleFontSize},
  5338. fontWeight: {value: cfg.titleFontWeight},
  5339. baseline: {value: "top"},
  5340. text: {field: "data"},
  5341. opacity: {value: 1e-6}
  5342. },
  5343. exit: { opacity: {value: 1e-6} },
  5344. update: { opacity: {value: 1} }
  5345. }
  5346. };
  5347. }
  5348. function vg_legendSymbols() {
  5349. var cfg = vg.config.legend;
  5350. return {
  5351. type: "symbol",
  5352. interactive: false,
  5353. key: "data",
  5354. properties: {
  5355. enter: {
  5356. x: {field: "offset", mult: 0.5},
  5357. y: {scale: "legend", field: "index"},
  5358. shape: {value: cfg.symbolShape},
  5359. size: {value: cfg.symbolSize},
  5360. stroke: {value: cfg.symbolColor},
  5361. strokeWidth: {value: cfg.symbolStrokeWidth},
  5362. opacity: {value: 1e-6}
  5363. },
  5364. exit: { opacity: {value: 1e-6} },
  5365. update: { opacity: {value: 1} }
  5366. }
  5367. };
  5368. }
  5369. function vg_vLegendLabels() {
  5370. var cfg = vg.config.legend;
  5371. return {
  5372. type: "text",
  5373. interactive: false,
  5374. key: "data",
  5375. properties: {
  5376. enter: {
  5377. x: {field: "offset", offset: 5},
  5378. y: {scale: "legend", field: "index"},
  5379. fill: {value: cfg.labelColor},
  5380. font: {value: cfg.labelFont},
  5381. fontSize: {value: cfg.labelFontSize},
  5382. align: {value: cfg.labelAlign},
  5383. baseline: {value: cfg.labelBaseline},
  5384. text: {field: "label"},
  5385. opacity: {value: 1e-6}
  5386. },
  5387. exit: { opacity: {value: 1e-6} },
  5388. update: { opacity: {value: 1} }
  5389. }
  5390. };
  5391. }
  5392. function vg_legendGradient() {
  5393. var cfg = vg.config.legend;
  5394. return {
  5395. type: "rect",
  5396. interactive: false,
  5397. properties: {
  5398. enter: {
  5399. x: {value: 0},
  5400. y: {value: 0},
  5401. width: {value: cfg.gradientWidth},
  5402. height: {value: cfg.gradientHeight},
  5403. stroke: {value: cfg.gradientStrokeColor},
  5404. strokeWidth: {value: cfg.gradientStrokeWidth},
  5405. opacity: {value: 1e-6}
  5406. },
  5407. exit: { opacity: {value: 1e-6} },
  5408. update: { opacity: {value: 1} }
  5409. }
  5410. };
  5411. }
  5412. function vg_hLegendLabels() {
  5413. var cfg = vg.config.legend;
  5414. return {
  5415. type: "text",
  5416. interactive: false,
  5417. key: "data",
  5418. properties: {
  5419. enter: {
  5420. x: {scale: "legend", field: "data"},
  5421. y: {value: 20},
  5422. dy: {value: 2},
  5423. fill: {value: cfg.labelColor},
  5424. font: {value: cfg.labelFont},
  5425. fontSize: {value: cfg.labelFontSize},
  5426. align: {field: "align"},
  5427. baseline: {value: "top"},
  5428. text: {field: "label"},
  5429. opacity: {value: 1e-6}
  5430. },
  5431. exit: { opacity: {value: 1e-6} },
  5432. update: { opacity: {value: 1} }
  5433. }
  5434. };
  5435. }vg.Model = (function() {
  5436. function model() {
  5437. this._defs = null;
  5438. this._data = {};
  5439. this._scene = null;
  5440. this._reset = false;
  5441. }
  5442. var prototype = model.prototype;
  5443. prototype.defs = function(defs) {
  5444. if (!arguments.length) return this._defs;
  5445. this._defs = defs;
  5446. return this;
  5447. };
  5448. prototype.data = function(data) {
  5449. if (!arguments.length) return this._data;
  5450. var tx = this._defs.data.flow || {},
  5451. keys = this._defs.data.defs.map(vg.accessor("name")),
  5452. len = keys.length, i, k;
  5453. for (i=0; i<len; ++i) {
  5454. if (!data[k=keys[i]]) continue;
  5455. this.ingest(k, tx, data[k]);
  5456. }
  5457. return this;
  5458. };
  5459. prototype.ingest = function(name, tx, input) {
  5460. this._data[name] = tx[name]
  5461. ? tx[name](input, this._data, this._defs.marks)
  5462. : input;
  5463. this.dependencies(name, tx);
  5464. };
  5465. prototype.dependencies = function(name, tx) {
  5466. var source = this._defs.data.source[name],
  5467. data = this._data[name],
  5468. n = source ? source.length : 0, i, x;
  5469. for (i=0; i<n; ++i) {
  5470. x = vg_data_duplicate(data);
  5471. if (vg.isTree(data)) vg_make_tree(x);
  5472. this.ingest(source[i], tx, x);
  5473. }
  5474. };
  5475. prototype.width = function(width) {
  5476. if (this._defs) this._defs.width = width;
  5477. if (this._defs && this._defs.marks) this._defs.marks.width = width;
  5478. if (this._scene) this._scene.items[0].width = width;
  5479. this._reset = true;
  5480. return this;
  5481. };
  5482. prototype.height = function(height) {
  5483. if (this._defs) this._defs.height = height;
  5484. if (this._defs && this._defs.marks) this._defs.marks.height = height;
  5485. if (this._scene) this._scene.items[0].height = height;
  5486. this._reset = true;
  5487. return this;
  5488. };
  5489. prototype.scene = function(node) {
  5490. if (!arguments.length) return this._scene;
  5491. this._scene = node;
  5492. return this;
  5493. };
  5494. prototype.build = function() {
  5495. var m = this, data = m._data, marks = m._defs.marks;
  5496. m._scene = vg.scene.build.call(m, marks, data, m._scene);
  5497. m._scene.items[0].width = marks.width;
  5498. m._scene.items[0].height = marks.height;
  5499. m._scene.interactive = false;
  5500. return this;
  5501. };
  5502. prototype.encode = function(trans, request, item) {
  5503. if (this._reset) { this.reset(); this._reset = false; }
  5504. var m = this, scene = m._scene, defs = m._defs;
  5505. vg.scene.encode.call(m, scene, defs.marks, trans, request, item);
  5506. return this;
  5507. };
  5508. prototype.reset = function() {
  5509. if (this._scene) {
  5510. vg.scene.visit(this._scene, function(item) {
  5511. if (item.axes) item.axes.forEach(function(axis) { axis.reset(); });
  5512. });
  5513. }
  5514. return this;
  5515. };
  5516. return model;
  5517. })();vg.View = (function() {
  5518. var view = function(el, width, height) {
  5519. this._el = null;
  5520. this._build = false;
  5521. this._model = new vg.Model();
  5522. this._width = this.__width = width || 500;
  5523. this._height = this.__height = height || 500;
  5524. this._autopad = 1;
  5525. this._padding = {top:0, left:0, bottom:0, right:0};
  5526. this._viewport = null;
  5527. this._renderer = null;
  5528. this._handler = null;
  5529. this._io = vg.canvas;
  5530. if (el) this.initialize(el);
  5531. };
  5532. var prototype = view.prototype;
  5533. prototype.width = function(width) {
  5534. if (!arguments.length) return this.__width;
  5535. if (this.__width !== width) {
  5536. this._width = this.__width = width;
  5537. if (this._el) this.initialize(this._el.parentNode);
  5538. this._model.width(width);
  5539. if (this._strict) this._autopad = 1;
  5540. }
  5541. return this;
  5542. };
  5543. prototype.height = function(height) {
  5544. if (!arguments.length) return this.__height;
  5545. if (this.__height !== height) {
  5546. this._height = this.__height = height;
  5547. if (this._el) this.initialize(this._el.parentNode);
  5548. this._model.height(this._height);
  5549. if (this._strict) this._autopad = 1;
  5550. }
  5551. return this;
  5552. };
  5553. prototype.padding = function(pad) {
  5554. if (!arguments.length) return this._padding;
  5555. if (this._padding !== pad) {
  5556. if (vg.isString(pad)) {
  5557. this._autopad = 1;
  5558. this._padding = {top:0, left:0, bottom:0, right:0};
  5559. this._strict = (pad === "strict");
  5560. } else {
  5561. this._autopad = 0;
  5562. this._padding = pad;
  5563. this._strict = false;
  5564. }
  5565. if (this._el) {
  5566. this._renderer.resize(this._width, this._height, pad);
  5567. this._handler.padding(pad);
  5568. }
  5569. }
  5570. return this;
  5571. };
  5572. prototype.autopad = function(opt) {
  5573. if (this._autopad < 1) return this;
  5574. else this._autopad = 0;
  5575. var pad = this._padding,
  5576. b = this.model().scene().bounds,
  5577. inset = vg.config.autopadInset,
  5578. l = b.x1 < 0 ? Math.ceil(-b.x1) + inset : 0,
  5579. t = b.y1 < 0 ? Math.ceil(-b.y1) + inset : 0,
  5580. r = b.x2 > this._width ? Math.ceil(+b.x2 - this._width) + inset : 0,
  5581. b = b.y2 > this._height ? Math.ceil(+b.y2 - this._height) + inset : 0;
  5582. pad = {left:l, top:t, right:r, bottom:b};
  5583. if (this._strict) {
  5584. this._autopad = 0;
  5585. this._padding = pad;
  5586. this._width = Math.max(0, this.__width - (l+r));
  5587. this._height = Math.max(0, this.__height - (t+b));
  5588. this._model.width(this._width);
  5589. this._model.height(this._height);
  5590. if (this._el) this.initialize(this._el.parentNode);
  5591. this.update({props:"enter"}).update({props:"update"});
  5592. } else {
  5593. this.padding(pad).update(opt);
  5594. }
  5595. return this;
  5596. };
  5597. prototype.viewport = function(size) {
  5598. if (!arguments.length) return this._viewport;
  5599. if (this._viewport !== size) {
  5600. this._viewport = size;
  5601. if (this._el) this.initialize(this._el.parentNode);
  5602. }
  5603. return this;
  5604. };
  5605. prototype.renderer = function(type) {
  5606. if (!arguments.length) return this._io;
  5607. if (type === "canvas") type = vg.canvas;
  5608. if (type === "svg") type = vg.svg;
  5609. if (this._io !== type) {
  5610. this._io = type;
  5611. this._renderer = null;
  5612. if (this._el) this.initialize(this._el.parentNode);
  5613. if (this._build) this.render();
  5614. }
  5615. return this;
  5616. };
  5617. prototype.defs = function(defs) {
  5618. if (!arguments.length) return this._model.defs();
  5619. this._model.defs(defs);
  5620. return this;
  5621. };
  5622. prototype.data = function(data) {
  5623. if (!arguments.length) return this._model.data();
  5624. var ingest = vg.keys(data).reduce(function(d, k) {
  5625. return (d[k] = vg.data.ingestAll(data[k]), d);
  5626. }, {});
  5627. this._model.data(ingest);
  5628. this._build = false;
  5629. return this;
  5630. };
  5631. prototype.model = function(model) {
  5632. if (!arguments.length) return this._model;
  5633. if (this._model !== model) {
  5634. this._model = model;
  5635. if (this._handler) this._handler.model(model);
  5636. }
  5637. return this;
  5638. };
  5639. prototype.initialize = function(el) {
  5640. var v = this, prevHandler,
  5641. w = v._width, h = v._height, pad = v._padding;
  5642. // clear pre-existing container
  5643. d3.select(el).select("div.vega").remove();
  5644. // add div container
  5645. this._el = el = d3.select(el)
  5646. .append("div")
  5647. .attr("class", "vega")
  5648. .style("position", "relative")
  5649. .node();
  5650. if (v._viewport) {
  5651. d3.select(el)
  5652. .style("width", (v._viewport[0] || w)+"px")
  5653. .style("height", (v._viewport[1] || h)+"px")
  5654. .style("overflow", "auto");
  5655. }
  5656. // renderer
  5657. v._renderer = (v._renderer || new this._io.Renderer())
  5658. .initialize(el, w, h, pad);
  5659. // input handler
  5660. prevHandler = v._handler;
  5661. v._handler = new this._io.Handler()
  5662. .initialize(el, pad, v)
  5663. .model(v._model);
  5664. if (prevHandler) {
  5665. prevHandler.handlers().forEach(function(h) {
  5666. v._handler.on(h.type, h.handler);
  5667. });
  5668. }
  5669. return this;
  5670. };
  5671. prototype.render = function(items) {
  5672. this._renderer.render(this._model.scene(), items);
  5673. return this;
  5674. };
  5675. prototype.on = function() {
  5676. this._handler.on.apply(this._handler, arguments);
  5677. return this;
  5678. };
  5679. prototype.off = function() {
  5680. this._handler.off.apply(this._handler, arguments);
  5681. return this;
  5682. };
  5683. prototype.update = function(opt) {
  5684. opt = opt || {};
  5685. var view = this,
  5686. trans = opt.duration
  5687. ? vg.scene.transition(opt.duration, opt.ease)
  5688. : null;
  5689. view._build = view._build || (view._model.build(), true);
  5690. view._model.encode(trans, opt.props, opt.items);
  5691. if (trans) {
  5692. trans.start(function(items) {
  5693. view._renderer.render(view._model.scene(), items);
  5694. });
  5695. }
  5696. else view.render(opt.items);
  5697. return view.autopad(opt);
  5698. };
  5699. return view;
  5700. })();
  5701. // view constructor factory
  5702. // takes definitions from parsed specification as input
  5703. // returns a view constructor
  5704. vg.ViewFactory = function(defs) {
  5705. return function(opt) {
  5706. opt = opt || {};
  5707. var v = new vg.View()
  5708. .width(defs.width)
  5709. .height(defs.height)
  5710. .padding(defs.padding)
  5711. .viewport(defs.viewport)
  5712. .renderer(opt.renderer || "canvas")
  5713. .defs(defs);
  5714. if (defs.data.load) v.data(defs.data.load);
  5715. if (opt.data) v.data(opt.data);
  5716. if (opt.el) v.initialize(opt.el);
  5717. if (opt.hover !== false) {
  5718. v.on("mouseover", function(evt, item) {
  5719. if (item.hasPropertySet("hover")) {
  5720. this.update({props:"hover", items:item});
  5721. }
  5722. })
  5723. .on("mouseout", function(evt, item) {
  5724. if (item.hasPropertySet("hover")) {
  5725. this.update({props:"update", items:item});
  5726. }
  5727. });
  5728. }
  5729. return v;
  5730. };
  5731. };
  5732. vg.Spec = (function() {
  5733. var spec = function(s) {
  5734. this.spec = {
  5735. width: 500,
  5736. height: 500,
  5737. padding: 0,
  5738. data: [],
  5739. scales: [],
  5740. axes: [],
  5741. marks: []
  5742. };
  5743. if (s) vg.extend(this.spec, s);
  5744. };
  5745. var prototype = spec.prototype;
  5746. prototype.width = function(w) {
  5747. this.spec.width = w;
  5748. return this;
  5749. };
  5750. prototype.height = function(h) {
  5751. this.spec.height = h;
  5752. return this;
  5753. };
  5754. prototype.padding = function(p) {
  5755. this.spec.padding = p;
  5756. return this;
  5757. };
  5758. prototype.viewport = function(v) {
  5759. this.spec.viewport = v;
  5760. return this;
  5761. };
  5762. prototype.data = function(name, params) {
  5763. if (!params) params = vg.isString(name) ? {name: name} : name;
  5764. else params.name = name;
  5765. this.spec.data.push(params);
  5766. return this;
  5767. };
  5768. prototype.scale = function(name, params) {
  5769. if (!params) params = vg.isString(name) ? {name: name} : name;
  5770. else params.name = name;
  5771. this.spec.scales.push(params);
  5772. return this;
  5773. };
  5774. prototype.axis = function(params) {
  5775. this.spec.axes.push(params);
  5776. return this;
  5777. };
  5778. prototype.mark = function(type, mark) {
  5779. if (!mark) mark = {type: type};
  5780. else mark.type = type;
  5781. mark.properties = {};
  5782. this.spec.marks.push(mark);
  5783. var that = this;
  5784. return {
  5785. from: function(name, obj) {
  5786. mark.from = obj
  5787. ? (obj.data = name, obj)
  5788. : vg.isString(name) ? {data: name} : name;
  5789. return this;
  5790. },
  5791. prop: function(name, obj) {
  5792. mark.properties[name] = vg.keys(obj).reduce(function(o,k) {
  5793. var v = obj[k];
  5794. return (o[k] = vg.isObject(v) ? v : {value: v}, o);
  5795. }, {});
  5796. return this;
  5797. },
  5798. done: function() { return that; }
  5799. };
  5800. };
  5801. prototype.parse = function(callback) {
  5802. vg.parse.spec(this.spec, callback);
  5803. };
  5804. prototype.json = function() {
  5805. return this.spec;
  5806. };
  5807. return spec;
  5808. })();
  5809. vg.spec = function(s) {
  5810. return new vg.Spec(s);
  5811. };
  5812. vg.headless = {};vg.headless.View = (function() {
  5813. var view = function(width, height, pad, type) {
  5814. this._canvas = null;
  5815. this._type = type;
  5816. this._el = "body";
  5817. this._build = false;
  5818. this._model = new vg.Model();
  5819. this._width = this.__width = width || 500;
  5820. this._height = this.__height = height || 500;
  5821. this._autopad = 1;
  5822. this._padding = pad || {top:0, left:0, bottom:0, right:0};
  5823. this._renderer = new vg[type].Renderer();
  5824. this.initialize();
  5825. };
  5826. var prototype = view.prototype;
  5827. prototype.el = function(el) {
  5828. if (!arguments.length) return this._el;
  5829. if (this._el !== el) {
  5830. this._el = el;
  5831. this.initialize();
  5832. }
  5833. return this;
  5834. };
  5835. prototype.width = function(width) {
  5836. if (!arguments.length) return this._width;
  5837. if (this._width !== width) {
  5838. this._width = width;
  5839. this.initialize();
  5840. this._model.width(width);
  5841. }
  5842. return this;
  5843. };
  5844. prototype.height = function(height) {
  5845. if (!arguments.length) return this._height;
  5846. if (this._height !== height) {
  5847. this._height = height;
  5848. this.initialize();
  5849. this._model.height(this._height);
  5850. }
  5851. return this;
  5852. };
  5853. prototype.padding = function(pad) {
  5854. if (!arguments.length) return this._padding;
  5855. if (this._padding !== pad) {
  5856. if (vg.isString(pad)) {
  5857. this._autopad = 1;
  5858. this._padding = {top:0, left:0, bottom:0, right:0};
  5859. this._strict = (pad === "strict");
  5860. } else {
  5861. this._autopad = 0;
  5862. this._padding = pad;
  5863. this._strict = false;
  5864. }
  5865. this.initialize();
  5866. }
  5867. return this;
  5868. };
  5869. prototype.autopad = function(opt) {
  5870. if (this._autopad < 1) return this;
  5871. else this._autopad = 0;
  5872. var pad = this._padding,
  5873. b = this._model.scene().bounds,
  5874. inset = vg.config.autopadInset,
  5875. l = b.x1 < 0 ? Math.ceil(-b.x1) + inset : 0,
  5876. t = b.y1 < 0 ? Math.ceil(-b.y1) + inset : 0,
  5877. r = b.x2 > this._width ? Math.ceil(+b.x2 - this._width) + inset : 0,
  5878. b = b.y2 > this._height ? Math.ceil(+b.y2 - this._height) + inset : 0;
  5879. pad = {left:l, top:t, right:r, bottom:b};
  5880. if (this._strict) {
  5881. this._autopad = 0;
  5882. this._padding = pad;
  5883. this._width = Math.max(0, this.__width - (l+r));
  5884. this._height = Math.max(0, this.__height - (t+b));
  5885. this._model.width(this._width);
  5886. this._model.height(this._height);
  5887. if (this._el) this.initialize();
  5888. this.update({props:"enter"}).update({props:"update"});
  5889. } else {
  5890. this.padding(pad).update(opt);
  5891. }
  5892. return this;
  5893. };
  5894. prototype.viewport = function() {
  5895. if (!arguments.length) return null;
  5896. return this;
  5897. };
  5898. prototype.defs = function(defs) {
  5899. if (!arguments.length) return this._model.defs();
  5900. this._model.defs(defs);
  5901. return this;
  5902. };
  5903. prototype.data = function(data) {
  5904. if (!arguments.length) return this._model.data();
  5905. var ingest = vg.keys(data).reduce(function(d, k) {
  5906. return (d[k] = vg.data.ingestAll(data[k]), d);
  5907. }, {});
  5908. this._model.data(ingest);
  5909. this._build = false;
  5910. return this;
  5911. };
  5912. prototype.renderer = function() {
  5913. return this._renderer;
  5914. };
  5915. prototype.canvas = function() {
  5916. return this._canvas;
  5917. };
  5918. prototype.canvasAsync = function(callback) {
  5919. var r = this._renderer, view = this;
  5920. function wait() {
  5921. if (r.pendingImages() === 0) {
  5922. view.render(); // re-render with all images
  5923. callback(view._canvas);
  5924. } else {
  5925. setTimeout(wait, 10);
  5926. }
  5927. }
  5928. // if images loading, poll until ready
  5929. (r.pendingImages() > 0) ? wait() : callback(this._canvas);
  5930. };
  5931. prototype.svg = function() {
  5932. if (this._type !== "svg") return null;
  5933. var p = this._padding,
  5934. w = this._width + (p ? p.left + p.right : 0),
  5935. h = this._height + (p ? p.top + p.bottom : 0);
  5936. // build svg text
  5937. var svg = d3.select(this._el)
  5938. .select("svg").node().innerHTML
  5939. .replace(/ href=/g, " xlink:href="); // ns hack. sigh.
  5940. return '<svg '
  5941. + 'width="' + w + '" '
  5942. + 'height="' + h + '" '
  5943. + vg.config.svgNamespace + '>' + svg + '</svg>'
  5944. };
  5945. prototype.initialize = function() {
  5946. var w = this._width,
  5947. h = this._height,
  5948. pad = this._padding;
  5949. if (this._type === "svg") {
  5950. this.initSVG(w, h, pad);
  5951. } else {
  5952. this.initCanvas(w, h, pad);
  5953. }
  5954. return this;
  5955. };
  5956. prototype.initCanvas = function(w, h, pad) {
  5957. var Canvas = require("canvas"),
  5958. tw = w + pad.left + pad.right,
  5959. th = h + pad.top + pad.bottom,
  5960. canvas = this._canvas = new Canvas(tw, th),
  5961. ctx = canvas.getContext("2d");
  5962. // setup canvas context
  5963. ctx.setTransform(1, 0, 0, 1, pad.left, pad.top);
  5964. // configure renderer
  5965. this._renderer.context(ctx);
  5966. this._renderer.resize(w, h, pad);
  5967. };
  5968. prototype.initSVG = function(w, h, pad) {
  5969. var tw = w + pad.left + pad.right,
  5970. th = h + pad.top + pad.bottom;
  5971. // configure renderer
  5972. this._renderer.initialize(this._el, w, h, pad);
  5973. }
  5974. prototype.render = function(items) {
  5975. this._renderer.render(this._model.scene(), items);
  5976. return this;
  5977. };
  5978. prototype.update = function(opt) {
  5979. opt = opt || {};
  5980. var view = this;
  5981. view._build = view._build || (view._model.build(), true);
  5982. view._model.encode(null, opt.props, opt.items);
  5983. view.render(opt.items);
  5984. return view.autopad(opt);
  5985. };
  5986. return view;
  5987. })();
  5988. // headless view constructor factory
  5989. // takes definitions from parsed specification as input
  5990. // returns a view constructor
  5991. vg.headless.View.Factory = function(defs) {
  5992. return function(opt) {
  5993. opt = opt || {};
  5994. var w = defs.width,
  5995. h = defs.height,
  5996. p = defs.padding,
  5997. r = opt.renderer || "canvas",
  5998. v = new vg.headless.View(w, h, p, r).defs(defs);
  5999. if (defs.data.load) v.data(defs.data.load);
  6000. if (opt.data) v.data(opt.data);
  6001. return v;
  6002. };
  6003. };vg.headless.render = function(opt, callback) {
  6004. function draw(chart) {
  6005. try {
  6006. // create and render view
  6007. var view = chart({
  6008. data: opt.data,
  6009. renderer: opt.renderer
  6010. }).update();
  6011. if (opt.renderer === "svg") {
  6012. // extract rendered svg
  6013. callback(null, {svg: view.svg()});
  6014. } else {
  6015. // extract rendered canvas, waiting for any images to load
  6016. view.canvasAsync(function(canvas) {
  6017. callback(null, {canvas: canvas});
  6018. });
  6019. }
  6020. } catch (err) {
  6021. callback(err, null);
  6022. }
  6023. }
  6024. vg.parse.spec(opt.spec, draw, vg.headless.View.Factory);
  6025. }; return vg;
  6026. })(d3, typeof topojson === "undefined" ? null : topojson);
  6027. // assumes D3 and topojson in global namespace