Chart2D.js.uncompressed.js 605 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. /*
  7. This is an optimized version of Dojo, built for deployment and not for
  8. development. To get sources and documentation, please visit:
  9. http://dojotoolkit.org
  10. */
  11. if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12. dojo._hasResource["dijit._base.manager"] = true;
  13. dojo.provide("dijit._base.manager");
  14. dojo.declare("dijit.WidgetSet", null, {
  15. // summary:
  16. // A set of widgets indexed by id. A default instance of this class is
  17. // available as `dijit.registry`
  18. //
  19. // example:
  20. // Create a small list of widgets:
  21. // | var ws = new dijit.WidgetSet();
  22. // | ws.add(dijit.byId("one"));
  23. // | ws.add(dijit.byId("two"));
  24. // | // destroy both:
  25. // | ws.forEach(function(w){ w.destroy(); });
  26. //
  27. // example:
  28. // Using dijit.registry:
  29. // | dijit.registry.forEach(function(w){ /* do something */ });
  30. constructor: function(){
  31. this._hash = {};
  32. this.length = 0;
  33. },
  34. add: function(/*dijit._Widget*/ widget){
  35. // summary:
  36. // Add a widget to this list. If a duplicate ID is detected, a error is thrown.
  37. //
  38. // widget: dijit._Widget
  39. // Any dijit._Widget subclass.
  40. if(this._hash[widget.id]){
  41. throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
  42. }
  43. this._hash[widget.id] = widget;
  44. this.length++;
  45. },
  46. remove: function(/*String*/ id){
  47. // summary:
  48. // Remove a widget from this WidgetSet. Does not destroy the widget; simply
  49. // removes the reference.
  50. if(this._hash[id]){
  51. delete this._hash[id];
  52. this.length--;
  53. }
  54. },
  55. forEach: function(/*Function*/ func, /* Object? */thisObj){
  56. // summary:
  57. // Call specified function for each widget in this set.
  58. //
  59. // func:
  60. // A callback function to run for each item. Is passed the widget, the index
  61. // in the iteration, and the full hash, similar to `dojo.forEach`.
  62. //
  63. // thisObj:
  64. // An optional scope parameter
  65. //
  66. // example:
  67. // Using the default `dijit.registry` instance:
  68. // | dijit.registry.forEach(function(widget){
  69. // | console.log(widget.declaredClass);
  70. // | });
  71. //
  72. // returns:
  73. // Returns self, in order to allow for further chaining.
  74. thisObj = thisObj || dojo.global;
  75. var i = 0, id;
  76. for(id in this._hash){
  77. func.call(thisObj, this._hash[id], i++, this._hash);
  78. }
  79. return this; // dijit.WidgetSet
  80. },
  81. filter: function(/*Function*/ filter, /* Object? */thisObj){
  82. // summary:
  83. // Filter down this WidgetSet to a smaller new WidgetSet
  84. // Works the same as `dojo.filter` and `dojo.NodeList.filter`
  85. //
  86. // filter:
  87. // Callback function to test truthiness. Is passed the widget
  88. // reference and the pseudo-index in the object.
  89. //
  90. // thisObj: Object?
  91. // Option scope to use for the filter function.
  92. //
  93. // example:
  94. // Arbitrary: select the odd widgets in this list
  95. // | dijit.registry.filter(function(w, i){
  96. // | return i % 2 == 0;
  97. // | }).forEach(function(w){ /* odd ones */ });
  98. thisObj = thisObj || dojo.global;
  99. var res = new dijit.WidgetSet(), i = 0, id;
  100. for(id in this._hash){
  101. var w = this._hash[id];
  102. if(filter.call(thisObj, w, i++, this._hash)){
  103. res.add(w);
  104. }
  105. }
  106. return res; // dijit.WidgetSet
  107. },
  108. byId: function(/*String*/ id){
  109. // summary:
  110. // Find a widget in this list by it's id.
  111. // example:
  112. // Test if an id is in a particular WidgetSet
  113. // | var ws = new dijit.WidgetSet();
  114. // | ws.add(dijit.byId("bar"));
  115. // | var t = ws.byId("bar") // returns a widget
  116. // | var x = ws.byId("foo"); // returns undefined
  117. return this._hash[id]; // dijit._Widget
  118. },
  119. byClass: function(/*String*/ cls){
  120. // summary:
  121. // Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
  122. //
  123. // cls: String
  124. // The Class to scan for. Full dot-notated string.
  125. //
  126. // example:
  127. // Find all `dijit.TitlePane`s in a page:
  128. // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });
  129. var res = new dijit.WidgetSet(), id, widget;
  130. for(id in this._hash){
  131. widget = this._hash[id];
  132. if(widget.declaredClass == cls){
  133. res.add(widget);
  134. }
  135. }
  136. return res; // dijit.WidgetSet
  137. },
  138. toArray: function(){
  139. // summary:
  140. // Convert this WidgetSet into a true Array
  141. //
  142. // example:
  143. // Work with the widget .domNodes in a real Array
  144. // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });
  145. var ar = [];
  146. for(var id in this._hash){
  147. ar.push(this._hash[id]);
  148. }
  149. return ar; // dijit._Widget[]
  150. },
  151. map: function(/* Function */func, /* Object? */thisObj){
  152. // summary:
  153. // Create a new Array from this WidgetSet, following the same rules as `dojo.map`
  154. // example:
  155. // | var nodes = dijit.registry.map(function(w){ return w.domNode; });
  156. //
  157. // returns:
  158. // A new array of the returned values.
  159. return dojo.map(this.toArray(), func, thisObj); // Array
  160. },
  161. every: function(func, thisObj){
  162. // summary:
  163. // A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
  164. //
  165. // func: Function
  166. // A callback function run for every widget in this list. Exits loop
  167. // when the first false return is encountered.
  168. //
  169. // thisObj: Object?
  170. // Optional scope parameter to use for the callback
  171. thisObj = thisObj || dojo.global;
  172. var x = 0, i;
  173. for(i in this._hash){
  174. if(!func.call(thisObj, this._hash[i], x++, this._hash)){
  175. return false; // Boolean
  176. }
  177. }
  178. return true; // Boolean
  179. },
  180. some: function(func, thisObj){
  181. // summary:
  182. // A synthetic clone of `dojo.some` acting explictly on this WidgetSet
  183. //
  184. // func: Function
  185. // A callback function run for every widget in this list. Exits loop
  186. // when the first true return is encountered.
  187. //
  188. // thisObj: Object?
  189. // Optional scope parameter to use for the callback
  190. thisObj = thisObj || dojo.global;
  191. var x = 0, i;
  192. for(i in this._hash){
  193. if(func.call(thisObj, this._hash[i], x++, this._hash)){
  194. return true; // Boolean
  195. }
  196. }
  197. return false; // Boolean
  198. }
  199. });
  200. (function(){
  201. /*=====
  202. dijit.registry = {
  203. // summary:
  204. // A list of widgets on a page.
  205. // description:
  206. // Is an instance of `dijit.WidgetSet`
  207. };
  208. =====*/
  209. dijit.registry = new dijit.WidgetSet();
  210. var hash = dijit.registry._hash,
  211. attr = dojo.attr,
  212. hasAttr = dojo.hasAttr,
  213. style = dojo.style;
  214. dijit.byId = function(/*String|dijit._Widget*/ id){
  215. // summary:
  216. // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
  217. return typeof id == "string" ? hash[id] : id; // dijit._Widget
  218. };
  219. var _widgetTypeCtr = {};
  220. dijit.getUniqueId = function(/*String*/widgetType){
  221. // summary:
  222. // Generates a unique id for a given widgetType
  223. var id;
  224. do{
  225. id = widgetType + "_" +
  226. (widgetType in _widgetTypeCtr ?
  227. ++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
  228. }while(hash[id]);
  229. return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
  230. };
  231. dijit.findWidgets = function(/*DomNode*/ root){
  232. // summary:
  233. // Search subtree under root returning widgets found.
  234. // Doesn't search for nested widgets (ie, widgets inside other widgets).
  235. var outAry = [];
  236. function getChildrenHelper(root){
  237. for(var node = root.firstChild; node; node = node.nextSibling){
  238. if(node.nodeType == 1){
  239. var widgetId = node.getAttribute("widgetId");
  240. if(widgetId){
  241. var widget = hash[widgetId];
  242. if(widget){ // may be null on page w/multiple dojo's loaded
  243. outAry.push(widget);
  244. }
  245. }else{
  246. getChildrenHelper(node);
  247. }
  248. }
  249. }
  250. }
  251. getChildrenHelper(root);
  252. return outAry;
  253. };
  254. dijit._destroyAll = function(){
  255. // summary:
  256. // Code to destroy all widgets and do other cleanup on page unload
  257. // Clean up focus manager lingering references to widgets and nodes
  258. dijit._curFocus = null;
  259. dijit._prevFocus = null;
  260. dijit._activeStack = [];
  261. // Destroy all the widgets, top down
  262. dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
  263. // Avoid double destroy of widgets like Menu that are attached to <body>
  264. // even though they are logically children of other widgets.
  265. if(!widget._destroyed){
  266. if(widget.destroyRecursive){
  267. widget.destroyRecursive();
  268. }else if(widget.destroy){
  269. widget.destroy();
  270. }
  271. }
  272. });
  273. };
  274. if(dojo.isIE){
  275. // Only run _destroyAll() for IE because we think it's only necessary in that case,
  276. // and because it causes problems on FF. See bug #3531 for details.
  277. dojo.addOnWindowUnload(function(){
  278. dijit._destroyAll();
  279. });
  280. }
  281. dijit.byNode = function(/*DOMNode*/ node){
  282. // summary:
  283. // Returns the widget corresponding to the given DOMNode
  284. return hash[node.getAttribute("widgetId")]; // dijit._Widget
  285. };
  286. dijit.getEnclosingWidget = function(/*DOMNode*/ node){
  287. // summary:
  288. // Returns the widget whose DOM tree contains the specified DOMNode, or null if
  289. // the node is not contained within the DOM tree of any widget
  290. while(node){
  291. var id = node.getAttribute && node.getAttribute("widgetId");
  292. if(id){
  293. return hash[id];
  294. }
  295. node = node.parentNode;
  296. }
  297. return null;
  298. };
  299. var shown = (dijit._isElementShown = function(/*Element*/ elem){
  300. var s = style(elem);
  301. return (s.visibility != "hidden")
  302. && (s.visibility != "collapsed")
  303. && (s.display != "none")
  304. && (attr(elem, "type") != "hidden");
  305. });
  306. dijit.hasDefaultTabStop = function(/*Element*/ elem){
  307. // summary:
  308. // Tests if element is tab-navigable even without an explicit tabIndex setting
  309. // No explicit tabIndex setting, need to investigate node type
  310. switch(elem.nodeName.toLowerCase()){
  311. case "a":
  312. // An <a> w/out a tabindex is only navigable if it has an href
  313. return hasAttr(elem, "href");
  314. case "area":
  315. case "button":
  316. case "input":
  317. case "object":
  318. case "select":
  319. case "textarea":
  320. // These are navigable by default
  321. return true;
  322. case "iframe":
  323. // If it's an editor <iframe> then it's tab navigable.
  324. var body;
  325. try{
  326. // non-IE
  327. var contentDocument = elem.contentDocument;
  328. if("designMode" in contentDocument && contentDocument.designMode == "on"){
  329. return true;
  330. }
  331. body = contentDocument.body;
  332. }catch(e1){
  333. // contentWindow.document isn't accessible within IE7/8
  334. // if the iframe.src points to a foreign url and this
  335. // page contains an element, that could get focus
  336. try{
  337. body = elem.contentWindow.document.body;
  338. }catch(e2){
  339. return false;
  340. }
  341. }
  342. return body.contentEditable == 'true' || (body.firstChild && body.firstChild.contentEditable == 'true');
  343. default:
  344. return elem.contentEditable == 'true';
  345. }
  346. };
  347. var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
  348. // summary:
  349. // Tests if an element is tab-navigable
  350. // TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
  351. if(attr(elem, "disabled")){
  352. return false;
  353. }else if(hasAttr(elem, "tabIndex")){
  354. // Explicit tab index setting
  355. return attr(elem, "tabIndex") >= 0; // boolean
  356. }else{
  357. // No explicit tabIndex setting, so depends on node type
  358. return dijit.hasDefaultTabStop(elem);
  359. }
  360. });
  361. dijit._getTabNavigable = function(/*DOMNode*/ root){
  362. // summary:
  363. // Finds descendants of the specified root node.
  364. //
  365. // description:
  366. // Finds the following descendants of the specified root node:
  367. // * the first tab-navigable element in document order
  368. // without a tabIndex or with tabIndex="0"
  369. // * the last tab-navigable element in document order
  370. // without a tabIndex or with tabIndex="0"
  371. // * the first element in document order with the lowest
  372. // positive tabIndex value
  373. // * the last element in document order with the highest
  374. // positive tabIndex value
  375. var first, last, lowest, lowestTabindex, highest, highestTabindex, radioSelected = {};
  376. function radioName(node) {
  377. // If this element is part of a radio button group, return the name for that group.
  378. return node && node.tagName.toLowerCase() == "input" &&
  379. node.type && node.type.toLowerCase() == "radio" &&
  380. node.name && node.name.toLowerCase();
  381. }
  382. var walkTree = function(/*DOMNode*/parent){
  383. dojo.query("> *", parent).forEach(function(child){
  384. // Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
  385. // since show() invokes getAttribute("type"), which crash on VML nodes in IE.
  386. if((dojo.isIE <= 9 && child.scopeName !== "HTML") || !shown(child)){
  387. return;
  388. }
  389. if(isTabNavigable(child)){
  390. var tabindex = attr(child, "tabIndex");
  391. if(!hasAttr(child, "tabIndex") || tabindex == 0){
  392. if(!first){ first = child; }
  393. last = child;
  394. }else if(tabindex > 0){
  395. if(!lowest || tabindex < lowestTabindex){
  396. lowestTabindex = tabindex;
  397. lowest = child;
  398. }
  399. if(!highest || tabindex >= highestTabindex){
  400. highestTabindex = tabindex;
  401. highest = child;
  402. }
  403. }
  404. var rn = radioName(child);
  405. if(dojo.attr(child, "checked") && rn) {
  406. radioSelected[rn] = child;
  407. }
  408. }
  409. if(child.nodeName.toUpperCase() != 'SELECT'){
  410. walkTree(child);
  411. }
  412. });
  413. };
  414. if(shown(root)){ walkTree(root) }
  415. function rs(node) {
  416. // substitute checked radio button for unchecked one, if there is a checked one with the same name.
  417. return radioSelected[radioName(node)] || node;
  418. }
  419. return { first: rs(first), last: rs(last), lowest: rs(lowest), highest: rs(highest) };
  420. }
  421. dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
  422. // summary:
  423. // Finds the descendant of the specified root node
  424. // that is first in the tabbing order
  425. var elems = dijit._getTabNavigable(dojo.byId(root));
  426. return elems.lowest ? elems.lowest : elems.first; // DomNode
  427. };
  428. dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
  429. // summary:
  430. // Finds the descendant of the specified root node
  431. // that is last in the tabbing order
  432. var elems = dijit._getTabNavigable(dojo.byId(root));
  433. return elems.last ? elems.last : elems.highest; // DomNode
  434. };
  435. /*=====
  436. dojo.mixin(dijit, {
  437. // defaultDuration: Integer
  438. // The default animation speed (in ms) to use for all Dijit
  439. // transitional animations, unless otherwise specified
  440. // on a per-instance basis. Defaults to 200, overrided by
  441. // `djConfig.defaultDuration`
  442. defaultDuration: 200
  443. });
  444. =====*/
  445. dijit.defaultDuration = dojo.config["defaultDuration"] || 200;
  446. })();
  447. }
  448. if(!dojo._hasResource["dojo.Stateful"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  449. dojo._hasResource["dojo.Stateful"] = true;
  450. dojo.provide("dojo.Stateful");
  451. dojo.declare("dojo.Stateful", null, {
  452. // summary:
  453. // Base class for objects that provide named properties with optional getter/setter
  454. // control and the ability to watch for property changes
  455. // example:
  456. // | var obj = new dojo.Stateful();
  457. // | obj.watch("foo", function(){
  458. // | console.log("foo changed to " + this.get("foo"));
  459. // | });
  460. // | obj.set("foo","bar");
  461. postscript: function(mixin){
  462. if(mixin){
  463. dojo.mixin(this, mixin);
  464. }
  465. },
  466. get: function(/*String*/name){
  467. // summary:
  468. // Get a property on a Stateful instance.
  469. // name:
  470. // The property to get.
  471. // description:
  472. // Get a named property on a Stateful object. The property may
  473. // potentially be retrieved via a getter method in subclasses. In the base class
  474. // this just retrieves the object's property.
  475. // For example:
  476. // | stateful = new dojo.Stateful({foo: 3});
  477. // | stateful.get("foo") // returns 3
  478. // | stateful.foo // returns 3
  479. return this[name];
  480. },
  481. set: function(/*String*/name, /*Object*/value){
  482. // summary:
  483. // Set a property on a Stateful instance
  484. // name:
  485. // The property to set.
  486. // value:
  487. // The value to set in the property.
  488. // description:
  489. // Sets named properties on a stateful object and notifies any watchers of
  490. // the property. A programmatic setter may be defined in subclasses.
  491. // For example:
  492. // | stateful = new dojo.Stateful();
  493. // | stateful.watch(function(name, oldValue, value){
  494. // | // this will be called on the set below
  495. // | }
  496. // | stateful.set(foo, 5);
  497. //
  498. // set() may also be called with a hash of name/value pairs, ex:
  499. // | myObj.set({
  500. // | foo: "Howdy",
  501. // | bar: 3
  502. // | })
  503. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  504. if(typeof name === "object"){
  505. for(var x in name){
  506. this.set(x, name[x]);
  507. }
  508. return this;
  509. }
  510. var oldValue = this[name];
  511. this[name] = value;
  512. if(this._watchCallbacks){
  513. this._watchCallbacks(name, oldValue, value);
  514. }
  515. return this;
  516. },
  517. watch: function(/*String?*/name, /*Function*/callback){
  518. // summary:
  519. // Watches a property for changes
  520. // name:
  521. // Indicates the property to watch. This is optional (the callback may be the
  522. // only parameter), and if omitted, all the properties will be watched
  523. // returns:
  524. // An object handle for the watch. The unwatch method of this object
  525. // can be used to discontinue watching this property:
  526. // | var watchHandle = obj.watch("foo", callback);
  527. // | watchHandle.unwatch(); // callback won't be called now
  528. // callback:
  529. // The function to execute when the property changes. This will be called after
  530. // the property has been changed. The callback will be called with the |this|
  531. // set to the instance, the first argument as the name of the property, the
  532. // second argument as the old value and the third argument as the new value.
  533. var callbacks = this._watchCallbacks;
  534. if(!callbacks){
  535. var self = this;
  536. callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
  537. var notify = function(propertyCallbacks){
  538. if(propertyCallbacks){
  539. propertyCallbacks = propertyCallbacks.slice();
  540. for(var i = 0, l = propertyCallbacks.length; i < l; i++){
  541. try{
  542. propertyCallbacks[i].call(self, name, oldValue, value);
  543. }catch(e){
  544. console.error(e);
  545. }
  546. }
  547. }
  548. };
  549. notify(callbacks['_' + name]);
  550. if(!ignoreCatchall){
  551. notify(callbacks["*"]); // the catch-all
  552. }
  553. }; // we use a function instead of an object so it will be ignored by JSON conversion
  554. }
  555. if(!callback && typeof name === "function"){
  556. callback = name;
  557. name = "*";
  558. }else{
  559. // prepend with dash to prevent name conflicts with function (like "name" property)
  560. name = '_' + name;
  561. }
  562. var propertyCallbacks = callbacks[name];
  563. if(typeof propertyCallbacks !== "object"){
  564. propertyCallbacks = callbacks[name] = [];
  565. }
  566. propertyCallbacks.push(callback);
  567. return {
  568. unwatch: function(){
  569. propertyCallbacks.splice(dojo.indexOf(propertyCallbacks, callback), 1);
  570. }
  571. };
  572. }
  573. });
  574. }
  575. if(!dojo._hasResource["dijit._WidgetBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  576. dojo._hasResource["dijit._WidgetBase"] = true;
  577. dojo.provide("dijit._WidgetBase");
  578. (function(){
  579. function isEqual(a, b){
  580. // summary:
  581. // Function that determines whether two values are identical,
  582. // taking into account that NaN is not normally equal to itself
  583. // in JS.
  584. return a === b || (/* a is NaN */ a !== a && /* b is NaN */ b !== b);
  585. }
  586. dojo.declare("dijit._WidgetBase", dojo.Stateful, {
  587. // summary:
  588. // Future base class for all Dijit widgets.
  589. // _Widget extends this class adding support for various features needed by desktop.
  590. // id: [const] String
  591. // A unique, opaque ID string that can be assigned by users or by the
  592. // system. If the developer passes an ID which is known not to be
  593. // unique, the specified ID is ignored and the system-generated ID is
  594. // used instead.
  595. id: "",
  596. // lang: [const] String
  597. // Rarely used. Overrides the default Dojo locale used to render this widget,
  598. // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
  599. // Value must be among the list of locales specified during by the Dojo bootstrap,
  600. // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
  601. lang: "",
  602. // dir: [const] String
  603. // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
  604. // attribute. Either left-to-right "ltr" or right-to-left "rtl". If undefined, widgets renders in page's
  605. // default direction.
  606. dir: "",
  607. // class: String
  608. // HTML class attribute
  609. "class": "",
  610. // style: String||Object
  611. // HTML style attributes as cssText string or name/value hash
  612. style: "",
  613. // title: String
  614. // HTML title attribute.
  615. //
  616. // For form widgets this specifies a tooltip to display when hovering over
  617. // the widget (just like the native HTML title attribute).
  618. //
  619. // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
  620. // etc., it's used to specify the tab label, accordion pane title, etc.
  621. title: "",
  622. // tooltip: String
  623. // When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
  624. // this specifies the tooltip to appear when the mouse is hovered over that text.
  625. tooltip: "",
  626. // baseClass: [protected] String
  627. // Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
  628. // widget state.
  629. baseClass: "",
  630. // srcNodeRef: [readonly] DomNode
  631. // pointer to original DOM node
  632. srcNodeRef: null,
  633. // domNode: [readonly] DomNode
  634. // This is our visible representation of the widget! Other DOM
  635. // Nodes may by assigned to other properties, usually through the
  636. // template system's dojoAttachPoint syntax, but the domNode
  637. // property is the canonical "top level" node in widget UI.
  638. domNode: null,
  639. // containerNode: [readonly] DomNode
  640. // Designates where children of the source DOM node will be placed.
  641. // "Children" in this case refers to both DOM nodes and widgets.
  642. // For example, for myWidget:
  643. //
  644. // | <div dojoType=myWidget>
  645. // | <b> here's a plain DOM node
  646. // | <span dojoType=subWidget>and a widget</span>
  647. // | <i> and another plain DOM node </i>
  648. // | </div>
  649. //
  650. // containerNode would point to:
  651. //
  652. // | <b> here's a plain DOM node
  653. // | <span dojoType=subWidget>and a widget</span>
  654. // | <i> and another plain DOM node </i>
  655. //
  656. // In templated widgets, "containerNode" is set via a
  657. // dojoAttachPoint assignment.
  658. //
  659. // containerNode must be defined for any widget that accepts innerHTML
  660. // (like ContentPane or BorderContainer or even Button), and conversely
  661. // is null for widgets that don't, like TextBox.
  662. containerNode: null,
  663. /*=====
  664. // _started: Boolean
  665. // startup() has completed.
  666. _started: false,
  667. =====*/
  668. // attributeMap: [protected] Object
  669. // attributeMap sets up a "binding" between attributes (aka properties)
  670. // of the widget and the widget's DOM.
  671. // Changes to widget attributes listed in attributeMap will be
  672. // reflected into the DOM.
  673. //
  674. // For example, calling set('title', 'hello')
  675. // on a TitlePane will automatically cause the TitlePane's DOM to update
  676. // with the new title.
  677. //
  678. // attributeMap is a hash where the key is an attribute of the widget,
  679. // and the value reflects a binding to a:
  680. //
  681. // - DOM node attribute
  682. // | focus: {node: "focusNode", type: "attribute"}
  683. // Maps this.focus to this.focusNode.focus
  684. //
  685. // - DOM node innerHTML
  686. // | title: { node: "titleNode", type: "innerHTML" }
  687. // Maps this.title to this.titleNode.innerHTML
  688. //
  689. // - DOM node innerText
  690. // | title: { node: "titleNode", type: "innerText" }
  691. // Maps this.title to this.titleNode.innerText
  692. //
  693. // - DOM node CSS class
  694. // | myClass: { node: "domNode", type: "class" }
  695. // Maps this.myClass to this.domNode.className
  696. //
  697. // If the value is an array, then each element in the array matches one of the
  698. // formats of the above list.
  699. //
  700. // There are also some shorthands for backwards compatibility:
  701. // - string --> { node: string, type: "attribute" }, for example:
  702. // | "focusNode" ---> { node: "focusNode", type: "attribute" }
  703. // - "" --> { node: "domNode", type: "attribute" }
  704. attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},
  705. // _blankGif: [protected] String
  706. // Path to a blank 1x1 image.
  707. // Used by <img> nodes in templates that really get their image via CSS background-image.
  708. _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),
  709. //////////// INITIALIZATION METHODS ///////////////////////////////////////
  710. postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
  711. // summary:
  712. // Kicks off widget instantiation. See create() for details.
  713. // tags:
  714. // private
  715. this.create(params, srcNodeRef);
  716. },
  717. create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
  718. // summary:
  719. // Kick off the life-cycle of a widget
  720. // params:
  721. // Hash of initialization parameters for widget, including
  722. // scalar values (like title, duration etc.) and functions,
  723. // typically callbacks like onClick.
  724. // srcNodeRef:
  725. // If a srcNodeRef (DOM node) is specified:
  726. // - use srcNodeRef.innerHTML as my contents
  727. // - if this is a behavioral widget then apply behavior
  728. // to that srcNodeRef
  729. // - otherwise, replace srcNodeRef with my generated DOM
  730. // tree
  731. // description:
  732. // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
  733. // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
  734. // for a discussion of the widget creation lifecycle.
  735. //
  736. // Of course, adventurous developers could override create entirely, but this should
  737. // only be done as a last resort.
  738. // tags:
  739. // private
  740. // store pointer to original DOM tree
  741. this.srcNodeRef = dojo.byId(srcNodeRef);
  742. // For garbage collection. An array of handles returned by Widget.connect()
  743. // Each handle returned from Widget.connect() is an array of handles from dojo.connect()
  744. this._connects = [];
  745. // For garbage collection. An array of handles returned by Widget.subscribe()
  746. // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
  747. this._subscribes = [];
  748. // mix in our passed parameters
  749. if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
  750. if(params){
  751. this.params = params;
  752. dojo._mixin(this, params);
  753. }
  754. this.postMixInProperties();
  755. // generate an id for the widget if one wasn't specified
  756. // (be sure to do this before buildRendering() because that function might
  757. // expect the id to be there.)
  758. if(!this.id){
  759. this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
  760. }
  761. dijit.registry.add(this);
  762. this.buildRendering();
  763. if(this.domNode){
  764. // Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
  765. // Also calls custom setters for all attributes with custom setters.
  766. this._applyAttributes();
  767. // If srcNodeRef was specified, then swap out original srcNode for this widget's DOM tree.
  768. // For 2.0, move this after postCreate(). postCreate() shouldn't depend on the
  769. // widget being attached to the DOM since it isn't when a widget is created programmatically like
  770. // new MyWidget({}). See #11635.
  771. var source = this.srcNodeRef;
  772. if(source && source.parentNode && this.domNode !== source){
  773. source.parentNode.replaceChild(this.domNode, source);
  774. }
  775. }
  776. if(this.domNode){
  777. // Note: for 2.0 may want to rename widgetId to dojo._scopeName + "_widgetId",
  778. // assuming that dojo._scopeName even exists in 2.0
  779. this.domNode.setAttribute("widgetId", this.id);
  780. }
  781. this.postCreate();
  782. // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
  783. if(this.srcNodeRef && !this.srcNodeRef.parentNode){
  784. delete this.srcNodeRef;
  785. }
  786. this._created = true;
  787. },
  788. _applyAttributes: function(){
  789. // summary:
  790. // Step during widget creation to copy all widget attributes to the
  791. // DOM as per attributeMap and _setXXXAttr functions.
  792. // description:
  793. // Skips over blank/false attribute values, unless they were explicitly specified
  794. // as parameters to the widget, since those are the default anyway,
  795. // and setting tabIndex="" is different than not setting tabIndex at all.
  796. //
  797. // It processes the attributes in the attribute map first, and then
  798. // it goes through and processes the attributes for the _setXXXAttr
  799. // functions that have been specified
  800. // tags:
  801. // private
  802. var condAttrApply = function(attr, scope){
  803. if((scope.params && attr in scope.params) || scope[attr]){
  804. scope.set(attr, scope[attr]);
  805. }
  806. };
  807. // Do the attributes in attributeMap
  808. for(var attr in this.attributeMap){
  809. condAttrApply(attr, this);
  810. }
  811. // And also any attributes with custom setters
  812. dojo.forEach(this._getSetterAttributes(), function(a){
  813. if(!(a in this.attributeMap)){
  814. condAttrApply(a, this);
  815. }
  816. }, this);
  817. },
  818. _getSetterAttributes: function(){
  819. // summary:
  820. // Returns list of attributes with custom setters for this widget
  821. var ctor = this.constructor;
  822. if(!ctor._setterAttrs){
  823. var r = (ctor._setterAttrs = []),
  824. attrs,
  825. proto = ctor.prototype;
  826. for(var fxName in proto){
  827. if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
  828. r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
  829. }
  830. }
  831. }
  832. return ctor._setterAttrs; // String[]
  833. },
  834. postMixInProperties: function(){
  835. // summary:
  836. // Called after the parameters to the widget have been read-in,
  837. // but before the widget template is instantiated. Especially
  838. // useful to set properties that are referenced in the widget
  839. // template.
  840. // tags:
  841. // protected
  842. },
  843. buildRendering: function(){
  844. // summary:
  845. // Construct the UI for this widget, setting this.domNode
  846. // description:
  847. // Most widgets will mixin `dijit._Templated`, which implements this
  848. // method.
  849. // tags:
  850. // protected
  851. if(!this.domNode){
  852. // Create root node if it wasn't created by _Templated
  853. this.domNode = this.srcNodeRef || dojo.create('div');
  854. }
  855. // baseClass is a single class name or occasionally a space-separated list of names.
  856. // Add those classes to the DOMNode. If RTL mode then also add with Rtl suffix.
  857. // TODO: make baseClass custom setter
  858. if(this.baseClass){
  859. var classes = this.baseClass.split(" ");
  860. if(!this.isLeftToRight()){
  861. classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
  862. }
  863. dojo.addClass(this.domNode, classes);
  864. }
  865. },
  866. postCreate: function(){
  867. // summary:
  868. // Processing after the DOM fragment is created
  869. // description:
  870. // Called after the DOM fragment has been created, but not necessarily
  871. // added to the document. Do not include any operations which rely on
  872. // node dimensions or placement.
  873. // tags:
  874. // protected
  875. },
  876. startup: function(){
  877. // summary:
  878. // Processing after the DOM fragment is added to the document
  879. // description:
  880. // Called after a widget and its children have been created and added to the page,
  881. // and all related widgets have finished their create() cycle, up through postCreate().
  882. // This is useful for composite widgets that need to control or layout sub-widgets.
  883. // Many layout widgets can use this as a wiring phase.
  884. this._started = true;
  885. },
  886. //////////// DESTROY FUNCTIONS ////////////////////////////////
  887. destroyRecursive: function(/*Boolean?*/ preserveDom){
  888. // summary:
  889. // Destroy this widget and its descendants
  890. // description:
  891. // This is the generic "destructor" function that all widget users
  892. // should call to cleanly discard with a widget. Once a widget is
  893. // destroyed, it is removed from the manager object.
  894. // preserveDom:
  895. // If true, this method will leave the original DOM structure
  896. // alone of descendant Widgets. Note: This will NOT work with
  897. // dijit._Templated widgets.
  898. this._beingDestroyed = true;
  899. this.destroyDescendants(preserveDom);
  900. this.destroy(preserveDom);
  901. },
  902. destroy: function(/*Boolean*/ preserveDom){
  903. // summary:
  904. // Destroy this widget, but not its descendants.
  905. // This method will, however, destroy internal widgets such as those used within a template.
  906. // preserveDom: Boolean
  907. // If true, this method will leave the original DOM structure alone.
  908. // Note: This will not yet work with _Templated widgets
  909. this._beingDestroyed = true;
  910. this.uninitialize();
  911. var d = dojo,
  912. dfe = d.forEach,
  913. dun = d.unsubscribe;
  914. dfe(this._connects, function(array){
  915. dfe(array, d.disconnect);
  916. });
  917. dfe(this._subscribes, function(handle){
  918. dun(handle);
  919. });
  920. // destroy widgets created as part of template, etc.
  921. dfe(this._supportingWidgets || [], function(w){
  922. if(w.destroyRecursive){
  923. w.destroyRecursive();
  924. }else if(w.destroy){
  925. w.destroy();
  926. }
  927. });
  928. this.destroyRendering(preserveDom);
  929. dijit.registry.remove(this.id);
  930. this._destroyed = true;
  931. },
  932. destroyRendering: function(/*Boolean?*/ preserveDom){
  933. // summary:
  934. // Destroys the DOM nodes associated with this widget
  935. // preserveDom:
  936. // If true, this method will leave the original DOM structure alone
  937. // during tear-down. Note: this will not work with _Templated
  938. // widgets yet.
  939. // tags:
  940. // protected
  941. if(this.bgIframe){
  942. this.bgIframe.destroy(preserveDom);
  943. delete this.bgIframe;
  944. }
  945. if(this.domNode){
  946. if(preserveDom){
  947. dojo.removeAttr(this.domNode, "widgetId");
  948. }else{
  949. dojo.destroy(this.domNode);
  950. }
  951. delete this.domNode;
  952. }
  953. if(this.srcNodeRef){
  954. if(!preserveDom){
  955. dojo.destroy(this.srcNodeRef);
  956. }
  957. delete this.srcNodeRef;
  958. }
  959. },
  960. destroyDescendants: function(/*Boolean?*/ preserveDom){
  961. // summary:
  962. // Recursively destroy the children of this widget and their
  963. // descendants.
  964. // preserveDom:
  965. // If true, the preserveDom attribute is passed to all descendant
  966. // widget's .destroy() method. Not for use with _Templated
  967. // widgets.
  968. // get all direct descendants and destroy them recursively
  969. dojo.forEach(this.getChildren(), function(widget){
  970. if(widget.destroyRecursive){
  971. widget.destroyRecursive(preserveDom);
  972. }
  973. });
  974. },
  975. uninitialize: function(){
  976. // summary:
  977. // Stub function. Override to implement custom widget tear-down
  978. // behavior.
  979. // tags:
  980. // protected
  981. return false;
  982. },
  983. ////////////////// GET/SET, CUSTOM SETTERS, ETC. ///////////////////
  984. _setClassAttr: function(/*String*/ value){
  985. // summary:
  986. // Custom setter for the CSS "class" attribute
  987. // tags:
  988. // protected
  989. var mapNode = this[this.attributeMap["class"] || 'domNode'];
  990. dojo.replaceClass(mapNode, value, this["class"]);
  991. this._set("class", value);
  992. },
  993. _setStyleAttr: function(/*String||Object*/ value){
  994. // summary:
  995. // Sets the style attribute of the widget according to value,
  996. // which is either a hash like {height: "5px", width: "3px"}
  997. // or a plain string
  998. // description:
  999. // Determines which node to set the style on based on style setting
  1000. // in attributeMap.
  1001. // tags:
  1002. // protected
  1003. var mapNode = this[this.attributeMap.style || 'domNode'];
  1004. // Note: technically we should revert any style setting made in a previous call
  1005. // to his method, but that's difficult to keep track of.
  1006. if(dojo.isObject(value)){
  1007. dojo.style(mapNode, value);
  1008. }else{
  1009. if(mapNode.style.cssText){
  1010. mapNode.style.cssText += "; " + value;
  1011. }else{
  1012. mapNode.style.cssText = value;
  1013. }
  1014. }
  1015. this._set("style", value);
  1016. },
  1017. _attrToDom: function(/*String*/ attr, /*String*/ value){
  1018. // summary:
  1019. // Reflect a widget attribute (title, tabIndex, duration etc.) to
  1020. // the widget DOM, as specified in attributeMap.
  1021. // Note some attributes like "type"
  1022. // cannot be processed this way as they are not mutable.
  1023. //
  1024. // tags:
  1025. // private
  1026. var commands = this.attributeMap[attr];
  1027. dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){
  1028. // Get target node and what we are doing to that node
  1029. var mapNode = this[command.node || command || "domNode"]; // DOM node
  1030. var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute
  1031. switch(type){
  1032. case "attribute":
  1033. if(dojo.isFunction(value)){ // functions execute in the context of the widget
  1034. value = dojo.hitch(this, value);
  1035. }
  1036. // Get the name of the DOM node attribute; usually it's the same
  1037. // as the name of the attribute in the widget (attr), but can be overridden.
  1038. // Also maps handler names to lowercase, like onSubmit --> onsubmit
  1039. var attrName = command.attribute ? command.attribute :
  1040. (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);
  1041. dojo.attr(mapNode, attrName, value);
  1042. break;
  1043. case "innerText":
  1044. mapNode.innerHTML = "";
  1045. mapNode.appendChild(dojo.doc.createTextNode(value));
  1046. break;
  1047. case "innerHTML":
  1048. mapNode.innerHTML = value;
  1049. break;
  1050. case "class":
  1051. dojo.replaceClass(mapNode, value, this[attr]);
  1052. break;
  1053. }
  1054. }, this);
  1055. },
  1056. get: function(name){
  1057. // summary:
  1058. // Get a property from a widget.
  1059. // name:
  1060. // The property to get.
  1061. // description:
  1062. // Get a named property from a widget. The property may
  1063. // potentially be retrieved via a getter method. If no getter is defined, this
  1064. // just retrieves the object's property.
  1065. // For example, if the widget has a properties "foo"
  1066. // and "bar" and a method named "_getFooAttr", calling:
  1067. // | myWidget.get("foo");
  1068. // would be equivalent to writing:
  1069. // | widget._getFooAttr();
  1070. // and:
  1071. // | myWidget.get("bar");
  1072. // would be equivalent to writing:
  1073. // | widget.bar;
  1074. var names = this._getAttrNames(name);
  1075. return this[names.g] ? this[names.g]() : this[name];
  1076. },
  1077. set: function(name, value){
  1078. // summary:
  1079. // Set a property on a widget
  1080. // name:
  1081. // The property to set.
  1082. // value:
  1083. // The value to set in the property.
  1084. // description:
  1085. // Sets named properties on a widget which may potentially be handled by a
  1086. // setter in the widget.
  1087. // For example, if the widget has a properties "foo"
  1088. // and "bar" and a method named "_setFooAttr", calling:
  1089. // | myWidget.set("foo", "Howdy!");
  1090. // would be equivalent to writing:
  1091. // | widget._setFooAttr("Howdy!");
  1092. // and:
  1093. // | myWidget.set("bar", 3);
  1094. // would be equivalent to writing:
  1095. // | widget.bar = 3;
  1096. //
  1097. // set() may also be called with a hash of name/value pairs, ex:
  1098. // | myWidget.set({
  1099. // | foo: "Howdy",
  1100. // | bar: 3
  1101. // | })
  1102. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  1103. if(typeof name === "object"){
  1104. for(var x in name){
  1105. this.set(x, name[x]);
  1106. }
  1107. return this;
  1108. }
  1109. var names = this._getAttrNames(name);
  1110. if(this[names.s]){
  1111. // use the explicit setter
  1112. var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
  1113. }else{
  1114. // if param is specified as DOM node attribute, copy it
  1115. if(name in this.attributeMap){
  1116. this._attrToDom(name, value);
  1117. }
  1118. this._set(name, value);
  1119. }
  1120. return result || this;
  1121. },
  1122. _attrPairNames: {}, // shared between all widgets
  1123. _getAttrNames: function(name){
  1124. // summary:
  1125. // Helper function for get() and set().
  1126. // Caches attribute name values so we don't do the string ops every time.
  1127. // tags:
  1128. // private
  1129. var apn = this._attrPairNames;
  1130. if(apn[name]){ return apn[name]; }
  1131. var uc = name.charAt(0).toUpperCase() + name.substr(1);
  1132. return (apn[name] = {
  1133. n: name+"Node",
  1134. s: "_set"+uc+"Attr",
  1135. g: "_get"+uc+"Attr"
  1136. });
  1137. },
  1138. _set: function(/*String*/ name, /*anything*/ value){
  1139. // summary:
  1140. // Helper function to set new value for specified attribute, and call handlers
  1141. // registered with watch() if the value has changed.
  1142. var oldValue = this[name];
  1143. this[name] = value;
  1144. if(this._watchCallbacks && this._created && !isEqual(value, oldValue)){
  1145. this._watchCallbacks(name, oldValue, value);
  1146. }
  1147. },
  1148. toString: function(){
  1149. // summary:
  1150. // Returns a string that represents the widget
  1151. // description:
  1152. // When a widget is cast to a string, this method will be used to generate the
  1153. // output. Currently, it does not implement any sort of reversible
  1154. // serialization.
  1155. return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
  1156. },
  1157. getDescendants: function(){
  1158. // summary:
  1159. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  1160. // This method should generally be avoided as it returns widgets declared in templates, which are
  1161. // supposed to be internal/hidden, but it's left here for back-compat reasons.
  1162. return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
  1163. },
  1164. getChildren: function(){
  1165. // summary:
  1166. // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
  1167. // Does not return nested widgets, nor widgets that are part of this widget's template.
  1168. return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
  1169. },
  1170. connect: function(
  1171. /*Object|null*/ obj,
  1172. /*String|Function*/ event,
  1173. /*String|Function*/ method){
  1174. // summary:
  1175. // Connects specified obj/event to specified method of this object
  1176. // and registers for disconnect() on widget destroy.
  1177. // description:
  1178. // Provide widget-specific analog to dojo.connect, except with the
  1179. // implicit use of this widget as the target object.
  1180. // Events connected with `this.connect` are disconnected upon
  1181. // destruction.
  1182. // returns:
  1183. // A handle that can be passed to `disconnect` in order to disconnect before
  1184. // the widget is destroyed.
  1185. // example:
  1186. // | var btn = new dijit.form.Button();
  1187. // | // when foo.bar() is called, call the listener we're going to
  1188. // | // provide in the scope of btn
  1189. // | btn.connect(foo, "bar", function(){
  1190. // | console.debug(this.toString());
  1191. // | });
  1192. // tags:
  1193. // protected
  1194. var handles = [dojo._connect(obj, event, this, method)];
  1195. this._connects.push(handles);
  1196. return handles; // _Widget.Handle
  1197. },
  1198. disconnect: function(/* _Widget.Handle */ handles){
  1199. // summary:
  1200. // Disconnects handle created by `connect`.
  1201. // Also removes handle from this widget's list of connects.
  1202. // tags:
  1203. // protected
  1204. for(var i=0; i<this._connects.length; i++){
  1205. if(this._connects[i] == handles){
  1206. dojo.forEach(handles, dojo.disconnect);
  1207. this._connects.splice(i, 1);
  1208. return;
  1209. }
  1210. }
  1211. },
  1212. subscribe: function(
  1213. /*String*/ topic,
  1214. /*String|Function*/ method){
  1215. // summary:
  1216. // Subscribes to the specified topic and calls the specified method
  1217. // of this object and registers for unsubscribe() on widget destroy.
  1218. // description:
  1219. // Provide widget-specific analog to dojo.subscribe, except with the
  1220. // implicit use of this widget as the target object.
  1221. // example:
  1222. // | var btn = new dijit.form.Button();
  1223. // | // when /my/topic is published, this button changes its label to
  1224. // | // be the parameter of the topic.
  1225. // | btn.subscribe("/my/topic", function(v){
  1226. // | this.set("label", v);
  1227. // | });
  1228. var handle = dojo.subscribe(topic, this, method);
  1229. // return handles for Any widget that may need them
  1230. this._subscribes.push(handle);
  1231. return handle;
  1232. },
  1233. unsubscribe: function(/*Object*/ handle){
  1234. // summary:
  1235. // Unsubscribes handle created by this.subscribe.
  1236. // Also removes handle from this widget's list of subscriptions
  1237. for(var i=0; i<this._subscribes.length; i++){
  1238. if(this._subscribes[i] == handle){
  1239. dojo.unsubscribe(handle);
  1240. this._subscribes.splice(i, 1);
  1241. return;
  1242. }
  1243. }
  1244. },
  1245. isLeftToRight: function(){
  1246. // summary:
  1247. // Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
  1248. // tags:
  1249. // protected
  1250. return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
  1251. },
  1252. placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
  1253. // summary:
  1254. // Place this widget's domNode reference somewhere in the DOM based
  1255. // on standard dojo.place conventions, or passing a Widget reference that
  1256. // contains and addChild member.
  1257. //
  1258. // description:
  1259. // A convenience function provided in all _Widgets, providing a simple
  1260. // shorthand mechanism to put an existing (or newly created) Widget
  1261. // somewhere in the dom, and allow chaining.
  1262. //
  1263. // reference:
  1264. // The String id of a domNode, a domNode reference, or a reference to a Widget posessing
  1265. // an addChild method.
  1266. //
  1267. // position:
  1268. // If passed a string or domNode reference, the position argument
  1269. // accepts a string just as dojo.place does, one of: "first", "last",
  1270. // "before", or "after".
  1271. //
  1272. // If passed a _Widget reference, and that widget reference has an ".addChild" method,
  1273. // it will be called passing this widget instance into that method, supplying the optional
  1274. // position index passed.
  1275. //
  1276. // returns:
  1277. // dijit._Widget
  1278. // Provides a useful return of the newly created dijit._Widget instance so you
  1279. // can "chain" this function by instantiating, placing, then saving the return value
  1280. // to a variable.
  1281. //
  1282. // example:
  1283. // | // create a Button with no srcNodeRef, and place it in the body:
  1284. // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
  1285. // | // now, 'button' is still the widget reference to the newly created button
  1286. // | dojo.connect(button, "onClick", function(e){ console.log('click'); });
  1287. //
  1288. // example:
  1289. // | // create a button out of a node with id="src" and append it to id="wrapper":
  1290. // | var button = new dijit.form.Button({},"src").placeAt("wrapper");
  1291. //
  1292. // example:
  1293. // | // place a new button as the first element of some div
  1294. // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
  1295. //
  1296. // example:
  1297. // | // create a contentpane and add it to a TabContainer
  1298. // | var tc = dijit.byId("myTabs");
  1299. // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)
  1300. if(reference.declaredClass && reference.addChild){
  1301. reference.addChild(this, position);
  1302. }else{
  1303. dojo.place(this.domNode, reference, position);
  1304. }
  1305. return this;
  1306. },
  1307. defer: function(fcn, delay){
  1308. // summary:
  1309. // Wrapper to setTimeout to avoid deferred functions executing
  1310. // after the originating widget has been destroyed.
  1311. // Returns an object handle with a remove method (that returns null) (replaces clearTimeout).
  1312. // fcn: function reference
  1313. // delay: Optional number (defaults to 0)
  1314. // tags:
  1315. // protected.
  1316. var timer = setTimeout(dojo.hitch(this,
  1317. function(){
  1318. timer = null;
  1319. if(!this._destroyed){
  1320. dojo.hitch(this, fcn)();
  1321. }
  1322. }),
  1323. delay || 0
  1324. );
  1325. return {
  1326. remove: function(){
  1327. if(timer){
  1328. clearTimeout(timer);
  1329. timer = null;
  1330. }
  1331. return null; // so this works well: handle = handle.remove();
  1332. }
  1333. };
  1334. }
  1335. });
  1336. })();
  1337. }
  1338. if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  1339. dojo._hasResource["dojo.window"] = true;
  1340. dojo.provide("dojo.window");
  1341. dojo.getObject("window", true, dojo);
  1342. dojo.window.getBox = function(){
  1343. // summary:
  1344. // Returns the dimensions and scroll position of the viewable area of a browser window
  1345. var scrollRoot = (dojo.doc.compatMode == 'BackCompat') ? dojo.body() : dojo.doc.documentElement;
  1346. // get scroll position
  1347. var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work
  1348. return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y };
  1349. };
  1350. dojo.window.get = function(doc){
  1351. // summary:
  1352. // Get window object associated with document doc
  1353. // In some IE versions (at least 6.0), document.parentWindow does not return a
  1354. // reference to the real window object (maybe a copy), so we must fix it as well
  1355. // We use IE specific execScript to attach the real window reference to
  1356. // document._parentWindow for later use
  1357. if(dojo.isIE && window !== document.parentWindow){
  1358. /*
  1359. In IE 6, only the variable "window" can be used to connect events (others
  1360. may be only copies).
  1361. */
  1362. doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
  1363. //to prevent memory leak, unset it after use
  1364. //another possibility is to add an onUnload handler which seems overkill to me (liucougar)
  1365. var win = doc._parentWindow;
  1366. doc._parentWindow = null;
  1367. return win; // Window
  1368. }
  1369. return doc.parentWindow || doc.defaultView; // Window
  1370. };
  1371. dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
  1372. // summary:
  1373. // Scroll the passed node into view using minimal movement, if it is not already.
  1374. // Don't rely on node.scrollIntoView working just because the function is there since
  1375. // it forces the node to the page's bottom or top (and left or right in IE) without consideration for the minimal movement.
  1376. // WebKit's node.scrollIntoViewIfNeeded doesn't work either for inner scrollbars in right-to-left mode
  1377. // and when there's a fixed position scrollable element
  1378. node = dojo.byId(node);
  1379. var body, doc = node.ownerDocument || dojo.doc;
  1380. // has() functions but without has() support
  1381. if(!("rtl_adjust_position_for_verticalScrollBar" in dojo.window)){
  1382. body = dojo.body();
  1383. var scrollable = dojo.create('div', {
  1384. style: {overflow:'scroll', overflowX:'visible', direction:'rtl', visibility:'hidden', position:'absolute', left:'0', top:'0', width:'64px', height:'64px'}
  1385. }, body, "last"),
  1386. div = dojo.create('div', {
  1387. style: {overflow:'hidden', direction:'ltr'}
  1388. }, scrollable, "last");
  1389. dojo.window.rtl_adjust_position_for_verticalScrollBar = dojo.position(div).x != 0;
  1390. scrollable.removeChild(div);
  1391. body.removeChild(scrollable);
  1392. }
  1393. if(!("position_fixed_support" in dojo.window)){
  1394. // IE6, IE7+quirks, and some older mobile browsers don't support position:fixed
  1395. body = dojo.body();
  1396. var outer = dojo.create('span', {
  1397. style: {visibility:'hidden', position:'fixed', left:'1px', top:'1px'}
  1398. }, body, "last"),
  1399. inner = dojo.create('span', {
  1400. style: {position:'fixed', left:'0', top:'0'}
  1401. }, outer, "last");
  1402. dojo.window.position_fixed_support = dojo.position(inner).x != dojo.position(outer).x;
  1403. outer.removeChild(inner);
  1404. body.removeChild(outer);
  1405. }
  1406. try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
  1407. body = doc.body || doc.getElementsByTagName("body")[0];
  1408. var html = doc.documentElement || body.parentNode,
  1409. isIE = dojo.isIE,
  1410. isWK = dojo.isWebKit;
  1411. // if an untested browser, then use the native method
  1412. if(node == body || node == html){ return; }
  1413. if(!(dojo.isMozilla || isIE || isWK || dojo.isOpera) && ("scrollIntoView" in node)){
  1414. node.scrollIntoView(false); // short-circuit to native if possible
  1415. return;
  1416. }
  1417. var backCompat = doc.compatMode == 'BackCompat',
  1418. rootWidth = Math.min(body.clientWidth || html.clientWidth, html.clientWidth || body.clientWidth),
  1419. rootHeight = Math.min(body.clientHeight || html.clientHeight, html.clientHeight || body.clientHeight),
  1420. scrollRoot = (isWK || backCompat) ? body : html,
  1421. nodePos = pos || dojo.position(node),
  1422. el = node.parentNode,
  1423. isFixed = function(el){
  1424. return (isIE <= 6 || (isIE == 7 && backCompat))
  1425. ? false
  1426. : (dojo.window.position_fixed_support && (dojo.style(el, 'position').toLowerCase() == "fixed"));
  1427. };
  1428. if(isFixed(node)){ return; } // nothing to do
  1429. while(el){
  1430. if(el == body){ el = scrollRoot; }
  1431. var elPos = dojo.position(el),
  1432. fixedPos = isFixed(el),
  1433. rtl = dojo.getComputedStyle(el).direction.toLowerCase() == "rtl";
  1434. if(el == scrollRoot){
  1435. elPos.w = rootWidth; elPos.h = rootHeight;
  1436. if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
  1437. if(elPos.x < 0 || !isIE || isIE >= 9){ elPos.x = 0; } // older IE can have values > 0
  1438. if(elPos.y < 0 || !isIE || isIE >= 9){ elPos.y = 0; }
  1439. }else{
  1440. var pb = dojo._getPadBorderExtents(el);
  1441. elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
  1442. var clientSize = el.clientWidth,
  1443. scrollBarSize = elPos.w - clientSize;
  1444. if(clientSize > 0 && scrollBarSize > 0){
  1445. if(rtl && dojo.window.rtl_adjust_position_for_verticalScrollBar){
  1446. elPos.x += scrollBarSize;
  1447. }
  1448. elPos.w = clientSize;
  1449. }
  1450. clientSize = el.clientHeight;
  1451. scrollBarSize = elPos.h - clientSize;
  1452. if(clientSize > 0 && scrollBarSize > 0){
  1453. elPos.h = clientSize;
  1454. }
  1455. }
  1456. if(fixedPos){ // bounded by viewport, not parents
  1457. if(elPos.y < 0){
  1458. elPos.h += elPos.y; elPos.y = 0;
  1459. }
  1460. if(elPos.x < 0){
  1461. elPos.w += elPos.x; elPos.x = 0;
  1462. }
  1463. if(elPos.y + elPos.h > rootHeight){
  1464. elPos.h = rootHeight - elPos.y;
  1465. }
  1466. if(elPos.x + elPos.w > rootWidth){
  1467. elPos.w = rootWidth - elPos.x;
  1468. }
  1469. }
  1470. // calculate overflow in all 4 directions
  1471. var l = nodePos.x - elPos.x, // beyond left: < 0
  1472. // t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
  1473. t = nodePos.y - elPos.y, // beyond top: < 0
  1474. r = l + nodePos.w - elPos.w, // beyond right: > 0
  1475. bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
  1476. var s, old;
  1477. if(r * l > 0 && (!!el.scrollLeft || el == scrollRoot || el.scrollWidth > el.offsetHeight)){
  1478. s = Math[l < 0? "max" : "min"](l, r);
  1479. if(rtl && ((isIE == 8 && !backCompat) || isIE >= 9)){ s = -s; }
  1480. old = el.scrollLeft;
  1481. el.scrollLeft += s;
  1482. s = el.scrollLeft - old;
  1483. nodePos.x -= s;
  1484. }
  1485. if(bot * t > 0 && (!!el.scrollTop || el == scrollRoot || el.scrollHeight > el.offsetHeight)){
  1486. s = Math.ceil(Math[t < 0? "max" : "min"](t, bot));
  1487. old = el.scrollTop;
  1488. el.scrollTop += s;
  1489. s = el.scrollTop - old;
  1490. nodePos.y -= s;
  1491. }
  1492. el = (el != scrollRoot) && !fixedPos && el.parentNode;
  1493. }
  1494. }catch(error){
  1495. console.error('scrollIntoView: ' + error);
  1496. node.scrollIntoView(false);
  1497. }
  1498. };
  1499. }
  1500. if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  1501. dojo._hasResource["dijit._base.focus"] = true;
  1502. dojo.provide("dijit._base.focus");
  1503. // summary:
  1504. // These functions are used to query or set the focus and selection.
  1505. //
  1506. // Also, they trace when widgets become activated/deactivated,
  1507. // so that the widget can fire _onFocus/_onBlur events.
  1508. // "Active" here means something similar to "focused", but
  1509. // "focus" isn't quite the right word because we keep track of
  1510. // a whole stack of "active" widgets. Example: ComboButton --> Menu -->
  1511. // MenuItem. The onBlur event for ComboButton doesn't fire due to focusing
  1512. // on the Menu or a MenuItem, since they are considered part of the
  1513. // ComboButton widget. It only happens when focus is shifted
  1514. // somewhere completely different.
  1515. dojo.mixin(dijit, {
  1516. // _curFocus: DomNode
  1517. // Currently focused item on screen
  1518. _curFocus: null,
  1519. // _prevFocus: DomNode
  1520. // Previously focused item on screen
  1521. _prevFocus: null,
  1522. isCollapsed: function(){
  1523. // summary:
  1524. // Returns true if there is no text selected
  1525. return dijit.getBookmark().isCollapsed;
  1526. },
  1527. getBookmark: function(){
  1528. // summary:
  1529. // Retrieves a bookmark that can be used with moveToBookmark to return to the same range
  1530. var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus;
  1531. if(dojo.global.getSelection){
  1532. //W3C Range API for selections.
  1533. sel = dojo.global.getSelection();
  1534. if(sel){
  1535. if(sel.isCollapsed){
  1536. tg = cf? cf.tagName : "";
  1537. if(tg){
  1538. //Create a fake rangelike item to restore selections.
  1539. tg = tg.toLowerCase();
  1540. if(tg == "textarea" ||
  1541. (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
  1542. sel = {
  1543. start: cf.selectionStart,
  1544. end: cf.selectionEnd,
  1545. node: cf,
  1546. pRange: true
  1547. };
  1548. return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
  1549. }
  1550. }
  1551. bm = {isCollapsed:true};
  1552. if(sel.rangeCount){
  1553. bm.mark = sel.getRangeAt(0).cloneRange();
  1554. }
  1555. }else{
  1556. rg = sel.getRangeAt(0);
  1557. bm = {isCollapsed: false, mark: rg.cloneRange()};
  1558. }
  1559. }
  1560. }else if(sel){
  1561. // If the current focus was a input of some sort and no selection, don't bother saving
  1562. // a native bookmark. This is because it causes issues with dialog/page selection restore.
  1563. // So, we need to create psuedo bookmarks to work with.
  1564. tg = cf ? cf.tagName : "";
  1565. tg = tg.toLowerCase();
  1566. if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
  1567. if(sel.type && sel.type.toLowerCase() == "none"){
  1568. return {
  1569. isCollapsed: true,
  1570. mark: null
  1571. }
  1572. }else{
  1573. rg = sel.createRange();
  1574. return {
  1575. isCollapsed: rg.text && rg.text.length?false:true,
  1576. mark: {
  1577. range: rg,
  1578. pRange: true
  1579. }
  1580. };
  1581. }
  1582. }
  1583. bm = {};
  1584. //'IE' way for selections.
  1585. try{
  1586. // createRange() throws exception when dojo in iframe
  1587. //and nothing selected, see #9632
  1588. rg = sel.createRange();
  1589. bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
  1590. }catch(e){
  1591. bm.isCollapsed = true;
  1592. return bm;
  1593. }
  1594. if(sel.type.toUpperCase() == 'CONTROL'){
  1595. if(rg.length){
  1596. bm.mark=[];
  1597. var i=0,len=rg.length;
  1598. while(i<len){
  1599. bm.mark.push(rg.item(i++));
  1600. }
  1601. }else{
  1602. bm.isCollapsed = true;
  1603. bm.mark = null;
  1604. }
  1605. }else{
  1606. bm.mark = rg.getBookmark();
  1607. }
  1608. }else{
  1609. console.warn("No idea how to store the current selection for this browser!");
  1610. }
  1611. return bm; // Object
  1612. },
  1613. moveToBookmark: function(/*Object*/bookmark){
  1614. // summary:
  1615. // Moves current selection to a bookmark
  1616. // bookmark:
  1617. // This should be a returned object from dijit.getBookmark()
  1618. var _doc = dojo.doc,
  1619. mark = bookmark.mark;
  1620. if(mark){
  1621. if(dojo.global.getSelection){
  1622. //W3C Rangi API (FF, WebKit, Opera, etc)
  1623. var sel = dojo.global.getSelection();
  1624. if(sel && sel.removeAllRanges){
  1625. if(mark.pRange){
  1626. var r = mark;
  1627. var n = r.node;
  1628. n.selectionStart = r.start;
  1629. n.selectionEnd = r.end;
  1630. }else{
  1631. sel.removeAllRanges();
  1632. sel.addRange(mark);
  1633. }
  1634. }else{
  1635. console.warn("No idea how to restore selection for this browser!");
  1636. }
  1637. }else if(_doc.selection && mark){
  1638. //'IE' way.
  1639. var rg;
  1640. if(mark.pRange){
  1641. rg = mark.range;
  1642. }else if(dojo.isArray(mark)){
  1643. rg = _doc.body.createControlRange();
  1644. //rg.addElement does not have call/apply method, so can not call it directly
  1645. //rg is not available in "range.addElement(item)", so can't use that either
  1646. dojo.forEach(mark, function(n){
  1647. rg.addElement(n);
  1648. });
  1649. }else{
  1650. rg = _doc.body.createTextRange();
  1651. rg.moveToBookmark(mark);
  1652. }
  1653. rg.select();
  1654. }
  1655. }
  1656. },
  1657. getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
  1658. // summary:
  1659. // Called as getFocus(), this returns an Object showing the current focus
  1660. // and selected text.
  1661. //
  1662. // Called as getFocus(widget), where widget is a (widget representing) a button
  1663. // that was just pressed, it returns where focus was before that button
  1664. // was pressed. (Pressing the button may have either shifted focus to the button,
  1665. // or removed focus altogether.) In this case the selected text is not returned,
  1666. // since it can't be accurately determined.
  1667. //
  1668. // menu: dijit._Widget or {domNode: DomNode} structure
  1669. // The button that was just pressed. If focus has disappeared or moved
  1670. // to this button, returns the previous focus. In this case the bookmark
  1671. // information is already lost, and null is returned.
  1672. //
  1673. // openedForWindow:
  1674. // iframe in which menu was opened
  1675. //
  1676. // returns:
  1677. // A handle to restore focus/selection, to be passed to `dijit.focus`
  1678. var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus;
  1679. return {
  1680. node: node,
  1681. bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark),
  1682. openedForWindow: openedForWindow
  1683. }; // Object
  1684. },
  1685. focus: function(/*Object || DomNode */ handle){
  1686. // summary:
  1687. // Sets the focused node and the selection according to argument.
  1688. // To set focus to an iframe's content, pass in the iframe itself.
  1689. // handle:
  1690. // object returned by get(), or a DomNode
  1691. if(!handle){ return; }
  1692. var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object
  1693. bookmark = handle.bookmark,
  1694. openedForWindow = handle.openedForWindow,
  1695. collapsed = bookmark ? bookmark.isCollapsed : false;
  1696. // Set the focus
  1697. // Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
  1698. // but we need to set focus to iframe.contentWindow
  1699. if(node){
  1700. var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
  1701. if(focusNode && focusNode.focus){
  1702. try{
  1703. // Gecko throws sometimes if setting focus is impossible,
  1704. // node not displayed or something like that
  1705. focusNode.focus();
  1706. }catch(e){/*quiet*/}
  1707. }
  1708. dijit._onFocusNode(node);
  1709. }
  1710. // set the selection
  1711. // do not need to restore if current selection is not empty
  1712. // (use keyboard to select a menu item) or if previous selection was collapsed
  1713. // as it may cause focus shift (Esp in IE).
  1714. if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){
  1715. if(openedForWindow){
  1716. openedForWindow.focus();
  1717. }
  1718. try{
  1719. dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]);
  1720. }catch(e2){
  1721. /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
  1722. }
  1723. }
  1724. },
  1725. // _activeStack: dijit._Widget[]
  1726. // List of currently active widgets (focused widget and it's ancestors)
  1727. _activeStack: [],
  1728. registerIframe: function(/*DomNode*/ iframe){
  1729. // summary:
  1730. // Registers listeners on the specified iframe so that any click
  1731. // or focus event on that iframe (or anything in it) is reported
  1732. // as a focus/click event on the <iframe> itself.
  1733. // description:
  1734. // Currently only used by editor.
  1735. // returns:
  1736. // Handle to pass to unregisterIframe()
  1737. return dijit.registerWin(iframe.contentWindow, iframe);
  1738. },
  1739. unregisterIframe: function(/*Object*/ handle){
  1740. // summary:
  1741. // Unregisters listeners on the specified iframe created by registerIframe.
  1742. // After calling be sure to delete or null out the handle itself.
  1743. // handle:
  1744. // Handle returned by registerIframe()
  1745. dijit.unregisterWin(handle);
  1746. },
  1747. registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
  1748. // summary:
  1749. // Registers listeners on the specified window (either the main
  1750. // window or an iframe's window) to detect when the user has clicked somewhere
  1751. // or focused somewhere.
  1752. // description:
  1753. // Users should call registerIframe() instead of this method.
  1754. // targetWindow:
  1755. // If specified this is the window associated with the iframe,
  1756. // i.e. iframe.contentWindow.
  1757. // effectiveNode:
  1758. // If specified, report any focus events inside targetWindow as
  1759. // an event on effectiveNode, rather than on evt.target.
  1760. // returns:
  1761. // Handle to pass to unregisterWin()
  1762. // TODO: make this function private in 2.0; Editor/users should call registerIframe(),
  1763. var mousedownListener = function(evt){
  1764. dijit._justMouseDowned = true;
  1765. setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
  1766. // workaround weird IE bug where the click is on an orphaned node
  1767. // (first time clicking a Select/DropDownButton inside a TooltipDialog)
  1768. if(dojo.isIE && evt && evt.srcElement && evt.srcElement.parentNode == null){
  1769. return;
  1770. }
  1771. dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
  1772. };
  1773. //dojo.connect(targetWindow, "onscroll", ???);
  1774. // Listen for blur and focus events on targetWindow's document.
  1775. // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
  1776. // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
  1777. // fire.
  1778. // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
  1779. // (at least for FF) the focus event doesn't fire on <html> or <body>.
  1780. var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
  1781. if(doc){
  1782. if(dojo.isIE){
  1783. targetWindow.document.body.attachEvent('onmousedown', mousedownListener);
  1784. var activateListener = function(evt){
  1785. // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
  1786. // Should consider those more like a mouse-click than a focus....
  1787. if(evt.srcElement.tagName.toLowerCase() != "#document" &&
  1788. dijit.isTabNavigable(evt.srcElement)){
  1789. dijit._onFocusNode(effectiveNode || evt.srcElement);
  1790. }else{
  1791. dijit._onTouchNode(effectiveNode || evt.srcElement);
  1792. }
  1793. };
  1794. doc.attachEvent('onactivate', activateListener);
  1795. var deactivateListener = function(evt){
  1796. dijit._onBlurNode(effectiveNode || evt.srcElement);
  1797. };
  1798. doc.attachEvent('ondeactivate', deactivateListener);
  1799. return function(){
  1800. targetWindow.document.detachEvent('onmousedown', mousedownListener);
  1801. doc.detachEvent('onactivate', activateListener);
  1802. doc.detachEvent('ondeactivate', deactivateListener);
  1803. doc = null; // prevent memory leak (apparent circular reference via closure)
  1804. };
  1805. }else{
  1806. doc.body.addEventListener('mousedown', mousedownListener, true);
  1807. var focusListener = function(evt){
  1808. dijit._onFocusNode(effectiveNode || evt.target);
  1809. };
  1810. doc.addEventListener('focus', focusListener, true);
  1811. var blurListener = function(evt){
  1812. dijit._onBlurNode(effectiveNode || evt.target);
  1813. };
  1814. doc.addEventListener('blur', blurListener, true);
  1815. return function(){
  1816. doc.body.removeEventListener('mousedown', mousedownListener, true);
  1817. doc.removeEventListener('focus', focusListener, true);
  1818. doc.removeEventListener('blur', blurListener, true);
  1819. doc = null; // prevent memory leak (apparent circular reference via closure)
  1820. };
  1821. }
  1822. }
  1823. },
  1824. unregisterWin: function(/*Handle*/ handle){
  1825. // summary:
  1826. // Unregisters listeners on the specified window (either the main
  1827. // window or an iframe's window) according to handle returned from registerWin().
  1828. // After calling be sure to delete or null out the handle itself.
  1829. // Currently our handle is actually a function
  1830. handle && handle();
  1831. },
  1832. _onBlurNode: function(/*DomNode*/ node){
  1833. // summary:
  1834. // Called when focus leaves a node.
  1835. // Usually ignored, _unless_ it *isn't* follwed by touching another node,
  1836. // which indicates that we tabbed off the last field on the page,
  1837. // in which case every widget is marked inactive
  1838. dijit._prevFocus = dijit._curFocus;
  1839. dijit._curFocus = null;
  1840. if(dijit._justMouseDowned){
  1841. // the mouse down caused a new widget to be marked as active; this blur event
  1842. // is coming late, so ignore it.
  1843. return;
  1844. }
  1845. // if the blur event isn't followed by a focus event then mark all widgets as inactive.
  1846. if(dijit._clearActiveWidgetsTimer){
  1847. clearTimeout(dijit._clearActiveWidgetsTimer);
  1848. }
  1849. dijit._clearActiveWidgetsTimer = setTimeout(function(){
  1850. delete dijit._clearActiveWidgetsTimer;
  1851. dijit._setStack([]);
  1852. dijit._prevFocus = null;
  1853. }, 100);
  1854. },
  1855. _onTouchNode: function(/*DomNode*/ node, /*String*/ by){
  1856. // summary:
  1857. // Callback when node is focused or mouse-downed
  1858. // node:
  1859. // The node that was touched.
  1860. // by:
  1861. // "mouse" if the focus/touch was caused by a mouse down event
  1862. // ignore the recent blurNode event
  1863. if(dijit._clearActiveWidgetsTimer){
  1864. clearTimeout(dijit._clearActiveWidgetsTimer);
  1865. delete dijit._clearActiveWidgetsTimer;
  1866. }
  1867. // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
  1868. var newStack=[];
  1869. try{
  1870. while(node){
  1871. var popupParent = dojo.attr(node, "dijitPopupParent");
  1872. if(popupParent){
  1873. node=dijit.byId(popupParent).domNode;
  1874. }else if(node.tagName && node.tagName.toLowerCase() == "body"){
  1875. // is this the root of the document or just the root of an iframe?
  1876. if(node === dojo.body()){
  1877. // node is the root of the main document
  1878. break;
  1879. }
  1880. // otherwise, find the iframe this node refers to (can't access it via parentNode,
  1881. // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
  1882. node=dojo.window.get(node.ownerDocument).frameElement;
  1883. }else{
  1884. // if this node is the root node of a widget, then add widget id to stack,
  1885. // except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
  1886. // to support MenuItem)
  1887. var id = node.getAttribute && node.getAttribute("widgetId"),
  1888. widget = id && dijit.byId(id);
  1889. if(widget && !(by == "mouse" && widget.get("disabled"))){
  1890. newStack.unshift(id);
  1891. }
  1892. node=node.parentNode;
  1893. }
  1894. }
  1895. }catch(e){ /* squelch */ }
  1896. dijit._setStack(newStack, by);
  1897. },
  1898. _onFocusNode: function(/*DomNode*/ node){
  1899. // summary:
  1900. // Callback when node is focused
  1901. if(!node){
  1902. return;
  1903. }
  1904. if(node.nodeType == 9){
  1905. // Ignore focus events on the document itself. This is here so that
  1906. // (for example) clicking the up/down arrows of a spinner
  1907. // (which don't get focus) won't cause that widget to blur. (FF issue)
  1908. return;
  1909. }
  1910. dijit._onTouchNode(node);
  1911. if(node == dijit._curFocus){ return; }
  1912. if(dijit._curFocus){
  1913. dijit._prevFocus = dijit._curFocus;
  1914. }
  1915. dijit._curFocus = node;
  1916. dojo.publish("focusNode", [node]);
  1917. },
  1918. _setStack: function(/*String[]*/ newStack, /*String*/ by){
  1919. // summary:
  1920. // The stack of active widgets has changed. Send out appropriate events and records new stack.
  1921. // newStack:
  1922. // array of widget id's, starting from the top (outermost) widget
  1923. // by:
  1924. // "mouse" if the focus/touch was caused by a mouse down event
  1925. var oldStack = dijit._activeStack;
  1926. dijit._activeStack = newStack;
  1927. // compare old stack to new stack to see how many elements they have in common
  1928. for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
  1929. if(oldStack[nCommon] != newStack[nCommon]){
  1930. break;
  1931. }
  1932. }
  1933. var widget;
  1934. // for all elements that have gone out of focus, send blur event
  1935. for(var i=oldStack.length-1; i>=nCommon; i--){
  1936. widget = dijit.byId(oldStack[i]);
  1937. if(widget){
  1938. widget._focused = false;
  1939. widget.set("focused", false);
  1940. widget._hasBeenBlurred = true;
  1941. if(widget._onBlur){
  1942. widget._onBlur(by);
  1943. }
  1944. dojo.publish("widgetBlur", [widget, by]);
  1945. }
  1946. }
  1947. // for all element that have come into focus, send focus event
  1948. for(i=nCommon; i<newStack.length; i++){
  1949. widget = dijit.byId(newStack[i]);
  1950. if(widget){
  1951. widget._focused = true;
  1952. widget.set("focused", true);
  1953. if(widget._onFocus){
  1954. widget._onFocus(by);
  1955. }
  1956. dojo.publish("widgetFocus", [widget, by]);
  1957. }
  1958. }
  1959. }
  1960. });
  1961. // register top window and all the iframes it contains
  1962. dojo.addOnLoad(function(){
  1963. var handle = dijit.registerWin(window);
  1964. if(dojo.isIE){
  1965. dojo.addOnWindowUnload(function(){
  1966. dijit.unregisterWin(handle);
  1967. handle = null;
  1968. })
  1969. }
  1970. });
  1971. }
  1972. if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  1973. dojo._hasResource["dojo.AdapterRegistry"] = true;
  1974. dojo.provide("dojo.AdapterRegistry");
  1975. dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
  1976. // summary:
  1977. // A registry to make contextual calling/searching easier.
  1978. // description:
  1979. // Objects of this class keep list of arrays in the form [name, check,
  1980. // wrap, directReturn] that are used to determine what the contextual
  1981. // result of a set of checked arguments is. All check/wrap functions
  1982. // in this registry should be of the same arity.
  1983. // example:
  1984. // | // create a new registry
  1985. // | var reg = new dojo.AdapterRegistry();
  1986. // | reg.register("handleString",
  1987. // | dojo.isString,
  1988. // | function(str){
  1989. // | // do something with the string here
  1990. // | }
  1991. // | );
  1992. // | reg.register("handleArr",
  1993. // | dojo.isArray,
  1994. // | function(arr){
  1995. // | // do something with the array here
  1996. // | }
  1997. // | );
  1998. // |
  1999. // | // now we can pass reg.match() *either* an array or a string and
  2000. // | // the value we pass will get handled by the right function
  2001. // | reg.match("someValue"); // will call the first function
  2002. // | reg.match(["someValue"]); // will call the second
  2003. this.pairs = [];
  2004. this.returnWrappers = returnWrappers || false; // Boolean
  2005. };
  2006. dojo.extend(dojo.AdapterRegistry, {
  2007. register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
  2008. // summary:
  2009. // register a check function to determine if the wrap function or
  2010. // object gets selected
  2011. // name:
  2012. // a way to identify this matcher.
  2013. // check:
  2014. // a function that arguments are passed to from the adapter's
  2015. // match() function. The check function should return true if the
  2016. // given arguments are appropriate for the wrap function.
  2017. // directReturn:
  2018. // If directReturn is true, the value passed in for wrap will be
  2019. // returned instead of being called. Alternately, the
  2020. // AdapterRegistry can be set globally to "return not call" using
  2021. // the returnWrappers property. Either way, this behavior allows
  2022. // the registry to act as a "search" function instead of a
  2023. // function interception library.
  2024. // override:
  2025. // If override is given and true, the check function will be given
  2026. // highest priority. Otherwise, it will be the lowest priority
  2027. // adapter.
  2028. this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
  2029. },
  2030. match: function(/* ... */){
  2031. // summary:
  2032. // Find an adapter for the given arguments. If no suitable adapter
  2033. // is found, throws an exception. match() accepts any number of
  2034. // arguments, all of which are passed to all matching functions
  2035. // from the registered pairs.
  2036. for(var i = 0; i < this.pairs.length; i++){
  2037. var pair = this.pairs[i];
  2038. if(pair[1].apply(this, arguments)){
  2039. if((pair[3])||(this.returnWrappers)){
  2040. return pair[2];
  2041. }else{
  2042. return pair[2].apply(this, arguments);
  2043. }
  2044. }
  2045. }
  2046. throw new Error("No match found");
  2047. },
  2048. unregister: function(name){
  2049. // summary: Remove a named adapter from the registry
  2050. // FIXME: this is kind of a dumb way to handle this. On a large
  2051. // registry this will be slow-ish and we can use the name as a lookup
  2052. // should we choose to trade memory for speed.
  2053. for(var i = 0; i < this.pairs.length; i++){
  2054. var pair = this.pairs[i];
  2055. if(pair[0] == name){
  2056. this.pairs.splice(i, 1);
  2057. return true;
  2058. }
  2059. }
  2060. return false;
  2061. }
  2062. });
  2063. }
  2064. if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2065. dojo._hasResource["dijit._base.place"] = true;
  2066. dojo.provide("dijit._base.place");
  2067. dijit.getViewport = function(){
  2068. // summary:
  2069. // Returns the dimensions and scroll position of the viewable area of a browser window
  2070. return dojo.window.getBox();
  2071. };
  2072. /*=====
  2073. dijit.__Position = function(){
  2074. // x: Integer
  2075. // horizontal coordinate in pixels, relative to document body
  2076. // y: Integer
  2077. // vertical coordinate in pixels, relative to document body
  2078. thix.x = x;
  2079. this.y = y;
  2080. }
  2081. =====*/
  2082. dijit.placeOnScreen = function(
  2083. /* DomNode */ node,
  2084. /* dijit.__Position */ pos,
  2085. /* String[] */ corners,
  2086. /* dijit.__Position? */ padding){
  2087. // summary:
  2088. // Positions one of the node's corners at specified position
  2089. // such that node is fully visible in viewport.
  2090. // description:
  2091. // NOTE: node is assumed to be absolutely or relatively positioned.
  2092. // pos:
  2093. // Object like {x: 10, y: 20}
  2094. // corners:
  2095. // Array of Strings representing order to try corners in, like ["TR", "BL"].
  2096. // Possible values are:
  2097. // * "BL" - bottom left
  2098. // * "BR" - bottom right
  2099. // * "TL" - top left
  2100. // * "TR" - top right
  2101. // padding:
  2102. // set padding to put some buffer around the element you want to position.
  2103. // example:
  2104. // Try to place node's top right corner at (10,20).
  2105. // If that makes node go (partially) off screen, then try placing
  2106. // bottom left corner at (10,20).
  2107. // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])
  2108. var choices = dojo.map(corners, function(corner){
  2109. var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
  2110. if(padding){
  2111. c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
  2112. c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
  2113. }
  2114. return c;
  2115. });
  2116. return dijit._place(node, choices);
  2117. }
  2118. dijit._place = function(/*DomNode*/ node, choices, layoutNode, /*Object*/ aroundNodeCoords){
  2119. // summary:
  2120. // Given a list of spots to put node, put it at the first spot where it fits,
  2121. // of if it doesn't fit anywhere then the place with the least overflow
  2122. // choices: Array
  2123. // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
  2124. // Above example says to put the top-left corner of the node at (10,20)
  2125. // layoutNode: Function(node, aroundNodeCorner, nodeCorner, size)
  2126. // for things like tooltip, they are displayed differently (and have different dimensions)
  2127. // based on their orientation relative to the parent. This adjusts the popup based on orientation.
  2128. // It also passes in the available size for the popup, which is useful for tooltips to
  2129. // tell them that their width is limited to a certain amount. layoutNode() may return a value expressing
  2130. // how much the popup had to be modified to fit into the available space. This is used to determine
  2131. // what the best placement is.
  2132. // aroundNodeCoords: Object
  2133. // Size of aroundNode, ex: {w: 200, h: 50}
  2134. // get {x: 10, y: 10, w: 100, h:100} type obj representing position of
  2135. // viewport over document
  2136. var view = dojo.window.getBox();
  2137. // This won't work if the node is inside a <div style="position: relative">,
  2138. // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong
  2139. // and also it might get cutoff)
  2140. if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
  2141. dojo.body().appendChild(node);
  2142. }
  2143. var best = null;
  2144. dojo.some(choices, function(choice){
  2145. var corner = choice.corner;
  2146. var pos = choice.pos;
  2147. var overflow = 0;
  2148. // calculate amount of space available given specified position of node
  2149. var spaceAvailable = {
  2150. w: corner.charAt(1) == 'L' ? (view.l + view.w) - pos.x : pos.x - view.l,
  2151. h: corner.charAt(1) == 'T' ? (view.t + view.h) - pos.y : pos.y - view.t
  2152. };
  2153. // configure node to be displayed in given position relative to button
  2154. // (need to do this in order to get an accurate size for the node, because
  2155. // a tooltip's size changes based on position, due to triangle)
  2156. if(layoutNode){
  2157. var res = layoutNode(node, choice.aroundCorner, corner, spaceAvailable, aroundNodeCoords);
  2158. overflow = typeof res == "undefined" ? 0 : res;
  2159. }
  2160. // get node's size
  2161. var style = node.style;
  2162. var oldDisplay = style.display;
  2163. var oldVis = style.visibility;
  2164. style.visibility = "hidden";
  2165. style.display = "";
  2166. var mb = dojo.marginBox(node);
  2167. style.display = oldDisplay;
  2168. style.visibility = oldVis;
  2169. // coordinates and size of node with specified corner placed at pos,
  2170. // and clipped by viewport
  2171. var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)),
  2172. startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)),
  2173. endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
  2174. endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y),
  2175. width = endX - startX,
  2176. height = endY - startY;
  2177. overflow += (mb.w - width) + (mb.h - height);
  2178. if(best == null || overflow < best.overflow){
  2179. best = {
  2180. corner: corner,
  2181. aroundCorner: choice.aroundCorner,
  2182. x: startX,
  2183. y: startY,
  2184. w: width,
  2185. h: height,
  2186. overflow: overflow,
  2187. spaceAvailable: spaceAvailable
  2188. };
  2189. }
  2190. return !overflow;
  2191. });
  2192. // In case the best position is not the last one we checked, need to call
  2193. // layoutNode() again.
  2194. if(best.overflow && layoutNode){
  2195. layoutNode(node, best.aroundCorner, best.corner, best.spaceAvailable, aroundNodeCoords);
  2196. }
  2197. // And then position the node. Do this last, after the layoutNode() above
  2198. // has sized the node, due to browser quirks when the viewport is scrolled
  2199. // (specifically that a Tooltip will shrink to fit as though the window was
  2200. // scrolled to the left).
  2201. //
  2202. // In RTL mode, set style.right rather than style.left so in the common case,
  2203. // window resizes move the popup along with the aroundNode.
  2204. var l = dojo._isBodyLtr(),
  2205. s = node.style;
  2206. s.top = best.y + "px";
  2207. s[l ? "left" : "right"] = (l ? best.x : view.w - best.x - best.w) + "px";
  2208. s[l ? "right" : "left"] = "auto"; // needed for FF or else tooltip goes to far left
  2209. return best;
  2210. }
  2211. dijit.placeOnScreenAroundNode = function(
  2212. /* DomNode */ node,
  2213. /* DomNode */ aroundNode,
  2214. /* Object */ aroundCorners,
  2215. /* Function? */ layoutNode){
  2216. // summary:
  2217. // Position node adjacent or kitty-corner to aroundNode
  2218. // such that it's fully visible in viewport.
  2219. //
  2220. // description:
  2221. // Place node such that corner of node touches a corner of
  2222. // aroundNode, and that node is fully visible.
  2223. //
  2224. // aroundCorners:
  2225. // Ordered list of pairs of corners to try matching up.
  2226. // Each pair of corners is represented as a key/value in the hash,
  2227. // where the key corresponds to the aroundNode's corner, and
  2228. // the value corresponds to the node's corner:
  2229. //
  2230. // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
  2231. //
  2232. // The following strings are used to represent the four corners:
  2233. // * "BL" - bottom left
  2234. // * "BR" - bottom right
  2235. // * "TL" - top left
  2236. // * "TR" - top right
  2237. //
  2238. // layoutNode: Function(node, aroundNodeCorner, nodeCorner)
  2239. // For things like tooltip, they are displayed differently (and have different dimensions)
  2240. // based on their orientation relative to the parent. This adjusts the popup based on orientation.
  2241. //
  2242. // example:
  2243. // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
  2244. // This will try to position node such that node's top-left corner is at the same position
  2245. // as the bottom left corner of the aroundNode (ie, put node below
  2246. // aroundNode, with left edges aligned). If that fails it will try to put
  2247. // the bottom-right corner of node where the top right corner of aroundNode is
  2248. // (ie, put node above aroundNode, with right edges aligned)
  2249. //
  2250. // get coordinates of aroundNode
  2251. aroundNode = dojo.byId(aroundNode);
  2252. var aroundNodePos = dojo.position(aroundNode, true);
  2253. // place the node around the calculated rectangle
  2254. return dijit._placeOnScreenAroundRect(node,
  2255. aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle
  2256. aroundCorners, layoutNode);
  2257. };
  2258. /*=====
  2259. dijit.__Rectangle = function(){
  2260. // x: Integer
  2261. // horizontal offset in pixels, relative to document body
  2262. // y: Integer
  2263. // vertical offset in pixels, relative to document body
  2264. // width: Integer
  2265. // width in pixels
  2266. // height: Integer
  2267. // height in pixels
  2268. this.x = x;
  2269. this.y = y;
  2270. this.width = width;
  2271. this.height = height;
  2272. }
  2273. =====*/
  2274. dijit.placeOnScreenAroundRectangle = function(
  2275. /* DomNode */ node,
  2276. /* dijit.__Rectangle */ aroundRect,
  2277. /* Object */ aroundCorners,
  2278. /* Function */ layoutNode){
  2279. // summary:
  2280. // Like dijit.placeOnScreenAroundNode(), except that the "around"
  2281. // parameter is an arbitrary rectangle on the screen (x, y, width, height)
  2282. // instead of a dom node.
  2283. return dijit._placeOnScreenAroundRect(node,
  2284. aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle
  2285. aroundCorners, layoutNode);
  2286. };
  2287. dijit._placeOnScreenAroundRect = function(
  2288. /* DomNode */ node,
  2289. /* Number */ x,
  2290. /* Number */ y,
  2291. /* Number */ width,
  2292. /* Number */ height,
  2293. /* Object */ aroundCorners,
  2294. /* Function */ layoutNode){
  2295. // summary:
  2296. // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
  2297. // of a rectangle to place node adjacent to.
  2298. // TODO: combine with placeOnScreenAroundRectangle()
  2299. // Generate list of possible positions for node
  2300. var choices = [];
  2301. for(var nodeCorner in aroundCorners){
  2302. choices.push( {
  2303. aroundCorner: nodeCorner,
  2304. corner: aroundCorners[nodeCorner],
  2305. pos: {
  2306. x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
  2307. y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
  2308. }
  2309. });
  2310. }
  2311. return dijit._place(node, choices, layoutNode, {w: width, h: height});
  2312. };
  2313. dijit.placementRegistry= new dojo.AdapterRegistry();
  2314. dijit.placementRegistry.register("node",
  2315. function(n, x){
  2316. return typeof x == "object" &&
  2317. typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
  2318. },
  2319. dijit.placeOnScreenAroundNode);
  2320. dijit.placementRegistry.register("rect",
  2321. function(n, x){
  2322. return typeof x == "object" &&
  2323. "x" in x && "y" in x && "width" in x && "height" in x;
  2324. },
  2325. dijit.placeOnScreenAroundRectangle);
  2326. dijit.placeOnScreenAroundElement = function(
  2327. /* DomNode */ node,
  2328. /* Object */ aroundElement,
  2329. /* Object */ aroundCorners,
  2330. /* Function */ layoutNode){
  2331. // summary:
  2332. // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
  2333. // for the "around" argument and finds a proper processor to place a node.
  2334. return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
  2335. };
  2336. dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
  2337. // summary:
  2338. // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
  2339. //
  2340. // position: String[]
  2341. // This variable controls the position of the drop down.
  2342. // It's an array of strings with the following values:
  2343. //
  2344. // * before: places drop down to the left of the target node/widget, or to the right in
  2345. // the case of RTL scripts like Hebrew and Arabic
  2346. // * after: places drop down to the right of the target node/widget, or to the left in
  2347. // the case of RTL scripts like Hebrew and Arabic
  2348. // * above: drop down goes above target node
  2349. // * below: drop down goes below target node
  2350. //
  2351. // The list is positions is tried, in order, until a position is found where the drop down fits
  2352. // within the viewport.
  2353. //
  2354. // leftToRight: Boolean
  2355. // Whether the popup will be displaying in leftToRight mode.
  2356. //
  2357. var align = {};
  2358. dojo.forEach(position, function(pos){
  2359. switch(pos){
  2360. case "after":
  2361. align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
  2362. break;
  2363. case "before":
  2364. align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
  2365. break;
  2366. case "below-alt":
  2367. leftToRight = !leftToRight;
  2368. // fall through
  2369. case "below":
  2370. // first try to align left borders, next try to align right borders (or reverse for RTL mode)
  2371. align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
  2372. align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
  2373. break;
  2374. case "above-alt":
  2375. leftToRight = !leftToRight;
  2376. // fall through
  2377. case "above":
  2378. default:
  2379. // first try to align left borders, next try to align right borders (or reverse for RTL mode)
  2380. align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR";
  2381. align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL";
  2382. break;
  2383. }
  2384. });
  2385. return align;
  2386. };
  2387. }
  2388. if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2389. dojo._hasResource["dijit._base.window"] = true;
  2390. dojo.provide("dijit._base.window");
  2391. dijit.getDocumentWindow = function(doc){
  2392. return dojo.window.get(doc);
  2393. };
  2394. }
  2395. if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2396. dojo._hasResource["dijit._base.popup"] = true;
  2397. dojo.provide("dijit._base.popup");
  2398. /*=====
  2399. dijit.popup.__OpenArgs = function(){
  2400. // popup: Widget
  2401. // widget to display
  2402. // parent: Widget
  2403. // the button etc. that is displaying this popup
  2404. // around: DomNode
  2405. // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.)
  2406. // x: Integer
  2407. // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.)
  2408. // y: Integer
  2409. // Absolute vertical position (in pixels) to place node at. (Specify this *or* "around" parameter.)
  2410. // orient: Object|String
  2411. // When the around parameter is specified, orient should be an
  2412. // ordered list of tuples of the form (around-node-corner, popup-node-corner).
  2413. // dijit.popup.open() tries to position the popup according to each tuple in the list, in order,
  2414. // until the popup appears fully within the viewport.
  2415. //
  2416. // The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples:
  2417. // 1. (BL, TL)
  2418. // 2. (TL, BL)
  2419. // where BL means "bottom left" and "TL" means "top left".
  2420. // So by default, it first tries putting the popup below the around node, left-aligning them,
  2421. // and then tries to put it above the around node, still left-aligning them. Note that the
  2422. // default is horizontally reversed when in RTL mode.
  2423. //
  2424. // When an (x,y) position is specified rather than an around node, orient is either
  2425. // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse,
  2426. // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
  2427. // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
  2428. // and the top-right corner.
  2429. // onCancel: Function
  2430. // callback when user has canceled the popup by
  2431. // 1. hitting ESC or
  2432. // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
  2433. // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called
  2434. // onClose: Function
  2435. // callback whenever this popup is closed
  2436. // onExecute: Function
  2437. // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
  2438. // padding: dijit.__Position
  2439. // adding a buffer around the opening position. This is only useful when around is not set.
  2440. this.popup = popup;
  2441. this.parent = parent;
  2442. this.around = around;
  2443. this.x = x;
  2444. this.y = y;
  2445. this.orient = orient;
  2446. this.onCancel = onCancel;
  2447. this.onClose = onClose;
  2448. this.onExecute = onExecute;
  2449. this.padding = padding;
  2450. }
  2451. =====*/
  2452. dijit.popup = {
  2453. // summary:
  2454. // This singleton is used to show/hide widgets as popups.
  2455. // _stack: dijit._Widget[]
  2456. // Stack of currently popped up widgets.
  2457. // (someone opened _stack[0], and then it opened _stack[1], etc.)
  2458. _stack: [],
  2459. // _beginZIndex: Number
  2460. // Z-index of the first popup. (If first popup opens other
  2461. // popups they get a higher z-index.)
  2462. _beginZIndex: 1000,
  2463. _idGen: 1,
  2464. _createWrapper: function(/*Widget || DomNode*/ widget){
  2465. // summary:
  2466. // Initialization for widgets that will be used as popups.
  2467. // Puts widget inside a wrapper DIV (if not already in one),
  2468. // and returns pointer to that wrapper DIV.
  2469. var node = widget.domNode || widget,
  2470. wrapper = widget.declaredClass ? widget._popupWrapper :
  2471. node.parentNode && dojo.hasClass(node.parentNode, "dijitPopup") ? node.parentNode : null;
  2472. if(!wrapper){
  2473. // Create wrapper <div> for when this widget [in the future] will be used as a popup.
  2474. // This is done early because of IE bugs where creating/moving DOM nodes causes focus
  2475. // to go wonky, see tests/robot/Toolbar.html to reproduce
  2476. wrapper = dojo.create("div",{
  2477. "class":"dijitPopup",
  2478. style:{ display: "none"},
  2479. role: "presentation"
  2480. }, dojo.body());
  2481. wrapper.appendChild(node);
  2482. var s = node.style;
  2483. s.display = "";
  2484. s.visibility = "";
  2485. s.position = "";
  2486. s.top = "0px";
  2487. if(widget.declaredClass){ // TODO: in 2.0 change signature to always take widget, then remove if()
  2488. widget._popupWrapper = wrapper;
  2489. dojo.connect(widget, "destroy", function(){
  2490. dojo.destroy(wrapper);
  2491. delete widget._popupWrapper;
  2492. });
  2493. }
  2494. }
  2495. return wrapper; // DOMNode
  2496. },
  2497. moveOffScreen: function(/*Widget || DomNode*/ widget){
  2498. // summary:
  2499. // Moves the popup widget off-screen.
  2500. // Do not use this method to hide popups when not in use, because
  2501. // that will create an accessibility issue: the offscreen popup is
  2502. // still in the tabbing order.
  2503. // Create wrapper if not already there
  2504. var wrapper = this._createWrapper(widget);
  2505. dojo.style(wrapper, {
  2506. visibility: "hidden",
  2507. top: "-9999px", // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
  2508. display: ""
  2509. });
  2510. },
  2511. hide: function(/*dijit._Widget*/ widget){
  2512. // summary:
  2513. // Hide this popup widget (until it is ready to be shown).
  2514. // Initialization for widgets that will be used as popups
  2515. //
  2516. // Also puts widget inside a wrapper DIV (if not already in one)
  2517. //
  2518. // If popup widget needs to layout it should
  2519. // do so when it is made visible, and popup._onShow() is called.
  2520. // Create wrapper if not already there
  2521. var wrapper = this._createWrapper(widget);
  2522. dojo.style(wrapper, "display", "none");
  2523. },
  2524. getTopPopup: function(){
  2525. // summary:
  2526. // Compute the closest ancestor popup that's *not* a child of another popup.
  2527. // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
  2528. var stack = this._stack;
  2529. for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
  2530. /* do nothing, just trying to get right value for pi */
  2531. }
  2532. return stack[pi];
  2533. },
  2534. open: function(/*dijit.popup.__OpenArgs*/ args){
  2535. // summary:
  2536. // Popup the widget at the specified position
  2537. //
  2538. // example:
  2539. // opening at the mouse position
  2540. // | dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
  2541. //
  2542. // example:
  2543. // opening the widget as a dropdown
  2544. // | dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
  2545. //
  2546. // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
  2547. // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.
  2548. var stack = this._stack,
  2549. widget = args.popup,
  2550. orient = args.orient || (
  2551. (args.parent ? args.parent.isLeftToRight() : dojo._isBodyLtr()) ?
  2552. {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} :
  2553. {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'}
  2554. ),
  2555. around = args.around,
  2556. id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);
  2557. // If we are opening a new popup that isn't a child of a currently opened popup, then
  2558. // close currently opened popup(s). This should happen automatically when the old popups
  2559. // gets the _onBlur() event, except that the _onBlur() event isn't reliable on IE, see [22198].
  2560. while(stack.length && (!args.parent || !dojo.isDescendant(args.parent.domNode, stack[stack.length-1].widget.domNode))){
  2561. dijit.popup.close(stack[stack.length-1].widget);
  2562. }
  2563. // Get pointer to popup wrapper, and create wrapper if it doesn't exist
  2564. var wrapper = this._createWrapper(widget);
  2565. dojo.attr(wrapper, {
  2566. id: id,
  2567. style: {
  2568. zIndex: this._beginZIndex + stack.length
  2569. },
  2570. "class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
  2571. dijitPopupParent: args.parent ? args.parent.id : ""
  2572. });
  2573. if(dojo.isIE || dojo.isMoz){
  2574. if(!widget.bgIframe){
  2575. // setting widget.bgIframe triggers cleanup in _Widget.destroy()
  2576. widget.bgIframe = new dijit.BackgroundIframe(wrapper);
  2577. }
  2578. }
  2579. // position the wrapper node and make it visible
  2580. var best = around ?
  2581. dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
  2582. dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);
  2583. wrapper.style.display = "";
  2584. wrapper.style.visibility = "visible";
  2585. widget.domNode.style.visibility = "visible"; // counteract effects from _HasDropDown
  2586. var handlers = [];
  2587. // provide default escape and tab key handling
  2588. // (this will work for any widget, not just menu)
  2589. handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
  2590. if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){
  2591. dojo.stopEvent(evt);
  2592. args.onCancel();
  2593. }else if(evt.charOrCode === dojo.keys.TAB){
  2594. dojo.stopEvent(evt);
  2595. var topPopup = this.getTopPopup();
  2596. if(topPopup && topPopup.onCancel){
  2597. topPopup.onCancel();
  2598. }
  2599. }
  2600. }));
  2601. // watch for cancel/execute events on the popup and notify the caller
  2602. // (for a menu, "execute" means clicking an item)
  2603. if(widget.onCancel){
  2604. handlers.push(dojo.connect(widget, "onCancel", args.onCancel));
  2605. }
  2606. handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", this, function(){
  2607. var topPopup = this.getTopPopup();
  2608. if(topPopup && topPopup.onExecute){
  2609. topPopup.onExecute();
  2610. }
  2611. }));
  2612. stack.push({
  2613. widget: widget,
  2614. parent: args.parent,
  2615. onExecute: args.onExecute,
  2616. onCancel: args.onCancel,
  2617. onClose: args.onClose,
  2618. handlers: handlers
  2619. });
  2620. if(widget.onOpen){
  2621. // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
  2622. widget.onOpen(best);
  2623. }
  2624. return best;
  2625. },
  2626. close: function(/*dijit._Widget?*/ popup){
  2627. // summary:
  2628. // Close specified popup and any popups that it parented.
  2629. // If no popup is specified, closes all popups.
  2630. var stack = this._stack;
  2631. // Basically work backwards from the top of the stack closing popups
  2632. // until we hit the specified popup, but IIRC there was some issue where closing
  2633. // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C]
  2634. // closing C might close B indirectly and then the while() condition will run where stack==[A]...
  2635. // so the while condition is constructed defensively.
  2636. while((popup && dojo.some(stack, function(elem){return elem.widget == popup;})) ||
  2637. (!popup && stack.length)){
  2638. var top = stack.pop(),
  2639. widget = top.widget,
  2640. onClose = top.onClose;
  2641. if(widget.onClose){
  2642. // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
  2643. widget.onClose();
  2644. }
  2645. dojo.forEach(top.handlers, dojo.disconnect);
  2646. // Hide the widget and it's wrapper unless it has already been destroyed in above onClose() etc.
  2647. if(widget && widget.domNode){
  2648. this.hide(widget);
  2649. }
  2650. if(onClose){
  2651. onClose();
  2652. }
  2653. }
  2654. }
  2655. };
  2656. // TODO: remove dijit._frames, it isn't being used much, since popups never release their
  2657. // iframes (see [22236])
  2658. dijit._frames = new function(){
  2659. // summary:
  2660. // cache of iframes
  2661. var queue = [];
  2662. this.pop = function(){
  2663. var iframe;
  2664. if(queue.length){
  2665. iframe = queue.pop();
  2666. iframe.style.display="";
  2667. }else{
  2668. if(dojo.isIE < 9){
  2669. var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
  2670. var html="<iframe src='" + burl + "'"
  2671. + " style='position: absolute; left: 0px; top: 0px;"
  2672. + "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
  2673. iframe = dojo.doc.createElement(html);
  2674. }else{
  2675. iframe = dojo.create("iframe");
  2676. iframe.src = 'javascript:""';
  2677. iframe.className = "dijitBackgroundIframe";
  2678. dojo.style(iframe, "opacity", 0.1);
  2679. }
  2680. iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didn't work.
  2681. dijit.setWaiRole(iframe,"presentation");
  2682. }
  2683. return iframe;
  2684. };
  2685. this.push = function(iframe){
  2686. iframe.style.display="none";
  2687. queue.push(iframe);
  2688. }
  2689. }();
  2690. dijit.BackgroundIframe = function(/*DomNode*/ node){
  2691. // summary:
  2692. // For IE/FF z-index schenanigans. id attribute is required.
  2693. //
  2694. // description:
  2695. // new dijit.BackgroundIframe(node)
  2696. // Makes a background iframe as a child of node, that fills
  2697. // area (and position) of node
  2698. if(!node.id){ throw new Error("no id"); }
  2699. if(dojo.isIE || dojo.isMoz){
  2700. var iframe = (this.iframe = dijit._frames.pop());
  2701. node.appendChild(iframe);
  2702. if(dojo.isIE<7 || dojo.isQuirks){
  2703. this.resize(node);
  2704. this._conn = dojo.connect(node, 'onresize', this, function(){
  2705. this.resize(node);
  2706. });
  2707. }else{
  2708. dojo.style(iframe, {
  2709. width: '100%',
  2710. height: '100%'
  2711. });
  2712. }
  2713. }
  2714. };
  2715. dojo.extend(dijit.BackgroundIframe, {
  2716. resize: function(node){
  2717. // summary:
  2718. // Resize the iframe so it's the same size as node.
  2719. // Needed on IE6 and IE/quirks because height:100% doesn't work right.
  2720. if(this.iframe){
  2721. dojo.style(this.iframe, {
  2722. width: node.offsetWidth + 'px',
  2723. height: node.offsetHeight + 'px'
  2724. });
  2725. }
  2726. },
  2727. destroy: function(){
  2728. // summary:
  2729. // destroy the iframe
  2730. if(this._conn){
  2731. dojo.disconnect(this._conn);
  2732. this._conn = null;
  2733. }
  2734. if(this.iframe){
  2735. dijit._frames.push(this.iframe);
  2736. delete this.iframe;
  2737. }
  2738. }
  2739. });
  2740. }
  2741. if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2742. dojo._hasResource["dijit._base.scroll"] = true;
  2743. dojo.provide("dijit._base.scroll");
  2744. dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
  2745. // summary:
  2746. // Scroll the passed node into view, if it is not already.
  2747. // Deprecated, use `dojo.window.scrollIntoView` instead.
  2748. dojo.window.scrollIntoView(node, pos);
  2749. };
  2750. }
  2751. if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2752. dojo._hasResource["dojo.uacss"] = true;
  2753. dojo.provide("dojo.uacss");
  2754. (function(){
  2755. // summary:
  2756. // Applies pre-set CSS classes to the top-level HTML node, based on:
  2757. // - browser (ex: dj_ie)
  2758. // - browser version (ex: dj_ie6)
  2759. // - box model (ex: dj_contentBox)
  2760. // - text direction (ex: dijitRtl)
  2761. //
  2762. // In addition, browser, browser version, and box model are
  2763. // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl.
  2764. var d = dojo,
  2765. html = d.doc.documentElement,
  2766. ie = d.isIE,
  2767. opera = d.isOpera,
  2768. maj = Math.floor,
  2769. ff = d.isFF,
  2770. boxModel = d.boxModel.replace(/-/,''),
  2771. classes = {
  2772. dj_quirks: d.isQuirks,
  2773. // NOTE: Opera not supported by dijit
  2774. dj_opera: opera,
  2775. dj_khtml: d.isKhtml,
  2776. dj_webkit: d.isWebKit,
  2777. dj_safari: d.isSafari,
  2778. dj_chrome: d.isChrome,
  2779. dj_gecko: d.isMozilla
  2780. }; // no dojo unsupported browsers
  2781. if(ie){
  2782. classes["dj_ie"] = true;
  2783. classes["dj_ie" + maj(ie)] = true;
  2784. classes["dj_iequirks"] = d.isQuirks;
  2785. }
  2786. if(ff){
  2787. classes["dj_ff" + maj(ff)] = true;
  2788. }
  2789. classes["dj_" + boxModel] = true;
  2790. // apply browser, browser version, and box model class names
  2791. var classStr = "";
  2792. for(var clz in classes){
  2793. if(classes[clz]){
  2794. classStr += clz + " ";
  2795. }
  2796. }
  2797. html.className = d.trim(html.className + " " + classStr);
  2798. // If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
  2799. // We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).
  2800. // Unshift() is to run sniff code before the parser.
  2801. dojo._loaders.unshift(function(){
  2802. if(!dojo._isBodyLtr()){
  2803. var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
  2804. html.className = d.trim(html.className + " " + rtlClassStr);
  2805. }
  2806. });
  2807. })();
  2808. }
  2809. if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2810. dojo._hasResource["dijit._base.sniff"] = true;
  2811. dojo.provide("dijit._base.sniff");
  2812. // summary:
  2813. // Applies pre-set CSS classes to the top-level HTML node, see
  2814. // `dojo.uacss` for details.
  2815. //
  2816. // Simply doing a require on this module will
  2817. // establish this CSS. Modified version of Morris' CSS hack.
  2818. }
  2819. if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2820. dojo._hasResource["dijit._base.typematic"] = true;
  2821. dojo.provide("dijit._base.typematic");
  2822. dijit.typematic = {
  2823. // summary:
  2824. // These functions are used to repetitively call a user specified callback
  2825. // method when a specific key or mouse click over a specific DOM node is
  2826. // held down for a specific amount of time.
  2827. // Only 1 such event is allowed to occur on the browser page at 1 time.
  2828. _fireEventAndReload: function(){
  2829. this._timer = null;
  2830. this._callback(++this._count, this._node, this._evt);
  2831. // Schedule next event, timer is at most minDelay (default 10ms) to avoid
  2832. // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
  2833. this._currentTimeout = Math.max(
  2834. this._currentTimeout < 0 ? this._initialDelay :
  2835. (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
  2836. this._minDelay);
  2837. this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
  2838. },
  2839. trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  2840. // summary:
  2841. // Start a timed, repeating callback sequence.
  2842. // If already started, the function call is ignored.
  2843. // This method is not normally called by the user but can be
  2844. // when the normal listener code is insufficient.
  2845. // evt:
  2846. // key or mouse event object to pass to the user callback
  2847. // _this:
  2848. // pointer to the user's widget space.
  2849. // node:
  2850. // the DOM node object to pass the the callback function
  2851. // callback:
  2852. // function to call until the sequence is stopped called with 3 parameters:
  2853. // count:
  2854. // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
  2855. // node:
  2856. // the DOM node object passed in
  2857. // evt:
  2858. // key or mouse event object
  2859. // obj:
  2860. // user space object used to uniquely identify each typematic sequence
  2861. // subsequentDelay (optional):
  2862. // if > 1, the number of milliseconds until the 3->n events occur
  2863. // or else the fractional time multiplier for the next event's delay, default=0.9
  2864. // initialDelay (optional):
  2865. // the number of milliseconds until the 2nd event occurs, default=500ms
  2866. // minDelay (optional):
  2867. // the maximum delay in milliseconds for event to fire, default=10ms
  2868. if(obj != this._obj){
  2869. this.stop();
  2870. this._initialDelay = initialDelay || 500;
  2871. this._subsequentDelay = subsequentDelay || 0.90;
  2872. this._minDelay = minDelay || 10;
  2873. this._obj = obj;
  2874. this._evt = evt;
  2875. this._node = node;
  2876. this._currentTimeout = -1;
  2877. this._count = -1;
  2878. this._callback = dojo.hitch(_this, callback);
  2879. this._fireEventAndReload();
  2880. this._evt = dojo.mixin({faux: true}, evt);
  2881. }
  2882. },
  2883. stop: function(){
  2884. // summary:
  2885. // Stop an ongoing timed, repeating callback sequence.
  2886. if(this._timer){
  2887. clearTimeout(this._timer);
  2888. this._timer = null;
  2889. }
  2890. if(this._obj){
  2891. this._callback(-1, this._node, this._evt);
  2892. this._obj = null;
  2893. }
  2894. },
  2895. addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  2896. // summary:
  2897. // Start listening for a specific typematic key.
  2898. // See also the trigger method for other parameters.
  2899. // keyObject:
  2900. // an object defining the key to listen for:
  2901. // charOrCode:
  2902. // the printable character (string) or keyCode (number) to listen for.
  2903. // keyCode:
  2904. // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
  2905. // charCode:
  2906. // (deprecated - use charOrCode) the charCode (number) to listen for.
  2907. // ctrlKey:
  2908. // desired ctrl key state to initiate the callback sequence:
  2909. // - pressed (true)
  2910. // - released (false)
  2911. // - either (unspecified)
  2912. // altKey:
  2913. // same as ctrlKey but for the alt key
  2914. // shiftKey:
  2915. // same as ctrlKey but for the shift key
  2916. // returns:
  2917. // an array of dojo.connect handles
  2918. if(keyObject.keyCode){
  2919. keyObject.charOrCode = keyObject.keyCode;
  2920. dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  2921. }else if(keyObject.charCode){
  2922. keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
  2923. dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
  2924. }
  2925. return [
  2926. dojo.connect(node, "onkeypress", this, function(evt){
  2927. if(evt.charOrCode == keyObject.charOrCode &&
  2928. (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
  2929. (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
  2930. (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
  2931. (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
  2932. dojo.stopEvent(evt);
  2933. dijit.typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
  2934. }else if(dijit.typematic._obj == keyObject){
  2935. dijit.typematic.stop();
  2936. }
  2937. }),
  2938. dojo.connect(node, "onkeyup", this, function(evt){
  2939. if(dijit.typematic._obj == keyObject){
  2940. dijit.typematic.stop();
  2941. }
  2942. })
  2943. ];
  2944. },
  2945. addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  2946. // summary:
  2947. // Start listening for a typematic mouse click.
  2948. // See the trigger method for other parameters.
  2949. // returns:
  2950. // an array of dojo.connect handles
  2951. var dc = dojo.connect;
  2952. return [
  2953. dc(node, "mousedown", this, function(evt){
  2954. dojo.stopEvent(evt);
  2955. dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  2956. }),
  2957. dc(node, "mouseup", this, function(evt){
  2958. dojo.stopEvent(evt);
  2959. dijit.typematic.stop();
  2960. }),
  2961. dc(node, "mouseout", this, function(evt){
  2962. dojo.stopEvent(evt);
  2963. dijit.typematic.stop();
  2964. }),
  2965. dc(node, "mousemove", this, function(evt){
  2966. evt.preventDefault();
  2967. }),
  2968. dc(node, "dblclick", this, function(evt){
  2969. dojo.stopEvent(evt);
  2970. if(dojo.isIE < 9){
  2971. dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
  2972. setTimeout(dojo.hitch(this, dijit.typematic.stop), 50);
  2973. }
  2974. })
  2975. ];
  2976. },
  2977. addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
  2978. // summary:
  2979. // Start listening for a specific typematic key and mouseclick.
  2980. // This is a thin wrapper to addKeyListener and addMouseListener.
  2981. // See the addMouseListener and addKeyListener methods for other parameters.
  2982. // mouseNode:
  2983. // the DOM node object to listen on for mouse events.
  2984. // keyNode:
  2985. // the DOM node object to listen on for key events.
  2986. // returns:
  2987. // an array of dojo.connect handles
  2988. return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay).concat(
  2989. this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay));
  2990. }
  2991. };
  2992. }
  2993. if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  2994. dojo._hasResource["dijit._base.wai"] = true;
  2995. dojo.provide("dijit._base.wai");
  2996. dijit.wai = {
  2997. onload: function(){
  2998. // summary:
  2999. // Detects if we are in high-contrast mode or not
  3000. // This must be a named function and not an anonymous
  3001. // function, so that the widget parsing code can make sure it
  3002. // registers its onload function after this function.
  3003. // DO NOT USE "this" within this function.
  3004. // create div for testing if high contrast mode is on or images are turned off
  3005. var div = dojo.create("div",{
  3006. id: "a11yTestNode",
  3007. style:{
  3008. cssText:'border: 1px solid;'
  3009. + 'border-color:red green;'
  3010. + 'position: absolute;'
  3011. + 'height: 5px;'
  3012. + 'top: -999px;'
  3013. + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");'
  3014. }
  3015. }, dojo.body());
  3016. // test it
  3017. var cs = dojo.getComputedStyle(div);
  3018. if(cs){
  3019. var bkImg = cs.backgroundImage;
  3020. var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
  3021. dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
  3022. if(dojo.isIE){
  3023. div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014
  3024. }else{
  3025. dojo.body().removeChild(div);
  3026. }
  3027. }
  3028. }
  3029. };
  3030. // Test if computer is in high contrast mode.
  3031. // Make sure the a11y test runs first, before widgets are instantiated.
  3032. if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up
  3033. dojo._loaders.unshift(dijit.wai.onload);
  3034. }
  3035. dojo.mixin(dijit, {
  3036. hasWaiRole: function(/*Element*/ elem, /*String?*/ role){
  3037. // summary:
  3038. // Determines if an element has a particular role.
  3039. // returns:
  3040. // True if elem has the specific role attribute and false if not.
  3041. // For backwards compatibility if role parameter not provided,
  3042. // returns true if has a role
  3043. var waiRole = this.getWaiRole(elem);
  3044. return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
  3045. },
  3046. getWaiRole: function(/*Element*/ elem){
  3047. // summary:
  3048. // Gets the role for an element (which should be a wai role).
  3049. // returns:
  3050. // The role of elem or an empty string if elem
  3051. // does not have a role.
  3052. return dojo.trim((dojo.attr(elem, "role") || "").replace("wairole:",""));
  3053. },
  3054. setWaiRole: function(/*Element*/ elem, /*String*/ role){
  3055. // summary:
  3056. // Sets the role on an element.
  3057. // description:
  3058. // Replace existing role attribute with new role.
  3059. dojo.attr(elem, "role", role);
  3060. },
  3061. removeWaiRole: function(/*Element*/ elem, /*String*/ role){
  3062. // summary:
  3063. // Removes the specified role from an element.
  3064. // Removes role attribute if no specific role provided (for backwards compat.)
  3065. var roleValue = dojo.attr(elem, "role");
  3066. if(!roleValue){ return; }
  3067. if(role){
  3068. var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " "));
  3069. dojo.attr(elem, "role", t);
  3070. }else{
  3071. elem.removeAttribute("role");
  3072. }
  3073. },
  3074. hasWaiState: function(/*Element*/ elem, /*String*/ state){
  3075. // summary:
  3076. // Determines if an element has a given state.
  3077. // description:
  3078. // Checks for an attribute called "aria-"+state.
  3079. // returns:
  3080. // true if elem has a value for the given state and
  3081. // false if it does not.
  3082. return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state);
  3083. },
  3084. getWaiState: function(/*Element*/ elem, /*String*/ state){
  3085. // summary:
  3086. // Gets the value of a state on an element.
  3087. // description:
  3088. // Checks for an attribute called "aria-"+state.
  3089. // returns:
  3090. // The value of the requested state on elem
  3091. // or an empty string if elem has no value for state.
  3092. return elem.getAttribute("aria-"+state) || "";
  3093. },
  3094. setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
  3095. // summary:
  3096. // Sets a state on an element.
  3097. // description:
  3098. // Sets an attribute called "aria-"+state.
  3099. elem.setAttribute("aria-"+state, value);
  3100. },
  3101. removeWaiState: function(/*Element*/ elem, /*String*/ state){
  3102. // summary:
  3103. // Removes a state from an element.
  3104. // description:
  3105. // Sets an attribute called "aria-"+state.
  3106. elem.removeAttribute("aria-"+state);
  3107. }
  3108. });
  3109. }
  3110. if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  3111. dojo._hasResource["dijit._base"] = true;
  3112. dojo.provide("dijit._base");
  3113. }
  3114. if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  3115. dojo._hasResource["dijit._Widget"] = true;
  3116. dojo.provide("dijit._Widget");
  3117. ////////////////// DEFERRED CONNECTS ///////////////////
  3118. // This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
  3119. // DOM nodes) until someone actually needs to monitor that event.
  3120. dojo.connect(dojo, "_connect",
  3121. function(/*dijit._Widget*/ widget, /*String*/ event){
  3122. if(widget && dojo.isFunction(widget._onConnect)){
  3123. widget._onConnect(event);
  3124. }
  3125. });
  3126. dijit._connectOnUseEventHandler = function(/*Event*/ event){};
  3127. ////////////////// ONDIJITCLICK SUPPORT ///////////////////
  3128. // Keep track of where the last keydown event was, to help avoid generating
  3129. // spurious ondijitclick events when:
  3130. // 1. focus is on a <button> or <a>
  3131. // 2. user presses then releases the ENTER key
  3132. // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
  3133. // 4. onkeyup event fires, causing the ondijitclick handler to fire
  3134. dijit._lastKeyDownNode = null;
  3135. if(dojo.isIE){
  3136. (function(){
  3137. var keydownCallback = function(evt){
  3138. dijit._lastKeyDownNode = evt.srcElement;
  3139. };
  3140. dojo.doc.attachEvent('onkeydown', keydownCallback);
  3141. dojo.addOnWindowUnload(function(){
  3142. dojo.doc.detachEvent('onkeydown', keydownCallback);
  3143. });
  3144. })();
  3145. }else{
  3146. dojo.doc.addEventListener('keydown', function(evt){
  3147. dijit._lastKeyDownNode = evt.target;
  3148. }, true);
  3149. }
  3150. (function(){
  3151. dojo.declare("dijit._Widget", dijit._WidgetBase, {
  3152. // summary:
  3153. // Base class for all Dijit widgets.
  3154. //
  3155. // Extends _WidgetBase, adding support for:
  3156. // - deferred connections
  3157. // A call like dojo.connect(myWidget, "onMouseMove", func)
  3158. // will essentially do a dojo.connect(myWidget.domNode, "onMouseMove", func)
  3159. // - ondijitclick
  3160. // Support new dojoAttachEvent="ondijitclick: ..." that is triggered by a mouse click or a SPACE/ENTER keypress
  3161. // - focus related functions
  3162. // In particular, the onFocus()/onBlur() callbacks. Driven internally by
  3163. // dijit/_base/focus.js.
  3164. // - deprecated methods
  3165. // - onShow(), onHide(), onClose()
  3166. //
  3167. // Also, by loading code in dijit/_base, turns on:
  3168. // - browser sniffing (putting browser id like .dj_ie on <html> node)
  3169. // - high contrast mode sniffing (add .dijit_a11y class to <body> if machine is in high contrast mode)
  3170. ////////////////// DEFERRED CONNECTS ///////////////////
  3171. // _deferredConnects: [protected] Object
  3172. // attributeMap addendum for event handlers that should be connected only on first use
  3173. _deferredConnects: {
  3174. onClick: "",
  3175. onDblClick: "",
  3176. onKeyDown: "",
  3177. onKeyPress: "",
  3178. onKeyUp: "",
  3179. onMouseMove: "",
  3180. onMouseDown: "",
  3181. onMouseOut: "",
  3182. onMouseOver: "",
  3183. onMouseLeave: "",
  3184. onMouseEnter: "",
  3185. onMouseUp: ""
  3186. },
  3187. onClick: dijit._connectOnUseEventHandler,
  3188. /*=====
  3189. onClick: function(event){
  3190. // summary:
  3191. // Connect to this function to receive notifications of mouse click events.
  3192. // event:
  3193. // mouse Event
  3194. // tags:
  3195. // callback
  3196. },
  3197. =====*/
  3198. onDblClick: dijit._connectOnUseEventHandler,
  3199. /*=====
  3200. onDblClick: function(event){
  3201. // summary:
  3202. // Connect to this function to receive notifications of mouse double click events.
  3203. // event:
  3204. // mouse Event
  3205. // tags:
  3206. // callback
  3207. },
  3208. =====*/
  3209. onKeyDown: dijit._connectOnUseEventHandler,
  3210. /*=====
  3211. onKeyDown: function(event){
  3212. // summary:
  3213. // Connect to this function to receive notifications of keys being pressed down.
  3214. // event:
  3215. // key Event
  3216. // tags:
  3217. // callback
  3218. },
  3219. =====*/
  3220. onKeyPress: dijit._connectOnUseEventHandler,
  3221. /*=====
  3222. onKeyPress: function(event){
  3223. // summary:
  3224. // Connect to this function to receive notifications of printable keys being typed.
  3225. // event:
  3226. // key Event
  3227. // tags:
  3228. // callback
  3229. },
  3230. =====*/
  3231. onKeyUp: dijit._connectOnUseEventHandler,
  3232. /*=====
  3233. onKeyUp: function(event){
  3234. // summary:
  3235. // Connect to this function to receive notifications of keys being released.
  3236. // event:
  3237. // key Event
  3238. // tags:
  3239. // callback
  3240. },
  3241. =====*/
  3242. onMouseDown: dijit._connectOnUseEventHandler,
  3243. /*=====
  3244. onMouseDown: function(event){
  3245. // summary:
  3246. // Connect to this function to receive notifications of when the mouse button is pressed down.
  3247. // event:
  3248. // mouse Event
  3249. // tags:
  3250. // callback
  3251. },
  3252. =====*/
  3253. onMouseMove: dijit._connectOnUseEventHandler,
  3254. /*=====
  3255. onMouseMove: function(event){
  3256. // summary:
  3257. // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
  3258. // event:
  3259. // mouse Event
  3260. // tags:
  3261. // callback
  3262. },
  3263. =====*/
  3264. onMouseOut: dijit._connectOnUseEventHandler,
  3265. /*=====
  3266. onMouseOut: function(event){
  3267. // summary:
  3268. // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
  3269. // event:
  3270. // mouse Event
  3271. // tags:
  3272. // callback
  3273. },
  3274. =====*/
  3275. onMouseOver: dijit._connectOnUseEventHandler,
  3276. /*=====
  3277. onMouseOver: function(event){
  3278. // summary:
  3279. // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
  3280. // event:
  3281. // mouse Event
  3282. // tags:
  3283. // callback
  3284. },
  3285. =====*/
  3286. onMouseLeave: dijit._connectOnUseEventHandler,
  3287. /*=====
  3288. onMouseLeave: function(event){
  3289. // summary:
  3290. // Connect to this function to receive notifications of when the mouse moves off of this widget.
  3291. // event:
  3292. // mouse Event
  3293. // tags:
  3294. // callback
  3295. },
  3296. =====*/
  3297. onMouseEnter: dijit._connectOnUseEventHandler,
  3298. /*=====
  3299. onMouseEnter: function(event){
  3300. // summary:
  3301. // Connect to this function to receive notifications of when the mouse moves onto this widget.
  3302. // event:
  3303. // mouse Event
  3304. // tags:
  3305. // callback
  3306. },
  3307. =====*/
  3308. onMouseUp: dijit._connectOnUseEventHandler,
  3309. /*=====
  3310. onMouseUp: function(event){
  3311. // summary:
  3312. // Connect to this function to receive notifications of when the mouse button is released.
  3313. // event:
  3314. // mouse Event
  3315. // tags:
  3316. // callback
  3317. },
  3318. =====*/
  3319. create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
  3320. // To avoid double-connects, remove entries from _deferredConnects
  3321. // that have been setup manually by a subclass (ex, by dojoAttachEvent).
  3322. // If a subclass has redefined a callback (ex: onClick) then assume it's being
  3323. // connected to manually.
  3324. this._deferredConnects = dojo.clone(this._deferredConnects);
  3325. for(var attr in this.attributeMap){
  3326. delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
  3327. }
  3328. for(attr in this._deferredConnects){
  3329. if(this[attr] !== dijit._connectOnUseEventHandler){
  3330. delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists
  3331. }
  3332. }
  3333. this.inherited(arguments);
  3334. if(this.domNode){
  3335. // If the developer has specified a handler as a widget parameter
  3336. // (ex: new Button({onClick: ...})
  3337. // then naturally need to connect from DOM node to that handler immediately,
  3338. for(attr in this.params){
  3339. this._onConnect(attr);
  3340. }
  3341. }
  3342. },
  3343. _onConnect: function(/*String*/ event){
  3344. // summary:
  3345. // Called when someone connects to one of my handlers.
  3346. // "Turn on" that handler if it isn't active yet.
  3347. //
  3348. // This is also called for every single initialization parameter
  3349. // so need to do nothing for parameters like "id".
  3350. // tags:
  3351. // private
  3352. if(event in this._deferredConnects){
  3353. var mapNode = this[this._deferredConnects[event] || 'domNode'];
  3354. this.connect(mapNode, event.toLowerCase(), event);
  3355. delete this._deferredConnects[event];
  3356. }
  3357. },
  3358. ////////////////// FOCUS RELATED ///////////////////
  3359. // _onFocus() and _onBlur() are called by the focus manager
  3360. // focused: [readonly] Boolean
  3361. // This widget or a widget it contains has focus, or is "active" because
  3362. // it was recently clicked.
  3363. focused: false,
  3364. isFocusable: function(){
  3365. // summary:
  3366. // Return true if this widget can currently be focused
  3367. // and false if not
  3368. return this.focus && (dojo.style(this.domNode, "display") != "none");
  3369. },
  3370. onFocus: function(){
  3371. // summary:
  3372. // Called when the widget becomes "active" because
  3373. // it or a widget inside of it either has focus, or has recently
  3374. // been clicked.
  3375. // tags:
  3376. // callback
  3377. },
  3378. onBlur: function(){
  3379. // summary:
  3380. // Called when the widget stops being "active" because
  3381. // focus moved to something outside of it, or the user
  3382. // clicked somewhere outside of it, or the widget was
  3383. // hidden.
  3384. // tags:
  3385. // callback
  3386. },
  3387. _onFocus: function(e){
  3388. // summary:
  3389. // This is where widgets do processing for when they are active,
  3390. // such as changing CSS classes. See onFocus() for more details.
  3391. // tags:
  3392. // protected
  3393. this.onFocus();
  3394. },
  3395. _onBlur: function(){
  3396. // summary:
  3397. // This is where widgets do processing for when they stop being active,
  3398. // such as changing CSS classes. See onBlur() for more details.
  3399. // tags:
  3400. // protected
  3401. this.onBlur();
  3402. },
  3403. ////////////////// DEPRECATED METHODS ///////////////////
  3404. setAttribute: function(/*String*/ attr, /*anything*/ value){
  3405. // summary:
  3406. // Deprecated. Use set() instead.
  3407. // tags:
  3408. // deprecated
  3409. dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
  3410. this.set(attr, value);
  3411. },
  3412. attr: function(/*String|Object*/name, /*Object?*/value){
  3413. // summary:
  3414. // Set or get properties on a widget instance.
  3415. // name:
  3416. // The property to get or set. If an object is passed here and not
  3417. // a string, its keys are used as names of attributes to be set
  3418. // and the value of the object as values to set in the widget.
  3419. // value:
  3420. // Optional. If provided, attr() operates as a setter. If omitted,
  3421. // the current value of the named property is returned.
  3422. // description:
  3423. // This method is deprecated, use get() or set() directly.
  3424. // Print deprecation warning but only once per calling function
  3425. if(dojo.config.isDebug){
  3426. var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
  3427. caller = (arguments.callee.caller || "unknown caller").toString();
  3428. if(!alreadyCalledHash[caller]){
  3429. dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
  3430. caller, "", "2.0");
  3431. alreadyCalledHash[caller] = true;
  3432. }
  3433. }
  3434. var args = arguments.length;
  3435. if(args >= 2 || typeof name === "object"){ // setter
  3436. return this.set.apply(this, arguments);
  3437. }else{ // getter
  3438. return this.get(name);
  3439. }
  3440. },
  3441. ////////////////// ONDIJITCLICK SUPPORT ///////////////////
  3442. // nodesWithKeyClick: [private] String[]
  3443. // List of nodes that correctly handle click events via native browser support,
  3444. // and don't need dijit's help
  3445. nodesWithKeyClick: ["input", "button"],
  3446. connect: function(
  3447. /*Object|null*/ obj,
  3448. /*String|Function*/ event,
  3449. /*String|Function*/ method){
  3450. // summary:
  3451. // Connects specified obj/event to specified method of this object
  3452. // and registers for disconnect() on widget destroy.
  3453. // description:
  3454. // Provide widget-specific analog to dojo.connect, except with the
  3455. // implicit use of this widget as the target object.
  3456. // This version of connect also provides a special "ondijitclick"
  3457. // event which triggers on a click or space or enter keyup.
  3458. // Events connected with `this.connect` are disconnected upon
  3459. // destruction.
  3460. // returns:
  3461. // A handle that can be passed to `disconnect` in order to disconnect before
  3462. // the widget is destroyed.
  3463. // example:
  3464. // | var btn = new dijit.form.Button();
  3465. // | // when foo.bar() is called, call the listener we're going to
  3466. // | // provide in the scope of btn
  3467. // | btn.connect(foo, "bar", function(){
  3468. // | console.debug(this.toString());
  3469. // | });
  3470. // tags:
  3471. // protected
  3472. var d = dojo,
  3473. dc = d._connect,
  3474. handles = this.inherited(arguments, [obj, event == "ondijitclick" ? "onclick" : event, method]);
  3475. if(event == "ondijitclick"){
  3476. // add key based click activation for unsupported nodes.
  3477. // do all processing onkey up to prevent spurious clicks
  3478. // for details see comments at top of this file where _lastKeyDownNode is defined
  3479. if(d.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
  3480. var m = d.hitch(this, method);
  3481. handles.push(
  3482. dc(obj, "onkeydown", this, function(e){
  3483. //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
  3484. if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
  3485. !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
  3486. // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
  3487. dijit._lastKeyDownNode = e.target;
  3488. // Stop event to prevent scrolling on space key in IE.
  3489. // But don't do this for _HasDropDown because it surpresses the onkeypress
  3490. // event needed to open the drop down when the user presses the SPACE key.
  3491. if(!("openDropDown" in this && obj == this._buttonNode)){
  3492. e.preventDefault();
  3493. }
  3494. }
  3495. }),
  3496. dc(obj, "onkeyup", this, function(e){
  3497. //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
  3498. if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
  3499. e.target == dijit._lastKeyDownNode && // === breaks greasemonkey
  3500. !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
  3501. //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
  3502. dijit._lastKeyDownNode = null;
  3503. return m(e);
  3504. }
  3505. })
  3506. );
  3507. }
  3508. }
  3509. return handles; // _Widget.Handle
  3510. },
  3511. ////////////////// MISCELLANEOUS METHODS ///////////////////
  3512. _onShow: function(){
  3513. // summary:
  3514. // Internal method called when this widget is made visible.
  3515. // See `onShow` for details.
  3516. this.onShow();
  3517. },
  3518. onShow: function(){
  3519. // summary:
  3520. // Called when this widget becomes the selected pane in a
  3521. // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
  3522. // `dijit.layout.AccordionContainer`, etc.
  3523. //
  3524. // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
  3525. // tags:
  3526. // callback
  3527. },
  3528. onHide: function(){
  3529. // summary:
  3530. // Called when another widget becomes the selected pane in a
  3531. // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
  3532. // `dijit.layout.AccordionContainer`, etc.
  3533. //
  3534. // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
  3535. // tags:
  3536. // callback
  3537. },
  3538. onClose: function(){
  3539. // summary:
  3540. // Called when this widget is being displayed as a popup (ex: a Calendar popped
  3541. // up from a DateTextBox), and it is hidden.
  3542. // This is called from the dijit.popup code, and should not be called directly.
  3543. //
  3544. // Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
  3545. // Callback if a user tries to close the child. Child will be closed if this function returns true.
  3546. // tags:
  3547. // extension
  3548. return true; // Boolean
  3549. }
  3550. });
  3551. })();
  3552. }
  3553. if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  3554. dojo._hasResource["dojox.gfx.matrix"] = true;
  3555. dojo.provide("dojox.gfx.matrix");
  3556. (function(){
  3557. var m = dojox.gfx.matrix;
  3558. // candidates for dojox.math:
  3559. var _degToRadCache = {};
  3560. m._degToRad = function(degree){
  3561. return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180));
  3562. };
  3563. m._radToDeg = function(radian){ return radian / Math.PI * 180; };
  3564. m.Matrix2D = function(arg){
  3565. // summary: a 2D matrix object
  3566. // description: Normalizes a 2D matrix-like object. If arrays is passed,
  3567. // all objects of the array are normalized and multiplied sequentially.
  3568. // arg: Object
  3569. // a 2D matrix-like object, a number, or an array of such objects
  3570. if(arg){
  3571. if(typeof arg == "number"){
  3572. this.xx = this.yy = arg;
  3573. }else if(arg instanceof Array){
  3574. if(arg.length > 0){
  3575. var matrix = m.normalize(arg[0]);
  3576. // combine matrices
  3577. for(var i = 1; i < arg.length; ++i){
  3578. var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]);
  3579. matrix = new m.Matrix2D();
  3580. matrix.xx = l.xx * r.xx + l.xy * r.yx;
  3581. matrix.xy = l.xx * r.xy + l.xy * r.yy;
  3582. matrix.yx = l.yx * r.xx + l.yy * r.yx;
  3583. matrix.yy = l.yx * r.xy + l.yy * r.yy;
  3584. matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  3585. matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  3586. }
  3587. dojo.mixin(this, matrix);
  3588. }
  3589. }else{
  3590. dojo.mixin(this, arg);
  3591. }
  3592. }
  3593. };
  3594. // the default (identity) matrix, which is used to fill in missing values
  3595. dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
  3596. dojo.mixin(m, {
  3597. // summary: class constants, and methods of dojox.gfx.matrix
  3598. // matrix constants
  3599. // identity: dojox.gfx.matrix.Matrix2D
  3600. // an identity matrix constant: identity * (x, y) == (x, y)
  3601. identity: new m.Matrix2D(),
  3602. // flipX: dojox.gfx.matrix.Matrix2D
  3603. // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
  3604. flipX: new m.Matrix2D({xx: -1}),
  3605. // flipY: dojox.gfx.matrix.Matrix2D
  3606. // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
  3607. flipY: new m.Matrix2D({yy: -1}),
  3608. // flipXY: dojox.gfx.matrix.Matrix2D
  3609. // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
  3610. flipXY: new m.Matrix2D({xx: -1, yy: -1}),
  3611. // matrix creators
  3612. translate: function(a, b){
  3613. // summary: forms a translation matrix
  3614. // description: The resulting matrix is used to translate (move) points by specified offsets.
  3615. // a: Number: an x coordinate value
  3616. // b: Number: a y coordinate value
  3617. if(arguments.length > 1){
  3618. return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D
  3619. }
  3620. // branch
  3621. // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions
  3622. // b: null
  3623. return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D
  3624. },
  3625. scale: function(a, b){
  3626. // summary: forms a scaling matrix
  3627. // description: The resulting matrix is used to scale (magnify) points by specified offsets.
  3628. // a: Number: a scaling factor used for the x coordinate
  3629. // b: Number: a scaling factor used for the y coordinate
  3630. if(arguments.length > 1){
  3631. return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D
  3632. }
  3633. if(typeof a == "number"){
  3634. // branch
  3635. // a: Number: a uniform scaling factor used for the both coordinates
  3636. // b: null
  3637. return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D
  3638. }
  3639. // branch
  3640. // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions
  3641. // b: null
  3642. return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D
  3643. },
  3644. rotate: function(angle){
  3645. // summary: forms a rotating matrix
  3646. // description: The resulting matrix is used to rotate points
  3647. // around the origin of coordinates (0, 0) by specified angle.
  3648. // angle: Number: an angle of rotation in radians (>0 for CW)
  3649. var c = Math.cos(angle);
  3650. var s = Math.sin(angle);
  3651. return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D
  3652. },
  3653. rotateg: function(degree){
  3654. // summary: forms a rotating matrix
  3655. // description: The resulting matrix is used to rotate points
  3656. // around the origin of coordinates (0, 0) by specified degree.
  3657. // See dojox.gfx.matrix.rotate() for comparison.
  3658. // degree: Number: an angle of rotation in degrees (>0 for CW)
  3659. return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  3660. },
  3661. skewX: function(angle) {
  3662. // summary: forms an x skewing matrix
  3663. // description: The resulting matrix is used to skew points in the x dimension
  3664. // around the origin of coordinates (0, 0) by specified angle.
  3665. // angle: Number: an skewing angle in radians
  3666. return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  3667. },
  3668. skewXg: function(degree){
  3669. // summary: forms an x skewing matrix
  3670. // description: The resulting matrix is used to skew points in the x dimension
  3671. // around the origin of coordinates (0, 0) by specified degree.
  3672. // See dojox.gfx.matrix.skewX() for comparison.
  3673. // degree: Number: an skewing angle in degrees
  3674. return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  3675. },
  3676. skewY: function(angle){
  3677. // summary: forms a y skewing matrix
  3678. // description: The resulting matrix is used to skew points in the y dimension
  3679. // around the origin of coordinates (0, 0) by specified angle.
  3680. // angle: Number: an skewing angle in radians
  3681. return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D
  3682. },
  3683. skewYg: function(degree){
  3684. // summary: forms a y skewing matrix
  3685. // description: The resulting matrix is used to skew points in the y dimension
  3686. // around the origin of coordinates (0, 0) by specified degree.
  3687. // See dojox.gfx.matrix.skewY() for comparison.
  3688. // degree: Number: an skewing angle in degrees
  3689. return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D
  3690. },
  3691. reflect: function(a, b){
  3692. // summary: forms a reflection matrix
  3693. // description: The resulting matrix is used to reflect points around a vector,
  3694. // which goes through the origin.
  3695. // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection
  3696. // b: null
  3697. if(arguments.length == 1){
  3698. b = a.y;
  3699. a = a.x;
  3700. }
  3701. // branch
  3702. // a: Number: an x coordinate value
  3703. // b: Number: a y coordinate value
  3704. // make a unit vector
  3705. var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2;
  3706. return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D
  3707. },
  3708. project: function(a, b){
  3709. // summary: forms an orthogonal projection matrix
  3710. // description: The resulting matrix is used to project points orthogonally on a vector,
  3711. // which goes through the origin.
  3712. // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection
  3713. // b: null
  3714. if(arguments.length == 1){
  3715. b = a.y;
  3716. a = a.x;
  3717. }
  3718. // branch
  3719. // a: Number: an x coordinate value
  3720. // b: Number: a y coordinate value
  3721. // make a unit vector
  3722. var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
  3723. return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D
  3724. },
  3725. // ensure matrix 2D conformance
  3726. normalize: function(matrix){
  3727. // summary: converts an object to a matrix, if necessary
  3728. // description: Converts any 2D matrix-like object or an array of
  3729. // such objects to a valid dojox.gfx.matrix.Matrix2D object.
  3730. // matrix: Object: an object, which is converted to a matrix, if necessary
  3731. return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D
  3732. },
  3733. // common operations
  3734. clone: function(matrix){
  3735. // summary: creates a copy of a 2D matrix
  3736. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned
  3737. var obj = new m.Matrix2D();
  3738. for(var i in matrix){
  3739. if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
  3740. }
  3741. return obj; // dojox.gfx.matrix.Matrix2D
  3742. },
  3743. invert: function(matrix){
  3744. // summary: inverts a 2D matrix
  3745. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted
  3746. var M = m.normalize(matrix),
  3747. D = M.xx * M.yy - M.xy * M.yx,
  3748. M = new m.Matrix2D({
  3749. xx: M.yy/D, xy: -M.xy/D,
  3750. yx: -M.yx/D, yy: M.xx/D,
  3751. dx: (M.xy * M.dy - M.yy * M.dx) / D,
  3752. dy: (M.yx * M.dx - M.xx * M.dy) / D
  3753. });
  3754. return M; // dojox.gfx.matrix.Matrix2D
  3755. },
  3756. _multiplyPoint: function(matrix, x, y){
  3757. // summary: applies a matrix to a point
  3758. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  3759. // x: Number: an x coordinate of a point
  3760. // y: Number: a y coordinate of a point
  3761. return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point
  3762. },
  3763. multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){
  3764. // summary: applies a matrix to a point
  3765. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  3766. // a: Number: an x coordinate of a point
  3767. // b: Number: a y coordinate of a point
  3768. var M = m.normalize(matrix);
  3769. if(typeof a == "number" && typeof b == "number"){
  3770. return m._multiplyPoint(M, a, b); // dojox.gfx.Point
  3771. }
  3772. // branch
  3773. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied
  3774. // a: dojox.gfx.Point: a point
  3775. // b: null
  3776. return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point
  3777. },
  3778. multiply: function(matrix){
  3779. // summary: combines matrices by multiplying them sequentially in the given order
  3780. // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object,
  3781. // all subsequent arguments are matrix-like objects too
  3782. var M = m.normalize(matrix);
  3783. // combine matrices
  3784. for(var i = 1; i < arguments.length; ++i){
  3785. var l = M, r = m.normalize(arguments[i]);
  3786. M = new m.Matrix2D();
  3787. M.xx = l.xx * r.xx + l.xy * r.yx;
  3788. M.xy = l.xx * r.xy + l.xy * r.yy;
  3789. M.yx = l.yx * r.xx + l.yy * r.yx;
  3790. M.yy = l.yx * r.xy + l.yy * r.yy;
  3791. M.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
  3792. M.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
  3793. }
  3794. return M; // dojox.gfx.matrix.Matrix2D
  3795. },
  3796. // high level operations
  3797. _sandwich: function(matrix, x, y){
  3798. // summary: applies a matrix at a centrtal point
  3799. // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point
  3800. // x: Number: an x component of the central point
  3801. // y: Number: a y component of the central point
  3802. return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D
  3803. },
  3804. scaleAt: function(a, b, c, d){
  3805. // summary: scales a picture using a specified point as a center of scaling
  3806. // description: Compare with dojox.gfx.matrix.scale().
  3807. // a: Number: a scaling factor used for the x coordinate
  3808. // b: Number: a scaling factor used for the y coordinate
  3809. // c: Number: an x component of a central point
  3810. // d: Number: a y component of a central point
  3811. // accepts several signatures:
  3812. // 1) uniform scale factor, Point
  3813. // 2) uniform scale factor, x, y
  3814. // 3) x scale, y scale, Point
  3815. // 4) x scale, y scale, x, y
  3816. switch(arguments.length){
  3817. case 4:
  3818. // a and b are scale factor components, c and d are components of a point
  3819. return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D
  3820. case 3:
  3821. if(typeof c == "number"){
  3822. // branch
  3823. // a: Number: a uniform scaling factor used for both coordinates
  3824. // b: Number: an x component of a central point
  3825. // c: Number: a y component of a central point
  3826. // d: null
  3827. return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D
  3828. }
  3829. // branch
  3830. // a: Number: a scaling factor used for the x coordinate
  3831. // b: Number: a scaling factor used for the y coordinate
  3832. // c: dojox.gfx.Point: a central point
  3833. // d: null
  3834. return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D
  3835. }
  3836. // branch
  3837. // a: Number: a uniform scaling factor used for both coordinates
  3838. // b: dojox.gfx.Point: a central point
  3839. // c: null
  3840. // d: null
  3841. return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D
  3842. },
  3843. rotateAt: function(angle, a, b){
  3844. // summary: rotates a picture using a specified point as a center of rotation
  3845. // description: Compare with dojox.gfx.matrix.rotate().
  3846. // angle: Number: an angle of rotation in radians (>0 for CW)
  3847. // a: Number: an x component of a central point
  3848. // b: Number: a y component of a central point
  3849. // accepts several signatures:
  3850. // 1) rotation angle in radians, Point
  3851. // 2) rotation angle in radians, x, y
  3852. if(arguments.length > 2){
  3853. return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D
  3854. }
  3855. // branch
  3856. // angle: Number: an angle of rotation in radians (>0 for CCW)
  3857. // a: dojox.gfx.Point: a central point
  3858. // b: null
  3859. return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3860. },
  3861. rotategAt: function(degree, a, b){
  3862. // summary: rotates a picture using a specified point as a center of rotation
  3863. // description: Compare with dojox.gfx.matrix.rotateg().
  3864. // degree: Number: an angle of rotation in degrees (>0 for CW)
  3865. // a: Number: an x component of a central point
  3866. // b: Number: a y component of a central point
  3867. // accepts several signatures:
  3868. // 1) rotation angle in degrees, Point
  3869. // 2) rotation angle in degrees, x, y
  3870. if(arguments.length > 2){
  3871. return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  3872. }
  3873. // branch
  3874. // degree: Number: an angle of rotation in degrees (>0 for CCW)
  3875. // a: dojox.gfx.Point: a central point
  3876. // b: null
  3877. return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3878. },
  3879. skewXAt: function(angle, a, b){
  3880. // summary: skews a picture along the x axis using a specified point as a center of skewing
  3881. // description: Compare with dojox.gfx.matrix.skewX().
  3882. // angle: Number: an skewing angle in radians
  3883. // a: Number: an x component of a central point
  3884. // b: Number: a y component of a central point
  3885. // accepts several signatures:
  3886. // 1) skew angle in radians, Point
  3887. // 2) skew angle in radians, x, y
  3888. if(arguments.length > 2){
  3889. return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D
  3890. }
  3891. // branch
  3892. // angle: Number: an skewing angle in radians
  3893. // a: dojox.gfx.Point: a central point
  3894. // b: null
  3895. return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3896. },
  3897. skewXgAt: function(degree, a, b){
  3898. // summary: skews a picture along the x axis using a specified point as a center of skewing
  3899. // description: Compare with dojox.gfx.matrix.skewXg().
  3900. // degree: Number: an skewing angle in degrees
  3901. // a: Number: an x component of a central point
  3902. // b: Number: a y component of a central point
  3903. // accepts several signatures:
  3904. // 1) skew angle in degrees, Point
  3905. // 2) skew angle in degrees, x, y
  3906. if(arguments.length > 2){
  3907. return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  3908. }
  3909. // branch
  3910. // degree: Number: an skewing angle in degrees
  3911. // a: dojox.gfx.Point: a central point
  3912. // b: null
  3913. return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3914. },
  3915. skewYAt: function(angle, a, b){
  3916. // summary: skews a picture along the y axis using a specified point as a center of skewing
  3917. // description: Compare with dojox.gfx.matrix.skewY().
  3918. // angle: Number: an skewing angle in radians
  3919. // a: Number: an x component of a central point
  3920. // b: Number: a y component of a central point
  3921. // accepts several signatures:
  3922. // 1) skew angle in radians, Point
  3923. // 2) skew angle in radians, x, y
  3924. if(arguments.length > 2){
  3925. return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D
  3926. }
  3927. // branch
  3928. // angle: Number: an skewing angle in radians
  3929. // a: dojox.gfx.Point: a central point
  3930. // b: null
  3931. return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3932. },
  3933. skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){
  3934. // summary: skews a picture along the y axis using a specified point as a center of skewing
  3935. // description: Compare with dojox.gfx.matrix.skewYg().
  3936. // degree: Number: an skewing angle in degrees
  3937. // a: Number: an x component of a central point
  3938. // b: Number: a y component of a central point
  3939. // accepts several signatures:
  3940. // 1) skew angle in degrees, Point
  3941. // 2) skew angle in degrees, x, y
  3942. if(arguments.length > 2){
  3943. return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D
  3944. }
  3945. // branch
  3946. // degree: Number: an skewing angle in degrees
  3947. // a: dojox.gfx.Point: a central point
  3948. // b: null
  3949. return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D
  3950. }
  3951. //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
  3952. });
  3953. })();
  3954. // propagate Matrix2D up
  3955. dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D;
  3956. }
  3957. if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  3958. dojo._hasResource["dojox.gfx._base"] = true;
  3959. dojo.provide("dojox.gfx._base");
  3960. (function(){
  3961. var g = dojox.gfx, b = g._base;
  3962. // candidates for dojox.style (work on VML and SVG nodes)
  3963. g._hasClass = function(/*DomNode*/node, /*String*/classStr){
  3964. // summary:
  3965. // Returns whether or not the specified classes are a portion of the
  3966. // class list currently applied to the node.
  3967. // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
  3968. var cls = node.getAttribute("className");
  3969. return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean
  3970. };
  3971. g._addClass = function(/*DomNode*/node, /*String*/classStr){
  3972. // summary:
  3973. // Adds the specified classes to the end of the class list on the
  3974. // passed node.
  3975. var cls = node.getAttribute("className") || "";
  3976. if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){
  3977. node.setAttribute("className", cls + (cls ? " " : "") + classStr);
  3978. }
  3979. };
  3980. g._removeClass = function(/*DomNode*/node, /*String*/classStr){
  3981. // summary: Removes classes from node.
  3982. var cls = node.getAttribute("className");
  3983. if(cls){
  3984. node.setAttribute(
  3985. "className",
  3986. cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2")
  3987. );
  3988. }
  3989. };
  3990. // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
  3991. // derived from Morris John's emResized measurer
  3992. b._getFontMeasurements = function(){
  3993. // summary:
  3994. // Returns an object that has pixel equivilents of standard font
  3995. // size values.
  3996. var heights = {
  3997. '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0,
  3998. 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0,
  3999. 'xx-large': 0
  4000. };
  4001. if(dojo.isIE){
  4002. // we do a font-size fix if and only if one isn't applied already.
  4003. // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
  4004. dojo.doc.documentElement.style.fontSize="100%";
  4005. }
  4006. // set up the measuring node.
  4007. var div = dojo.create("div", {style: {
  4008. position: "absolute",
  4009. left: "0",
  4010. top: "-100px",
  4011. width: "30px",
  4012. height: "1000em",
  4013. borderWidth: "0",
  4014. margin: "0",
  4015. padding: "0",
  4016. outline: "none",
  4017. lineHeight: "1",
  4018. overflow: "hidden"
  4019. }}, dojo.body());
  4020. // do the measurements.
  4021. for(var p in heights){
  4022. div.style.fontSize = p;
  4023. heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
  4024. }
  4025. dojo.body().removeChild(div);
  4026. return heights; // object
  4027. };
  4028. var fontMeasurements = null;
  4029. b._getCachedFontMeasurements = function(recalculate){
  4030. if(recalculate || !fontMeasurements){
  4031. fontMeasurements = b._getFontMeasurements();
  4032. }
  4033. return fontMeasurements;
  4034. };
  4035. // candidate for dojox.html.metrics
  4036. var measuringNode = null, empty = {};
  4037. b._getTextBox = function( /*String*/ text,
  4038. /*Object*/ style,
  4039. /*String?*/ className){
  4040. var m, s, al = arguments.length;
  4041. if(!measuringNode){
  4042. measuringNode = dojo.create("div", {style: {
  4043. position: "absolute",
  4044. top: "-10000px",
  4045. left: "0"
  4046. }}, dojo.body());
  4047. }
  4048. m = measuringNode;
  4049. // reset styles
  4050. m.className = "";
  4051. s = m.style;
  4052. s.borderWidth = "0";
  4053. s.margin = "0";
  4054. s.padding = "0";
  4055. s.outline = "0";
  4056. // set new style
  4057. if(al > 1 && style){
  4058. for(var i in style){
  4059. if(i in empty){ continue; }
  4060. s[i] = style[i];
  4061. }
  4062. }
  4063. // set classes
  4064. if(al > 2 && className){
  4065. m.className = className;
  4066. }
  4067. // take a measure
  4068. m.innerHTML = text;
  4069. if(m["getBoundingClientRect"]){
  4070. var bcr = m.getBoundingClientRect();
  4071. return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
  4072. }else{
  4073. return dojo.marginBox(m);
  4074. }
  4075. };
  4076. // candidate for dojo.dom
  4077. var uniqueId = 0;
  4078. b._getUniqueId = function(){
  4079. // summary: returns a unique string for use with any DOM element
  4080. var id;
  4081. do{
  4082. id = dojo._scopeName + "Unique" + (++uniqueId);
  4083. }while(dojo.byId(id));
  4084. return id;
  4085. };
  4086. })();
  4087. dojo.mixin(dojox.gfx, {
  4088. // summary:
  4089. // defines constants, prototypes, and utility functions
  4090. // default shapes, which are used to fill in missing parameters
  4091. defaultPath: {
  4092. type: "path", path: ""
  4093. },
  4094. defaultPolyline: {
  4095. type: "polyline", points: []
  4096. },
  4097. defaultRect: {
  4098. type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0
  4099. },
  4100. defaultEllipse: {
  4101. type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100
  4102. },
  4103. defaultCircle: {
  4104. type: "circle", cx: 0, cy: 0, r: 100
  4105. },
  4106. defaultLine: {
  4107. type: "line", x1: 0, y1: 0, x2: 100, y2: 100
  4108. },
  4109. defaultImage: {
  4110. type: "image", x: 0, y: 0, width: 0, height: 0, src: ""
  4111. },
  4112. defaultText: {
  4113. type: "text", x: 0, y: 0, text: "", align: "start",
  4114. decoration: "none", rotated: false, kerning: true
  4115. },
  4116. defaultTextPath: {
  4117. type: "textpath", text: "", align: "start",
  4118. decoration: "none", rotated: false, kerning: true
  4119. },
  4120. // default geometric attributes
  4121. defaultStroke: {
  4122. type: "stroke", color: "black", style: "solid", width: 1,
  4123. cap: "butt", join: 4
  4124. },
  4125. defaultLinearGradient: {
  4126. type: "linear", x1: 0, y1: 0, x2: 100, y2: 100,
  4127. colors: [
  4128. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  4129. ]
  4130. },
  4131. defaultRadialGradient: {
  4132. type: "radial", cx: 0, cy: 0, r: 100,
  4133. colors: [
  4134. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  4135. ]
  4136. },
  4137. defaultPattern: {
  4138. type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""
  4139. },
  4140. defaultFont: {
  4141. type: "font", style: "normal", variant: "normal",
  4142. weight: "normal", size: "10pt", family: "serif"
  4143. },
  4144. getDefault: (function(){
  4145. var typeCtorCache = {};
  4146. // a memoized delegate()
  4147. return function(/*String*/ type){
  4148. var t = typeCtorCache[type];
  4149. if(t){
  4150. return new t();
  4151. }
  4152. t = typeCtorCache[type] = new Function;
  4153. t.prototype = dojox.gfx[ "default" + type ];
  4154. return new t();
  4155. }
  4156. })(),
  4157. normalizeColor: function(/*Color*/ color){
  4158. // summary:
  4159. // converts any legal color representation to normalized
  4160. // dojo.Color object
  4161. return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color
  4162. },
  4163. normalizeParameters: function(existed, update){
  4164. // summary:
  4165. // updates an existing object with properties from an "update"
  4166. // object
  4167. // existed: Object
  4168. // the "target" object to be updated
  4169. // update: Object
  4170. // the "update" object, whose properties will be used to update
  4171. // the existed object
  4172. if(update){
  4173. var empty = {};
  4174. for(var x in existed){
  4175. if(x in update && !(x in empty)){
  4176. existed[x] = update[x];
  4177. }
  4178. }
  4179. }
  4180. return existed; // Object
  4181. },
  4182. makeParameters: function(defaults, update){
  4183. // summary:
  4184. // copies the original object, and all copied properties from the
  4185. // "update" object
  4186. // defaults: Object
  4187. // the object to be cloned before updating
  4188. // update: Object
  4189. // the object, which properties are to be cloned during updating
  4190. if(!update){
  4191. // return dojo.clone(defaults);
  4192. return dojo.delegate(defaults);
  4193. }
  4194. var result = {};
  4195. for(var i in defaults){
  4196. if(!(i in result)){
  4197. result[i] = dojo.clone((i in update) ? update[i] : defaults[i]);
  4198. }
  4199. }
  4200. return result; // Object
  4201. },
  4202. formatNumber: function(x, addSpace){
  4203. // summary: converts a number to a string using a fixed notation
  4204. // x: Number: number to be converted
  4205. // addSpace: Boolean?: if it is true, add a space before a positive number
  4206. var val = x.toString();
  4207. if(val.indexOf("e") >= 0){
  4208. val = x.toFixed(4);
  4209. }else{
  4210. var point = val.indexOf(".");
  4211. if(point >= 0 && val.length - point > 5){
  4212. val = x.toFixed(4);
  4213. }
  4214. }
  4215. if(x < 0){
  4216. return val; // String
  4217. }
  4218. return addSpace ? " " + val : val; // String
  4219. },
  4220. // font operations
  4221. makeFontString: function(font){
  4222. // summary: converts a font object to a CSS font string
  4223. // font: Object: font object (see dojox.gfx.defaultFont)
  4224. return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
  4225. },
  4226. splitFontString: function(str){
  4227. // summary:
  4228. // converts a CSS font string to a font object
  4229. // description:
  4230. // Converts a CSS font string to a gfx font object. The CSS font
  4231. // string components should follow the W3C specified order
  4232. // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
  4233. // style, variant, weight, size, optional line height (will be
  4234. // ignored), and family.
  4235. // str: String
  4236. // a CSS font string
  4237. var font = dojox.gfx.getDefault("Font");
  4238. var t = str.split(/\s+/);
  4239. do{
  4240. if(t.length < 5){ break; }
  4241. font.style = t[0];
  4242. font.variant = t[1];
  4243. font.weight = t[2];
  4244. var i = t[3].indexOf("/");
  4245. font.size = i < 0 ? t[3] : t[3].substring(0, i);
  4246. var j = 4;
  4247. if(i < 0){
  4248. if(t[4] == "/"){
  4249. j = 6;
  4250. }else if(t[4].charAt(0) == "/"){
  4251. j = 5;
  4252. }
  4253. }
  4254. if(j < t.length){
  4255. font.family = t.slice(j).join(" ");
  4256. }
  4257. }while(false);
  4258. return font; // Object
  4259. },
  4260. // length operations
  4261. cm_in_pt: 72 / 2.54, // Number: points per centimeter
  4262. mm_in_pt: 7.2 / 2.54, // Number: points per millimeter
  4263. px_in_pt: function(){
  4264. // summary: returns a number of pixels per point
  4265. return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number
  4266. },
  4267. pt2px: function(len){
  4268. // summary: converts points to pixels
  4269. // len: Number: a value in points
  4270. return len * dojox.gfx.px_in_pt(); // Number
  4271. },
  4272. px2pt: function(len){
  4273. // summary: converts pixels to points
  4274. // len: Number: a value in pixels
  4275. return len / dojox.gfx.px_in_pt(); // Number
  4276. },
  4277. normalizedLength: function(len) {
  4278. // summary: converts any length value to pixels
  4279. // len: String: a length, e.g., "12pc"
  4280. if(len.length == 0) return 0;
  4281. if(len.length > 2){
  4282. var px_in_pt = dojox.gfx.px_in_pt();
  4283. var val = parseFloat(len);
  4284. switch(len.slice(-2)){
  4285. case "px": return val;
  4286. case "pt": return val * px_in_pt;
  4287. case "in": return val * 72 * px_in_pt;
  4288. case "pc": return val * 12 * px_in_pt;
  4289. case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt;
  4290. case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt;
  4291. }
  4292. }
  4293. return parseFloat(len); // Number
  4294. },
  4295. // a constant used to split a SVG/VML path into primitive components
  4296. pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  4297. pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  4298. equalSources: function(a, b){
  4299. // summary: compares event sources, returns true if they are equal
  4300. return a && b && a == b;
  4301. },
  4302. switchTo: function(renderer){
  4303. var ns = dojox.gfx[renderer];
  4304. if(ns){
  4305. dojo.forEach(["Group", "Rect", "Ellipse", "Circle", "Line",
  4306. "Polyline", "Image", "Text", "Path", "TextPath",
  4307. "Surface", "createSurface"], function(name){
  4308. dojox.gfx[name] = ns[name];
  4309. });
  4310. }
  4311. }
  4312. });
  4313. }
  4314. if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4315. dojo._hasResource["dojox.gfx"] = true;
  4316. dojo.provide("dojox.gfx");
  4317. dojo.loadInit(function(){
  4318. // Since loaderInit can be fired before any dojo.provide/require calls,
  4319. // make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer
  4320. // has not been defined yet.
  4321. var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match;
  4322. while(!gfx.renderer){
  4323. // Have a way to force a GFX renderer, if so desired.
  4324. // Useful for being able to serialize GFX data in a particular format.
  4325. if(dojo.config.forceGfxRenderer){
  4326. dojox.gfx.renderer = dojo.config.forceGfxRenderer;
  4327. break;
  4328. }
  4329. var renderers = (typeof dojo.config.gfxRenderer == "string" ?
  4330. dojo.config.gfxRenderer : "svg,vml,canvas,silverlight").split(",");
  4331. for(var i = 0; i < renderers.length; ++i){
  4332. switch(renderers[i]){
  4333. case "svg":
  4334. // the next test is from https://github.com/phiggins42/has.js
  4335. if("SVGAngle" in dojo.global){
  4336. dojox.gfx.renderer = "svg";
  4337. }
  4338. break;
  4339. case "vml":
  4340. if(dojo.isIE){
  4341. dojox.gfx.renderer = "vml";
  4342. }
  4343. break;
  4344. case "silverlight":
  4345. try{
  4346. if(dojo.isIE){
  4347. sl = new ActiveXObject("AgControl.AgControl");
  4348. if(sl && sl.IsVersionSupported("1.0")){
  4349. flag = true;
  4350. }
  4351. }else{
  4352. if(navigator.plugins["Silverlight Plug-In"]){
  4353. flag = true;
  4354. }
  4355. }
  4356. }catch(e){
  4357. flag = false;
  4358. }finally{
  4359. sl = null;
  4360. }
  4361. if(flag){
  4362. dojox.gfx.renderer = "silverlight";
  4363. }
  4364. break;
  4365. case "canvas":
  4366. if(dojo.global.CanvasRenderingContext2D){
  4367. dojox.gfx.renderer = "canvas";
  4368. }
  4369. break;
  4370. }
  4371. if(gfx.renderer){
  4372. break;
  4373. }
  4374. }
  4375. break;
  4376. }
  4377. if(dojo.config.isDebug){
  4378. console.log("gfx renderer = " + gfx.renderer);
  4379. }
  4380. // load & initialize renderer
  4381. if(gfx[gfx.renderer]){
  4382. // already loaded
  4383. gfx.switchTo(gfx.renderer);
  4384. }else{
  4385. // load
  4386. gfx.loadAndSwitch = gfx.renderer;
  4387. dojo["require"]("dojox.gfx." + gfx.renderer);
  4388. }
  4389. });
  4390. }
  4391. if(!dojo._hasResource["dojox.lang.functional.lambda"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4392. dojo._hasResource["dojox.lang.functional.lambda"] = true;
  4393. dojo.provide("dojox.lang.functional.lambda");
  4394. // This module adds high-level functions and related constructs:
  4395. // - anonymous functions built from the string
  4396. // Acknoledgements:
  4397. // - lambda() is based on work by Oliver Steele
  4398. // (http://osteele.com/sources/javascript/functional/functional.js)
  4399. // which was published under MIT License
  4400. // Notes:
  4401. // - lambda() produces functions, which after the compilation step are
  4402. // as fast as regular JS functions (at least theoretically).
  4403. // Lambda input values:
  4404. // - returns functions unchanged
  4405. // - converts strings to functions
  4406. // - converts arrays to a functional composition
  4407. (function(){
  4408. var df = dojox.lang.functional, lcache = {};
  4409. // split() is augmented on IE6 to ensure the uniform behavior
  4410. var split = "ab".split(/a*/).length > 1 ? String.prototype.split :
  4411. function(sep){
  4412. var r = this.split.call(this, sep),
  4413. m = sep.exec(this);
  4414. if(m && m.index == 0){ r.unshift(""); }
  4415. return r;
  4416. };
  4417. var lambda = function(/*String*/ s){
  4418. var args = [], sects = split.call(s, /\s*->\s*/m);
  4419. if(sects.length > 1){
  4420. while(sects.length){
  4421. s = sects.pop();
  4422. args = sects.pop().split(/\s*,\s*|\s+/m);
  4423. if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); }
  4424. }
  4425. }else if(s.match(/\b_\b/)){
  4426. args = ["_"];
  4427. }else{
  4428. var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m),
  4429. r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m);
  4430. if(l || r){
  4431. if(l){
  4432. args.push("$1");
  4433. s = "$1" + s;
  4434. }
  4435. if(r){
  4436. args.push("$2");
  4437. s = s + "$2";
  4438. }
  4439. }else{
  4440. // the point of the long regex below is to exclude all well-known
  4441. // lower-case words from the list of potential arguments
  4442. var vars = s.
  4443. replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, "").
  4444. match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {};
  4445. dojo.forEach(vars, function(v){
  4446. if(!(v in t)){
  4447. args.push(v);
  4448. t[v] = 1;
  4449. }
  4450. });
  4451. }
  4452. }
  4453. return {args: args, body: s}; // Object
  4454. };
  4455. var compose = function(/*Array*/ a){
  4456. return a.length ?
  4457. function(){
  4458. var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments);
  4459. for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); }
  4460. return x;
  4461. }
  4462. :
  4463. // identity
  4464. function(x){ return x; };
  4465. };
  4466. dojo.mixin(df, {
  4467. // lambda
  4468. rawLambda: function(/*String*/ s){
  4469. // summary:
  4470. // builds a function from a snippet, or array (composing),
  4471. // returns an object describing the function; functions are
  4472. // passed through unmodified.
  4473. // description:
  4474. // This method is to normalize a functional representation (a
  4475. // text snippet) to an object that contains an array of
  4476. // arguments, and a body , which is used to calculate the
  4477. // returning value.
  4478. return lambda(s); // Object
  4479. },
  4480. buildLambda: function(/*String*/ s){
  4481. // summary:
  4482. // builds a function from a snippet, returns a string, which
  4483. // represents the function.
  4484. // description:
  4485. // This method returns a textual representation of a function
  4486. // built from the snippet. It is meant to be evaled in the
  4487. // proper context, so local variables can be pulled from the
  4488. // environment.
  4489. s = lambda(s);
  4490. return "function(" + s.args.join(",") + "){return (" + s.body + ");}"; // String
  4491. },
  4492. lambda: function(/*Function|String|Array*/ s){
  4493. // summary:
  4494. // builds a function from a snippet, or array (composing),
  4495. // returns a function object; functions are passed through
  4496. // unmodified.
  4497. // description:
  4498. // This method is used to normalize a functional
  4499. // representation (a text snippet, an array, or a function) to
  4500. // a function object.
  4501. if(typeof s == "function"){ return s; }
  4502. if(s instanceof Array){ return compose(s); }
  4503. if(s in lcache){ return lcache[s]; }
  4504. s = lambda(s);
  4505. return lcache[s] = new Function(s.args, "return (" + s.body + ");"); // Function
  4506. },
  4507. clearLambdaCache: function(){
  4508. // summary:
  4509. // clears internal cache of lambdas
  4510. lcache = {};
  4511. }
  4512. });
  4513. })();
  4514. }
  4515. if(!dojo._hasResource["dojox.lang.functional.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4516. dojo._hasResource["dojox.lang.functional.array"] = true;
  4517. dojo.provide("dojox.lang.functional.array");
  4518. // This module adds high-level functions and related constructs:
  4519. // - array-processing functions similar to standard JS functions
  4520. // Notes:
  4521. // - this module provides JS standard methods similar to high-level functions in dojo/_base/array.js:
  4522. // forEach, map, filter, every, some
  4523. // Defined methods:
  4524. // - take any valid lambda argument as the functional argument
  4525. // - operate on dense arrays
  4526. // - take a string as the array argument
  4527. // - take an iterator objects as the array argument
  4528. (function(){
  4529. var d = dojo, df = dojox.lang.functional, empty = {};
  4530. d.mixin(df, {
  4531. // JS 1.6 standard array functions, which can take a lambda as a parameter.
  4532. // Consider using dojo._base.array functions, if you don't need the lambda support.
  4533. filter: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4534. // summary: creates a new array with all elements that pass the test
  4535. // implemented by the provided function.
  4536. if(typeof a == "string"){ a = a.split(""); }
  4537. o = o || d.global; f = df.lambda(f);
  4538. var t = [], v, i, n;
  4539. if(d.isArray(a)){
  4540. // array
  4541. for(i = 0, n = a.length; i < n; ++i){
  4542. v = a[i];
  4543. if(f.call(o, v, i, a)){ t.push(v); }
  4544. }
  4545. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4546. // iterator
  4547. for(i = 0; a.hasNext();){
  4548. v = a.next();
  4549. if(f.call(o, v, i++, a)){ t.push(v); }
  4550. }
  4551. }else{
  4552. // object/dictionary
  4553. for(i in a){
  4554. if(!(i in empty)){
  4555. v = a[i];
  4556. if(f.call(o, v, i, a)){ t.push(v); }
  4557. }
  4558. }
  4559. }
  4560. return t; // Array
  4561. },
  4562. forEach: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4563. // summary: executes a provided function once per array element.
  4564. if(typeof a == "string"){ a = a.split(""); }
  4565. o = o || d.global; f = df.lambda(f);
  4566. var i, n;
  4567. if(d.isArray(a)){
  4568. // array
  4569. for(i = 0, n = a.length; i < n; f.call(o, a[i], i, a), ++i);
  4570. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4571. // iterator
  4572. for(i = 0; a.hasNext(); f.call(o, a.next(), i++, a));
  4573. }else{
  4574. // object/dictionary
  4575. for(i in a){
  4576. if(!(i in empty)){
  4577. f.call(o, a[i], i, a);
  4578. }
  4579. }
  4580. }
  4581. return o; // Object
  4582. },
  4583. map: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4584. // summary: creates a new array with the results of calling
  4585. // a provided function on every element in this array.
  4586. if(typeof a == "string"){ a = a.split(""); }
  4587. o = o || d.global; f = df.lambda(f);
  4588. var t, n, i;
  4589. if(d.isArray(a)){
  4590. // array
  4591. t = new Array(n = a.length);
  4592. for(i = 0; i < n; t[i] = f.call(o, a[i], i, a), ++i);
  4593. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4594. // iterator
  4595. t = [];
  4596. for(i = 0; a.hasNext(); t.push(f.call(o, a.next(), i++, a)));
  4597. }else{
  4598. // object/dictionary
  4599. t = [];
  4600. for(i in a){
  4601. if(!(i in empty)){
  4602. t.push(f.call(o, a[i], i, a));
  4603. }
  4604. }
  4605. }
  4606. return t; // Array
  4607. },
  4608. every: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4609. // summary: tests whether all elements in the array pass the test
  4610. // implemented by the provided function.
  4611. if(typeof a == "string"){ a = a.split(""); }
  4612. o = o || d.global; f = df.lambda(f);
  4613. var i, n;
  4614. if(d.isArray(a)){
  4615. // array
  4616. for(i = 0, n = a.length; i < n; ++i){
  4617. if(!f.call(o, a[i], i, a)){
  4618. return false; // Boolean
  4619. }
  4620. }
  4621. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4622. // iterator
  4623. for(i = 0; a.hasNext();){
  4624. if(!f.call(o, a.next(), i++, a)){
  4625. return false; // Boolean
  4626. }
  4627. }
  4628. }else{
  4629. // object/dictionary
  4630. for(i in a){
  4631. if(!(i in empty)){
  4632. if(!f.call(o, a[i], i, a)){
  4633. return false; // Boolean
  4634. }
  4635. }
  4636. }
  4637. }
  4638. return true; // Boolean
  4639. },
  4640. some: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4641. // summary: tests whether some element in the array passes the test
  4642. // implemented by the provided function.
  4643. if(typeof a == "string"){ a = a.split(""); }
  4644. o = o || d.global; f = df.lambda(f);
  4645. var i, n;
  4646. if(d.isArray(a)){
  4647. // array
  4648. for(i = 0, n = a.length; i < n; ++i){
  4649. if(f.call(o, a[i], i, a)){
  4650. return true; // Boolean
  4651. }
  4652. }
  4653. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4654. // iterator
  4655. for(i = 0; a.hasNext();){
  4656. if(f.call(o, a.next(), i++, a)){
  4657. return true; // Boolean
  4658. }
  4659. }
  4660. }else{
  4661. // object/dictionary
  4662. for(i in a){
  4663. if(!(i in empty)){
  4664. if(f.call(o, a[i], i, a)){
  4665. return true; // Boolean
  4666. }
  4667. }
  4668. }
  4669. }
  4670. return false; // Boolean
  4671. }
  4672. });
  4673. })();
  4674. }
  4675. if(!dojo._hasResource["dojox.lang.functional.object"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4676. dojo._hasResource["dojox.lang.functional.object"] = true;
  4677. dojo.provide("dojox.lang.functional.object");
  4678. // This module adds high-level functions and related constructs:
  4679. // - object/dictionary helpers
  4680. // Defined methods:
  4681. // - take any valid lambda argument as the functional argument
  4682. // - skip all attributes that are present in the empty object
  4683. // (IE and/or 3rd-party libraries).
  4684. (function(){
  4685. var d = dojo, df = dojox.lang.functional, empty = {};
  4686. d.mixin(df, {
  4687. // object helpers
  4688. keys: function(/*Object*/ obj){
  4689. // summary: returns an array of all keys in the object
  4690. var t = [];
  4691. for(var i in obj){
  4692. if(!(i in empty)){
  4693. t.push(i);
  4694. }
  4695. }
  4696. return t; // Array
  4697. },
  4698. values: function(/*Object*/ obj){
  4699. // summary: returns an array of all values in the object
  4700. var t = [];
  4701. for(var i in obj){
  4702. if(!(i in empty)){
  4703. t.push(obj[i]);
  4704. }
  4705. }
  4706. return t; // Array
  4707. },
  4708. filterIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){
  4709. // summary: creates new object with all attributes that pass the test
  4710. // implemented by the provided function.
  4711. o = o || d.global; f = df.lambda(f);
  4712. var t = {}, v, i;
  4713. for(i in obj){
  4714. if(!(i in empty)){
  4715. v = obj[i];
  4716. if(f.call(o, v, i, obj)){ t[i] = v; }
  4717. }
  4718. }
  4719. return t; // Object
  4720. },
  4721. forIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){
  4722. // summary: iterates over all object attributes.
  4723. o = o || d.global; f = df.lambda(f);
  4724. for(var i in obj){
  4725. if(!(i in empty)){
  4726. f.call(o, obj[i], i, obj);
  4727. }
  4728. }
  4729. return o; // Object
  4730. },
  4731. mapIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){
  4732. // summary: creates new object with the results of calling
  4733. // a provided function on every attribute in this object.
  4734. o = o || d.global; f = df.lambda(f);
  4735. var t = {}, i;
  4736. for(i in obj){
  4737. if(!(i in empty)){
  4738. t[i] = f.call(o, obj[i], i, obj);
  4739. }
  4740. }
  4741. return t; // Object
  4742. }
  4743. });
  4744. })();
  4745. }
  4746. if(!dojo._hasResource["dojox.lang.functional"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4747. dojo._hasResource["dojox.lang.functional"] = true;
  4748. dojo.provide("dojox.lang.functional");
  4749. }
  4750. if(!dojo._hasResource["dojox.lang.functional.fold"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4751. dojo._hasResource["dojox.lang.functional.fold"] = true;
  4752. dojo.provide("dojox.lang.functional.fold");
  4753. // This module adds high-level functions and related constructs:
  4754. // - "fold" family of functions
  4755. // Notes:
  4756. // - missing high-level functions are provided with the compatible API:
  4757. // foldl, foldl1, foldr, foldr1
  4758. // - missing JS standard functions are provided with the compatible API:
  4759. // reduce, reduceRight
  4760. // - the fold's counterpart: unfold
  4761. // Defined methods:
  4762. // - take any valid lambda argument as the functional argument
  4763. // - operate on dense arrays
  4764. // - take a string as the array argument
  4765. // - take an iterator objects as the array argument (only foldl, foldl1, and reduce)
  4766. (function(){
  4767. var d = dojo, df = dojox.lang.functional, empty = {};
  4768. d.mixin(df, {
  4769. // classic reduce-class functions
  4770. foldl: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object*/ z, /*Object?*/ o){
  4771. // summary: repeatedly applies a binary function to an array from left
  4772. // to right using a seed value as a starting point; returns the final
  4773. // value.
  4774. if(typeof a == "string"){ a = a.split(""); }
  4775. o = o || d.global; f = df.lambda(f);
  4776. var i, n;
  4777. if(d.isArray(a)){
  4778. // array
  4779. for(i = 0, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i);
  4780. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4781. // iterator
  4782. for(i = 0; a.hasNext(); z = f.call(o, z, a.next(), i++, a));
  4783. }else{
  4784. // object/dictionary
  4785. for(i in a){
  4786. if(!(i in empty)){
  4787. z = f.call(o, z, a[i], i, a);
  4788. }
  4789. }
  4790. }
  4791. return z; // Object
  4792. },
  4793. foldl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4794. // summary: repeatedly applies a binary function to an array from left
  4795. // to right; returns the final value.
  4796. if(typeof a == "string"){ a = a.split(""); }
  4797. o = o || d.global; f = df.lambda(f);
  4798. var z, i, n;
  4799. if(d.isArray(a)){
  4800. // array
  4801. z = a[0];
  4802. for(i = 1, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i);
  4803. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  4804. // iterator
  4805. if(a.hasNext()){
  4806. z = a.next();
  4807. for(i = 1; a.hasNext(); z = f.call(o, z, a.next(), i++, a));
  4808. }
  4809. }else{
  4810. // object/dictionary
  4811. var first = true;
  4812. for(i in a){
  4813. if(!(i in empty)){
  4814. if(first){
  4815. z = a[i];
  4816. first = false;
  4817. }else{
  4818. z = f.call(o, z, a[i], i, a);
  4819. }
  4820. }
  4821. }
  4822. }
  4823. return z; // Object
  4824. },
  4825. foldr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  4826. // summary: repeatedly applies a binary function to an array from right
  4827. // to left using a seed value as a starting point; returns the final
  4828. // value.
  4829. if(typeof a == "string"){ a = a.split(""); }
  4830. o = o || d.global; f = df.lambda(f);
  4831. for(var i = a.length; i > 0; --i, z = f.call(o, z, a[i], i, a));
  4832. return z; // Object
  4833. },
  4834. foldr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4835. // summary: repeatedly applies a binary function to an array from right
  4836. // to left; returns the final value.
  4837. if(typeof a == "string"){ a = a.split(""); }
  4838. o = o || d.global; f = df.lambda(f);
  4839. var n = a.length, z = a[n - 1], i = n - 1;
  4840. for(; i > 0; --i, z = f.call(o, z, a[i], i, a));
  4841. return z; // Object
  4842. },
  4843. // JS 1.8 standard array functions, which can take a lambda as a parameter.
  4844. reduce: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ z){
  4845. // summary: apply a function simultaneously against two values of the array
  4846. // (from left-to-right) as to reduce it to a single value.
  4847. return arguments.length < 3 ? df.foldl1(a, f) : df.foldl(a, f, z); // Object
  4848. },
  4849. reduceRight: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ z){
  4850. // summary: apply a function simultaneously against two values of the array
  4851. // (from right-to-left) as to reduce it to a single value.
  4852. return arguments.length < 3 ? df.foldr1(a, f) : df.foldr(a, f, z); // Object
  4853. },
  4854. // the fold's counterpart: unfold
  4855. unfold: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f,
  4856. /*Function|String|Array*/ g, /*Object*/ z, /*Object?*/ o){
  4857. // summary: builds an array by unfolding a value
  4858. o = o || d.global; f = df.lambda(f); g = df.lambda(g); pr = df.lambda(pr);
  4859. var t = [];
  4860. for(; !pr.call(o, z); t.push(f.call(o, z)), z = g.call(o, z));
  4861. return t; // Array
  4862. }
  4863. });
  4864. })();
  4865. }
  4866. if(!dojo._hasResource["dojox.lang.functional.reversed"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4867. dojo._hasResource["dojox.lang.functional.reversed"] = true;
  4868. dojo.provide("dojox.lang.functional.reversed");
  4869. // This module adds high-level functions and related constructs:
  4870. // - reversed versions of array-processing functions similar to standard JS functions
  4871. // Notes:
  4872. // - this module provides reversed versions of standard array-processing functions:
  4873. // forEachRev, mapRev, filterRev
  4874. // Defined methods:
  4875. // - take any valid lambda argument as the functional argument
  4876. // - operate on dense arrays
  4877. // - take a string as the array argument
  4878. (function(){
  4879. var d = dojo, df = dojox.lang.functional;
  4880. d.mixin(df, {
  4881. // JS 1.6 standard array functions, which can take a lambda as a parameter.
  4882. // Consider using dojo._base.array functions, if you don't need the lambda support.
  4883. filterRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4884. // summary: creates a new array with all elements that pass the test
  4885. // implemented by the provided function.
  4886. if(typeof a == "string"){ a = a.split(""); }
  4887. o = o || d.global; f = df.lambda(f);
  4888. var t = [], v, i = a.length - 1;
  4889. for(; i >= 0; --i){
  4890. v = a[i];
  4891. if(f.call(o, v, i, a)){ t.push(v); }
  4892. }
  4893. return t; // Array
  4894. },
  4895. forEachRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4896. // summary: executes a provided function once per array element.
  4897. if(typeof a == "string"){ a = a.split(""); }
  4898. o = o || d.global; f = df.lambda(f);
  4899. for(var i = a.length - 1; i >= 0; f.call(o, a[i], i, a), --i);
  4900. },
  4901. mapRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4902. // summary: creates a new array with the results of calling
  4903. // a provided function on every element in this array.
  4904. if(typeof a == "string"){ a = a.split(""); }
  4905. o = o || d.global; f = df.lambda(f);
  4906. var n = a.length, t = new Array(n), i = n - 1, j = 0;
  4907. for(; i >= 0; t[j++] = f.call(o, a[i], i, a), --i);
  4908. return t; // Array
  4909. },
  4910. everyRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4911. // summary: tests whether all elements in the array pass the test
  4912. // implemented by the provided function.
  4913. if(typeof a == "string"){ a = a.split(""); }
  4914. o = o || d.global; f = df.lambda(f);
  4915. for(var i = a.length - 1; i >= 0; --i){
  4916. if(!f.call(o, a[i], i, a)){
  4917. return false; // Boolean
  4918. }
  4919. }
  4920. return true; // Boolean
  4921. },
  4922. someRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  4923. // summary: tests whether some element in the array passes the test
  4924. // implemented by the provided function.
  4925. if(typeof a == "string"){ a = a.split(""); }
  4926. o = o || d.global; f = df.lambda(f);
  4927. for(var i = a.length - 1; i >= 0; --i){
  4928. if(f.call(o, a[i], i, a)){
  4929. return true; // Boolean
  4930. }
  4931. }
  4932. return false; // Boolean
  4933. }
  4934. });
  4935. })();
  4936. }
  4937. if(!dojo._hasResource["dojox.charting.Element"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  4938. dojo._hasResource["dojox.charting.Element"] = true;
  4939. dojo.provide("dojox.charting.Element");
  4940. dojo.declare("dojox.charting.Element", null, {
  4941. // summary:
  4942. // A base class that is used to build other elements of a chart, such as
  4943. // a series.
  4944. // chart: dojox.charting.Chart2D
  4945. // The parent chart for this element.
  4946. // group: dojox.gfx.Group
  4947. // The visual GFX group representing this element.
  4948. // htmlElement: Array
  4949. // Any DOMNodes used as a part of this element (such as HTML-based labels).
  4950. // dirty: Boolean
  4951. // A flag indicating whether or not this element needs to be rendered.
  4952. chart: null,
  4953. group: null,
  4954. htmlElements: null,
  4955. dirty: true,
  4956. constructor: function(chart){
  4957. // summary:
  4958. // Creates a new charting element.
  4959. // chart: dojox.charting.Chart2D
  4960. // The chart that this element belongs to.
  4961. this.chart = chart;
  4962. this.group = null;
  4963. this.htmlElements = [];
  4964. this.dirty = true;
  4965. this.trailingSymbol = "...";
  4966. this._events = [];
  4967. },
  4968. createGroup: function(creator){
  4969. // summary:
  4970. // Convenience function to create a new dojox.gfx.Group.
  4971. // creator: dojox.gfx.Surface?
  4972. // An optional surface in which to create this group.
  4973. // returns: dojox.charting.Element
  4974. // A reference to this object for functional chaining.
  4975. if(!creator){ creator = this.chart.surface; }
  4976. if(!this.group){
  4977. this.group = creator.createGroup();
  4978. }
  4979. return this; // dojox.charting.Element
  4980. },
  4981. purgeGroup: function(){
  4982. // summary:
  4983. // Clear any elements out of our group, and destroy the group.
  4984. // returns: dojox.charting.Element
  4985. // A reference to this object for functional chaining.
  4986. this.destroyHtmlElements();
  4987. if(this.group){
  4988. this.group.clear();
  4989. this.group.removeShape();
  4990. this.group = null;
  4991. }
  4992. this.dirty = true;
  4993. if(this._events.length){
  4994. dojo.forEach(this._events, function(item){
  4995. item.shape.disconnect(item.handle);
  4996. });
  4997. this._events = [];
  4998. }
  4999. return this; // dojox.charting.Element
  5000. },
  5001. cleanGroup: function(creator){
  5002. // summary:
  5003. // Clean any elements (HTML or GFX-based) out of our group, and create a new one.
  5004. // creator: dojox.gfx.Surface?
  5005. // An optional surface to work with.
  5006. // returns: dojox.charting.Element
  5007. // A reference to this object for functional chaining.
  5008. this.destroyHtmlElements();
  5009. if(!creator){ creator = this.chart.surface; }
  5010. if(this.group){
  5011. this.group.clear();
  5012. }else{
  5013. this.group = creator.createGroup();
  5014. }
  5015. this.dirty = true;
  5016. return this; // dojox.charting.Element
  5017. },
  5018. destroyHtmlElements: function(){
  5019. // summary:
  5020. // Destroy any DOMNodes that may have been created as a part of this element.
  5021. if(this.htmlElements.length){
  5022. dojo.forEach(this.htmlElements, dojo.destroy);
  5023. this.htmlElements = [];
  5024. }
  5025. },
  5026. destroy: function(){
  5027. // summary:
  5028. // API addition to conform to the rest of the Dojo Toolkit's standard.
  5029. this.purgeGroup();
  5030. },
  5031. //text utilities
  5032. getTextWidth: function(s, font){
  5033. return dojox.gfx._base._getTextBox(s, {font: font}).w || 0;
  5034. },
  5035. getTextWithLimitLength: function(s, font, limitWidth, truncated){
  5036. // summary:
  5037. // Get the truncated string based on the limited width in px(dichotomy algorithm)
  5038. // s: String?
  5039. // candidate text.
  5040. // font: String?
  5041. // text's font style.
  5042. // limitWidth: Number?
  5043. // text limited width in px.
  5044. // truncated: Boolean?
  5045. // whether the input text(s) has already been truncated.
  5046. // returns: Object
  5047. // {
  5048. // text: processed text, maybe truncated or not
  5049. // truncated: whether text has been truncated
  5050. // }
  5051. if (!s || s.length <= 0) {
  5052. return {
  5053. text: "",
  5054. truncated: truncated || false
  5055. };
  5056. }
  5057. if(!limitWidth || limitWidth <= 0){
  5058. return {
  5059. text: s,
  5060. truncated: truncated || false
  5061. };
  5062. }
  5063. var delta = 2,
  5064. //golden section for dichotomy algorithm
  5065. trucPercentage = 0.618,
  5066. minStr = s.substring(0,1) + this.trailingSymbol,
  5067. minWidth = this.getTextWidth(minStr, font);
  5068. if (limitWidth <= minWidth) {
  5069. return {
  5070. text: minStr,
  5071. truncated: true
  5072. };
  5073. }
  5074. var width = this.getTextWidth(s, font);
  5075. if(width <= limitWidth){
  5076. return {
  5077. text: s,
  5078. truncated: truncated || false
  5079. };
  5080. }else{
  5081. var begin = 0,
  5082. end = s.length;
  5083. while(begin < end){
  5084. if(end - begin <= delta ){
  5085. while (this.getTextWidth(s.substring(0, begin) + this.trailingSymbol, font) > limitWidth) {
  5086. begin -= 1;
  5087. }
  5088. return {
  5089. text: (s.substring(0,begin) + this.trailingSymbol),
  5090. truncated: true
  5091. };
  5092. }
  5093. var index = begin + Math.round((end - begin) * trucPercentage),
  5094. widthIntercepted = this.getTextWidth(s.substring(0, index), font);
  5095. if(widthIntercepted < limitWidth){
  5096. begin = index;
  5097. end = end;
  5098. }else{
  5099. begin = begin;
  5100. end = index;
  5101. }
  5102. }
  5103. }
  5104. },
  5105. getTextWithLimitCharCount: function(s, font, wcLimit, truncated){
  5106. // summary:
  5107. // Get the truncated string based on the limited character count(dichotomy algorithm)
  5108. // s: String?
  5109. // candidate text.
  5110. // font: String?
  5111. // text's font style.
  5112. // wcLimit: Number?
  5113. // text limited character count.
  5114. // truncated: Boolean?
  5115. // whether the input text(s) has already been truncated.
  5116. // returns: Object
  5117. // {
  5118. // text: processed text, maybe truncated or not
  5119. // truncated: whether text has been truncated
  5120. // }
  5121. if (!s || s.length <= 0) {
  5122. return {
  5123. text: "",
  5124. truncated: truncated || false
  5125. };
  5126. }
  5127. if(!wcLimit || wcLimit <= 0 || s.length <= wcLimit){
  5128. return {
  5129. text: s,
  5130. truncated: truncated || false
  5131. };
  5132. }
  5133. return {
  5134. text: s.substring(0, wcLimit) + this.trailingSymbol,
  5135. truncated: true
  5136. };
  5137. },
  5138. // fill utilities
  5139. _plotFill: function(fill, dim, offsets){
  5140. // process a plot-wide fill
  5141. if(!fill || !fill.type || !fill.space){
  5142. return fill;
  5143. }
  5144. var space = fill.space;
  5145. switch(fill.type){
  5146. case "linear":
  5147. if(space === "plot" || space === "shapeX" || space === "shapeY"){
  5148. // clone a fill so we can modify properly directly
  5149. fill = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill);
  5150. fill.space = space;
  5151. // process dimensions
  5152. if(space === "plot" || space === "shapeX"){
  5153. // process Y
  5154. var span = dim.height - offsets.t - offsets.b;
  5155. fill.y1 = offsets.t + span * fill.y1 / 100;
  5156. fill.y2 = offsets.t + span * fill.y2 / 100;
  5157. }
  5158. if(space === "plot" || space === "shapeY"){
  5159. // process X
  5160. var span = dim.width - offsets.l - offsets.r;
  5161. fill.x1 = offsets.l + span * fill.x1 / 100;
  5162. fill.x2 = offsets.l + span * fill.x2 / 100;
  5163. }
  5164. }
  5165. break;
  5166. case "radial":
  5167. if(space === "plot"){
  5168. // this one is used exclusively for scatter charts
  5169. // clone a fill so we can modify properly directly
  5170. fill = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
  5171. fill.space = space;
  5172. // process both dimensions
  5173. var spanX = dim.width - offsets.l - offsets.r,
  5174. spanY = dim.height - offsets.t - offsets.b;
  5175. fill.cx = offsets.l + spanX * fill.cx / 100;
  5176. fill.cy = offsets.t + spanY * fill.cy / 100;
  5177. fill.r = fill.r * Math.sqrt(spanX * spanX + spanY * spanY) / 200;
  5178. }
  5179. break;
  5180. case "pattern":
  5181. if(space === "plot" || space === "shapeX" || space === "shapeY"){
  5182. // clone a fill so we can modify properly directly
  5183. fill = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
  5184. fill.space = space;
  5185. // process dimensions
  5186. if(space === "plot" || space === "shapeX"){
  5187. // process Y
  5188. var span = dim.height - offsets.t - offsets.b;
  5189. fill.y = offsets.t + span * fill.y / 100;
  5190. fill.height = span * fill.height / 100;
  5191. }
  5192. if(space === "plot" || space === "shapeY"){
  5193. // process X
  5194. var span = dim.width - offsets.l - offsets.r;
  5195. fill.x = offsets.l + span * fill.x / 100;
  5196. fill.width = span * fill.width / 100;
  5197. }
  5198. }
  5199. break;
  5200. }
  5201. return fill;
  5202. },
  5203. _shapeFill: function(fill, bbox){
  5204. // process shape-specific fill
  5205. if(!fill || !fill.space){
  5206. return fill;
  5207. }
  5208. var space = fill.space;
  5209. switch(fill.type){
  5210. case "linear":
  5211. if(space === "shape" || space === "shapeX" || space === "shapeY"){
  5212. // clone a fill so we can modify properly directly
  5213. fill = dojox.gfx.makeParameters(dojox.gfx.defaultLinearGradient, fill);
  5214. fill.space = space;
  5215. // process dimensions
  5216. if(space === "shape" || space === "shapeX"){
  5217. // process X
  5218. var span = bbox.width;
  5219. fill.x1 = bbox.x + span * fill.x1 / 100;
  5220. fill.x2 = bbox.x + span * fill.x2 / 100;
  5221. }
  5222. if(space === "shape" || space === "shapeY"){
  5223. // process Y
  5224. var span = bbox.height;
  5225. fill.y1 = bbox.y + span * fill.y1 / 100;
  5226. fill.y2 = bbox.y + span * fill.y2 / 100;
  5227. }
  5228. }
  5229. break;
  5230. case "radial":
  5231. if(space === "shape"){
  5232. // this one is used exclusively for bubble charts and pie charts
  5233. // clone a fill so we can modify properly directly
  5234. fill = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
  5235. fill.space = space;
  5236. // process both dimensions
  5237. fill.cx = bbox.x + bbox.width / 2;
  5238. fill.cy = bbox.y + bbox.height / 2;
  5239. fill.r = fill.r * bbox.width / 200;
  5240. }
  5241. break;
  5242. case "pattern":
  5243. if(space === "shape" || space === "shapeX" || space === "shapeY"){
  5244. // clone a fill so we can modify properly directly
  5245. fill = dojox.gfx.makeParameters(dojox.gfx.defaultPattern, fill);
  5246. fill.space = space;
  5247. // process dimensions
  5248. if(space === "shape" || space === "shapeX"){
  5249. // process X
  5250. var span = bbox.width;
  5251. fill.x = bbox.x + span * fill.x / 100;
  5252. fill.width = span * fill.width / 100;
  5253. }
  5254. if(space === "shape" || space === "shapeY"){
  5255. // process Y
  5256. var span = bbox.height;
  5257. fill.y = bbox.y + span * fill.y / 100;
  5258. fill.height = span * fill.height / 100;
  5259. }
  5260. }
  5261. break;
  5262. }
  5263. return fill;
  5264. },
  5265. _pseudoRadialFill: function(fill, center, radius, start, end){
  5266. // process pseudo-radial fills
  5267. if(!fill || fill.type !== "radial" || fill.space !== "shape"){
  5268. return fill;
  5269. }
  5270. // clone and normalize fill
  5271. var space = fill.space;
  5272. fill = dojox.gfx.makeParameters(dojox.gfx.defaultRadialGradient, fill);
  5273. fill.space = space;
  5274. if(arguments.length < 4){
  5275. // process both dimensions
  5276. fill.cx = center.x;
  5277. fill.cy = center.y;
  5278. fill.r = fill.r * radius / 100;
  5279. return fill;
  5280. }
  5281. // convert to a linear gradient
  5282. var angle = arguments.length < 5 ? start : (end + start) / 2;
  5283. return {
  5284. type: "linear",
  5285. x1: center.x,
  5286. y1: center.y,
  5287. x2: center.x + fill.r * radius * Math.cos(angle) / 100,
  5288. y2: center.y + fill.r * radius * Math.sin(angle) / 100,
  5289. colors: fill.colors
  5290. };
  5291. return fill;
  5292. }
  5293. });
  5294. }
  5295. if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  5296. dojo._hasResource["dojo.colors"] = true;
  5297. dojo.provide("dojo.colors");
  5298. dojo.getObject("colors", true, dojo);
  5299. //TODO: this module appears to break naming conventions
  5300. /*=====
  5301. dojo.colors = {
  5302. // summary: Color utilities
  5303. }
  5304. =====*/
  5305. (function(){
  5306. // this is a standard conversion prescribed by the CSS3 Color Module
  5307. var hue2rgb = function(m1, m2, h){
  5308. if(h < 0){ ++h; }
  5309. if(h > 1){ --h; }
  5310. var h6 = 6 * h;
  5311. if(h6 < 1){ return m1 + (m2 - m1) * h6; }
  5312. if(2 * h < 1){ return m2; }
  5313. if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
  5314. return m1;
  5315. };
  5316. dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
  5317. // summary:
  5318. // get rgb(a) array from css-style color declarations
  5319. // description:
  5320. // this function can handle all 4 CSS3 Color Module formats: rgb,
  5321. // rgba, hsl, hsla, including rgb(a) with percentage values.
  5322. var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
  5323. if(m){
  5324. var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a;
  5325. if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
  5326. var r = c[0];
  5327. if(r.charAt(r.length - 1) == "%"){
  5328. // 3 rgb percentage values
  5329. a = dojo.map(c, function(x){
  5330. return parseFloat(x) * 2.56;
  5331. });
  5332. if(l == 4){ a[3] = c[3]; }
  5333. return dojo.colorFromArray(a, obj); // dojo.Color
  5334. }
  5335. return dojo.colorFromArray(c, obj); // dojo.Color
  5336. }
  5337. if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
  5338. // normalize hsl values
  5339. var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
  5340. S = parseFloat(c[1]) / 100,
  5341. L = parseFloat(c[2]) / 100,
  5342. // calculate rgb according to the algorithm
  5343. // recommended by the CSS3 Color Module
  5344. m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S,
  5345. m1 = 2 * L - m2;
  5346. a = [
  5347. hue2rgb(m1, m2, H + 1 / 3) * 256,
  5348. hue2rgb(m1, m2, H) * 256,
  5349. hue2rgb(m1, m2, H - 1 / 3) * 256,
  5350. 1
  5351. ];
  5352. if(l == 4){ a[3] = c[3]; }
  5353. return dojo.colorFromArray(a, obj); // dojo.Color
  5354. }
  5355. }
  5356. return null; // dojo.Color
  5357. };
  5358. var confine = function(c, low, high){
  5359. // summary:
  5360. // sanitize a color component by making sure it is a number,
  5361. // and clamping it to valid values
  5362. c = Number(c);
  5363. return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number
  5364. };
  5365. dojo.Color.prototype.sanitize = function(){
  5366. // summary: makes sure that the object has correct attributes
  5367. var t = this;
  5368. t.r = Math.round(confine(t.r, 0, 255));
  5369. t.g = Math.round(confine(t.g, 0, 255));
  5370. t.b = Math.round(confine(t.b, 0, 255));
  5371. t.a = confine(t.a, 0, 1);
  5372. return this; // dojo.Color
  5373. };
  5374. })();
  5375. dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){
  5376. // summary: creates a greyscale color with an optional alpha
  5377. return dojo.colorFromArray([g, g, g, a]);
  5378. };
  5379. // mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
  5380. dojo.mixin(dojo.Color.named, {
  5381. aliceblue: [240,248,255],
  5382. antiquewhite: [250,235,215],
  5383. aquamarine: [127,255,212],
  5384. azure: [240,255,255],
  5385. beige: [245,245,220],
  5386. bisque: [255,228,196],
  5387. blanchedalmond: [255,235,205],
  5388. blueviolet: [138,43,226],
  5389. brown: [165,42,42],
  5390. burlywood: [222,184,135],
  5391. cadetblue: [95,158,160],
  5392. chartreuse: [127,255,0],
  5393. chocolate: [210,105,30],
  5394. coral: [255,127,80],
  5395. cornflowerblue: [100,149,237],
  5396. cornsilk: [255,248,220],
  5397. crimson: [220,20,60],
  5398. cyan: [0,255,255],
  5399. darkblue: [0,0,139],
  5400. darkcyan: [0,139,139],
  5401. darkgoldenrod: [184,134,11],
  5402. darkgray: [169,169,169],
  5403. darkgreen: [0,100,0],
  5404. darkgrey: [169,169,169],
  5405. darkkhaki: [189,183,107],
  5406. darkmagenta: [139,0,139],
  5407. darkolivegreen: [85,107,47],
  5408. darkorange: [255,140,0],
  5409. darkorchid: [153,50,204],
  5410. darkred: [139,0,0],
  5411. darksalmon: [233,150,122],
  5412. darkseagreen: [143,188,143],
  5413. darkslateblue: [72,61,139],
  5414. darkslategray: [47,79,79],
  5415. darkslategrey: [47,79,79],
  5416. darkturquoise: [0,206,209],
  5417. darkviolet: [148,0,211],
  5418. deeppink: [255,20,147],
  5419. deepskyblue: [0,191,255],
  5420. dimgray: [105,105,105],
  5421. dimgrey: [105,105,105],
  5422. dodgerblue: [30,144,255],
  5423. firebrick: [178,34,34],
  5424. floralwhite: [255,250,240],
  5425. forestgreen: [34,139,34],
  5426. gainsboro: [220,220,220],
  5427. ghostwhite: [248,248,255],
  5428. gold: [255,215,0],
  5429. goldenrod: [218,165,32],
  5430. greenyellow: [173,255,47],
  5431. grey: [128,128,128],
  5432. honeydew: [240,255,240],
  5433. hotpink: [255,105,180],
  5434. indianred: [205,92,92],
  5435. indigo: [75,0,130],
  5436. ivory: [255,255,240],
  5437. khaki: [240,230,140],
  5438. lavender: [230,230,250],
  5439. lavenderblush: [255,240,245],
  5440. lawngreen: [124,252,0],
  5441. lemonchiffon: [255,250,205],
  5442. lightblue: [173,216,230],
  5443. lightcoral: [240,128,128],
  5444. lightcyan: [224,255,255],
  5445. lightgoldenrodyellow: [250,250,210],
  5446. lightgray: [211,211,211],
  5447. lightgreen: [144,238,144],
  5448. lightgrey: [211,211,211],
  5449. lightpink: [255,182,193],
  5450. lightsalmon: [255,160,122],
  5451. lightseagreen: [32,178,170],
  5452. lightskyblue: [135,206,250],
  5453. lightslategray: [119,136,153],
  5454. lightslategrey: [119,136,153],
  5455. lightsteelblue: [176,196,222],
  5456. lightyellow: [255,255,224],
  5457. limegreen: [50,205,50],
  5458. linen: [250,240,230],
  5459. magenta: [255,0,255],
  5460. mediumaquamarine: [102,205,170],
  5461. mediumblue: [0,0,205],
  5462. mediumorchid: [186,85,211],
  5463. mediumpurple: [147,112,219],
  5464. mediumseagreen: [60,179,113],
  5465. mediumslateblue: [123,104,238],
  5466. mediumspringgreen: [0,250,154],
  5467. mediumturquoise: [72,209,204],
  5468. mediumvioletred: [199,21,133],
  5469. midnightblue: [25,25,112],
  5470. mintcream: [245,255,250],
  5471. mistyrose: [255,228,225],
  5472. moccasin: [255,228,181],
  5473. navajowhite: [255,222,173],
  5474. oldlace: [253,245,230],
  5475. olivedrab: [107,142,35],
  5476. orange: [255,165,0],
  5477. orangered: [255,69,0],
  5478. orchid: [218,112,214],
  5479. palegoldenrod: [238,232,170],
  5480. palegreen: [152,251,152],
  5481. paleturquoise: [175,238,238],
  5482. palevioletred: [219,112,147],
  5483. papayawhip: [255,239,213],
  5484. peachpuff: [255,218,185],
  5485. peru: [205,133,63],
  5486. pink: [255,192,203],
  5487. plum: [221,160,221],
  5488. powderblue: [176,224,230],
  5489. rosybrown: [188,143,143],
  5490. royalblue: [65,105,225],
  5491. saddlebrown: [139,69,19],
  5492. salmon: [250,128,114],
  5493. sandybrown: [244,164,96],
  5494. seagreen: [46,139,87],
  5495. seashell: [255,245,238],
  5496. sienna: [160,82,45],
  5497. skyblue: [135,206,235],
  5498. slateblue: [106,90,205],
  5499. slategray: [112,128,144],
  5500. slategrey: [112,128,144],
  5501. snow: [255,250,250],
  5502. springgreen: [0,255,127],
  5503. steelblue: [70,130,180],
  5504. tan: [210,180,140],
  5505. thistle: [216,191,216],
  5506. tomato: [255,99,71],
  5507. transparent: [0, 0, 0, 0],
  5508. turquoise: [64,224,208],
  5509. violet: [238,130,238],
  5510. wheat: [245,222,179],
  5511. whitesmoke: [245,245,245],
  5512. yellowgreen: [154,205,50]
  5513. });
  5514. }
  5515. if(!dojo._hasResource["dojox.color._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  5516. dojo._hasResource["dojox.color._base"] = true;
  5517. dojo.provide("dojox.color._base");
  5518. // alias all the dojo.Color mechanisms
  5519. dojox.color.Color=dojo.Color;
  5520. dojox.color.blend=dojo.blendColors;
  5521. dojox.color.fromRgb=dojo.colorFromRgb;
  5522. dojox.color.fromHex=dojo.colorFromHex;
  5523. dojox.color.fromArray=dojo.colorFromArray;
  5524. dojox.color.fromString=dojo.colorFromString;
  5525. // alias the dojo.colors mechanisms
  5526. dojox.color.greyscale=dojo.colors.makeGrey;
  5527. // static methods
  5528. dojo.mixin(dojox.color, {
  5529. fromCmy: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow){
  5530. // summary
  5531. // Create a dojox.color.Color from a CMY defined color.
  5532. // All colors should be expressed as 0-100 (percentage)
  5533. if(dojo.isArray(cyan)){
  5534. magenta=cyan[1], yellow=cyan[2], cyan=cyan[0];
  5535. } else if(dojo.isObject(cyan)){
  5536. magenta=cyan.m, yellow=cyan.y, cyan=cyan.c;
  5537. }
  5538. cyan/=100, magenta/=100, yellow/=100;
  5539. var r=1-cyan, g=1-magenta, b=1-yellow;
  5540. return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color
  5541. },
  5542. fromCmyk: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow, /*int*/black){
  5543. // summary
  5544. // Create a dojox.color.Color from a CMYK defined color.
  5545. // All colors should be expressed as 0-100 (percentage)
  5546. if(dojo.isArray(cyan)){
  5547. magenta=cyan[1], yellow=cyan[2], black=cyan[3], cyan=cyan[0];
  5548. } else if(dojo.isObject(cyan)){
  5549. magenta=cyan.m, yellow=cyan.y, black=cyan.b, cyan=cyan.c;
  5550. }
  5551. cyan/=100, magenta/=100, yellow/=100, black/=100;
  5552. var r,g,b;
  5553. r = 1-Math.min(1, cyan*(1-black)+black);
  5554. g = 1-Math.min(1, magenta*(1-black)+black);
  5555. b = 1-Math.min(1, yellow*(1-black)+black);
  5556. return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color
  5557. },
  5558. fromHsl: function(/* Object|Array|int */hue, /* int */saturation, /* int */luminosity){
  5559. // summary
  5560. // Create a dojox.color.Color from an HSL defined color.
  5561. // hue from 0-359 (degrees), saturation and luminosity 0-100.
  5562. if(dojo.isArray(hue)){
  5563. saturation=hue[1], luminosity=hue[2], hue=hue[0];
  5564. } else if(dojo.isObject(hue)){
  5565. saturation=hue.s, luminosity=hue.l, hue=hue.h;
  5566. }
  5567. saturation/=100;
  5568. luminosity/=100;
  5569. while(hue<0){ hue+=360; }
  5570. while(hue>=360){ hue-=360; }
  5571. var r, g, b;
  5572. if(hue<120){
  5573. r=(120-hue)/60, g=hue/60, b=0;
  5574. } else if (hue<240){
  5575. r=0, g=(240-hue)/60, b=(hue-120)/60;
  5576. } else {
  5577. r=(hue-240)/60, g=0, b=(360-hue)/60;
  5578. }
  5579. r=2*saturation*Math.min(r, 1)+(1-saturation);
  5580. g=2*saturation*Math.min(g, 1)+(1-saturation);
  5581. b=2*saturation*Math.min(b, 1)+(1-saturation);
  5582. if(luminosity<0.5){
  5583. r*=luminosity, g*=luminosity, b*=luminosity;
  5584. }else{
  5585. r=(1-luminosity)*r+2*luminosity-1;
  5586. g=(1-luminosity)*g+2*luminosity-1;
  5587. b=(1-luminosity)*b+2*luminosity-1;
  5588. }
  5589. return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color
  5590. },
  5591. fromHsv: function(/* Object|Array|int */hue, /* int */saturation, /* int */value){
  5592. // summary
  5593. // Create a dojox.color.Color from an HSV defined color.
  5594. // hue from 0-359 (degrees), saturation and value 0-100.
  5595. if(dojo.isArray(hue)){
  5596. saturation=hue[1], value=hue[2], hue=hue[0];
  5597. } else if (dojo.isObject(hue)){
  5598. saturation=hue.s, value=hue.v, hue=hue.h;
  5599. }
  5600. if(hue==360){ hue=0; }
  5601. saturation/=100;
  5602. value/=100;
  5603. var r, g, b;
  5604. if(saturation==0){
  5605. r=value, b=value, g=value;
  5606. }else{
  5607. var hTemp=hue/60, i=Math.floor(hTemp), f=hTemp-i;
  5608. var p=value*(1-saturation);
  5609. var q=value*(1-(saturation*f));
  5610. var t=value*(1-(saturation*(1-f)));
  5611. switch(i){
  5612. case 0:{ r=value, g=t, b=p; break; }
  5613. case 1:{ r=q, g=value, b=p; break; }
  5614. case 2:{ r=p, g=value, b=t; break; }
  5615. case 3:{ r=p, g=q, b=value; break; }
  5616. case 4:{ r=t, g=p, b=value; break; }
  5617. case 5:{ r=value, g=p, b=q; break; }
  5618. }
  5619. }
  5620. return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color
  5621. }
  5622. });
  5623. // Conversions directly on dojox.color.Color
  5624. dojo.extend(dojox.color.Color, {
  5625. toCmy: function(){
  5626. // summary
  5627. // Convert this Color to a CMY definition.
  5628. var cyan=1-(this.r/255), magenta=1-(this.g/255), yellow=1-(this.b/255);
  5629. return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100) }; // Object
  5630. },
  5631. toCmyk: function(){
  5632. // summary
  5633. // Convert this Color to a CMYK definition.
  5634. var cyan, magenta, yellow, black;
  5635. var r=this.r/255, g=this.g/255, b=this.b/255;
  5636. black = Math.min(1-r, 1-g, 1-b);
  5637. cyan = (1-r-black)/(1-black);
  5638. magenta = (1-g-black)/(1-black);
  5639. yellow = (1-b-black)/(1-black);
  5640. return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100), b:Math.round(black*100) }; // Object
  5641. },
  5642. toHsl: function(){
  5643. // summary
  5644. // Convert this Color to an HSL definition.
  5645. var r=this.r/255, g=this.g/255, b=this.b/255;
  5646. var min = Math.min(r, b, g), max = Math.max(r, g, b);
  5647. var delta = max-min;
  5648. var h=0, s=0, l=(min+max)/2;
  5649. if(l>0 && l<1){
  5650. s = delta/((l<0.5)?(2*l):(2-2*l));
  5651. }
  5652. if(delta>0){
  5653. if(max==r && max!=g){
  5654. h+=(g-b)/delta;
  5655. }
  5656. if(max==g && max!=b){
  5657. h+=(2+(b-r)/delta);
  5658. }
  5659. if(max==b && max!=r){
  5660. h+=(4+(r-g)/delta);
  5661. }
  5662. h*=60;
  5663. }
  5664. return { h:h, s:Math.round(s*100), l:Math.round(l*100) }; // Object
  5665. },
  5666. toHsv: function(){
  5667. // summary
  5668. // Convert this Color to an HSV definition.
  5669. var r=this.r/255, g=this.g/255, b=this.b/255;
  5670. var min = Math.min(r, b, g), max = Math.max(r, g, b);
  5671. var delta = max-min;
  5672. var h = null, s = (max==0)?0:(delta/max);
  5673. if(s==0){
  5674. h = 0;
  5675. }else{
  5676. if(r==max){
  5677. h = 60*(g-b)/delta;
  5678. }else if(g==max){
  5679. h = 120 + 60*(b-r)/delta;
  5680. }else{
  5681. h = 240 + 60*(r-g)/delta;
  5682. }
  5683. if(h<0){ h+=360; }
  5684. }
  5685. return { h:h, s:Math.round(s*100), v:Math.round(max*100) }; // Object
  5686. }
  5687. });
  5688. }
  5689. if(!dojo._hasResource["dojox.color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  5690. dojo._hasResource["dojox.color"] = true;
  5691. dojo.provide("dojox.color");
  5692. }
  5693. if(!dojo._hasResource["dojox.color.Palette"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  5694. dojo._hasResource["dojox.color.Palette"] = true;
  5695. dojo.provide("dojox.color.Palette");
  5696. (function(){
  5697. var dxc = dojox.color;
  5698. /***************************************************************
  5699. * dojox.color.Palette
  5700. *
  5701. * The Palette object is loosely based on the color palettes
  5702. * at Kuler (http://kuler.adobe.com). They are 5 color palettes
  5703. * with the base color considered to be the third color in the
  5704. * palette (for generation purposes).
  5705. *
  5706. * Palettes can be generated from well-known algorithms or they
  5707. * can be manually created by passing an array to the constructor.
  5708. *
  5709. * Palettes can be transformed, using a set of specific params
  5710. * similar to the way shapes can be transformed with dojox.gfx.
  5711. * However, unlike with transformations in dojox.gfx, transforming
  5712. * a palette will return you a new Palette object, in effect
  5713. * a clone of the original.
  5714. ***************************************************************/
  5715. // ctor ----------------------------------------------------------------------------
  5716. dxc.Palette = function(/* String|Array|dojox.color.Color|dojox.color.Palette */base){
  5717. // summary:
  5718. // An object that represents a palette of colors.
  5719. // description:
  5720. // A Palette is a representation of a set of colors. While the standard
  5721. // number of colors contained in a palette is 5, it can really handle any
  5722. // number of colors.
  5723. //
  5724. // A palette is useful for the ability to transform all the colors in it
  5725. // using a simple object-based approach. In addition, you can generate
  5726. // palettes using dojox.color.Palette.generate; these generated palettes
  5727. // are based on the palette generators at http://kuler.adobe.com.
  5728. //
  5729. // colors: dojox.color.Color[]
  5730. // The actual color references in this palette.
  5731. this.colors = [];
  5732. if(base instanceof dojox.color.Palette){
  5733. this.colors = base.colors.slice(0);
  5734. }
  5735. else if(base instanceof dojox.color.Color){
  5736. this.colors = [ null, null, base, null, null ];
  5737. }
  5738. else if(dojo.isArray(base)){
  5739. this.colors = dojo.map(base.slice(0), function(item){
  5740. if(dojo.isString(item)){ return new dojox.color.Color(item); }
  5741. return item;
  5742. });
  5743. }
  5744. else if (dojo.isString(base)){
  5745. this.colors = [ null, null, new dojox.color.Color(base), null, null ];
  5746. }
  5747. }
  5748. // private functions ---------------------------------------------------------------
  5749. // transformations
  5750. function tRGBA(p, param, val){
  5751. var ret = new dojox.color.Palette();
  5752. ret.colors = [];
  5753. dojo.forEach(p.colors, function(item){
  5754. var r=(param=="dr")?item.r+val:item.r,
  5755. g=(param=="dg")?item.g+val:item.g,
  5756. b=(param=="db")?item.b+val:item.b,
  5757. a=(param=="da")?item.a+val:item.a
  5758. ret.colors.push(new dojox.color.Color({
  5759. r: Math.min(255, Math.max(0, r)),
  5760. g: Math.min(255, Math.max(0, g)),
  5761. b: Math.min(255, Math.max(0, b)),
  5762. a: Math.min(1, Math.max(0, a))
  5763. }));
  5764. });
  5765. return ret;
  5766. }
  5767. function tCMY(p, param, val){
  5768. var ret = new dojox.color.Palette();
  5769. ret.colors = [];
  5770. dojo.forEach(p.colors, function(item){
  5771. var o=item.toCmy(),
  5772. c=(param=="dc")?o.c+val:o.c,
  5773. m=(param=="dm")?o.m+val:o.m,
  5774. y=(param=="dy")?o.y+val:o.y;
  5775. ret.colors.push(dojox.color.fromCmy(
  5776. Math.min(100, Math.max(0, c)),
  5777. Math.min(100, Math.max(0, m)),
  5778. Math.min(100, Math.max(0, y))
  5779. ));
  5780. });
  5781. return ret;
  5782. }
  5783. function tCMYK(p, param, val){
  5784. var ret = new dojox.color.Palette();
  5785. ret.colors = [];
  5786. dojo.forEach(p.colors, function(item){
  5787. var o=item.toCmyk(),
  5788. c=(param=="dc")?o.c+val:o.c,
  5789. m=(param=="dm")?o.m+val:o.m,
  5790. y=(param=="dy")?o.y+val:o.y,
  5791. k=(param=="dk")?o.b+val:o.b;
  5792. ret.colors.push(dojox.color.fromCmyk(
  5793. Math.min(100, Math.max(0, c)),
  5794. Math.min(100, Math.max(0, m)),
  5795. Math.min(100, Math.max(0, y)),
  5796. Math.min(100, Math.max(0, k))
  5797. ));
  5798. });
  5799. return ret;
  5800. }
  5801. function tHSL(p, param, val){
  5802. var ret = new dojox.color.Palette();
  5803. ret.colors = [];
  5804. dojo.forEach(p.colors, function(item){
  5805. var o=item.toHsl(),
  5806. h=(param=="dh")?o.h+val:o.h,
  5807. s=(param=="ds")?o.s+val:o.s,
  5808. l=(param=="dl")?o.l+val:o.l;
  5809. ret.colors.push(dojox.color.fromHsl(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, l))));
  5810. });
  5811. return ret;
  5812. }
  5813. function tHSV(p, param, val){
  5814. var ret = new dojox.color.Palette();
  5815. ret.colors = [];
  5816. dojo.forEach(p.colors, function(item){
  5817. var o=item.toHsv(),
  5818. h=(param=="dh")?o.h+val:o.h,
  5819. s=(param=="ds")?o.s+val:o.s,
  5820. v=(param=="dv")?o.v+val:o.v;
  5821. ret.colors.push(dojox.color.fromHsv(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, v))));
  5822. });
  5823. return ret;
  5824. }
  5825. // helper functions
  5826. function rangeDiff(val, low, high){
  5827. // given the value in a range from 0 to high, find the equiv
  5828. // using the range low to high.
  5829. return high-((high-val)*((high-low)/high));
  5830. }
  5831. // object methods ---------------------------------------------------------------
  5832. dojo.extend(dxc.Palette, {
  5833. transform: function(/* dojox.color.Palette.__transformArgs */kwArgs){
  5834. // summary:
  5835. // Transform the palette using a specific transformation function
  5836. // and a set of transformation parameters.
  5837. // description:
  5838. // {palette}.transform is a simple way to uniformly transform
  5839. // all of the colors in a palette using any of 5 formulae:
  5840. // RGBA, HSL, HSV, CMYK or CMY.
  5841. //
  5842. // Once the forumula to be used is determined, you can pass any
  5843. // number of parameters based on the formula "d"[param]; for instance,
  5844. // { use: "rgba", dr: 20, dg: -50 } will take all of the colors in
  5845. // palette, add 20 to the R value and subtract 50 from the G value.
  5846. //
  5847. // Unlike other types of transformations, transform does *not* alter
  5848. // the original palette but will instead return a new one.
  5849. var fn=tRGBA; // the default transform function.
  5850. if(kwArgs.use){
  5851. // we are being specific about the algo we want to use.
  5852. var use=kwArgs.use.toLowerCase();
  5853. if(use.indexOf("hs")==0){
  5854. if(use.charAt(2)=="l"){ fn=tHSL; }
  5855. else { fn=tHSV; }
  5856. }
  5857. else if(use.indexOf("cmy")==0){
  5858. if(use.charAt(3)=="k"){ fn=tCMYK; }
  5859. else { fn=tCMY; }
  5860. }
  5861. }
  5862. // try to guess the best choice.
  5863. else if("dc" in kwArgs || "dm" in kwArgs || "dy" in kwArgs){
  5864. if("dk" in kwArgs){ fn = tCMYK; }
  5865. else { fn = tCMY; }
  5866. }
  5867. else if("dh" in kwArgs || "ds" in kwArgs){
  5868. if("dv" in kwArgs){ fn = tHSV; }
  5869. else { fn = tHSL; }
  5870. }
  5871. var palette = this;
  5872. for(var p in kwArgs){
  5873. // ignore use
  5874. if(p=="use"){ continue; }
  5875. palette = fn(palette, p, kwArgs[p]);
  5876. }
  5877. return palette; // dojox.color.Palette
  5878. },
  5879. clone: function(){
  5880. // summary:
  5881. // Clones the current palette.
  5882. return new dxc.Palette(this); // dojox.color.Palette
  5883. }
  5884. });
  5885. /*=====
  5886. dojox.color.Palette.__transformArgs = function(use, dr, dg, db, da, dc, dm, dy, dk, dh, ds, dv, dl){
  5887. // summary:
  5888. // The keywords argument to be passed to the dojox.color.Palette.transform function. Note that
  5889. // while all arguments are optional, *some* arguments must be passed. The basic concept is that
  5890. // you pass a delta value for a specific aspect of a color model (or multiple aspects of the same
  5891. // color model); for instance, if you wish to transform a palette based on the HSV color model,
  5892. // you would pass one of "dh", "ds", or "dv" as a value.
  5893. //
  5894. // use: String?
  5895. // Specify the color model to use for the transformation. Can be "rgb", "rgba", "hsv", "hsl", "cmy", "cmyk".
  5896. // dr: Number?
  5897. // The delta to be applied to the red aspect of the RGB/RGBA color model.
  5898. // dg: Number?
  5899. // The delta to be applied to the green aspect of the RGB/RGBA color model.
  5900. // db: Number?
  5901. // The delta to be applied to the blue aspect of the RGB/RGBA color model.
  5902. // da: Number?
  5903. // The delta to be applied to the alpha aspect of the RGBA color model.
  5904. // dc: Number?
  5905. // The delta to be applied to the cyan aspect of the CMY/CMYK color model.
  5906. // dm: Number?
  5907. // The delta to be applied to the magenta aspect of the CMY/CMYK color model.
  5908. // dy: Number?
  5909. // The delta to be applied to the yellow aspect of the CMY/CMYK color model.
  5910. // dk: Number?
  5911. // The delta to be applied to the black aspect of the CMYK color model.
  5912. // dh: Number?
  5913. // The delta to be applied to the hue aspect of the HSL/HSV color model.
  5914. // ds: Number?
  5915. // The delta to be applied to the saturation aspect of the HSL/HSV color model.
  5916. // dl: Number?
  5917. // The delta to be applied to the luminosity aspect of the HSL color model.
  5918. // dv: Number?
  5919. // The delta to be applied to the value aspect of the HSV color model.
  5920. this.use = use;
  5921. this.dr = dr;
  5922. this.dg = dg;
  5923. this.db = db;
  5924. this.da = da;
  5925. this.dc = dc;
  5926. this.dm = dm;
  5927. this.dy = dy;
  5928. this.dk = dk;
  5929. this.dh = dh;
  5930. this.ds = ds;
  5931. this.dl = dl;
  5932. this.dv = dv;
  5933. }
  5934. dojox.color.Palette.__generatorArgs = function(base){
  5935. // summary:
  5936. // The keyword arguments object used to create a palette based on a base color.
  5937. //
  5938. // base: dojo.Color
  5939. // The base color to be used to generate the palette.
  5940. this.base = base;
  5941. }
  5942. dojox.color.Palette.__analogousArgs = function(base, high, low){
  5943. // summary:
  5944. // The keyword arguments object that is used to create a 5 color palette based on the
  5945. // analogous rules as implemented at http://kuler.adobe.com, using the HSV color model.
  5946. //
  5947. // base: dojo.Color
  5948. // The base color to be used to generate the palette.
  5949. // high: Number?
  5950. // The difference between the hue of the base color and the highest hue. In degrees, default is 60.
  5951. // low: Number?
  5952. // The difference between the hue of the base color and the lowest hue. In degrees, default is 18.
  5953. this.base = base;
  5954. this.high = high;
  5955. this.low = low;
  5956. }
  5957. dojox.color.Palette.__splitComplementaryArgs = function(base, da){
  5958. // summary:
  5959. // The keyword arguments object used to create a palette based on the split complementary rules
  5960. // as implemented at http://kuler.adobe.com.
  5961. //
  5962. // base: dojo.Color
  5963. // The base color to be used to generate the palette.
  5964. // da: Number?
  5965. // The delta angle to be used to determine where the split for the complementary rules happen.
  5966. // In degrees, the default is 30.
  5967. this.base = base;
  5968. this.da = da;
  5969. }
  5970. =====*/
  5971. dojo.mixin(dxc.Palette, {
  5972. generators: {
  5973. analogous:function(/* dojox.color.Palette.__analogousArgs */args){
  5974. // summary:
  5975. // Create a 5 color palette based on the analogous rules as implemented at
  5976. // http://kuler.adobe.com.
  5977. var high=args.high||60, // delta between base hue and highest hue (subtracted from base)
  5978. low=args.low||18, // delta between base hue and lowest hue (added to base)
  5979. base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  5980. hsv=base.toHsv();
  5981. // generate our hue angle differences
  5982. var h=[
  5983. (hsv.h+low+360)%360,
  5984. (hsv.h+Math.round(low/2)+360)%360,
  5985. hsv.h,
  5986. (hsv.h-Math.round(high/2)+360)%360,
  5987. (hsv.h-high+360)%360
  5988. ];
  5989. var s1=Math.max(10, (hsv.s<=95)?hsv.s+5:(100-(hsv.s-95))),
  5990. s2=(hsv.s>1)?hsv.s-1:21-hsv.s,
  5991. v1=(hsv.v>=92)?hsv.v-9:Math.max(hsv.v+9, 20),
  5992. v2=(hsv.v<=90)?Math.max(hsv.v+5, 20):(95+Math.ceil((hsv.v-90)/2)),
  5993. s=[ s1, s2, hsv.s, s1, s1 ],
  5994. v=[ v1, v2, hsv.v, v1, v2 ]
  5995. return new dxc.Palette(dojo.map(h, function(hue, i){
  5996. return dojox.color.fromHsv(hue, s[i], v[i]);
  5997. })); // dojox.color.Palette
  5998. },
  5999. monochromatic: function(/* dojox.color.Palette.__generatorArgs */args){
  6000. // summary:
  6001. // Create a 5 color palette based on the monochromatic rules as implemented at
  6002. // http://kuler.adobe.com.
  6003. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6004. hsv = base.toHsv();
  6005. // figure out the saturation and value
  6006. var s1 = (hsv.s-30>9)?hsv.s-30:hsv.s+30,
  6007. s2 = hsv.s,
  6008. v1 = rangeDiff(hsv.v, 20, 100),
  6009. v2 = (hsv.v-20>20)?hsv.v-20:hsv.v+60,
  6010. v3 = (hsv.v-50>20)?hsv.v-50:hsv.v+30;
  6011. return new dxc.Palette([
  6012. dojox.color.fromHsv(hsv.h, s1, v1),
  6013. dojox.color.fromHsv(hsv.h, s2, v3),
  6014. base,
  6015. dojox.color.fromHsv(hsv.h, s1, v3),
  6016. dojox.color.fromHsv(hsv.h, s2, v2)
  6017. ]); // dojox.color.Palette
  6018. },
  6019. triadic: function(/* dojox.color.Palette.__generatorArgs */args){
  6020. // summary:
  6021. // Create a 5 color palette based on the triadic rules as implemented at
  6022. // http://kuler.adobe.com.
  6023. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6024. hsv = base.toHsv();
  6025. var h1 = (hsv.h+57+360)%360,
  6026. h2 = (hsv.h-157+360)%360,
  6027. s1 = (hsv.s>20)?hsv.s-10:hsv.s+10,
  6028. s2 = (hsv.s>90)?hsv.s-10:hsv.s+10,
  6029. s3 = (hsv.s>95)?hsv.s-5:hsv.s+5,
  6030. v1 = (hsv.v-20>20)?hsv.v-20:hsv.v+20,
  6031. v2 = (hsv.v-30>20)?hsv.v-30:hsv.v+30,
  6032. v3 = (hsv.v-30>70)?hsv.v-30:hsv.v+30;
  6033. return new dxc.Palette([
  6034. dojox.color.fromHsv(h1, s1, hsv.v),
  6035. dojox.color.fromHsv(hsv.h, s2, v2),
  6036. base,
  6037. dojox.color.fromHsv(h2, s2, v1),
  6038. dojox.color.fromHsv(h2, s3, v3)
  6039. ]); // dojox.color.Palette
  6040. },
  6041. complementary: function(/* dojox.color.Palette.__generatorArgs */args){
  6042. // summary:
  6043. // Create a 5 color palette based on the complementary rules as implemented at
  6044. // http://kuler.adobe.com.
  6045. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6046. hsv = base.toHsv();
  6047. var h1 = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137,
  6048. s1 = Math.max(hsv.s-10, 0),
  6049. s2 = rangeDiff(hsv.s, 10, 100),
  6050. s3 = Math.min(100, hsv.s+20),
  6051. v1 = Math.min(100, hsv.v+30),
  6052. v2 = (hsv.v>20)?hsv.v-30:hsv.v+30;
  6053. return new dxc.Palette([
  6054. dojox.color.fromHsv(hsv.h, s1, v1),
  6055. dojox.color.fromHsv(hsv.h, s2, v2),
  6056. base,
  6057. dojox.color.fromHsv(h1, s3, v2),
  6058. dojox.color.fromHsv(h1, hsv.s, hsv.v)
  6059. ]); // dojox.color.Palette
  6060. },
  6061. splitComplementary: function(/* dojox.color.Palette.__splitComplementaryArgs */args){
  6062. // summary:
  6063. // Create a 5 color palette based on the split complementary rules as implemented at
  6064. // http://kuler.adobe.com.
  6065. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6066. dangle = args.da || 30,
  6067. hsv = base.toHsv();
  6068. var baseh = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137,
  6069. h1 = (baseh-dangle+360)%360,
  6070. h2 = (baseh+dangle)%360,
  6071. s1 = Math.max(hsv.s-10, 0),
  6072. s2 = rangeDiff(hsv.s, 10, 100),
  6073. s3 = Math.min(100, hsv.s+20),
  6074. v1 = Math.min(100, hsv.v+30),
  6075. v2 = (hsv.v>20)?hsv.v-30:hsv.v+30;
  6076. return new dxc.Palette([
  6077. dojox.color.fromHsv(h1, s1, v1),
  6078. dojox.color.fromHsv(h1, s2, v2),
  6079. base,
  6080. dojox.color.fromHsv(h2, s3, v2),
  6081. dojox.color.fromHsv(h2, hsv.s, hsv.v)
  6082. ]); // dojox.color.Palette
  6083. },
  6084. compound: function(/* dojox.color.Palette.__generatorArgs */args){
  6085. // summary:
  6086. // Create a 5 color palette based on the compound rules as implemented at
  6087. // http://kuler.adobe.com.
  6088. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6089. hsv = base.toHsv();
  6090. var h1 = ((hsv.h*2)+18<360)?(hsv.h*2)+18:Math.floor(hsv.h/2)-18,
  6091. h2 = ((hsv.h*2)+120<360)?(hsv.h*2)+120:Math.floor(hsv.h/2)-120,
  6092. h3 = ((hsv.h*2)+99<360)?(hsv.h*2)+99:Math.floor(hsv.h/2)-99,
  6093. s1 = (hsv.s-40>10)?hsv.s-40:hsv.s+40,
  6094. s2 = (hsv.s-10>80)?hsv.s-10:hsv.s+10,
  6095. s3 = (hsv.s-25>10)?hsv.s-25:hsv.s+25,
  6096. v1 = (hsv.v-40>10)?hsv.v-40:hsv.v+40,
  6097. v2 = (hsv.v-20>80)?hsv.v-20:hsv.v+20,
  6098. v3 = Math.max(hsv.v, 20);
  6099. return new dxc.Palette([
  6100. dojox.color.fromHsv(h1, s1, v1),
  6101. dojox.color.fromHsv(h1, s2, v2),
  6102. base,
  6103. dojox.color.fromHsv(h2, s3, v3),
  6104. dojox.color.fromHsv(h3, s2, v2)
  6105. ]); // dojox.color.Palette
  6106. },
  6107. shades: function(/* dojox.color.Palette.__generatorArgs */args){
  6108. // summary:
  6109. // Create a 5 color palette based on the shades rules as implemented at
  6110. // http://kuler.adobe.com.
  6111. var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base,
  6112. hsv = base.toHsv();
  6113. var s = (hsv.s==100 && hsv.v==0)?0:hsv.s,
  6114. v1 = (hsv.v-50>20)?hsv.v-50:hsv.v+30,
  6115. v2 = (hsv.v-25>=20)?hsv.v-25:hsv.v+55,
  6116. v3 = (hsv.v-75>=20)?hsv.v-75:hsv.v+5,
  6117. v4 = Math.max(hsv.v-10, 20);
  6118. return new dxc.Palette([
  6119. new dojox.color.fromHsv(hsv.h, s, v1),
  6120. new dojox.color.fromHsv(hsv.h, s, v2),
  6121. base,
  6122. new dojox.color.fromHsv(hsv.h, s, v3),
  6123. new dojox.color.fromHsv(hsv.h, s, v4)
  6124. ]); // dojox.color.Palette
  6125. }
  6126. },
  6127. generate: function(/* String|dojox.color.Color */base, /* Function|String */type){
  6128. // summary:
  6129. // Generate a new Palette using any of the named functions in
  6130. // dojox.color.Palette.generators or an optional function definition. Current
  6131. // generators include "analogous", "monochromatic", "triadic", "complementary",
  6132. // "splitComplementary", and "shades".
  6133. if(dojo.isFunction(type)){
  6134. return type({ base: base }); // dojox.color.Palette
  6135. }
  6136. else if(dxc.Palette.generators[type]){
  6137. return dxc.Palette.generators[type]({ base: base }); // dojox.color.Palette
  6138. }
  6139. throw new Error("dojox.color.Palette.generate: the specified generator ('" + type + "') does not exist.");
  6140. }
  6141. });
  6142. })();
  6143. }
  6144. if(!dojo._hasResource["dojox.lang.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  6145. dojo._hasResource["dojox.lang.utils"] = true;
  6146. dojo.provide("dojox.lang.utils");
  6147. (function(){
  6148. var empty = {}, du = dojox.lang.utils, opts = Object.prototype.toString;
  6149. var clone = function(o){
  6150. if(o){
  6151. switch(opts.call(o)){
  6152. case "[object Array]":
  6153. return o.slice(0);
  6154. case "[object Object]":
  6155. return dojo.delegate(o);
  6156. }
  6157. }
  6158. return o;
  6159. }
  6160. dojo.mixin(du, {
  6161. coerceType: function(target, source){
  6162. // summary: Coerces one object to the type of another.
  6163. // target: Object: object, which typeof result is used to coerce "source" object.
  6164. // source: Object: object, which will be forced to change type.
  6165. switch(typeof target){
  6166. case "number": return Number(eval("(" + source + ")"));
  6167. case "string": return String(source);
  6168. case "boolean": return Boolean(eval("(" + source + ")"));
  6169. }
  6170. return eval("(" + source + ")");
  6171. },
  6172. updateWithObject: function(target, source, conv){
  6173. // summary: Updates an existing object in place with properties from an "source" object.
  6174. // target: Object: the "target" object to be updated
  6175. // source: Object: the "source" object, whose properties will be used to source the existed object.
  6176. // conv: Boolean?: force conversion to the original type
  6177. if(!source){ return target; }
  6178. for(var x in target){
  6179. if(x in source && !(x in empty)){
  6180. var t = target[x];
  6181. if(t && typeof t == "object"){
  6182. du.updateWithObject(t, source[x], conv);
  6183. }else{
  6184. target[x] = conv ? du.coerceType(t, source[x]) : clone(source[x]);
  6185. }
  6186. }
  6187. }
  6188. return target; // Object
  6189. },
  6190. updateWithPattern: function(target, source, pattern, conv){
  6191. // summary: Updates an existing object in place with properties from an "source" object.
  6192. // target: Object: the "target" object to be updated
  6193. // source: Object: the "source" object, whose properties will be used to source the existed object.
  6194. // pattern: Object: object, whose properties will be used to pull values from the "source"
  6195. // conv: Boolean?: force conversion to the original type
  6196. if(!source || !pattern){ return target; }
  6197. for(var x in pattern){
  6198. if(x in source && !(x in empty)){
  6199. target[x] = conv ? du.coerceType(pattern[x], source[x]) : clone(source[x]);
  6200. }
  6201. }
  6202. return target; // Object
  6203. },
  6204. merge: function(object, mixin){
  6205. // summary: Merge two objects structurally, mixin properties will override object's properties.
  6206. // object: Object: original object.
  6207. // mixin: Object: additional object, which properties will override object's properties.
  6208. if(mixin){
  6209. var otype = opts.call(object), mtype = opts.call(mixin), t, i, l, m;
  6210. switch(mtype){
  6211. case "[object Array]":
  6212. if(mtype == otype){
  6213. t = new Array(Math.max(object.length, mixin.length));
  6214. for(i = 0, l = t.length; i < l; ++i){
  6215. t[i] = du.merge(object[i], mixin[i]);
  6216. }
  6217. return t;
  6218. }
  6219. return mixin.slice(0);
  6220. case "[object Object]":
  6221. if(mtype == otype && object){
  6222. t = dojo.delegate(object);
  6223. for(i in mixin){
  6224. if(i in object){
  6225. l = object[i];
  6226. m = mixin[i];
  6227. if(m !== l){
  6228. t[i] = du.merge(l, m);
  6229. }
  6230. }else{
  6231. t[i] = dojo.clone(mixin[i]);
  6232. }
  6233. }
  6234. return t;
  6235. }
  6236. return dojo.clone(mixin);
  6237. }
  6238. }
  6239. return mixin;
  6240. }
  6241. });
  6242. })();
  6243. }
  6244. if(!dojo._hasResource["dojox.gfx.gradutils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  6245. dojo._hasResource["dojox.gfx.gradutils"] = true;
  6246. dojo.provide("dojox.gfx.gradutils");
  6247. // Various generic utilities to deal with a linear gradient
  6248. (function(){
  6249. var d = dojo, m = dojox.gfx.matrix, C = d.Color;
  6250. function findColor(o, c){
  6251. if(o <= 0){
  6252. return c[0].color;
  6253. }
  6254. var len = c.length;
  6255. if(o >= 1){
  6256. return c[len - 1].color;
  6257. }
  6258. //TODO: use binary search
  6259. for(var i = 0; i < len; ++i){
  6260. var stop = c[i];
  6261. if(stop.offset >= o){
  6262. if(i){
  6263. var prev = c[i - 1];
  6264. return d.blendColors(new C(prev.color), new C(stop.color),
  6265. (o - prev.offset) / (stop.offset - prev.offset));
  6266. }
  6267. return stop.color;
  6268. }
  6269. }
  6270. return c[len - 1].color;
  6271. }
  6272. dojox.gfx.gradutils.getColor = function(fill, pt){
  6273. // summary:
  6274. // sample a color from a gradient using a point
  6275. // fill: Object:
  6276. // fill object
  6277. // pt: dojox.gfx.Point:
  6278. // point where to sample a color
  6279. var o;
  6280. if(fill){
  6281. switch(fill.type){
  6282. case "linear":
  6283. var angle = Math.atan2(fill.y2 - fill.y1, fill.x2 - fill.x1),
  6284. rotation = m.rotate(-angle),
  6285. projection = m.project(fill.x2 - fill.x1, fill.y2 - fill.y1),
  6286. p = m.multiplyPoint(projection, pt),
  6287. pf1 = m.multiplyPoint(projection, fill.x1, fill.y1),
  6288. pf2 = m.multiplyPoint(projection, fill.x2, fill.y2),
  6289. scale = m.multiplyPoint(rotation, pf2.x - pf1.x, pf2.y - pf1.y).x,
  6290. o = m.multiplyPoint(rotation, p.x - pf1.x, p.y - pf1.y).x / scale;
  6291. break;
  6292. case "radial":
  6293. var dx = pt.x - fill.cx, dy = pt.y - fill.cy,
  6294. o = Math.sqrt(dx * dx + dy * dy) / fill.r;
  6295. break;
  6296. }
  6297. return findColor(o, fill.colors); // dojo.Color
  6298. }
  6299. // simple color
  6300. return new C(fill || [0, 0, 0, 0]); // dojo.Color
  6301. };
  6302. dojox.gfx.gradutils.reverse = function(fill){
  6303. // summary:
  6304. // reverses a gradient
  6305. // fill: Object:
  6306. // fill object
  6307. if(fill){
  6308. switch(fill.type){
  6309. case "linear":
  6310. case "radial":
  6311. fill = dojo.delegate(fill);
  6312. if(fill.colors){
  6313. var c = fill.colors, l = c.length, i = 0, stop,
  6314. n = fill.colors = new Array(c.length);
  6315. for(; i < l; ++i){
  6316. stop = c[i];
  6317. n[i] = {
  6318. offset: 1 - stop.offset,
  6319. color: stop.color
  6320. };
  6321. }
  6322. n.sort(function(a, b){ return a.offset - b.offset; });
  6323. }
  6324. break;
  6325. }
  6326. }
  6327. return fill; // Object
  6328. };
  6329. })();
  6330. }
  6331. if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  6332. dojo._hasResource["dojox.charting.Theme"] = true;
  6333. dojo.provide("dojox.charting.Theme");
  6334. dojo.declare("dojox.charting.Theme", null, {
  6335. // summary:
  6336. // A Theme is a pre-defined object, primarily JSON-based, that makes up the definitions to
  6337. // style a chart.
  6338. //
  6339. // description:
  6340. // While you can set up style definitions on a chart directly (usually through the various add methods
  6341. // on a dojox.charting.Chart2D object), a Theme simplifies this manual setup by allowing you to
  6342. // pre-define all of the various visual parameters of each element in a chart.
  6343. //
  6344. // Most of the properties of a Theme are straight-forward; if something is line-based (such as
  6345. // an axis or the ticks on an axis), they will be defined using basic stroke parameters. Likewise,
  6346. // if an element is primarily block-based (such as the background of a chart), it will be primarily
  6347. // fill-based.
  6348. //
  6349. // In addition (for convenience), a Theme definition does not have to contain the entire JSON-based
  6350. // structure. Each theme is built on top of a default theme (which serves as the basis for the theme
  6351. // "GreySkies"), and is mixed into the default theme object. This allows you to create a theme based,
  6352. // say, solely on colors for data series.
  6353. //
  6354. // Defining a new theme is relatively easy; see any of the themes in dojox.charting.themes for examples
  6355. // on how to define your own.
  6356. //
  6357. // When you set a theme on a chart, the theme itself is deep-cloned. This means that you cannot alter
  6358. // the theme itself after setting the theme value on a chart, and expect it to change your chart. If you
  6359. // are looking to make alterations to a theme for a chart, the suggestion would be to create your own
  6360. // theme, based on the one you want to use, that makes those alterations before it is applied to a chart.
  6361. //
  6362. // Finally, a Theme contains a number of functions to facilitate rendering operations on a chart--the main
  6363. // helper of which is the ~next~ method, in which a chart asks for the information for the next data series
  6364. // to be rendered.
  6365. //
  6366. // A note on colors:
  6367. // The Theme constructor was on the use of dojox.color.Palette (in general) for creating a visually distinct
  6368. // set of colors for usage in a chart. A palette is usually comprised of 5 different color definitions, and
  6369. // no more. If you have a need to render a chart with more than 5 data elements, you can simply "push"
  6370. // new color definitions into the theme's .color array. Make sure that you do that with the actual
  6371. // theme object from a Chart, and not in the theme itself (i.e. either do that before using .setTheme
  6372. // on a chart).
  6373. //
  6374. // example:
  6375. // The default theme (and structure) looks like so:
  6376. // | // all objects are structs used directly in dojox.gfx
  6377. // | chart:{
  6378. // | stroke: null,
  6379. // | fill: "white",
  6380. // | pageStyle: null // suggested page style as an object suitable for dojo.style()
  6381. // | },
  6382. // | plotarea:{
  6383. // | stroke: null,
  6384. // | fill: "white"
  6385. // | },
  6386. // | axis:{
  6387. // | stroke: { // the axis itself
  6388. // | color: "#333",
  6389. // | width: 1
  6390. // | },
  6391. // | tick: { // used as a foundation for all ticks
  6392. // | color: "#666",
  6393. // | position: "center",
  6394. // | font: "normal normal normal 7pt Tahoma", // labels on axis
  6395. // | fontColor: "#333" // color of labels
  6396. // | },
  6397. // | majorTick: { // major ticks on axis, and used for major gridlines
  6398. // | width: 1,
  6399. // | length: 6
  6400. // | },
  6401. // | minorTick: { // minor ticks on axis, and used for minor gridlines
  6402. // | width: 0.8,
  6403. // | length: 3
  6404. // | },
  6405. // | microTick: { // minor ticks on axis, and used for minor gridlines
  6406. // | width: 0.5,
  6407. // | length: 1
  6408. // | }
  6409. // | },
  6410. // | series: {
  6411. // | stroke: {width: 1.5, color: "#333"}, // line
  6412. // | outline: {width: 0.1, color: "#ccc"}, // outline
  6413. // | //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  6414. // | shadow: null, // no shadow
  6415. // | fill: "#ccc", // fill, if appropriate
  6416. // | font: "normal normal normal 8pt Tahoma", // if there's a label
  6417. // | fontColor: "#000" // color of labels
  6418. // | labelWiring: {width: 1, color: "#ccc"}, // connect marker and target data item(slice, column, bar...)
  6419. // | },
  6420. // | marker: { // any markers on a series
  6421. // | symbol: "m-3,3 l3,-6 3,6 z", // symbol
  6422. // | stroke: {width: 1.5, color: "#333"}, // stroke
  6423. // | outline: {width: 0.1, color: "#ccc"}, // outline
  6424. // | shadow: null, // no shadow
  6425. // | fill: "#ccc", // fill if needed
  6426. // | font: "normal normal normal 8pt Tahoma", // label
  6427. // | fontColor: "#000"
  6428. // | }
  6429. //
  6430. // example:
  6431. // Defining a new theme is pretty simple:
  6432. // | dojox.charting.themes.Grasslands = new dojox.charting.Theme({
  6433. // | colors: [ "#70803a", "#dde574", "#788062", "#b1cc5d", "#eff2c2" ]
  6434. // | });
  6435. // |
  6436. // | myChart.setTheme(dojox.charting.themes.Grasslands);
  6437. shapeSpaces: {shape: 1, shapeX: 1, shapeY: 1},
  6438. constructor: function(kwArgs){
  6439. // summary:
  6440. // Initialize a theme using the keyword arguments. Note that the arguments
  6441. // look like the example (above), and may include a few more parameters.
  6442. kwArgs = kwArgs || {};
  6443. // populate theme with defaults updating them if needed
  6444. var def = dojox.charting.Theme.defaultTheme;
  6445. dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(name){
  6446. this[name] = dojo.delegate(def[name], kwArgs[name]);
  6447. }, this);
  6448. // personalize theme
  6449. if(kwArgs.seriesThemes && kwArgs.seriesThemes.length){
  6450. this.colors = null;
  6451. this.seriesThemes = kwArgs.seriesThemes.slice(0);
  6452. }else{
  6453. this.seriesThemes = null;
  6454. this.colors = (kwArgs.colors || dojox.charting.Theme.defaultColors).slice(0);
  6455. }
  6456. this.markerThemes = null;
  6457. if(kwArgs.markerThemes && kwArgs.markerThemes.length){
  6458. this.markerThemes = kwArgs.markerThemes.slice(0);
  6459. }
  6460. this.markers = kwArgs.markers ? dojo.clone(kwArgs.markers) : dojo.delegate(dojox.charting.Theme.defaultMarkers);
  6461. // set flags
  6462. this.noGradConv = kwArgs.noGradConv;
  6463. this.noRadialConv = kwArgs.noRadialConv;
  6464. if(kwArgs.reverseFills){
  6465. this.reverseFills();
  6466. }
  6467. // private housekeeping
  6468. this._current = 0;
  6469. this._buildMarkerArray();
  6470. },
  6471. clone: function(){
  6472. // summary:
  6473. // Clone the current theme.
  6474. // returns: dojox.charting.Theme
  6475. // The cloned theme; any alterations made will not affect the original.
  6476. var theme = new dojox.charting.Theme({
  6477. // theme components
  6478. chart: this.chart,
  6479. plotarea: this.plotarea,
  6480. axis: this.axis,
  6481. series: this.series,
  6482. marker: this.marker,
  6483. // individual arrays
  6484. colors: this.colors,
  6485. markers: this.markers,
  6486. seriesThemes: this.seriesThemes,
  6487. markerThemes: this.markerThemes,
  6488. // flags
  6489. noGradConv: this.noGradConv,
  6490. noRadialConv: this.noRadialConv
  6491. });
  6492. // copy custom methods
  6493. dojo.forEach(
  6494. ["clone", "clear", "next", "skip", "addMixin", "post", "getTick"],
  6495. function(name){
  6496. if(this.hasOwnProperty(name)){
  6497. theme[name] = this[name];
  6498. }
  6499. },
  6500. this
  6501. );
  6502. return theme; // dojox.charting.Theme
  6503. },
  6504. clear: function(){
  6505. // summary:
  6506. // Clear and reset the internal pointer to start fresh.
  6507. this._current = 0;
  6508. },
  6509. next: function(elementType, mixin, doPost){
  6510. // summary:
  6511. // Get the next color or series theme.
  6512. // elementType: String?
  6513. // An optional element type (for use with series themes)
  6514. // mixin: Object?
  6515. // An optional object to mix into the theme.
  6516. // doPost: Boolean?
  6517. // A flag to post-process the results.
  6518. // returns: Object
  6519. // An object of the structure { series, marker, symbol }
  6520. var merge = dojox.lang.utils.merge, series, marker;
  6521. if(this.colors){
  6522. series = dojo.delegate(this.series);
  6523. marker = dojo.delegate(this.marker);
  6524. var color = new dojo.Color(this.colors[this._current % this.colors.length]), old;
  6525. // modify the stroke
  6526. if(series.stroke && series.stroke.color){
  6527. series.stroke = dojo.delegate(series.stroke);
  6528. old = new dojo.Color(series.stroke.color);
  6529. series.stroke.color = new dojo.Color(color);
  6530. series.stroke.color.a = old.a;
  6531. }else{
  6532. series.stroke = {color: color};
  6533. }
  6534. if(marker.stroke && marker.stroke.color){
  6535. marker.stroke = dojo.delegate(marker.stroke);
  6536. old = new dojo.Color(marker.stroke.color);
  6537. marker.stroke.color = new dojo.Color(color);
  6538. marker.stroke.color.a = old.a;
  6539. }else{
  6540. marker.stroke = {color: color};
  6541. }
  6542. // modify the fill
  6543. if(!series.fill || series.fill.type){
  6544. series.fill = color;
  6545. }else{
  6546. old = new dojo.Color(series.fill);
  6547. series.fill = new dojo.Color(color);
  6548. series.fill.a = old.a;
  6549. }
  6550. if(!marker.fill || marker.fill.type){
  6551. marker.fill = color;
  6552. }else{
  6553. old = new dojo.Color(marker.fill);
  6554. marker.fill = new dojo.Color(color);
  6555. marker.fill.a = old.a;
  6556. }
  6557. }else{
  6558. series = this.seriesThemes ?
  6559. merge(this.series, this.seriesThemes[this._current % this.seriesThemes.length]) :
  6560. this.series;
  6561. marker = this.markerThemes ?
  6562. merge(this.marker, this.markerThemes[this._current % this.markerThemes.length]) :
  6563. series;
  6564. }
  6565. var symbol = marker && marker.symbol || this._markers[this._current % this._markers.length];
  6566. var theme = {series: series, marker: marker, symbol: symbol};
  6567. // advance the counter
  6568. ++this._current;
  6569. if(mixin){
  6570. theme = this.addMixin(theme, elementType, mixin);
  6571. }
  6572. if(doPost){
  6573. theme = this.post(theme, elementType);
  6574. }
  6575. return theme; // Object
  6576. },
  6577. skip: function(){
  6578. // summary:
  6579. // Skip the next internal color.
  6580. ++this._current;
  6581. },
  6582. addMixin: function(theme, elementType, mixin, doPost){
  6583. // summary:
  6584. // Add a mixin object to the passed theme and process.
  6585. // theme: dojox.charting.Theme
  6586. // The theme to mixin to.
  6587. // elementType: String
  6588. // The type of element in question. Can be "line", "bar" or "circle"
  6589. // mixin: Object|Array
  6590. // The object or objects to mix into the theme.
  6591. // doPost: Boolean
  6592. // If true, run the new theme through the post-processor.
  6593. // returns: dojox.charting.Theme
  6594. // The new theme.
  6595. if(dojo.isArray(mixin)){
  6596. dojo.forEach(mixin, function(m){
  6597. theme = this.addMixin(theme, elementType, m);
  6598. }, this);
  6599. }else{
  6600. var t = {};
  6601. if("color" in mixin){
  6602. if(elementType == "line" || elementType == "area"){
  6603. dojo.setObject("series.stroke.color", mixin.color, t);
  6604. dojo.setObject("marker.stroke.color", mixin.color, t);
  6605. }else{
  6606. dojo.setObject("series.fill", mixin.color, t);
  6607. }
  6608. }
  6609. dojo.forEach(["stroke", "outline", "shadow", "fill", "font", "fontColor", "labelWiring"], function(name){
  6610. var markerName = "marker" + name.charAt(0).toUpperCase() + name.substr(1),
  6611. b = markerName in mixin;
  6612. if(name in mixin){
  6613. dojo.setObject("series." + name, mixin[name], t);
  6614. if(!b){
  6615. dojo.setObject("marker." + name, mixin[name], t);
  6616. }
  6617. }
  6618. if(b){
  6619. dojo.setObject("marker." + name, mixin[markerName], t);
  6620. }
  6621. });
  6622. if("marker" in mixin){
  6623. t.symbol = mixin.marker;
  6624. }
  6625. theme = dojox.lang.utils.merge(theme, t);
  6626. }
  6627. if(doPost){
  6628. theme = this.post(theme, elementType);
  6629. }
  6630. return theme; // dojox.charting.Theme
  6631. },
  6632. post: function(theme, elementType){
  6633. // summary:
  6634. // Process any post-shape fills.
  6635. // theme: dojox.charting.Theme
  6636. // The theme to post process with.
  6637. // elementType: String
  6638. // The type of element being filled. Can be "bar" or "circle".
  6639. // returns: dojox.charting.Theme
  6640. // The post-processed theme.
  6641. var fill = theme.series.fill, t;
  6642. if(!this.noGradConv && this.shapeSpaces[fill.space] && fill.type == "linear"){
  6643. if(elementType == "bar"){
  6644. // transpose start and end points
  6645. t = {
  6646. x1: fill.y1,
  6647. y1: fill.x1,
  6648. x2: fill.y2,
  6649. y2: fill.x2
  6650. };
  6651. }else if(!this.noRadialConv && fill.space == "shape" && (elementType == "slice" || elementType == "circle")){
  6652. // switch to radial
  6653. t = {
  6654. type: "radial",
  6655. cx: 0,
  6656. cy: 0,
  6657. r: 100
  6658. };
  6659. }
  6660. if(t){
  6661. return dojox.lang.utils.merge(theme, {series: {fill: t}});
  6662. }
  6663. }
  6664. return theme; // dojox.charting.Theme
  6665. },
  6666. getTick: function(name, mixin){
  6667. // summary:
  6668. // Calculates and merges tick parameters.
  6669. // name: String
  6670. // Tick name, can be "major", "minor", or "micro".
  6671. // mixin: Object?
  6672. // Optional object to mix in to the tick.
  6673. var tick = this.axis.tick, tickName = name + "Tick";
  6674. merge = dojox.lang.utils.merge;
  6675. if(tick){
  6676. if(this.axis[tickName]){
  6677. tick = merge(tick, this.axis[tickName]);
  6678. }
  6679. }else{
  6680. tick = this.axis[tickName];
  6681. }
  6682. if(mixin){
  6683. if(tick){
  6684. if(mixin[tickName]){
  6685. tick = merge(tick, mixin[tickName]);
  6686. }
  6687. }else{
  6688. tick = mixin[tickName];
  6689. }
  6690. }
  6691. return tick; // Object
  6692. },
  6693. inspectObjects: function(f){
  6694. dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(name){
  6695. f(this[name]);
  6696. }, this);
  6697. if(this.seriesThemes){
  6698. dojo.forEach(this.seriesThemes, f);
  6699. }
  6700. if(this.markerThemes){
  6701. dojo.forEach(this.markerThemes, f);
  6702. }
  6703. },
  6704. reverseFills: function(){
  6705. this.inspectObjects(function(o){
  6706. if(o && o.fill){
  6707. o.fill = dojox.gfx.gradutils.reverse(o.fill);
  6708. }
  6709. });
  6710. },
  6711. addMarker:function(/*String*/ name, /*String*/ segment){
  6712. // summary:
  6713. // Add a custom marker to this theme.
  6714. // example:
  6715. // | myTheme.addMarker("Ellipse", foo);
  6716. this.markers[name] = segment;
  6717. this._buildMarkerArray();
  6718. },
  6719. setMarkers:function(/*Object*/ obj){
  6720. // summary:
  6721. // Set all the markers of this theme at once. obj should be a
  6722. // dictionary of keys and path segments.
  6723. //
  6724. // example:
  6725. // | myTheme.setMarkers({ "CIRCLE": foo });
  6726. this.markers = obj;
  6727. this._buildMarkerArray();
  6728. },
  6729. _buildMarkerArray: function(){
  6730. this._markers = [];
  6731. for(var p in this.markers){
  6732. this._markers.push(this.markers[p]);
  6733. }
  6734. }
  6735. });
  6736. /*=====
  6737. dojox.charting.Theme.__DefineColorArgs = function(num, colors, hue, saturation, low, high, base, generator){
  6738. // summary:
  6739. // The arguments object that can be passed to define colors for a theme.
  6740. // num: Number?
  6741. // The number of colors to generate. Defaults to 5.
  6742. // colors: String[]|dojo.Color[]?
  6743. // A pre-defined set of colors; this is passed through to the Theme directly.
  6744. // hue: Number?
  6745. // A hue to base the generated colors from (a number from 0 - 359).
  6746. // saturation: Number?
  6747. // If a hue is passed, this is used for the saturation value (0 - 100).
  6748. // low: Number?
  6749. // An optional value to determine the lowest value used to generate a color (HSV model)
  6750. // high: Number?
  6751. // An optional value to determine the highest value used to generate a color (HSV model)
  6752. // base: String|dojo.Color?
  6753. // A base color to use if we are defining colors using dojox.color.Palette
  6754. // generator: String?
  6755. // The generator function name from dojox.color.Palette.
  6756. this.num = num;
  6757. this.colors = colors;
  6758. this.hue = hue;
  6759. this.saturation = saturation;
  6760. this.low = low;
  6761. this.high = high;
  6762. this.base = base;
  6763. this.generator = generator;
  6764. }
  6765. =====*/
  6766. dojo.mixin(dojox.charting.Theme, {
  6767. defaultMarkers: {
  6768. CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",
  6769. SQUARE: "m-3,-3 l0,6 6,0 0,-6 z",
  6770. DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z",
  6771. CROSS: "m0,-3 l0,6 m-3,-3 l6,0",
  6772. X: "m-3,-3 l6,6 m0,-6 l-6,6",
  6773. TRIANGLE: "m-3,3 l3,-6 3,6 z",
  6774. TRIANGLE_INVERTED: "m-3,-3 l3,6 3,-6 z"
  6775. },
  6776. defaultColors:[
  6777. // gray skies
  6778. "#54544c", "#858e94", "#6e767a", "#948585", "#474747"
  6779. ],
  6780. defaultTheme: {
  6781. // all objects are structs used directly in dojox.gfx
  6782. chart:{
  6783. stroke: null,
  6784. fill: "white",
  6785. pageStyle: null,
  6786. titleGap: 20,
  6787. titlePos: "top",
  6788. titleFont: "normal normal bold 14pt Tahoma", // labels on axis
  6789. titleFontColor: "#333"
  6790. },
  6791. plotarea:{
  6792. stroke: null,
  6793. fill: "white"
  6794. },
  6795. // TODO: label rotation on axis
  6796. axis:{
  6797. stroke: { // the axis itself
  6798. color: "#333",
  6799. width: 1
  6800. },
  6801. tick: { // used as a foundation for all ticks
  6802. color: "#666",
  6803. position: "center",
  6804. font: "normal normal normal 7pt Tahoma", // labels on axis
  6805. fontColor: "#333", // color of labels
  6806. titleGap: 15,
  6807. titleFont: "normal normal normal 11pt Tahoma", // labels on axis
  6808. titleFontColor: "#333", // color of labels
  6809. titleOrientation: "axis" // "axis": facing the axis, "away": facing away
  6810. },
  6811. majorTick: { // major ticks on axis, and used for major gridlines
  6812. width: 1,
  6813. length: 6
  6814. },
  6815. minorTick: { // minor ticks on axis, and used for minor gridlines
  6816. width: 0.8,
  6817. length: 3
  6818. },
  6819. microTick: { // minor ticks on axis, and used for minor gridlines
  6820. width: 0.5,
  6821. length: 1
  6822. }
  6823. },
  6824. series: {
  6825. // used as a "main" theme for series, sThemes augment it
  6826. stroke: {width: 1.5, color: "#333"}, // line
  6827. outline: {width: 0.1, color: "#ccc"}, // outline
  6828. //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  6829. shadow: null, // no shadow
  6830. fill: "#ccc", // fill, if appropriate
  6831. font: "normal normal normal 8pt Tahoma", // if there's a label
  6832. fontColor: "#000", // color of labels
  6833. labelWiring: {width: 1, color: "#ccc"} // connect marker and target data item(slice, column, bar...)
  6834. },
  6835. marker: { // any markers on a series
  6836. stroke: {width: 1.5, color: "#333"}, // stroke
  6837. outline: {width: 0.1, color: "#ccc"}, // outline
  6838. //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  6839. shadow: null, // no shadow
  6840. fill: "#ccc", // fill if needed
  6841. font: "normal normal normal 8pt Tahoma", // label
  6842. fontColor: "#000"
  6843. }
  6844. },
  6845. defineColors: function(kwArgs){
  6846. // summary:
  6847. // Generate a set of colors for the theme based on keyword
  6848. // arguments.
  6849. // kwArgs: dojox.charting.Theme.__DefineColorArgs
  6850. // The arguments object used to define colors.
  6851. // returns: dojo.Color[]
  6852. // An array of colors for use in a theme.
  6853. //
  6854. // example:
  6855. // | var colors = dojox.charting.Theme.defineColors({
  6856. // | base: "#369",
  6857. // | generator: "compound"
  6858. // | });
  6859. //
  6860. // example:
  6861. // | var colors = dojox.charting.Theme.defineColors({
  6862. // | hue: 60,
  6863. // | saturation: 90,
  6864. // | low: 30,
  6865. // | high: 80
  6866. // | });
  6867. kwArgs = kwArgs || {};
  6868. var c = [], n = kwArgs.num || 5; // the number of colors to generate
  6869. if(kwArgs.colors){
  6870. // we have an array of colors predefined, so fix for the number of series.
  6871. var l = kwArgs.colors.length;
  6872. for(var i = 0; i < n; i++){
  6873. c.push(kwArgs.colors[i % l]);
  6874. }
  6875. return c; // dojo.Color[]
  6876. }
  6877. if(kwArgs.hue){
  6878. // single hue, generate a set based on brightness
  6879. var s = kwArgs.saturation || 100; // saturation
  6880. var st = kwArgs.low || 30;
  6881. var end = kwArgs.high || 90;
  6882. // we'd like it to be a little on the darker side.
  6883. var l = (end + st) / 2;
  6884. // alternately, use "shades"
  6885. return dojox.color.Palette.generate(
  6886. dojox.color.fromHsv(kwArgs.hue, s, l), "monochromatic"
  6887. ).colors;
  6888. }
  6889. if(kwArgs.generator){
  6890. // pass a base color and the name of a generator
  6891. return dojox.color.Palette.generate(kwArgs.base, kwArgs.generator).colors;
  6892. }
  6893. return c; // dojo.Color[]
  6894. },
  6895. generateGradient: function(fillPattern, colorFrom, colorTo){
  6896. var fill = dojo.delegate(fillPattern);
  6897. fill.colors = [
  6898. {offset: 0, color: colorFrom},
  6899. {offset: 1, color: colorTo}
  6900. ];
  6901. return fill;
  6902. },
  6903. generateHslColor: function(color, luminance){
  6904. color = new dojox.color.Color(color);
  6905. var hsl = color.toHsl(),
  6906. result = dojox.color.fromHsl(hsl.h, hsl.s, luminance);
  6907. result.a = color.a; // add missing opacity
  6908. return result;
  6909. },
  6910. generateHslGradient: function(color, fillPattern, lumFrom, lumTo){
  6911. color = new dojox.color.Color(color);
  6912. var hsl = color.toHsl(),
  6913. colorFrom = dojox.color.fromHsl(hsl.h, hsl.s, lumFrom),
  6914. colorTo = dojox.color.fromHsl(hsl.h, hsl.s, lumTo);
  6915. colorFrom.a = colorTo.a = color.a; // add missing opacity
  6916. return dojox.charting.Theme.generateGradient(fillPattern, colorFrom, colorTo); // Object
  6917. }
  6918. });
  6919. }
  6920. if(!dojo._hasResource["dojox.charting.Series"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  6921. dojo._hasResource["dojox.charting.Series"] = true;
  6922. dojo.provide("dojox.charting.Series");
  6923. /*=====
  6924. dojox.charting.__SeriesCtorArgs = function(plot){
  6925. // summary:
  6926. // An optional arguments object that can be used in the Series constructor.
  6927. // plot: String?
  6928. // The plot (by name) that this series belongs to.
  6929. this.plot = plot;
  6930. }
  6931. =====*/
  6932. dojo.declare("dojox.charting.Series", dojox.charting.Element, {
  6933. // summary:
  6934. // An object representing a series of data for plotting on a chart.
  6935. constructor: function(chart, data, kwArgs){
  6936. // summary:
  6937. // Create a new data series object for use within charting.
  6938. // chart: dojox.charting.Chart2D
  6939. // The chart that this series belongs to.
  6940. // data: Array|Object:
  6941. // The array of data points (either numbers or objects) that
  6942. // represents the data to be drawn. Or it can be an object. In
  6943. // the latter case, it should have a property "data" (an array),
  6944. // destroy(), and setSeriesObject().
  6945. // kwArgs: dojox.charting.__SeriesCtorArgs?
  6946. // An optional keyword arguments object to set details for this series.
  6947. dojo.mixin(this, kwArgs);
  6948. if(typeof this.plot != "string"){ this.plot = "default"; }
  6949. this.update(data);
  6950. },
  6951. clear: function(){
  6952. // summary:
  6953. // Clear the calculated additional parameters set on this series.
  6954. this.dyn = {};
  6955. },
  6956. update: function(data){
  6957. // summary:
  6958. // Set data and make this object dirty, so it can be redrawn.
  6959. // data: Array|Object:
  6960. // The array of data points (either numbers or objects) that
  6961. // represents the data to be drawn. Or it can be an object. In
  6962. // the latter case, it should have a property "data" (an array),
  6963. // destroy(), and setSeriesObject().
  6964. if(dojo.isArray(data)){
  6965. this.data = data;
  6966. }else{
  6967. this.source = data;
  6968. this.data = this.source.data;
  6969. if(this.source.setSeriesObject){
  6970. this.source.setSeriesObject(this);
  6971. }
  6972. }
  6973. this.dirty = true;
  6974. this.clear();
  6975. }
  6976. });
  6977. }
  6978. if(!dojo._hasResource["dojox.charting.axis2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  6979. dojo._hasResource["dojox.charting.axis2d.common"] = true;
  6980. dojo.provide("dojox.charting.axis2d.common");
  6981. (function(){
  6982. var g = dojox.gfx;
  6983. var clearNode = function(s){
  6984. s.marginLeft = "0px";
  6985. s.marginTop = "0px";
  6986. s.marginRight = "0px";
  6987. s.marginBottom = "0px";
  6988. s.paddingLeft = "0px";
  6989. s.paddingTop = "0px";
  6990. s.paddingRight = "0px";
  6991. s.paddingBottom = "0px";
  6992. s.borderLeftWidth = "0px";
  6993. s.borderTopWidth = "0px";
  6994. s.borderRightWidth = "0px";
  6995. s.borderBottomWidth = "0px";
  6996. };
  6997. var getBoxWidth = function(n){
  6998. // marginBox is incredibly slow, so avoid it if we can
  6999. if(n["getBoundingClientRect"]){
  7000. var bcr = n.getBoundingClientRect();
  7001. return bcr.width || (bcr.right - bcr.left);
  7002. }else{
  7003. return dojo.marginBox(n).w;
  7004. }
  7005. };
  7006. dojo.mixin(dojox.charting.axis2d.common, {
  7007. // summary:
  7008. // Common methods to be used by any axis. This is considered "static".
  7009. createText: {
  7010. gfx: function(chart, creator, x, y, align, text, font, fontColor){
  7011. // summary:
  7012. // Use dojox.gfx to create any text.
  7013. // chart: dojox.charting.Chart2D
  7014. // The chart to create the text into.
  7015. // creator: dojox.gfx.Surface
  7016. // The graphics surface to use for creating the text.
  7017. // x: Number
  7018. // Where to create the text along the x axis (CSS left).
  7019. // y: Number
  7020. // Where to create the text along the y axis (CSS top).
  7021. // align: String
  7022. // How to align the text. Can be "left", "right", "center".
  7023. // text: String
  7024. // The text to render.
  7025. // font: String
  7026. // The font definition, a la CSS "font".
  7027. // fontColor: String|dojo.Color
  7028. // The color of the resultant text.
  7029. // returns: dojox.gfx.Text
  7030. // The resultant GFX object.
  7031. return creator.createText({
  7032. x: x, y: y, text: text, align: align
  7033. }).setFont(font).setFill(fontColor); // dojox.gfx.Text
  7034. },
  7035. html: function(chart, creator, x, y, align, text, font, fontColor, labelWidth){
  7036. // summary:
  7037. // Use the HTML DOM to create any text.
  7038. // chart: dojox.charting.Chart2D
  7039. // The chart to create the text into.
  7040. // creator: dojox.gfx.Surface
  7041. // The graphics surface to use for creating the text.
  7042. // x: Number
  7043. // Where to create the text along the x axis (CSS left).
  7044. // y: Number
  7045. // Where to create the text along the y axis (CSS top).
  7046. // align: String
  7047. // How to align the text. Can be "left", "right", "center".
  7048. // text: String
  7049. // The text to render.
  7050. // font: String
  7051. // The font definition, a la CSS "font".
  7052. // fontColor: String|dojo.Color
  7053. // The color of the resultant text.
  7054. // labelWidth: Number?
  7055. // The maximum width of the resultant DOM node.
  7056. // returns: DOMNode
  7057. // The resultant DOMNode (a "div" element).
  7058. // setup the text node
  7059. var p = dojo.doc.createElement("div"), s = p.style, boxWidth;
  7060. clearNode(s);
  7061. s.font = font;
  7062. p.innerHTML = String(text).replace(/\s/g, "&nbsp;");
  7063. s.color = fontColor;
  7064. // measure the size
  7065. s.position = "absolute";
  7066. s.left = "-10000px";
  7067. dojo.body().appendChild(p);
  7068. var size = g.normalizedLength(g.splitFontString(font).size);
  7069. // do we need to calculate the label width?
  7070. if(!labelWidth){
  7071. boxWidth = getBoxWidth(p);
  7072. }
  7073. // new settings for the text node
  7074. dojo.body().removeChild(p);
  7075. s.position = "relative";
  7076. if(labelWidth){
  7077. s.width = labelWidth + "px";
  7078. // s.border = "1px dotted grey";
  7079. switch(align){
  7080. case "middle":
  7081. s.textAlign = "center";
  7082. s.left = (x - labelWidth / 2) + "px";
  7083. break;
  7084. case "end":
  7085. s.textAlign = "right";
  7086. s.left = (x - labelWidth) + "px";
  7087. break;
  7088. default:
  7089. s.left = x + "px";
  7090. s.textAlign = "left";
  7091. break;
  7092. }
  7093. }else{
  7094. switch(align){
  7095. case "middle":
  7096. s.left = Math.floor(x - boxWidth / 2) + "px";
  7097. // s.left = Math.floor(x - p.offsetWidth / 2) + "px";
  7098. break;
  7099. case "end":
  7100. s.left = Math.floor(x - boxWidth) + "px";
  7101. // s.left = Math.floor(x - p.offsetWidth) + "px";
  7102. break;
  7103. //case "start":
  7104. default:
  7105. s.left = Math.floor(x) + "px";
  7106. break;
  7107. }
  7108. }
  7109. s.top = Math.floor(y - size) + "px";
  7110. s.whiteSpace = "nowrap"; // hack for WebKit
  7111. // setup the wrapper node
  7112. var wrap = dojo.doc.createElement("div"), w = wrap.style;
  7113. clearNode(w);
  7114. w.width = "0px";
  7115. w.height = "0px";
  7116. // insert nodes
  7117. wrap.appendChild(p)
  7118. chart.node.insertBefore(wrap, chart.node.firstChild);
  7119. return wrap; // DOMNode
  7120. }
  7121. }
  7122. });
  7123. })();
  7124. }
  7125. if(!dojo._hasResource["dojox.charting.Chart"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7126. dojo._hasResource["dojox.charting.Chart"] = true;
  7127. dojo.provide("dojox.charting.Chart");
  7128. /*=====
  7129. dojox.charting.__ChartCtorArgs = function(margins, stroke, fill, delayInMs){
  7130. // summary:
  7131. // The keyword arguments that can be passed in a Chart constructor.
  7132. //
  7133. // margins: Object?
  7134. // Optional margins for the chart, in the form of { l, t, r, b}.
  7135. // stroke: dojox.gfx.Stroke?
  7136. // An optional outline/stroke for the chart.
  7137. // fill: dojox.gfx.Fill?
  7138. // An optional fill for the chart.
  7139. // delayInMs: Number
  7140. // Delay in ms for delayedRender(). Default: 200.
  7141. this.margins = margins;
  7142. this.stroke = stroke;
  7143. this.fill = fill;
  7144. this.delayInMs = delayInMs;
  7145. }
  7146. =====*/
  7147. (function(){
  7148. var df = dojox.lang.functional, dc = dojox.charting, g = dojox.gfx,
  7149. clear = df.lambda("item.clear()"),
  7150. purge = df.lambda("item.purgeGroup()"),
  7151. destroy = df.lambda("item.destroy()"),
  7152. makeClean = df.lambda("item.dirty = false"),
  7153. makeDirty = df.lambda("item.dirty = true"),
  7154. getName = df.lambda("item.name");
  7155. dojo.declare("dojox.charting.Chart", null, {
  7156. // summary:
  7157. // The main chart object in dojox.charting. This will create a two dimensional
  7158. // chart based on dojox.gfx.
  7159. //
  7160. // description:
  7161. // dojox.charting.Chart is the primary object used for any kind of charts. It
  7162. // is simple to create--just pass it a node reference, which is used as the
  7163. // container for the chart--and a set of optional keyword arguments and go.
  7164. //
  7165. // Note that like most of dojox.gfx, most of dojox.charting.Chart's methods are
  7166. // designed to return a reference to the chart itself, to allow for functional
  7167. // chaining. This makes defining everything on a Chart very easy to do.
  7168. //
  7169. // example:
  7170. // Create an area chart, with smoothing.
  7171. // | new dojox.charting.Chart(node))
  7172. // | .addPlot("default", { type: "Areas", tension: "X" })
  7173. // | .setTheme(dojox.charting.themes.Shrooms)
  7174. // | .addSeries("Series A", [1, 2, 0.5, 1.5, 1, 2.8, 0.4])
  7175. // | .addSeries("Series B", [2.6, 1.8, 2, 1, 1.4, 0.7, 2])
  7176. // | .addSeries("Series C", [6.3, 1.8, 3, 0.5, 4.4, 2.7, 2])
  7177. // | .render();
  7178. //
  7179. // example:
  7180. // The form of data in a data series can take a number of forms: a simple array,
  7181. // an array of objects {x,y}, or something custom (as determined by the plot).
  7182. // Here's an example of a Candlestick chart, which expects an object of
  7183. // { open, high, low, close }.
  7184. // | new dojox.charting.Chart(node))
  7185. // | .addPlot("default", {type: "Candlesticks", gap: 1})
  7186. // | .addAxis("x", {fixLower: "major", fixUpper: "major", includeZero: true})
  7187. // | .addAxis("y", {vertical: true, fixLower: "major", fixUpper: "major", natural: true})
  7188. // | .addSeries("Series A", [
  7189. // | { open: 20, close: 16, high: 22, low: 8 },
  7190. // | { open: 16, close: 22, high: 26, low: 6, mid: 18 },
  7191. // | { open: 22, close: 18, high: 22, low: 11, mid: 21 },
  7192. // | { open: 18, close: 29, high: 32, low: 14, mid: 27 },
  7193. // | { open: 29, close: 24, high: 29, low: 13, mid: 27 },
  7194. // | { open: 24, close: 8, high: 24, low: 5 },
  7195. // | { open: 8, close: 16, high: 22, low: 2 },
  7196. // | { open: 16, close: 12, high: 19, low: 7 },
  7197. // | { open: 12, close: 20, high: 22, low: 8 },
  7198. // | { open: 20, close: 16, high: 22, low: 8 },
  7199. // | { open: 16, close: 22, high: 26, low: 6, mid: 18 },
  7200. // | { open: 22, close: 18, high: 22, low: 11, mid: 21 },
  7201. // | { open: 18, close: 29, high: 32, low: 14, mid: 27 },
  7202. // | { open: 29, close: 24, high: 29, low: 13, mid: 27 },
  7203. // | { open: 24, close: 8, high: 24, low: 5 },
  7204. // | { open: 8, close: 16, high: 22, low: 2 },
  7205. // | { open: 16, close: 12, high: 19, low: 7 },
  7206. // | { open: 12, close: 20, high: 22, low: 8 },
  7207. // | { open: 20, close: 16, high: 22, low: 8 },
  7208. // | { open: 16, close: 22, high: 26, low: 6 },
  7209. // | { open: 22, close: 18, high: 22, low: 11 },
  7210. // | { open: 18, close: 29, high: 32, low: 14 },
  7211. // | { open: 29, close: 24, high: 29, low: 13 },
  7212. // | { open: 24, close: 8, high: 24, low: 5 },
  7213. // | { open: 8, close: 16, high: 22, low: 2 },
  7214. // | { open: 16, close: 12, high: 19, low: 7 },
  7215. // | { open: 12, close: 20, high: 22, low: 8 },
  7216. // | { open: 20, close: 16, high: 22, low: 8 }
  7217. // | ],
  7218. // | { stroke: { color: "green" }, fill: "lightgreen" }
  7219. // | )
  7220. // | .render();
  7221. //
  7222. // theme: dojox.charting.Theme?
  7223. // An optional theme to use for styling the chart.
  7224. // axes: dojox.charting.Axis{}?
  7225. // A map of axes for use in plotting a chart.
  7226. // stack: dojox.charting.plot2d.Base[]
  7227. // A stack of plotters.
  7228. // plots: dojox.charting.plot2d.Base{}
  7229. // A map of plotter indices
  7230. // series: dojox.charting.Series[]
  7231. // The stack of data runs used to create plots.
  7232. // runs: dojox.charting.Series{}
  7233. // A map of series indices
  7234. // margins: Object?
  7235. // The margins around the chart. Default is { l:10, t:10, r:10, b:10 }.
  7236. // stroke: dojox.gfx.Stroke?
  7237. // The outline of the chart (stroke in vector graphics terms).
  7238. // fill: dojox.gfx.Fill?
  7239. // The color for the chart.
  7240. // node: DOMNode
  7241. // The container node passed to the constructor.
  7242. // surface: dojox.gfx.Surface
  7243. // The main graphics surface upon which a chart is drawn.
  7244. // dirty: Boolean
  7245. // A boolean flag indicating whether or not the chart needs to be updated/re-rendered.
  7246. // coords: Object
  7247. // The coordinates on a page of the containing node, as returned from dojo.coords.
  7248. constructor: function(/* DOMNode */node, /* dojox.charting.__ChartCtorArgs? */kwArgs){
  7249. // summary:
  7250. // The constructor for a new Chart. Initializes all parameters used for a chart.
  7251. // returns: dojox.charting.Chart
  7252. // The newly created chart.
  7253. // initialize parameters
  7254. if(!kwArgs){ kwArgs = {}; }
  7255. this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10};
  7256. this.stroke = kwArgs.stroke;
  7257. this.fill = kwArgs.fill;
  7258. this.delayInMs = kwArgs.delayInMs || 200;
  7259. this.title = kwArgs.title;
  7260. this.titleGap = kwArgs.titleGap;
  7261. this.titlePos = kwArgs.titlePos;
  7262. this.titleFont = kwArgs.titleFont;
  7263. this.titleFontColor = kwArgs.titleFontColor;
  7264. this.chartTitle = null;
  7265. // default initialization
  7266. this.theme = null;
  7267. this.axes = {}; // map of axes
  7268. this.stack = []; // stack of plotters
  7269. this.plots = {}; // map of plotter indices
  7270. this.series = []; // stack of data runs
  7271. this.runs = {}; // map of data run indices
  7272. this.dirty = true;
  7273. this.coords = null;
  7274. // create a surface
  7275. this.node = dojo.byId(node);
  7276. var box = dojo.marginBox(node);
  7277. this.surface = g.createSurface(this.node, box.w || 400, box.h || 300);
  7278. },
  7279. destroy: function(){
  7280. // summary:
  7281. // Cleanup when a chart is to be destroyed.
  7282. // returns: void
  7283. dojo.forEach(this.series, destroy);
  7284. dojo.forEach(this.stack, destroy);
  7285. df.forIn(this.axes, destroy);
  7286. if(this.chartTitle && this.chartTitle.tagName){
  7287. // destroy title if it is a DOM node
  7288. dojo.destroy(this.chartTitle);
  7289. }
  7290. this.surface.destroy();
  7291. },
  7292. getCoords: function(){
  7293. // summary:
  7294. // Get the coordinates and dimensions of the containing DOMNode, as
  7295. // returned by dojo.coords.
  7296. // returns: Object
  7297. // The resulting coordinates of the chart. See dojo.coords for details.
  7298. if(!this.coords){
  7299. this.coords = dojo.coords(this.node, true);
  7300. }
  7301. return this.coords; // Object
  7302. },
  7303. setTheme: function(theme){
  7304. // summary:
  7305. // Set a theme of the chart.
  7306. // theme: dojox.charting.Theme
  7307. // The theme to be used for visual rendering.
  7308. // returns: dojox.charting.Chart
  7309. // A reference to the current chart for functional chaining.
  7310. this.theme = theme.clone();
  7311. this.dirty = true;
  7312. return this; // dojox.charting.Chart
  7313. },
  7314. addAxis: function(name, kwArgs){
  7315. // summary:
  7316. // Add an axis to the chart, for rendering.
  7317. // name: String
  7318. // The name of the axis.
  7319. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  7320. // An optional keyword arguments object for use in defining details of an axis.
  7321. // returns: dojox.charting.Chart
  7322. // A reference to the current chart for functional chaining.
  7323. var axis, axisType = kwArgs && kwArgs.type || "Default";
  7324. if(typeof axisType == "string"){
  7325. if(!dc.axis2d || !dc.axis2d[axisType]){
  7326. throw Error("Can't find axis: " + axisType + " - didn't you forget to dojo" + ".require() it?");
  7327. }
  7328. axis = new dc.axis2d[axisType](this, kwArgs);
  7329. }else{
  7330. axis = new axisType(this, kwArgs);
  7331. }
  7332. axis.name = name;
  7333. axis.dirty = true;
  7334. if(name in this.axes){
  7335. this.axes[name].destroy();
  7336. }
  7337. this.axes[name] = axis;
  7338. this.dirty = true;
  7339. return this; // dojox.charting.Chart
  7340. },
  7341. getAxis: function(name){
  7342. // summary:
  7343. // Get the given axis, by name.
  7344. // name: String
  7345. // The name the axis was defined by.
  7346. // returns: dojox.charting.axis2d.Default
  7347. // The axis as stored in the chart's axis map.
  7348. return this.axes[name]; // dojox.charting.axis2d.Default
  7349. },
  7350. removeAxis: function(name){
  7351. // summary:
  7352. // Remove the axis that was defined using name.
  7353. // name: String
  7354. // The axis name, as defined in addAxis.
  7355. // returns: dojox.charting.Chart
  7356. // A reference to the current chart for functional chaining.
  7357. if(name in this.axes){
  7358. // destroy the axis
  7359. this.axes[name].destroy();
  7360. delete this.axes[name];
  7361. // mark the chart as dirty
  7362. this.dirty = true;
  7363. }
  7364. return this; // dojox.charting.Chart
  7365. },
  7366. addPlot: function(name, kwArgs){
  7367. // summary:
  7368. // Add a new plot to the chart, defined by name and using the optional keyword arguments object.
  7369. // Note that dojox.charting assumes the main plot to be called "default"; if you do not have
  7370. // a plot called "default" and attempt to add data series to the chart without specifying the
  7371. // plot to be rendered on, you WILL get errors.
  7372. // name: String
  7373. // The name of the plot to be added to the chart. If you only plan on using one plot, call it "default".
  7374. // kwArgs: dojox.charting.plot2d.__PlotCtorArgs
  7375. // An object with optional parameters for the plot in question.
  7376. // returns: dojox.charting.Chart
  7377. // A reference to the current chart for functional chaining.
  7378. var plot, plotType = kwArgs && kwArgs.type || "Default";
  7379. if(typeof plotType == "string"){
  7380. if(!dc.plot2d || !dc.plot2d[plotType]){
  7381. throw Error("Can't find plot: " + plotType + " - didn't you forget to dojo" + ".require() it?");
  7382. }
  7383. plot = new dc.plot2d[plotType](this, kwArgs);
  7384. }else{
  7385. plot = new plotType(this, kwArgs);
  7386. }
  7387. plot.name = name;
  7388. plot.dirty = true;
  7389. if(name in this.plots){
  7390. this.stack[this.plots[name]].destroy();
  7391. this.stack[this.plots[name]] = plot;
  7392. }else{
  7393. this.plots[name] = this.stack.length;
  7394. this.stack.push(plot);
  7395. }
  7396. this.dirty = true;
  7397. return this; // dojox.charting.Chart
  7398. },
  7399. removePlot: function(name){
  7400. // summary:
  7401. // Remove the plot defined using name from the chart's plot stack.
  7402. // name: String
  7403. // The name of the plot as defined using addPlot.
  7404. // returns: dojox.charting.Chart
  7405. // A reference to the current chart for functional chaining.
  7406. if(name in this.plots){
  7407. // get the index and remove the name
  7408. var index = this.plots[name];
  7409. delete this.plots[name];
  7410. // destroy the plot
  7411. this.stack[index].destroy();
  7412. // remove the plot from the stack
  7413. this.stack.splice(index, 1);
  7414. // update indices to reflect the shift
  7415. df.forIn(this.plots, function(idx, name, plots){
  7416. if(idx > index){
  7417. plots[name] = idx - 1;
  7418. }
  7419. });
  7420. // remove all related series
  7421. var ns = dojo.filter(this.series, function(run){ return run.plot != name; });
  7422. if(ns.length < this.series.length){
  7423. // kill all removed series
  7424. dojo.forEach(this.series, function(run){
  7425. if(run.plot == name){
  7426. run.destroy();
  7427. }
  7428. });
  7429. // rebuild all necessary data structures
  7430. this.runs = {};
  7431. dojo.forEach(ns, function(run, index){
  7432. this.runs[run.plot] = index;
  7433. }, this);
  7434. this.series = ns;
  7435. }
  7436. // mark the chart as dirty
  7437. this.dirty = true;
  7438. }
  7439. return this; // dojox.charting.Chart
  7440. },
  7441. getPlotOrder: function(){
  7442. // summary:
  7443. // Returns an array of plot names in the current order
  7444. // (the top-most plot is the first).
  7445. // returns: Array
  7446. return df.map(this.stack, getName); // Array
  7447. },
  7448. setPlotOrder: function(newOrder){
  7449. // summary:
  7450. // Sets new order of plots. newOrder cannot add or remove
  7451. // plots. Wrong names, or dups are ignored.
  7452. // newOrder: Array:
  7453. // Array of plot names compatible with getPlotOrder().
  7454. // returns: dojox.charting.Chart
  7455. // A reference to the current chart for functional chaining.
  7456. var names = {},
  7457. order = df.filter(newOrder, function(name){
  7458. if(!(name in this.plots) || (name in names)){
  7459. return false;
  7460. }
  7461. names[name] = 1;
  7462. return true;
  7463. }, this);
  7464. if(order.length < this.stack.length){
  7465. df.forEach(this.stack, function(plot){
  7466. var name = plot.name;
  7467. if(!(name in names)){
  7468. order.push(name);
  7469. }
  7470. });
  7471. }
  7472. var newStack = df.map(order, function(name){
  7473. return this.stack[this.plots[name]];
  7474. }, this);
  7475. df.forEach(newStack, function(plot, i){
  7476. this.plots[plot.name] = i;
  7477. }, this);
  7478. this.stack = newStack;
  7479. this.dirty = true;
  7480. return this; // dojox.charting.Chart
  7481. },
  7482. movePlotToFront: function(name){
  7483. // summary:
  7484. // Moves a given plot to front.
  7485. // name: String:
  7486. // Plot's name to move.
  7487. // returns: dojox.charting.Chart
  7488. // A reference to the current chart for functional chaining.
  7489. if(name in this.plots){
  7490. var index = this.plots[name];
  7491. if(index){
  7492. var newOrder = this.getPlotOrder();
  7493. newOrder.splice(index, 1);
  7494. newOrder.unshift(name);
  7495. return this.setPlotOrder(newOrder); // dojox.charting.Chart
  7496. }
  7497. }
  7498. return this; // dojox.charting.Chart
  7499. },
  7500. movePlotToBack: function(name){
  7501. // summary:
  7502. // Moves a given plot to back.
  7503. // name: String:
  7504. // Plot's name to move.
  7505. // returns: dojox.charting.Chart
  7506. // A reference to the current chart for functional chaining.
  7507. if(name in this.plots){
  7508. var index = this.plots[name];
  7509. if(index < this.stack.length - 1){
  7510. var newOrder = this.getPlotOrder();
  7511. newOrder.splice(index, 1);
  7512. newOrder.push(name);
  7513. return this.setPlotOrder(newOrder); // dojox.charting.Chart
  7514. }
  7515. }
  7516. return this; // dojox.charting.Chart
  7517. },
  7518. addSeries: function(name, data, kwArgs){
  7519. // summary:
  7520. // Add a data series to the chart for rendering.
  7521. // name: String:
  7522. // The name of the data series to be plotted.
  7523. // data: Array|Object:
  7524. // The array of data points (either numbers or objects) that
  7525. // represents the data to be drawn. Or it can be an object. In
  7526. // the latter case, it should have a property "data" (an array),
  7527. // destroy(), and setSeriesObject().
  7528. // kwArgs: dojox.charting.__SeriesCtorArgs?:
  7529. // An optional keyword arguments object that will be mixed into
  7530. // the resultant series object.
  7531. // returns: dojox.charting.Chart:
  7532. // A reference to the current chart for functional chaining.
  7533. var run = new dc.Series(this, data, kwArgs);
  7534. run.name = name;
  7535. if(name in this.runs){
  7536. this.series[this.runs[name]].destroy();
  7537. this.series[this.runs[name]] = run;
  7538. }else{
  7539. this.runs[name] = this.series.length;
  7540. this.series.push(run);
  7541. }
  7542. this.dirty = true;
  7543. // fix min/max
  7544. if(!("ymin" in run) && "min" in run){ run.ymin = run.min; }
  7545. if(!("ymax" in run) && "max" in run){ run.ymax = run.max; }
  7546. return this; // dojox.charting.Chart
  7547. },
  7548. removeSeries: function(name){
  7549. // summary:
  7550. // Remove the series defined by name from the chart.
  7551. // name: String
  7552. // The name of the series as defined by addSeries.
  7553. // returns: dojox.charting.Chart
  7554. // A reference to the current chart for functional chaining.
  7555. if(name in this.runs){
  7556. // get the index and remove the name
  7557. var index = this.runs[name];
  7558. delete this.runs[name];
  7559. // destroy the run
  7560. this.series[index].destroy();
  7561. // remove the run from the stack of series
  7562. this.series.splice(index, 1);
  7563. // update indices to reflect the shift
  7564. df.forIn(this.runs, function(idx, name, runs){
  7565. if(idx > index){
  7566. runs[name] = idx - 1;
  7567. }
  7568. });
  7569. this.dirty = true;
  7570. }
  7571. return this; // dojox.charting.Chart
  7572. },
  7573. updateSeries: function(name, data){
  7574. // summary:
  7575. // Update the given series with a new set of data points.
  7576. // name: String
  7577. // The name of the series as defined in addSeries.
  7578. // data: Array|Object:
  7579. // The array of data points (either numbers or objects) that
  7580. // represents the data to be drawn. Or it can be an object. In
  7581. // the latter case, it should have a property "data" (an array),
  7582. // destroy(), and setSeriesObject().
  7583. // returns: dojox.charting.Chart
  7584. // A reference to the current chart for functional chaining.
  7585. if(name in this.runs){
  7586. var run = this.series[this.runs[name]];
  7587. run.update(data);
  7588. this._invalidateDependentPlots(run.plot, false);
  7589. this._invalidateDependentPlots(run.plot, true);
  7590. }
  7591. return this; // dojox.charting.Chart
  7592. },
  7593. getSeriesOrder: function(plotName){
  7594. // summary:
  7595. // Returns an array of series names in the current order
  7596. // (the top-most series is the first) within a plot.
  7597. // plotName: String:
  7598. // Plot's name.
  7599. // returns: Array
  7600. return df.map(df.filter(this.series, function(run){
  7601. return run.plot == plotName;
  7602. }), getName);
  7603. },
  7604. setSeriesOrder: function(newOrder){
  7605. // summary:
  7606. // Sets new order of series within a plot. newOrder cannot add
  7607. // or remove series. Wrong names, or dups are ignored.
  7608. // newOrder: Array:
  7609. // Array of series names compatible with getPlotOrder(). All
  7610. // series should belong to the same plot.
  7611. // returns: dojox.charting.Chart
  7612. // A reference to the current chart for functional chaining.
  7613. var plotName, names = {},
  7614. order = df.filter(newOrder, function(name){
  7615. if(!(name in this.runs) || (name in names)){
  7616. return false;
  7617. }
  7618. var run = this.series[this.runs[name]];
  7619. if(plotName){
  7620. if(run.plot != plotName){
  7621. return false;
  7622. }
  7623. }else{
  7624. plotName = run.plot;
  7625. }
  7626. names[name] = 1;
  7627. return true;
  7628. }, this);
  7629. df.forEach(this.series, function(run){
  7630. var name = run.name;
  7631. if(!(name in names) && run.plot == plotName){
  7632. order.push(name);
  7633. }
  7634. });
  7635. var newSeries = df.map(order, function(name){
  7636. return this.series[this.runs[name]];
  7637. }, this);
  7638. this.series = newSeries.concat(df.filter(this.series, function(run){
  7639. return run.plot != plotName;
  7640. }));
  7641. df.forEach(this.series, function(run, i){
  7642. this.runs[run.name] = i;
  7643. }, this);
  7644. this.dirty = true;
  7645. return this; // dojox.charting.Chart
  7646. },
  7647. moveSeriesToFront: function(name){
  7648. // summary:
  7649. // Moves a given series to front of a plot.
  7650. // name: String:
  7651. // Series' name to move.
  7652. // returns: dojox.charting.Chart
  7653. // A reference to the current chart for functional chaining.
  7654. if(name in this.runs){
  7655. var index = this.runs[name],
  7656. newOrder = this.getSeriesOrder(this.series[index].plot);
  7657. if(name != newOrder[0]){
  7658. newOrder.splice(index, 1);
  7659. newOrder.unshift(name);
  7660. return this.setSeriesOrder(newOrder); // dojox.charting.Chart
  7661. }
  7662. }
  7663. return this; // dojox.charting.Chart
  7664. },
  7665. moveSeriesToBack: function(name){
  7666. // summary:
  7667. // Moves a given series to back of a plot.
  7668. // name: String:
  7669. // Series' name to move.
  7670. // returns: dojox.charting.Chart
  7671. // A reference to the current chart for functional chaining.
  7672. if(name in this.runs){
  7673. var index = this.runs[name],
  7674. newOrder = this.getSeriesOrder(this.series[index].plot);
  7675. if(name != newOrder[newOrder.length - 1]){
  7676. newOrder.splice(index, 1);
  7677. newOrder.push(name);
  7678. return this.setSeriesOrder(newOrder); // dojox.charting.Chart
  7679. }
  7680. }
  7681. return this; // dojox.charting.Chart
  7682. },
  7683. resize: function(width, height){
  7684. // summary:
  7685. // Resize the chart to the dimensions of width and height.
  7686. // description:
  7687. // Resize the chart and its surface to the width and height dimensions.
  7688. // If no width/height or box is provided, resize the surface to the marginBox of the chart.
  7689. // width: Number
  7690. // The new width of the chart.
  7691. // height: Number
  7692. // The new height of the chart.
  7693. // returns: dojox.charting.Chart
  7694. // A reference to the current chart for functional chaining.
  7695. var box;
  7696. switch(arguments.length){
  7697. // case 0, do not resize the div, just the surface
  7698. case 1:
  7699. // argument, override node box
  7700. box = dojo.mixin({}, width);
  7701. dojo.marginBox(this.node, box);
  7702. break;
  7703. case 2:
  7704. box = {w: width, h: height};
  7705. // argument, override node box
  7706. dojo.marginBox(this.node, box);
  7707. break;
  7708. }
  7709. // in all cases take back the computed box
  7710. box = dojo.marginBox(this.node);
  7711. // and set it on the surface
  7712. this.surface.setDimensions(box.w, box.h);
  7713. this.dirty = true;
  7714. this.coords = null;
  7715. return this.render(); // dojox.charting.Chart
  7716. },
  7717. getGeometry: function(){
  7718. // summary:
  7719. // Returns a map of information about all axes in a chart and what they represent
  7720. // in terms of scaling (see dojox.charting.axis2d.Default.getScaler).
  7721. // returns: Object
  7722. // An map of geometry objects, a one-to-one mapping of axes.
  7723. var ret = {};
  7724. df.forIn(this.axes, function(axis){
  7725. if(axis.initialized()){
  7726. ret[axis.name] = {
  7727. name: axis.name,
  7728. vertical: axis.vertical,
  7729. scaler: axis.scaler,
  7730. ticks: axis.ticks
  7731. };
  7732. }
  7733. });
  7734. return ret; // Object
  7735. },
  7736. setAxisWindow: function(name, scale, offset, zoom){
  7737. // summary:
  7738. // Zooms an axis and all dependent plots. Can be used to zoom in 1D.
  7739. // name: String
  7740. // The name of the axis as defined by addAxis.
  7741. // scale: Number
  7742. // The scale on the target axis.
  7743. // offset: Number
  7744. // Any offest, as measured by axis tick
  7745. // zoom: Boolean|Object?
  7746. // The chart zooming animation trigger. This is null by default,
  7747. // e.g. {duration: 1200}, or just set true.
  7748. // returns: dojox.charting.Chart
  7749. // A reference to the current chart for functional chaining.
  7750. var axis = this.axes[name];
  7751. if(axis){
  7752. axis.setWindow(scale, offset);
  7753. dojo.forEach(this.stack,function(plot){
  7754. if(plot.hAxis == name || plot.vAxis == name){
  7755. plot.zoom = zoom;
  7756. }
  7757. })
  7758. }
  7759. return this; // dojox.charting.Chart
  7760. },
  7761. setWindow: function(sx, sy, dx, dy, zoom){
  7762. // summary:
  7763. // Zooms in or out any plots in two dimensions.
  7764. // sx: Number
  7765. // The scale for the x axis.
  7766. // sy: Number
  7767. // The scale for the y axis.
  7768. // dx: Number
  7769. // The pixel offset on the x axis.
  7770. // dy: Number
  7771. // The pixel offset on the y axis.
  7772. // zoom: Boolean|Object?
  7773. // The chart zooming animation trigger. This is null by default,
  7774. // e.g. {duration: 1200}, or just set true.
  7775. // returns: dojox.charting.Chart
  7776. // A reference to the current chart for functional chaining.
  7777. if(!("plotArea" in this)){
  7778. this.calculateGeometry();
  7779. }
  7780. df.forIn(this.axes, function(axis){
  7781. var scale, offset, bounds = axis.getScaler().bounds,
  7782. s = bounds.span / (bounds.upper - bounds.lower);
  7783. if(axis.vertical){
  7784. scale = sy;
  7785. offset = dy / s / scale;
  7786. }else{
  7787. scale = sx;
  7788. offset = dx / s / scale;
  7789. }
  7790. axis.setWindow(scale, offset);
  7791. });
  7792. dojo.forEach(this.stack, function(plot){ plot.zoom = zoom; });
  7793. return this; // dojox.charting.Chart
  7794. },
  7795. zoomIn: function(name, range){
  7796. // summary:
  7797. // Zoom the chart to a specific range on one axis. This calls render()
  7798. // directly as a convenience method.
  7799. // name: String
  7800. // The name of the axis as defined by addAxis.
  7801. // range: Array
  7802. // The end points of the zoom range, measured in axis ticks.
  7803. var axis = this.axes[name];
  7804. if(axis){
  7805. var scale, offset, bounds = axis.getScaler().bounds;
  7806. var lower = Math.min(range[0],range[1]);
  7807. var upper = Math.max(range[0],range[1]);
  7808. lower = range[0] < bounds.lower ? bounds.lower : lower;
  7809. upper = range[1] > bounds.upper ? bounds.upper : upper;
  7810. scale = (bounds.upper - bounds.lower) / (upper - lower);
  7811. offset = lower - bounds.lower;
  7812. this.setAxisWindow(name, scale, offset);
  7813. this.render();
  7814. }
  7815. },
  7816. calculateGeometry: function(){
  7817. // summary:
  7818. // Calculate the geometry of the chart based on the defined axes of
  7819. // a chart.
  7820. // returns: dojox.charting.Chart
  7821. // A reference to the current chart for functional chaining.
  7822. if(this.dirty){
  7823. return this.fullGeometry();
  7824. }
  7825. // calculate geometry
  7826. var dirty = dojo.filter(this.stack, function(plot){
  7827. return plot.dirty ||
  7828. (plot.hAxis && this.axes[plot.hAxis].dirty) ||
  7829. (plot.vAxis && this.axes[plot.vAxis].dirty);
  7830. }, this);
  7831. calculateAxes(dirty, this.plotArea);
  7832. return this; // dojox.charting.Chart
  7833. },
  7834. fullGeometry: function(){
  7835. // summary:
  7836. // Calculate the full geometry of the chart. This includes passing
  7837. // over all major elements of a chart (plots, axes, series, container)
  7838. // in order to ensure proper rendering.
  7839. // returns: dojox.charting.Chart
  7840. // A reference to the current chart for functional chaining.
  7841. this._makeDirty();
  7842. // clear old values
  7843. dojo.forEach(this.stack, clear);
  7844. // rebuild new connections, and add defaults
  7845. // set up a theme
  7846. if(!this.theme){
  7847. this.setTheme(new dojox.charting.Theme(dojox.charting._def));
  7848. }
  7849. // assign series
  7850. dojo.forEach(this.series, function(run){
  7851. if(!(run.plot in this.plots)){
  7852. if(!dc.plot2d || !dc.plot2d.Default){
  7853. throw Error("Can't find plot: Default - didn't you forget to dojo" + ".require() it?");
  7854. }
  7855. var plot = new dc.plot2d.Default(this, {});
  7856. plot.name = run.plot;
  7857. this.plots[run.plot] = this.stack.length;
  7858. this.stack.push(plot);
  7859. }
  7860. this.stack[this.plots[run.plot]].addSeries(run);
  7861. }, this);
  7862. // assign axes
  7863. dojo.forEach(this.stack, function(plot){
  7864. if(plot.hAxis){
  7865. plot.setAxis(this.axes[plot.hAxis]);
  7866. }
  7867. if(plot.vAxis){
  7868. plot.setAxis(this.axes[plot.vAxis]);
  7869. }
  7870. }, this);
  7871. // calculate geometry
  7872. // 1st pass
  7873. var dim = this.dim = this.surface.getDimensions();
  7874. dim.width = g.normalizedLength(dim.width);
  7875. dim.height = g.normalizedLength(dim.height);
  7876. df.forIn(this.axes, clear);
  7877. calculateAxes(this.stack, dim);
  7878. // assumption: we don't have stacked axes yet
  7879. var offsets = this.offsets = { l: 0, r: 0, t: 0, b: 0 };
  7880. df.forIn(this.axes, function(axis){
  7881. df.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; });
  7882. });
  7883. // add title area
  7884. if(this.title){
  7885. this.titleGap = (this.titleGap==0) ? 0 : this.titleGap || this.theme.chart.titleGap || 20;
  7886. this.titlePos = this.titlePos || this.theme.chart.titlePos || "top";
  7887. this.titleFont = this.titleFont || this.theme.chart.titleFont;
  7888. this.titleFontColor = this.titleFontColor || this.theme.chart.titleFontColor || "black";
  7889. var tsize = g.normalizedLength(g.splitFontString(this.titleFont).size);
  7890. offsets[this.titlePos=="top" ? "t":"b"] += (tsize + this.titleGap);
  7891. }
  7892. // add margins
  7893. df.forIn(this.margins, function(o, i){ offsets[i] += o; });
  7894. // 2nd pass with realistic dimensions
  7895. this.plotArea = {
  7896. width: dim.width - offsets.l - offsets.r,
  7897. height: dim.height - offsets.t - offsets.b
  7898. };
  7899. df.forIn(this.axes, clear);
  7900. calculateAxes(this.stack, this.plotArea);
  7901. return this; // dojox.charting.Chart
  7902. },
  7903. render: function(){
  7904. // summary:
  7905. // Render the chart according to the current information defined. This should
  7906. // be the last call made when defining/creating a chart, or if data within the
  7907. // chart has been changed.
  7908. // returns: dojox.charting.Chart
  7909. // A reference to the current chart for functional chaining.
  7910. if(this.theme){
  7911. this.theme.clear();
  7912. }
  7913. if(this.dirty){
  7914. return this.fullRender();
  7915. }
  7916. this.calculateGeometry();
  7917. // go over the stack backwards
  7918. df.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this);
  7919. // go over axes
  7920. df.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this);
  7921. this._makeClean();
  7922. // BEGIN FOR HTML CANVAS
  7923. if(this.surface.render){ this.surface.render(); };
  7924. // END FOR HTML CANVAS
  7925. return this; // dojox.charting.Chart
  7926. },
  7927. fullRender: function(){
  7928. // summary:
  7929. // Force a full rendering of the chart, including full resets on the chart itself.
  7930. // You should not call this method directly unless absolutely necessary.
  7931. // returns: dojox.charting.Chart
  7932. // A reference to the current chart for functional chaining.
  7933. // calculate geometry
  7934. this.fullGeometry();
  7935. var offsets = this.offsets, dim = this.dim, rect;
  7936. // get required colors
  7937. //var requiredColors = df.foldl(this.stack, "z + plot.getRequiredColors()", 0);
  7938. //this.theme.defineColors({num: requiredColors, cache: false});
  7939. // clear old shapes
  7940. dojo.forEach(this.series, purge);
  7941. df.forIn(this.axes, purge);
  7942. dojo.forEach(this.stack, purge);
  7943. if(this.chartTitle && this.chartTitle.tagName){
  7944. // destroy title if it is a DOM node
  7945. dojo.destroy(this.chartTitle);
  7946. }
  7947. this.surface.clear();
  7948. this.chartTitle = null;
  7949. // generate shapes
  7950. // draw a plot background
  7951. var t = this.theme,
  7952. fill = t.plotarea && t.plotarea.fill,
  7953. stroke = t.plotarea && t.plotarea.stroke,
  7954. rect = {
  7955. x: offsets.l - 1, y: offsets.t - 1,
  7956. width: dim.width - offsets.l - offsets.r + 2,
  7957. height: dim.height - offsets.t - offsets.b + 2
  7958. };
  7959. if(fill){
  7960. fill = dc.Element.prototype._shapeFill(dc.Element.prototype._plotFill(fill, dim, offsets), rect);
  7961. this.surface.createRect(rect).setFill(fill);
  7962. }
  7963. if(stroke){
  7964. this.surface.createRect({
  7965. x: offsets.l, y: offsets.t,
  7966. width: dim.width - offsets.l - offsets.r + 1,
  7967. height: dim.height - offsets.t - offsets.b + 1
  7968. }).setStroke(stroke);
  7969. }
  7970. // go over the stack backwards
  7971. df.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0);
  7972. // pseudo-clipping: matting
  7973. fill = this.fill !== undefined ? this.fill : (t.chart && t.chart.fill);
  7974. stroke = this.stroke !== undefined ? this.stroke : (t.chart && t.chart.stroke);
  7975. // TRT: support for "inherit" as a named value in a theme.
  7976. if(fill == "inherit"){
  7977. // find the background color of the nearest ancestor node, and use that explicitly.
  7978. var node = this.node, fill = new dojo.Color(dojo.style(node, "backgroundColor"));
  7979. while(fill.a==0 && node!=document.documentElement){
  7980. fill = new dojo.Color(dojo.style(node, "backgroundColor"));
  7981. node = node.parentNode;
  7982. }
  7983. }
  7984. if(fill){
  7985. fill = dc.Element.prototype._plotFill(fill, dim, offsets);
  7986. if(offsets.l){ // left
  7987. rect = {
  7988. width: offsets.l,
  7989. height: dim.height + 1
  7990. };
  7991. this.surface.createRect(rect).setFill(dc.Element.prototype._shapeFill(fill, rect));
  7992. }
  7993. if(offsets.r){ // right
  7994. rect = {
  7995. x: dim.width - offsets.r,
  7996. width: offsets.r + 1,
  7997. height: dim.height + 2
  7998. };
  7999. this.surface.createRect(rect).setFill(dc.Element.prototype._shapeFill(fill, rect));
  8000. }
  8001. if(offsets.t){ // top
  8002. rect = {
  8003. width: dim.width + 1,
  8004. height: offsets.t
  8005. };
  8006. this.surface.createRect(rect).setFill(dc.Element.prototype._shapeFill(fill, rect));
  8007. }
  8008. if(offsets.b){ // bottom
  8009. rect = {
  8010. y: dim.height - offsets.b,
  8011. width: dim.width + 1,
  8012. height: offsets.b + 2
  8013. };
  8014. this.surface.createRect(rect).setFill(dc.Element.prototype._shapeFill(fill, rect));
  8015. }
  8016. }
  8017. if(stroke){
  8018. this.surface.createRect({
  8019. width: dim.width - 1,
  8020. height: dim.height - 1
  8021. }).setStroke(stroke);
  8022. }
  8023. //create title: Whether to make chart title as a widget which extends dojox.charting.Element?
  8024. if(this.title){
  8025. var forceHtmlLabels = (g.renderer == "canvas"),
  8026. labelType = forceHtmlLabels || !dojo.isIE && !dojo.isOpera ? "html" : "gfx",
  8027. tsize = g.normalizedLength(g.splitFontString(this.titleFont).size);
  8028. this.chartTitle = dc.axis2d.common.createText[labelType](
  8029. this,
  8030. this.surface,
  8031. dim.width/2,
  8032. this.titlePos=="top" ? tsize + this.margins.t : dim.height - this.margins.b,
  8033. "middle",
  8034. this.title,
  8035. this.titleFont,
  8036. this.titleFontColor
  8037. );
  8038. }
  8039. // go over axes
  8040. df.forIn(this.axes, function(axis){ axis.render(dim, offsets); });
  8041. this._makeClean();
  8042. // BEGIN FOR HTML CANVAS
  8043. if(this.surface.render){ this.surface.render(); };
  8044. // END FOR HTML CANVAS
  8045. return this; // dojox.charting.Chart
  8046. },
  8047. delayedRender: function(){
  8048. // summary:
  8049. // Delayed render, which is used to collect multiple updates
  8050. // within a delayInMs time window.
  8051. // returns: dojox.charting.Chart
  8052. // A reference to the current chart for functional chaining.
  8053. if(!this._delayedRenderHandle){
  8054. this._delayedRenderHandle = setTimeout(
  8055. dojo.hitch(this, function(){
  8056. clearTimeout(this._delayedRenderHandle);
  8057. this._delayedRenderHandle = null;
  8058. this.render();
  8059. }),
  8060. this.delayInMs
  8061. );
  8062. }
  8063. return this; // dojox.charting.Chart
  8064. },
  8065. connectToPlot: function(name, object, method){
  8066. // summary:
  8067. // A convenience method to connect a function to a plot.
  8068. // name: String
  8069. // The name of the plot as defined by addPlot.
  8070. // object: Object
  8071. // The object to be connected.
  8072. // method: Function
  8073. // The function to be executed.
  8074. // returns: Array
  8075. // A handle to the connection, as defined by dojo.connect (see dojo.connect).
  8076. return name in this.plots ? this.stack[this.plots[name]].connect(object, method) : null; // Array
  8077. },
  8078. fireEvent: function(seriesName, eventName, index){
  8079. // summary:
  8080. // Fires a synthetic event for a series item.
  8081. // seriesName: String:
  8082. // Series name.
  8083. // eventName: String:
  8084. // Event name to simulate: onmouseover, onmouseout, onclick.
  8085. // index: Number:
  8086. // Valid data value index for the event.
  8087. // returns: dojox.charting.Chart
  8088. // A reference to the current chart for functional chaining.
  8089. if(seriesName in this.runs){
  8090. var plotName = this.series[this.runs[seriesName]].plot;
  8091. if(plotName in this.plots){
  8092. var plot = this.stack[this.plots[plotName]];
  8093. if(plot){
  8094. plot.fireEvent(seriesName, eventName, index);
  8095. }
  8096. }
  8097. }
  8098. return this; // dojox.charting.Chart
  8099. },
  8100. _makeClean: function(){
  8101. // reset dirty flags
  8102. dojo.forEach(this.axes, makeClean);
  8103. dojo.forEach(this.stack, makeClean);
  8104. dojo.forEach(this.series, makeClean);
  8105. this.dirty = false;
  8106. },
  8107. _makeDirty: function(){
  8108. // reset dirty flags
  8109. dojo.forEach(this.axes, makeDirty);
  8110. dojo.forEach(this.stack, makeDirty);
  8111. dojo.forEach(this.series, makeDirty);
  8112. this.dirty = true;
  8113. },
  8114. _invalidateDependentPlots: function(plotName, /* Boolean */ verticalAxis){
  8115. if(plotName in this.plots){
  8116. var plot = this.stack[this.plots[plotName]], axis,
  8117. axisName = verticalAxis ? "vAxis" : "hAxis";
  8118. if(plot[axisName]){
  8119. axis = this.axes[plot[axisName]];
  8120. if(axis && axis.dependOnData()){
  8121. axis.dirty = true;
  8122. // find all plots and mark them dirty
  8123. dojo.forEach(this.stack, function(p){
  8124. if(p[axisName] && p[axisName] == plot[axisName]){
  8125. p.dirty = true;
  8126. }
  8127. });
  8128. }
  8129. }else{
  8130. plot.dirty = true;
  8131. }
  8132. }
  8133. }
  8134. });
  8135. function hSection(stats){
  8136. return {min: stats.hmin, max: stats.hmax};
  8137. }
  8138. function vSection(stats){
  8139. return {min: stats.vmin, max: stats.vmax};
  8140. }
  8141. function hReplace(stats, h){
  8142. stats.hmin = h.min;
  8143. stats.hmax = h.max;
  8144. }
  8145. function vReplace(stats, v){
  8146. stats.vmin = v.min;
  8147. stats.vmax = v.max;
  8148. }
  8149. function combineStats(target, source){
  8150. if(target && source){
  8151. target.min = Math.min(target.min, source.min);
  8152. target.max = Math.max(target.max, source.max);
  8153. }
  8154. return target || source;
  8155. }
  8156. function calculateAxes(stack, plotArea){
  8157. var plots = {}, axes = {};
  8158. dojo.forEach(stack, function(plot){
  8159. var stats = plots[plot.name] = plot.getSeriesStats();
  8160. if(plot.hAxis){
  8161. axes[plot.hAxis] = combineStats(axes[plot.hAxis], hSection(stats));
  8162. }
  8163. if(plot.vAxis){
  8164. axes[plot.vAxis] = combineStats(axes[plot.vAxis], vSection(stats));
  8165. }
  8166. });
  8167. dojo.forEach(stack, function(plot){
  8168. var stats = plots[plot.name];
  8169. if(plot.hAxis){
  8170. hReplace(stats, axes[plot.hAxis]);
  8171. }
  8172. if(plot.vAxis){
  8173. vReplace(stats, axes[plot.vAxis]);
  8174. }
  8175. plot.initializeScalers(plotArea, stats);
  8176. });
  8177. }
  8178. })();
  8179. }
  8180. if(!dojo._hasResource["dojox.charting.widget.Chart"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  8181. dojo._hasResource["dojox.charting.widget.Chart"] = true;
  8182. dojo.provide("dojox.charting.widget.Chart");
  8183. (function(){
  8184. var collectParams, collectAxisParams, collectPlotParams,
  8185. collectActionParams, collectDataParams,
  8186. notNull = function(o){ return o; },
  8187. df = dojox.lang.functional,
  8188. du = dojox.lang.utils,
  8189. dc = dojox.charting,
  8190. d = dojo;
  8191. dojo.declare("dojox.charting.widget.Chart", dijit._Widget, {
  8192. // parameters for the markup
  8193. // theme for the chart
  8194. theme: null,
  8195. // margins for the chart: {l: 10, r: 10, t: 10, b: 10}
  8196. margins: null,
  8197. // chart area
  8198. stroke: null,
  8199. fill: null,
  8200. // methods
  8201. buildRendering: function(){
  8202. var n = this.domNode = this.srcNodeRef;
  8203. // collect chart parameters
  8204. var axes = d.query("> .axis", n).map(collectAxisParams).filter(notNull),
  8205. plots = d.query("> .plot", n).map(collectPlotParams).filter(notNull),
  8206. actions = d.query("> .action", n).map(collectActionParams).filter(notNull),
  8207. series = d.query("> .series", n).map(collectDataParams).filter(notNull);
  8208. // build the chart
  8209. n.innerHTML = "";
  8210. var c = this.chart = new dc.Chart(n, {
  8211. margins: this.margins,
  8212. stroke: this.stroke,
  8213. fill: this.fill
  8214. });
  8215. // add collected parameters
  8216. if(this.theme){
  8217. c.setTheme(this.theme);
  8218. }
  8219. axes.forEach(function(axis){
  8220. c.addAxis(axis.name, axis.kwArgs);
  8221. });
  8222. plots.forEach(function(plot){
  8223. c.addPlot(plot.name, plot.kwArgs);
  8224. });
  8225. this.actions = actions.map(function(action){
  8226. return new action.action(c, action.plot, action.kwArgs)
  8227. });
  8228. var render = df.foldl(series, function(render, series){
  8229. if(series.type == "data"){
  8230. c.addSeries(series.name, series.data, series.kwArgs);
  8231. render = true;
  8232. }else{
  8233. c.addSeries(series.name, [0], series.kwArgs);
  8234. var kw = {};
  8235. du.updateWithPattern(
  8236. kw,
  8237. series.kwArgs,
  8238. {
  8239. "query": "",
  8240. "queryOptions": null,
  8241. "start": 0,
  8242. "count": 1 //,
  8243. // "sort": []
  8244. },
  8245. true
  8246. );
  8247. if(series.kwArgs.sort){
  8248. // sort is a complex object type and doesn't survive coercian
  8249. kw.sort = dojo.clone(series.kwArgs.sort);
  8250. }
  8251. d.mixin(kw, {
  8252. onComplete: function(data){
  8253. var values;
  8254. if("valueFn" in series.kwArgs){
  8255. var fn = series.kwArgs.valueFn;
  8256. values = d.map(data, function(x){
  8257. return fn(series.data.getValue(x, series.field, 0));
  8258. });
  8259. }else{
  8260. values = d.map(data, function(x){
  8261. return series.data.getValue(x, series.field, 0);
  8262. });
  8263. }
  8264. c.addSeries(series.name, values, series.kwArgs).render();
  8265. }
  8266. });
  8267. series.data.fetch(kw);
  8268. }
  8269. return render;
  8270. }, false);
  8271. if(render){ c.render(); }
  8272. },
  8273. destroy: function(){
  8274. // summary: properly destroy the widget
  8275. this.chart.destroy();
  8276. this.inherited(arguments);
  8277. },
  8278. resize: function(box){
  8279. // summary:
  8280. // Resize the widget.
  8281. // description:
  8282. // Resize the domNode and the widget surface to the dimensions of a box of the following form:
  8283. // `{ l: 50, t: 200, w: 300: h: 150 }`
  8284. // If no box is provided, resize the surface to the marginBox of the domNode.
  8285. // box:
  8286. // If passed, denotes the new size of the widget.
  8287. this.chart.resize(box);
  8288. }
  8289. });
  8290. collectParams = function(node, type, kw){
  8291. var dp = eval("(" + type + ".prototype.defaultParams)");
  8292. var x, attr;
  8293. for(x in dp){
  8294. if(x in kw){ continue; }
  8295. attr = node.getAttribute(x);
  8296. kw[x] = du.coerceType(dp[x], attr == null || typeof attr == "undefined" ? dp[x] : attr);
  8297. }
  8298. var op = eval("(" + type + ".prototype.optionalParams)");
  8299. for(x in op){
  8300. if(x in kw){ continue; }
  8301. attr = node.getAttribute(x);
  8302. if(attr != null){
  8303. kw[x] = du.coerceType(op[x], attr);
  8304. }
  8305. }
  8306. };
  8307. collectAxisParams = function(node){
  8308. var name = node.getAttribute("name"), type = node.getAttribute("type");
  8309. if(!name){ return null; }
  8310. var o = {name: name, kwArgs: {}}, kw = o.kwArgs;
  8311. if(type){
  8312. if(dc.axis2d[type]){
  8313. type = dojox._scopeName + ".charting.axis2d." + type;
  8314. }
  8315. var axis = eval("(" + type + ")");
  8316. if(axis){ kw.type = axis; }
  8317. }else{
  8318. type = dojox._scopeName + ".charting.axis2d.Default";
  8319. }
  8320. collectParams(node, type, kw);
  8321. // compatibility conversions
  8322. if(kw.font || kw.fontColor){
  8323. if(!kw.tick){
  8324. kw.tick = {};
  8325. }
  8326. if(kw.font){
  8327. kw.tick.font = kw.font;
  8328. }
  8329. if(kw.fontColor){
  8330. kw.tick.fontColor = kw.fontColor;
  8331. }
  8332. }
  8333. return o;
  8334. };
  8335. collectPlotParams = function(node){
  8336. // var name = d.attr(node, "name"), type = d.attr(node, "type");
  8337. var name = node.getAttribute("name"), type = node.getAttribute("type");
  8338. if(!name){ return null; }
  8339. var o = {name: name, kwArgs: {}}, kw = o.kwArgs;
  8340. if(type){
  8341. if(dc.plot2d && dc.plot2d[type]){
  8342. type = dojox._scopeName + ".charting.plot2d." + type;
  8343. }
  8344. var plot = eval("(" + type + ")");
  8345. if(plot){ kw.type = plot; }
  8346. }else{
  8347. type = dojox._scopeName + ".charting.plot2d.Default";
  8348. }
  8349. collectParams(node, type, kw);
  8350. return o;
  8351. };
  8352. collectActionParams = function(node){
  8353. // var plot = d.attr(node, "plot"), type = d.attr(node, "type");
  8354. var plot = node.getAttribute("plot"), type = node.getAttribute("type");
  8355. if(!plot){ plot = "default"; }
  8356. var o = {plot: plot, kwArgs: {}}, kw = o.kwArgs;
  8357. if(type){
  8358. if(dc.action2d[type]){
  8359. type = dojox._scopeName + ".charting.action2d." + type;
  8360. }
  8361. var action = eval("(" + type + ")");
  8362. if(!action){ return null; }
  8363. o.action = action;
  8364. }else{
  8365. return null;
  8366. }
  8367. collectParams(node, type, kw);
  8368. return o;
  8369. };
  8370. collectDataParams = function(node){
  8371. var ga = d.partial(d.attr, node);
  8372. var name = ga("name");
  8373. if(!name){ return null; }
  8374. var o = { name: name, kwArgs: {} }, kw = o.kwArgs, t;
  8375. t = ga("plot");
  8376. if(t != null){ kw.plot = t; }
  8377. t = ga("marker");
  8378. if(t != null){ kw.marker = t; }
  8379. t = ga("stroke");
  8380. if(t != null){ kw.stroke = eval("(" + t + ")"); }
  8381. t = ga("outline");
  8382. if(t != null){ kw.outline = eval("(" + t + ")"); }
  8383. t = ga("shadow");
  8384. if(t != null){ kw.shadow = eval("(" + t + ")"); }
  8385. t = ga("fill");
  8386. if(t != null){ kw.fill = eval("(" + t + ")"); }
  8387. t = ga("font");
  8388. if(t != null){ kw.font = t; }
  8389. t = ga("fontColor");
  8390. if(t != null){ kw.fontColor = eval("(" + t + ")"); }
  8391. t = ga("legend");
  8392. if(t != null){ kw.legend = t; }
  8393. t = ga("data");
  8394. if(t != null){
  8395. o.type = "data";
  8396. o.data = t ? dojo.map(String(t).split(','), Number) : [];
  8397. return o;
  8398. }
  8399. t = ga("array");
  8400. if(t != null){
  8401. o.type = "data";
  8402. o.data = eval("(" + t + ")");
  8403. return o;
  8404. }
  8405. t = ga("store");
  8406. if(t != null){
  8407. o.type = "store";
  8408. o.data = eval("(" + t + ")");
  8409. t = ga("field");
  8410. o.field = t != null ? t : "value";
  8411. t = ga("query");
  8412. if(!!t){ kw.query = t; }
  8413. t = ga("queryOptions");
  8414. if(!!t){ kw.queryOptions = eval("(" + t + ")"); }
  8415. t = ga("start");
  8416. if(!!t){ kw.start = Number(t); }
  8417. t = ga("count");
  8418. if(!!t){ kw.count = Number(t); }
  8419. t = ga("sort");
  8420. if(!!t){ kw.sort = eval("("+t+")"); }
  8421. t = ga("valueFn");
  8422. if(!!t){ kw.valueFn = df.lambda(t); }
  8423. return o;
  8424. }
  8425. return null;
  8426. };
  8427. })();
  8428. }
  8429. if(!dojo._hasResource["dojo.fx.easing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  8430. dojo._hasResource["dojo.fx.easing"] = true;
  8431. dojo.provide("dojo.fx.easing");
  8432. dojo.getObject("fx.easing", true, dojo);
  8433. dojo.fx.easing = {
  8434. // summary:
  8435. // Collection of easing functions to use beyond the default
  8436. // `dojo._defaultEasing` function.
  8437. //
  8438. // description:
  8439. //
  8440. // Easing functions are used to manipulate the iteration through
  8441. // an `dojo.Animation`s _Line. _Line being the properties of an Animation,
  8442. // and the easing function progresses through that Line determing
  8443. // how quickly (or slowly) it should go. Or more accurately: modify
  8444. // the value of the _Line based on the percentage of animation completed.
  8445. //
  8446. // All functions follow a simple naming convention of "ease type" + "when".
  8447. // If the name of the function ends in Out, the easing described appears
  8448. // towards the end of the animation. "In" means during the beginning,
  8449. // and InOut means both ranges of the Animation will applied, both
  8450. // beginning and end.
  8451. //
  8452. // One does not call the easing function directly, it must be passed to
  8453. // the `easing` property of an animation.
  8454. //
  8455. // example:
  8456. // |
  8457. // | var anim = dojo.fadeOut({
  8458. // | node: 'node',
  8459. // | duration: 2000,
  8460. // | // note there is no ()
  8461. // | easing: dojo.fx.easing.quadIn
  8462. // | }).play();
  8463. //
  8464. linear: function(/* Decimal? */n){
  8465. // summary: A linear easing function
  8466. return n;
  8467. },
  8468. quadIn: function(/* Decimal? */n){
  8469. return Math.pow(n, 2);
  8470. },
  8471. quadOut: function(/* Decimal? */n){
  8472. return n * (n - 2) * -1;
  8473. },
  8474. quadInOut: function(/* Decimal? */n){
  8475. n = n * 2;
  8476. if(n < 1){ return Math.pow(n, 2) / 2; }
  8477. return -1 * ((--n) * (n - 2) - 1) / 2;
  8478. },
  8479. cubicIn: function(/* Decimal? */n){
  8480. return Math.pow(n, 3);
  8481. },
  8482. cubicOut: function(/* Decimal? */n){
  8483. return Math.pow(n - 1, 3) + 1;
  8484. },
  8485. cubicInOut: function(/* Decimal? */n){
  8486. n = n * 2;
  8487. if(n < 1){ return Math.pow(n, 3) / 2; }
  8488. n -= 2;
  8489. return (Math.pow(n, 3) + 2) / 2;
  8490. },
  8491. quartIn: function(/* Decimal? */n){
  8492. return Math.pow(n, 4);
  8493. },
  8494. quartOut: function(/* Decimal? */n){
  8495. return -1 * (Math.pow(n - 1, 4) - 1);
  8496. },
  8497. quartInOut: function(/* Decimal? */n){
  8498. n = n * 2;
  8499. if(n < 1){ return Math.pow(n, 4) / 2; }
  8500. n -= 2;
  8501. return -1 / 2 * (Math.pow(n, 4) - 2);
  8502. },
  8503. quintIn: function(/* Decimal? */n){
  8504. return Math.pow(n, 5);
  8505. },
  8506. quintOut: function(/* Decimal? */n){
  8507. return Math.pow(n - 1, 5) + 1;
  8508. },
  8509. quintInOut: function(/* Decimal? */n){
  8510. n = n * 2;
  8511. if(n < 1){ return Math.pow(n, 5) / 2; };
  8512. n -= 2;
  8513. return (Math.pow(n, 5) + 2) / 2;
  8514. },
  8515. sineIn: function(/* Decimal? */n){
  8516. return -1 * Math.cos(n * (Math.PI / 2)) + 1;
  8517. },
  8518. sineOut: function(/* Decimal? */n){
  8519. return Math.sin(n * (Math.PI / 2));
  8520. },
  8521. sineInOut: function(/* Decimal? */n){
  8522. return -1 * (Math.cos(Math.PI * n) - 1) / 2;
  8523. },
  8524. expoIn: function(/* Decimal? */n){
  8525. return (n == 0) ? 0 : Math.pow(2, 10 * (n - 1));
  8526. },
  8527. expoOut: function(/* Decimal? */n){
  8528. return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1);
  8529. },
  8530. expoInOut: function(/* Decimal? */n){
  8531. if(n == 0){ return 0; }
  8532. if(n == 1){ return 1; }
  8533. n = n * 2;
  8534. if(n < 1){ return Math.pow(2, 10 * (n - 1)) / 2; }
  8535. --n;
  8536. return (-1 * Math.pow(2, -10 * n) + 2) / 2;
  8537. },
  8538. circIn: function(/* Decimal? */n){
  8539. return -1 * (Math.sqrt(1 - Math.pow(n, 2)) - 1);
  8540. },
  8541. circOut: function(/* Decimal? */n){
  8542. n = n - 1;
  8543. return Math.sqrt(1 - Math.pow(n, 2));
  8544. },
  8545. circInOut: function(/* Decimal? */n){
  8546. n = n * 2;
  8547. if(n < 1){ return -1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); }
  8548. n -= 2;
  8549. return 1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) + 1);
  8550. },
  8551. backIn: function(/* Decimal? */n){
  8552. // summary:
  8553. // An easing function that starts away from the target,
  8554. // and quickly accelerates towards the end value.
  8555. //
  8556. // Use caution when the easing will cause values to become
  8557. // negative as some properties cannot be set to negative values.
  8558. var s = 1.70158;
  8559. return Math.pow(n, 2) * ((s + 1) * n - s);
  8560. },
  8561. backOut: function(/* Decimal? */n){
  8562. // summary:
  8563. // An easing function that pops past the range briefly, and slowly comes back.
  8564. //
  8565. // description:
  8566. // An easing function that pops past the range briefly, and slowly comes back.
  8567. //
  8568. // Use caution when the easing will cause values to become negative as some
  8569. // properties cannot be set to negative values.
  8570. n = n - 1;
  8571. var s = 1.70158;
  8572. return Math.pow(n, 2) * ((s + 1) * n + s) + 1;
  8573. },
  8574. backInOut: function(/* Decimal? */n){
  8575. // summary:
  8576. // An easing function combining the effects of `backIn` and `backOut`
  8577. //
  8578. // description:
  8579. // An easing function combining the effects of `backIn` and `backOut`.
  8580. // Use caution when the easing will cause values to become negative
  8581. // as some properties cannot be set to negative values.
  8582. var s = 1.70158 * 1.525;
  8583. n = n * 2;
  8584. if(n < 1){ return (Math.pow(n, 2) * ((s + 1) * n - s)) / 2; }
  8585. n-=2;
  8586. return (Math.pow(n, 2) * ((s + 1) * n + s) + 2) / 2;
  8587. },
  8588. elasticIn: function(/* Decimal? */n){
  8589. // summary:
  8590. // An easing function the elastically snaps from the start value
  8591. //
  8592. // description:
  8593. // An easing function the elastically snaps from the start value
  8594. //
  8595. // Use caution when the elasticity will cause values to become negative
  8596. // as some properties cannot be set to negative values.
  8597. if(n == 0 || n == 1){ return n; }
  8598. var p = .3;
  8599. var s = p / 4;
  8600. n = n - 1;
  8601. return -1 * Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p);
  8602. },
  8603. elasticOut: function(/* Decimal? */n){
  8604. // summary:
  8605. // An easing function that elasticly snaps around the target value,
  8606. // near the end of the Animation
  8607. //
  8608. // description:
  8609. // An easing function that elasticly snaps around the target value,
  8610. // near the end of the Animation
  8611. //
  8612. // Use caution when the elasticity will cause values to become
  8613. // negative as some properties cannot be set to negative values.
  8614. if(n==0 || n == 1){ return n; }
  8615. var p = .3;
  8616. var s = p / 4;
  8617. return Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p) + 1;
  8618. },
  8619. elasticInOut: function(/* Decimal? */n){
  8620. // summary:
  8621. // An easing function that elasticly snaps around the value, near
  8622. // the beginning and end of the Animation.
  8623. //
  8624. // description:
  8625. // An easing function that elasticly snaps around the value, near
  8626. // the beginning and end of the Animation.
  8627. //
  8628. // Use caution when the elasticity will cause values to become
  8629. // negative as some properties cannot be set to negative values.
  8630. if(n == 0) return 0;
  8631. n = n * 2;
  8632. if(n == 2) return 1;
  8633. var p = .3 * 1.5;
  8634. var s = p / 4;
  8635. if(n < 1){
  8636. n -= 1;
  8637. return -.5 * (Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p));
  8638. }
  8639. n -= 1;
  8640. return .5 * (Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)) + 1;
  8641. },
  8642. bounceIn: function(/* Decimal? */n){
  8643. // summary:
  8644. // An easing function that 'bounces' near the beginning of an Animation
  8645. return (1 - dojo.fx.easing.bounceOut(1 - n)); // Decimal
  8646. },
  8647. bounceOut: function(/* Decimal? */n){
  8648. // summary:
  8649. // An easing function that 'bounces' near the end of an Animation
  8650. var s = 7.5625;
  8651. var p = 2.75;
  8652. var l;
  8653. if(n < (1 / p)){
  8654. l = s * Math.pow(n, 2);
  8655. }else if(n < (2 / p)){
  8656. n -= (1.5 / p);
  8657. l = s * Math.pow(n, 2) + .75;
  8658. }else if(n < (2.5 / p)){
  8659. n -= (2.25 / p);
  8660. l = s * Math.pow(n, 2) + .9375;
  8661. }else{
  8662. n -= (2.625 / p);
  8663. l = s * Math.pow(n, 2) + .984375;
  8664. }
  8665. return l;
  8666. },
  8667. bounceInOut: function(/* Decimal? */n){
  8668. // summary:
  8669. // An easing function that 'bounces' at the beginning and end of the Animation
  8670. if(n < 0.5){ return dojo.fx.easing.bounceIn(n * 2) / 2; }
  8671. return (dojo.fx.easing.bounceOut(n * 2 - 1) / 2) + 0.5; // Decimal
  8672. }
  8673. };
  8674. }
  8675. if(!dojo._hasResource["dojox.gfx.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  8676. dojo._hasResource["dojox.gfx.fx"] = true;
  8677. dojo.provide("dojox.gfx.fx");
  8678. (function(){
  8679. var d = dojo, g = dojox.gfx, m = g.matrix;
  8680. // Generic interpolators. Should they be moved to dojox.fx?
  8681. function InterpolNumber(start, end){
  8682. this.start = start, this.end = end;
  8683. }
  8684. InterpolNumber.prototype.getValue = function(r){
  8685. return (this.end - this.start) * r + this.start;
  8686. };
  8687. function InterpolUnit(start, end, units){
  8688. this.start = start, this.end = end;
  8689. this.units = units;
  8690. }
  8691. InterpolUnit.prototype.getValue = function(r){
  8692. return (this.end - this.start) * r + this.start + this.units;
  8693. };
  8694. function InterpolColor(start, end){
  8695. this.start = start, this.end = end;
  8696. this.temp = new dojo.Color();
  8697. }
  8698. InterpolColor.prototype.getValue = function(r){
  8699. return d.blendColors(this.start, this.end, r, this.temp);
  8700. };
  8701. function InterpolValues(values){
  8702. this.values = values;
  8703. this.length = values.length;
  8704. }
  8705. InterpolValues.prototype.getValue = function(r){
  8706. return this.values[Math.min(Math.floor(r * this.length), this.length - 1)];
  8707. };
  8708. function InterpolObject(values, def){
  8709. this.values = values;
  8710. this.def = def ? def : {};
  8711. }
  8712. InterpolObject.prototype.getValue = function(r){
  8713. var ret = dojo.clone(this.def);
  8714. for(var i in this.values){
  8715. ret[i] = this.values[i].getValue(r);
  8716. }
  8717. return ret;
  8718. };
  8719. function InterpolTransform(stack, original){
  8720. this.stack = stack;
  8721. this.original = original;
  8722. }
  8723. InterpolTransform.prototype.getValue = function(r){
  8724. var ret = [];
  8725. dojo.forEach(this.stack, function(t){
  8726. if(t instanceof m.Matrix2D){
  8727. ret.push(t);
  8728. return;
  8729. }
  8730. if(t.name == "original" && this.original){
  8731. ret.push(this.original);
  8732. return;
  8733. }
  8734. if(!(t.name in m)){ return; }
  8735. var f = m[t.name];
  8736. if(typeof f != "function"){
  8737. // constant
  8738. ret.push(f);
  8739. return;
  8740. }
  8741. var val = dojo.map(t.start, function(v, i){
  8742. return (t.end[i] - v) * r + v;
  8743. }),
  8744. matrix = f.apply(m, val);
  8745. if(matrix instanceof m.Matrix2D){
  8746. ret.push(matrix);
  8747. }
  8748. }, this);
  8749. return ret;
  8750. };
  8751. var transparent = new d.Color(0, 0, 0, 0);
  8752. function getColorInterpol(prop, obj, name, def){
  8753. if(prop.values){
  8754. return new InterpolValues(prop.values);
  8755. }
  8756. var value, start, end;
  8757. if(prop.start){
  8758. start = g.normalizeColor(prop.start);
  8759. }else{
  8760. start = value = obj ? (name ? obj[name] : obj) : def;
  8761. }
  8762. if(prop.end){
  8763. end = g.normalizeColor(prop.end);
  8764. }else{
  8765. if(!value){
  8766. value = obj ? (name ? obj[name] : obj) : def;
  8767. }
  8768. end = value;
  8769. }
  8770. return new InterpolColor(start, end);
  8771. }
  8772. function getNumberInterpol(prop, obj, name, def){
  8773. if(prop.values){
  8774. return new InterpolValues(prop.values);
  8775. }
  8776. var value, start, end;
  8777. if(prop.start){
  8778. start = prop.start;
  8779. }else{
  8780. start = value = obj ? obj[name] : def;
  8781. }
  8782. if(prop.end){
  8783. end = prop.end;
  8784. }else{
  8785. if(typeof value != "number"){
  8786. value = obj ? obj[name] : def;
  8787. }
  8788. end = value;
  8789. }
  8790. return new InterpolNumber(start, end);
  8791. }
  8792. g.fx.animateStroke = function(/*Object*/ args){
  8793. // summary:
  8794. // Returns an animation which will change stroke properties over time
  8795. // example:
  8796. // | dojox.gfx.fx.animateStroke{{
  8797. // | shape: shape,
  8798. // | duration: 500,
  8799. // | color: {start: "red", end: "green"},
  8800. // | width: {end: 15},
  8801. // | join: {values: ["miter", "bevel", "round"]}
  8802. // | }).play();
  8803. if(!args.easing){ args.easing = d._defaultEasing; }
  8804. var anim = new d.Animation(args), shape = args.shape, stroke;
  8805. d.connect(anim, "beforeBegin", anim, function(){
  8806. stroke = shape.getStroke();
  8807. var prop = args.color, values = {}, value, start, end;
  8808. if(prop){
  8809. values.color = getColorInterpol(prop, stroke, "color", transparent);
  8810. }
  8811. prop = args.style;
  8812. if(prop && prop.values){
  8813. values.style = new InterpolValues(prop.values);
  8814. }
  8815. prop = args.width;
  8816. if(prop){
  8817. values.width = getNumberInterpol(prop, stroke, "width", 1);
  8818. }
  8819. prop = args.cap;
  8820. if(prop && prop.values){
  8821. values.cap = new InterpolValues(prop.values);
  8822. }
  8823. prop = args.join;
  8824. if(prop){
  8825. if(prop.values){
  8826. values.join = new InterpolValues(prop.values);
  8827. }else{
  8828. start = prop.start ? prop.start : (stroke && stroke.join || 0);
  8829. end = prop.end ? prop.end : (stroke && stroke.join || 0);
  8830. if(typeof start == "number" && typeof end == "number"){
  8831. values.join = new InterpolNumber(start, end);
  8832. }
  8833. }
  8834. }
  8835. this.curve = new InterpolObject(values, stroke);
  8836. });
  8837. d.connect(anim, "onAnimate", shape, "setStroke");
  8838. return anim; // dojo.Animation
  8839. };
  8840. g.fx.animateFill = function(/*Object*/ args){
  8841. // summary:
  8842. // Returns an animation which will change fill color over time.
  8843. // Only solid fill color is supported at the moment
  8844. // example:
  8845. // | dojox.gfx.fx.animateFill{{
  8846. // | shape: shape,
  8847. // | duration: 500,
  8848. // | color: {start: "red", end: "green"}
  8849. // | }).play();
  8850. if(!args.easing){ args.easing = d._defaultEasing; }
  8851. var anim = new d.Animation(args), shape = args.shape, fill;
  8852. d.connect(anim, "beforeBegin", anim, function(){
  8853. fill = shape.getFill();
  8854. var prop = args.color, values = {};
  8855. if(prop){
  8856. this.curve = getColorInterpol(prop, fill, "", transparent);
  8857. }
  8858. });
  8859. d.connect(anim, "onAnimate", shape, "setFill");
  8860. return anim; // dojo.Animation
  8861. };
  8862. g.fx.animateFont = function(/*Object*/ args){
  8863. // summary:
  8864. // Returns an animation which will change font properties over time
  8865. // example:
  8866. // | dojox.gfx.fx.animateFont{{
  8867. // | shape: shape,
  8868. // | duration: 500,
  8869. // | variant: {values: ["normal", "small-caps"]},
  8870. // | size: {end: 10, units: "pt"}
  8871. // | }).play();
  8872. if(!args.easing){ args.easing = d._defaultEasing; }
  8873. var anim = new d.Animation(args), shape = args.shape, font;
  8874. d.connect(anim, "beforeBegin", anim, function(){
  8875. font = shape.getFont();
  8876. var prop = args.style, values = {}, value, start, end;
  8877. if(prop && prop.values){
  8878. values.style = new InterpolValues(prop.values);
  8879. }
  8880. prop = args.variant;
  8881. if(prop && prop.values){
  8882. values.variant = new InterpolValues(prop.values);
  8883. }
  8884. prop = args.weight;
  8885. if(prop && prop.values){
  8886. values.weight = new InterpolValues(prop.values);
  8887. }
  8888. prop = args.family;
  8889. if(prop && prop.values){
  8890. values.family = new InterpolValues(prop.values);
  8891. }
  8892. prop = args.size;
  8893. if(prop && prop.units){
  8894. start = parseFloat(prop.start ? prop.start : (shape.font && shape.font.size || "0"));
  8895. end = parseFloat(prop.end ? prop.end : (shape.font && shape.font.size || "0"));
  8896. values.size = new InterpolUnit(start, end, prop.units);
  8897. }
  8898. this.curve = new InterpolObject(values, font);
  8899. });
  8900. d.connect(anim, "onAnimate", shape, "setFont");
  8901. return anim; // dojo.Animation
  8902. };
  8903. g.fx.animateTransform = function(/*Object*/ args){
  8904. // summary:
  8905. // Returns an animation which will change transformation over time
  8906. // example:
  8907. // | dojox.gfx.fx.animateTransform{{
  8908. // | shape: shape,
  8909. // | duration: 500,
  8910. // | transform: [
  8911. // | {name: "translate", start: [0, 0], end: [200, 200]},
  8912. // | {name: "original"}
  8913. // | ]
  8914. // | }).play();
  8915. if(!args.easing){ args.easing = d._defaultEasing; }
  8916. var anim = new d.Animation(args), shape = args.shape, original;
  8917. d.connect(anim, "beforeBegin", anim, function(){
  8918. original = shape.getTransform();
  8919. this.curve = new InterpolTransform(args.transform, original);
  8920. });
  8921. d.connect(anim, "onAnimate", shape, "setTransform");
  8922. return anim; // dojo.Animation
  8923. };
  8924. })();
  8925. }
  8926. if(!dojo._hasResource["dojox.charting.action2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  8927. dojo._hasResource["dojox.charting.action2d.Base"] = true;
  8928. dojo.provide("dojox.charting.action2d.Base");
  8929. /*=====
  8930. dojox.charting.action2d.__BaseCtorArgs = function(duration, easing){
  8931. // summary:
  8932. // The base keyword arguments object for creating an action2d.
  8933. // duration: Number?
  8934. // The amount of time in milliseconds for an animation to last. Default is 400.
  8935. // easing: dojo.fx.easing.*?
  8936. // An easing object (see dojo.fx.easing) for use in an animation. The
  8937. // default is dojo.fx.easing.backOut.
  8938. this.duration = duration;
  8939. this.easing = easing;
  8940. }
  8941. =====*/
  8942. (function(){
  8943. var DEFAULT_DURATION = 400, // ms
  8944. DEFAULT_EASING = dojo.fx.easing.backOut,
  8945. df = dojox.lang.functional;
  8946. dojo.declare("dojox.charting.action2d.Base", null, {
  8947. overOutEvents: {onmouseover: 1, onmouseout: 1},
  8948. constructor: function(chart, plot, kwargs){
  8949. // summary:
  8950. // Create a new base Action.
  8951. // chart: dojox.charting.Chart2D
  8952. // The chart this action applies to.
  8953. // plot: String?
  8954. // The name of the plot this action belongs to. If none is passed "default" is assumed.
  8955. // kwargs: dojox.charting.action2d.__BaseCtorArgs?
  8956. // Optional arguments for the action.
  8957. this.chart = chart;
  8958. this.plot = plot || "default";
  8959. this.anim = {};
  8960. // process common optional named parameters
  8961. if(!kwargs){ kwargs = {}; }
  8962. this.duration = kwargs.duration ? kwargs.duration : DEFAULT_DURATION;
  8963. this.easing = kwargs.easing ? kwargs.easing : DEFAULT_EASING;
  8964. },
  8965. connect: function(){
  8966. // summary:
  8967. // Connect this action to the given plot.
  8968. this.handle = this.chart.connectToPlot(this.plot, this, "process");
  8969. },
  8970. disconnect: function(){
  8971. // summary:
  8972. // Disconnect this action from the given plot, if connected.
  8973. if(this.handle){
  8974. dojo.disconnect(this.handle);
  8975. this.handle = null;
  8976. }
  8977. },
  8978. reset: function(){
  8979. // summary:
  8980. // Reset the action.
  8981. },
  8982. destroy: function(){
  8983. // summary:
  8984. // Do any cleanup needed when destroying parent elements.
  8985. this.disconnect();
  8986. df.forIn(this.anim, function(o){
  8987. df.forIn(o, function(anim){
  8988. anim.action.stop(true);
  8989. });
  8990. });
  8991. this.anim = {};
  8992. }
  8993. });
  8994. })();
  8995. }
  8996. if(!dojo._hasResource["dojox.charting.action2d.Highlight"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  8997. dojo._hasResource["dojox.charting.action2d.Highlight"] = true;
  8998. dojo.provide("dojox.charting.action2d.Highlight");
  8999. /*=====
  9000. dojo.declare("dojox.charting.action2d.__HighlightCtorArgs", dojox.charting.action2d.__BaseCtorArgs, {
  9001. // summary:
  9002. // Additional arguments for highlighting actions.
  9003. // highlight: String|dojo.Color|Function?
  9004. // Either a color or a function that creates a color when highlighting happens.
  9005. highlight: null
  9006. });
  9007. =====*/
  9008. (function(){
  9009. var DEFAULT_SATURATION = 100, // %
  9010. DEFAULT_LUMINOSITY1 = 75, // %
  9011. DEFAULT_LUMINOSITY2 = 50, // %
  9012. c = dojox.color,
  9013. cc = function(color){
  9014. return function(){ return color; };
  9015. },
  9016. hl = function(color){
  9017. var a = new c.Color(color),
  9018. x = a.toHsl();
  9019. if(x.s == 0){
  9020. x.l = x.l < 50 ? 100 : 0;
  9021. }else{
  9022. x.s = DEFAULT_SATURATION;
  9023. if(x.l < DEFAULT_LUMINOSITY2){
  9024. x.l = DEFAULT_LUMINOSITY1;
  9025. }else if(x.l > DEFAULT_LUMINOSITY1){
  9026. x.l = DEFAULT_LUMINOSITY2;
  9027. }else{
  9028. x.l = x.l - DEFAULT_LUMINOSITY2 > DEFAULT_LUMINOSITY1 - x.l ?
  9029. DEFAULT_LUMINOSITY2 : DEFAULT_LUMINOSITY1;
  9030. }
  9031. }
  9032. return c.fromHsl(x);
  9033. };
  9034. dojo.declare("dojox.charting.action2d.Highlight", dojox.charting.action2d.Base, {
  9035. // summary:
  9036. // Creates a highlighting action on a plot, where an element on that plot
  9037. // has a highlight on it.
  9038. // the data description block for the widget parser
  9039. defaultParams: {
  9040. duration: 400, // duration of the action in ms
  9041. easing: dojo.fx.easing.backOut // easing for the action
  9042. },
  9043. optionalParams: {
  9044. highlight: "red" // name for the highlight color
  9045. // programmatic instantiation can use functions and color objects
  9046. },
  9047. constructor: function(chart, plot, kwArgs){
  9048. // summary:
  9049. // Create the highlighting action and connect it to the plot.
  9050. // chart: dojox.charting.Chart2D
  9051. // The chart this action belongs to.
  9052. // plot: String?
  9053. // The plot this action is attached to. If not passed, "default" is assumed.
  9054. // kwArgs: dojox.charting.action2d.__HighlightCtorArgs?
  9055. // Optional keyword arguments object for setting parameters.
  9056. var a = kwArgs && kwArgs.highlight;
  9057. this.colorFun = a ? (dojo.isFunction(a) ? a : cc(a)) : hl;
  9058. this.connect();
  9059. },
  9060. process: function(o){
  9061. // summary:
  9062. // Process the action on the given object.
  9063. // o: dojox.gfx.Shape
  9064. // The object on which to process the highlighting action.
  9065. if(!o.shape || !(o.type in this.overOutEvents)){ return; }
  9066. var runName = o.run.name, index = o.index, anim, startFill, endFill;
  9067. if(runName in this.anim){
  9068. anim = this.anim[runName][index];
  9069. }else{
  9070. this.anim[runName] = {};
  9071. }
  9072. if(anim){
  9073. anim.action.stop(true);
  9074. }else{
  9075. var color = o.shape.getFill();
  9076. if(!color || !(color instanceof dojo.Color)){
  9077. return;
  9078. }
  9079. this.anim[runName][index] = anim = {
  9080. start: color,
  9081. end: this.colorFun(color)
  9082. };
  9083. }
  9084. var start = anim.start, end = anim.end;
  9085. if(o.type == "onmouseout"){
  9086. // swap colors
  9087. var t = start;
  9088. start = end;
  9089. end = t;
  9090. }
  9091. anim.action = dojox.gfx.fx.animateFill({
  9092. shape: o.shape,
  9093. duration: this.duration,
  9094. easing: this.easing,
  9095. color: {start: start, end: end}
  9096. });
  9097. if(o.type == "onmouseout"){
  9098. dojo.connect(anim.action, "onEnd", this, function(){
  9099. if(this.anim[runName]){
  9100. delete this.anim[runName][index];
  9101. }
  9102. });
  9103. }
  9104. anim.action.play();
  9105. }
  9106. });
  9107. })();
  9108. }
  9109. if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9110. dojo._hasResource["dojo.fx.Toggler"] = true;
  9111. dojo.provide("dojo.fx.Toggler");
  9112. dojo.declare("dojo.fx.Toggler", null, {
  9113. // summary:
  9114. // A simple `dojo.Animation` toggler API.
  9115. //
  9116. // description:
  9117. // class constructor for an animation toggler. It accepts a packed
  9118. // set of arguments about what type of animation to use in each
  9119. // direction, duration, etc. All available members are mixed into
  9120. // these animations from the constructor (for example, `node`,
  9121. // `showDuration`, `hideDuration`).
  9122. //
  9123. // example:
  9124. // | var t = new dojo.fx.Toggler({
  9125. // | node: "nodeId",
  9126. // | showDuration: 500,
  9127. // | // hideDuration will default to "200"
  9128. // | showFunc: dojo.fx.wipeIn,
  9129. // | // hideFunc will default to "fadeOut"
  9130. // | });
  9131. // | t.show(100); // delay showing for 100ms
  9132. // | // ...time passes...
  9133. // | t.hide();
  9134. // node: DomNode
  9135. // the node to target for the showing and hiding animations
  9136. node: null,
  9137. // showFunc: Function
  9138. // The function that returns the `dojo.Animation` to show the node
  9139. showFunc: dojo.fadeIn,
  9140. // hideFunc: Function
  9141. // The function that returns the `dojo.Animation` to hide the node
  9142. hideFunc: dojo.fadeOut,
  9143. // showDuration:
  9144. // Time in milliseconds to run the show Animation
  9145. showDuration: 200,
  9146. // hideDuration:
  9147. // Time in milliseconds to run the hide Animation
  9148. hideDuration: 200,
  9149. // FIXME: need a policy for where the toggler should "be" the next
  9150. // time show/hide are called if we're stopped somewhere in the
  9151. // middle.
  9152. // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
  9153. // each animation individually.
  9154. // FIXME: also would be nice to have events from the animations exposed/bridged
  9155. /*=====
  9156. _showArgs: null,
  9157. _showAnim: null,
  9158. _hideArgs: null,
  9159. _hideAnim: null,
  9160. _isShowing: false,
  9161. _isHiding: false,
  9162. =====*/
  9163. constructor: function(args){
  9164. var _t = this;
  9165. dojo.mixin(_t, args);
  9166. _t.node = args.node;
  9167. _t._showArgs = dojo.mixin({}, args);
  9168. _t._showArgs.node = _t.node;
  9169. _t._showArgs.duration = _t.showDuration;
  9170. _t.showAnim = _t.showFunc(_t._showArgs);
  9171. _t._hideArgs = dojo.mixin({}, args);
  9172. _t._hideArgs.node = _t.node;
  9173. _t._hideArgs.duration = _t.hideDuration;
  9174. _t.hideAnim = _t.hideFunc(_t._hideArgs);
  9175. dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
  9176. dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
  9177. },
  9178. show: function(delay){
  9179. // summary: Toggle the node to showing
  9180. // delay: Integer?
  9181. // Ammount of time to stall playing the show animation
  9182. return this.showAnim.play(delay || 0);
  9183. },
  9184. hide: function(delay){
  9185. // summary: Toggle the node to hidden
  9186. // delay: Integer?
  9187. // Ammount of time to stall playing the hide animation
  9188. return this.hideAnim.play(delay || 0);
  9189. }
  9190. });
  9191. }
  9192. if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9193. dojo._hasResource["dojo.fx"] = true;
  9194. dojo.provide("dojo.fx");
  9195. /*=====
  9196. dojo.fx = {
  9197. // summary: Effects library on top of Base animations
  9198. };
  9199. =====*/
  9200. (function(){
  9201. var d = dojo,
  9202. _baseObj = {
  9203. _fire: function(evt, args){
  9204. if(this[evt]){
  9205. this[evt].apply(this, args||[]);
  9206. }
  9207. return this;
  9208. }
  9209. };
  9210. var _chain = function(animations){
  9211. this._index = -1;
  9212. this._animations = animations||[];
  9213. this._current = this._onAnimateCtx = this._onEndCtx = null;
  9214. this.duration = 0;
  9215. d.forEach(this._animations, function(a){
  9216. this.duration += a.duration;
  9217. if(a.delay){ this.duration += a.delay; }
  9218. }, this);
  9219. };
  9220. d.extend(_chain, {
  9221. _onAnimate: function(){
  9222. this._fire("onAnimate", arguments);
  9223. },
  9224. _onEnd: function(){
  9225. d.disconnect(this._onAnimateCtx);
  9226. d.disconnect(this._onEndCtx);
  9227. this._onAnimateCtx = this._onEndCtx = null;
  9228. if(this._index + 1 == this._animations.length){
  9229. this._fire("onEnd");
  9230. }else{
  9231. // switch animations
  9232. this._current = this._animations[++this._index];
  9233. this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
  9234. this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
  9235. this._current.play(0, true);
  9236. }
  9237. },
  9238. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  9239. if(!this._current){ this._current = this._animations[this._index = 0]; }
  9240. if(!gotoStart && this._current.status() == "playing"){ return this; }
  9241. var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
  9242. this._fire("beforeBegin");
  9243. }),
  9244. onBegin = d.connect(this._current, "onBegin", this, function(arg){
  9245. this._fire("onBegin", arguments);
  9246. }),
  9247. onPlay = d.connect(this._current, "onPlay", this, function(arg){
  9248. this._fire("onPlay", arguments);
  9249. d.disconnect(beforeBegin);
  9250. d.disconnect(onBegin);
  9251. d.disconnect(onPlay);
  9252. });
  9253. if(this._onAnimateCtx){
  9254. d.disconnect(this._onAnimateCtx);
  9255. }
  9256. this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
  9257. if(this._onEndCtx){
  9258. d.disconnect(this._onEndCtx);
  9259. }
  9260. this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
  9261. this._current.play.apply(this._current, arguments);
  9262. return this;
  9263. },
  9264. pause: function(){
  9265. if(this._current){
  9266. var e = d.connect(this._current, "onPause", this, function(arg){
  9267. this._fire("onPause", arguments);
  9268. d.disconnect(e);
  9269. });
  9270. this._current.pause();
  9271. }
  9272. return this;
  9273. },
  9274. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  9275. this.pause();
  9276. var offset = this.duration * percent;
  9277. this._current = null;
  9278. d.some(this._animations, function(a){
  9279. if(a.duration <= offset){
  9280. this._current = a;
  9281. return true;
  9282. }
  9283. offset -= a.duration;
  9284. return false;
  9285. });
  9286. if(this._current){
  9287. this._current.gotoPercent(offset / this._current.duration, andPlay);
  9288. }
  9289. return this;
  9290. },
  9291. stop: function(/*boolean?*/ gotoEnd){
  9292. if(this._current){
  9293. if(gotoEnd){
  9294. for(; this._index + 1 < this._animations.length; ++this._index){
  9295. this._animations[this._index].stop(true);
  9296. }
  9297. this._current = this._animations[this._index];
  9298. }
  9299. var e = d.connect(this._current, "onStop", this, function(arg){
  9300. this._fire("onStop", arguments);
  9301. d.disconnect(e);
  9302. });
  9303. this._current.stop();
  9304. }
  9305. return this;
  9306. },
  9307. status: function(){
  9308. return this._current ? this._current.status() : "stopped";
  9309. },
  9310. destroy: function(){
  9311. if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
  9312. if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
  9313. }
  9314. });
  9315. d.extend(_chain, _baseObj);
  9316. dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
  9317. // summary:
  9318. // Chain a list of `dojo.Animation`s to run in sequence
  9319. //
  9320. // description:
  9321. // Return a `dojo.Animation` which will play all passed
  9322. // `dojo.Animation` instances in sequence, firing its own
  9323. // synthesized events simulating a single animation. (eg:
  9324. // onEnd of this animation means the end of the chain,
  9325. // not the individual animations within)
  9326. //
  9327. // example:
  9328. // Once `node` is faded out, fade in `otherNode`
  9329. // | dojo.fx.chain([
  9330. // | dojo.fadeIn({ node:node }),
  9331. // | dojo.fadeOut({ node:otherNode })
  9332. // | ]).play();
  9333. //
  9334. return new _chain(animations) // dojo.Animation
  9335. };
  9336. var _combine = function(animations){
  9337. this._animations = animations||[];
  9338. this._connects = [];
  9339. this._finished = 0;
  9340. this.duration = 0;
  9341. d.forEach(animations, function(a){
  9342. var duration = a.duration;
  9343. if(a.delay){ duration += a.delay; }
  9344. if(this.duration < duration){ this.duration = duration; }
  9345. this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
  9346. }, this);
  9347. this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
  9348. var self = this;
  9349. d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"],
  9350. function(evt){
  9351. self._connects.push(d.connect(self._pseudoAnimation, evt,
  9352. function(){ self._fire(evt, arguments); }
  9353. ));
  9354. }
  9355. );
  9356. };
  9357. d.extend(_combine, {
  9358. _doAction: function(action, args){
  9359. d.forEach(this._animations, function(a){
  9360. a[action].apply(a, args);
  9361. });
  9362. return this;
  9363. },
  9364. _onEnd: function(){
  9365. if(++this._finished > this._animations.length){
  9366. this._fire("onEnd");
  9367. }
  9368. },
  9369. _call: function(action, args){
  9370. var t = this._pseudoAnimation;
  9371. t[action].apply(t, args);
  9372. },
  9373. play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
  9374. this._finished = 0;
  9375. this._doAction("play", arguments);
  9376. this._call("play", arguments);
  9377. return this;
  9378. },
  9379. pause: function(){
  9380. this._doAction("pause", arguments);
  9381. this._call("pause", arguments);
  9382. return this;
  9383. },
  9384. gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
  9385. var ms = this.duration * percent;
  9386. d.forEach(this._animations, function(a){
  9387. a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
  9388. });
  9389. this._call("gotoPercent", arguments);
  9390. return this;
  9391. },
  9392. stop: function(/*boolean?*/ gotoEnd){
  9393. this._doAction("stop", arguments);
  9394. this._call("stop", arguments);
  9395. return this;
  9396. },
  9397. status: function(){
  9398. return this._pseudoAnimation.status();
  9399. },
  9400. destroy: function(){
  9401. d.forEach(this._connects, dojo.disconnect);
  9402. }
  9403. });
  9404. d.extend(_combine, _baseObj);
  9405. dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
  9406. // summary:
  9407. // Combine a list of `dojo.Animation`s to run in parallel
  9408. //
  9409. // description:
  9410. // Combine an array of `dojo.Animation`s to run in parallel,
  9411. // providing a new `dojo.Animation` instance encompasing each
  9412. // animation, firing standard animation events.
  9413. //
  9414. // example:
  9415. // Fade out `node` while fading in `otherNode` simultaneously
  9416. // | dojo.fx.combine([
  9417. // | dojo.fadeIn({ node:node }),
  9418. // | dojo.fadeOut({ node:otherNode })
  9419. // | ]).play();
  9420. //
  9421. // example:
  9422. // When the longest animation ends, execute a function:
  9423. // | var anim = dojo.fx.combine([
  9424. // | dojo.fadeIn({ node: n, duration:700 }),
  9425. // | dojo.fadeOut({ node: otherNode, duration: 300 })
  9426. // | ]);
  9427. // | dojo.connect(anim, "onEnd", function(){
  9428. // | // overall animation is done.
  9429. // | });
  9430. // | anim.play(); // play the animation
  9431. //
  9432. return new _combine(animations); // dojo.Animation
  9433. };
  9434. dojo.fx.wipeIn = function(/*Object*/ args){
  9435. // summary:
  9436. // Expand a node to it's natural height.
  9437. //
  9438. // description:
  9439. // Returns an animation that will expand the
  9440. // node defined in 'args' object from it's current height to
  9441. // it's natural height (with no scrollbar).
  9442. // Node must have no margin/border/padding.
  9443. //
  9444. // args: Object
  9445. // A hash-map of standard `dojo.Animation` constructor properties
  9446. // (such as easing: node: duration: and so on)
  9447. //
  9448. // example:
  9449. // | dojo.fx.wipeIn({
  9450. // | node:"someId"
  9451. // | }).play()
  9452. var node = args.node = d.byId(args.node), s = node.style, o;
  9453. var anim = d.animateProperty(d.mixin({
  9454. properties: {
  9455. height: {
  9456. // wrapped in functions so we wait till the last second to query (in case value has changed)
  9457. start: function(){
  9458. // start at current [computed] height, but use 1px rather than 0
  9459. // because 0 causes IE to display the whole panel
  9460. o = s.overflow;
  9461. s.overflow = "hidden";
  9462. if(s.visibility == "hidden" || s.display == "none"){
  9463. s.height = "1px";
  9464. s.display = "";
  9465. s.visibility = "";
  9466. return 1;
  9467. }else{
  9468. var height = d.style(node, "height");
  9469. return Math.max(height, 1);
  9470. }
  9471. },
  9472. end: function(){
  9473. return node.scrollHeight;
  9474. }
  9475. }
  9476. }
  9477. }, args));
  9478. d.connect(anim, "onEnd", function(){
  9479. s.height = "auto";
  9480. s.overflow = o;
  9481. });
  9482. return anim; // dojo.Animation
  9483. };
  9484. dojo.fx.wipeOut = function(/*Object*/ args){
  9485. // summary:
  9486. // Shrink a node to nothing and hide it.
  9487. //
  9488. // description:
  9489. // Returns an animation that will shrink node defined in "args"
  9490. // from it's current height to 1px, and then hide it.
  9491. //
  9492. // args: Object
  9493. // A hash-map of standard `dojo.Animation` constructor properties
  9494. // (such as easing: node: duration: and so on)
  9495. //
  9496. // example:
  9497. // | dojo.fx.wipeOut({ node:"someId" }).play()
  9498. var node = args.node = d.byId(args.node), s = node.style, o;
  9499. var anim = d.animateProperty(d.mixin({
  9500. properties: {
  9501. height: {
  9502. end: 1 // 0 causes IE to display the whole panel
  9503. }
  9504. }
  9505. }, args));
  9506. d.connect(anim, "beforeBegin", function(){
  9507. o = s.overflow;
  9508. s.overflow = "hidden";
  9509. s.display = "";
  9510. });
  9511. d.connect(anim, "onEnd", function(){
  9512. s.overflow = o;
  9513. s.height = "auto";
  9514. s.display = "none";
  9515. });
  9516. return anim; // dojo.Animation
  9517. };
  9518. dojo.fx.slideTo = function(/*Object*/ args){
  9519. // summary:
  9520. // Slide a node to a new top/left position
  9521. //
  9522. // description:
  9523. // Returns an animation that will slide "node"
  9524. // defined in args Object from its current position to
  9525. // the position defined by (args.left, args.top).
  9526. //
  9527. // args: Object
  9528. // A hash-map of standard `dojo.Animation` constructor properties
  9529. // (such as easing: node: duration: and so on). Special args members
  9530. // are `top` and `left`, which indicate the new position to slide to.
  9531. //
  9532. // example:
  9533. // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()
  9534. var node = args.node = d.byId(args.node),
  9535. top = null, left = null;
  9536. var init = (function(n){
  9537. return function(){
  9538. var cs = d.getComputedStyle(n);
  9539. var pos = cs.position;
  9540. top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
  9541. left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
  9542. if(pos != 'absolute' && pos != 'relative'){
  9543. var ret = d.position(n, true);
  9544. top = ret.y;
  9545. left = ret.x;
  9546. n.style.position="absolute";
  9547. n.style.top=top+"px";
  9548. n.style.left=left+"px";
  9549. }
  9550. };
  9551. })(node);
  9552. init();
  9553. var anim = d.animateProperty(d.mixin({
  9554. properties: {
  9555. top: args.top || 0,
  9556. left: args.left || 0
  9557. }
  9558. }, args));
  9559. d.connect(anim, "beforeBegin", anim, init);
  9560. return anim; // dojo.Animation
  9561. };
  9562. })();
  9563. }
  9564. if(!dojo._hasResource["dojox.charting.action2d.Magnify"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9565. dojo._hasResource["dojox.charting.action2d.Magnify"] = true;
  9566. dojo.provide("dojox.charting.action2d.Magnify");
  9567. /*=====
  9568. dojo.declare("dojox.charting.action2d.__MagnifyCtorArgs", dojox.charting.action2d.__BaseCtorArgs, {
  9569. // summary:
  9570. // Additional arguments for highlighting actions.
  9571. // scale: Number?
  9572. // The amount to magnify the given object to. Default is 2.
  9573. scale: 2
  9574. });
  9575. =====*/
  9576. (function(){
  9577. var DEFAULT_SCALE = 2,
  9578. m = dojox.gfx.matrix,
  9579. gf = dojox.gfx.fx;
  9580. dojo.declare("dojox.charting.action2d.Magnify", dojox.charting.action2d.Base, {
  9581. // summary:
  9582. // Create an action that magnifies the object the action is applied to.
  9583. // the data description block for the widget parser
  9584. defaultParams: {
  9585. duration: 400, // duration of the action in ms
  9586. easing: dojo.fx.easing.backOut, // easing for the action
  9587. scale: DEFAULT_SCALE // scale of magnification
  9588. },
  9589. optionalParams: {}, // no optional parameters
  9590. constructor: function(chart, plot, kwArgs){
  9591. // summary:
  9592. // Create the magnifying action.
  9593. // chart: dojox.charting.Chart2D
  9594. // The chart this action belongs to.
  9595. // plot: String?
  9596. // The plot to apply the action to. If not passed, "default" is assumed.
  9597. // kwArgs: dojox.charting.action2d.__MagnifyCtorArgs?
  9598. // Optional keyword arguments for this action.
  9599. // process optional named parameters
  9600. this.scale = kwArgs && typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE;
  9601. this.connect();
  9602. },
  9603. process: function(o){
  9604. // summary:
  9605. // Process the action on the given object.
  9606. // o: dojox.gfx.Shape
  9607. // The object on which to process the magnifying action.
  9608. if(!o.shape || !(o.type in this.overOutEvents) ||
  9609. !("cx" in o) || !("cy" in o)){ return; }
  9610. var runName = o.run.name, index = o.index, vector = [], anim, init, scale;
  9611. if(runName in this.anim){
  9612. anim = this.anim[runName][index];
  9613. }else{
  9614. this.anim[runName] = {};
  9615. }
  9616. if(anim){
  9617. anim.action.stop(true);
  9618. }else{
  9619. this.anim[runName][index] = anim = {};
  9620. }
  9621. if(o.type == "onmouseover"){
  9622. init = m.identity;
  9623. scale = this.scale;
  9624. }else{
  9625. init = m.scaleAt(this.scale, o.cx, o.cy);
  9626. scale = 1 / this.scale;
  9627. }
  9628. var kwArgs = {
  9629. shape: o.shape,
  9630. duration: this.duration,
  9631. easing: this.easing,
  9632. transform: [
  9633. {name: "scaleAt", start: [1, o.cx, o.cy], end: [scale, o.cx, o.cy]},
  9634. init
  9635. ]
  9636. };
  9637. if(o.shape){
  9638. vector.push(gf.animateTransform(kwArgs));
  9639. }
  9640. if(o.oultine){
  9641. kwArgs.shape = o.outline;
  9642. vector.push(gf.animateTransform(kwArgs));
  9643. }
  9644. if(o.shadow){
  9645. kwArgs.shape = o.shadow;
  9646. vector.push(gf.animateTransform(kwArgs));
  9647. }
  9648. if(!vector.length){
  9649. delete this.anim[runName][index];
  9650. return;
  9651. }
  9652. anim.action = dojo.fx.combine(vector);
  9653. if(o.type == "onmouseout"){
  9654. dojo.connect(anim.action, "onEnd", this, function(){
  9655. if(this.anim[runName]){
  9656. delete this.anim[runName][index];
  9657. }
  9658. });
  9659. }
  9660. anim.action.play();
  9661. }
  9662. });
  9663. })();
  9664. }
  9665. if(!dojo._hasResource["dojox.lang.functional.scan"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9666. dojo._hasResource["dojox.lang.functional.scan"] = true;
  9667. dojo.provide("dojox.lang.functional.scan");
  9668. // This module adds high-level functions and related constructs:
  9669. // - "scan" family of functions
  9670. // Notes:
  9671. // - missing high-level functions are provided with the compatible API:
  9672. // scanl, scanl1, scanr, scanr1
  9673. // Defined methods:
  9674. // - take any valid lambda argument as the functional argument
  9675. // - operate on dense arrays
  9676. // - take a string as the array argument
  9677. // - take an iterator objects as the array argument (only scanl, and scanl1)
  9678. (function(){
  9679. var d = dojo, df = dojox.lang.functional, empty = {};
  9680. d.mixin(df, {
  9681. // classic reduce-class functions
  9682. scanl: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  9683. // summary: repeatedly applies a binary function to an array from left
  9684. // to right using a seed value as a starting point; returns an array
  9685. // of values produced by foldl() at that point.
  9686. if(typeof a == "string"){ a = a.split(""); }
  9687. o = o || d.global; f = df.lambda(f);
  9688. var t, n, i;
  9689. if(d.isArray(a)){
  9690. // array
  9691. t = new Array((n = a.length) + 1);
  9692. t[0] = z;
  9693. for(i = 0; i < n; z = f.call(o, z, a[i], i, a), t[++i] = z);
  9694. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  9695. // iterator
  9696. t = [z];
  9697. for(i = 0; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a)));
  9698. }else{
  9699. // object/dictionary
  9700. t = [z];
  9701. for(i in a){
  9702. if(!(i in empty)){
  9703. t.push(z = f.call(o, z, a[i], i, a));
  9704. }
  9705. }
  9706. }
  9707. return t; // Array
  9708. },
  9709. scanl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  9710. // summary: repeatedly applies a binary function to an array from left
  9711. // to right; returns an array of values produced by foldl1() at that
  9712. // point.
  9713. if(typeof a == "string"){ a = a.split(""); }
  9714. o = o || d.global; f = df.lambda(f);
  9715. var t, n, z, first = true;
  9716. if(d.isArray(a)){
  9717. // array
  9718. t = new Array(n = a.length);
  9719. t[0] = z = a[0];
  9720. for(var i = 1; i < n; t[i] = z = f.call(o, z, a[i], i, a), ++i);
  9721. }else if(typeof a.hasNext == "function" && typeof a.next == "function"){
  9722. // iterator
  9723. if(a.hasNext()){
  9724. t = [z = a.next()];
  9725. for(var i = 1; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a)));
  9726. }
  9727. }else{
  9728. // object/dictionary
  9729. for(var i in a){
  9730. if(!(i in empty)){
  9731. if(first){
  9732. t = [z = a[i]];
  9733. first = false;
  9734. }else{
  9735. t.push(z = f.call(o, z, a[i], i, a));
  9736. }
  9737. }
  9738. }
  9739. }
  9740. return t; // Array
  9741. },
  9742. scanr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  9743. // summary: repeatedly applies a binary function to an array from right
  9744. // to left using a seed value as a starting point; returns an array
  9745. // of values produced by foldr() at that point.
  9746. if(typeof a == "string"){ a = a.split(""); }
  9747. o = o || d.global; f = df.lambda(f);
  9748. var n = a.length, t = new Array(n + 1), i = n;
  9749. t[n] = z;
  9750. for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z);
  9751. return t; // Array
  9752. },
  9753. scanr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){
  9754. // summary: repeatedly applies a binary function to an array from right
  9755. // to left; returns an array of values produced by foldr1() at that
  9756. // point.
  9757. if(typeof a == "string"){ a = a.split(""); }
  9758. o = o || d.global; f = df.lambda(f);
  9759. var n = a.length, t = new Array(n), z = a[n - 1], i = n - 1;
  9760. t[i] = z;
  9761. for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z);
  9762. return t; // Array
  9763. }
  9764. });
  9765. })();
  9766. }
  9767. if(!dojo._hasResource["dojox.charting.action2d.MoveSlice"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9768. dojo._hasResource["dojox.charting.action2d.MoveSlice"] = true;
  9769. dojo.provide("dojox.charting.action2d.MoveSlice");
  9770. /*=====
  9771. dojo.declare("dojox.charting.action2d.__MoveSliceCtorArgs", dojox.charting.action2d.__BaseCtorArgs, {
  9772. // summary:
  9773. // Additional arguments for highlighting actions.
  9774. // scale: Number?
  9775. // The amount to scale the pie slice. Default is 1.05.
  9776. scale: 1.05,
  9777. // shift: Number?
  9778. // The amount in pixels to shift the pie slice. Default is 7.
  9779. shift: 7
  9780. });
  9781. =====*/
  9782. (function(){
  9783. var DEFAULT_SCALE = 1.05,
  9784. DEFAULT_SHIFT = 7, // px
  9785. m = dojox.gfx.matrix,
  9786. gf = dojox.gfx.fx,
  9787. df = dojox.lang.functional;
  9788. dojo.declare("dojox.charting.action2d.MoveSlice", dojox.charting.action2d.Base, {
  9789. // summary:
  9790. // Create an action for a pie chart that moves and scales a pie slice.
  9791. // the data description block for the widget parser
  9792. defaultParams: {
  9793. duration: 400, // duration of the action in ms
  9794. easing: dojo.fx.easing.backOut, // easing for the action
  9795. scale: DEFAULT_SCALE, // scale of magnification
  9796. shift: DEFAULT_SHIFT // shift of the slice
  9797. },
  9798. optionalParams: {}, // no optional parameters
  9799. constructor: function(chart, plot, kwArgs){
  9800. // summary:
  9801. // Create the slice moving action and connect it to the plot.
  9802. // chart: dojox.charting.Chart2D
  9803. // The chart this action belongs to.
  9804. // plot: String?
  9805. // The plot this action is attached to. If not passed, "default" is assumed.
  9806. // kwArgs: dojox.charting.action2d.__MoveSliceCtorArgs?
  9807. // Optional keyword arguments object for setting parameters.
  9808. if(!kwArgs){ kwArgs = {}; }
  9809. this.scale = typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE;
  9810. this.shift = typeof kwArgs.shift == "number" ? kwArgs.shift : DEFAULT_SHIFT;
  9811. this.connect();
  9812. },
  9813. process: function(o){
  9814. // summary:
  9815. // Process the action on the given object.
  9816. // o: dojox.gfx.Shape
  9817. // The object on which to process the slice moving action.
  9818. if(!o.shape || o.element != "slice" || !(o.type in this.overOutEvents)){ return; }
  9819. if(!this.angles){
  9820. // calculate the running total of slice angles
  9821. var startAngle = m._degToRad(o.plot.opt.startAngle);
  9822. if(typeof o.run.data[0] == "number"){
  9823. this.angles = df.map(df.scanl(o.run.data, "+", startAngle),
  9824. "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0));
  9825. }else{
  9826. this.angles = df.map(df.scanl(o.run.data, "a + b.y", startAngle),
  9827. "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0));
  9828. }
  9829. }
  9830. var index = o.index, anim, startScale, endScale, startOffset, endOffset,
  9831. angle = (this.angles[index] + this.angles[index + 1]) / 2,
  9832. rotateTo0 = m.rotateAt(-angle, o.cx, o.cy),
  9833. rotateBack = m.rotateAt( angle, o.cx, o.cy);
  9834. anim = this.anim[index];
  9835. if(anim){
  9836. anim.action.stop(true);
  9837. }else{
  9838. this.anim[index] = anim = {};
  9839. }
  9840. if(o.type == "onmouseover"){
  9841. startOffset = 0;
  9842. endOffset = this.shift;
  9843. startScale = 1;
  9844. endScale = this.scale;
  9845. }else{
  9846. startOffset = this.shift;
  9847. endOffset = 0;
  9848. startScale = this.scale;
  9849. endScale = 1;
  9850. }
  9851. anim.action = dojox.gfx.fx.animateTransform({
  9852. shape: o.shape,
  9853. duration: this.duration,
  9854. easing: this.easing,
  9855. transform: [
  9856. rotateBack,
  9857. {name: "translate", start: [startOffset, 0], end: [endOffset, 0]},
  9858. {name: "scaleAt", start: [startScale, o.cx, o.cy], end: [endScale, o.cx, o.cy]},
  9859. rotateTo0
  9860. ]
  9861. });
  9862. if(o.type == "onmouseout"){
  9863. dojo.connect(anim.action, "onEnd", this, function(){
  9864. delete this.anim[index];
  9865. });
  9866. }
  9867. anim.action.play();
  9868. },
  9869. reset: function(){
  9870. delete this.angles;
  9871. }
  9872. });
  9873. })();
  9874. }
  9875. if(!dojo._hasResource["dojox.charting.action2d.Shake"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9876. dojo._hasResource["dojox.charting.action2d.Shake"] = true;
  9877. dojo.provide("dojox.charting.action2d.Shake");
  9878. /*=====
  9879. dojo.declare("dojox.charting.action2d.__ShakeCtorArgs", dojox.charting.action2d.__BaseCtorArgs, {
  9880. // summary:
  9881. // Additional arguments for highlighting actions.
  9882. // shift: Number?
  9883. // The amount in pixels to shift the pie slice. Default is 3.
  9884. shift: 3
  9885. });
  9886. =====*/
  9887. (function(){
  9888. var DEFAULT_SHIFT = 3,
  9889. m = dojox.gfx.matrix,
  9890. gf = dojox.gfx.fx;
  9891. dojo.declare("dojox.charting.action2d.Shake", dojox.charting.action2d.Base, {
  9892. // summary:
  9893. // Create a shaking action for use on an element in a chart.
  9894. // the data description block for the widget parser
  9895. defaultParams: {
  9896. duration: 400, // duration of the action in ms
  9897. easing: dojo.fx.easing.backOut, // easing for the action
  9898. shiftX: DEFAULT_SHIFT, // shift of the element along the X axis
  9899. shiftY: DEFAULT_SHIFT // shift of the element along the Y axis
  9900. },
  9901. optionalParams: {}, // no optional parameters
  9902. constructor: function(chart, plot, kwArgs){
  9903. // summary:
  9904. // Create the shaking action and connect it to the plot.
  9905. // chart: dojox.charting.Chart2D
  9906. // The chart this action belongs to.
  9907. // plot: String?
  9908. // The plot this action is attached to. If not passed, "default" is assumed.
  9909. // kwArgs: dojox.charting.action2d.__ShakeCtorArgs?
  9910. // Optional keyword arguments object for setting parameters.
  9911. if(!kwArgs){ kwArgs = {}; }
  9912. this.shiftX = typeof kwArgs.shiftX == "number" ? kwArgs.shiftX : DEFAULT_SHIFT;
  9913. this.shiftY = typeof kwArgs.shiftY == "number" ? kwArgs.shiftY : DEFAULT_SHIFT;
  9914. this.connect();
  9915. },
  9916. process: function(o){
  9917. // summary:
  9918. // Process the action on the given object.
  9919. // o: dojox.gfx.Shape
  9920. // The object on which to process the slice moving action.
  9921. if(!o.shape || !(o.type in this.overOutEvents)){ return; }
  9922. var runName = o.run.name, index = o.index, vector = [], anim,
  9923. shiftX = o.type == "onmouseover" ? this.shiftX : -this.shiftX,
  9924. shiftY = o.type == "onmouseover" ? this.shiftY : -this.shiftY;
  9925. if(runName in this.anim){
  9926. anim = this.anim[runName][index];
  9927. }else{
  9928. this.anim[runName] = {};
  9929. }
  9930. if(anim){
  9931. anim.action.stop(true);
  9932. }else{
  9933. this.anim[runName][index] = anim = {};
  9934. }
  9935. var kwArgs = {
  9936. shape: o.shape,
  9937. duration: this.duration,
  9938. easing: this.easing,
  9939. transform: [
  9940. {name: "translate", start: [this.shiftX, this.shiftY], end: [0, 0]},
  9941. m.identity
  9942. ]
  9943. };
  9944. if(o.shape){
  9945. vector.push(gf.animateTransform(kwArgs));
  9946. }
  9947. if(o.oultine){
  9948. kwArgs.shape = o.outline;
  9949. vector.push(gf.animateTransform(kwArgs));
  9950. }
  9951. if(o.shadow){
  9952. kwArgs.shape = o.shadow;
  9953. vector.push(gf.animateTransform(kwArgs));
  9954. }
  9955. if(!vector.length){
  9956. delete this.anim[runName][index];
  9957. return;
  9958. }
  9959. anim.action = dojo.fx.combine(vector);
  9960. if(o.type == "onmouseout"){
  9961. dojo.connect(anim.action, "onEnd", this, function(){
  9962. if(this.anim[runName]){
  9963. delete this.anim[runName][index];
  9964. }
  9965. });
  9966. }
  9967. anim.action.play();
  9968. }
  9969. });
  9970. })();
  9971. }
  9972. if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  9973. dojo._hasResource["dojo.string"] = true;
  9974. dojo.provide("dojo.string");
  9975. dojo.getObject("string", true, dojo);
  9976. /*=====
  9977. dojo.string = {
  9978. // summary: String utilities for Dojo
  9979. };
  9980. =====*/
  9981. dojo.string.rep = function(/*String*/str, /*Integer*/num){
  9982. // summary:
  9983. // Efficiently replicate a string `n` times.
  9984. // str:
  9985. // the string to replicate
  9986. // num:
  9987. // number of times to replicate the string
  9988. if(num <= 0 || !str){ return ""; }
  9989. var buf = [];
  9990. for(;;){
  9991. if(num & 1){
  9992. buf.push(str);
  9993. }
  9994. if(!(num >>= 1)){ break; }
  9995. str += str;
  9996. }
  9997. return buf.join(""); // String
  9998. };
  9999. dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
  10000. // summary:
  10001. // Pad a string to guarantee that it is at least `size` length by
  10002. // filling with the character `ch` at either the start or end of the
  10003. // string. Pads at the start, by default.
  10004. // text:
  10005. // the string to pad
  10006. // size:
  10007. // length to provide padding
  10008. // ch:
  10009. // character to pad, defaults to '0'
  10010. // end:
  10011. // adds padding at the end if true, otherwise pads at start
  10012. // example:
  10013. // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++".
  10014. // | dojo.string.pad("Dojo", 10, "+", true);
  10015. if(!ch){
  10016. ch = '0';
  10017. }
  10018. var out = String(text),
  10019. pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
  10020. return end ? out + pad : pad + out; // String
  10021. };
  10022. dojo.string.substitute = function( /*String*/ template,
  10023. /*Object|Array*/map,
  10024. /*Function?*/ transform,
  10025. /*Object?*/ thisObject){
  10026. // summary:
  10027. // Performs parameterized substitutions on a string. Throws an
  10028. // exception if any parameter is unmatched.
  10029. // template:
  10030. // a string with expressions in the form `${key}` to be replaced or
  10031. // `${key:format}` which specifies a format function. keys are case-sensitive.
  10032. // map:
  10033. // hash to search for substitutions
  10034. // transform:
  10035. // a function to process all parameters before substitution takes
  10036. // place, e.g. mylib.encodeXML
  10037. // thisObject:
  10038. // where to look for optional format function; default to the global
  10039. // namespace
  10040. // example:
  10041. // Substitutes two expressions in a string from an Array or Object
  10042. // | // returns "File 'foo.html' is not found in directory '/temp'."
  10043. // | // by providing substitution data in an Array
  10044. // | dojo.string.substitute(
  10045. // | "File '${0}' is not found in directory '${1}'.",
  10046. // | ["foo.html","/temp"]
  10047. // | );
  10048. // |
  10049. // | // also returns "File 'foo.html' is not found in directory '/temp'."
  10050. // | // but provides substitution data in an Object structure. Dotted
  10051. // | // notation may be used to traverse the structure.
  10052. // | dojo.string.substitute(
  10053. // | "File '${name}' is not found in directory '${info.dir}'.",
  10054. // | { name: "foo.html", info: { dir: "/temp" } }
  10055. // | );
  10056. // example:
  10057. // Use a transform function to modify the values:
  10058. // | // returns "file 'foo.html' is not found in directory '/temp'."
  10059. // | dojo.string.substitute(
  10060. // | "${0} is not found in ${1}.",
  10061. // | ["foo.html","/temp"],
  10062. // | function(str){
  10063. // | // try to figure out the type
  10064. // | var prefix = (str.charAt(0) == "/") ? "directory": "file";
  10065. // | return prefix + " '" + str + "'";
  10066. // | }
  10067. // | );
  10068. // example:
  10069. // Use a formatter
  10070. // | // returns "thinger -- howdy"
  10071. // | dojo.string.substitute(
  10072. // | "${0:postfix}", ["thinger"], null, {
  10073. // | postfix: function(value, key){
  10074. // | return value + " -- howdy";
  10075. // | }
  10076. // | }
  10077. // | );
  10078. thisObject = thisObject || dojo.global;
  10079. transform = transform ?
  10080. dojo.hitch(thisObject, transform) : function(v){ return v; };
  10081. return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
  10082. function(match, key, format){
  10083. var value = dojo.getObject(key, false, map);
  10084. if(format){
  10085. value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
  10086. }
  10087. return transform(value, key).toString();
  10088. }); // String
  10089. };
  10090. /*=====
  10091. dojo.string.trim = function(str){
  10092. // summary:
  10093. // Trims whitespace from both sides of the string
  10094. // str: String
  10095. // String to be trimmed
  10096. // returns: String
  10097. // Returns the trimmed string
  10098. // description:
  10099. // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
  10100. // The short yet performant version of this function is dojo.trim(),
  10101. // which is part of Dojo base. Uses String.prototype.trim instead, if available.
  10102. return ""; // String
  10103. }
  10104. =====*/
  10105. dojo.string.trim = String.prototype.trim ?
  10106. dojo.trim : // aliasing to the native function
  10107. function(str){
  10108. str = str.replace(/^\s+/, '');
  10109. for(var i = str.length - 1; i >= 0; i--){
  10110. if(/\S/.test(str.charAt(i))){
  10111. str = str.substring(0, i + 1);
  10112. break;
  10113. }
  10114. }
  10115. return str;
  10116. };
  10117. }
  10118. if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  10119. dojo._hasResource["dojo.date.stamp"] = true;
  10120. dojo.provide("dojo.date.stamp");
  10121. dojo.getObject("date.stamp", true, dojo);
  10122. // Methods to convert dates to or from a wire (string) format using well-known conventions
  10123. dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
  10124. // summary:
  10125. // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
  10126. //
  10127. // description:
  10128. // Accepts a string formatted according to a profile of ISO8601 as defined by
  10129. // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
  10130. // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
  10131. // The following combinations are valid:
  10132. //
  10133. // * dates only
  10134. // | * yyyy
  10135. // | * yyyy-MM
  10136. // | * yyyy-MM-dd
  10137. // * times only, with an optional time zone appended
  10138. // | * THH:mm
  10139. // | * THH:mm:ss
  10140. // | * THH:mm:ss.SSS
  10141. // * and "datetimes" which could be any combination of the above
  10142. //
  10143. // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
  10144. // Assumes the local time zone if not specified. Does not validate. Improperly formatted
  10145. // input may return null. Arguments which are out of bounds will be handled
  10146. // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
  10147. // Only years between 100 and 9999 are supported.
  10148. //
  10149. // formattedString:
  10150. // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
  10151. //
  10152. // defaultTime:
  10153. // Used for defaults for fields omitted in the formattedString.
  10154. // Uses 1970-01-01T00:00:00.0Z by default.
  10155. if(!dojo.date.stamp._isoRegExp){
  10156. dojo.date.stamp._isoRegExp =
  10157. //TODO: could be more restrictive and check for 00-59, etc.
  10158. /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
  10159. }
  10160. var match = dojo.date.stamp._isoRegExp.exec(formattedString),
  10161. result = null;
  10162. if(match){
  10163. match.shift();
  10164. if(match[1]){match[1]--;} // Javascript Date months are 0-based
  10165. if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds
  10166. if(defaultTime){
  10167. // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0
  10168. defaultTime = new Date(defaultTime);
  10169. dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
  10170. return defaultTime["get" + prop]();
  10171. }), function(value, index){
  10172. match[index] = match[index] || value;
  10173. });
  10174. }
  10175. result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
  10176. if(match[0] < 100){
  10177. result.setFullYear(match[0] || 1970);
  10178. }
  10179. var offset = 0,
  10180. zoneSign = match[7] && match[7].charAt(0);
  10181. if(zoneSign != 'Z'){
  10182. offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
  10183. if(zoneSign != '-'){ offset *= -1; }
  10184. }
  10185. if(zoneSign){
  10186. offset -= result.getTimezoneOffset();
  10187. }
  10188. if(offset){
  10189. result.setTime(result.getTime() + offset * 60000);
  10190. }
  10191. }
  10192. return result; // Date or null
  10193. };
  10194. /*=====
  10195. dojo.date.stamp.__Options = function(){
  10196. // selector: String
  10197. // "date" or "time" for partial formatting of the Date object.
  10198. // Both date and time will be formatted by default.
  10199. // zulu: Boolean
  10200. // if true, UTC/GMT is used for a timezone
  10201. // milliseconds: Boolean
  10202. // if true, output milliseconds
  10203. this.selector = selector;
  10204. this.zulu = zulu;
  10205. this.milliseconds = milliseconds;
  10206. }
  10207. =====*/
  10208. dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
  10209. // summary:
  10210. // Format a Date object as a string according a subset of the ISO-8601 standard
  10211. //
  10212. // description:
  10213. // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
  10214. // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
  10215. // Does not check bounds. Only years between 100 and 9999 are supported.
  10216. //
  10217. // dateObject:
  10218. // A Date object
  10219. var _ = function(n){ return (n < 10) ? "0" + n : n; };
  10220. options = options || {};
  10221. var formattedDate = [],
  10222. getter = options.zulu ? "getUTC" : "get",
  10223. date = "";
  10224. if(options.selector != "time"){
  10225. var year = dateObject[getter+"FullYear"]();
  10226. date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
  10227. }
  10228. formattedDate.push(date);
  10229. if(options.selector != "date"){
  10230. var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
  10231. var millis = dateObject[getter+"Milliseconds"]();
  10232. if(options.milliseconds){
  10233. time += "."+ (millis < 100 ? "0" : "") + _(millis);
  10234. }
  10235. if(options.zulu){
  10236. time += "Z";
  10237. }else if(options.selector != "time"){
  10238. var timezoneOffset = dateObject.getTimezoneOffset();
  10239. var absOffset = Math.abs(timezoneOffset);
  10240. time += (timezoneOffset > 0 ? "-" : "+") +
  10241. _(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
  10242. }
  10243. formattedDate.push(time);
  10244. }
  10245. return formattedDate.join('T'); // String
  10246. };
  10247. }
  10248. if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  10249. dojo._hasResource["dojo.parser"] = true;
  10250. dojo.provide("dojo.parser");
  10251. new Date("X"); // workaround for #11279, new Date("") == NaN
  10252. dojo.parser = new function(){
  10253. // summary:
  10254. // The Dom/Widget parsing package
  10255. var d = dojo;
  10256. function val2type(/*Object*/ value){
  10257. // summary:
  10258. // Returns name of type of given value.
  10259. if(d.isString(value)){ return "string"; }
  10260. if(typeof value == "number"){ return "number"; }
  10261. if(typeof value == "boolean"){ return "boolean"; }
  10262. if(d.isFunction(value)){ return "function"; }
  10263. if(d.isArray(value)){ return "array"; } // typeof [] == "object"
  10264. if(value instanceof Date) { return "date"; } // assume timestamp
  10265. if(value instanceof d._Url){ return "url"; }
  10266. return "object";
  10267. }
  10268. function str2obj(/*String*/ value, /*String*/ type){
  10269. // summary:
  10270. // Convert given string value to given type
  10271. switch(type){
  10272. case "string":
  10273. return value;
  10274. case "number":
  10275. return value.length ? Number(value) : NaN;
  10276. case "boolean":
  10277. // for checked/disabled value might be "" or "checked". interpret as true.
  10278. return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
  10279. case "function":
  10280. if(d.isFunction(value)){
  10281. // IE gives us a function, even when we say something like onClick="foo"
  10282. // (in which case it gives us an invalid function "function(){ foo }").
  10283. // Therefore, convert to string
  10284. value=value.toString();
  10285. value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
  10286. }
  10287. try{
  10288. if(value === "" || value.search(/[^\w\.]+/i) != -1){
  10289. // The user has specified some text for a function like "return x+5"
  10290. return new Function(value);
  10291. }else{
  10292. // The user has specified the name of a function like "myOnClick"
  10293. // or a single word function "return"
  10294. return d.getObject(value, false) || new Function(value);
  10295. }
  10296. }catch(e){ return new Function(); }
  10297. case "array":
  10298. return value ? value.split(/\s*,\s*/) : [];
  10299. case "date":
  10300. switch(value){
  10301. case "": return new Date(""); // the NaN of dates
  10302. case "now": return new Date(); // current date
  10303. default: return d.date.stamp.fromISOString(value);
  10304. }
  10305. case "url":
  10306. return d.baseUrl + value;
  10307. default:
  10308. return d.fromJson(value);
  10309. }
  10310. }
  10311. var dummyClass = {}, instanceClasses = {
  10312. // map from fully qualified name (like "dijit.Button") to structure like
  10313. // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
  10314. };
  10315. // Widgets like BorderContainer add properties to _Widget via dojo.extend().
  10316. // If BorderContainer is loaded after _Widget's parameter list has been cached,
  10317. // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
  10318. // TODO: remove this in 2.0, when we stop caching parameters.
  10319. d.connect(d, "extend", function(){
  10320. instanceClasses = {};
  10321. });
  10322. function getProtoInfo(cls, params){
  10323. // cls: A prototype
  10324. // The prototype of the class to check props on
  10325. // params: Object
  10326. // The parameters object to mix found parameters onto.
  10327. for(var name in cls){
  10328. if(name.charAt(0)=="_"){ continue; } // skip internal properties
  10329. if(name in dummyClass){ continue; } // skip "constructor" and "toString"
  10330. params[name] = val2type(cls[name]);
  10331. }
  10332. return params;
  10333. }
  10334. function getClassInfo(/*String*/ className, /*Boolean*/ skipParamsLookup){
  10335. // summary:
  10336. // Maps a widget name string like "dijit.form.Button" to the widget constructor itself,
  10337. // and a list of that widget's parameters and their types
  10338. // className:
  10339. // fully qualified name (like "dijit.form.Button")
  10340. // returns:
  10341. // structure like
  10342. // {
  10343. // cls: dijit.Button,
  10344. // params: { label: "string", disabled: "boolean"}
  10345. // }
  10346. var c = instanceClasses[className];
  10347. if(!c){
  10348. // get pointer to widget class
  10349. var cls = d.getObject(className), params = null;
  10350. if(!cls){ return null; } // class not defined [yet]
  10351. if(!skipParamsLookup){ // from fastpath, we don't need to lookup the attrs on the proto because they are explicit
  10352. params = getProtoInfo(cls.prototype, {})
  10353. }
  10354. c = { cls: cls, params: params };
  10355. }else if(!skipParamsLookup && !c.params){
  10356. // if we're calling getClassInfo and have a cls proto, but no params info, scan that cls for params now
  10357. // and update the pointer in instanceClasses[className]. This happens when a widget appears in another
  10358. // widget's template which still uses dojoType, but an instance of the widget appears prior with a data-dojo-type,
  10359. // skipping this lookup the first time.
  10360. c.params = getProtoInfo(c.cls.prototype, {});
  10361. }
  10362. return c;
  10363. }
  10364. this._functionFromScript = function(script, attrData){
  10365. // summary:
  10366. // Convert a <script type="dojo/method" args="a, b, c"> ... </script>
  10367. // into a function
  10368. // script: DOMNode
  10369. // The <script> DOMNode
  10370. // attrData: String
  10371. // For HTML5 compliance, searches for attrData + "args" (typically
  10372. // "data-dojo-args") instead of "args"
  10373. var preamble = "";
  10374. var suffix = "";
  10375. var argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args"));
  10376. if(argsStr){
  10377. d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
  10378. preamble += "var "+part+" = arguments["+idx+"]; ";
  10379. });
  10380. }
  10381. var withStr = script.getAttribute("with");
  10382. if(withStr && withStr.length){
  10383. d.forEach(withStr.split(/\s*,\s*/), function(part){
  10384. preamble += "with("+part+"){";
  10385. suffix += "}";
  10386. });
  10387. }
  10388. return new Function(preamble+script.innerHTML+suffix);
  10389. };
  10390. this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
  10391. // summary:
  10392. // Takes array of nodes, and turns them into class instances and
  10393. // potentially calls a startup method to allow them to connect with
  10394. // any children.
  10395. // nodes: Array
  10396. // Array of nodes or objects like
  10397. // | {
  10398. // | type: "dijit.form.Button",
  10399. // | node: DOMNode,
  10400. // | scripts: [ ... ], // array of <script type="dojo/..."> children of node
  10401. // | inherited: { ... } // settings inherited from ancestors like dir, theme, etc.
  10402. // | }
  10403. // mixin: Object?
  10404. // An object that will be mixed in with each node in the array.
  10405. // Values in the mixin will override values in the node, if they
  10406. // exist.
  10407. // args: Object?
  10408. // An object used to hold kwArgs for instantiation.
  10409. // See parse.args argument for details.
  10410. var thelist = [],
  10411. mixin = mixin||{};
  10412. args = args||{};
  10413. // TODO: for 2.0 default to data-dojo- regardless of scopeName (or maybe scopeName won't exist in 2.0)
  10414. var attrName = (args.scope || d._scopeName) + "Type", // typically "dojoType"
  10415. attrData = "data-" + (args.scope || d._scopeName) + "-"; // typically "data-dojo-"
  10416. d.forEach(nodes, function(obj){
  10417. if(!obj){ return; }
  10418. // Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.
  10419. var node, type, clsInfo, clazz, scripts, fastpath;
  10420. if(obj.node){
  10421. // new format of nodes[] array, object w/lots of properties pre-computed for me
  10422. node = obj.node;
  10423. type = obj.type;
  10424. fastpath = obj.fastpath;
  10425. clsInfo = obj.clsInfo || (type && getClassInfo(type, fastpath));
  10426. clazz = clsInfo && clsInfo.cls;
  10427. scripts = obj.scripts;
  10428. }else{
  10429. // old (backwards compatible) format of nodes[] array, simple array of DOMNodes. no fastpath/data-dojo-type support here.
  10430. node = obj;
  10431. type = attrName in mixin ? mixin[attrName] : node.getAttribute(attrName);
  10432. clsInfo = type && getClassInfo(type);
  10433. clazz = clsInfo && clsInfo.cls;
  10434. scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] :
  10435. d.query("> script[type^='dojo/']", node));
  10436. }
  10437. if(!clsInfo){
  10438. throw new Error("Could not load class '" + type);
  10439. }
  10440. // Setup hash to hold parameter settings for this widget. Start with the parameter
  10441. // settings inherited from ancestors ("dir" and "lang").
  10442. // Inherited setting may later be overridden by explicit settings on node itself.
  10443. var params = {};
  10444. if(args.defaults){
  10445. // settings for the document itself (or whatever subtree is being parsed)
  10446. d._mixin(params, args.defaults);
  10447. }
  10448. if(obj.inherited){
  10449. // settings from dir=rtl or lang=... on a node above this node
  10450. d._mixin(params, obj.inherited);
  10451. }
  10452. // mix things found in data-dojo-props into the params
  10453. if(fastpath){
  10454. var extra = node.getAttribute(attrData + "props");
  10455. if(extra && extra.length){
  10456. try{
  10457. extra = d.fromJson.call(args.propsThis, "{" + extra + "}");
  10458. d._mixin(params, extra);
  10459. }catch(e){
  10460. // give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
  10461. throw new Error(e.toString() + " in data-dojo-props='" + extra + "'");
  10462. }
  10463. }
  10464. // For the benefit of _Templated, check if node has data-dojo-attach-point/data-dojo-attach-event
  10465. // and mix those in as though they were parameters
  10466. var attachPoint = node.getAttribute(attrData + "attach-point");
  10467. if(attachPoint){
  10468. params.dojoAttachPoint = attachPoint;
  10469. }
  10470. var attachEvent = node.getAttribute(attrData + "attach-event");
  10471. if(attachEvent){
  10472. params.dojoAttachEvent = attachEvent;
  10473. }
  10474. dojo.mixin(params, mixin);
  10475. }else{
  10476. // FIXME: we need something like "deprecateOnce()" to throw dojo.deprecation for something.
  10477. // remove this logic in 2.0
  10478. // read parameters (ie, attributes) specified on DOMNode
  10479. var attributes = node.attributes;
  10480. // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
  10481. for(var name in clsInfo.params){
  10482. var item = name in mixin ? { value:mixin[name], specified:true } : attributes.getNamedItem(name);
  10483. if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
  10484. var value = item.value;
  10485. // Deal with IE quirks for 'class' and 'style'
  10486. switch(name){
  10487. case "class":
  10488. value = "className" in mixin ? mixin.className : node.className;
  10489. break;
  10490. case "style":
  10491. value = "style" in mixin ? mixin.style : (node.style && node.style.cssText); // FIXME: Opera?
  10492. }
  10493. var _type = clsInfo.params[name];
  10494. if(typeof value == "string"){
  10495. params[name] = str2obj(value, _type);
  10496. }else{
  10497. params[name] = value;
  10498. }
  10499. }
  10500. }
  10501. // Process <script type="dojo/*"> script tags
  10502. // <script type="dojo/method" event="foo"> tags are added to params, and passed to
  10503. // the widget on instantiation.
  10504. // <script type="dojo/method"> tags (with no event) are executed after instantiation
  10505. // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
  10506. // note: dojo/* script tags cannot exist in self closing widgets, like <input />
  10507. var connects = [], // functions to connect after instantiation
  10508. calls = []; // functions to call after instantiation
  10509. d.forEach(scripts, function(script){
  10510. node.removeChild(script);
  10511. // FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
  10512. var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")),
  10513. type = script.getAttribute("type"),
  10514. nf = d.parser._functionFromScript(script, attrData);
  10515. if(event){
  10516. if(type == "dojo/connect"){
  10517. connects.push({event: event, func: nf});
  10518. }else{
  10519. params[event] = nf;
  10520. }
  10521. }else{
  10522. calls.push(nf);
  10523. }
  10524. });
  10525. var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory;
  10526. // create the instance
  10527. var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
  10528. thelist.push(instance);
  10529. // map it to the JS namespace if that makes sense
  10530. // FIXME: in 2.0, drop jsId support. use data-dojo-id instead
  10531. var jsname = (node.getAttribute(attrData + "id") || node.getAttribute("jsId"));
  10532. if(jsname){
  10533. d.setObject(jsname, instance);
  10534. }
  10535. // process connections and startup functions
  10536. d.forEach(connects, function(connect){
  10537. d.connect(instance, connect.event, null, connect.func);
  10538. });
  10539. d.forEach(calls, function(func){
  10540. func.call(instance);
  10541. });
  10542. });
  10543. // Call startup on each top level instance if it makes sense (as for
  10544. // widgets). Parent widgets will recursively call startup on their
  10545. // (non-top level) children
  10546. if(!mixin._started){
  10547. // TODO: for 2.0, when old instantiate() API is desupported, store parent-child
  10548. // relationships in the nodes[] array so that no getParent() call is needed.
  10549. // Note that will require a parse() call from ContentPane setting a param that the
  10550. // ContentPane is the parent widget (so that the parse doesn't call startup() on the
  10551. // ContentPane's children)
  10552. d.forEach(thelist, function(instance){
  10553. if( !args.noStart && instance &&
  10554. dojo.isFunction(instance.startup) &&
  10555. !instance._started &&
  10556. (!instance.getParent || !instance.getParent())
  10557. ){
  10558. instance.startup();
  10559. }
  10560. });
  10561. }
  10562. return thelist;
  10563. };
  10564. this.parse = function(rootNode, args){
  10565. // summary:
  10566. // Scan the DOM for class instances, and instantiate them.
  10567. //
  10568. // description:
  10569. // Search specified node (or root node) recursively for class instances,
  10570. // and instantiate them. Searches for either data-dojo-type="Class" or
  10571. // dojoType="Class" where "Class" is a a fully qualified class name,
  10572. // like `dijit.form.Button`
  10573. //
  10574. // Using `data-dojo-type`:
  10575. // Attributes using can be mixed into the parameters used to instantitate the
  10576. // Class by using a `data-dojo-props` attribute on the node being converted.
  10577. // `data-dojo-props` should be a string attribute to be converted from JSON.
  10578. //
  10579. // Using `dojoType`:
  10580. // Attributes are read from the original domNode and converted to appropriate
  10581. // types by looking up the Class prototype values. This is the default behavior
  10582. // from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
  10583. // go away in Dojo 2.0.
  10584. //
  10585. // rootNode: DomNode?
  10586. // A default starting root node from which to start the parsing. Can be
  10587. // omitted, defaulting to the entire document. If omitted, the `args`
  10588. // object can be passed in this place. If the `args` object has a
  10589. // `rootNode` member, that is used.
  10590. //
  10591. // args: Object
  10592. // a kwArgs object passed along to instantiate()
  10593. //
  10594. // * noStart: Boolean?
  10595. // when set will prevent the parser from calling .startup()
  10596. // when locating the nodes.
  10597. // * rootNode: DomNode?
  10598. // identical to the function's `rootNode` argument, though
  10599. // allowed to be passed in via this `args object.
  10600. // * template: Boolean
  10601. // If true, ignores ContentPane's stopParser flag and parses contents inside of
  10602. // a ContentPane inside of a template. This allows dojoAttachPoint on widgets/nodes
  10603. // nested inside the ContentPane to work.
  10604. // * inherited: Object
  10605. // Hash possibly containing dir and lang settings to be applied to
  10606. // parsed widgets, unless there's another setting on a sub-node that overrides
  10607. // * scope: String
  10608. // Root for attribute names to search for. If scopeName is dojo,
  10609. // will search for data-dojo-type (or dojoType). For backwards compatibility
  10610. // reasons defaults to dojo._scopeName (which is "dojo" except when
  10611. // multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  10612. // * propsThis: Object
  10613. // If specified, "this" referenced from data-dojo-props will refer to propsThis.
  10614. // Intended for use from the widgets-in-template feature of `dijit._Templated`
  10615. //
  10616. // example:
  10617. // Parse all widgets on a page:
  10618. // | dojo.parser.parse();
  10619. //
  10620. // example:
  10621. // Parse all classes within the node with id="foo"
  10622. // | dojo.parser.parse(dojo.byId('foo'));
  10623. //
  10624. // example:
  10625. // Parse all classes in a page, but do not call .startup() on any
  10626. // child
  10627. // | dojo.parser.parse({ noStart: true })
  10628. //
  10629. // example:
  10630. // Parse all classes in a node, but do not call .startup()
  10631. // | dojo.parser.parse(someNode, { noStart:true });
  10632. // | // or
  10633. // | dojo.parser.parse({ noStart:true, rootNode: someNode });
  10634. // determine the root node based on the passed arguments.
  10635. var root;
  10636. if(!args && rootNode && rootNode.rootNode){
  10637. args = rootNode;
  10638. root = args.rootNode;
  10639. }else{
  10640. root = rootNode;
  10641. }
  10642. root = root ? dojo.byId(root) : dojo.body();
  10643. args = args || {};
  10644. var attrName = (args.scope || d._scopeName) + "Type", // typically "dojoType"
  10645. attrData = "data-" + (args.scope || d._scopeName) + "-"; // typically "data-dojo-"
  10646. function scan(parent, list){
  10647. // summary:
  10648. // Parent is an Object representing a DOMNode, with or without a dojoType specified.
  10649. // Scan parent's children looking for nodes with dojoType specified, storing in list[].
  10650. // If parent has a dojoType, also collects <script type=dojo/*> children and stores in parent.scripts[].
  10651. // parent: Object
  10652. // Object representing the parent node, like
  10653. // | {
  10654. // | node: DomNode, // scan children of this node
  10655. // | inherited: {dir: "rtl"}, // dir/lang setting inherited from above node
  10656. // |
  10657. // | // attributes only set if node has dojoType specified
  10658. // | scripts: [], // empty array, put <script type=dojo/*> in here
  10659. // | clsInfo: { cls: dijit.form.Button, ...}
  10660. // | }
  10661. // list: DomNode[]
  10662. // Output array of objects (same format as parent) representing nodes to be turned into widgets
  10663. // Effective dir and lang settings on parent node, either set directly or inherited from grandparent
  10664. var inherited = dojo.clone(parent.inherited);
  10665. dojo.forEach(["dir", "lang"], function(name){
  10666. // TODO: what if this is a widget and dir/lang are declared in data-dojo-props?
  10667. var val = parent.node.getAttribute(name);
  10668. if(val){
  10669. inherited[name] = val;
  10670. }
  10671. });
  10672. // if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
  10673. var scripts = parent.clsInfo && !parent.clsInfo.cls.prototype._noScript ? parent.scripts : null;
  10674. // unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
  10675. var recurse = (!parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser) || (args && args.template);
  10676. // scan parent's children looking for dojoType and <script type=dojo/*>
  10677. for(var child = parent.node.firstChild; child; child = child.nextSibling){
  10678. if(child.nodeType == 1){
  10679. // FIXME: desupport dojoType in 2.0. use data-dojo-type instead
  10680. var type, html5 = recurse && child.getAttribute(attrData + "type");
  10681. if(html5){
  10682. type = html5;
  10683. }else{
  10684. // fallback to backward compatible mode, using dojoType. remove in 2.0
  10685. type = recurse && child.getAttribute(attrName);
  10686. }
  10687. var fastpath = html5 == type;
  10688. if(type){
  10689. // if dojoType/data-dojo-type specified, add to output array of nodes to instantiate
  10690. var params = {
  10691. "type": type,
  10692. fastpath: fastpath,
  10693. clsInfo: getClassInfo(type, fastpath), // note: won't find classes declared via dojo.Declaration
  10694. node: child,
  10695. scripts: [], // <script> nodes that are parent's children
  10696. inherited: inherited // dir & lang attributes inherited from parent
  10697. };
  10698. list.push(params);
  10699. // Recurse, collecting <script type="dojo/..."> children, and also looking for
  10700. // descendant nodes with dojoType specified (unless the widget has the stopParser flag),
  10701. scan(params, list);
  10702. }else if(scripts && child.nodeName.toLowerCase() == "script"){
  10703. // if <script type="dojo/...">, save in scripts[]
  10704. type = child.getAttribute("type");
  10705. if (type && /^dojo\/\w/i.test(type)) {
  10706. scripts.push(child);
  10707. }
  10708. }else if(recurse){
  10709. // Recurse, looking for grandchild nodes with dojoType specified
  10710. scan({
  10711. node: child,
  10712. inherited: inherited
  10713. }, list);
  10714. }
  10715. }
  10716. }
  10717. }
  10718. // Ignore bogus entries in inherited hash like {dir: ""}
  10719. var inherited = {};
  10720. if(args && args.inherited){
  10721. for(var key in args.inherited){
  10722. if(args.inherited[key]){ inherited[key] = args.inherited[key]; }
  10723. }
  10724. }
  10725. // Make list of all nodes on page w/dojoType specified
  10726. var list = [];
  10727. scan({
  10728. node: root,
  10729. inherited: inherited
  10730. }, list);
  10731. // go build the object instances
  10732. var mixin = args && args.template ? {template: true} : null;
  10733. return this.instantiate(list, mixin, args); // Array
  10734. };
  10735. }();
  10736. //Register the parser callback. It should be the first callback
  10737. //after the a11y test.
  10738. (function(){
  10739. var parseRunner = function(){
  10740. if(dojo.config.parseOnLoad){
  10741. dojo.parser.parse();
  10742. }
  10743. };
  10744. // FIXME: need to clobber cross-dependency!!
  10745. if(dojo.getObject("dijit.wai.onload") === dojo._loaders[0]){
  10746. dojo._loaders.splice(1, 0, parseRunner);
  10747. }else{
  10748. dojo._loaders.unshift(parseRunner);
  10749. }
  10750. })();
  10751. }
  10752. if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  10753. dojo._hasResource["dojo.cache"] = true;
  10754. dojo.provide("dojo.cache");
  10755. /*=====
  10756. dojo.cache = {
  10757. // summary:
  10758. // A way to cache string content that is fetchable via `dojo.moduleUrl`.
  10759. };
  10760. =====*/
  10761. var cache = {};
  10762. dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
  10763. // summary:
  10764. // A getter and setter for storing the string content associated with the
  10765. // module and url arguments.
  10766. // description:
  10767. // module and url are used to call `dojo.moduleUrl()` to generate a module URL.
  10768. // If value is specified, the cache value for the moduleUrl will be set to
  10769. // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
  10770. // in its internal cache and return that cached value for the URL. To clear
  10771. // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
  10772. // the URL contents, only modules on the same domain of the page can use this capability.
  10773. // The build system can inline the cache values though, to allow for xdomain hosting.
  10774. // module: String||Object
  10775. // If a String, the module name to use for the base part of the URL, similar to module argument
  10776. // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
  10777. // generates a valid path for the cache item. For example, a dojo._Url object.
  10778. // url: String
  10779. // The rest of the path to append to the path derived from the module argument. If
  10780. // module is an object, then this second argument should be the "value" argument instead.
  10781. // value: String||Object?
  10782. // If a String, the value to use in the cache for the module/url combination.
  10783. // If an Object, it can have two properties: value and sanitize. The value property
  10784. // should be the value to use in the cache, and sanitize can be set to true or false,
  10785. // to indicate if XML declarations should be removed from the value and if the HTML
  10786. // inside a body tag in the value should be extracted as the real value. The value argument
  10787. // or the value property on the value argument are usually only used by the build system
  10788. // as it inlines cache content.
  10789. // example:
  10790. // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
  10791. // of call is used to avoid an issue with the build system erroneously trying to intern
  10792. // this example. To get the build system to intern your dojo.cache calls, use the
  10793. // "dojo.cache" style of call):
  10794. // | //If template.html contains "<h1>Hello</h1>" that will be
  10795. // | //the value for the text variable.
  10796. // | var text = dojo["cache"]("my.module", "template.html");
  10797. // example:
  10798. // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
  10799. // (the dojo["cache"] style of call is used to avoid an issue with the build system
  10800. // erroneously trying to intern this example. To get the build system to intern your
  10801. // dojo.cache calls, use the "dojo.cache" style of call):
  10802. // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
  10803. // | //text variable will contain just "<h1>Hello</h1>".
  10804. // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
  10805. // example:
  10806. // Same example as previous, but demostrates how an object can be passed in as
  10807. // the first argument, then the value argument can then be the second argument.
  10808. // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
  10809. // | //text variable will contain just "<h1>Hello</h1>".
  10810. // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
  10811. //Module could be a string, or an object that has a toString() method
  10812. //that will return a useful path. If it is an object, then the "url" argument
  10813. //will actually be the value argument.
  10814. if(typeof module == "string"){
  10815. var pathObj = dojo.moduleUrl(module, url);
  10816. }else{
  10817. pathObj = module;
  10818. value = url;
  10819. }
  10820. var key = pathObj.toString();
  10821. var val = value;
  10822. if(value != undefined && !dojo.isString(value)){
  10823. val = ("value" in value ? value.value : undefined);
  10824. }
  10825. var sanitize = value && value.sanitize ? true : false;
  10826. if(typeof val == "string"){
  10827. //We have a string, set cache value
  10828. val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
  10829. }else if(val === null){
  10830. //Remove cached value
  10831. delete cache[key];
  10832. }else{
  10833. //Allow cache values to be empty strings. If key property does
  10834. //not exist, fetch it.
  10835. if(!(key in cache)){
  10836. val = dojo._getText(key);
  10837. cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
  10838. }
  10839. val = cache[key];
  10840. }
  10841. return val; //String
  10842. };
  10843. dojo.cache._sanitize = function(/*String*/val){
  10844. // summary:
  10845. // Strips <?xml ...?> declarations so that external SVG and XML
  10846. // documents can be added to a document without worry. Also, if the string
  10847. // is an HTML document, only the part inside the body tag is returned.
  10848. // description:
  10849. // Copied from dijit._Templated._sanitizeTemplateString.
  10850. if(val){
  10851. val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
  10852. var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  10853. if(matches){
  10854. val = matches[1];
  10855. }
  10856. }else{
  10857. val = "";
  10858. }
  10859. return val; //String
  10860. };
  10861. }
  10862. if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  10863. dojo._hasResource["dijit._Templated"] = true;
  10864. dojo.provide("dijit._Templated");
  10865. dojo.declare("dijit._Templated",
  10866. null,
  10867. {
  10868. // summary:
  10869. // Mixin for widgets that are instantiated from a template
  10870. // templateString: [protected] String
  10871. // A string that represents the widget template. Pre-empts the
  10872. // templatePath. In builds that have their strings "interned", the
  10873. // templatePath is converted to an inline templateString, thereby
  10874. // preventing a synchronous network call.
  10875. //
  10876. // Use in conjunction with dojo.cache() to load from a file.
  10877. templateString: null,
  10878. // templatePath: [protected deprecated] String
  10879. // Path to template (HTML file) for this widget relative to dojo.baseUrl.
  10880. // Deprecated: use templateString with dojo.cache() instead.
  10881. templatePath: null,
  10882. // widgetsInTemplate: [protected] Boolean
  10883. // Should we parse the template to find widgets that might be
  10884. // declared in markup inside it? False by default.
  10885. widgetsInTemplate: false,
  10886. // skipNodeCache: [protected] Boolean
  10887. // If using a cached widget template node poses issues for a
  10888. // particular widget class, it can set this property to ensure
  10889. // that its template is always re-built from a string
  10890. _skipNodeCache: false,
  10891. // _earlyTemplatedStartup: Boolean
  10892. // A fallback to preserve the 1.0 - 1.3 behavior of children in
  10893. // templates having their startup called before the parent widget
  10894. // fires postCreate. Defaults to 'false', causing child widgets to
  10895. // have their .startup() called immediately before a parent widget
  10896. // .startup(), but always after the parent .postCreate(). Set to
  10897. // 'true' to re-enable to previous, arguably broken, behavior.
  10898. _earlyTemplatedStartup: false,
  10899. /*=====
  10900. // _attachPoints: [private] String[]
  10901. // List of widget attribute names associated with dojoAttachPoint=... in the
  10902. // template, ex: ["containerNode", "labelNode"]
  10903. _attachPoints: [],
  10904. =====*/
  10905. /*=====
  10906. // _attachEvents: [private] Handle[]
  10907. // List of connections associated with dojoAttachEvent=... in the
  10908. // template
  10909. _attachEvents: [],
  10910. =====*/
  10911. constructor: function(){
  10912. this._attachPoints = [];
  10913. this._attachEvents = [];
  10914. },
  10915. _stringRepl: function(tmpl){
  10916. // summary:
  10917. // Does substitution of ${foo} type properties in template string
  10918. // tags:
  10919. // private
  10920. var className = this.declaredClass, _this = this;
  10921. // Cache contains a string because we need to do property replacement
  10922. // do the property replacement
  10923. return dojo.string.substitute(tmpl, this, function(value, key){
  10924. if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
  10925. if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
  10926. if(value == null){ return ""; }
  10927. // Substitution keys beginning with ! will skip the transform step,
  10928. // in case a user wishes to insert unescaped markup, e.g. ${!foo}
  10929. return key.charAt(0) == "!" ? value :
  10930. // Safer substitution, see heading "Attribute values" in
  10931. // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
  10932. value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
  10933. }, this);
  10934. },
  10935. buildRendering: function(){
  10936. // summary:
  10937. // Construct the UI for this widget from a template, setting this.domNode.
  10938. // tags:
  10939. // protected
  10940. // Lookup cached version of template, and download to cache if it
  10941. // isn't there already. Returns either a DomNode or a string, depending on
  10942. // whether or not the template contains ${foo} replacement parameters.
  10943. var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);
  10944. var node;
  10945. if(dojo.isString(cached)){
  10946. node = dojo._toDom(this._stringRepl(cached));
  10947. if(node.nodeType != 1){
  10948. // Flag common problems such as templates with multiple top level nodes (nodeType == 11)
  10949. throw new Error("Invalid template: " + cached);
  10950. }
  10951. }else{
  10952. // if it's a node, all we have to do is clone it
  10953. node = cached.cloneNode(true);
  10954. }
  10955. this.domNode = node;
  10956. // Call down to _Widget.buildRendering() to get base classes assigned
  10957. // TODO: change the baseClass assignment to attributeMap
  10958. this.inherited(arguments);
  10959. // recurse through the node, looking for, and attaching to, our
  10960. // attachment points and events, which should be defined on the template node.
  10961. this._attachTemplateNodes(node);
  10962. if(this.widgetsInTemplate){
  10963. // Store widgets that we need to start at a later point in time
  10964. var cw = (this._startupWidgets = dojo.parser.parse(node, {
  10965. noStart: !this._earlyTemplatedStartup,
  10966. template: true,
  10967. inherited: {dir: this.dir, lang: this.lang},
  10968. propsThis: this, // so data-dojo-props of widgets in the template can reference "this" to refer to me
  10969. scope: "dojo" // even in multi-version mode templates use dojoType/data-dojo-type
  10970. }));
  10971. this._supportingWidgets = dijit.findWidgets(node);
  10972. this._attachTemplateNodes(cw, function(n,p){
  10973. return n[p];
  10974. });
  10975. }
  10976. this._fillContent(this.srcNodeRef);
  10977. },
  10978. _fillContent: function(/*DomNode*/ source){
  10979. // summary:
  10980. // Relocate source contents to templated container node.
  10981. // this.containerNode must be able to receive children, or exceptions will be thrown.
  10982. // tags:
  10983. // protected
  10984. var dest = this.containerNode;
  10985. if(source && dest){
  10986. while(source.hasChildNodes()){
  10987. dest.appendChild(source.firstChild);
  10988. }
  10989. }
  10990. },
  10991. _attachTemplateNodes: function(rootNode, getAttrFunc){
  10992. // summary:
  10993. // Iterate through the template and attach functions and nodes accordingly.
  10994. // Alternately, if rootNode is an array of widgets, then will process dojoAttachPoint
  10995. // etc. for those widgets.
  10996. // description:
  10997. // Map widget properties and functions to the handlers specified in
  10998. // the dom node and it's descendants. This function iterates over all
  10999. // nodes and looks for these properties:
  11000. // * dojoAttachPoint
  11001. // * dojoAttachEvent
  11002. // * waiRole
  11003. // * waiState
  11004. // rootNode: DomNode|Array[Widgets]
  11005. // the node to search for properties. All children will be searched.
  11006. // getAttrFunc: Function?
  11007. // a function which will be used to obtain property for a given
  11008. // DomNode/Widget
  11009. // tags:
  11010. // private
  11011. getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };
  11012. var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
  11013. var x = dojo.isArray(rootNode) ? 0 : -1;
  11014. for(; x<nodes.length; x++){
  11015. var baseNode = (x == -1) ? rootNode : nodes[x];
  11016. if(this.widgetsInTemplate && (getAttrFunc(baseNode, "dojoType") || getAttrFunc(baseNode, "data-dojo-type"))){
  11017. continue;
  11018. }
  11019. // Process dojoAttachPoint
  11020. var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint") || getAttrFunc(baseNode, "data-dojo-attach-point");
  11021. if(attachPoint){
  11022. var point, points = attachPoint.split(/\s*,\s*/);
  11023. while((point = points.shift())){
  11024. if(dojo.isArray(this[point])){
  11025. this[point].push(baseNode);
  11026. }else{
  11027. this[point]=baseNode;
  11028. }
  11029. this._attachPoints.push(point);
  11030. }
  11031. }
  11032. // Process dojoAttachEvent
  11033. var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent") || getAttrFunc(baseNode, "data-dojo-attach-event");;
  11034. if(attachEvent){
  11035. // NOTE: we want to support attributes that have the form
  11036. // "domEvent: nativeEvent; ..."
  11037. var event, events = attachEvent.split(/\s*,\s*/);
  11038. var trim = dojo.trim;
  11039. while((event = events.shift())){
  11040. if(event){
  11041. var thisFunc = null;
  11042. if(event.indexOf(":") != -1){
  11043. // oh, if only JS had tuple assignment
  11044. var funcNameArr = event.split(":");
  11045. event = trim(funcNameArr[0]);
  11046. thisFunc = trim(funcNameArr[1]);
  11047. }else{
  11048. event = trim(event);
  11049. }
  11050. if(!thisFunc){
  11051. thisFunc = event;
  11052. }
  11053. this._attachEvents.push(this.connect(baseNode, event, thisFunc));
  11054. }
  11055. }
  11056. }
  11057. // waiRole, waiState
  11058. // TODO: remove this in 2.0, templates are now using role=... and aria-XXX=... attributes directicly
  11059. var role = getAttrFunc(baseNode, "waiRole");
  11060. if(role){
  11061. dijit.setWaiRole(baseNode, role);
  11062. }
  11063. var values = getAttrFunc(baseNode, "waiState");
  11064. if(values){
  11065. dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
  11066. if(stateValue.indexOf('-') != -1){
  11067. var pair = stateValue.split('-');
  11068. dijit.setWaiState(baseNode, pair[0], pair[1]);
  11069. }
  11070. });
  11071. }
  11072. }
  11073. },
  11074. startup: function(){
  11075. dojo.forEach(this._startupWidgets, function(w){
  11076. if(w && !w._started && w.startup){
  11077. w.startup();
  11078. }
  11079. });
  11080. this.inherited(arguments);
  11081. },
  11082. destroyRendering: function(){
  11083. // Delete all attach points to prevent IE6 memory leaks.
  11084. dojo.forEach(this._attachPoints, function(point){
  11085. delete this[point];
  11086. }, this);
  11087. this._attachPoints = [];
  11088. // And same for event handlers
  11089. dojo.forEach(this._attachEvents, this.disconnect, this);
  11090. this._attachEvents = [];
  11091. this.inherited(arguments);
  11092. }
  11093. }
  11094. );
  11095. // key is either templatePath or templateString; object is either string or DOM tree
  11096. dijit._Templated._templateCache = {};
  11097. dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
  11098. // summary:
  11099. // Static method to get a template based on the templatePath or
  11100. // templateString key
  11101. // templatePath: String||dojo.uri.Uri
  11102. // The URL to get the template from.
  11103. // templateString: String?
  11104. // a string to use in lieu of fetching the template from a URL. Takes precedence
  11105. // over templatePath
  11106. // returns: Mixed
  11107. // Either string (if there are ${} variables that need to be replaced) or just
  11108. // a DOM tree (if the node can be cloned directly)
  11109. // is it already cached?
  11110. var tmplts = dijit._Templated._templateCache;
  11111. var key = templateString || templatePath;
  11112. var cached = tmplts[key];
  11113. if(cached){
  11114. try{
  11115. // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
  11116. if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){
  11117. // string or node of the same document
  11118. return cached;
  11119. }
  11120. }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
  11121. dojo.destroy(cached);
  11122. }
  11123. // If necessary, load template string from template path
  11124. if(!templateString){
  11125. templateString = dojo.cache(templatePath, {sanitize: true});
  11126. }
  11127. templateString = dojo.string.trim(templateString);
  11128. if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){
  11129. // there are variables in the template so all we can do is cache the string
  11130. return (tmplts[key] = templateString); //String
  11131. }else{
  11132. // there are no variables in the template so we can cache the DOM tree
  11133. var node = dojo._toDom(templateString);
  11134. if(node.nodeType != 1){
  11135. throw new Error("Invalid template: " + templateString);
  11136. }
  11137. return (tmplts[key] = node); //Node
  11138. }
  11139. };
  11140. if(dojo.isIE){
  11141. dojo.addOnWindowUnload(function(){
  11142. var cache = dijit._Templated._templateCache;
  11143. for(var key in cache){
  11144. var value = cache[key];
  11145. if(typeof value == "object"){ // value is either a string or a DOM node template
  11146. dojo.destroy(value);
  11147. }
  11148. delete cache[key];
  11149. }
  11150. });
  11151. }
  11152. // These arguments can be specified for widgets which are used in templates.
  11153. // Since any widget can be specified as sub widgets in template, mix it
  11154. // into the base widget class. (This is a hack, but it's effective.)
  11155. dojo.extend(dijit._Widget,{
  11156. dojoAttachEvent: "",
  11157. dojoAttachPoint: "",
  11158. waiRole: "",
  11159. waiState:""
  11160. });
  11161. }
  11162. if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  11163. dojo._hasResource["dijit.Tooltip"] = true;
  11164. dojo.provide("dijit.Tooltip");
  11165. dojo.declare(
  11166. "dijit._MasterTooltip",
  11167. [dijit._Widget, dijit._Templated],
  11168. {
  11169. // summary:
  11170. // Internal widget that holds the actual tooltip markup,
  11171. // which occurs once per page.
  11172. // Called by Tooltip widgets which are just containers to hold
  11173. // the markup
  11174. // tags:
  11175. // protected
  11176. // duration: Integer
  11177. // Milliseconds to fade in/fade out
  11178. duration: dijit.defaultDuration,
  11179. templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\"\n\t><div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" role='alert'></div\n\t><div class=\"dijitTooltipConnector\" dojoAttachPoint=\"connectorNode\"></div\n></div>\n"),
  11180. postCreate: function(){
  11181. dojo.body().appendChild(this.domNode);
  11182. this.bgIframe = new dijit.BackgroundIframe(this.domNode);
  11183. // Setup fade-in and fade-out functions.
  11184. this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
  11185. this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });
  11186. },
  11187. show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
  11188. // summary:
  11189. // Display tooltip w/specified contents to right of specified node
  11190. // (To left if there's no space on the right, or if rtl == true)
  11191. if(this.aroundNode && this.aroundNode === aroundNode){
  11192. return;
  11193. }
  11194. // reset width; it may have been set by orient() on a previous tooltip show()
  11195. this.domNode.width = "auto";
  11196. if(this.fadeOut.status() == "playing"){
  11197. // previous tooltip is being hidden; wait until the hide completes then show new one
  11198. this._onDeck=arguments;
  11199. return;
  11200. }
  11201. this.containerNode.innerHTML=innerHTML;
  11202. var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, dijit.getPopupAroundAlignment((position && position.length) ? position : dijit.Tooltip.defaultPosition, !rtl), dojo.hitch(this, "orient"));
  11203. // show it
  11204. dojo.style(this.domNode, "opacity", 0);
  11205. this.fadeIn.play();
  11206. this.isShowingNow = true;
  11207. this.aroundNode = aroundNode;
  11208. },
  11209. orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
  11210. // summary:
  11211. // Private function to set CSS for tooltip node based on which position it's in.
  11212. // This is called by the dijit popup code. It will also reduce the tooltip's
  11213. // width to whatever width is available
  11214. // tags:
  11215. // protected
  11216. this.connectorNode.style.top = ""; //reset to default
  11217. //Adjust the spaceAvailable width, without changing the spaceAvailable object
  11218. var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;
  11219. node.className = "dijitTooltip " +
  11220. {
  11221. "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
  11222. "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
  11223. "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
  11224. "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
  11225. "BR-BL": "dijitTooltipRight",
  11226. "BL-BR": "dijitTooltipLeft"
  11227. }[aroundCorner + "-" + tooltipCorner];
  11228. // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
  11229. this.domNode.style.width = "auto";
  11230. var size = dojo.contentBox(this.domNode);
  11231. var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
  11232. var widthWasReduced = width < size.w;
  11233. this.domNode.style.width = width+"px";
  11234. //Adjust width for tooltips that have a really long word or a nowrap setting
  11235. if(widthWasReduced){
  11236. this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
  11237. var scrollWidth = this.containerNode.scrollWidth;
  11238. this.containerNode.style.overflow = "visible"; //change it back
  11239. if(scrollWidth > width){
  11240. scrollWidth = scrollWidth + dojo.style(this.domNode,"paddingLeft") + dojo.style(this.domNode,"paddingRight");
  11241. this.domNode.style.width = scrollWidth + "px";
  11242. }
  11243. }
  11244. // Reposition the tooltip connector.
  11245. if(tooltipCorner.charAt(0) == 'B' && aroundCorner.charAt(0) == 'B'){
  11246. var mb = dojo.marginBox(node);
  11247. var tooltipConnectorHeight = this.connectorNode.offsetHeight;
  11248. if(mb.h > spaceAvailable.h){
  11249. // The tooltip starts at the top of the page and will extend past the aroundNode
  11250. var aroundNodePlacement = spaceAvailable.h - (aroundNodeCoords.h / 2) - (tooltipConnectorHeight / 2);
  11251. this.connectorNode.style.top = aroundNodePlacement + "px";
  11252. this.connectorNode.style.bottom = "";
  11253. }else{
  11254. // Align center of connector with center of aroundNode, except don't let bottom
  11255. // of connector extend below bottom of tooltip content, or top of connector
  11256. // extend past top of tooltip content
  11257. this.connectorNode.style.bottom = Math.min(
  11258. Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
  11259. mb.h - tooltipConnectorHeight) + "px";
  11260. this.connectorNode.style.top = "";
  11261. }
  11262. }else{
  11263. // reset the tooltip back to the defaults
  11264. this.connectorNode.style.top = "";
  11265. this.connectorNode.style.bottom = "";
  11266. }
  11267. return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
  11268. },
  11269. _onShow: function(){
  11270. // summary:
  11271. // Called at end of fade-in operation
  11272. // tags:
  11273. // protected
  11274. if(dojo.isIE){
  11275. // the arrow won't show up on a node w/an opacity filter
  11276. this.domNode.style.filter="";
  11277. }
  11278. },
  11279. hide: function(aroundNode){
  11280. // summary:
  11281. // Hide the tooltip
  11282. if(this._onDeck && this._onDeck[1] == aroundNode){
  11283. // this hide request is for a show() that hasn't even started yet;
  11284. // just cancel the pending show()
  11285. this._onDeck=null;
  11286. }else if(this.aroundNode === aroundNode){
  11287. // this hide request is for the currently displayed tooltip
  11288. this.fadeIn.stop();
  11289. this.isShowingNow = false;
  11290. this.aroundNode = null;
  11291. this.fadeOut.play();
  11292. }else{
  11293. // just ignore the call, it's for a tooltip that has already been erased
  11294. }
  11295. },
  11296. _onHide: function(){
  11297. // summary:
  11298. // Called at end of fade-out operation
  11299. // tags:
  11300. // protected
  11301. this.domNode.style.cssText=""; // to position offscreen again
  11302. this.containerNode.innerHTML="";
  11303. if(this._onDeck){
  11304. // a show request has been queued up; do it now
  11305. this.show.apply(this, this._onDeck);
  11306. this._onDeck=null;
  11307. }
  11308. }
  11309. }
  11310. );
  11311. dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
  11312. // summary:
  11313. // Display tooltip w/specified contents in specified position.
  11314. // See description of dijit.Tooltip.defaultPosition for details on position parameter.
  11315. // If position is not specified then dijit.Tooltip.defaultPosition is used.
  11316. if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
  11317. return dijit._masterTT.show(innerHTML, aroundNode, position, rtl);
  11318. };
  11319. dijit.hideTooltip = function(aroundNode){
  11320. // summary:
  11321. // Hide the tooltip
  11322. if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
  11323. return dijit._masterTT.hide(aroundNode);
  11324. };
  11325. dojo.declare(
  11326. "dijit.Tooltip",
  11327. dijit._Widget,
  11328. {
  11329. // summary:
  11330. // Pops up a tooltip (a help message) when you hover over a node.
  11331. // label: String
  11332. // Text to display in the tooltip.
  11333. // Specified as innerHTML when creating the widget from markup.
  11334. label: "",
  11335. // showDelay: Integer
  11336. // Number of milliseconds to wait after hovering over/focusing on the object, before
  11337. // the tooltip is displayed.
  11338. showDelay: 400,
  11339. // connectId: String|String[]
  11340. // Id of domNode(s) to attach the tooltip to.
  11341. // When user hovers over specified dom node, the tooltip will appear.
  11342. connectId: [],
  11343. // position: String[]
  11344. // See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
  11345. position: [],
  11346. _setConnectIdAttr: function(/*String*/ newId){
  11347. // summary:
  11348. // Connect to node(s) (specified by id)
  11349. // Remove connections to old nodes (if there are any)
  11350. dojo.forEach(this._connections || [], function(nested){
  11351. dojo.forEach(nested, dojo.hitch(this, "disconnect"));
  11352. }, this);
  11353. // Make connections to nodes in newIds.
  11354. var ary = dojo.isArrayLike(newId) ? newId : (newId ? [newId] : []);
  11355. this._connections = dojo.map(ary, function(id){
  11356. var node = dojo.byId(id);
  11357. return node ? [
  11358. this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
  11359. this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
  11360. this.connect(node, "onfocus", "_onTargetFocus"),
  11361. this.connect(node, "onblur", "_onTargetBlur")
  11362. ] : [];
  11363. }, this);
  11364. this._set("connectId", newId);
  11365. this._connectIds = ary; // save as array
  11366. },
  11367. addTarget: function(/*DOMNODE || String*/ node){
  11368. // summary:
  11369. // Attach tooltip to specified node if it's not already connected
  11370. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  11371. var id = node.id || node;
  11372. if(dojo.indexOf(this._connectIds, id) == -1){
  11373. this.set("connectId", this._connectIds.concat(id));
  11374. }
  11375. },
  11376. removeTarget: function(/*DOMNODE || String*/ node){
  11377. // summary:
  11378. // Detach tooltip from specified node
  11379. // TODO: remove in 2.0 and just use set("connectId", ...) interface
  11380. var id = node.id || node, // map from DOMNode back to plain id string
  11381. idx = dojo.indexOf(this._connectIds, id);
  11382. if(idx >= 0){
  11383. // remove id (modifies original this._connectIds but that's OK in this case)
  11384. this._connectIds.splice(idx, 1);
  11385. this.set("connectId", this._connectIds);
  11386. }
  11387. },
  11388. buildRendering: function(){
  11389. this.inherited(arguments);
  11390. dojo.addClass(this.domNode,"dijitTooltipData");
  11391. },
  11392. startup: function(){
  11393. this.inherited(arguments);
  11394. // If this tooltip was created in a template, or for some other reason the specified connectId[s]
  11395. // didn't exist during the widget's initialization, then connect now.
  11396. var ids = this.connectId;
  11397. dojo.forEach(dojo.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
  11398. },
  11399. _onTargetMouseEnter: function(/*Event*/ e){
  11400. // summary:
  11401. // Handler for mouseenter event on the target node
  11402. // tags:
  11403. // private
  11404. this._onHover(e);
  11405. },
  11406. _onTargetMouseLeave: function(/*Event*/ e){
  11407. // summary:
  11408. // Handler for mouseleave event on the target node
  11409. // tags:
  11410. // private
  11411. this._onUnHover(e);
  11412. },
  11413. _onTargetFocus: function(/*Event*/ e){
  11414. // summary:
  11415. // Handler for focus event on the target node
  11416. // tags:
  11417. // private
  11418. this._focus = true;
  11419. this._onHover(e);
  11420. },
  11421. _onTargetBlur: function(/*Event*/ e){
  11422. // summary:
  11423. // Handler for blur event on the target node
  11424. // tags:
  11425. // private
  11426. this._focus = false;
  11427. this._onUnHover(e);
  11428. },
  11429. _onHover: function(/*Event*/ e){
  11430. // summary:
  11431. // Despite the name of this method, it actually handles both hover and focus
  11432. // events on the target node, setting a timer to show the tooltip.
  11433. // tags:
  11434. // private
  11435. if(!this._showTimer){
  11436. var target = e.target;
  11437. this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
  11438. }
  11439. },
  11440. _onUnHover: function(/*Event*/ e){
  11441. // summary:
  11442. // Despite the name of this method, it actually handles both mouseleave and blur
  11443. // events on the target node, hiding the tooltip.
  11444. // tags:
  11445. // private
  11446. // keep a tooltip open if the associated element still has focus (even though the
  11447. // mouse moved away)
  11448. if(this._focus){ return; }
  11449. if(this._showTimer){
  11450. clearTimeout(this._showTimer);
  11451. delete this._showTimer;
  11452. }
  11453. this.close();
  11454. },
  11455. open: function(/*DomNode*/ target){
  11456. // summary:
  11457. // Display the tooltip; usually not called directly.
  11458. // tags:
  11459. // private
  11460. if(this._showTimer){
  11461. clearTimeout(this._showTimer);
  11462. delete this._showTimer;
  11463. }
  11464. dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight());
  11465. this._connectNode = target;
  11466. this.onShow(target, this.position);
  11467. },
  11468. close: function(){
  11469. // summary:
  11470. // Hide the tooltip or cancel timer for show of tooltip
  11471. // tags:
  11472. // private
  11473. if(this._connectNode){
  11474. // if tooltip is currently shown
  11475. dijit.hideTooltip(this._connectNode);
  11476. delete this._connectNode;
  11477. this.onHide();
  11478. }
  11479. if(this._showTimer){
  11480. // if tooltip is scheduled to be shown (after a brief delay)
  11481. clearTimeout(this._showTimer);
  11482. delete this._showTimer;
  11483. }
  11484. },
  11485. onShow: function(target, position){
  11486. // summary:
  11487. // Called when the tooltip is shown
  11488. // tags:
  11489. // callback
  11490. },
  11491. onHide: function(){
  11492. // summary:
  11493. // Called when the tooltip is hidden
  11494. // tags:
  11495. // callback
  11496. },
  11497. uninitialize: function(){
  11498. this.close();
  11499. this.inherited(arguments);
  11500. }
  11501. }
  11502. );
  11503. // dijit.Tooltip.defaultPosition: String[]
  11504. // This variable controls the position of tooltips, if the position is not specified to
  11505. // the Tooltip widget or *TextBox widget itself. It's an array of strings with the following values:
  11506. //
  11507. // * before: places tooltip to the left of the target node/widget, or to the right in
  11508. // the case of RTL scripts like Hebrew and Arabic
  11509. // * after: places tooltip to the right of the target node/widget, or to the left in
  11510. // the case of RTL scripts like Hebrew and Arabic
  11511. // * above: tooltip goes above target node
  11512. // * below: tooltip goes below target node
  11513. //
  11514. // The list is positions is tried, in order, until a position is found where the tooltip fits
  11515. // within the viewport.
  11516. //
  11517. // Be careful setting this parameter. A value of "above" may work fine until the user scrolls
  11518. // the screen so that there's no room above the target node. Nodes with drop downs, like
  11519. // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
  11520. // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
  11521. // is only room below (or above) the target node, but not both.
  11522. dijit.Tooltip.defaultPosition = ["after", "before"];
  11523. }
  11524. if(!dojo._hasResource["dojox.charting.action2d.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  11525. dojo._hasResource["dojox.charting.action2d.Tooltip"] = true;
  11526. dojo.provide("dojox.charting.action2d.Tooltip");
  11527. /*=====
  11528. dojo.declare("dojox.charting.action2d.__TooltipCtorArgs", dojox.charting.action2d.__BaseCtorArgs, {
  11529. // summary:
  11530. // Additional arguments for tooltip actions.
  11531. // text: Function?
  11532. // The function that produces the text to be shown within a tooltip. By default this will be
  11533. // set by the plot in question, by returning the value of the element.
  11534. text: null
  11535. });
  11536. =====*/
  11537. (function(){
  11538. var DEFAULT_TEXT = function(o){
  11539. var t = o.run && o.run.data && o.run.data[o.index];
  11540. if(t && typeof t != "number" && (t.tooltip || t.text)){
  11541. return t.tooltip || t.text;
  11542. }
  11543. if(o.element == "candlestick"){
  11544. return '<table cellpadding="1" cellspacing="0" border="0" style="font-size:0.9em;">'
  11545. + '<tr><td>Open:</td><td align="right"><strong>' + o.data.open + '</strong></td></tr>'
  11546. + '<tr><td>High:</td><td align="right"><strong>' + o.data.high + '</strong></td></tr>'
  11547. + '<tr><td>Low:</td><td align="right"><strong>' + o.data.low + '</strong></td></tr>'
  11548. + '<tr><td>Close:</td><td align="right"><strong>' + o.data.close + '</strong></td></tr>'
  11549. + (o.data.mid !== undefined ? '<tr><td>Mid:</td><td align="right"><strong>' + o.data.mid + '</strong></td></tr>' : '')
  11550. + '</table>';
  11551. }
  11552. return o.element == "bar" ? o.x : o.y;
  11553. };
  11554. var df = dojox.lang.functional, m = dojox.gfx.matrix, pi4 = Math.PI / 4, pi2 = Math.PI / 2;
  11555. dojo.declare("dojox.charting.action2d.Tooltip", dojox.charting.action2d.Base, {
  11556. // summary:
  11557. // Create an action on a plot where a tooltip is shown when hovering over an element.
  11558. // the data description block for the widget parser
  11559. defaultParams: {
  11560. text: DEFAULT_TEXT // the function to produce a tooltip from the object
  11561. },
  11562. optionalParams: {}, // no optional parameters
  11563. constructor: function(chart, plot, kwArgs){
  11564. // summary:
  11565. // Create the tooltip action and connect it to the plot.
  11566. // chart: dojox.charting.Chart2D
  11567. // The chart this action belongs to.
  11568. // plot: String?
  11569. // The plot this action is attached to. If not passed, "default" is assumed.
  11570. // kwArgs: dojox.charting.action2d.__TooltipCtorArgs?
  11571. // Optional keyword arguments object for setting parameters.
  11572. this.text = kwArgs && kwArgs.text ? kwArgs.text : DEFAULT_TEXT;
  11573. this.connect();
  11574. },
  11575. process: function(o){
  11576. // summary:
  11577. // Process the action on the given object.
  11578. // o: dojox.gfx.Shape
  11579. // The object on which to process the highlighting action.
  11580. if(o.type === "onplotreset" || o.type === "onmouseout"){
  11581. dijit.hideTooltip(this.aroundRect);
  11582. this.aroundRect = null;
  11583. if(o.type === "onplotreset"){
  11584. delete this.angles;
  11585. }
  11586. return;
  11587. }
  11588. if(!o.shape || o.type !== "onmouseover"){ return; }
  11589. // calculate relative coordinates and the position
  11590. var aroundRect = {type: "rect"}, position = ["after", "before"];
  11591. switch(o.element){
  11592. case "marker":
  11593. aroundRect.x = o.cx;
  11594. aroundRect.y = o.cy;
  11595. aroundRect.width = aroundRect.height = 1;
  11596. break;
  11597. case "circle":
  11598. aroundRect.x = o.cx - o.cr;
  11599. aroundRect.y = o.cy - o.cr;
  11600. aroundRect.width = aroundRect.height = 2 * o.cr;
  11601. break;
  11602. case "column":
  11603. position = ["above", "below"];
  11604. // intentional fall down
  11605. case "bar":
  11606. aroundRect = dojo.clone(o.shape.getShape());
  11607. break;
  11608. case "candlestick":
  11609. aroundRect.x = o.x;
  11610. aroundRect.y = o.y;
  11611. aroundRect.width = o.width;
  11612. aroundRect.height = o.height;
  11613. break;
  11614. default:
  11615. //case "slice":
  11616. if(!this.angles){
  11617. // calculate the running total of slice angles
  11618. if(typeof o.run.data[0] == "number"){
  11619. this.angles = df.map(df.scanl(o.run.data, "+", 0),
  11620. "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0));
  11621. }else{
  11622. this.angles = df.map(df.scanl(o.run.data, "a + b.y", 0),
  11623. "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0));
  11624. }
  11625. }
  11626. var startAngle = m._degToRad(o.plot.opt.startAngle),
  11627. angle = (this.angles[o.index] + this.angles[o.index + 1]) / 2 + startAngle;
  11628. aroundRect.x = o.cx + o.cr * Math.cos(angle);
  11629. aroundRect.y = o.cy + o.cr * Math.sin(angle);
  11630. aroundRect.width = aroundRect.height = 1;
  11631. // calculate the position
  11632. if(angle < pi4){
  11633. // do nothing: the position is right
  11634. }else if(angle < pi2 + pi4){
  11635. position = ["below", "above"];
  11636. }else if(angle < Math.PI + pi4){
  11637. position = ["before", "after"];
  11638. }else if(angle < 2 * Math.PI - pi4){
  11639. position = ["above", "below"];
  11640. }
  11641. /*
  11642. else{
  11643. // do nothing: the position is right
  11644. }
  11645. */
  11646. break;
  11647. }
  11648. // adjust relative coordinates to absolute, and remove fractions
  11649. var lt = dojo.coords(this.chart.node, true);
  11650. aroundRect.x += lt.x;
  11651. aroundRect.y += lt.y;
  11652. aroundRect.x = Math.round(aroundRect.x);
  11653. aroundRect.y = Math.round(aroundRect.y);
  11654. aroundRect.width = Math.ceil(aroundRect.width);
  11655. aroundRect.height = Math.ceil(aroundRect.height);
  11656. this.aroundRect = aroundRect;
  11657. var tooltip = this.text(o);
  11658. if(tooltip){
  11659. dijit.showTooltip(tooltip, this.aroundRect, position);
  11660. }
  11661. }
  11662. });
  11663. })();
  11664. }
  11665. if(!dojo._hasResource["dojox.charting.scaler.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  11666. dojo._hasResource["dojox.charting.scaler.common"] = true;
  11667. dojo.provide("dojox.charting.scaler.common");
  11668. (function(){
  11669. var eq = function(/*Number*/ a, /*Number*/ b){
  11670. // summary: compare two FP numbers for equality
  11671. return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b)); // Boolean
  11672. };
  11673. dojo.mixin(dojox.charting.scaler.common, {
  11674. findString: function(/*String*/ val, /*Array*/ text){
  11675. val = val.toLowerCase();
  11676. for(var i = 0; i < text.length; ++i){
  11677. if(val == text[i]){ return true; }
  11678. }
  11679. return false;
  11680. },
  11681. getNumericLabel: function(/*Number*/ number, /*Number*/ precision, /*Object*/ kwArgs){
  11682. var def = "";
  11683. if(dojo.number){
  11684. def = (kwArgs.fixed ? dojo.number.format(number, {places : precision < 0 ? -precision : 0}) :
  11685. dojo.number.format(number)) || "";
  11686. }else{
  11687. def = kwArgs.fixed ? number.toFixed(precision < 0 ? -precision : 0) : number.toString();
  11688. }
  11689. if(kwArgs.labelFunc){
  11690. var r = kwArgs.labelFunc(def, number, precision);
  11691. if(r){ return r; }
  11692. // else fall through to the regular labels search
  11693. }
  11694. if(kwArgs.labels){
  11695. // classic binary search
  11696. var l = kwArgs.labels, lo = 0, hi = l.length;
  11697. while(lo < hi){
  11698. var mid = Math.floor((lo + hi) / 2), val = l[mid].value;
  11699. if(val < number){
  11700. lo = mid + 1;
  11701. }else{
  11702. hi = mid;
  11703. }
  11704. }
  11705. // lets take into account FP errors
  11706. if(lo < l.length && eq(l[lo].value, number)){
  11707. return l[lo].text;
  11708. }
  11709. --lo;
  11710. if(lo >= 0 && lo < l.length && eq(l[lo].value, number)){
  11711. return l[lo].text;
  11712. }
  11713. lo += 2;
  11714. if(lo < l.length && eq(l[lo].value, number)){
  11715. return l[lo].text;
  11716. }
  11717. // otherwise we will produce a number
  11718. }
  11719. return def;
  11720. }
  11721. });
  11722. })();
  11723. }
  11724. if(!dojo._hasResource["dojox.charting.scaler.linear"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  11725. dojo._hasResource["dojox.charting.scaler.linear"] = true;
  11726. dojo.provide("dojox.charting.scaler.linear");
  11727. (function(){
  11728. var deltaLimit = 3, // pixels
  11729. dc = dojox.charting, dcs = dc.scaler, dcsc = dcs.common,
  11730. findString = dcsc.findString,
  11731. getLabel = dcsc.getNumericLabel;
  11732. var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){
  11733. kwArgs = dojo.delegate(kwArgs);
  11734. if(!majorTick){
  11735. if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; }
  11736. if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; }
  11737. }
  11738. if(!minorTick){
  11739. if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; }
  11740. if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; }
  11741. }
  11742. if(!microTick){
  11743. if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; }
  11744. if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; }
  11745. }
  11746. var lowerBound = findString(kwArgs.fixLower, ["major"]) ?
  11747. Math.floor(kwArgs.min / majorTick) * majorTick :
  11748. findString(kwArgs.fixLower, ["minor"]) ?
  11749. Math.floor(kwArgs.min / minorTick) * minorTick :
  11750. findString(kwArgs.fixLower, ["micro"]) ?
  11751. Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min,
  11752. upperBound = findString(kwArgs.fixUpper, ["major"]) ?
  11753. Math.ceil(kwArgs.max / majorTick) * majorTick :
  11754. findString(kwArgs.fixUpper, ["minor"]) ?
  11755. Math.ceil(kwArgs.max / minorTick) * minorTick :
  11756. findString(kwArgs.fixUpper, ["micro"]) ?
  11757. Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max;
  11758. if(kwArgs.useMin){ min = lowerBound; }
  11759. if(kwArgs.useMax){ max = upperBound; }
  11760. var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ?
  11761. min : Math.ceil(min / majorTick) * majorTick,
  11762. minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ?
  11763. min : Math.ceil(min / minorTick) * minorTick,
  11764. microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ?
  11765. min : Math.ceil(min / microTick) * microTick,
  11766. majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ?
  11767. Math.round((max - majorStart) / majorTick) :
  11768. Math.floor((max - majorStart) / majorTick)) + 1,
  11769. minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ?
  11770. Math.round((max - minorStart) / minorTick) :
  11771. Math.floor((max - minorStart) / minorTick)) + 1,
  11772. microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ?
  11773. Math.round((max - microStart) / microTick) :
  11774. Math.floor((max - microStart) / microTick)) + 1,
  11775. minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0,
  11776. microPerMinor = microTick ? Math.round(minorTick / microTick) : 0,
  11777. majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0,
  11778. minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0,
  11779. scale = span / (max - min);
  11780. if(!isFinite(scale)){ scale = 1; }
  11781. return {
  11782. bounds: {
  11783. lower: lowerBound,
  11784. upper: upperBound,
  11785. from: min,
  11786. to: max,
  11787. scale: scale,
  11788. span: span
  11789. },
  11790. major: {
  11791. tick: majorTick,
  11792. start: majorStart,
  11793. count: majorCount,
  11794. prec: majorPrecision
  11795. },
  11796. minor: {
  11797. tick: minorTick,
  11798. start: minorStart,
  11799. count: minorCount,
  11800. prec: minorPrecision
  11801. },
  11802. micro: {
  11803. tick: microTick,
  11804. start: microStart,
  11805. count: microCount,
  11806. prec: 0
  11807. },
  11808. minorPerMajor: minorPerMajor,
  11809. microPerMinor: microPerMinor,
  11810. scaler: dcs.linear
  11811. };
  11812. };
  11813. dojo.mixin(dojox.charting.scaler.linear, {
  11814. buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){
  11815. var h = {fixUpper: "none", fixLower: "none", natural: false};
  11816. if(kwArgs){
  11817. if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); }
  11818. if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); }
  11819. if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); }
  11820. }
  11821. // update bounds
  11822. if("min" in kwArgs){ min = kwArgs.min; }
  11823. if("max" in kwArgs){ max = kwArgs.max; }
  11824. if(kwArgs.includeZero){
  11825. if(min > 0){ min = 0; }
  11826. if(max < 0){ max = 0; }
  11827. }
  11828. h.min = min;
  11829. h.useMin = true;
  11830. h.max = max;
  11831. h.useMax = true;
  11832. if("from" in kwArgs){
  11833. min = kwArgs.from;
  11834. h.useMin = false;
  11835. }
  11836. if("to" in kwArgs){
  11837. max = kwArgs.to;
  11838. h.useMax = false;
  11839. }
  11840. // check for erroneous condition
  11841. if(max <= min){
  11842. return calcTicks(min, max, h, 0, 0, 0, span); // Object
  11843. }
  11844. var mag = Math.floor(Math.log(max - min) / Math.LN10),
  11845. major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag),
  11846. minor = 0, micro = 0, ticks;
  11847. // calculate minor ticks
  11848. if(kwArgs && ("minorTickStep" in kwArgs)){
  11849. minor = kwArgs.minorTickStep;
  11850. }else{
  11851. do{
  11852. minor = major / 10;
  11853. if(!h.natural || minor > 0.9){
  11854. ticks = calcTicks(min, max, h, major, minor, 0, span);
  11855. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  11856. }
  11857. minor = major / 5;
  11858. if(!h.natural || minor > 0.9){
  11859. ticks = calcTicks(min, max, h, major, minor, 0, span);
  11860. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  11861. }
  11862. minor = major / 2;
  11863. if(!h.natural || minor > 0.9){
  11864. ticks = calcTicks(min, max, h, major, minor, 0, span);
  11865. if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; }
  11866. }
  11867. return calcTicks(min, max, h, major, 0, 0, span); // Object
  11868. }while(false);
  11869. }
  11870. // calculate micro ticks
  11871. if(kwArgs && ("microTickStep" in kwArgs)){
  11872. micro = kwArgs.microTickStep;
  11873. ticks = calcTicks(min, max, h, major, minor, micro, span);
  11874. }else{
  11875. do{
  11876. micro = minor / 10;
  11877. if(!h.natural || micro > 0.9){
  11878. ticks = calcTicks(min, max, h, major, minor, micro, span);
  11879. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  11880. }
  11881. micro = minor / 5;
  11882. if(!h.natural || micro > 0.9){
  11883. ticks = calcTicks(min, max, h, major, minor, micro, span);
  11884. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  11885. }
  11886. micro = minor / 2;
  11887. if(!h.natural || micro > 0.9){
  11888. ticks = calcTicks(min, max, h, major, minor, micro, span);
  11889. if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; }
  11890. }
  11891. micro = 0;
  11892. }while(false);
  11893. }
  11894. return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object
  11895. },
  11896. buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){
  11897. var step, next, tick,
  11898. nextMajor = scaler.major.start,
  11899. nextMinor = scaler.minor.start,
  11900. nextMicro = scaler.micro.start;
  11901. if(kwArgs.microTicks && scaler.micro.tick){
  11902. step = scaler.micro.tick, next = nextMicro;
  11903. }else if(kwArgs.minorTicks && scaler.minor.tick){
  11904. step = scaler.minor.tick, next = nextMinor;
  11905. }else if(scaler.major.tick){
  11906. step = scaler.major.tick, next = nextMajor;
  11907. }else{
  11908. // no ticks
  11909. return null;
  11910. }
  11911. // make sure that we have finite bounds
  11912. var revScale = 1 / scaler.bounds.scale;
  11913. if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) ||
  11914. step <= 0 || isNaN(step) || !isFinite(step)){
  11915. // no ticks
  11916. return null;
  11917. }
  11918. // loop over all ticks
  11919. var majorTicks = [], minorTicks = [], microTicks = [];
  11920. while(next <= scaler.bounds.to + revScale){
  11921. if(Math.abs(nextMajor - next) < step / 2){
  11922. // major tick
  11923. tick = {value: nextMajor};
  11924. if(kwArgs.majorLabels){
  11925. tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs);
  11926. }
  11927. majorTicks.push(tick);
  11928. nextMajor += scaler.major.tick;
  11929. nextMinor += scaler.minor.tick;
  11930. nextMicro += scaler.micro.tick;
  11931. }else if(Math.abs(nextMinor - next) < step / 2){
  11932. // minor tick
  11933. if(kwArgs.minorTicks){
  11934. tick = {value: nextMinor};
  11935. if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){
  11936. tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs);
  11937. }
  11938. minorTicks.push(tick);
  11939. }
  11940. nextMinor += scaler.minor.tick;
  11941. nextMicro += scaler.micro.tick;
  11942. }else{
  11943. // micro tick
  11944. if(kwArgs.microTicks){
  11945. microTicks.push({value: nextMicro});
  11946. }
  11947. nextMicro += scaler.micro.tick;
  11948. }
  11949. next += step;
  11950. }
  11951. return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object
  11952. },
  11953. getTransformerFromModel: function(/*Object*/ scaler){
  11954. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  11955. return function(x){ return (x - offset) * scale; }; // Function
  11956. },
  11957. getTransformerFromPlot: function(/*Object*/ scaler){
  11958. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  11959. return function(x){ return x / scale + offset; }; // Function
  11960. }
  11961. });
  11962. })();
  11963. }
  11964. if(!dojo._hasResource["dojox.charting.axis2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  11965. dojo._hasResource["dojox.charting.axis2d.Base"] = true;
  11966. dojo.provide("dojox.charting.axis2d.Base");
  11967. dojo.declare("dojox.charting.axis2d.Base", dojox.charting.Element, {
  11968. // summary:
  11969. // The base class for any axis. This is more of an interface/API
  11970. // definition than anything else; see dojox.charting.axis2d.Default
  11971. // for more details.
  11972. constructor: function(chart, kwArgs){
  11973. // summary:
  11974. // Return a new base axis.
  11975. // chart: dojox.charting.Chart2D
  11976. // The chart this axis belongs to.
  11977. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  11978. // An optional arguments object to define the axis parameters.
  11979. this.vertical = kwArgs && kwArgs.vertical;
  11980. },
  11981. clear: function(){
  11982. // summary:
  11983. // Stub function for clearing the axis.
  11984. // returns: dojox.charting.axis2d.Base
  11985. // A reference to the axis for functional chaining.
  11986. return this; // dojox.charting.axis2d.Base
  11987. },
  11988. initialized: function(){
  11989. // summary:
  11990. // Return a flag as to whether or not this axis has been initialized.
  11991. // returns: Boolean
  11992. // If the axis is initialized or not.
  11993. return false; // Boolean
  11994. },
  11995. calculate: function(min, max, span){
  11996. // summary:
  11997. // Stub function to run the calcuations needed for drawing this axis.
  11998. // returns: dojox.charting.axis2d.Base
  11999. // A reference to the axis for functional chaining.
  12000. return this; // dojox.charting.axis2d.Base
  12001. },
  12002. getScaler: function(){
  12003. // summary:
  12004. // A stub function to return the scaler object created during calculate.
  12005. // returns: Object
  12006. // The scaler object (see dojox.charting.scaler.linear for more information)
  12007. return null; // Object
  12008. },
  12009. getTicks: function(){
  12010. // summary:
  12011. // A stub function to return the object that helps define how ticks are rendered.
  12012. // returns: Object
  12013. // The ticks object.
  12014. return null; // Object
  12015. },
  12016. getOffsets: function(){
  12017. // summary:
  12018. // A stub function to return any offsets needed for axis and series rendering.
  12019. // returns: Object
  12020. // An object of the form { l, r, t, b }.
  12021. return {l: 0, r: 0, t: 0, b: 0}; // Object
  12022. },
  12023. render: function(dim, offsets){
  12024. // summary:
  12025. // Stub function to render this axis.
  12026. // returns: dojox.charting.axis2d.Base
  12027. // A reference to the axis for functional chaining.
  12028. this.dirty = false;
  12029. return this; // dojox.charting.axis2d.Base
  12030. }
  12031. });
  12032. }
  12033. if(!dojo._hasResource["dojox.charting.axis2d.Invisible"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12034. dojo._hasResource["dojox.charting.axis2d.Invisible"] = true;
  12035. dojo.provide("dojox.charting.axis2d.Invisible");
  12036. (function(){
  12037. var dc = dojox.charting,
  12038. df = dojox.lang.functional,
  12039. du = dojox.lang.utils,
  12040. g = dojox.gfx,
  12041. lin = dc.scaler.linear,
  12042. merge = du.merge,
  12043. labelGap = 4, // in pixels
  12044. centerAnchorLimit = 45; // in degrees
  12045. dojo.declare("dojox.charting.axis2d.Invisible", dojox.charting.axis2d.Base, {
  12046. // summary:
  12047. // The default axis object used in dojox.charting. See dojox.charting.Chart2D.addAxis for details.
  12048. //
  12049. // defaultParams: Object
  12050. // The default parameters used to define any axis.
  12051. // optionalParams: Object
  12052. // Any optional parameters needed to define an axis.
  12053. /*
  12054. // TODO: the documentation tools need these to be pre-defined in order to pick them up
  12055. // correctly, but the code here is partially predicated on whether or not the properties
  12056. // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT
  12057. // opt: Object
  12058. // The actual options used to define this axis, created at initialization.
  12059. // scalar: Object
  12060. // The calculated helper object to tell charts how to draw an axis and any data.
  12061. // ticks: Object
  12062. // The calculated tick object that helps a chart draw the scaling on an axis.
  12063. // dirty: Boolean
  12064. // The state of the axis (whether it needs to be redrawn or not)
  12065. // scale: Number
  12066. // The current scale of the axis.
  12067. // offset: Number
  12068. // The current offset of the axis.
  12069. opt: null,
  12070. scalar: null,
  12071. ticks: null,
  12072. dirty: true,
  12073. scale: 1,
  12074. offset: 0,
  12075. */
  12076. defaultParams: {
  12077. vertical: false, // true for vertical axis
  12078. fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none"
  12079. fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none"
  12080. natural: false, // all tick marks should be made on natural numbers
  12081. leftBottom: true, // position of the axis, used with "vertical"
  12082. includeZero: false, // 0 should be included
  12083. fixed: true, // all labels are fixed numbers
  12084. majorLabels: true, // draw major labels
  12085. minorTicks: true, // draw minor ticks
  12086. minorLabels: true, // draw minor labels
  12087. microTicks: false, // draw micro ticks
  12088. rotation: 0 // label rotation angle in degrees
  12089. },
  12090. optionalParams: {
  12091. min: 0, // minimal value on this axis
  12092. max: 1, // maximal value on this axis
  12093. from: 0, // visible from this value
  12094. to: 1, // visible to this value
  12095. majorTickStep: 4, // major tick step
  12096. minorTickStep: 2, // minor tick step
  12097. microTickStep: 1, // micro tick step
  12098. labels: [], // array of labels for major ticks
  12099. // with corresponding numeric values
  12100. // ordered by values
  12101. labelFunc: null, // function to compute label values
  12102. maxLabelSize: 0, // size in px. For use with labelFunc
  12103. maxLabelCharCount: 0, // size in word count.
  12104. trailingSymbol: null
  12105. // TODO: add support for minRange!
  12106. // minRange: 1, // smallest distance from min allowed on the axis
  12107. },
  12108. constructor: function(chart, kwArgs){
  12109. // summary:
  12110. // The constructor for an axis.
  12111. // chart: dojox.charting.Chart2D
  12112. // The chart the axis belongs to.
  12113. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  12114. // Any optional keyword arguments to be used to define this axis.
  12115. this.opt = dojo.clone(this.defaultParams);
  12116. du.updateWithObject(this.opt, kwArgs);
  12117. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  12118. },
  12119. dependOnData: function(){
  12120. // summary:
  12121. // Find out whether or not the axis options depend on the data in the axis.
  12122. return !("min" in this.opt) || !("max" in this.opt); // Boolean
  12123. },
  12124. clear: function(){
  12125. // summary:
  12126. // Clear out all calculated properties on this axis;
  12127. // returns: dojox.charting.axis2d.Default
  12128. // The reference to the axis for functional chaining.
  12129. delete this.scaler;
  12130. delete this.ticks;
  12131. this.dirty = true;
  12132. return this; // dojox.charting.axis2d.Default
  12133. },
  12134. initialized: function(){
  12135. // summary:
  12136. // Finds out if this axis has been initialized or not.
  12137. // returns: Boolean
  12138. // Whether a scaler has been calculated and if the axis is not dirty.
  12139. return "scaler" in this && !(this.dirty && this.dependOnData());
  12140. },
  12141. setWindow: function(scale, offset){
  12142. // summary:
  12143. // Set the drawing "window" for the axis.
  12144. // scale: Number
  12145. // The new scale for the axis.
  12146. // offset: Number
  12147. // The new offset for the axis.
  12148. // returns: dojox.charting.axis2d.Default
  12149. // The reference to the axis for functional chaining.
  12150. this.scale = scale;
  12151. this.offset = offset;
  12152. return this.clear(); // dojox.charting.axis2d.Default
  12153. },
  12154. getWindowScale: function(){
  12155. // summary:
  12156. // Get the current windowing scale of the axis.
  12157. return "scale" in this ? this.scale : 1; // Number
  12158. },
  12159. getWindowOffset: function(){
  12160. // summary:
  12161. // Get the current windowing offset for the axis.
  12162. return "offset" in this ? this.offset : 0; // Number
  12163. },
  12164. _groupLabelWidth: function(labels, font, wcLimit){
  12165. if(!labels.length){
  12166. return 0;
  12167. }
  12168. if(dojo.isObject(labels[0])){
  12169. labels = df.map(labels, function(label){ return label.text; });
  12170. }
  12171. if (wcLimit) {
  12172. labels = df.map(labels, function(label){
  12173. return dojo.trim(label).length == 0 ? "" : label.substring(0, wcLimit) + this.trailingSymbol;
  12174. }, this);
  12175. }
  12176. var s = labels.join("<br>");
  12177. return dojox.gfx._base._getTextBox(s, {font: font}).w || 0;
  12178. },
  12179. calculate: function(min, max, span, labels){
  12180. // summary:
  12181. // Perform all calculations needed to render this axis.
  12182. // min: Number
  12183. // The smallest value represented on this axis.
  12184. // max: Number
  12185. // The largest value represented on this axis.
  12186. // span: Number
  12187. // The span in pixels over which axis calculations are made.
  12188. // labels: String[]
  12189. // Optional list of labels.
  12190. // returns: dojox.charting.axis2d.Default
  12191. // The reference to the axis for functional chaining.
  12192. if(this.initialized()){
  12193. return this;
  12194. }
  12195. var o = this.opt;
  12196. this.labels = "labels" in o ? o.labels : labels;
  12197. this.scaler = lin.buildScaler(min, max, span, o);
  12198. var tsb = this.scaler.bounds;
  12199. if("scale" in this){
  12200. // calculate new range
  12201. o.from = tsb.lower + this.offset;
  12202. o.to = (tsb.upper - tsb.lower) / this.scale + o.from;
  12203. // make sure that bounds are correct
  12204. if( !isFinite(o.from) ||
  12205. isNaN(o.from) ||
  12206. !isFinite(o.to) ||
  12207. isNaN(o.to) ||
  12208. o.to - o.from >= tsb.upper - tsb.lower
  12209. ){
  12210. // any error --- remove from/to bounds
  12211. delete o.from;
  12212. delete o.to;
  12213. delete this.scale;
  12214. delete this.offset;
  12215. }else{
  12216. // shift the window, if we are out of bounds
  12217. if(o.from < tsb.lower){
  12218. o.to += tsb.lower - o.from;
  12219. o.from = tsb.lower;
  12220. }else if(o.to > tsb.upper){
  12221. o.from += tsb.upper - o.to;
  12222. o.to = tsb.upper;
  12223. }
  12224. // update the offset
  12225. this.offset = o.from - tsb.lower;
  12226. }
  12227. // re-calculate the scaler
  12228. this.scaler = lin.buildScaler(min, max, span, o);
  12229. tsb = this.scaler.bounds;
  12230. // cleanup
  12231. if(this.scale == 1 && this.offset == 0){
  12232. delete this.scale;
  12233. delete this.offset;
  12234. }
  12235. }
  12236. var ta = this.chart.theme.axis, labelWidth = 0, rotation = o.rotation % 360,
  12237. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  12238. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  12239. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  12240. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  12241. sinr = Math.abs(Math.sin(rotation * Math.PI / 180));
  12242. if(rotation < 0){
  12243. rotation += 360;
  12244. }
  12245. if(size){
  12246. if(this.vertical ? rotation != 0 && rotation != 180 : rotation != 90 && rotation != 270){
  12247. // we need width of all labels
  12248. if(this.labels){
  12249. labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount);
  12250. }else{
  12251. var labelLength = Math.ceil(
  12252. Math.log(
  12253. Math.max(
  12254. Math.abs(tsb.from),
  12255. Math.abs(tsb.to)
  12256. )
  12257. ) / Math.LN10
  12258. ),
  12259. t = [];
  12260. if(tsb.from < 0 || tsb.to < 0){
  12261. t.push("-");
  12262. }
  12263. t.push(dojo.string.rep("9", labelLength));
  12264. var precision = Math.floor(
  12265. Math.log( tsb.to - tsb.from ) / Math.LN10
  12266. );
  12267. if(precision > 0){
  12268. t.push(".");
  12269. t.push(dojo.string.rep("9", precision));
  12270. }
  12271. labelWidth = dojox.gfx._base._getTextBox(
  12272. t.join(""),
  12273. { font: taFont }
  12274. ).w;
  12275. }
  12276. labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth;
  12277. }else{
  12278. labelWidth = size;
  12279. }
  12280. switch(rotation){
  12281. case 0:
  12282. case 90:
  12283. case 180:
  12284. case 270:
  12285. // trivial cases: use labelWidth
  12286. break;
  12287. default:
  12288. // rotated labels
  12289. var gap1 = Math.sqrt(labelWidth * labelWidth + size * size), // short labels
  12290. gap2 = this.vertical ? size * cosr + labelWidth * sinr : labelWidth * cosr + size * sinr; // slanted labels
  12291. labelWidth = Math.min(gap1, gap2);
  12292. break;
  12293. }
  12294. }
  12295. this.scaler.minMinorStep = labelWidth + labelGap;
  12296. this.ticks = lin.buildTicks(this.scaler, o);
  12297. return this; // dojox.charting.axis2d.Default
  12298. },
  12299. getScaler: function(){
  12300. // summary:
  12301. // Get the pre-calculated scaler object.
  12302. return this.scaler; // Object
  12303. },
  12304. getTicks: function(){
  12305. // summary:
  12306. // Get the pre-calculated ticks object.
  12307. return this.ticks; // Object
  12308. }
  12309. });
  12310. })();
  12311. }
  12312. if(!dojo._hasResource["dojox.charting.axis2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12313. dojo._hasResource["dojox.charting.axis2d.Default"] = true;
  12314. dojo.provide("dojox.charting.axis2d.Default");
  12315. /*=====
  12316. dojox.charting.axis2d.__AxisCtorArgs = function(
  12317. vertical, fixUpper, fixLower, natural, leftBottom,
  12318. includeZero, fixed, majorLabels, minorTicks, minorLabels, microTicks, htmlLabels,
  12319. min, max, from, to, majorTickStep, minorTickStep, microTickStep,
  12320. labels, labelFunc, maxLabelSize,
  12321. stroke, majorTick, minorTick, microTick, tick,
  12322. font, fontColor
  12323. ){
  12324. // summary:
  12325. // Optional arguments used in the definition of an axis.
  12326. //
  12327. // vertical: Boolean?
  12328. // A flag that says whether an axis is vertical (i.e. y axis) or horizontal. Default is false (horizontal).
  12329. // fixUpper: String?
  12330. // Align the greatest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none".
  12331. // fixLower: String?
  12332. // Align the smallest value on the axis with the specified tick level. Options are "major", "minor", "micro", or "none". Defaults to "none".
  12333. // natural: Boolean?
  12334. // Ensure tick marks are made on "natural" numbers. Defaults to false.
  12335. // leftBottom: Boolean?
  12336. // The position of a vertical axis; if true, will be placed against the left-bottom corner of the chart. Defaults to true.
  12337. // includeZero: Boolean?
  12338. // Include 0 on the axis rendering. Default is false.
  12339. // fixed: Boolean?
  12340. // Force all axis labels to be fixed numbers. Default is true.
  12341. // majorLabels: Boolean?
  12342. // Flag to draw all labels at major ticks. Default is true.
  12343. // minorTicks: Boolean?
  12344. // Flag to draw minor ticks on an axis. Default is true.
  12345. // minorLabels: Boolean?
  12346. // Flag to draw labels on minor ticks. Default is true.
  12347. // microTicks: Boolean?
  12348. // Flag to draw micro ticks on an axis. Default is false.
  12349. // htmlLabels: Boolean?
  12350. // Flag to use HTML (as opposed to the native vector graphics engine) to draw labels. Default is true.
  12351. // min: Number?
  12352. // The smallest value on an axis. Default is 0.
  12353. // max: Number?
  12354. // The largest value on an axis. Default is 1.
  12355. // from: Number?
  12356. // Force the chart to render data visible from this value. Default is 0.
  12357. // to: Number?
  12358. // Force the chart to render data visible to this value. Default is 1.
  12359. // majorTickStep: Number?
  12360. // The amount to skip before a major tick is drawn. Default is 4.
  12361. // minorTickStep: Number?
  12362. // The amount to skip before a minor tick is drawn. Default is 2.
  12363. // microTickStep: Number?
  12364. // The amount to skip before a micro tick is drawn. Default is 1.
  12365. // labels: Object[]?
  12366. // An array of labels for major ticks, with corresponding numeric values, ordered by value.
  12367. // labelFunc: Function?
  12368. // An optional function used to compute label values.
  12369. // maxLabelSize: Number?
  12370. // The maximum size, in pixels, for a label. To be used with the optional label function.
  12371. // stroke: dojox.gfx.Stroke?
  12372. // An optional stroke to be used for drawing an axis.
  12373. // majorTick: Object?
  12374. // An object containing a dojox.gfx.Stroke, and a length (number) for a major tick.
  12375. // minorTick: Object?
  12376. // An object containing a dojox.gfx.Stroke, and a length (number) for a minor tick.
  12377. // microTick: Object?
  12378. // An object containing a dojox.gfx.Stroke, and a length (number) for a micro tick.
  12379. // tick: Object?
  12380. // An object containing a dojox.gfx.Stroke, and a length (number) for a tick.
  12381. // font: String?
  12382. // An optional font definition (as used in the CSS font property) for labels.
  12383. // fontColor: String|dojo.Color?
  12384. // An optional color to be used in drawing labels.
  12385. this.vertical = vertical;
  12386. this.fixUpper = fixUpper;
  12387. this.fixLower = fixLower;
  12388. this.natural = natural;
  12389. this.leftBottom = leftBottom;
  12390. this.includeZero = includeZero;
  12391. this.fixed = fixed;
  12392. this.majorLabels = majorLabels;
  12393. this.minorTicks = minorTicks;
  12394. this.minorLabels = minorLabels;
  12395. this.microTicks = microTicks;
  12396. this.htmlLabels = htmlLabels;
  12397. this.min = min;
  12398. this.max = max;
  12399. this.from = from;
  12400. this.to = to;
  12401. this.majorTickStep = majorTickStep;
  12402. this.minorTickStep = minorTickStep;
  12403. this.microTickStep = microTickStep;
  12404. this.labels = labels;
  12405. this.labelFunc = labelFunc;
  12406. this.maxLabelSize = maxLabelSize;
  12407. this.stroke = stroke;
  12408. this.majorTick = majorTick;
  12409. this.minorTick = minorTick;
  12410. this.microTick = microTick;
  12411. this.tick = tick;
  12412. this.font = font;
  12413. this.fontColor = fontColor;
  12414. }
  12415. =====*/
  12416. (function(){
  12417. var dc = dojox.charting,
  12418. du = dojox.lang.utils,
  12419. g = dojox.gfx,
  12420. lin = dc.scaler.linear,
  12421. labelGap = 4, // in pixels
  12422. centerAnchorLimit = 45; // in degrees
  12423. dojo.declare("dojox.charting.axis2d.Default", dojox.charting.axis2d.Invisible, {
  12424. // summary:
  12425. // The default axis object used in dojox.charting. See dojox.charting.Chart.addAxis for details.
  12426. //
  12427. // defaultParams: Object
  12428. // The default parameters used to define any axis.
  12429. // optionalParams: Object
  12430. // Any optional parameters needed to define an axis.
  12431. /*
  12432. // TODO: the documentation tools need these to be pre-defined in order to pick them up
  12433. // correctly, but the code here is partially predicated on whether or not the properties
  12434. // actually exist. For now, we will leave these undocumented but in the code for later. -- TRT
  12435. // opt: Object
  12436. // The actual options used to define this axis, created at initialization.
  12437. // scalar: Object
  12438. // The calculated helper object to tell charts how to draw an axis and any data.
  12439. // ticks: Object
  12440. // The calculated tick object that helps a chart draw the scaling on an axis.
  12441. // dirty: Boolean
  12442. // The state of the axis (whether it needs to be redrawn or not)
  12443. // scale: Number
  12444. // The current scale of the axis.
  12445. // offset: Number
  12446. // The current offset of the axis.
  12447. opt: null,
  12448. scalar: null,
  12449. ticks: null,
  12450. dirty: true,
  12451. scale: 1,
  12452. offset: 0,
  12453. */
  12454. defaultParams: {
  12455. vertical: false, // true for vertical axis
  12456. fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none"
  12457. fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none"
  12458. natural: false, // all tick marks should be made on natural numbers
  12459. leftBottom: true, // position of the axis, used with "vertical"
  12460. includeZero: false, // 0 should be included
  12461. fixed: true, // all labels are fixed numbers
  12462. majorLabels: true, // draw major labels
  12463. minorTicks: true, // draw minor ticks
  12464. minorLabels: true, // draw minor labels
  12465. microTicks: false, // draw micro ticks
  12466. rotation: 0, // label rotation angle in degrees
  12467. htmlLabels: true // use HTML to draw labels
  12468. },
  12469. optionalParams: {
  12470. min: 0, // minimal value on this axis
  12471. max: 1, // maximal value on this axis
  12472. from: 0, // visible from this value
  12473. to: 1, // visible to this value
  12474. majorTickStep: 4, // major tick step
  12475. minorTickStep: 2, // minor tick step
  12476. microTickStep: 1, // micro tick step
  12477. labels: [], // array of labels for major ticks
  12478. // with corresponding numeric values
  12479. // ordered by values
  12480. labelFunc: null, // function to compute label values
  12481. maxLabelSize: 0, // size in px. For use with labelFunc
  12482. maxLabelCharCount: 0, // size in word count.
  12483. trailingSymbol: null,
  12484. // TODO: add support for minRange!
  12485. // minRange: 1, // smallest distance from min allowed on the axis
  12486. // theme components
  12487. stroke: {}, // stroke for an axis
  12488. majorTick: {}, // stroke + length for a tick
  12489. minorTick: {}, // stroke + length for a tick
  12490. microTick: {}, // stroke + length for a tick
  12491. tick: {}, // stroke + length for a tick
  12492. font: "", // font for labels
  12493. fontColor: "", // color for labels as a string
  12494. title: "", // axis title
  12495. titleGap: 0, // gap between axis title and axis label
  12496. titleFont: "", // axis title font
  12497. titleFontColor: "", // axis title font color
  12498. titleOrientation: "" // "axis" means the title facing the axis, "away" means facing away
  12499. },
  12500. constructor: function(chart, kwArgs){
  12501. // summary:
  12502. // The constructor for an axis.
  12503. // chart: dojox.charting.Chart2D
  12504. // The chart the axis belongs to.
  12505. // kwArgs: dojox.charting.axis2d.__AxisCtorArgs?
  12506. // Any optional keyword arguments to be used to define this axis.
  12507. this.opt = dojo.clone(this.defaultParams);
  12508. du.updateWithObject(this.opt, kwArgs);
  12509. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  12510. },
  12511. getOffsets: function(){
  12512. // summary:
  12513. // Get the physical offset values for this axis (used in drawing data series).
  12514. // returns: Object
  12515. // The calculated offsets in the form of { l, r, t, b } (left, right, top, bottom).
  12516. var s = this.scaler, offsets = { l: 0, r: 0, t: 0, b: 0 };
  12517. if(!s){
  12518. return offsets;
  12519. }
  12520. var o = this.opt, labelWidth = 0, a, b, c, d,
  12521. gl = dc.scaler.common.getNumericLabel,
  12522. offset = 0, ma = s.major, mi = s.minor,
  12523. ta = this.chart.theme.axis,
  12524. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  12525. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  12526. taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont),
  12527. taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15,
  12528. taMajorTick = this.chart.theme.getTick("major", o),
  12529. taMinorTick = this.chart.theme.getTick("minor", o),
  12530. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  12531. tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0,
  12532. rotation = o.rotation % 360, leftBottom = o.leftBottom,
  12533. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  12534. sinr = Math.abs(Math.sin(rotation * Math.PI / 180));
  12535. this.trailingSymbol = (o.trailingSymbol === undefined || o.trailingSymbol === null) ? this.trailingSymbol : o.trailingSymbol;
  12536. if(rotation < 0){
  12537. rotation += 360;
  12538. }
  12539. if(size){
  12540. // we need width of all labels
  12541. if(this.labels){
  12542. labelWidth = this._groupLabelWidth(this.labels, taFont, o.maxLabelCharCount);
  12543. }else{
  12544. labelWidth = this._groupLabelWidth([
  12545. gl(ma.start, ma.prec, o),
  12546. gl(ma.start + ma.count * ma.tick, ma.prec, o),
  12547. gl(mi.start, mi.prec, o),
  12548. gl(mi.start + mi.count * mi.tick, mi.prec, o)
  12549. ], taFont, o.maxLabelCharCount);
  12550. }
  12551. labelWidth = o.maxLabelSize ? Math.min(o.maxLabelSize, labelWidth) : labelWidth;
  12552. if(this.vertical){
  12553. var side = leftBottom ? "l" : "r";
  12554. switch(rotation){
  12555. case 0:
  12556. case 180:
  12557. offsets[side] = labelWidth;
  12558. offsets.t = offsets.b = size / 2;
  12559. break;
  12560. case 90:
  12561. case 270:
  12562. offsets[side] = size;
  12563. offsets.t = offsets.b = labelWidth / 2;
  12564. break;
  12565. default:
  12566. if(rotation <= centerAnchorLimit || (180 < rotation && rotation <= (180 + centerAnchorLimit))){
  12567. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  12568. offsets[leftBottom ? "t" : "b"] = size * cosr / 2 + labelWidth * sinr;
  12569. offsets[leftBottom ? "b" : "t"] = size * cosr / 2;
  12570. }else if(rotation > (360 - centerAnchorLimit) || (180 > rotation && rotation > (180 - centerAnchorLimit))){
  12571. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  12572. offsets[leftBottom ? "b" : "t"] = size * cosr / 2 + labelWidth * sinr;
  12573. offsets[leftBottom ? "t" : "b"] = size * cosr / 2;
  12574. }else if(rotation < 90 || (180 < rotation && rotation < 270)){
  12575. offsets[side] = size * sinr + labelWidth * cosr;
  12576. offsets[leftBottom ? "t" : "b"] = size * cosr + labelWidth * sinr;
  12577. }else{
  12578. offsets[side] = size * sinr + labelWidth * cosr;
  12579. offsets[leftBottom ? "b" : "t"] = size * cosr + labelWidth * sinr;
  12580. }
  12581. break;
  12582. }
  12583. offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0);
  12584. }else{
  12585. var side = leftBottom ? "b" : "t";
  12586. switch(rotation){
  12587. case 0:
  12588. case 180:
  12589. offsets[side] = size;
  12590. offsets.l = offsets.r = labelWidth / 2;
  12591. break;
  12592. case 90:
  12593. case 270:
  12594. offsets[side] = labelWidth;
  12595. offsets.l = offsets.r = size / 2;
  12596. break;
  12597. default:
  12598. if((90 - centerAnchorLimit) <= rotation && rotation <= 90 || (270 - centerAnchorLimit) <= rotation && rotation <= 270){
  12599. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  12600. offsets[leftBottom ? "r" : "l"] = size * cosr / 2 + labelWidth * sinr;
  12601. offsets[leftBottom ? "l" : "r"] = size * cosr / 2;
  12602. }else if(90 <= rotation && rotation <= (90 + centerAnchorLimit) || 270 <= rotation && rotation <= (270 + centerAnchorLimit)){
  12603. offsets[side] = size * sinr / 2 + labelWidth * cosr;
  12604. offsets[leftBottom ? "l" : "r"] = size * cosr / 2 + labelWidth * sinr;
  12605. offsets[leftBottom ? "r" : "l"] = size * cosr / 2;
  12606. }else if(rotation < centerAnchorLimit || (180 < rotation && rotation < (180 - centerAnchorLimit))){
  12607. offsets[side] = size * sinr + labelWidth * cosr;
  12608. offsets[leftBottom ? "r" : "l"] = size * cosr + labelWidth * sinr;
  12609. }else{
  12610. offsets[side] = size * sinr + labelWidth * cosr;
  12611. offsets[leftBottom ? "l" : "r"] = size * cosr + labelWidth * sinr;
  12612. }
  12613. break;
  12614. }
  12615. offsets[side] += labelGap + Math.max(taMajorTick.length, taMinorTick.length) + (o.title ? (tsize + taTitleGap) : 0);
  12616. }
  12617. }
  12618. if(labelWidth){
  12619. this._cachedLabelWidth = labelWidth;
  12620. }
  12621. return offsets; // Object
  12622. },
  12623. render: function(dim, offsets){
  12624. // summary:
  12625. // Render/draw the axis.
  12626. // dim: Object
  12627. // An object of the form { width, height}.
  12628. // offsets: Object
  12629. // An object of the form { l, r, t, b }.
  12630. // returns: dojox.charting.axis2d.Default
  12631. // The reference to the axis for functional chaining.
  12632. if(!this.dirty){
  12633. return this; // dojox.charting.axis2d.Default
  12634. }
  12635. // prepare variable
  12636. var o = this.opt, ta = this.chart.theme.axis, leftBottom = o.leftBottom, rotation = o.rotation % 360,
  12637. start, stop, titlePos, titleRotation=0, titleOffset, axisVector, tickVector, anchorOffset, labelOffset, labelAlign,
  12638. // TODO: we use one font --- of major tick, we need to use major and minor fonts
  12639. taFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font),
  12640. taTitleFont = o.titleFont || (ta.tick && ta.tick.titleFont),
  12641. // TODO: we use one font color --- we need to use different colors
  12642. taFontColor = o.fontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "black",
  12643. taTitleFontColor = o.titleFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
  12644. taTitleGap = (o.titleGap==0) ? 0 : o.titleGap || (ta.tick && ta.tick.titleGap) || 15,
  12645. taTitleOrientation = o.titleOrientation || (ta.tick && ta.tick.titleOrientation) || "axis",
  12646. taMajorTick = this.chart.theme.getTick("major", o),
  12647. taMinorTick = this.chart.theme.getTick("minor", o),
  12648. taMicroTick = this.chart.theme.getTick("micro", o),
  12649. tickSize = Math.max(taMajorTick.length, taMinorTick.length, taMicroTick.length),
  12650. taStroke = "stroke" in o ? o.stroke : ta.stroke,
  12651. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  12652. cosr = Math.abs(Math.cos(rotation * Math.PI / 180)),
  12653. sinr = Math.abs(Math.sin(rotation * Math.PI / 180)),
  12654. tsize = taTitleFont ? g.normalizedLength(g.splitFontString(taTitleFont).size) : 0;
  12655. if(rotation < 0){
  12656. rotation += 360;
  12657. }
  12658. if(this.vertical){
  12659. start = {y: dim.height - offsets.b};
  12660. stop = {y: offsets.t};
  12661. titlePos = {y: (dim.height - offsets.b + offsets.t)/2};
  12662. titleOffset = size * sinr + (this._cachedLabelWidth || 0) * cosr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap;
  12663. axisVector = {x: 0, y: -1};
  12664. labelOffset = {x: 0, y: 0};
  12665. tickVector = {x: 1, y: 0};
  12666. anchorOffset = {x: labelGap, y: 0};
  12667. switch(rotation){
  12668. case 0:
  12669. labelAlign = "end";
  12670. labelOffset.y = size * 0.4;
  12671. break;
  12672. case 90:
  12673. labelAlign = "middle";
  12674. labelOffset.x = -size;
  12675. break;
  12676. case 180:
  12677. labelAlign = "start";
  12678. labelOffset.y = -size * 0.4;
  12679. break;
  12680. case 270:
  12681. labelAlign = "middle";
  12682. break;
  12683. default:
  12684. if(rotation < centerAnchorLimit){
  12685. labelAlign = "end";
  12686. labelOffset.y = size * 0.4;
  12687. }else if(rotation < 90){
  12688. labelAlign = "end";
  12689. labelOffset.y = size * 0.4;
  12690. }else if(rotation < (180 - centerAnchorLimit)){
  12691. labelAlign = "start";
  12692. }else if(rotation < (180 + centerAnchorLimit)){
  12693. labelAlign = "start";
  12694. labelOffset.y = -size * 0.4;
  12695. }else if(rotation < 270){
  12696. labelAlign = "start";
  12697. labelOffset.x = leftBottom ? 0 : size * 0.4;
  12698. }else if(rotation < (360 - centerAnchorLimit)){
  12699. labelAlign = "end";
  12700. labelOffset.x = leftBottom ? 0 : size * 0.4;
  12701. }else{
  12702. labelAlign = "end";
  12703. labelOffset.y = size * 0.4;
  12704. }
  12705. }
  12706. if(leftBottom){
  12707. start.x = stop.x = offsets.l;
  12708. titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 90 : 270;
  12709. titlePos.x = offsets.l - titleOffset + (titleRotation == 270 ? tsize : 0);
  12710. tickVector.x = -1;
  12711. anchorOffset.x = -anchorOffset.x;
  12712. }else{
  12713. start.x = stop.x = dim.width - offsets.r;
  12714. titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 90 : 270;
  12715. titlePos.x = dim.width - offsets.r + titleOffset - (titleRotation == 270 ? 0 : tsize);
  12716. switch(labelAlign){
  12717. case "start":
  12718. labelAlign = "end";
  12719. break;
  12720. case "end":
  12721. labelAlign = "start";
  12722. break;
  12723. case "middle":
  12724. labelOffset.x += size;
  12725. break;
  12726. }
  12727. }
  12728. }else{
  12729. start = {x: offsets.l};
  12730. stop = {x: dim.width - offsets.r};
  12731. titlePos = {x: (dim.width - offsets.r + offsets.l)/2};
  12732. titleOffset = size * cosr + (this._cachedLabelWidth || 0) * sinr + labelGap + Math.max(taMajorTick.length, taMinorTick.length) + tsize + taTitleGap;
  12733. axisVector = {x: 1, y: 0};
  12734. labelOffset = {x: 0, y: 0};
  12735. tickVector = {x: 0, y: 1};
  12736. anchorOffset = {x: 0, y: labelGap};
  12737. switch(rotation){
  12738. case 0:
  12739. labelAlign = "middle";
  12740. labelOffset.y = size;
  12741. break;
  12742. case 90:
  12743. labelAlign = "start";
  12744. labelOffset.x = -size * 0.4;
  12745. break;
  12746. case 180:
  12747. labelAlign = "middle";
  12748. break;
  12749. case 270:
  12750. labelAlign = "end";
  12751. labelOffset.x = size * 0.4;
  12752. break;
  12753. default:
  12754. if(rotation < (90 - centerAnchorLimit)){
  12755. labelAlign = "start";
  12756. labelOffset.y = leftBottom ? size : 0;
  12757. }else if(rotation < (90 + centerAnchorLimit)){
  12758. labelAlign = "start";
  12759. labelOffset.x = -size * 0.4;
  12760. }else if(rotation < 180){
  12761. labelAlign = "start";
  12762. labelOffset.y = leftBottom ? 0 : -size;
  12763. }else if(rotation < (270 - centerAnchorLimit)){
  12764. labelAlign = "end";
  12765. labelOffset.y = leftBottom ? 0 : -size;
  12766. }else if(rotation < (270 + centerAnchorLimit)){
  12767. labelAlign = "end";
  12768. labelOffset.y = leftBottom ? size * 0.4 : 0;
  12769. }else{
  12770. labelAlign = "end";
  12771. labelOffset.y = leftBottom ? size : 0;
  12772. }
  12773. }
  12774. if(leftBottom){
  12775. start.y = stop.y = dim.height - offsets.b;
  12776. titleRotation = (taTitleOrientation && taTitleOrientation == "axis") ? 180 : 0;
  12777. titlePos.y = dim.height - offsets.b + titleOffset - (titleRotation ? tsize : 0);
  12778. }else{
  12779. start.y = stop.y = offsets.t;
  12780. titleRotation = (taTitleOrientation && taTitleOrientation == "away") ? 180 : 0;
  12781. titlePos.y = offsets.t - titleOffset + (titleRotation ? 0 : tsize);
  12782. tickVector.y = -1;
  12783. anchorOffset.y = -anchorOffset.y;
  12784. switch(labelAlign){
  12785. case "start":
  12786. labelAlign = "end";
  12787. break;
  12788. case "end":
  12789. labelAlign = "start";
  12790. break;
  12791. case "middle":
  12792. labelOffset.y -= size;
  12793. break;
  12794. }
  12795. }
  12796. }
  12797. // render shapes
  12798. this.cleanGroup();
  12799. try{
  12800. var s = this.group,
  12801. c = this.scaler,
  12802. t = this.ticks,
  12803. canLabel,
  12804. f = lin.getTransformerFromModel(this.scaler),
  12805. // GFX Canvas now supports labels, so let's _not_ fallback to HTML anymore on canvas, just use
  12806. // HTML labels if explicitly asked + no rotation + no IE + no Opera
  12807. labelType = !titleRotation && !rotation && this.opt.htmlLabels && !dojo.isIE && !dojo.isOpera ? "html" : "gfx",
  12808. dx = tickVector.x * taMajorTick.length,
  12809. dy = tickVector.y * taMajorTick.length;
  12810. s.createLine({
  12811. x1: start.x,
  12812. y1: start.y,
  12813. x2: stop.x,
  12814. y2: stop.y
  12815. }).setStroke(taStroke);
  12816. //create axis title
  12817. if(o.title){
  12818. var axisTitle = dc.axis2d.common.createText[labelType](
  12819. this.chart,
  12820. s,
  12821. titlePos.x,
  12822. titlePos.y,
  12823. "middle",
  12824. o.title,
  12825. taTitleFont,
  12826. taTitleFontColor
  12827. );
  12828. if(labelType == "html"){
  12829. this.htmlElements.push(axisTitle);
  12830. }else{
  12831. //as soon as rotation is provided, labelType won't be "html"
  12832. //rotate gfx labels
  12833. axisTitle.setTransform(g.matrix.rotategAt(titleRotation, titlePos.x, titlePos.y));
  12834. }
  12835. }
  12836. dojo.forEach(t.major, function(tick){
  12837. var offset = f(tick.value), elem,
  12838. x = start.x + axisVector.x * offset,
  12839. y = start.y + axisVector.y * offset;
  12840. s.createLine({
  12841. x1: x, y1: y,
  12842. x2: x + dx,
  12843. y2: y + dy
  12844. }).setStroke(taMajorTick);
  12845. if(tick.label){
  12846. var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : {
  12847. text: tick.label,
  12848. truncated: false
  12849. };
  12850. label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label;
  12851. elem = dc.axis2d.common.createText[labelType](
  12852. this.chart,
  12853. s,
  12854. x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x),
  12855. y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y),
  12856. labelAlign,
  12857. label.text,
  12858. taFont,
  12859. taFontColor
  12860. //this._cachedLabelWidth
  12861. );
  12862. label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType);
  12863. if(labelType == "html"){
  12864. this.htmlElements.push(elem);
  12865. }else if(rotation){
  12866. elem.setTransform([
  12867. {dx: labelOffset.x, dy: labelOffset.y},
  12868. g.matrix.rotategAt(
  12869. rotation,
  12870. x + dx + anchorOffset.x,
  12871. y + dy + anchorOffset.y
  12872. )
  12873. ]);
  12874. }
  12875. }
  12876. }, this);
  12877. dx = tickVector.x * taMinorTick.length;
  12878. dy = tickVector.y * taMinorTick.length;
  12879. canLabel = c.minMinorStep <= c.minor.tick * c.bounds.scale;
  12880. dojo.forEach(t.minor, function(tick){
  12881. var offset = f(tick.value), elem,
  12882. x = start.x + axisVector.x * offset,
  12883. y = start.y + axisVector.y * offset;
  12884. s.createLine({
  12885. x1: x, y1: y,
  12886. x2: x + dx,
  12887. y2: y + dy
  12888. }).setStroke(taMinorTick);
  12889. if(canLabel && tick.label){
  12890. var label = o.maxLabelCharCount ? this.getTextWithLimitCharCount(tick.label, taFont, o.maxLabelCharCount) : {
  12891. text: tick.label,
  12892. truncated: false
  12893. };
  12894. label = o.maxLabelSize ? this.getTextWithLimitLength(label.text, taFont, o.maxLabelSize, label.truncated) : label;
  12895. elem = dc.axis2d.common.createText[labelType](
  12896. this.chart,
  12897. s,
  12898. x + dx + anchorOffset.x + (rotation ? 0 : labelOffset.x),
  12899. y + dy + anchorOffset.y + (rotation ? 0 : labelOffset.y),
  12900. labelAlign,
  12901. label.text,
  12902. taFont,
  12903. taFontColor
  12904. //this._cachedLabelWidth
  12905. );
  12906. label.truncated && this.labelTooltip(elem, this.chart, tick.label, label.text, taFont, labelType);
  12907. if(labelType == "html"){
  12908. this.htmlElements.push(elem);
  12909. }else if(rotation){
  12910. elem.setTransform([
  12911. {dx: labelOffset.x, dy: labelOffset.y},
  12912. g.matrix.rotategAt(
  12913. rotation,
  12914. x + dx + anchorOffset.x,
  12915. y + dy + anchorOffset.y
  12916. )
  12917. ]);
  12918. }
  12919. }
  12920. }, this);
  12921. dx = tickVector.x * taMicroTick.length;
  12922. dy = tickVector.y * taMicroTick.length;
  12923. dojo.forEach(t.micro, function(tick){
  12924. var offset = f(tick.value), elem,
  12925. x = start.x + axisVector.x * offset,
  12926. y = start.y + axisVector.y * offset;
  12927. s.createLine({
  12928. x1: x, y1: y,
  12929. x2: x + dx,
  12930. y2: y + dy
  12931. }).setStroke(taMicroTick);
  12932. }, this);
  12933. }catch(e){
  12934. // squelch
  12935. }
  12936. this.dirty = false;
  12937. return this; // dojox.charting.axis2d.Default
  12938. },
  12939. labelTooltip: function(elem, chart, label, truncatedLabel, font, elemType){
  12940. // to avoid requiring dijit module for that feature, let's test that
  12941. // dynamically and return if we can't do it
  12942. if(!dijit || !dijit.Tooltip){
  12943. return;
  12944. }
  12945. var aroundRect = {type: "rect"}, position = ["above", "below"],
  12946. fontWidth = dojox.gfx._base._getTextBox(truncatedLabel, {font: font}).w || 0;
  12947. fontHeight = font ? g.normalizedLength(g.splitFontString(font).size) : 0;
  12948. if(elemType == "html"){
  12949. dojo.mixin(aroundRect, dojo.coords(elem.firstChild, true));
  12950. aroundRect.width = Math.ceil(fontWidth);
  12951. aroundRect.height = Math.ceil(fontHeight);
  12952. this._events.push({
  12953. shape: dojo,
  12954. handle: dojo.connect(elem.firstChild, "onmouseover", this, function(e){
  12955. dijit.showTooltip(label, aroundRect, position);
  12956. })
  12957. });
  12958. this._events.push({
  12959. shape: dojo,
  12960. handle: dojo.connect(elem.firstChild, "onmouseout", this, function(e){
  12961. dijit.hideTooltip(aroundRect);
  12962. })
  12963. });
  12964. }else{
  12965. var shp = elem.getShape(),
  12966. lt = dojo.coords(chart.node, true);
  12967. aroundRect = dojo.mixin(aroundRect, {
  12968. x: shp.x - fontWidth / 2,
  12969. y: shp.y
  12970. });
  12971. aroundRect.x += lt.x;
  12972. aroundRect.y += lt.y;
  12973. aroundRect.x = Math.round(aroundRect.x);
  12974. aroundRect.y = Math.round(aroundRect.y);
  12975. aroundRect.width = Math.ceil(fontWidth);
  12976. aroundRect.height = Math.ceil(fontHeight);
  12977. this._events.push({
  12978. shape: elem,
  12979. handle: elem.connect("onmouseenter", this, function(e){
  12980. dijit.showTooltip(label, aroundRect, position);
  12981. })
  12982. });
  12983. this._events.push({
  12984. shape: elem,
  12985. handle: elem.connect("onmouseleave", this, function(e){
  12986. dijit.hideTooltip(aroundRect);
  12987. })
  12988. });
  12989. }
  12990. }
  12991. });
  12992. })();
  12993. }
  12994. if(!dojo._hasResource["dojox.charting.plot2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  12995. dojo._hasResource["dojox.charting.plot2d.common"] = true;
  12996. dojo.provide("dojox.charting.plot2d.common");
  12997. (function(){
  12998. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common;
  12999. dojo.mixin(dojox.charting.plot2d.common, {
  13000. makeStroke: function(stroke){
  13001. if(!stroke){ return stroke; }
  13002. if(typeof stroke == "string" || stroke instanceof dojo.Color){
  13003. stroke = {color: stroke};
  13004. }
  13005. return dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke);
  13006. },
  13007. augmentColor: function(target, color){
  13008. var t = new dojo.Color(target),
  13009. c = new dojo.Color(color);
  13010. c.a = t.a;
  13011. return c;
  13012. },
  13013. augmentStroke: function(stroke, color){
  13014. var s = dc.makeStroke(stroke);
  13015. if(s){
  13016. s.color = dc.augmentColor(s.color, color);
  13017. }
  13018. return s;
  13019. },
  13020. augmentFill: function(fill, color){
  13021. var fc, c = new dojo.Color(color);
  13022. if(typeof fill == "string" || fill instanceof dojo.Color){
  13023. return dc.augmentColor(fill, color);
  13024. }
  13025. return fill;
  13026. },
  13027. defaultStats: {
  13028. vmin: Number.POSITIVE_INFINITY, vmax: Number.NEGATIVE_INFINITY,
  13029. hmin: Number.POSITIVE_INFINITY, hmax: Number.NEGATIVE_INFINITY
  13030. },
  13031. collectSimpleStats: function(series){
  13032. var stats = dojo.delegate(dc.defaultStats);
  13033. for(var i = 0; i < series.length; ++i){
  13034. var run = series[i];
  13035. for(var j = 0; j < run.data.length; j++){
  13036. if(run.data[j] !== null){
  13037. if(typeof run.data[j] == "number"){
  13038. // 1D case
  13039. var old_vmin = stats.vmin, old_vmax = stats.vmax;
  13040. if(!("ymin" in run) || !("ymax" in run)){
  13041. dojo.forEach(run.data, function(val, i){
  13042. if(val !== null){
  13043. var x = i + 1, y = val;
  13044. if(isNaN(y)){ y = 0; }
  13045. stats.hmin = Math.min(stats.hmin, x);
  13046. stats.hmax = Math.max(stats.hmax, x);
  13047. stats.vmin = Math.min(stats.vmin, y);
  13048. stats.vmax = Math.max(stats.vmax, y);
  13049. }
  13050. });
  13051. }
  13052. if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); }
  13053. if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); }
  13054. }else{
  13055. // 2D case
  13056. var old_hmin = stats.hmin, old_hmax = stats.hmax,
  13057. old_vmin = stats.vmin, old_vmax = stats.vmax;
  13058. if(!("xmin" in run) || !("xmax" in run) || !("ymin" in run) || !("ymax" in run)){
  13059. dojo.forEach(run.data, function(val, i){
  13060. if(val !== null){
  13061. var x = "x" in val ? val.x : i + 1, y = val.y;
  13062. if(isNaN(x)){ x = 0; }
  13063. if(isNaN(y)){ y = 0; }
  13064. stats.hmin = Math.min(stats.hmin, x);
  13065. stats.hmax = Math.max(stats.hmax, x);
  13066. stats.vmin = Math.min(stats.vmin, y);
  13067. stats.vmax = Math.max(stats.vmax, y);
  13068. }
  13069. });
  13070. }
  13071. if("xmin" in run){ stats.hmin = Math.min(old_hmin, run.xmin); }
  13072. if("xmax" in run){ stats.hmax = Math.max(old_hmax, run.xmax); }
  13073. if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); }
  13074. if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); }
  13075. }
  13076. break;
  13077. }
  13078. }
  13079. }
  13080. return stats;
  13081. },
  13082. calculateBarSize: function(/* Number */ availableSize, /* Object */ opt, /* Number? */ clusterSize){
  13083. if(!clusterSize){
  13084. clusterSize = 1;
  13085. }
  13086. var gap = opt.gap, size = (availableSize - 2 * gap) / clusterSize;
  13087. if("minBarSize" in opt){
  13088. size = Math.max(size, opt.minBarSize);
  13089. }
  13090. if("maxBarSize" in opt){
  13091. size = Math.min(size, opt.maxBarSize);
  13092. }
  13093. size = Math.max(size, 1);
  13094. gap = (availableSize - size * clusterSize) / 2;
  13095. return {size: size, gap: gap}; // Object
  13096. },
  13097. collectStackedStats: function(series){
  13098. // collect statistics
  13099. var stats = dojo.clone(dc.defaultStats);
  13100. if(series.length){
  13101. // 1st pass: find the maximal length of runs
  13102. stats.hmin = Math.min(stats.hmin, 1);
  13103. stats.hmax = df.foldl(series, "seed, run -> Math.max(seed, run.data.length)", stats.hmax);
  13104. // 2nd pass: stack values
  13105. for(var i = 0; i < stats.hmax; ++i){
  13106. var v = series[0].data[i];
  13107. v = v && (typeof v == "number" ? v : v.y);
  13108. if(isNaN(v)){ v = 0; }
  13109. stats.vmin = Math.min(stats.vmin, v);
  13110. for(var j = 1; j < series.length; ++j){
  13111. var t = series[j].data[i];
  13112. t = t && (typeof t == "number" ? t : t.y);
  13113. if(isNaN(t)){ t = 0; }
  13114. v += t;
  13115. }
  13116. stats.vmax = Math.max(stats.vmax, v);
  13117. }
  13118. }
  13119. return stats;
  13120. },
  13121. curve: function(/* Number[] */a, /* Number|String */tension){
  13122. // FIX for #7235, submitted by Enzo Michelangeli.
  13123. // Emulates the smoothing algorithms used in a famous, unnamed spreadsheet
  13124. // program ;)
  13125. var arr = a.slice(0);
  13126. if(tension == "x") {
  13127. arr[arr.length] = arr[0]; // add a last element equal to the first, closing the loop
  13128. }
  13129. var p=dojo.map(arr, function(item, i){
  13130. if(i==0){ return "M" + item.x + "," + item.y; }
  13131. if(!isNaN(tension)) { // use standard Dojo smoothing in tension is numeric
  13132. var dx=item.x-arr[i-1].x, dy=arr[i-1].y;
  13133. return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y;
  13134. } else if(tension == "X" || tension == "x" || tension == "S") {
  13135. // use Excel "line smoothing" algorithm (http://xlrotor.com/resources/files.shtml)
  13136. var p0, p1 = arr[i-1], p2 = arr[i], p3;
  13137. var bz1x, bz1y, bz2x, bz2y;
  13138. var f = 1/6;
  13139. if(i==1) {
  13140. if(tension == "x") {
  13141. p0 = arr[arr.length-2];
  13142. } else { // "tension == X || tension == "S"
  13143. p0 = p1;
  13144. }
  13145. f = 1/3;
  13146. } else {
  13147. p0 = arr[i-2];
  13148. }
  13149. if(i==(arr.length-1)) {
  13150. if(tension == "x") {
  13151. p3 = arr[1];
  13152. } else { // "tension == X || tension == "S"
  13153. p3 = p2;
  13154. }
  13155. f = 1/3;
  13156. } else {
  13157. p3 = arr[i+1];
  13158. }
  13159. var p1p2 = Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
  13160. var p0p2 = Math.sqrt((p2.x-p0.x)*(p2.x-p0.x)+(p2.y-p0.y)*(p2.y-p0.y));
  13161. var p1p3 = Math.sqrt((p3.x-p1.x)*(p3.x-p1.x)+(p3.y-p1.y)*(p3.y-p1.y));
  13162. var p0p2f = p0p2 * f;
  13163. var p1p3f = p1p3 * f;
  13164. if(p0p2f > p1p2/2 && p1p3f > p1p2/2) {
  13165. p0p2f = p1p2/2;
  13166. p1p3f = p1p2/2;
  13167. } else if(p0p2f > p1p2/2) {
  13168. p0p2f = p1p2/2;
  13169. p1p3f = p1p2/2 * p1p3/p0p2;
  13170. } else if(p1p3f > p1p2/2) {
  13171. p1p3f = p1p2/2;
  13172. p0p2f = p1p2/2 * p0p2/p1p3;
  13173. }
  13174. if(tension == "S") {
  13175. if(p0 == p1) { p0p2f = 0; }
  13176. if(p2 == p3) { p1p3f = 0; }
  13177. }
  13178. bz1x = p1.x + p0p2f*(p2.x - p0.x)/p0p2;
  13179. bz1y = p1.y + p0p2f*(p2.y - p0.y)/p0p2;
  13180. bz2x = p2.x - p1p3f*(p3.x - p1.x)/p1p3;
  13181. bz2y = p2.y - p1p3f*(p3.y - p1.y)/p1p3;
  13182. }
  13183. return "C"+(bz1x+","+bz1y+" "+bz2x+","+bz2y+" "+p2.x+","+p2.y);
  13184. });
  13185. return p.join(" ");
  13186. },
  13187. getLabel: function(/*Number*/number, /*Boolean*/fixed, /*Number*/precision){
  13188. if(dojo.number){
  13189. return (fixed ? dojo.number.format(number, {places : precision}) :
  13190. dojo.number.format(number)) || "";
  13191. }
  13192. return fixed ? number.toFixed(precision) : number.toString();
  13193. }
  13194. });
  13195. })();
  13196. }
  13197. if(!dojo._hasResource["dojox.charting.scaler.primitive"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13198. dojo._hasResource["dojox.charting.scaler.primitive"] = true;
  13199. dojo.provide("dojox.charting.scaler.primitive");
  13200. dojox.charting.scaler.primitive = {
  13201. buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){
  13202. if(min == max){
  13203. // artificially extend bounds
  13204. min -= 0.5;
  13205. max += 0.5;
  13206. // now the line will be centered
  13207. }
  13208. return {
  13209. bounds: {
  13210. lower: min,
  13211. upper: max,
  13212. from: min,
  13213. to: max,
  13214. scale: span / (max - min),
  13215. span: span
  13216. },
  13217. scaler: dojox.charting.scaler.primitive
  13218. };
  13219. },
  13220. buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){
  13221. return {major: [], minor: [], micro: []}; // Object
  13222. },
  13223. getTransformerFromModel: function(/*Object*/ scaler){
  13224. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  13225. return function(x){ return (x - offset) * scale; }; // Function
  13226. },
  13227. getTransformerFromPlot: function(/*Object*/ scaler){
  13228. var offset = scaler.bounds.from, scale = scaler.bounds.scale;
  13229. return function(x){ return x / scale + offset; }; // Function
  13230. }
  13231. };
  13232. }
  13233. if(!dojo._hasResource["dojox.charting.plot2d._PlotEvents"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13234. dojo._hasResource["dojox.charting.plot2d._PlotEvents"] = true;
  13235. dojo.provide("dojox.charting.plot2d._PlotEvents");
  13236. dojo.declare("dojox.charting.plot2d._PlotEvents", null, {
  13237. constructor: function(){
  13238. this._shapeEvents = [];
  13239. this._eventSeries = {};
  13240. },
  13241. destroy: function(){
  13242. // summary:
  13243. // Destroy any internal elements and event handlers.
  13244. this.resetEvents();
  13245. this.inherited(arguments);
  13246. },
  13247. plotEvent: function(o){
  13248. // summary:
  13249. // Stub function for use by specific plots.
  13250. // o: Object
  13251. // An object intended to represent event parameters.
  13252. },
  13253. raiseEvent: function(o){
  13254. // summary:
  13255. // Raises events in predefined order
  13256. // o: Object
  13257. // An object intended to represent event parameters.
  13258. this.plotEvent(o);
  13259. var t = dojo.delegate(o);
  13260. t.originalEvent = o.type;
  13261. t.originalPlot = o.plot;
  13262. t.type = "onindirect";
  13263. dojo.forEach(this.chart.stack, function(plot){
  13264. if(plot !== this && plot.plotEvent){
  13265. t.plot = plot;
  13266. plot.plotEvent(t);
  13267. }
  13268. }, this);
  13269. },
  13270. connect: function(object, method){
  13271. // summary:
  13272. // Helper function to connect any object's method to our plotEvent.
  13273. // object: Object
  13274. // The object to connect to.
  13275. // method: String|Function
  13276. // The method to fire when our plotEvent is fired.
  13277. // returns: Array
  13278. // The handle as returned from dojo.connect (see dojo.connect).
  13279. this.dirty = true;
  13280. return dojo.connect(this, "plotEvent", object, method); // Array
  13281. },
  13282. events: function(){
  13283. // summary:
  13284. // Find out if any event handlers have been connected to our plotEvent.
  13285. // returns: Boolean
  13286. // A flag indicating that there are handlers attached.
  13287. var ls = this.plotEvent._listeners;
  13288. if(!ls || !ls.length){ return false; }
  13289. for(var i in ls){
  13290. if(!(i in Array.prototype)){
  13291. return true;
  13292. }
  13293. }
  13294. return false;
  13295. },
  13296. resetEvents: function(){
  13297. // summary:
  13298. // Reset all events attached to our plotEvent (i.e. disconnect).
  13299. if(this._shapeEvents.length){
  13300. dojo.forEach(this._shapeEvents, function(item){
  13301. item.shape.disconnect(item.handle);
  13302. });
  13303. this._shapeEvents = [];
  13304. }
  13305. this.raiseEvent({type: "onplotreset", plot: this});
  13306. },
  13307. _connectSingleEvent: function(o, eventName){
  13308. this._shapeEvents.push({
  13309. shape: o.eventMask,
  13310. handle: o.eventMask.connect(eventName, this, function(e){
  13311. o.type = eventName;
  13312. o.event = e;
  13313. this.raiseEvent(o);
  13314. o.event = null;
  13315. })
  13316. });
  13317. },
  13318. _connectEvents: function(o){
  13319. if(o){
  13320. o.chart = this.chart;
  13321. o.plot = this;
  13322. o.hAxis = this.hAxis || null;
  13323. o.vAxis = this.vAxis || null;
  13324. o.eventMask = o.eventMask || o.shape;
  13325. this._connectSingleEvent(o, "onmouseover");
  13326. this._connectSingleEvent(o, "onmouseout");
  13327. this._connectSingleEvent(o, "onclick");
  13328. }
  13329. },
  13330. _reconnectEvents: function(seriesName){
  13331. var a = this._eventSeries[seriesName];
  13332. if(a){
  13333. dojo.forEach(a, this._connectEvents, this);
  13334. }
  13335. },
  13336. fireEvent: function(seriesName, eventName, index, eventObject){
  13337. // summary:
  13338. // Emulates firing an event for a given data value (specified by
  13339. // an index) of a given series.
  13340. // seriesName: String:
  13341. // Series name.
  13342. // eventName: String:
  13343. // Event name to emulate.
  13344. // index: Number:
  13345. // Valid data value index used to raise an event.
  13346. // eventObject: Object?:
  13347. // Optional event object. Especially useful for synthetic events.
  13348. // Default: null.
  13349. var s = this._eventSeries[seriesName];
  13350. if(s && s.length && index < s.length){
  13351. var o = s[index];
  13352. o.type = eventName;
  13353. o.event = eventObject || null;
  13354. this.raiseEvent(o);
  13355. o.event = null;
  13356. }
  13357. }
  13358. });
  13359. }
  13360. if(!dojo._hasResource["dojox.charting.plot2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13361. dojo._hasResource["dojox.charting.plot2d.Base"] = true;
  13362. dojo.provide("dojox.charting.plot2d.Base");
  13363. /*=====
  13364. dojox.charting.plot2d.__PlotCtorArgs = function(){
  13365. // summary:
  13366. // The base keyword arguments object for plot constructors.
  13367. // Note that the parameters for this may change based on the
  13368. // specific plot type (see the corresponding plot type for
  13369. // details).
  13370. }
  13371. =====*/
  13372. dojo.declare("dojox.charting.plot2d.Base", [dojox.charting.Element, dojox.charting.plot2d._PlotEvents], {
  13373. constructor: function(chart, kwArgs){
  13374. // summary:
  13375. // Create a base plot for charting.
  13376. // chart: dojox.chart.Chart2D
  13377. // The chart this plot belongs to.
  13378. // kwArgs: dojox.charting.plot2d.__PlotCtorArgs?
  13379. // An optional arguments object to help define the plot.
  13380. this.zoom = null,
  13381. this.zoomQueue = []; // zooming action task queue
  13382. this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0};
  13383. },
  13384. clear: function(){
  13385. // summary:
  13386. // Clear out all of the information tied to this plot.
  13387. // returns: dojox.charting.plot2d.Base
  13388. // A reference to this plot for functional chaining.
  13389. this.series = [];
  13390. this._hAxis = null;
  13391. this._vAxis = null;
  13392. this.dirty = true;
  13393. return this; // dojox.charting.plot2d.Base
  13394. },
  13395. setAxis: function(axis){
  13396. // summary:
  13397. // Set an axis for this plot.
  13398. // axis: dojox.charting.axis2d.Base
  13399. // The axis to set.
  13400. // returns: dojox.charting.plot2d.Base
  13401. // A reference to this plot for functional chaining.
  13402. if(axis){
  13403. this[axis.vertical ? "_vAxis" : "_hAxis"] = axis;
  13404. }
  13405. return this; // dojox.charting.plot2d.Base
  13406. },
  13407. addSeries: function(run){
  13408. // summary:
  13409. // Add a data series to this plot.
  13410. // run: dojox.charting.Series
  13411. // The series to be added.
  13412. // returns: dojox.charting.plot2d.Base
  13413. // A reference to this plot for functional chaining.
  13414. this.series.push(run);
  13415. return this; // dojox.charting.plot2d.Base
  13416. },
  13417. getSeriesStats: function(){
  13418. // summary:
  13419. // Calculate the min/max on all attached series in both directions.
  13420. // returns: Object
  13421. // {hmin, hmax, vmin, vmax} min/max in both directions.
  13422. return dojox.charting.plot2d.common.collectSimpleStats(this.series);
  13423. },
  13424. calculateAxes: function(dim){
  13425. // summary:
  13426. // Stub function for running the axis calculations (depricated).
  13427. // dim: Object
  13428. // An object of the form { width, height }
  13429. // returns: dojox.charting.plot2d.Base
  13430. // A reference to this plot for functional chaining.
  13431. this.initializeScalers(dim, this.getSeriesStats());
  13432. return this; // dojox.charting.plot2d.Base
  13433. },
  13434. isDirty: function(){
  13435. // summary:
  13436. // Returns whether or not this plot needs to be rendered.
  13437. // returns: Boolean
  13438. // The state of the plot.
  13439. return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean
  13440. },
  13441. isDataDirty: function(){
  13442. // summary:
  13443. // Returns whether or not any of this plot's data series need to be rendered.
  13444. // returns: Boolean
  13445. // Flag indicating if any of this plot's series are invalid and need rendering.
  13446. return dojo.some(this.series, function(item){ return item.dirty; }); // Boolean
  13447. },
  13448. performZoom: function(dim, offsets){
  13449. // summary:
  13450. // Create/alter any zooming windows on this plot.
  13451. // dim: Object
  13452. // An object of the form { width, height }.
  13453. // offsets: Object
  13454. // An object of the form { l, r, t, b }.
  13455. // returns: dojox.charting.plot2d.Base
  13456. // A reference to this plot for functional chaining.
  13457. // get current zooming various
  13458. var vs = this._vAxis.scale || 1,
  13459. hs = this._hAxis.scale || 1,
  13460. vOffset = dim.height - offsets.b,
  13461. hBounds = this._hScaler.bounds,
  13462. xOffset = (hBounds.from - hBounds.lower) * hBounds.scale,
  13463. vBounds = this._vScaler.bounds,
  13464. yOffset = (vBounds.from - vBounds.lower) * vBounds.scale;
  13465. // get incremental zooming various
  13466. rVScale = vs / this.lastWindow.vscale,
  13467. rHScale = hs / this.lastWindow.hscale,
  13468. rXOffset = (this.lastWindow.xoffset - xOffset)/
  13469. ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale),
  13470. rYOffset = (yOffset - this.lastWindow.yoffset)/
  13471. ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale),
  13472. shape = this.group,
  13473. anim = dojox.gfx.fx.animateTransform(dojo.delegate({
  13474. shape: shape,
  13475. duration: 1200,
  13476. transform:[
  13477. {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]},
  13478. {name:"scale", start:[1, 1], end: [rHScale, rVScale]},
  13479. {name:"original"},
  13480. {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]}
  13481. ]}, this.zoom));
  13482. dojo.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset});
  13483. //add anim to zooming action queue,
  13484. //in order to avoid several zooming action happened at the same time
  13485. this.zoomQueue.push(anim);
  13486. //perform each anim one by one in zoomQueue
  13487. dojo.connect(anim, "onEnd", this, function(){
  13488. this.zoom = null;
  13489. this.zoomQueue.shift();
  13490. if(this.zoomQueue.length > 0){
  13491. this.zoomQueue[0].play();
  13492. }
  13493. });
  13494. if(this.zoomQueue.length == 1){
  13495. this.zoomQueue[0].play();
  13496. }
  13497. return this; // dojox.charting.plot2d.Base
  13498. },
  13499. render: function(dim, offsets){
  13500. // summary:
  13501. // Render the plot on the chart.
  13502. // dim: Object
  13503. // An object of the form { width, height }.
  13504. // offsets: Object
  13505. // An object of the form { l, r, t, b }.
  13506. // returns: dojox.charting.plot2d.Base
  13507. // A reference to this plot for functional chaining.
  13508. return this; // dojox.charting.plot2d.Base
  13509. },
  13510. getRequiredColors: function(){
  13511. // summary:
  13512. // Get how many data series we have, so we know how many colors to use.
  13513. // returns: Number
  13514. // The number of colors needed.
  13515. return this.series.length; // Number
  13516. },
  13517. initializeScalers: function(dim, stats){
  13518. // summary:
  13519. // Initializes scalers using attached axes.
  13520. // dim: Object:
  13521. // Size of a plot area in pixels as {width, height}.
  13522. // stats: Object:
  13523. // Min/max of data in both directions as {hmin, hmax, vmin, vmax}.
  13524. // returns: dojox.charting.plot2d.Base
  13525. // A reference to this plot for functional chaining.
  13526. if(this._hAxis){
  13527. if(!this._hAxis.initialized()){
  13528. this._hAxis.calculate(stats.hmin, stats.hmax, dim.width);
  13529. }
  13530. this._hScaler = this._hAxis.getScaler();
  13531. }else{
  13532. this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width);
  13533. }
  13534. if(this._vAxis){
  13535. if(!this._vAxis.initialized()){
  13536. this._vAxis.calculate(stats.vmin, stats.vmax, dim.height);
  13537. }
  13538. this._vScaler = this._vAxis.getScaler();
  13539. }else{
  13540. this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height);
  13541. }
  13542. return this; // dojox.charting.plot2d.Base
  13543. }
  13544. });
  13545. }
  13546. if(!dojo._hasResource["dojox.charting.plot2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13547. dojo._hasResource["dojox.charting.plot2d.Default"] = true;
  13548. dojo.provide("dojox.charting.plot2d.Default");
  13549. /*=====
  13550. dojo.declare("dojox.charting.plot2d.__DefaultCtorArgs", dojox.charting.plot2d.__PlotCtorArgs, {
  13551. // summary:
  13552. // The arguments used for any/most plots.
  13553. // hAxis: String?
  13554. // The horizontal axis name.
  13555. hAxis: "x",
  13556. // vAxis: String?
  13557. // The vertical axis name
  13558. vAxis: "y",
  13559. // lines: Boolean?
  13560. // Whether or not to draw lines on this plot. Defaults to true.
  13561. lines: true,
  13562. // areas: Boolean?
  13563. // Whether or not to draw areas on this plot. Defaults to false.
  13564. areas: false,
  13565. // markers: Boolean?
  13566. // Whether or not to draw markers at data points on this plot. Default is false.
  13567. markers: false,
  13568. // tension: Number|String?
  13569. // Whether or not to apply 'tensioning' to the lines on this chart.
  13570. // Options include a number, "X", "x", or "S"; if a number is used, the
  13571. // simpler bezier curve calculations are used to draw the lines. If X, x or S
  13572. // is used, the more accurate smoothing algorithm is used.
  13573. tension: "",
  13574. // animate: Boolean?
  13575. // Whether or not to animate the chart to place.
  13576. animate: false,
  13577. // stroke: dojox.gfx.Stroke?
  13578. // An optional stroke to use for any series on the plot.
  13579. stroke: {},
  13580. // outline: dojox.gfx.Stroke?
  13581. // An optional stroke used to outline any series on the plot.
  13582. outline: {},
  13583. // shadow: dojox.gfx.Stroke?
  13584. // An optional stroke to use to draw any shadows for a series on a plot.
  13585. shadow: {},
  13586. // fill: dojox.gfx.Fill?
  13587. // Any fill to be used for elements on the plot (such as areas).
  13588. fill: {},
  13589. // font: String?
  13590. // A font definition to be used for labels and other text-based elements on the plot.
  13591. font: "",
  13592. // fontColor: String|dojo.Color?
  13593. // The color to be used for any text-based elements on the plot.
  13594. fontColor: "",
  13595. // markerStroke: dojo.gfx.Stroke?
  13596. // An optional stroke to use for any markers on the plot.
  13597. markerStroke: {},
  13598. // markerOutline: dojo.gfx.Stroke?
  13599. // An optional outline to use for any markers on the plot.
  13600. markerOutline: {},
  13601. // markerShadow: dojo.gfx.Stroke?
  13602. // An optional shadow to use for any markers on the plot.
  13603. markerShadow: {},
  13604. // markerFill: dojo.gfx.Fill?
  13605. // An optional fill to use for any markers on the plot.
  13606. markerFill: {},
  13607. // markerFont: String?
  13608. // An optional font definition to use for any markers on the plot.
  13609. markerFont: "",
  13610. // markerFontColor: String|dojo.Color?
  13611. // An optional color to use for any marker text on the plot.
  13612. markerFontColor: ""
  13613. });
  13614. =====*/
  13615. (function(){
  13616. var df = dojox.lang.functional, du = dojox.lang.utils,
  13617. dc = dojox.charting.plot2d.common,
  13618. purgeGroup = df.lambda("item.purgeGroup()");
  13619. var DEFAULT_ANIMATION_LENGTH = 1200; // in ms
  13620. dojo.declare("dojox.charting.plot2d.Default", dojox.charting.plot2d.Base, {
  13621. defaultParams: {
  13622. hAxis: "x", // use a horizontal axis named "x"
  13623. vAxis: "y", // use a vertical axis named "y"
  13624. lines: true, // draw lines
  13625. areas: false, // draw areas
  13626. markers: false, // draw markers
  13627. tension: "", // draw curved lines (tension is "X", "x", or "S")
  13628. animate: false // animate chart to place
  13629. },
  13630. optionalParams: {
  13631. // theme component
  13632. stroke: {},
  13633. outline: {},
  13634. shadow: {},
  13635. fill: {},
  13636. font: "",
  13637. fontColor: "",
  13638. markerStroke: {},
  13639. markerOutline: {},
  13640. markerShadow: {},
  13641. markerFill: {},
  13642. markerFont: "",
  13643. markerFontColor: ""
  13644. },
  13645. constructor: function(chart, kwArgs){
  13646. // summary:
  13647. // Return a new plot.
  13648. // chart: dojox.charting.Chart2D
  13649. // The chart this plot belongs to.
  13650. // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs?
  13651. // An optional arguments object to help define this plot.
  13652. this.opt = dojo.clone(this.defaultParams);
  13653. du.updateWithObject(this.opt, kwArgs);
  13654. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  13655. this.series = [];
  13656. this.hAxis = this.opt.hAxis;
  13657. this.vAxis = this.opt.vAxis;
  13658. // animation properties
  13659. this.animate = this.opt.animate;
  13660. },
  13661. render: function(dim, offsets){
  13662. // summary:
  13663. // Render/draw everything on this plot.
  13664. // dim: Object
  13665. // An object of the form { width, height }
  13666. // offsets: Object
  13667. // An object of the form { l, r, t, b }
  13668. // returns: dojox.charting.plot2d.Default
  13669. // A reference to this plot for functional chaining.
  13670. // make sure all the series is not modified
  13671. if(this.zoom && !this.isDataDirty()){
  13672. return this.performZoom(dim, offsets);
  13673. }
  13674. this.resetEvents();
  13675. this.dirty = this.isDirty();
  13676. if(this.dirty){
  13677. dojo.forEach(this.series, purgeGroup);
  13678. this._eventSeries = {};
  13679. this.cleanGroup();
  13680. this.group.setTransform(null);
  13681. var s = this.group;
  13682. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  13683. }
  13684. var t = this.chart.theme, stroke, outline, marker, events = this.events();
  13685. for(var i = this.series.length - 1; i >= 0; --i){
  13686. var run = this.series[i];
  13687. if(!this.dirty && !run.dirty){
  13688. t.skip();
  13689. this._reconnectEvents(run.name);
  13690. continue;
  13691. }
  13692. run.cleanGroup();
  13693. if(!run.data.length){
  13694. run.dirty = false;
  13695. t.skip();
  13696. continue;
  13697. }
  13698. var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true),
  13699. s = run.group, rsegments = [], startindexes = [], rseg = null, lpoly,
  13700. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  13701. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  13702. eventSeries = this._eventSeries[run.name] = new Array(run.data.length);
  13703. // split the run data into dense segments (each containing no nulls)
  13704. for(var j = 0; j < run.data.length; j++){
  13705. if(run.data[j] != null){
  13706. if(!rseg){
  13707. rseg = [];
  13708. startindexes.push(j);
  13709. rsegments.push(rseg)
  13710. }
  13711. rseg.push(run.data[j]);
  13712. }else{
  13713. rseg = null;
  13714. }
  13715. }
  13716. for(var seg = 0; seg < rsegments.length; seg++){
  13717. if(typeof rsegments[seg][0] == "number"){
  13718. lpoly = dojo.map(rsegments[seg], function(v, i){
  13719. return {
  13720. x: ht(i + startindexes[seg] + 1) + offsets.l,
  13721. y: dim.height - offsets.b - vt(v)
  13722. };
  13723. }, this);
  13724. }else{
  13725. lpoly = dojo.map(rsegments[seg], function(v, i){
  13726. return {
  13727. x: ht(v.x) + offsets.l,
  13728. y: dim.height - offsets.b - vt(v.y)
  13729. };
  13730. }, this);
  13731. }
  13732. var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : "";
  13733. if(this.opt.areas && lpoly.length > 1){
  13734. var fill = theme.series.fill;
  13735. var apoly = dojo.clone(lpoly);
  13736. if(this.opt.tension){
  13737. var apath = "L" + apoly[apoly.length-1].x + "," + (dim.height - offsets.b) +
  13738. " L" + apoly[0].x + "," + (dim.height - offsets.b) +
  13739. " L" + apoly[0].x + "," + apoly[0].y;
  13740. run.dyn.fill = s.createPath(lpath + " " + apath).setFill(fill).getFill();
  13741. } else {
  13742. apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b});
  13743. apoly.push({x: lpoly[0].x, y: dim.height - offsets.b});
  13744. apoly.push(lpoly[0]);
  13745. run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill();
  13746. }
  13747. }
  13748. if(this.opt.lines || this.opt.markers){
  13749. // need a stroke
  13750. stroke = theme.series.stroke;
  13751. if(theme.series.outline){
  13752. outline = run.dyn.outline = dc.makeStroke(theme.series.outline);
  13753. outline.width = 2 * outline.width + stroke.width;
  13754. }
  13755. }
  13756. if(this.opt.markers){
  13757. run.dyn.marker = theme.symbol;
  13758. }
  13759. var frontMarkers = null, outlineMarkers = null, shadowMarkers = null;
  13760. if(stroke && theme.series.shadow && lpoly.length > 1){
  13761. var shadow = theme.series.shadow,
  13762. spoly = dojo.map(lpoly, function(c){
  13763. return {x: c.x + shadow.dx, y: c.y + shadow.dy};
  13764. });
  13765. if(this.opt.lines){
  13766. if(this.opt.tension){
  13767. run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke();
  13768. } else {
  13769. run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke();
  13770. }
  13771. }
  13772. if(this.opt.markers && theme.marker.shadow){
  13773. shadow = theme.marker.shadow;
  13774. shadowMarkers = dojo.map(spoly, function(c){
  13775. return s.createPath("M" + c.x + " " + c.y + " " + theme.symbol).
  13776. setStroke(shadow).setFill(shadow.color);
  13777. }, this);
  13778. }
  13779. }
  13780. if(this.opt.lines && lpoly.length > 1){
  13781. if(outline){
  13782. if(this.opt.tension){
  13783. run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke();
  13784. } else {
  13785. run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke();
  13786. }
  13787. }
  13788. if(this.opt.tension){
  13789. run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke();
  13790. } else {
  13791. run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke();
  13792. }
  13793. }
  13794. if(this.opt.markers){
  13795. frontMarkers = new Array(lpoly.length);
  13796. outlineMarkers = new Array(lpoly.length);
  13797. outline = null;
  13798. if(theme.marker.outline){
  13799. outline = dc.makeStroke(theme.marker.outline);
  13800. outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0);
  13801. }
  13802. dojo.forEach(lpoly, function(c, i){
  13803. var path = "M" + c.x + " " + c.y + " " + theme.symbol;
  13804. if(outline){
  13805. outlineMarkers[i] = s.createPath(path).setStroke(outline);
  13806. }
  13807. frontMarkers[i] = s.createPath(path).setStroke(theme.marker.stroke).setFill(theme.marker.fill);
  13808. }, this);
  13809. run.dyn.markerFill = theme.marker.fill;
  13810. run.dyn.markerStroke = theme.marker.stroke;
  13811. if(events){
  13812. dojo.forEach(frontMarkers, function(s, i){
  13813. var o = {
  13814. element: "marker",
  13815. index: i + startindexes[seg],
  13816. run: run,
  13817. shape: s,
  13818. outline: outlineMarkers[i] || null,
  13819. shadow: shadowMarkers && shadowMarkers[i] || null,
  13820. cx: lpoly[i].x,
  13821. cy: lpoly[i].y
  13822. };
  13823. if(typeof rsegments[seg][0] == "number"){
  13824. o.x = i + startindexes[seg] + 1;
  13825. o.y = rsegments[seg][i];
  13826. }else{
  13827. o.x = rsegments[seg][i].x;
  13828. o.y = rsegments[seg][i].y;
  13829. }
  13830. this._connectEvents(o);
  13831. eventSeries[i + startindexes[seg]] = o;
  13832. }, this);
  13833. }else{
  13834. delete this._eventSeries[run.name];
  13835. }
  13836. }
  13837. }
  13838. run.dirty = false;
  13839. }
  13840. if(this.animate){
  13841. // grow from the bottom
  13842. var plotGroup = this.group;
  13843. dojox.gfx.fx.animateTransform(dojo.delegate({
  13844. shape: plotGroup,
  13845. duration: DEFAULT_ANIMATION_LENGTH,
  13846. transform:[
  13847. {name:"translate", start: [0, dim.height - offsets.b], end: [0, 0]},
  13848. {name:"scale", start: [1, 0], end:[1, 1]},
  13849. {name:"original"}
  13850. ]
  13851. }, this.animate)).play();
  13852. }
  13853. this.dirty = false;
  13854. return this; // dojox.charting.plot2d.Default
  13855. }
  13856. });
  13857. })();
  13858. }
  13859. if(!dojo._hasResource["dojox.charting.plot2d.Lines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13860. dojo._hasResource["dojox.charting.plot2d.Lines"] = true;
  13861. dojo.provide("dojox.charting.plot2d.Lines");
  13862. dojo.declare("dojox.charting.plot2d.Lines", dojox.charting.plot2d.Default, {
  13863. // summary:
  13864. // A convenience constructor to create a typical line chart.
  13865. constructor: function(){
  13866. // summary:
  13867. // Preset our default plot to be line-based.
  13868. this.opt.lines = true;
  13869. }
  13870. });
  13871. }
  13872. if(!dojo._hasResource["dojox.charting.plot2d.Areas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13873. dojo._hasResource["dojox.charting.plot2d.Areas"] = true;
  13874. dojo.provide("dojox.charting.plot2d.Areas");
  13875. dojo.declare("dojox.charting.plot2d.Areas", dojox.charting.plot2d.Default, {
  13876. // summary:
  13877. // Represents an area chart. See dojox.charting.plot2d.Default for details.
  13878. constructor: function(){
  13879. this.opt.lines = true;
  13880. this.opt.areas = true;
  13881. }
  13882. });
  13883. }
  13884. if(!dojo._hasResource["dojox.charting.plot2d.Markers"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13885. dojo._hasResource["dojox.charting.plot2d.Markers"] = true;
  13886. dojo.provide("dojox.charting.plot2d.Markers");
  13887. dojo.declare("dojox.charting.plot2d.Markers", dojox.charting.plot2d.Default, {
  13888. // summary:
  13889. // A convenience plot to draw a line chart with markers.
  13890. constructor: function(){
  13891. // summary:
  13892. // Set up the plot for lines and markers.
  13893. this.opt.markers = true;
  13894. }
  13895. });
  13896. }
  13897. if(!dojo._hasResource["dojox.charting.plot2d.MarkersOnly"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13898. dojo._hasResource["dojox.charting.plot2d.MarkersOnly"] = true;
  13899. dojo.provide("dojox.charting.plot2d.MarkersOnly");
  13900. dojo.declare("dojox.charting.plot2d.MarkersOnly", dojox.charting.plot2d.Default, {
  13901. // summary:
  13902. // A convenience object to draw only markers (like a scatter but not quite).
  13903. constructor: function(){
  13904. // summary:
  13905. // Set up our default plot to only have markers and no lines.
  13906. this.opt.lines = false;
  13907. this.opt.markers = true;
  13908. }
  13909. });
  13910. }
  13911. if(!dojo._hasResource["dojox.charting.plot2d.Scatter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  13912. dojo._hasResource["dojox.charting.plot2d.Scatter"] = true;
  13913. dojo.provide("dojox.charting.plot2d.Scatter");
  13914. (function(){
  13915. var df = dojox.lang.functional, du = dojox.lang.utils,
  13916. dc = dojox.charting.plot2d.common,
  13917. purgeGroup = df.lambda("item.purgeGroup()");
  13918. dojo.declare("dojox.charting.plot2d.Scatter", dojox.charting.plot2d.Base, {
  13919. // summary:
  13920. // A plot object representing a typical scatter chart.
  13921. defaultParams: {
  13922. hAxis: "x", // use a horizontal axis named "x"
  13923. vAxis: "y", // use a vertical axis named "y"
  13924. shadows: null, // draw shadows
  13925. animate: null // animate chart to place
  13926. },
  13927. optionalParams: {
  13928. // theme component
  13929. markerStroke: {},
  13930. markerOutline: {},
  13931. markerShadow: {},
  13932. markerFill: {},
  13933. markerFont: "",
  13934. markerFontColor: ""
  13935. },
  13936. constructor: function(chart, kwArgs){
  13937. // summary:
  13938. // Create the scatter plot.
  13939. // chart: dojox.charting.Chart2D
  13940. // The chart this plot belongs to.
  13941. // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs?
  13942. // An optional keyword arguments object to help define this plot's parameters.
  13943. this.opt = dojo.clone(this.defaultParams);
  13944. du.updateWithObject(this.opt, kwArgs);
  13945. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  13946. this.series = [];
  13947. this.hAxis = this.opt.hAxis;
  13948. this.vAxis = this.opt.vAxis;
  13949. this.animate = this.opt.animate;
  13950. },
  13951. render: function(dim, offsets){
  13952. // summary:
  13953. // Run the calculations for any axes for this plot.
  13954. // dim: Object
  13955. // An object in the form of { width, height }
  13956. // offsets: Object
  13957. // An object of the form { l, r, t, b}.
  13958. // returns: dojox.charting.plot2d.Scatter
  13959. // A reference to this plot for functional chaining.
  13960. if(this.zoom && !this.isDataDirty()){
  13961. return this.performZoom(dim, offsets);
  13962. }
  13963. this.resetEvents();
  13964. this.dirty = this.isDirty();
  13965. if(this.dirty){
  13966. dojo.forEach(this.series, purgeGroup);
  13967. this._eventSeries = {};
  13968. this.cleanGroup();
  13969. var s = this.group;
  13970. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  13971. }
  13972. var t = this.chart.theme, events = this.events();
  13973. for(var i = this.series.length - 1; i >= 0; --i){
  13974. var run = this.series[i];
  13975. if(!this.dirty && !run.dirty){
  13976. t.skip();
  13977. this._reconnectEvents(run.name);
  13978. continue;
  13979. }
  13980. run.cleanGroup();
  13981. if(!run.data.length){
  13982. run.dirty = false;
  13983. t.skip();
  13984. continue;
  13985. }
  13986. var theme = t.next("marker", [this.opt, run]), s = run.group, lpoly,
  13987. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  13988. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler);
  13989. if(typeof run.data[0] == "number"){
  13990. lpoly = dojo.map(run.data, function(v, i){
  13991. return {
  13992. x: ht(i + 1) + offsets.l,
  13993. y: dim.height - offsets.b - vt(v)
  13994. };
  13995. }, this);
  13996. }else{
  13997. lpoly = dojo.map(run.data, function(v, i){
  13998. return {
  13999. x: ht(v.x) + offsets.l,
  14000. y: dim.height - offsets.b - vt(v.y)
  14001. };
  14002. }, this);
  14003. }
  14004. var shadowMarkers = new Array(lpoly.length),
  14005. frontMarkers = new Array(lpoly.length),
  14006. outlineMarkers = new Array(lpoly.length);
  14007. dojo.forEach(lpoly, function(c, i){
  14008. var finalTheme = typeof run.data[i] == "number" ?
  14009. t.post(theme, "marker") :
  14010. t.addMixin(theme, "marker", run.data[i], true),
  14011. path = "M" + c.x + " " + c.y + " " + finalTheme.symbol;
  14012. if(finalTheme.marker.shadow){
  14013. shadowMarkers[i] = s.createPath("M" + (c.x + finalTheme.marker.shadow.dx) + " " +
  14014. (c.y + finalTheme.marker.shadow.dy) + " " + finalTheme.symbol).
  14015. setStroke(finalTheme.marker.shadow).setFill(finalTheme.marker.shadow.color);
  14016. if(this.animate){
  14017. this._animateScatter(shadowMarkers[i], dim.height - offsets.b);
  14018. }
  14019. }
  14020. if(finalTheme.marker.outline){
  14021. var outline = dc.makeStroke(finalTheme.marker.outline);
  14022. outline.width = 2 * outline.width + finalTheme.marker.stroke.width;
  14023. outlineMarkers[i] = s.createPath(path).setStroke(outline);
  14024. if(this.animate){
  14025. this._animateScatter(outlineMarkers[i], dim.height - offsets.b);
  14026. }
  14027. }
  14028. var stroke = dc.makeStroke(finalTheme.marker.stroke),
  14029. fill = this._plotFill(finalTheme.marker.fill, dim, offsets);
  14030. if(fill && (fill.type === "linear" || fill.type == "radial")){
  14031. var color = dojox.gfx.gradutils.getColor(fill, {x: c.x, y: c.y});
  14032. if(stroke){
  14033. stroke.color = color;
  14034. }
  14035. frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(color);
  14036. }else{
  14037. frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(fill);
  14038. }
  14039. if(this.animate){
  14040. this._animateScatter(frontMarkers[i], dim.height - offsets.b);
  14041. }
  14042. }, this);
  14043. if(frontMarkers.length){
  14044. run.dyn.stroke = frontMarkers[frontMarkers.length - 1].getStroke();
  14045. run.dyn.fill = frontMarkers[frontMarkers.length - 1].getFill();
  14046. }
  14047. if(events){
  14048. var eventSeries = new Array(frontMarkers.length);
  14049. dojo.forEach(frontMarkers, function(s, i){
  14050. var o = {
  14051. element: "marker",
  14052. index: i,
  14053. run: run,
  14054. shape: s,
  14055. outline: outlineMarkers && outlineMarkers[i] || null,
  14056. shadow: shadowMarkers && shadowMarkers[i] || null,
  14057. cx: lpoly[i].x,
  14058. cy: lpoly[i].y
  14059. };
  14060. if(typeof run.data[0] == "number"){
  14061. o.x = i + 1;
  14062. o.y = run.data[i];
  14063. }else{
  14064. o.x = run.data[i].x;
  14065. o.y = run.data[i].y;
  14066. }
  14067. this._connectEvents(o);
  14068. eventSeries[i] = o;
  14069. }, this);
  14070. this._eventSeries[run.name] = eventSeries;
  14071. }else{
  14072. delete this._eventSeries[run.name];
  14073. }
  14074. run.dirty = false;
  14075. }
  14076. this.dirty = false;
  14077. return this; // dojox.charting.plot2d.Scatter
  14078. },
  14079. _animateScatter: function(shape, offset){
  14080. dojox.gfx.fx.animateTransform(dojo.delegate({
  14081. shape: shape,
  14082. duration: 1200,
  14083. transform: [
  14084. {name: "translate", start: [0, offset], end: [0, 0]},
  14085. {name: "scale", start: [0, 0], end: [1, 1]},
  14086. {name: "original"}
  14087. ]
  14088. }, this.animate)).play();
  14089. }
  14090. });
  14091. })();
  14092. }
  14093. if(!dojo._hasResource["dojox.lang.functional.sequence"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14094. dojo._hasResource["dojox.lang.functional.sequence"] = true;
  14095. dojo.provide("dojox.lang.functional.sequence");
  14096. // This module adds high-level functions and related constructs:
  14097. // - sequence generators
  14098. // If you want more general sequence builders check out listcomp.js and
  14099. // unfold() (in fold.js).
  14100. // Defined methods:
  14101. // - take any valid lambda argument as the functional argument
  14102. (function(){
  14103. var d = dojo, df = dojox.lang.functional;
  14104. d.mixin(df, {
  14105. // sequence generators
  14106. repeat: function(/*Number*/ n, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  14107. // summary: builds an array by repeatedly applying a unary function N times
  14108. // with a seed value Z. N should be greater than 0.
  14109. o = o || d.global; f = df.lambda(f);
  14110. var t = new Array(n), i = 1;
  14111. t[0] = z;
  14112. for(; i < n; t[i] = z = f.call(o, z), ++i);
  14113. return t; // Array
  14114. },
  14115. until: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){
  14116. // summary: builds an array by repeatedly applying a unary function with
  14117. // a seed value Z until the predicate is satisfied.
  14118. o = o || d.global; f = df.lambda(f); pr = df.lambda(pr);
  14119. var t = [];
  14120. for(; !pr.call(o, z); t.push(z), z = f.call(o, z));
  14121. return t; // Array
  14122. }
  14123. });
  14124. })();
  14125. }
  14126. if(!dojo._hasResource["dojox.charting.plot2d.Stacked"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14127. dojo._hasResource["dojox.charting.plot2d.Stacked"] = true;
  14128. dojo.provide("dojox.charting.plot2d.Stacked");
  14129. (function(){
  14130. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common,
  14131. purgeGroup = df.lambda("item.purgeGroup()");
  14132. dojo.declare("dojox.charting.plot2d.Stacked", dojox.charting.plot2d.Default, {
  14133. // summary:
  14134. // Like the default plot, Stacked sets up lines, areas and markers
  14135. // in a stacked fashion (values on the y axis added to each other)
  14136. // as opposed to a direct one.
  14137. getSeriesStats: function(){
  14138. // summary:
  14139. // Calculate the min/max on all attached series in both directions.
  14140. // returns: Object
  14141. // {hmin, hmax, vmin, vmax} min/max in both directions.
  14142. var stats = dc.collectStackedStats(this.series);
  14143. this._maxRunLength = stats.hmax;
  14144. return stats;
  14145. },
  14146. render: function(dim, offsets){
  14147. // summary:
  14148. // Run the calculations for any axes for this plot.
  14149. // dim: Object
  14150. // An object in the form of { width, height }
  14151. // offsets: Object
  14152. // An object of the form { l, r, t, b}.
  14153. // returns: dojox.charting.plot2d.Stacked
  14154. // A reference to this plot for functional chaining.
  14155. if(this._maxRunLength <= 0){
  14156. return this;
  14157. }
  14158. // stack all values
  14159. var acc = df.repeat(this._maxRunLength, "-> 0", 0);
  14160. for(var i = 0; i < this.series.length; ++i){
  14161. var run = this.series[i];
  14162. for(var j = 0; j < run.data.length; ++j){
  14163. var v = run.data[j];
  14164. if(v !== null){
  14165. if(isNaN(v)){ v = 0; }
  14166. acc[j] += v;
  14167. }
  14168. }
  14169. }
  14170. // draw runs in backwards
  14171. if(this.zoom && !this.isDataDirty()){
  14172. return this.performZoom(dim, offsets);
  14173. }
  14174. this.resetEvents();
  14175. this.dirty = this.isDirty();
  14176. if(this.dirty){
  14177. dojo.forEach(this.series, purgeGroup);
  14178. this._eventSeries = {};
  14179. this.cleanGroup();
  14180. var s = this.group;
  14181. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14182. }
  14183. var t = this.chart.theme, events = this.events(),
  14184. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14185. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler);
  14186. for(var i = this.series.length - 1; i >= 0; --i){
  14187. var run = this.series[i];
  14188. if(!this.dirty && !run.dirty){
  14189. t.skip();
  14190. this._reconnectEvents(run.name);
  14191. continue;
  14192. }
  14193. run.cleanGroup();
  14194. var theme = t.next(this.opt.areas ? "area" : "line", [this.opt, run], true),
  14195. s = run.group, outline,
  14196. lpoly = dojo.map(acc, function(v, i){
  14197. return {
  14198. x: ht(i + 1) + offsets.l,
  14199. y: dim.height - offsets.b - vt(v)
  14200. };
  14201. }, this);
  14202. var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : "";
  14203. if(this.opt.areas){
  14204. var apoly = dojo.clone(lpoly);
  14205. if(this.opt.tension){
  14206. var p=dc.curve(apoly, this.opt.tension);
  14207. p += " L" + lpoly[lpoly.length - 1].x + "," + (dim.height - offsets.b) +
  14208. " L" + lpoly[0].x + "," + (dim.height - offsets.b) +
  14209. " L" + lpoly[0].x + "," + lpoly[0].y;
  14210. run.dyn.fill = s.createPath(p).setFill(theme.series.fill).getFill();
  14211. } else {
  14212. apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b});
  14213. apoly.push({x: lpoly[0].x, y: dim.height - offsets.b});
  14214. apoly.push(lpoly[0]);
  14215. run.dyn.fill = s.createPolyline(apoly).setFill(theme.series.fill).getFill();
  14216. }
  14217. }
  14218. if(this.opt.lines || this.opt.markers){
  14219. if(theme.series.outline){
  14220. outline = dc.makeStroke(theme.series.outline);
  14221. outline.width = 2 * outline.width + theme.series.stroke.width;
  14222. }
  14223. }
  14224. if(this.opt.markers){
  14225. run.dyn.marker = theme.symbol;
  14226. }
  14227. var frontMarkers, outlineMarkers, shadowMarkers;
  14228. if(theme.series.shadow && theme.series.stroke){
  14229. var shadow = theme.series.shadow,
  14230. spoly = dojo.map(lpoly, function(c){
  14231. return {x: c.x + shadow.dx, y: c.y + shadow.dy};
  14232. });
  14233. if(this.opt.lines){
  14234. if(this.opt.tension){
  14235. run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadow).getStroke();
  14236. } else {
  14237. run.dyn.shadow = s.createPolyline(spoly).setStroke(shadow).getStroke();
  14238. }
  14239. }
  14240. if(this.opt.markers){
  14241. shadow = theme.marker.shadow;
  14242. shadowMarkers = dojo.map(spoly, function(c){
  14243. return s.createPath("M" + c.x + " " + c.y + " " + theme.symbol).
  14244. setStroke(shadow).setFill(shadow.color);
  14245. }, this);
  14246. }
  14247. }
  14248. if(this.opt.lines){
  14249. if(outline){
  14250. if(this.opt.tension){
  14251. run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke();
  14252. } else {
  14253. run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke();
  14254. }
  14255. }
  14256. if(this.opt.tension){
  14257. run.dyn.stroke = s.createPath(lpath).setStroke(theme.series.stroke).getStroke();
  14258. } else {
  14259. run.dyn.stroke = s.createPolyline(lpoly).setStroke(theme.series.stroke).getStroke();
  14260. }
  14261. }
  14262. if(this.opt.markers){
  14263. frontMarkers = new Array(lpoly.length);
  14264. outlineMarkers = new Array(lpoly.length);
  14265. outline = null;
  14266. if(theme.marker.outline){
  14267. outline = dc.makeStroke(theme.marker.outline);
  14268. outline.width = 2 * outline.width + (theme.marker.stroke ? theme.marker.stroke.width : 0);
  14269. }
  14270. dojo.forEach(lpoly, function(c, i){
  14271. var path = "M" + c.x + " " + c.y + " " + theme.symbol;
  14272. if(outline){
  14273. outlineMarkers[i] = s.createPath(path).setStroke(outline);
  14274. }
  14275. frontMarkers[i] = s.createPath(path).setStroke(theme.marker.stroke).setFill(theme.marker.fill);
  14276. }, this);
  14277. if(events){
  14278. var eventSeries = new Array(frontMarkers.length);
  14279. dojo.forEach(frontMarkers, function(s, i){
  14280. var o = {
  14281. element: "marker",
  14282. index: i,
  14283. run: run,
  14284. shape: s,
  14285. outline: outlineMarkers[i] || null,
  14286. shadow: shadowMarkers && shadowMarkers[i] || null,
  14287. cx: lpoly[i].x,
  14288. cy: lpoly[i].y,
  14289. x: i + 1,
  14290. y: run.data[i]
  14291. };
  14292. this._connectEvents(o);
  14293. eventSeries[i] = o;
  14294. }, this);
  14295. this._eventSeries[run.name] = eventSeries;
  14296. }else{
  14297. delete this._eventSeries[run.name];
  14298. }
  14299. }
  14300. run.dirty = false;
  14301. // update the accumulator
  14302. for(var j = 0; j < run.data.length; ++j){
  14303. var v = run.data[j];
  14304. if(v !== null){
  14305. if(isNaN(v)){ v = 0; }
  14306. acc[j] -= v;
  14307. }
  14308. }
  14309. }
  14310. this.dirty = false;
  14311. return this; // dojox.charting.plot2d.Stacked
  14312. }
  14313. });
  14314. })();
  14315. }
  14316. if(!dojo._hasResource["dojox.charting.plot2d.StackedLines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14317. dojo._hasResource["dojox.charting.plot2d.StackedLines"] = true;
  14318. dojo.provide("dojox.charting.plot2d.StackedLines");
  14319. dojo.declare("dojox.charting.plot2d.StackedLines", dojox.charting.plot2d.Stacked, {
  14320. // summary:
  14321. // A convenience object to create a stacked line chart.
  14322. constructor: function(){
  14323. // summary:
  14324. // Force our Stacked base to be lines only.
  14325. this.opt.lines = true;
  14326. }
  14327. });
  14328. }
  14329. if(!dojo._hasResource["dojox.charting.plot2d.StackedAreas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14330. dojo._hasResource["dojox.charting.plot2d.StackedAreas"] = true;
  14331. dojo.provide("dojox.charting.plot2d.StackedAreas");
  14332. dojo.declare("dojox.charting.plot2d.StackedAreas", dojox.charting.plot2d.Stacked, {
  14333. // summary:
  14334. // A convenience object to set up a stacked area plot.
  14335. constructor: function(){
  14336. // summary:
  14337. // Force our Stacked plotter to include both lines and areas.
  14338. this.opt.lines = true;
  14339. this.opt.areas = true;
  14340. }
  14341. });
  14342. }
  14343. if(!dojo._hasResource["dojox.charting.plot2d.Columns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14344. dojo._hasResource["dojox.charting.plot2d.Columns"] = true;
  14345. dojo.provide("dojox.charting.plot2d.Columns");
  14346. (function(){
  14347. var df = dojox.lang.functional, du = dojox.lang.utils,
  14348. dc = dojox.charting.plot2d.common,
  14349. purgeGroup = df.lambda("item.purgeGroup()");
  14350. dojo.declare("dojox.charting.plot2d.Columns", dojox.charting.plot2d.Base, {
  14351. // summary:
  14352. // The plot object representing a column chart (vertical bars).
  14353. defaultParams: {
  14354. hAxis: "x", // use a horizontal axis named "x"
  14355. vAxis: "y", // use a vertical axis named "y"
  14356. gap: 0, // gap between columns in pixels
  14357. animate: null // animate bars into place
  14358. },
  14359. optionalParams: {
  14360. minBarSize: 1, // minimal column width in pixels
  14361. maxBarSize: 1, // maximal column width in pixels
  14362. // theme component
  14363. stroke: {},
  14364. outline: {},
  14365. shadow: {},
  14366. fill: {},
  14367. font: "",
  14368. fontColor: ""
  14369. },
  14370. constructor: function(chart, kwArgs){
  14371. // summary:
  14372. // The constructor for a columns chart.
  14373. // chart: dojox.charting.Chart2D
  14374. // The chart this plot belongs to.
  14375. // kwArgs: dojox.charting.plot2d.__BarCtorArgs?
  14376. // An optional keyword arguments object to help define the plot.
  14377. this.opt = dojo.clone(this.defaultParams);
  14378. du.updateWithObject(this.opt, kwArgs);
  14379. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  14380. this.series = [];
  14381. this.hAxis = this.opt.hAxis;
  14382. this.vAxis = this.opt.vAxis;
  14383. this.animate = this.opt.animate;
  14384. },
  14385. getSeriesStats: function(){
  14386. // summary:
  14387. // Calculate the min/max on all attached series in both directions.
  14388. // returns: Object
  14389. // {hmin, hmax, vmin, vmax} min/max in both directions.
  14390. var stats = dc.collectSimpleStats(this.series);
  14391. stats.hmin -= 0.5;
  14392. stats.hmax += 0.5;
  14393. return stats;
  14394. },
  14395. render: function(dim, offsets){
  14396. // summary:
  14397. // Run the calculations for any axes for this plot.
  14398. // dim: Object
  14399. // An object in the form of { width, height }
  14400. // offsets: Object
  14401. // An object of the form { l, r, t, b}.
  14402. // returns: dojox.charting.plot2d.Columns
  14403. // A reference to this plot for functional chaining.
  14404. if(this.zoom && !this.isDataDirty()){
  14405. return this.performZoom(dim, offsets);
  14406. }
  14407. this.resetEvents();
  14408. this.dirty = this.isDirty();
  14409. if(this.dirty){
  14410. dojo.forEach(this.series, purgeGroup);
  14411. this._eventSeries = {};
  14412. this.cleanGroup();
  14413. var s = this.group;
  14414. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14415. }
  14416. var t = this.chart.theme, f, gap, width,
  14417. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14418. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  14419. baseline = Math.max(0, this._vScaler.bounds.lower),
  14420. baselineHeight = vt(baseline),
  14421. events = this.events();
  14422. f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt);
  14423. gap = f.gap;
  14424. width = f.size;
  14425. for(var i = this.series.length - 1; i >= 0; --i){
  14426. var run = this.series[i];
  14427. if(!this.dirty && !run.dirty){
  14428. t.skip();
  14429. this._reconnectEvents(run.name);
  14430. continue;
  14431. }
  14432. run.cleanGroup();
  14433. var theme = t.next("column", [this.opt, run]), s = run.group,
  14434. eventSeries = new Array(run.data.length);
  14435. for(var j = 0; j < run.data.length; ++j){
  14436. var value = run.data[j];
  14437. if(value !== null){
  14438. var v = typeof value == "number" ? value : value.y,
  14439. vv = vt(v),
  14440. height = vv - baselineHeight,
  14441. h = Math.abs(height),
  14442. finalTheme = typeof value != "number" ?
  14443. t.addMixin(theme, "column", value, true) :
  14444. t.post(theme, "column");
  14445. if(width >= 1 && h >= 0){
  14446. var rect = {
  14447. x: offsets.l + ht(j + 0.5) + gap,
  14448. y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight),
  14449. width: width, height: h
  14450. };
  14451. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  14452. specialFill = this._shapeFill(specialFill, rect);
  14453. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  14454. run.dyn.fill = shape.getFill();
  14455. run.dyn.stroke = shape.getStroke();
  14456. if(events){
  14457. var o = {
  14458. element: "column",
  14459. index: j,
  14460. run: run,
  14461. shape: shape,
  14462. x: j + 0.5,
  14463. y: v
  14464. };
  14465. this._connectEvents(o);
  14466. eventSeries[j] = o;
  14467. }
  14468. if(this.animate){
  14469. this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h);
  14470. }
  14471. }
  14472. }
  14473. }
  14474. this._eventSeries[run.name] = eventSeries;
  14475. run.dirty = false;
  14476. }
  14477. this.dirty = false;
  14478. return this; // dojox.charting.plot2d.Columns
  14479. },
  14480. _animateColumn: function(shape, voffset, vsize){
  14481. dojox.gfx.fx.animateTransform(dojo.delegate({
  14482. shape: shape,
  14483. duration: 1200,
  14484. transform: [
  14485. {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]},
  14486. {name: "scale", start: [1, 1/vsize], end: [1, 1]},
  14487. {name: "original"}
  14488. ]
  14489. }, this.animate)).play();
  14490. }
  14491. });
  14492. })();
  14493. }
  14494. if(!dojo._hasResource["dojox.charting.plot2d.StackedColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14495. dojo._hasResource["dojox.charting.plot2d.StackedColumns"] = true;
  14496. dojo.provide("dojox.charting.plot2d.StackedColumns");
  14497. (function(){
  14498. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common,
  14499. purgeGroup = df.lambda("item.purgeGroup()");
  14500. dojo.declare("dojox.charting.plot2d.StackedColumns", dojox.charting.plot2d.Columns, {
  14501. // summary:
  14502. // The plot object representing a stacked column chart (vertical bars).
  14503. getSeriesStats: function(){
  14504. // summary:
  14505. // Calculate the min/max on all attached series in both directions.
  14506. // returns: Object
  14507. // {hmin, hmax, vmin, vmax} min/max in both directions.
  14508. var stats = dc.collectStackedStats(this.series);
  14509. this._maxRunLength = stats.hmax;
  14510. stats.hmin -= 0.5;
  14511. stats.hmax += 0.5;
  14512. return stats;
  14513. },
  14514. render: function(dim, offsets){
  14515. // summary:
  14516. // Run the calculations for any axes for this plot.
  14517. // dim: Object
  14518. // An object in the form of { width, height }
  14519. // offsets: Object
  14520. // An object of the form { l, r, t, b}.
  14521. // returns: dojox.charting.plot2d.StackedColumns
  14522. // A reference to this plot for functional chaining.
  14523. if(this._maxRunLength <= 0){
  14524. return this;
  14525. }
  14526. // stack all values
  14527. var acc = df.repeat(this._maxRunLength, "-> 0", 0);
  14528. for(var i = 0; i < this.series.length; ++i){
  14529. var run = this.series[i];
  14530. for(var j = 0; j < run.data.length; ++j){
  14531. var value = run.data[j];
  14532. if(value !== null){
  14533. var v = typeof value == "number" ? value : value.y;
  14534. if(isNaN(v)){ v = 0; }
  14535. acc[j] += v;
  14536. }
  14537. }
  14538. }
  14539. // draw runs in backwards
  14540. if(this.zoom && !this.isDataDirty()){
  14541. return this.performZoom(dim, offsets);
  14542. }
  14543. this.resetEvents();
  14544. this.dirty = this.isDirty();
  14545. if(this.dirty){
  14546. dojo.forEach(this.series, purgeGroup);
  14547. this._eventSeries = {};
  14548. this.cleanGroup();
  14549. var s = this.group;
  14550. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14551. }
  14552. var t = this.chart.theme, f, gap, width,
  14553. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14554. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  14555. events = this.events();
  14556. f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt);
  14557. gap = f.gap;
  14558. width = f.size;
  14559. for(var i = this.series.length - 1; i >= 0; --i){
  14560. var run = this.series[i];
  14561. if(!this.dirty && !run.dirty){
  14562. t.skip();
  14563. this._reconnectEvents(run.name);
  14564. continue;
  14565. }
  14566. run.cleanGroup();
  14567. var theme = t.next("column", [this.opt, run]), s = run.group,
  14568. eventSeries = new Array(acc.length);
  14569. for(var j = 0; j < acc.length; ++j){
  14570. var value = run.data[j];
  14571. if(value !== null){
  14572. var v = acc[j],
  14573. height = vt(v),
  14574. finalTheme = typeof value != "number" ?
  14575. t.addMixin(theme, "column", value, true) :
  14576. t.post(theme, "column");
  14577. if(width >= 1 && height >= 0){
  14578. var rect = {
  14579. x: offsets.l + ht(j + 0.5) + gap,
  14580. y: dim.height - offsets.b - vt(v),
  14581. width: width, height: height
  14582. };
  14583. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  14584. specialFill = this._shapeFill(specialFill, rect);
  14585. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  14586. run.dyn.fill = shape.getFill();
  14587. run.dyn.stroke = shape.getStroke();
  14588. if(events){
  14589. var o = {
  14590. element: "column",
  14591. index: j,
  14592. run: run,
  14593. shape: shape,
  14594. x: j + 0.5,
  14595. y: v
  14596. };
  14597. this._connectEvents(o);
  14598. eventSeries[j] = o;
  14599. }
  14600. if(this.animate){
  14601. this._animateColumn(shape, dim.height - offsets.b, height);
  14602. }
  14603. }
  14604. }
  14605. }
  14606. this._eventSeries[run.name] = eventSeries;
  14607. run.dirty = false;
  14608. // update the accumulator
  14609. for(var j = 0; j < run.data.length; ++j){
  14610. var value = run.data[j];
  14611. if(value !== null){
  14612. var v = typeof value == "number" ? value : value.y;
  14613. if(isNaN(v)){ v = 0; }
  14614. acc[j] -= v;
  14615. }
  14616. }
  14617. }
  14618. this.dirty = false;
  14619. return this; // dojox.charting.plot2d.StackedColumns
  14620. }
  14621. });
  14622. })();
  14623. }
  14624. if(!dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14625. dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"] = true;
  14626. dojo.provide("dojox.charting.plot2d.ClusteredColumns");
  14627. (function(){
  14628. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common,
  14629. purgeGroup = df.lambda("item.purgeGroup()");
  14630. dojo.declare("dojox.charting.plot2d.ClusteredColumns", dojox.charting.plot2d.Columns, {
  14631. // summary:
  14632. // A plot representing grouped or clustered columns (vertical bars).
  14633. render: function(dim, offsets){
  14634. // summary:
  14635. // Run the calculations for any axes for this plot.
  14636. // dim: Object
  14637. // An object in the form of { width, height }
  14638. // offsets: Object
  14639. // An object of the form { l, r, t, b}.
  14640. // returns: dojox.charting.plot2d.ClusteredColumns
  14641. // A reference to this plot for functional chaining.
  14642. if(this.zoom && !this.isDataDirty()){
  14643. return this.performZoom(dim, offsets);
  14644. }
  14645. this.resetEvents();
  14646. this.dirty = this.isDirty();
  14647. if(this.dirty){
  14648. dojo.forEach(this.series, purgeGroup);
  14649. this._eventSeries = {};
  14650. this.cleanGroup();
  14651. var s = this.group;
  14652. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14653. }
  14654. var t = this.chart.theme, f, gap, width, thickness,
  14655. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14656. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  14657. baseline = Math.max(0, this._vScaler.bounds.lower),
  14658. baselineHeight = vt(baseline),
  14659. events = this.events();
  14660. f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt, this.series.length);
  14661. gap = f.gap;
  14662. width = thickness = f.size;
  14663. for(var i = 0; i < this.series.length; ++i){
  14664. var run = this.series[i], shift = thickness * i;
  14665. if(!this.dirty && !run.dirty){
  14666. t.skip();
  14667. this._reconnectEvents(run.name);
  14668. continue;
  14669. }
  14670. run.cleanGroup();
  14671. var theme = t.next("column", [this.opt, run]), s = run.group,
  14672. eventSeries = new Array(run.data.length);
  14673. for(var j = 0; j < run.data.length; ++j){
  14674. var value = run.data[j];
  14675. if(value !== null){
  14676. var v = typeof value == "number" ? value : value.y,
  14677. vv = vt(v),
  14678. height = vv - baselineHeight,
  14679. h = Math.abs(height),
  14680. finalTheme = typeof value != "number" ?
  14681. t.addMixin(theme, "column", value, true) :
  14682. t.post(theme, "column");
  14683. if(width >= 1 && h >= 0){
  14684. var rect = {
  14685. x: offsets.l + ht(j + 0.5) + gap + shift,
  14686. y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight),
  14687. width: width, height: h
  14688. };
  14689. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  14690. specialFill = this._shapeFill(specialFill, rect);
  14691. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  14692. run.dyn.fill = shape.getFill();
  14693. run.dyn.stroke = shape.getStroke();
  14694. if(events){
  14695. var o = {
  14696. element: "column",
  14697. index: j,
  14698. run: run,
  14699. shape: shape,
  14700. x: j + 0.5,
  14701. y: v
  14702. };
  14703. this._connectEvents(o);
  14704. eventSeries[j] = o;
  14705. }
  14706. if(this.animate){
  14707. this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h);
  14708. }
  14709. }
  14710. }
  14711. }
  14712. this._eventSeries[run.name] = eventSeries;
  14713. run.dirty = false;
  14714. }
  14715. this.dirty = false;
  14716. return this; // dojox.charting.plot2d.ClusteredColumns
  14717. }
  14718. });
  14719. })();
  14720. }
  14721. if(!dojo._hasResource["dojox.charting.plot2d.Bars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14722. dojo._hasResource["dojox.charting.plot2d.Bars"] = true;
  14723. dojo.provide("dojox.charting.plot2d.Bars");
  14724. /*=====
  14725. dojo.declare("dojox.charting.plot2d.__BarCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, {
  14726. // summary:
  14727. // Additional keyword arguments for bar charts.
  14728. // minBarSize: Number?
  14729. // The minimum size for a bar in pixels. Default is 1.
  14730. minBarSize: 1,
  14731. // maxBarSize: Number?
  14732. // The maximum size for a bar in pixels. Default is 1.
  14733. maxBarSize: 1
  14734. });
  14735. =====*/
  14736. (function(){
  14737. var df = dojox.lang.functional, du = dojox.lang.utils,
  14738. dc = dojox.charting.plot2d.common,
  14739. purgeGroup = df.lambda("item.purgeGroup()");
  14740. dojo.declare("dojox.charting.plot2d.Bars", dojox.charting.plot2d.Base, {
  14741. // summary:
  14742. // The plot object representing a bar chart (horizontal bars).
  14743. defaultParams: {
  14744. hAxis: "x", // use a horizontal axis named "x"
  14745. vAxis: "y", // use a vertical axis named "y"
  14746. gap: 0, // gap between columns in pixels
  14747. animate: null // animate bars into place
  14748. },
  14749. optionalParams: {
  14750. minBarSize: 1, // minimal bar width in pixels
  14751. maxBarSize: 1, // maximal bar width in pixels
  14752. // theme component
  14753. stroke: {},
  14754. outline: {},
  14755. shadow: {},
  14756. fill: {},
  14757. font: "",
  14758. fontColor: ""
  14759. },
  14760. constructor: function(chart, kwArgs){
  14761. // summary:
  14762. // The constructor for a bar chart.
  14763. // chart: dojox.charting.Chart2D
  14764. // The chart this plot belongs to.
  14765. // kwArgs: dojox.charting.plot2d.__BarCtorArgs?
  14766. // An optional keyword arguments object to help define the plot.
  14767. this.opt = dojo.clone(this.defaultParams);
  14768. du.updateWithObject(this.opt, kwArgs);
  14769. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  14770. this.series = [];
  14771. this.hAxis = this.opt.hAxis;
  14772. this.vAxis = this.opt.vAxis;
  14773. this.animate = this.opt.animate;
  14774. },
  14775. getSeriesStats: function(){
  14776. // summary:
  14777. // Calculate the min/max on all attached series in both directions.
  14778. // returns: Object
  14779. // {hmin, hmax, vmin, vmax} min/max in both directions.
  14780. var stats = dc.collectSimpleStats(this.series), t;
  14781. stats.hmin -= 0.5;
  14782. stats.hmax += 0.5;
  14783. t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t;
  14784. t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t;
  14785. return stats;
  14786. },
  14787. render: function(dim, offsets){
  14788. // summary:
  14789. // Run the calculations for any axes for this plot.
  14790. // dim: Object
  14791. // An object in the form of { width, height }
  14792. // offsets: Object
  14793. // An object of the form { l, r, t, b}.
  14794. // returns: dojox.charting.plot2d.Bars
  14795. // A reference to this plot for functional chaining.
  14796. if(this.zoom && !this.isDataDirty()){
  14797. return this.performZoom(dim, offsets);
  14798. }
  14799. this.dirty = this.isDirty();
  14800. this.resetEvents();
  14801. if(this.dirty){
  14802. dojo.forEach(this.series, purgeGroup);
  14803. this._eventSeries = {};
  14804. this.cleanGroup();
  14805. var s = this.group;
  14806. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14807. }
  14808. var t = this.chart.theme, f, gap, height,
  14809. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14810. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  14811. baseline = Math.max(0, this._hScaler.bounds.lower),
  14812. baselineWidth = ht(baseline),
  14813. events = this.events();
  14814. f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt);
  14815. gap = f.gap;
  14816. height = f.size;
  14817. for(var i = this.series.length - 1; i >= 0; --i){
  14818. var run = this.series[i];
  14819. if(!this.dirty && !run.dirty){
  14820. t.skip();
  14821. this._reconnectEvents(run.name);
  14822. continue;
  14823. }
  14824. run.cleanGroup();
  14825. var theme = t.next("bar", [this.opt, run]), s = run.group,
  14826. eventSeries = new Array(run.data.length);
  14827. for(var j = 0; j < run.data.length; ++j){
  14828. var value = run.data[j];
  14829. if(value !== null){
  14830. var v = typeof value == "number" ? value : value.y,
  14831. hv = ht(v),
  14832. width = hv - baselineWidth,
  14833. w = Math.abs(width),
  14834. finalTheme = typeof value != "number" ?
  14835. t.addMixin(theme, "bar", value, true) :
  14836. t.post(theme, "bar");
  14837. if(w >= 0 && height >= 1){
  14838. var rect = {
  14839. x: offsets.l + (v < baseline ? hv : baselineWidth),
  14840. y: dim.height - offsets.b - vt(j + 1.5) + gap,
  14841. width: w, height: height
  14842. };
  14843. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  14844. specialFill = this._shapeFill(specialFill, rect);
  14845. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  14846. run.dyn.fill = shape.getFill();
  14847. run.dyn.stroke = shape.getStroke();
  14848. if(events){
  14849. var o = {
  14850. element: "bar",
  14851. index: j,
  14852. run: run,
  14853. shape: shape,
  14854. x: v,
  14855. y: j + 1.5
  14856. };
  14857. this._connectEvents(o);
  14858. eventSeries[j] = o;
  14859. }
  14860. if(this.animate){
  14861. this._animateBar(shape, offsets.l + baselineWidth, -w);
  14862. }
  14863. }
  14864. }
  14865. }
  14866. this._eventSeries[run.name] = eventSeries;
  14867. run.dirty = false;
  14868. }
  14869. this.dirty = false;
  14870. return this; // dojox.charting.plot2d.Bars
  14871. },
  14872. _animateBar: function(shape, hoffset, hsize){
  14873. dojox.gfx.fx.animateTransform(dojo.delegate({
  14874. shape: shape,
  14875. duration: 1200,
  14876. transform: [
  14877. {name: "translate", start: [hoffset - (hoffset/hsize), 0], end: [0, 0]},
  14878. {name: "scale", start: [1/hsize, 1], end: [1, 1]},
  14879. {name: "original"}
  14880. ]
  14881. }, this.animate)).play();
  14882. }
  14883. });
  14884. })();
  14885. }
  14886. if(!dojo._hasResource["dojox.charting.plot2d.StackedBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  14887. dojo._hasResource["dojox.charting.plot2d.StackedBars"] = true;
  14888. dojo.provide("dojox.charting.plot2d.StackedBars");
  14889. (function(){
  14890. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common,
  14891. purgeGroup = df.lambda("item.purgeGroup()");
  14892. dojo.declare("dojox.charting.plot2d.StackedBars", dojox.charting.plot2d.Bars, {
  14893. // summary:
  14894. // The plot object representing a stacked bar chart (horizontal bars).
  14895. getSeriesStats: function(){
  14896. // summary:
  14897. // Calculate the min/max on all attached series in both directions.
  14898. // returns: Object
  14899. // {hmin, hmax, vmin, vmax} min/max in both directions.
  14900. var stats = dc.collectStackedStats(this.series), t;
  14901. this._maxRunLength = stats.hmax;
  14902. stats.hmin -= 0.5;
  14903. stats.hmax += 0.5;
  14904. t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t;
  14905. t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t;
  14906. return stats;
  14907. },
  14908. render: function(dim, offsets){
  14909. // summary:
  14910. // Run the calculations for any axes for this plot.
  14911. // dim: Object
  14912. // An object in the form of { width, height }
  14913. // offsets: Object
  14914. // An object of the form { l, r, t, b}.
  14915. // returns: dojox.charting.plot2d.StackedBars
  14916. // A reference to this plot for functional chaining.
  14917. if(this._maxRunLength <= 0){
  14918. return this;
  14919. }
  14920. // stack all values
  14921. var acc = df.repeat(this._maxRunLength, "-> 0", 0);
  14922. for(var i = 0; i < this.series.length; ++i){
  14923. var run = this.series[i];
  14924. for(var j = 0; j < run.data.length; ++j){
  14925. var value = run.data[j];
  14926. if(value !== null){
  14927. var v = typeof value == "number" ? value : value.y;
  14928. if(isNaN(v)){ v = 0; }
  14929. acc[j] += v;
  14930. }
  14931. }
  14932. }
  14933. // draw runs in backwards
  14934. if(this.zoom && !this.isDataDirty()){
  14935. return this.performZoom(dim, offsets);
  14936. }
  14937. this.resetEvents();
  14938. this.dirty = this.isDirty();
  14939. if(this.dirty){
  14940. dojo.forEach(this.series, purgeGroup);
  14941. this._eventSeries = {};
  14942. this.cleanGroup();
  14943. var s = this.group;
  14944. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  14945. }
  14946. var t = this.chart.theme, f, gap, height,
  14947. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  14948. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  14949. events = this.events();
  14950. f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt);
  14951. gap = f.gap;
  14952. height = f.size;
  14953. for(var i = this.series.length - 1; i >= 0; --i){
  14954. var run = this.series[i];
  14955. if(!this.dirty && !run.dirty){
  14956. t.skip();
  14957. this._reconnectEvents(run.name);
  14958. continue;
  14959. }
  14960. run.cleanGroup();
  14961. var theme = t.next("bar", [this.opt, run]), s = run.group,
  14962. eventSeries = new Array(acc.length);
  14963. for(var j = 0; j < acc.length; ++j){
  14964. var value = run.data[j];
  14965. if(value !== null){
  14966. var v = acc[j],
  14967. width = ht(v),
  14968. finalTheme = typeof value != "number" ?
  14969. t.addMixin(theme, "bar", value, true) :
  14970. t.post(theme, "bar");
  14971. if(width >= 0 && height >= 1){
  14972. var rect = {
  14973. x: offsets.l,
  14974. y: dim.height - offsets.b - vt(j + 1.5) + gap,
  14975. width: width, height: height
  14976. };
  14977. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  14978. specialFill = this._shapeFill(specialFill, rect);
  14979. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  14980. run.dyn.fill = shape.getFill();
  14981. run.dyn.stroke = shape.getStroke();
  14982. if(events){
  14983. var o = {
  14984. element: "bar",
  14985. index: j,
  14986. run: run,
  14987. shape: shape,
  14988. x: v,
  14989. y: j + 1.5
  14990. };
  14991. this._connectEvents(o);
  14992. eventSeries[j] = o;
  14993. }
  14994. if(this.animate){
  14995. this._animateBar(shape, offsets.l, -width);
  14996. }
  14997. }
  14998. }
  14999. }
  15000. this._eventSeries[run.name] = eventSeries;
  15001. run.dirty = false;
  15002. // update the accumulator
  15003. for(var j = 0; j < run.data.length; ++j){
  15004. var value = run.data[j];
  15005. if(value !== null){
  15006. var v = typeof value == "number" ? value : value.y;
  15007. if(isNaN(v)){ v = 0; }
  15008. acc[j] -= v;
  15009. }
  15010. }
  15011. }
  15012. this.dirty = false;
  15013. return this; // dojox.charting.plot2d.StackedBars
  15014. }
  15015. });
  15016. })();
  15017. }
  15018. if(!dojo._hasResource["dojox.charting.plot2d.ClusteredBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  15019. dojo._hasResource["dojox.charting.plot2d.ClusteredBars"] = true;
  15020. dojo.provide("dojox.charting.plot2d.ClusteredBars");
  15021. (function(){
  15022. var df = dojox.lang.functional, dc = dojox.charting.plot2d.common,
  15023. purgeGroup = df.lambda("item.purgeGroup()");
  15024. dojo.declare("dojox.charting.plot2d.ClusteredBars", dojox.charting.plot2d.Bars, {
  15025. // summary:
  15026. // A plot representing grouped or clustered bars (horizontal bars)
  15027. render: function(dim, offsets){
  15028. // summary:
  15029. // Run the calculations for any axes for this plot.
  15030. // dim: Object
  15031. // An object in the form of { width, height }
  15032. // offsets: Object
  15033. // An object of the form { l, r, t, b}.
  15034. // returns: dojox.charting.plot2d.ClusteredBars
  15035. // A reference to this plot for functional chaining.
  15036. if(this.zoom && !this.isDataDirty()){
  15037. return this.performZoom(dim, offsets);
  15038. }
  15039. this.resetEvents();
  15040. this.dirty = this.isDirty();
  15041. if(this.dirty){
  15042. dojo.forEach(this.series, purgeGroup);
  15043. this._eventSeries = {};
  15044. this.cleanGroup();
  15045. var s = this.group;
  15046. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  15047. }
  15048. var t = this.chart.theme, f, gap, height, thickness,
  15049. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  15050. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  15051. baseline = Math.max(0, this._hScaler.bounds.lower),
  15052. baselineWidth = ht(baseline),
  15053. events = this.events();
  15054. f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt, this.series.length);
  15055. gap = f.gap;
  15056. height = thickness = f.size;
  15057. for(var i = this.series.length - 1; i >= 0; --i){
  15058. var run = this.series[i], shift = thickness * (this.series.length - i - 1);
  15059. if(!this.dirty && !run.dirty){
  15060. t.skip();
  15061. this._reconnectEvents(run.name);
  15062. continue;
  15063. }
  15064. run.cleanGroup();
  15065. var theme = t.next("bar", [this.opt, run]), s = run.group,
  15066. eventSeries = new Array(run.data.length);
  15067. for(var j = 0; j < run.data.length; ++j){
  15068. var value = run.data[j];
  15069. if(value !== null){
  15070. var v = typeof value == "number" ? value : value.y,
  15071. hv = ht(v),
  15072. width = hv - baselineWidth,
  15073. w = Math.abs(width),
  15074. finalTheme = typeof value != "number" ?
  15075. t.addMixin(theme, "bar", value, true) :
  15076. t.post(theme, "bar");
  15077. if(w >= 0 && height >= 1){
  15078. var rect = {
  15079. x: offsets.l + (v < baseline ? hv : baselineWidth),
  15080. y: dim.height - offsets.b - vt(j + 1.5) + gap + shift,
  15081. width: w, height: height
  15082. };
  15083. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  15084. specialFill = this._shapeFill(specialFill, rect);
  15085. var shape = s.createRect(rect).setFill(specialFill).setStroke(finalTheme.series.stroke);
  15086. run.dyn.fill = shape.getFill();
  15087. run.dyn.stroke = shape.getStroke();
  15088. if(events){
  15089. var o = {
  15090. element: "bar",
  15091. index: j,
  15092. run: run,
  15093. shape: shape,
  15094. x: v,
  15095. y: j + 1.5
  15096. };
  15097. this._connectEvents(o);
  15098. eventSeries[j] = o;
  15099. }
  15100. if(this.animate){
  15101. this._animateBar(shape, offsets.l + baselineWidth, -width);
  15102. }
  15103. }
  15104. }
  15105. }
  15106. this._eventSeries[run.name] = eventSeries;
  15107. run.dirty = false;
  15108. }
  15109. this.dirty = false;
  15110. return this; // dojox.charting.plot2d.ClusteredBars
  15111. }
  15112. });
  15113. })();
  15114. }
  15115. if(!dojo._hasResource["dojox.charting.plot2d.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  15116. dojo._hasResource["dojox.charting.plot2d.Grid"] = true;
  15117. dojo.provide("dojox.charting.plot2d.Grid");
  15118. /*=====
  15119. dojo.declare("dojox.charting.plot2d.__GridCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, {
  15120. // summary:
  15121. // A special keyword arguments object that is specific to a grid "plot".
  15122. // hMajorLines: Boolean?
  15123. // Whether to show lines at the major ticks along the horizontal axis. Default is true.
  15124. hMajorLines: true,
  15125. // hMinorLines: Boolean?
  15126. // Whether to show lines at the minor ticks along the horizontal axis. Default is false.
  15127. hMinorLines: false,
  15128. // vMajorLines: Boolean?
  15129. // Whether to show lines at the major ticks along the vertical axis. Default is true.
  15130. vMajorLines: true,
  15131. // vMinorLines: Boolean?
  15132. // Whether to show lines at the major ticks along the vertical axis. Default is false.
  15133. vMinorLines: false,
  15134. // hStripes: String?
  15135. // Whether or not to show stripes (alternating fills) along the horizontal axis. Default is "none".
  15136. hStripes: "none",
  15137. // vStripes: String?
  15138. // Whether or not to show stripes (alternating fills) along the vertical axis. Default is "none".
  15139. vStripes: "none"
  15140. });
  15141. =====*/
  15142. (function(){
  15143. var du = dojox.lang.utils, dc = dojox.charting.plot2d.common;
  15144. dojo.declare("dojox.charting.plot2d.Grid", dojox.charting.Element, {
  15145. // summary:
  15146. // A "faux" plot that can be placed behind other plots to represent
  15147. // a grid against which other plots can be easily measured.
  15148. defaultParams: {
  15149. hAxis: "x", // use a horizontal axis named "x"
  15150. vAxis: "y", // use a vertical axis named "y"
  15151. hMajorLines: true, // draw horizontal major lines
  15152. hMinorLines: false, // draw horizontal minor lines
  15153. vMajorLines: true, // draw vertical major lines
  15154. vMinorLines: false, // draw vertical minor lines
  15155. hStripes: "none", // TBD
  15156. vStripes: "none", // TBD
  15157. animate: null // animate bars into place
  15158. },
  15159. optionalParams: {}, // no optional parameters
  15160. constructor: function(chart, kwArgs){
  15161. // summary:
  15162. // Create the faux Grid plot.
  15163. // chart: dojox.charting.Chart2D
  15164. // The chart this plot belongs to.
  15165. // kwArgs: dojox.charting.plot2d.__GridCtorArgs?
  15166. // An optional keyword arguments object to help define the parameters of the underlying grid.
  15167. this.opt = dojo.clone(this.defaultParams);
  15168. du.updateWithObject(this.opt, kwArgs);
  15169. this.hAxis = this.opt.hAxis;
  15170. this.vAxis = this.opt.vAxis;
  15171. this.dirty = true;
  15172. this.animate = this.opt.animate;
  15173. this.zoom = null,
  15174. this.zoomQueue = []; // zooming action task queue
  15175. this.lastWindow = {vscale: 1, hscale: 1, xoffset: 0, yoffset: 0};
  15176. },
  15177. clear: function(){
  15178. // summary:
  15179. // Clear out any parameters set on this plot.
  15180. // returns: dojox.charting.plot2d.Grid
  15181. // The reference to this plot for functional chaining.
  15182. this._hAxis = null;
  15183. this._vAxis = null;
  15184. this.dirty = true;
  15185. return this; // dojox.charting.plot2d.Grid
  15186. },
  15187. setAxis: function(axis){
  15188. // summary:
  15189. // Set an axis for this plot.
  15190. // returns: dojox.charting.plot2d.Grid
  15191. // The reference to this plot for functional chaining.
  15192. if(axis){
  15193. this[axis.vertical ? "_vAxis" : "_hAxis"] = axis;
  15194. }
  15195. return this; // dojox.charting.plot2d.Grid
  15196. },
  15197. addSeries: function(run){
  15198. // summary:
  15199. // Ignored but included as a dummy method.
  15200. // returns: dojox.charting.plot2d.Grid
  15201. // The reference to this plot for functional chaining.
  15202. return this; // dojox.charting.plot2d.Grid
  15203. },
  15204. getSeriesStats: function(){
  15205. // summary:
  15206. // Returns default stats (irrelevant for this type of plot).
  15207. // returns: Object
  15208. // {hmin, hmax, vmin, vmax} min/max in both directions.
  15209. return dojo.delegate(dc.defaultStats);
  15210. },
  15211. initializeScalers: function(){
  15212. // summary:
  15213. // Does nothing (irrelevant for this type of plot).
  15214. return this;
  15215. },
  15216. isDirty: function(){
  15217. // summary:
  15218. // Return whether or not this plot needs to be redrawn.
  15219. // returns: Boolean
  15220. // If this plot needs to be rendered, this will return true.
  15221. return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; // Boolean
  15222. },
  15223. performZoom: function(dim, offsets){
  15224. // summary:
  15225. // Create/alter any zooming windows on this plot.
  15226. // dim: Object
  15227. // An object of the form { width, height }.
  15228. // offsets: Object
  15229. // An object of the form { l, r, t, b }.
  15230. // returns: dojox.charting.plot2d.Grid
  15231. // A reference to this plot for functional chaining.
  15232. // get current zooming various
  15233. var vs = this._vAxis.scale || 1,
  15234. hs = this._hAxis.scale || 1,
  15235. vOffset = dim.height - offsets.b,
  15236. hBounds = this._hAxis.getScaler().bounds,
  15237. xOffset = (hBounds.from - hBounds.lower) * hBounds.scale,
  15238. vBounds = this._vAxis.getScaler().bounds,
  15239. yOffset = (vBounds.from - vBounds.lower) * vBounds.scale;
  15240. // get incremental zooming various
  15241. rVScale = vs / this.lastWindow.vscale,
  15242. rHScale = hs / this.lastWindow.hscale,
  15243. rXOffset = (this.lastWindow.xoffset - xOffset)/
  15244. ((this.lastWindow.hscale == 1)? hs : this.lastWindow.hscale),
  15245. rYOffset = (yOffset - this.lastWindow.yoffset)/
  15246. ((this.lastWindow.vscale == 1)? vs : this.lastWindow.vscale),
  15247. shape = this.group,
  15248. anim = dojox.gfx.fx.animateTransform(dojo.delegate({
  15249. shape: shape,
  15250. duration: 1200,
  15251. transform:[
  15252. {name:"translate", start:[0, 0], end: [offsets.l * (1 - rHScale), vOffset * (1 - rVScale)]},
  15253. {name:"scale", start:[1, 1], end: [rHScale, rVScale]},
  15254. {name:"original"},
  15255. {name:"translate", start: [0, 0], end: [rXOffset, rYOffset]}
  15256. ]}, this.zoom));
  15257. dojo.mixin(this.lastWindow, {vscale: vs, hscale: hs, xoffset: xOffset, yoffset: yOffset});
  15258. //add anim to zooming action queue,
  15259. //in order to avoid several zooming action happened at the same time
  15260. this.zoomQueue.push(anim);
  15261. //perform each anim one by one in zoomQueue
  15262. dojo.connect(anim, "onEnd", this, function(){
  15263. this.zoom = null;
  15264. this.zoomQueue.shift();
  15265. if(this.zoomQueue.length > 0){
  15266. this.zoomQueue[0].play();
  15267. }
  15268. });
  15269. if(this.zoomQueue.length == 1){
  15270. this.zoomQueue[0].play();
  15271. }
  15272. return this; // dojox.charting.plot2d.Grid
  15273. },
  15274. getRequiredColors: function(){
  15275. // summary:
  15276. // Ignored but included as a dummy method.
  15277. // returns: Number
  15278. // Returns 0, since there are no series associated with this plot type.
  15279. return 0; // Number
  15280. },
  15281. render: function(dim, offsets){
  15282. // summary:
  15283. // Render the plot on the chart.
  15284. // dim: Object
  15285. // An object of the form { width, height }.
  15286. // offsets: Object
  15287. // An object of the form { l, r, t, b }.
  15288. // returns: dojox.charting.plot2d.Grid
  15289. // A reference to this plot for functional chaining.
  15290. if(this.zoom){
  15291. return this.performZoom(dim, offsets);
  15292. }
  15293. this.dirty = this.isDirty();
  15294. if(!this.dirty){ return this; }
  15295. this.cleanGroup();
  15296. var s = this.group, ta = this.chart.theme.axis;
  15297. // draw horizontal stripes and lines
  15298. try{
  15299. var vScaler = this._vAxis.getScaler(),
  15300. vt = vScaler.scaler.getTransformerFromModel(vScaler),
  15301. ticks = this._vAxis.getTicks();
  15302. if(this.opt.hMinorLines){
  15303. dojo.forEach(ticks.minor, function(tick){
  15304. var y = dim.height - offsets.b - vt(tick.value);
  15305. var hMinorLine = s.createLine({
  15306. x1: offsets.l,
  15307. y1: y,
  15308. x2: dim.width - offsets.r,
  15309. y2: y
  15310. }).setStroke(ta.minorTick);
  15311. if(this.animate){
  15312. this._animateGrid(hMinorLine, "h", offsets.l, offsets.r + offsets.l - dim.width);
  15313. }
  15314. }, this);
  15315. }
  15316. if(this.opt.hMajorLines){
  15317. dojo.forEach(ticks.major, function(tick){
  15318. var y = dim.height - offsets.b - vt(tick.value);
  15319. var hMajorLine = s.createLine({
  15320. x1: offsets.l,
  15321. y1: y,
  15322. x2: dim.width - offsets.r,
  15323. y2: y
  15324. }).setStroke(ta.majorTick);
  15325. if(this.animate){
  15326. this._animateGrid(hMajorLine, "h", offsets.l, offsets.r + offsets.l - dim.width);
  15327. }
  15328. }, this);
  15329. }
  15330. }catch(e){
  15331. // squelch
  15332. }
  15333. // draw vertical stripes and lines
  15334. try{
  15335. var hScaler = this._hAxis.getScaler(),
  15336. ht = hScaler.scaler.getTransformerFromModel(hScaler),
  15337. ticks = this._hAxis.getTicks();
  15338. if(ticks && this.opt.vMinorLines){
  15339. dojo.forEach(ticks.minor, function(tick){
  15340. var x = offsets.l + ht(tick.value);
  15341. var vMinorLine = s.createLine({
  15342. x1: x,
  15343. y1: offsets.t,
  15344. x2: x,
  15345. y2: dim.height - offsets.b
  15346. }).setStroke(ta.minorTick);
  15347. if(this.animate){
  15348. this._animateGrid(vMinorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t);
  15349. }
  15350. }, this);
  15351. }
  15352. if(ticks && this.opt.vMajorLines){
  15353. dojo.forEach(ticks.major, function(tick){
  15354. var x = offsets.l + ht(tick.value);
  15355. var vMajorLine = s.createLine({
  15356. x1: x,
  15357. y1: offsets.t,
  15358. x2: x,
  15359. y2: dim.height - offsets.b
  15360. }).setStroke(ta.majorTick);
  15361. if(this.animate){
  15362. this._animateGrid(vMajorLine, "v", dim.height - offsets.b, dim.height - offsets.b - offsets.t);
  15363. }
  15364. }, this);
  15365. }
  15366. }catch(e){
  15367. // squelch
  15368. }
  15369. this.dirty = false;
  15370. return this; // dojox.charting.plot2d.Grid
  15371. },
  15372. _animateGrid: function(shape, type, offset, size){
  15373. var transStart = type == "h" ? [offset, 0] : [0, offset];
  15374. var scaleStart = type == "h" ? [1/size, 1] : [1, 1/size];
  15375. dojox.gfx.fx.animateTransform(dojo.delegate({
  15376. shape: shape,
  15377. duration: 1200,
  15378. transform: [
  15379. {name: "translate", start: transStart, end: [0, 0]},
  15380. {name: "scale", start: scaleStart, end: [1, 1]},
  15381. {name: "original"}
  15382. ]
  15383. }, this.animate)).play();
  15384. }
  15385. });
  15386. })();
  15387. }
  15388. if(!dojo._hasResource["dojox.charting.plot2d.Pie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  15389. dojo._hasResource["dojox.charting.plot2d.Pie"] = true;
  15390. dojo.provide("dojox.charting.plot2d.Pie");
  15391. /*=====
  15392. dojo.declare("dojox.charting.plot2d.__PieCtorArgs", dojox.charting.plot2d.__DefaultCtorArgs, {
  15393. // summary:
  15394. // Specialized keyword arguments object for use in defining parameters on a Pie chart.
  15395. // labels: Boolean?
  15396. // Whether or not to draw labels within each pie slice. Default is true.
  15397. labels: true,
  15398. // ticks: Boolean?
  15399. // Whether or not to draw ticks to labels within each slice. Default is false.
  15400. ticks: false,
  15401. // fixed: Boolean?
  15402. // TODO
  15403. fixed: true,
  15404. // precision: Number?
  15405. // The precision at which to sum/add data values. Default is 1.
  15406. precision: 1,
  15407. // labelOffset: Number?
  15408. // The amount in pixels by which to offset labels. Default is 20.
  15409. labelOffset: 20,
  15410. // labelStyle: String?
  15411. // Options as to where to draw labels. Values include "default", "rows", and "auto". Default is "default".
  15412. labelStyle: "default", // default/rows/auto
  15413. // htmlLabels: Boolean?
  15414. // Whether or not to use HTML to render slice labels. Default is true.
  15415. htmlLabels: true,
  15416. // radGrad: String?
  15417. // The type of radial gradient to use in rendering. Default is "native".
  15418. radGrad: "native",
  15419. // fanSize: Number?
  15420. // The amount for a radial gradient. Default is 5.
  15421. fanSize: 5,
  15422. // startAngle: Number?
  15423. // Where to being rendering gradients in slices, in degrees. Default is 0.
  15424. startAngle: 0,
  15425. // radius: Number?
  15426. // The size of the radial gradient. Default is 0.
  15427. radius: 0
  15428. });
  15429. =====*/
  15430. (function(){
  15431. var df = dojox.lang.functional, du = dojox.lang.utils,
  15432. dc = dojox.charting.plot2d.common,
  15433. da = dojox.charting.axis2d.common,
  15434. g = dojox.gfx, m = g.matrix,
  15435. FUDGE_FACTOR = 0.2; // use to overlap fans
  15436. dojo.declare("dojox.charting.plot2d.Pie", [dojox.charting.Element, dojox.charting.plot2d._PlotEvents], {
  15437. // summary:
  15438. // The plot that represents a typical pie chart.
  15439. defaultParams: {
  15440. labels: true,
  15441. ticks: false,
  15442. fixed: true,
  15443. precision: 1,
  15444. labelOffset: 20,
  15445. labelStyle: "default", // default/rows/auto/columns
  15446. htmlLabels: true, // use HTML to draw labels
  15447. radGrad: "native", // or "linear", or "fan"
  15448. fanSize: 5, // maximum fan size in degrees
  15449. startAngle: 0 // start angle for slices in degrees
  15450. },
  15451. optionalParams: {
  15452. radius: 0,
  15453. // theme components
  15454. stroke: {},
  15455. outline: {},
  15456. shadow: {},
  15457. fill: {},
  15458. font: "",
  15459. fontColor: "",
  15460. labelWiring: {}
  15461. },
  15462. constructor: function(chart, kwArgs){
  15463. // summary:
  15464. // Create a pie plot.
  15465. this.opt = dojo.clone(this.defaultParams);
  15466. du.updateWithObject(this.opt, kwArgs);
  15467. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  15468. this.run = null;
  15469. this.dyn = [];
  15470. },
  15471. clear: function(){
  15472. // summary:
  15473. // Clear out all of the information tied to this plot.
  15474. // returns: dojox.charting.plot2d.Pie
  15475. // A reference to this plot for functional chaining.
  15476. this.dirty = true;
  15477. this.dyn = [];
  15478. this.run = null;
  15479. return this; // dojox.charting.plot2d.Pie
  15480. },
  15481. setAxis: function(axis){
  15482. // summary:
  15483. // Dummy method, since axes are irrelevant with a Pie chart.
  15484. // returns: dojox.charting.plot2d.Pie
  15485. // The reference to this plot for functional chaining.
  15486. return this; // dojox.charting.plot2d.Pie
  15487. },
  15488. addSeries: function(run){
  15489. // summary:
  15490. // Add a series of data to this plot.
  15491. // returns: dojox.charting.plot2d.Pie
  15492. // The reference to this plot for functional chaining.
  15493. this.run = run;
  15494. return this; // dojox.charting.plot2d.Pie
  15495. },
  15496. getSeriesStats: function(){
  15497. // summary:
  15498. // Returns default stats (irrelevant for this type of plot).
  15499. // returns: Object
  15500. // {hmin, hmax, vmin, vmax} min/max in both directions.
  15501. return dojo.delegate(dc.defaultStats);
  15502. },
  15503. initializeScalers: function(){
  15504. // summary:
  15505. // Does nothing (irrelevant for this type of plot).
  15506. return this;
  15507. },
  15508. getRequiredColors: function(){
  15509. // summary:
  15510. // Return the number of colors needed to draw this plot.
  15511. return this.run ? this.run.data.length : 0;
  15512. },
  15513. render: function(dim, offsets){
  15514. // summary:
  15515. // Render the plot on the chart.
  15516. // dim: Object
  15517. // An object of the form { width, height }.
  15518. // offsets: Object
  15519. // An object of the form { l, r, t, b }.
  15520. // returns: dojox.charting.plot2d.Pie
  15521. // A reference to this plot for functional chaining.
  15522. if(!this.dirty){ return this; }
  15523. this.resetEvents();
  15524. this.dirty = false;
  15525. this._eventSeries = {};
  15526. this.cleanGroup();
  15527. var s = this.group, t = this.chart.theme;
  15528. if(!this.run || !this.run.data.length){
  15529. return this;
  15530. }
  15531. // calculate the geometry
  15532. var rx = (dim.width - offsets.l - offsets.r) / 2,
  15533. ry = (dim.height - offsets.t - offsets.b) / 2,
  15534. r = Math.min(rx, ry),
  15535. taFont = "font" in this.opt ? this.opt.font : t.axis.font,
  15536. size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0,
  15537. taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor,
  15538. startAngle = m._degToRad(this.opt.startAngle),
  15539. start = startAngle, step, filteredRun, slices, labels, shift, labelR,
  15540. run = this.run.data,
  15541. events = this.events();
  15542. if(typeof run[0] == "number"){
  15543. filteredRun = df.map(run, "x ? Math.max(x, 0) : 0");
  15544. if(df.every(filteredRun, "<= 0")){
  15545. return this;
  15546. }
  15547. slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0));
  15548. if(this.opt.labels){
  15549. labels = dojo.map(slices, function(x){
  15550. return x > 0 ? this._getLabel(x * 100) + "%" : "";
  15551. }, this);
  15552. }
  15553. }else{
  15554. filteredRun = df.map(run, "x ? Math.max(x.y, 0) : 0");
  15555. if(df.every(filteredRun, "<= 0")){
  15556. return this;
  15557. }
  15558. slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0));
  15559. if(this.opt.labels){
  15560. labels = dojo.map(slices, function(x, i){
  15561. if(x <= 0){ return ""; }
  15562. var v = run[i];
  15563. return "text" in v ? v.text : this._getLabel(x * 100) + "%";
  15564. }, this);
  15565. }
  15566. }
  15567. var themes = df.map(run, function(v, i){
  15568. if(v === null || typeof v == "number"){
  15569. return t.next("slice", [this.opt, this.run], true);
  15570. }
  15571. return t.next("slice", [this.opt, this.run, v], true);
  15572. }, this);
  15573. if(this.opt.labels){
  15574. shift = df.foldl1(df.map(labels, function(label, i){
  15575. var font = themes[i].series.font;
  15576. return dojox.gfx._base._getTextBox(label, {font: font}).w;
  15577. }, this), "Math.max(a, b)") / 2;
  15578. if(this.opt.labelOffset < 0){
  15579. r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset;
  15580. }
  15581. labelR = r - this.opt.labelOffset;
  15582. }
  15583. if("radius" in this.opt){
  15584. r = this.opt.radius;
  15585. labelR = r - this.opt.labelOffset;
  15586. }
  15587. var circle = {
  15588. cx: offsets.l + rx,
  15589. cy: offsets.t + ry,
  15590. r: r
  15591. };
  15592. this.dyn = [];
  15593. // draw slices
  15594. var eventSeries = new Array(slices.length);
  15595. dojo.some(slices, function(slice, i){
  15596. if(slice < 0){
  15597. // degenerated slice
  15598. return false; // continue
  15599. }
  15600. if(slice == 0){
  15601. this.dyn.push({fill: null, stroke: null});
  15602. return false;
  15603. }
  15604. var v = run[i], theme = themes[i], specialFill;
  15605. if(slice >= 1){
  15606. // whole pie
  15607. specialFill = this._plotFill(theme.series.fill, dim, offsets);
  15608. specialFill = this._shapeFill(specialFill,
  15609. {
  15610. x: circle.cx - circle.r, y: circle.cy - circle.r,
  15611. width: 2 * circle.r, height: 2 * circle.r
  15612. });
  15613. specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, circle.r);
  15614. var shape = s.createCircle(circle).setFill(specialFill).setStroke(theme.series.stroke);
  15615. this.dyn.push({fill: specialFill, stroke: theme.series.stroke});
  15616. if(events){
  15617. var o = {
  15618. element: "slice",
  15619. index: i,
  15620. run: this.run,
  15621. shape: shape,
  15622. x: i,
  15623. y: typeof v == "number" ? v : v.y,
  15624. cx: circle.cx,
  15625. cy: circle.cy,
  15626. cr: r
  15627. };
  15628. this._connectEvents(o);
  15629. eventSeries[i] = o;
  15630. }
  15631. return true; // stop iteration
  15632. }
  15633. // calculate the geometry of the slice
  15634. var end = start + slice * 2 * Math.PI;
  15635. if(i + 1 == slices.length){
  15636. end = startAngle + 2 * Math.PI;
  15637. }
  15638. var step = end - start,
  15639. x1 = circle.cx + r * Math.cos(start),
  15640. y1 = circle.cy + r * Math.sin(start),
  15641. x2 = circle.cx + r * Math.cos(end),
  15642. y2 = circle.cy + r * Math.sin(end);
  15643. // draw the slice
  15644. var fanSize = m._degToRad(this.opt.fanSize);
  15645. if(theme.series.fill && theme.series.fill.type === "radial" && this.opt.radGrad === "fan" && step > fanSize){
  15646. var group = s.createGroup(), nfans = Math.ceil(step / fanSize), delta = step / nfans;
  15647. specialFill = this._shapeFill(theme.series.fill,
  15648. {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r});
  15649. for(var j = 0; j < nfans; ++j){
  15650. var fansx = j == 0 ? x1 : circle.cx + r * Math.cos(start + (j - FUDGE_FACTOR) * delta),
  15651. fansy = j == 0 ? y1 : circle.cy + r * Math.sin(start + (j - FUDGE_FACTOR) * delta),
  15652. fanex = j == nfans - 1 ? x2 : circle.cx + r * Math.cos(start + (j + 1 + FUDGE_FACTOR) * delta),
  15653. faney = j == nfans - 1 ? y2 : circle.cy + r * Math.sin(start + (j + 1 + FUDGE_FACTOR) * delta),
  15654. fan = group.createPath({}).
  15655. moveTo(circle.cx, circle.cy).
  15656. lineTo(fansx, fansy).
  15657. arcTo(r, r, 0, delta > Math.PI, true, fanex, faney).
  15658. lineTo(circle.cx, circle.cy).
  15659. closePath().
  15660. setFill(this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start + (j + 0.5) * delta, start + (j + 0.5) * delta));
  15661. }
  15662. group.createPath({}).
  15663. moveTo(circle.cx, circle.cy).
  15664. lineTo(x1, y1).
  15665. arcTo(r, r, 0, step > Math.PI, true, x2, y2).
  15666. lineTo(circle.cx, circle.cy).
  15667. closePath().
  15668. setStroke(theme.series.stroke);
  15669. shape = group;
  15670. }else{
  15671. shape = s.createPath({}).
  15672. moveTo(circle.cx, circle.cy).
  15673. lineTo(x1, y1).
  15674. arcTo(r, r, 0, step > Math.PI, true, x2, y2).
  15675. lineTo(circle.cx, circle.cy).
  15676. closePath().
  15677. setStroke(theme.series.stroke);
  15678. var specialFill = theme.series.fill;
  15679. if(specialFill && specialFill.type === "radial"){
  15680. specialFill = this._shapeFill(specialFill, {x: circle.cx - circle.r, y: circle.cy - circle.r, width: 2 * circle.r, height: 2 * circle.r});
  15681. if(this.opt.radGrad === "linear"){
  15682. specialFill = this._pseudoRadialFill(specialFill, {x: circle.cx, y: circle.cy}, r, start, end);
  15683. }
  15684. }else if(specialFill && specialFill.type === "linear"){
  15685. specialFill = this._plotFill(specialFill, dim, offsets);
  15686. specialFill = this._shapeFill(specialFill, shape.getBoundingBox());
  15687. }
  15688. shape.setFill(specialFill);
  15689. }
  15690. this.dyn.push({fill: specialFill, stroke: theme.series.stroke});
  15691. if(events){
  15692. var o = {
  15693. element: "slice",
  15694. index: i,
  15695. run: this.run,
  15696. shape: shape,
  15697. x: i,
  15698. y: typeof v == "number" ? v : v.y,
  15699. cx: circle.cx,
  15700. cy: circle.cy,
  15701. cr: r
  15702. };
  15703. this._connectEvents(o);
  15704. eventSeries[i] = o;
  15705. }
  15706. start = end;
  15707. return false; // continue
  15708. }, this);
  15709. // draw labels
  15710. if(this.opt.labels){
  15711. if(this.opt.labelStyle == "default"){
  15712. start = startAngle;
  15713. dojo.some(slices, function(slice, i){
  15714. if(slice <= 0){
  15715. // degenerated slice
  15716. return false; // continue
  15717. }
  15718. var theme = themes[i];
  15719. if(slice >= 1){
  15720. // whole pie
  15721. var v = run[i], elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"](
  15722. this.chart, s, circle.cx, circle.cy + size / 2, "middle", labels[i],
  15723. theme.series.font, theme.series.fontColor);
  15724. if(this.opt.htmlLabels){
  15725. this.htmlElements.push(elem);
  15726. }
  15727. return true; // stop iteration
  15728. }
  15729. // calculate the geometry of the slice
  15730. var end = start + slice * 2 * Math.PI, v = run[i];
  15731. if(i + 1 == slices.length){
  15732. end = startAngle + 2 * Math.PI;
  15733. }
  15734. var labelAngle = (start + end) / 2,
  15735. x = circle.cx + labelR * Math.cos(labelAngle),
  15736. y = circle.cy + labelR * Math.sin(labelAngle) + size / 2;
  15737. // draw the label
  15738. var elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"]
  15739. (this.chart, s, x, y, "middle", labels[i], theme.series.font, theme.series.fontColor);
  15740. if(this.opt.htmlLabels){
  15741. this.htmlElements.push(elem);
  15742. }
  15743. start = end;
  15744. return false; // continue
  15745. }, this);
  15746. }else if(this.opt.labelStyle == "columns"){
  15747. start = startAngle;
  15748. //calculate label angles
  15749. var labeledSlices = [];
  15750. dojo.forEach(slices, function(slice, i){
  15751. var end = start + slice * 2 * Math.PI;
  15752. if(i + 1 == slices.length){
  15753. end = startAngle + 2 * Math.PI;
  15754. }
  15755. var labelAngle = (start + end) / 2;
  15756. labeledSlices.push({
  15757. angle: labelAngle,
  15758. left: Math.cos(labelAngle) < 0,
  15759. theme: themes[i],
  15760. index: i,
  15761. omit: end - start < 0.001
  15762. });
  15763. start = end;
  15764. });
  15765. //calculate label radius to each slice
  15766. var labelHeight = dojox.gfx._base._getTextBox("a",{font:taFont}).h;
  15767. this._getProperLabelRadius(labeledSlices, labelHeight, circle.r * 1.1);
  15768. //draw label and wiring
  15769. dojo.forEach(labeledSlices, function(slice, i){
  15770. if (!slice.omit) {
  15771. var leftColumn = circle.cx - circle.r * 2,
  15772. rightColumn = circle.cx + circle.r * 2,
  15773. labelWidth = dojox.gfx._base._getTextBox(labels[i], {font: taFont}).w,
  15774. x = circle.cx + slice.labelR * Math.cos(slice.angle),
  15775. y = circle.cy + slice.labelR * Math.sin(slice.angle),
  15776. jointX = (slice.left) ? (leftColumn + labelWidth) : (rightColumn - labelWidth),
  15777. labelX = (slice.left) ? leftColumn : jointX;
  15778. var wiring = s.createPath().moveTo(circle.cx + circle.r * Math.cos(slice.angle), circle.cy + circle.r * Math.sin(slice.angle))
  15779. if (Math.abs(slice.labelR * Math.cos(slice.angle)) < circle.r * 2 - labelWidth) {
  15780. wiring.lineTo(x, y);
  15781. }
  15782. wiring.lineTo(jointX, y).setStroke(slice.theme.series.labelWiring);
  15783. var elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"](
  15784. this.chart, s, labelX, y, "left", labels[i], slice.theme.series.font, slice.theme.series.fontColor);
  15785. if (this.opt.htmlLabels) {
  15786. this.htmlElements.push(elem);
  15787. }
  15788. }
  15789. },this);
  15790. }
  15791. }
  15792. // post-process events to restore the original indexing
  15793. var esi = 0;
  15794. this._eventSeries[this.run.name] = df.map(run, function(v){
  15795. return v <= 0 ? null : eventSeries[esi++];
  15796. });
  15797. return this; // dojox.charting.plot2d.Pie
  15798. },
  15799. _getProperLabelRadius: function(slices, labelHeight, minRidius){
  15800. var leftCenterSlice = {},rightCenterSlice = {},leftMinSIN = 1, rightMinSIN = 1;
  15801. if (slices.length == 1) {
  15802. slices[0].labelR = minRidius;
  15803. return;
  15804. }
  15805. for(var i = 0;i<slices.length;i++){
  15806. var tempSIN = Math.abs(Math.sin(slices[i].angle));
  15807. if(slices[i].left){
  15808. if(leftMinSIN > tempSIN){
  15809. leftMinSIN = tempSIN;
  15810. leftCenterSlice = slices[i];
  15811. }
  15812. }else{
  15813. if(rightMinSIN > tempSIN){
  15814. rightMinSIN = tempSIN;
  15815. rightCenterSlice = slices[i];
  15816. }
  15817. }
  15818. }
  15819. leftCenterSlice.labelR = rightCenterSlice.labelR = minRidius;
  15820. this._caculateLabelR(leftCenterSlice,slices,labelHeight);
  15821. this._caculateLabelR(rightCenterSlice,slices,labelHeight);
  15822. },
  15823. _caculateLabelR: function(firstSlice,slices,labelHeight){
  15824. var i = firstSlice.index,length = slices.length,
  15825. currentLabelR = firstSlice.labelR;
  15826. while(!(slices[i%length].left ^ slices[(i+1)%length].left)){
  15827. if (!slices[(i + 1) % length].omit) {
  15828. var nextLabelR = (Math.sin(slices[i % length].angle) * currentLabelR + ((slices[i % length].left) ? (-labelHeight) : labelHeight)) /
  15829. Math.sin(slices[(i + 1) % length].angle);
  15830. currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR;
  15831. slices[(i + 1) % length].labelR = currentLabelR;
  15832. }
  15833. i++;
  15834. }
  15835. i = firstSlice.index,j = (i == 0)?length-1 : i - 1;
  15836. while(!(slices[i].left ^ slices[j].left)){
  15837. if (!slices[j].omit) {
  15838. var nextLabelR = (Math.sin(slices[i].angle) * currentLabelR + ((slices[i].left) ? labelHeight : (-labelHeight))) /
  15839. Math.sin(slices[j].angle);
  15840. currentLabelR = (nextLabelR < firstSlice.labelR) ? firstSlice.labelR : nextLabelR;
  15841. slices[j].labelR = currentLabelR;
  15842. }
  15843. i--;j--;
  15844. i = (i < 0)?i+slices.length:i;
  15845. j = (j < 0)?j+slices.length:j;
  15846. }
  15847. },
  15848. // utilities
  15849. _getLabel: function(number){
  15850. return dc.getLabel(number, this.opt.fixed, this.opt.precision);
  15851. }
  15852. });
  15853. })();
  15854. }
  15855. if(!dojo._hasResource["dojox.charting.plot2d.Bubble"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  15856. dojo._hasResource["dojox.charting.plot2d.Bubble"] = true;
  15857. dojo.provide("dojox.charting.plot2d.Bubble");
  15858. (function(){
  15859. var df = dojox.lang.functional, du = dojox.lang.utils,
  15860. dc = dojox.charting.plot2d.common,
  15861. purgeGroup = df.lambda("item.purgeGroup()");
  15862. dojo.declare("dojox.charting.plot2d.Bubble", dojox.charting.plot2d.Base, {
  15863. // summary:
  15864. // A plot representing bubbles. Note that data for Bubbles requires 3 parameters,
  15865. // in the form of: { x, y, size }, where size determines the size of the bubble.
  15866. defaultParams: {
  15867. hAxis: "x", // use a horizontal axis named "x"
  15868. vAxis: "y", // use a vertical axis named "y"
  15869. animate: null // animate bars into place
  15870. },
  15871. optionalParams: {
  15872. // theme component
  15873. stroke: {},
  15874. outline: {},
  15875. shadow: {},
  15876. fill: {},
  15877. font: "",
  15878. fontColor: ""
  15879. },
  15880. constructor: function(chart, kwArgs){
  15881. // summary:
  15882. // Create a plot of bubbles.
  15883. // chart: dojox.charting.Chart2D
  15884. // The chart this plot belongs to.
  15885. // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs?
  15886. // Optional keyword arguments object to help define plot parameters.
  15887. this.opt = dojo.clone(this.defaultParams);
  15888. du.updateWithObject(this.opt, kwArgs);
  15889. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  15890. this.series = [];
  15891. this.hAxis = this.opt.hAxis;
  15892. this.vAxis = this.opt.vAxis;
  15893. this.animate = this.opt.animate;
  15894. },
  15895. // override the render so that we are plotting only circles.
  15896. render: function(dim, offsets){
  15897. // summary:
  15898. // Run the calculations for any axes for this plot.
  15899. // dim: Object
  15900. // An object in the form of { width, height }
  15901. // offsets: Object
  15902. // An object of the form { l, r, t, b}.
  15903. // returns: dojox.charting.plot2d.Bubble
  15904. // A reference to this plot for functional chaining.
  15905. if(this.zoom && !this.isDataDirty()){
  15906. return this.performZoom(dim, offsets);
  15907. }
  15908. this.resetEvents();
  15909. this.dirty = this.isDirty();
  15910. if(this.dirty){
  15911. dojo.forEach(this.series, purgeGroup);
  15912. this._eventSeries = {};
  15913. this.cleanGroup();
  15914. var s = this.group;
  15915. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  15916. }
  15917. var t = this.chart.theme,
  15918. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  15919. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  15920. events = this.events();
  15921. for(var i = this.series.length - 1; i >= 0; --i){
  15922. var run = this.series[i];
  15923. if(!this.dirty && !run.dirty){
  15924. t.skip();
  15925. this._reconnectEvents(run.name);
  15926. continue;
  15927. }
  15928. run.cleanGroup();
  15929. if(!run.data.length){
  15930. run.dirty = false;
  15931. t.skip();
  15932. continue;
  15933. }
  15934. if(typeof run.data[0] == "number"){
  15935. console.warn("dojox.charting.plot2d.Bubble: the data in the following series cannot be rendered as a bubble chart; ", run);
  15936. continue;
  15937. }
  15938. var theme = t.next("circle", [this.opt, run]), s = run.group,
  15939. points = dojo.map(run.data, function(v, i){
  15940. return v ? {
  15941. x: ht(v.x) + offsets.l,
  15942. y: dim.height - offsets.b - vt(v.y),
  15943. radius: this._vScaler.bounds.scale * (v.size / 2)
  15944. } : null;
  15945. }, this);
  15946. var frontCircles = null, outlineCircles = null, shadowCircles = null;
  15947. // make shadows if needed
  15948. if(theme.series.shadow){
  15949. shadowCircles = dojo.map(points, function(item){
  15950. if(item !== null){
  15951. var finalTheme = t.addMixin(theme, "circle", item, true),
  15952. shadow = finalTheme.series.shadow;
  15953. var shape = s.createCircle({
  15954. cx: item.x + shadow.dx, cy: item.y + shadow.dy, r: item.radius
  15955. }).setStroke(shadow).setFill(shadow.color);
  15956. if(this.animate){
  15957. this._animateBubble(shape, dim.height - offsets.b, item.radius);
  15958. }
  15959. return shape;
  15960. }
  15961. return null;
  15962. }, this);
  15963. if(shadowCircles.length){
  15964. run.dyn.shadow = shadowCircles[shadowCircles.length - 1].getStroke();
  15965. }
  15966. }
  15967. // make outlines if needed
  15968. if(theme.series.outline){
  15969. outlineCircles = dojo.map(points, function(item){
  15970. if(item !== null){
  15971. var finalTheme = t.addMixin(theme, "circle", item, true),
  15972. outline = dc.makeStroke(finalTheme.series.outline);
  15973. outline.width = 2 * outline.width + theme.series.stroke.width;
  15974. var shape = s.createCircle({
  15975. cx: item.x, cy: item.y, r: item.radius
  15976. }).setStroke(outline);
  15977. if(this.animate){
  15978. this._animateBubble(shape, dim.height - offsets.b, item.radius);
  15979. }
  15980. return shape;
  15981. }
  15982. return null;
  15983. }, this);
  15984. if(outlineCircles.length){
  15985. run.dyn.outline = outlineCircles[outlineCircles.length - 1].getStroke();
  15986. }
  15987. }
  15988. // run through the data and add the circles.
  15989. frontCircles = dojo.map(points, function(item){
  15990. if(item !== null){
  15991. var finalTheme = t.addMixin(theme, "circle", item, true),
  15992. rect = {
  15993. x: item.x - item.radius,
  15994. y: item.y - item.radius,
  15995. width: 2 * item.radius,
  15996. height: 2 * item.radius
  15997. };
  15998. var specialFill = this._plotFill(finalTheme.series.fill, dim, offsets);
  15999. specialFill = this._shapeFill(specialFill, rect);
  16000. var shape = s.createCircle({
  16001. cx: item.x, cy: item.y, r: item.radius
  16002. }).setFill(specialFill).setStroke(finalTheme.series.stroke);
  16003. if(this.animate){
  16004. this._animateBubble(shape, dim.height - offsets.b, item.radius);
  16005. }
  16006. return shape;
  16007. }
  16008. return null;
  16009. }, this);
  16010. if(frontCircles.length){
  16011. run.dyn.fill = frontCircles[frontCircles.length - 1].getFill();
  16012. run.dyn.stroke = frontCircles[frontCircles.length - 1].getStroke();
  16013. }
  16014. if(events){
  16015. var eventSeries = new Array(frontCircles.length);
  16016. dojo.forEach(frontCircles, function(s, i){
  16017. if(s !== null){
  16018. var o = {
  16019. element: "circle",
  16020. index: i,
  16021. run: run,
  16022. shape: s,
  16023. outline: outlineCircles && outlineCircles[i] || null,
  16024. shadow: shadowCircles && shadowCircles[i] || null,
  16025. x: run.data[i].x,
  16026. y: run.data[i].y,
  16027. r: run.data[i].size / 2,
  16028. cx: points[i].x,
  16029. cy: points[i].y,
  16030. cr: points[i].radius
  16031. };
  16032. this._connectEvents(o);
  16033. eventSeries[i] = o;
  16034. }
  16035. }, this);
  16036. this._eventSeries[run.name] = eventSeries;
  16037. }else{
  16038. delete this._eventSeries[run.name];
  16039. }
  16040. run.dirty = false;
  16041. }
  16042. this.dirty = false;
  16043. return this; // dojox.charting.plot2d.Bubble
  16044. },
  16045. _animateBubble: function(shape, offset, size){
  16046. dojox.gfx.fx.animateTransform(dojo.delegate({
  16047. shape: shape,
  16048. duration: 1200,
  16049. transform: [
  16050. {name: "translate", start: [0, offset], end: [0, 0]},
  16051. {name: "scale", start: [0, 1/size], end: [1, 1]},
  16052. {name: "original"}
  16053. ]
  16054. }, this.animate)).play();
  16055. }
  16056. });
  16057. })();
  16058. }
  16059. if(!dojo._hasResource["dojox.charting.plot2d.Candlesticks"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  16060. dojo._hasResource["dojox.charting.plot2d.Candlesticks"] = true;
  16061. dojo.provide("dojox.charting.plot2d.Candlesticks");
  16062. (function(){
  16063. var df = dojox.lang.functional, du = dojox.lang.utils,
  16064. dc = dojox.charting.plot2d.common,
  16065. purgeGroup = df.lambda("item.purgeGroup()");
  16066. // Candlesticks are based on the Bars plot type; we expect the following passed
  16067. // as values in a series:
  16068. // { x?, open, close, high, low, mid? }
  16069. // if x is not provided, the array index is used.
  16070. // failing to provide the OHLC values will throw an error.
  16071. dojo.declare("dojox.charting.plot2d.Candlesticks", dojox.charting.plot2d.Base, {
  16072. // summary:
  16073. // A plot that represents typical candlesticks (financial reporting, primarily).
  16074. // Unlike most charts, the Candlestick expects data points to be represented by
  16075. // an object of the form { x?, open, close, high, low, mid? }, where both
  16076. // x and mid are optional parameters. If x is not provided, the index of the
  16077. // data array is used.
  16078. defaultParams: {
  16079. hAxis: "x", // use a horizontal axis named "x"
  16080. vAxis: "y", // use a vertical axis named "y"
  16081. gap: 2, // gap between columns in pixels
  16082. animate: null // animate bars into place
  16083. },
  16084. optionalParams: {
  16085. minBarSize: 1, // minimal candle width in pixels
  16086. maxBarSize: 1, // maximal candle width in pixels
  16087. // theme component
  16088. stroke: {},
  16089. outline: {},
  16090. shadow: {},
  16091. fill: {},
  16092. font: "",
  16093. fontColor: ""
  16094. },
  16095. constructor: function(chart, kwArgs){
  16096. // summary:
  16097. // The constructor for a candlestick chart.
  16098. // chart: dojox.charting.Chart2D
  16099. // The chart this plot belongs to.
  16100. // kwArgs: dojox.charting.plot2d.__BarCtorArgs?
  16101. // An optional keyword arguments object to help define the plot.
  16102. this.opt = dojo.clone(this.defaultParams);
  16103. du.updateWithObject(this.opt, kwArgs);
  16104. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  16105. this.series = [];
  16106. this.hAxis = this.opt.hAxis;
  16107. this.vAxis = this.opt.vAxis;
  16108. this.animate = this.opt.animate;
  16109. },
  16110. collectStats: function(series){
  16111. // summary:
  16112. // Collect all statistics for drawing this chart. Since the common
  16113. // functionality only assumes x and y, Candlesticks must create it's own
  16114. // stats (since data has no y value, but open/close/high/low instead).
  16115. // series: dojox.charting.Series[]
  16116. // The data series array to be drawn on this plot.
  16117. // returns: Object
  16118. // Returns an object in the form of { hmin, hmax, vmin, vmax }.
  16119. // we have to roll our own, since we need to use all four passed
  16120. // values to figure out our stats, and common only assumes x and y.
  16121. var stats = dojo.delegate(dc.defaultStats);
  16122. for(var i=0; i<series.length; i++){
  16123. var run = series[i];
  16124. if(!run.data.length){ continue; }
  16125. var old_vmin = stats.vmin, old_vmax = stats.vmax;
  16126. if(!("ymin" in run) || !("ymax" in run)){
  16127. dojo.forEach(run.data, function(val, idx){
  16128. if(val !== null){
  16129. var x = val.x || idx + 1;
  16130. stats.hmin = Math.min(stats.hmin, x);
  16131. stats.hmax = Math.max(stats.hmax, x);
  16132. stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low);
  16133. stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low);
  16134. }
  16135. });
  16136. }
  16137. if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); }
  16138. if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); }
  16139. }
  16140. return stats; // Object
  16141. },
  16142. getSeriesStats: function(){
  16143. // summary:
  16144. // Calculate the min/max on all attached series in both directions.
  16145. // returns: Object
  16146. // {hmin, hmax, vmin, vmax} min/max in both directions.
  16147. var stats = this.collectStats(this.series);
  16148. stats.hmin -= 0.5;
  16149. stats.hmax += 0.5;
  16150. return stats;
  16151. },
  16152. render: function(dim, offsets){
  16153. // summary:
  16154. // Run the calculations for any axes for this plot.
  16155. // dim: Object
  16156. // An object in the form of { width, height }
  16157. // offsets: Object
  16158. // An object of the form { l, r, t, b}.
  16159. // returns: dojox.charting.plot2d.Candlesticks
  16160. // A reference to this plot for functional chaining.
  16161. if(this.zoom && !this.isDataDirty()){
  16162. return this.performZoom(dim, offsets);
  16163. }
  16164. this.resetEvents();
  16165. this.dirty = this.isDirty();
  16166. if(this.dirty){
  16167. dojo.forEach(this.series, purgeGroup);
  16168. this._eventSeries = {};
  16169. this.cleanGroup();
  16170. var s = this.group;
  16171. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  16172. }
  16173. var t = this.chart.theme, f, gap, width,
  16174. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  16175. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  16176. baseline = Math.max(0, this._vScaler.bounds.lower),
  16177. baselineHeight = vt(baseline),
  16178. events = this.events();
  16179. f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt);
  16180. gap = f.gap;
  16181. width = f.size;
  16182. for(var i = this.series.length - 1; i >= 0; --i){
  16183. var run = this.series[i];
  16184. if(!this.dirty && !run.dirty){
  16185. t.skip();
  16186. this._reconnectEvents(run.name);
  16187. continue;
  16188. }
  16189. run.cleanGroup();
  16190. var theme = t.next("candlestick", [this.opt, run]), s = run.group,
  16191. eventSeries = new Array(run.data.length);
  16192. for(var j = 0; j < run.data.length; ++j){
  16193. var v = run.data[j];
  16194. if(v !== null){
  16195. var finalTheme = t.addMixin(theme, "candlestick", v, true);
  16196. // calculate the points we need for OHLC
  16197. var x = ht(v.x || (j+0.5)) + offsets.l + gap,
  16198. y = dim.height - offsets.b,
  16199. open = vt(v.open),
  16200. close = vt(v.close),
  16201. high = vt(v.high),
  16202. low = vt(v.low);
  16203. if("mid" in v){
  16204. var mid = vt(v.mid);
  16205. }
  16206. if(low > high){
  16207. var tmp = high;
  16208. high = low;
  16209. low = tmp;
  16210. }
  16211. if(width >= 1){
  16212. // draw the line and rect, set up as a group and pass that to the events.
  16213. var doFill = open > close;
  16214. var line = { x1: width/2, x2: width/2, y1: y - high, y2: y - low },
  16215. rect = {
  16216. x: 0, y: y-Math.max(open, close),
  16217. width: width, height: Math.max(doFill ? open-close : close-open, 1)
  16218. };
  16219. shape = s.createGroup();
  16220. shape.setTransform({dx: x, dy: 0 });
  16221. var inner = shape.createGroup();
  16222. inner.createLine(line).setStroke(finalTheme.series.stroke);
  16223. inner.createRect(rect).setStroke(finalTheme.series.stroke).
  16224. setFill(doFill ? finalTheme.series.fill : "white");
  16225. if("mid" in v){
  16226. // add the mid line.
  16227. inner.createLine({
  16228. x1: (finalTheme.series.stroke.width||1), x2: width - (finalTheme.series.stroke.width || 1),
  16229. y1: y - mid, y2: y - mid
  16230. }).setStroke(doFill ? "white" : finalTheme.series.stroke);
  16231. }
  16232. // TODO: double check this.
  16233. run.dyn.fill = finalTheme.series.fill;
  16234. run.dyn.stroke = finalTheme.series.stroke;
  16235. if(events){
  16236. var o = {
  16237. element: "candlestick",
  16238. index: j,
  16239. run: run,
  16240. shape: inner,
  16241. x: x,
  16242. y: y-Math.max(open, close),
  16243. cx: width/2,
  16244. cy: (y-Math.max(open, close)) + (Math.max(doFill ? open-close : close-open, 1)/2),
  16245. width: width,
  16246. height: Math.max(doFill ? open-close : close-open, 1),
  16247. data: v
  16248. };
  16249. this._connectEvents(o);
  16250. eventSeries[j] = o;
  16251. }
  16252. }
  16253. if(this.animate){
  16254. this._animateCandlesticks(shape, y - low, high - low);
  16255. }
  16256. }
  16257. }
  16258. this._eventSeries[run.name] = eventSeries;
  16259. run.dirty = false;
  16260. }
  16261. this.dirty = false;
  16262. return this; // dojox.charting.plot2d.Candlesticks
  16263. },
  16264. _animateCandlesticks: function(shape, voffset, vsize){
  16265. dojox.gfx.fx.animateTransform(dojo.delegate({
  16266. shape: shape,
  16267. duration: 1200,
  16268. transform: [
  16269. {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]},
  16270. {name: "scale", start: [1, 1/vsize], end: [1, 1]},
  16271. {name: "original"}
  16272. ]
  16273. }, this.animate)).play();
  16274. }
  16275. });
  16276. })();
  16277. }
  16278. if(!dojo._hasResource["dojox.charting.plot2d.OHLC"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  16279. dojo._hasResource["dojox.charting.plot2d.OHLC"] = true;
  16280. dojo.provide("dojox.charting.plot2d.OHLC");
  16281. (function(){
  16282. var df = dojox.lang.functional, du = dojox.lang.utils,
  16283. dc = dojox.charting.plot2d.common,
  16284. purgeGroup = df.lambda("item.purgeGroup()");
  16285. // Candlesticks are based on the Bars plot type; we expect the following passed
  16286. // as values in a series:
  16287. // { x?, open, close, high, low }
  16288. // if x is not provided, the array index is used.
  16289. // failing to provide the OHLC values will throw an error.
  16290. dojo.declare("dojox.charting.plot2d.OHLC", dojox.charting.plot2d.Base, {
  16291. // summary:
  16292. // A plot that represents typical open/high/low/close (financial reporting, primarily).
  16293. // Unlike most charts, the Candlestick expects data points to be represented by
  16294. // an object of the form { x?, open, close, high, low, mid? }, where both
  16295. // x and mid are optional parameters. If x is not provided, the index of the
  16296. // data array is used.
  16297. defaultParams: {
  16298. hAxis: "x", // use a horizontal axis named "x"
  16299. vAxis: "y", // use a vertical axis named "y"
  16300. gap: 2, // gap between columns in pixels
  16301. animate: null // animate chart to place
  16302. },
  16303. optionalParams: {
  16304. minBarSize: 1, // minimal bar size in pixels
  16305. maxBarSize: 1, // maximal bar size in pixels
  16306. // theme component
  16307. stroke: {},
  16308. outline: {},
  16309. shadow: {},
  16310. fill: {},
  16311. font: "",
  16312. fontColor: ""
  16313. },
  16314. constructor: function(chart, kwArgs){
  16315. // summary:
  16316. // The constructor for a candlestick chart.
  16317. // chart: dojox.charting.Chart2D
  16318. // The chart this plot belongs to.
  16319. // kwArgs: dojox.charting.plot2d.__BarCtorArgs?
  16320. // An optional keyword arguments object to help define the plot.
  16321. this.opt = dojo.clone(this.defaultParams);
  16322. du.updateWithObject(this.opt, kwArgs);
  16323. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  16324. this.series = [];
  16325. this.hAxis = this.opt.hAxis;
  16326. this.vAxis = this.opt.vAxis;
  16327. this.animate = this.opt.animate;
  16328. },
  16329. collectStats: function(series){
  16330. // summary:
  16331. // Collect all statistics for drawing this chart. Since the common
  16332. // functionality only assumes x and y, OHLC must create it's own
  16333. // stats (since data has no y value, but open/close/high/low instead).
  16334. // series: dojox.charting.Series[]
  16335. // The data series array to be drawn on this plot.
  16336. // returns: Object
  16337. // Returns an object in the form of { hmin, hmax, vmin, vmax }.
  16338. // we have to roll our own, since we need to use all four passed
  16339. // values to figure out our stats, and common only assumes x and y.
  16340. var stats = dojo.delegate(dc.defaultStats);
  16341. for(var i=0; i<series.length; i++){
  16342. var run = series[i];
  16343. if(!run.data.length){ continue; }
  16344. var old_vmin = stats.vmin, old_vmax = stats.vmax;
  16345. if(!("ymin" in run) || !("ymax" in run)){
  16346. dojo.forEach(run.data, function(val, idx){
  16347. if(val !== null){
  16348. var x = val.x || idx + 1;
  16349. stats.hmin = Math.min(stats.hmin, x);
  16350. stats.hmax = Math.max(stats.hmax, x);
  16351. stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low);
  16352. stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low);
  16353. }
  16354. });
  16355. }
  16356. if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); }
  16357. if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); }
  16358. }
  16359. return stats;
  16360. },
  16361. getSeriesStats: function(){
  16362. // summary:
  16363. // Calculate the min/max on all attached series in both directions.
  16364. // returns: Object
  16365. // {hmin, hmax, vmin, vmax} min/max in both directions.
  16366. var stats = this.collectStats(this.series);
  16367. stats.hmin -= 0.5;
  16368. stats.hmax += 0.5;
  16369. return stats;
  16370. },
  16371. render: function(dim, offsets){
  16372. // summary:
  16373. // Run the calculations for any axes for this plot.
  16374. // dim: Object
  16375. // An object in the form of { width, height }
  16376. // offsets: Object
  16377. // An object of the form { l, r, t, b}.
  16378. // returns: dojox.charting.plot2d.OHLC
  16379. // A reference to this plot for functional chaining.
  16380. if(this.zoom && !this.isDataDirty()){
  16381. return this.performZoom(dim, offsets);
  16382. }
  16383. this.resetEvents();
  16384. this.dirty = this.isDirty();
  16385. if(this.dirty){
  16386. dojo.forEach(this.series, purgeGroup);
  16387. this._eventSeries = {};
  16388. this.cleanGroup();
  16389. var s = this.group;
  16390. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  16391. }
  16392. var t = this.chart.theme, f, gap, width,
  16393. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  16394. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler),
  16395. baseline = Math.max(0, this._vScaler.bounds.lower),
  16396. baselineHeight = vt(baseline),
  16397. events = this.events();
  16398. f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt);
  16399. gap = f.gap;
  16400. width = f.size;
  16401. for(var i = this.series.length - 1; i >= 0; --i){
  16402. var run = this.series[i];
  16403. if(!this.dirty && !run.dirty){
  16404. t.skip();
  16405. this._reconnectEvents(run.name);
  16406. continue;
  16407. }
  16408. run.cleanGroup();
  16409. var theme = t.next("candlestick", [this.opt, run]), s = run.group,
  16410. eventSeries = new Array(run.data.length);
  16411. for(var j = 0; j < run.data.length; ++j){
  16412. var v = run.data[j];
  16413. if(v !== null){
  16414. var finalTheme = t.addMixin(theme, "candlestick", v, true);
  16415. // calculate the points we need for OHLC
  16416. var x = ht(v.x || (j+0.5)) + offsets.l + gap,
  16417. y = dim.height - offsets.b,
  16418. open = vt(v.open),
  16419. close = vt(v.close),
  16420. high = vt(v.high),
  16421. low = vt(v.low);
  16422. if(low > high){
  16423. var tmp = high;
  16424. high = low;
  16425. low = tmp;
  16426. }
  16427. if(width >= 1){
  16428. var hl = {x1: width/2, x2: width/2, y1: y - high, y2: y - low},
  16429. op = {x1: 0, x2: ((width/2) + ((finalTheme.series.stroke.width||1)/2)), y1: y-open, y2: y-open},
  16430. cl = {x1: ((width/2) - ((finalTheme.series.stroke.width||1)/2)), x2: width, y1: y-close, y2: y-close};
  16431. shape = s.createGroup();
  16432. shape.setTransform({dx: x, dy: 0});
  16433. var inner = shape.createGroup();
  16434. inner.createLine(hl).setStroke(finalTheme.series.stroke);
  16435. inner.createLine(op).setStroke(finalTheme.series.stroke);
  16436. inner.createLine(cl).setStroke(finalTheme.series.stroke);
  16437. // TODO: double check this.
  16438. run.dyn.stroke = finalTheme.series.stroke;
  16439. if(events){
  16440. var o = {
  16441. element: "candlestick",
  16442. index: j,
  16443. run: run,
  16444. shape: inner,
  16445. x: x,
  16446. y: y-Math.max(open, close),
  16447. cx: width/2,
  16448. cy: (y-Math.max(open, close)) + (Math.max(open > close ? open-close : close-open, 1)/2),
  16449. width: width,
  16450. height: Math.max(open > close ? open-close : close-open, 1),
  16451. data: v
  16452. };
  16453. this._connectEvents(o);
  16454. eventSeries[j] = o;
  16455. }
  16456. }
  16457. if(this.animate){
  16458. this._animateOHLC(shape, y - low, high - low);
  16459. }
  16460. }
  16461. }
  16462. this._eventSeries[run.name] = eventSeries;
  16463. run.dirty = false;
  16464. }
  16465. this.dirty = false;
  16466. return this; // dojox.charting.plot2d.OHLC
  16467. },
  16468. _animateOHLC: function(shape, voffset, vsize){
  16469. dojox.gfx.fx.animateTransform(dojo.delegate({
  16470. shape: shape,
  16471. duration: 1200,
  16472. transform: [
  16473. {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]},
  16474. {name: "scale", start: [1, 1/vsize], end: [1, 1]},
  16475. {name: "original"}
  16476. ]
  16477. }, this.animate)).play();
  16478. }
  16479. });
  16480. })();
  16481. }
  16482. if(!dojo._hasResource["dojox.charting.plot2d.Spider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  16483. dojo._hasResource["dojox.charting.plot2d.Spider"] = true;
  16484. dojo.provide("dojox.charting.plot2d.Spider");
  16485. dojo.experimental("dojox.charting.plot2d.Spider");
  16486. (function(){
  16487. var df = dojox.lang.functional, du = dojox.lang.utils,
  16488. dc = dojox.charting.plot2d.common,
  16489. da = dojox.charting.axis2d.common,
  16490. g = dojox.gfx, m = g.matrix,
  16491. FUDGE_FACTOR = 0.2; // use to overlap fans
  16492. dojo.declare("dojox.charting.plot2d.Spider", [dojox.charting.Element, dojox.charting.plot2d._PlotEvents], {
  16493. // summary:
  16494. // The plot that represents a typical Spider chart.
  16495. defaultParams: {
  16496. labels: true,
  16497. ticks: false,
  16498. fixed: true,
  16499. precision: 1,
  16500. labelOffset: -10,
  16501. labelStyle: "default", // default/rows/auto
  16502. htmlLabels: true, // use HTML to draw labels
  16503. startAngle: -90, // start angle for slices in degrees
  16504. divisions: 3, // radius tick count
  16505. axisColor: "", // spider axis color
  16506. axisWidth: 0, // spider axis stroke width
  16507. spiderColor: "", // spider web color
  16508. spiderWidth: 0, // spider web stroke width
  16509. seriesWidth: 0, // plot border with
  16510. seriesFillAlpha: 0.2, // plot fill alpha
  16511. spiderOrigin: 0.16,
  16512. markerSize: 3, // radius of plot vertex (px)
  16513. spiderType: "polygon", //"circle"
  16514. animationType: dojo.fx.easing.backOut,
  16515. axisTickFont: "",
  16516. axisTickFontColor: "",
  16517. axisFont: "",
  16518. axisFontColor: ""
  16519. },
  16520. optionalParams: {
  16521. radius: 0,
  16522. font: "",
  16523. fontColor: ""
  16524. },
  16525. constructor: function(chart, kwArgs){
  16526. // summary:
  16527. // Create a Spider plot.
  16528. this.opt = dojo.clone(this.defaultParams);
  16529. du.updateWithObject(this.opt, kwArgs);
  16530. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  16531. this.series = [];
  16532. this.dyn = [];
  16533. this.datas = {};
  16534. this.labelKey = [];
  16535. this.oldSeriePoints = {};
  16536. this.animations = {};
  16537. },
  16538. clear: function(){
  16539. // summary:
  16540. // Clear out all of the information tied to this plot.
  16541. // returns: dojox.charting.plot2d.Spider
  16542. // A reference to this plot for functional chaining.
  16543. this.dirty = true;
  16544. this.dyn = [];
  16545. this.series = [];
  16546. this.datas = {};
  16547. this.labelKey = [];
  16548. this.oldSeriePoints = {};
  16549. this.animations = {};
  16550. return this; // dojox.charting.plot2d.Spider
  16551. },
  16552. setAxis: function(axis){
  16553. // summary:
  16554. // Dummy method, since axes are irrelevant with a Spider chart.
  16555. // returns: dojox.charting.plot2d.Spider
  16556. // The reference to this plot for functional chaining.
  16557. return this; // dojox.charting.plot2d.Spider
  16558. },
  16559. addSeries: function(run){
  16560. // summary:
  16561. // Add a data series to this plot.
  16562. // run: dojox.charting.Series
  16563. // The series to be added.
  16564. // returns: dojox.charting.plot2d.Base
  16565. // A reference to this plot for functional chaining.
  16566. var matched = false;
  16567. this.series.push(run);
  16568. for(var key in run.data){
  16569. var val = run.data[key],
  16570. data = this.datas[key];
  16571. if(data){
  16572. data.vlist.push(val);
  16573. data.min = Math.min(data.min, val);
  16574. data.max = Math.max(data.max, val);
  16575. }else{
  16576. this.datas[key] = {min: val, max: val, vlist: [val]};
  16577. }
  16578. }
  16579. if (this.labelKey.length <= 0) {
  16580. for (var key in run.data) {
  16581. this.labelKey.push(key);
  16582. }
  16583. }
  16584. return this; // dojox.charting.plot2d.Base
  16585. },
  16586. getSeriesStats: function(){
  16587. // summary:
  16588. // Calculate the min/max on all attached series in both directions.
  16589. // returns: Object
  16590. // {hmin, hmax, vmin, vmax} min/max in both directions.
  16591. return dojox.charting.plot2d.common.collectSimpleStats(this.series);
  16592. },
  16593. calculateAxes: function(dim){
  16594. // summary:
  16595. // Stub function for running the axis calculations (depricated).
  16596. // dim: Object
  16597. // An object of the form { width, height }
  16598. // returns: dojox.charting.plot2d.Base
  16599. // A reference to this plot for functional chaining.
  16600. this.initializeScalers(dim, this.getSeriesStats());
  16601. return this; // dojox.charting.plot2d.Base
  16602. },
  16603. getRequiredColors: function(){
  16604. // summary:
  16605. // Get how many data series we have, so we know how many colors to use.
  16606. // returns: Number
  16607. // The number of colors needed.
  16608. return this.series.length; // Number
  16609. },
  16610. initializeScalers: function(dim, stats){
  16611. // summary:
  16612. // Initializes scalers using attached axes.
  16613. // dim: Object:
  16614. // Size of a plot area in pixels as {width, height}.
  16615. // stats: Object:
  16616. // Min/max of data in both directions as {hmin, hmax, vmin, vmax}.
  16617. // returns: dojox.charting.plot2d.Base
  16618. // A reference to this plot for functional chaining.
  16619. if(this._hAxis){
  16620. if(!this._hAxis.initialized()){
  16621. this._hAxis.calculate(stats.hmin, stats.hmax, dim.width);
  16622. }
  16623. this._hScaler = this._hAxis.getScaler();
  16624. }else{
  16625. this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width);
  16626. }
  16627. if(this._vAxis){
  16628. if(!this._vAxis.initialized()){
  16629. this._vAxis.calculate(stats.vmin, stats.vmax, dim.height);
  16630. }
  16631. this._vScaler = this._vAxis.getScaler();
  16632. }else{
  16633. this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height);
  16634. }
  16635. return this; // dojox.charting.plot2d.Base
  16636. },
  16637. render: function(dim, offsets){
  16638. // summary:
  16639. // Render the plot on the chart.
  16640. // dim: Object
  16641. // An object of the form { width, height }.
  16642. // offsets: Object
  16643. // An object of the form { l, r, t, b }.
  16644. // returns: dojox.charting.plot2d.Spider
  16645. // A reference to this plot for functional chaining.
  16646. if(!this.dirty){ return this; }
  16647. this.dirty = false;
  16648. this.cleanGroup();
  16649. var s = this.group, t = this.chart.theme;
  16650. this.resetEvents();
  16651. if(!this.series || !this.series.length){
  16652. return this;
  16653. }
  16654. // calculate the geometry
  16655. var o = this.opt, ta = t.axis,
  16656. rx = (dim.width - offsets.l - offsets.r) / 2,
  16657. ry = (dim.height - offsets.t - offsets.b) / 2,
  16658. r = Math.min(rx, ry),
  16659. axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma",
  16660. axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma",
  16661. axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver",
  16662. axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
  16663. axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver",
  16664. spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver",
  16665. axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2,
  16666. spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2,
  16667. seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2,
  16668. asize = g.normalizedLength(g.splitFontString(axisFont).size),
  16669. startAngle = m._degToRad(o.startAngle),
  16670. start = startAngle, step, filteredRun, slices, labels, shift, labelR,
  16671. outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints,
  16672. ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize,
  16673. spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10,
  16674. axisExtra = 0.2;
  16675. if(o.labels){
  16676. labels = dojo.map(this.series, function(s){
  16677. return s.name;
  16678. }, this);
  16679. shift = df.foldl1(df.map(labels, function(label, i){
  16680. var font = t.series.font;
  16681. return dojox.gfx._base._getTextBox(label, {
  16682. font: font
  16683. }).w;
  16684. }, this), "Math.max(a, b)") / 2;
  16685. r = Math.min(rx - 2 * shift, ry - asize) + lboffset;
  16686. labelR = r - lboffset;
  16687. }
  16688. if ("radius" in o) {
  16689. r = o.radius;
  16690. labelR = r - lboffset;
  16691. }
  16692. r /= (1+axisExtra);
  16693. var circle = {
  16694. cx: offsets.l + rx,
  16695. cy: offsets.t + ry,
  16696. r: r
  16697. };
  16698. for (var i = this.series.length - 1; i >= 0; i--) {
  16699. var serieEntry = this.series[i];
  16700. if (!this.dirty && !serieEntry.dirty) {
  16701. t.skip();
  16702. continue;
  16703. }
  16704. serieEntry.cleanGroup();
  16705. var run = serieEntry.data;
  16706. if (run !== null) {
  16707. var len = this._getObjectLength(run);
  16708. //construct connect points
  16709. if (!outerPoints || outerPoints.length <= 0) {
  16710. outerPoints = [], innerPoints = [], labelPoints = [];
  16711. this._buildPoints(outerPoints, len, circle, r, start, true);
  16712. this._buildPoints(innerPoints, len, circle, r*ro, start, true);
  16713. this._buildPoints(labelPoints, len, circle, labelR, start);
  16714. if(dv > 2){
  16715. divisionPoints = [], divisionRadius = [];
  16716. for (var j = 0; j < dv - 2; j++) {
  16717. divisionPoints[j] = [];
  16718. this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true);
  16719. divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1));
  16720. }
  16721. }
  16722. }
  16723. }
  16724. }
  16725. //draw Spider
  16726. //axis
  16727. var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth},
  16728. spiderStroke = {color: spiderColor, width: spiderWidth};
  16729. for (var j = outerPoints.length - 1; j >= 0; --j) {
  16730. var point = outerPoints[j],
  16731. st = {
  16732. x: point.x + (point.x - circle.cx) * axisExtra,
  16733. y: point.y + (point.y - circle.cy) * axisExtra
  16734. },
  16735. nd = {
  16736. x: point.x + (point.x - circle.cx) * axisExtra / 2,
  16737. y: point.y + (point.y - circle.cy) * axisExtra / 2
  16738. };
  16739. axisGroup.createLine({
  16740. x1: circle.cx,
  16741. y1: circle.cy,
  16742. x2: st.x,
  16743. y2: st.y
  16744. }).setStroke(axisStroke);
  16745. //arrow
  16746. this._drawArrow(axisGroup, st, nd, axisStroke);
  16747. }
  16748. // draw the label
  16749. var labelGroup = s.createGroup();
  16750. for (var j = labelPoints.length - 1; j >= 0; --j) {
  16751. var point = labelPoints[j],
  16752. fontWidth = dojox.gfx._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0,
  16753. render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
  16754. elem = da.createText[render](this.chart, labelGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
  16755. "middle", this.labelKey[j], axisFont, axisFontColor);
  16756. if (this.opt.htmlLabels) {
  16757. this.htmlElements.push(elem);
  16758. }
  16759. }
  16760. //spider web: polygon or circle
  16761. var spiderGroup = s.createGroup();
  16762. if(spt == "polygon"){
  16763. spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke);
  16764. spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke);
  16765. if (divisionPoints.length > 0) {
  16766. for (var j = divisionPoints.length - 1; j >= 0; --j) {
  16767. spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke);
  16768. }
  16769. }
  16770. }else{//circle
  16771. var ccount = this._getObjectLength(this.datas);
  16772. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke);
  16773. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke);
  16774. if (divisionRadius.length > 0) {
  16775. for (var j = divisionRadius.length - 1; j >= 0; --j) {
  16776. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke);
  16777. }
  16778. }
  16779. }
  16780. //text
  16781. var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0;
  16782. for(var key in this.datas){
  16783. var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
  16784. end = start + 2 * Math.PI * k / len;
  16785. for (var i = 0; i < dv; i++) {
  16786. var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end);
  16787. text = this._getLabel(text);
  16788. var fontWidth = dojox.gfx._base._getTextBox(text, {font: axisTickFont}).w || 0,
  16789. render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
  16790. if (this.opt.htmlLabels) {
  16791. this.htmlElements.push(da.createText[render]
  16792. (this.chart, textGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
  16793. "start", text, axisTickFont, axisTickFontColor));
  16794. }
  16795. }
  16796. k++;
  16797. }
  16798. //draw series (animation)
  16799. this.chart.seriesShapes = {};
  16800. var animationConnections = [];
  16801. for (var i = this.series.length - 1; i >= 0; i--) {
  16802. var serieEntry = this.series[i], run = serieEntry.data;
  16803. if (run !== null) {
  16804. //series polygon
  16805. var seriePoints = [], k = 0, tipData = [];
  16806. for(var key in run){
  16807. var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
  16808. entry = run[key], end = start + 2 * Math.PI * k / len,
  16809. point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end);
  16810. seriePoints.push(point);
  16811. tipData.push({sname: serieEntry.name, key: key, data: entry});
  16812. k++;
  16813. }
  16814. seriePoints[seriePoints.length] = seriePoints[0];
  16815. tipData[tipData.length] = tipData[0];
  16816. var polygonBoundRect = this._getBoundary(seriePoints),
  16817. theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group,
  16818. f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth};
  16819. f.a = o.seriesFillAlpha;
  16820. serieEntry.dyn = {fill: f, stroke: sk};
  16821. var osps = this.oldSeriePoints[serieEntry.name];
  16822. var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at);
  16823. this.chart.seriesShapes[serieEntry.name] = cs;
  16824. this.oldSeriePoints[serieEntry.name] = seriePoints;
  16825. var po = {
  16826. element: "spider_poly",
  16827. index: i,
  16828. id: "spider_poly_"+serieEntry.name,
  16829. run: serieEntry,
  16830. plot: this,
  16831. shape: cs.poly,
  16832. parent: ts,
  16833. brect: polygonBoundRect,
  16834. cx: circle.cx,
  16835. cy: circle.cy,
  16836. cr: r,
  16837. f: f,
  16838. s: s
  16839. };
  16840. this._connectEvents(po);
  16841. var so = {
  16842. element: "spider_plot",
  16843. index: i,
  16844. id: "spider_plot_"+serieEntry.name,
  16845. run: serieEntry,
  16846. plot: this,
  16847. shape: serieEntry.group
  16848. };
  16849. this._connectEvents(so);
  16850. dojo.forEach(cs.circles, function(c, i){
  16851. var shape = c.getShape(),
  16852. co = {
  16853. element: "spider_circle",
  16854. index: i,
  16855. id: "spider_circle_"+serieEntry.name+i,
  16856. run: serieEntry,
  16857. plot: this,
  16858. shape: c,
  16859. parent: ts,
  16860. tdata: tipData[i],
  16861. cx: seriePoints[i].x,
  16862. cy: seriePoints[i].y,
  16863. f: f,
  16864. s: s
  16865. };
  16866. this._connectEvents(co);
  16867. }, this);
  16868. }
  16869. }
  16870. return this; // dojox.charting.plot2d.Spider
  16871. },
  16872. _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){
  16873. //polygon
  16874. var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = [];
  16875. for (var j = 0; j < osps.length; j++) {
  16876. var point = osps[j], cr = ms;
  16877. var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk);
  16878. scircle.push(circle);
  16879. }
  16880. var anims = dojo.map(sps, function(np, j){
  16881. // create animation
  16882. var sp = osps[j],
  16883. anim = new dojo._Animation({
  16884. duration: 1000,
  16885. easing: at,
  16886. curve: [sp.y, np.y]
  16887. });
  16888. var spl = spoly, sc = scircle[j];
  16889. dojo.connect(anim, "onAnimate", function(y){
  16890. //apply poly
  16891. var pshape = spl.getShape();
  16892. pshape.points[j].y = y;
  16893. spl.setShape(pshape);
  16894. //apply circle
  16895. var cshape = sc.getShape();
  16896. cshape.cy = y;
  16897. sc.setShape(cshape);
  16898. });
  16899. return anim;
  16900. });
  16901. var anims1 = dojo.map(sps, function(np, j){
  16902. // create animation
  16903. var sp = osps[j],
  16904. anim = new dojo._Animation({
  16905. duration: 1000,
  16906. easing: at,
  16907. curve: [sp.x, np.x]
  16908. });
  16909. var spl = spoly, sc = scircle[j];
  16910. dojo.connect(anim, "onAnimate", function(x){
  16911. //apply poly
  16912. var pshape = spl.getShape();
  16913. pshape.points[j].x = x;
  16914. spl.setShape(pshape);
  16915. //apply circle
  16916. var cshape = sc.getShape();
  16917. cshape.cx = x;
  16918. sc.setShape(cshape);
  16919. });
  16920. return anim;
  16921. });
  16922. var masterAnimation = dojo.fx.combine(anims.concat(anims1)); //dojo.fx.chain(anims);
  16923. masterAnimation.play();
  16924. return {group :ts, poly: spoly, circles: scircle};
  16925. },
  16926. plotEvent: function(o){
  16927. // summary:
  16928. // Stub function for use by specific plots.
  16929. // o: Object
  16930. // An object intended to represent event parameters.
  16931. var runName = o.id ? o.id : "default", a;
  16932. if (runName in this.animations) {
  16933. a = this.animations[runName];
  16934. a.anim && a.anim.stop(true);
  16935. } else {
  16936. a = this.animations[runName] = {};
  16937. }
  16938. if(o.element == "spider_poly"){
  16939. if(!a.color){
  16940. var color = o.shape.getFill();
  16941. if(!color || !(color instanceof dojo.Color)){
  16942. return;
  16943. }
  16944. a.color = {
  16945. start: color,
  16946. end: transColor(color)
  16947. };
  16948. }
  16949. var start = a.color.start, end = a.color.end;
  16950. if(o.type == "onmouseout"){
  16951. // swap colors
  16952. var t = start; start = end; end = t;
  16953. }
  16954. a.anim = dojox.gfx.fx.animateFill({
  16955. shape: o.shape,
  16956. duration: 800,
  16957. easing: dojo.fx.easing.backOut,
  16958. color: {start: start, end: end}
  16959. });
  16960. a.anim.play();
  16961. }else if(o.element == "spider_circle"){
  16962. var init, scale, defaultScale = 1.5;
  16963. if(o.type == "onmouseover"){
  16964. init = dojox.gfx.matrix.identity;
  16965. scale = defaultScale;
  16966. //show tooltip
  16967. var aroundRect = {type: "rect"};
  16968. aroundRect.x = o.cx;
  16969. aroundRect.y = o.cy;
  16970. aroundRect.width = aroundRect.height = 1;
  16971. var lt = dojo.coords(this.chart.node, true);
  16972. aroundRect.x += lt.x;
  16973. aroundRect.y += lt.y;
  16974. aroundRect.x = Math.round(aroundRect.x);
  16975. aroundRect.y = Math.round(aroundRect.y);
  16976. aroundRect.width = Math.ceil(aroundRect.width);
  16977. aroundRect.height = Math.ceil(aroundRect.height);
  16978. this.aroundRect = aroundRect;
  16979. var position = ["after", "before"];
  16980. if(dijit && dijit.Tooltip){
  16981. dijit.showTooltip(o.tdata.sname + "<br/>" + o.tdata.key + "<br/>" + o.tdata.data, this.aroundRect, position);
  16982. }
  16983. }else{
  16984. init = dojox.gfx.matrix.scaleAt(defaultScale, o.cx, o.cy);
  16985. scale = 1/defaultScale;
  16986. if(dijit && dijit.Tooltip){
  16987. this.aroundRect && dijit.hideTooltip(this.aroundRect);
  16988. }
  16989. }
  16990. var cs = o.shape.getShape(),
  16991. init = m.scaleAt(defaultScale, cs.cx, cs.cy),
  16992. kwArgs = {
  16993. shape: o.shape,
  16994. duration: 200,
  16995. easing: dojo.fx.easing.backOut,
  16996. transform: [
  16997. {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]},
  16998. init
  16999. ]
  17000. };
  17001. a.anim = dojox.gfx.fx.animateTransform(kwArgs);
  17002. a.anim.play();
  17003. }else if(o.element == "spider_plot"){
  17004. //dojo gfx function "moveToFront" not work in IE
  17005. if (o.type == "onmouseover" && !dojo.isIE) {
  17006. o.shape.moveToFront();
  17007. }
  17008. }
  17009. },
  17010. _getBoundary: function(points){
  17011. var xmax = points[0].x,
  17012. xmin = points[0].x,
  17013. ymax = points[0].y,
  17014. ymin = points[0].y;
  17015. for(var i = 0; i < points.length; i++){
  17016. var point = points[i];
  17017. xmax = Math.max(point.x, xmax);
  17018. ymax = Math.max(point.y, ymax);
  17019. xmin = Math.min(point.x, xmin);
  17020. ymin = Math.min(point.y, ymin);
  17021. }
  17022. return {
  17023. x: xmin,
  17024. y: ymin,
  17025. width: xmax - xmin,
  17026. height: ymax - ymin
  17027. };
  17028. },
  17029. _drawArrow: function(s, start, end, stroke){
  17030. var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)),
  17031. sin = (end.y - start.y)/len, cos = (end.x - start.x)/len,
  17032. point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos},
  17033. point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)};
  17034. s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke);
  17035. },
  17036. _buildPoints: function(points, count, circle, radius, angle, recursive){
  17037. for (var i = 0; i < count; i++) {
  17038. var end = angle + 2 * Math.PI * i / count;
  17039. points.push(this._getCoordinate(circle, radius, end));
  17040. }
  17041. if(recursive){
  17042. points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI));
  17043. }
  17044. },
  17045. _getCoordinate: function(circle, radius, angle){
  17046. return {
  17047. x: circle.cx + radius * Math.cos(angle),
  17048. y: circle.cy + radius * Math.sin(angle)
  17049. }
  17050. },
  17051. _getObjectLength: function(obj){
  17052. var count = 0;
  17053. if(dojo.isObject(obj)){
  17054. for(var key in obj){
  17055. count++;
  17056. }
  17057. }
  17058. return count;
  17059. },
  17060. // utilities
  17061. _getLabel: function(number){
  17062. return dc.getLabel(number, this.opt.fixed, this.opt.precision);
  17063. }
  17064. });
  17065. function transColor(color){
  17066. var a = new dojox.color.Color(color),
  17067. x = a.toHsl();
  17068. if(x.s == 0){
  17069. x.l = x.l < 50 ? 100 : 0;
  17070. }else{
  17071. x.s = 100;
  17072. if(x.l < 50){
  17073. x.l = 75;
  17074. }else if(x.l > 75){
  17075. x.l = 50;
  17076. }else{
  17077. x.l = x.l - 50 > 75 - x.l ?
  17078. 50 : 75;
  17079. }
  17080. }
  17081. var color = dojox.color.fromHsl(x);
  17082. color.a = 0.7;
  17083. return color;
  17084. }
  17085. })();
  17086. }
  17087. if(!dojo._hasResource["dojox.charting.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  17088. dojo._hasResource["dojox.charting.Chart2D"] = true;
  17089. dojo.provide("dojox.charting.Chart2D");
  17090. dojo.deprecated("dojox.charting.Chart2D", "Use dojo.charting.Chart instead and require all other components explicitly", "2.0");
  17091. // require all axes to support references by name
  17092. // require all plots to support references by name
  17093. // require the main file
  17094. dojox.charting.Chart2D = dojox.charting.Chart;
  17095. }
  17096. if(!dojo._hasResource["dojox.charting.widget.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  17097. dojo._hasResource["dojox.charting.widget.Chart2D"] = true;
  17098. dojo.provide("dojox.charting.widget.Chart2D");
  17099. dojo.deprecated("dojox.charting.widget.Chart2D", "Use dojo.charting.widget.Chart instead and require all other components explicitly", "2.0");
  17100. // require all actions to support references by name
  17101. // require Chart2D to get compatibility on chart type reference by name
  17102. dojox.charting.widget.Chart2D = dojox.charting.widget.Chart;
  17103. }
  17104. if(!dojo._hasResource["dojox.charting.themes.GreySkies"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  17105. dojo._hasResource["dojox.charting.themes.GreySkies"] = true;
  17106. dojo.provide("dojox.charting.themes.GreySkies");
  17107. (function(){
  17108. var dxc=dojox.charting;
  17109. dxc.themes.GreySkies=new dxc.Theme(dxc.Theme._def);
  17110. })();
  17111. }
  17112. if(!dojo._hasResource["dojox.charting.widget.Sparkline"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  17113. dojo._hasResource["dojox.charting.widget.Sparkline"] = true;
  17114. dojo.provide("dojox.charting.widget.Sparkline");
  17115. (function(){
  17116. var d = dojo;
  17117. dojo.declare("dojox.charting.widget.Sparkline",
  17118. dojox.charting.widget.Chart2D,
  17119. {
  17120. theme: dojox.charting.themes.GreySkies,
  17121. margins: { l: 0, r: 0, t: 0, b: 0 },
  17122. type: "Lines",
  17123. valueFn: "Number(x)",
  17124. store: "",
  17125. field: "",
  17126. query: "",
  17127. queryOptions: "",
  17128. start: "0",
  17129. count: "Infinity",
  17130. sort: "",
  17131. data: "",
  17132. name: "default",
  17133. buildRendering: function(){
  17134. var n = this.srcNodeRef;
  17135. if( !n.childNodes.length || // shortcut the query
  17136. !d.query("> .axis, > .plot, > .action, > .series", n).length){
  17137. var plot = document.createElement("div");
  17138. d.attr(plot, {
  17139. "class": "plot",
  17140. "name": "default",
  17141. "type": this.type
  17142. });
  17143. n.appendChild(plot);
  17144. var series = document.createElement("div");
  17145. d.attr(series, {
  17146. "class": "series",
  17147. plot: "default",
  17148. name: this.name,
  17149. start: this.start,
  17150. count: this.count,
  17151. valueFn: this.valueFn
  17152. });
  17153. d.forEach(
  17154. ["store", "field", "query", "queryOptions", "sort", "data"],
  17155. function(i){
  17156. if(this[i].length){
  17157. d.attr(series, i, this[i]);
  17158. }
  17159. },
  17160. this
  17161. );
  17162. n.appendChild(series);
  17163. }
  17164. this.inherited(arguments);
  17165. }
  17166. }
  17167. );
  17168. })();
  17169. }
  17170. if(!dojo._hasResource["dojox.charting.widget.Legend"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  17171. dojo._hasResource["dojox.charting.widget.Legend"] = true;
  17172. dojo.provide("dojox.charting.widget.Legend");
  17173. var REVERSED_SERIES = /\.(StackedColumns|StackedAreas|ClusteredBars)$/;
  17174. dojo.declare("dojox.charting.widget.Legend", [dijit._Widget, dijit._Templated], {
  17175. // summary: A legend for a chart. A legend contains summary labels for
  17176. // each series of data contained in the chart.
  17177. //
  17178. // Set the horizontal attribute to boolean false to layout legend labels vertically.
  17179. // Set the horizontal attribute to a number to layout legend labels in horizontal
  17180. // rows each containing that number of labels (except possibly the last row).
  17181. //
  17182. // (Line or Scatter charts (colored lines with shape symbols) )
  17183. // -o- Series1 -X- Series2 -v- Series3
  17184. //
  17185. // (Area/Bar/Pie charts (letters represent colors))
  17186. // [a] Series1 [b] Series2 [c] Series3
  17187. chartRef: "",
  17188. horizontal: true,
  17189. swatchSize: 18,
  17190. templateString: "<table dojoAttachPoint='legendNode' class='dojoxLegendNode' role='group' aria-label='chart legend'><tbody dojoAttachPoint='legendBody'></tbody></table>",
  17191. legendNode: null,
  17192. legendBody: null,
  17193. postCreate: function(){
  17194. if(!this.chart){
  17195. if(!this.chartRef){ return; }
  17196. this.chart = dijit.byId(this.chartRef);
  17197. if(!this.chart){
  17198. var node = dojo.byId(this.chartRef);
  17199. if(node){
  17200. this.chart = dijit.byNode(node);
  17201. }else{
  17202. console.log("Could not find chart instance with id: " + this.chartRef);
  17203. return;
  17204. }
  17205. }
  17206. this.series = this.chart.chart.series;
  17207. }else{
  17208. this.series = this.chart.series;
  17209. }
  17210. this.refresh();
  17211. },
  17212. refresh: function(){
  17213. // summary: regenerates the legend to reflect changes to the chart
  17214. var df = dojox.lang.functional;
  17215. // cleanup
  17216. if(this._surfaces){
  17217. dojo.forEach(this._surfaces, function(surface){
  17218. surface.destroy();
  17219. });
  17220. }
  17221. this._surfaces = [];
  17222. while(this.legendBody.lastChild){
  17223. dojo.destroy(this.legendBody.lastChild);
  17224. }
  17225. if(this.horizontal){
  17226. dojo.addClass(this.legendNode, "dojoxLegendHorizontal");
  17227. // make a container <tr>
  17228. this._tr = dojo.create("tr", null, this.legendBody);
  17229. this._inrow = 0;
  17230. }
  17231. var s = this.series;
  17232. if(s.length == 0){
  17233. return;
  17234. }
  17235. if(s[0].chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie"){
  17236. var t = s[0].chart.stack[0];
  17237. if(typeof t.run.data[0] == "number"){
  17238. var filteredRun = df.map(t.run.data, "Math.max(x, 0)");
  17239. if(df.every(filteredRun, "<= 0")){
  17240. return;
  17241. }
  17242. var slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0));
  17243. dojo.forEach(slices, function(x, i){
  17244. this._addLabel(t.dyn[i], t._getLabel(x * 100) + "%");
  17245. }, this);
  17246. }else{
  17247. dojo.forEach(t.run.data, function(x, i){
  17248. this._addLabel(t.dyn[i], x.legend || x.text || x.y);
  17249. }, this);
  17250. }
  17251. }else{
  17252. if(this._isReversal()){
  17253. s = s.slice(0).reverse();
  17254. }
  17255. dojo.forEach(s, function(x){
  17256. this._addLabel(x.dyn, x.legend || x.name);
  17257. }, this);
  17258. }
  17259. },
  17260. _addLabel: function(dyn, label){
  17261. // create necessary elements
  17262. var wrapper = dojo.create("td"),
  17263. icon = dojo.create("div", null, wrapper),
  17264. text = dojo.create("label", null, wrapper),
  17265. div = dojo.create("div", {
  17266. style: {
  17267. "width": this.swatchSize + "px",
  17268. "height":this.swatchSize + "px",
  17269. "float": "left"
  17270. }
  17271. }, icon);
  17272. dojo.addClass(icon, "dojoxLegendIcon dijitInline");
  17273. dojo.addClass(text, "dojoxLegendText");
  17274. // create a skeleton
  17275. if(this._tr){
  17276. // horizontal
  17277. this._tr.appendChild(wrapper);
  17278. if(++this._inrow === this.horizontal){
  17279. // make a fresh container <tr>
  17280. this._tr = dojo.create("tr", null, this.legendBody);
  17281. this._inrow = 0;
  17282. }
  17283. }else{
  17284. // vertical
  17285. var tr = dojo.create("tr", null, this.legendBody);
  17286. tr.appendChild(wrapper);
  17287. }
  17288. // populate the skeleton
  17289. this._makeIcon(div, dyn);
  17290. text.innerHTML = String(label);
  17291. },
  17292. _makeIcon: function(div, dyn){
  17293. var mb = { h: this.swatchSize, w: this.swatchSize };
  17294. var surface = dojox.gfx.createSurface(div, mb.w, mb.h);
  17295. this._surfaces.push(surface);
  17296. if(dyn.fill){
  17297. // regions
  17298. surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}).
  17299. setFill(dyn.fill).setStroke(dyn.stroke);
  17300. }else if(dyn.stroke || dyn.marker){
  17301. // draw line
  17302. var line = {x1: 0, y1: mb.h / 2, x2: mb.w, y2: mb.h / 2};
  17303. if(dyn.stroke){
  17304. surface.createLine(line).setStroke(dyn.stroke);
  17305. }
  17306. if(dyn.marker){
  17307. // draw marker on top
  17308. var c = {x: mb.w / 2, y: mb.h / 2};
  17309. if(dyn.stroke){
  17310. surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}).
  17311. setFill(dyn.stroke.color).setStroke(dyn.stroke);
  17312. }else{
  17313. surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}).
  17314. setFill(dyn.color).setStroke(dyn.color);
  17315. }
  17316. }
  17317. }else{
  17318. // nothing
  17319. surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}).
  17320. setStroke("black");
  17321. surface.createLine({x1: 2, y1: 2, x2: mb.w - 2, y2: mb.h - 2}).setStroke("black");
  17322. surface.createLine({x1: 2, y1: mb.h - 2, x2: mb.w - 2, y2: 2}).setStroke("black");
  17323. }
  17324. },
  17325. _isReversal: function(){
  17326. return (!this.horizontal) && dojo.some(this.chart.stack, function(item){
  17327. return REVERSED_SERIES.test(item.declaredClass);
  17328. });
  17329. }
  17330. });
  17331. }