mxGraph.js 330 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231
  1. /**
  2. * Copyright (c) 2006-2015, JGraph Ltd
  3. * Copyright (c) 2006-2015, Gaudenz Alder
  4. */
  5. /**
  6. * Class: mxGraph
  7. *
  8. * Extends <mxEventSource> to implement a graph component for
  9. * the browser. This is the main class of the package. To activate
  10. * panning and connections use <setPanning> and <setConnectable>.
  11. * For rubberband selection you must create a new instance of
  12. * <mxRubberband>. The following listeners are added to
  13. * <mouseListeners> by default:
  14. *
  15. * - <tooltipHandler>: <mxTooltipHandler> that displays tooltips
  16. * - <panningHandler>: <mxPanningHandler> for panning and popup menus
  17. * - <connectionHandler>: <mxConnectionHandler> for creating connections
  18. * - <graphHandler>: <mxGraphHandler> for moving and cloning cells
  19. *
  20. * These listeners will be called in the above order if they are enabled.
  21. *
  22. * Background Images:
  23. *
  24. * To display a background image, set the image, image width and
  25. * image height using <setBackgroundImage>. If one of the
  26. * above values has changed then the <view>'s <mxGraphView.validate>
  27. * should be invoked.
  28. *
  29. * Cell Images:
  30. *
  31. * To use images in cells, a shape must be specified in the default
  32. * vertex style (or any named style). Possible shapes are
  33. * <mxConstants.SHAPE_IMAGE> and <mxConstants.SHAPE_LABEL>.
  34. * The code to change the shape used in the default vertex style,
  35. * the following code is used:
  36. *
  37. * (code)
  38. * var style = graph.getStylesheet().getDefaultVertexStyle();
  39. * style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_IMAGE;
  40. * (end)
  41. *
  42. * For the default vertex style, the image to be displayed can be
  43. * specified in a cell's style using the <mxConstants.STYLE_IMAGE>
  44. * key and the image URL as a value, for example:
  45. *
  46. * (code)
  47. * image=http://www.example.com/image.gif
  48. * (end)
  49. *
  50. * For a named style, the the stylename must be the first element
  51. * of the cell style:
  52. *
  53. * (code)
  54. * stylename;image=http://www.example.com/image.gif
  55. * (end)
  56. *
  57. * A cell style can have any number of key=value pairs added, divided
  58. * by a semicolon as follows:
  59. *
  60. * (code)
  61. * [stylename;|key=value;]
  62. * (end)
  63. *
  64. * Labels:
  65. *
  66. * The cell labels are defined by <getLabel> which uses <convertValueToString>
  67. * if <labelsVisible> is true. If a label must be rendered as HTML markup, then
  68. * <isHtmlLabel> should return true for the respective cell. If all labels
  69. * contain HTML markup, <htmlLabels> can be set to true. NOTE: Enabling HTML
  70. * labels carries a possible security risk (see the section on security in
  71. * the manual).
  72. *
  73. * If wrapping is needed for a label, then <isHtmlLabel> and <isWrapping> must
  74. * return true for the cell whose label should be wrapped. See <isWrapping> for
  75. * an example.
  76. *
  77. * If clipping is needed to keep the rendering of a HTML label inside the
  78. * bounds of its vertex, then <isClipping> should return true for the
  79. * respective cell.
  80. *
  81. * By default, edge labels are movable and vertex labels are fixed. This can be
  82. * changed by setting <edgeLabelsMovable> and <vertexLabelsMovable>, or by
  83. * overriding <isLabelMovable>.
  84. *
  85. * In-place Editing:
  86. *
  87. * In-place editing is started with a doubleclick or by typing F2.
  88. * Programmatically, <edit> is used to check if the cell is editable
  89. * (<isCellEditable>) and call <startEditingAtCell>, which invokes
  90. * <mxCellEditor.startEditing>. The editor uses the value returned
  91. * by <getEditingValue> as the editing value.
  92. *
  93. * After in-place editing, <labelChanged> is called, which invokes
  94. * <mxGraphModel.setValue>, which in turn calls
  95. * <mxGraphModel.valueForCellChanged> via <mxValueChange>.
  96. *
  97. * The event that triggers in-place editing is passed through to the
  98. * <cellEditor>, which may take special actions depending on the type of the
  99. * event or mouse location, and is also passed to <getEditingValue>. The event
  100. * is then passed back to the event processing functions which can perform
  101. * specific actions based on the trigger event.
  102. *
  103. * Tooltips:
  104. *
  105. * Tooltips are implemented by <getTooltip>, which calls <getTooltipForCell>
  106. * if a cell is under the mousepointer. The default implementation checks if
  107. * the cell has a getTooltip function and calls it if it exists. Hence, in order
  108. * to provide custom tooltips, the cell must provide a getTooltip function, or
  109. * one of the two above functions must be overridden.
  110. *
  111. * Typically, for custom cell tooltips, the latter function is overridden as
  112. * follows:
  113. *
  114. * (code)
  115. * graph.getTooltipForCell = function(cell)
  116. * {
  117. * var label = this.convertValueToString(cell);
  118. * return 'Tooltip for '+label;
  119. * }
  120. * (end)
  121. *
  122. * When using a config file, the function is overridden in the mxGraph section
  123. * using the following entry:
  124. *
  125. * (code)
  126. * <add as="getTooltipForCell"><![CDATA[
  127. * function(cell)
  128. * {
  129. * var label = this.convertValueToString(cell);
  130. * return 'Tooltip for '+label;
  131. * }
  132. * ]]></add>
  133. * (end)
  134. *
  135. * "this" refers to the graph in the implementation, so for example to check if
  136. * a cell is an edge, you use this.getModel().isEdge(cell)
  137. *
  138. * For replacing the default implementation of <getTooltipForCell> (rather than
  139. * replacing the function on a specific instance), the following code should be
  140. * used after loading the JavaScript files, but before creating a new mxGraph
  141. * instance using <mxGraph>:
  142. *
  143. * (code)
  144. * mxGraph.prototype.getTooltipForCell = function(cell)
  145. * {
  146. * var label = this.convertValueToString(cell);
  147. * return 'Tooltip for '+label;
  148. * }
  149. * (end)
  150. *
  151. * Shapes & Styles:
  152. *
  153. * The implementation of new shapes is demonstrated in the examples. We'll assume
  154. * that we have implemented a custom shape with the name BoxShape which we want
  155. * to use for drawing vertices. To use this shape, it must first be registered in
  156. * the cell renderer as follows:
  157. *
  158. * (code)
  159. * mxCellRenderer.registerShape('box', BoxShape);
  160. * (end)
  161. *
  162. * The code registers the BoxShape constructor under the name box in the cell
  163. * renderer of the graph. The shape can now be referenced using the shape-key in
  164. * a style definition. (The cell renderer contains a set of additional shapes,
  165. * namely one for each constant with a SHAPE-prefix in <mxConstants>.)
  166. *
  167. * Styles are a collection of key, value pairs and a stylesheet is a collection
  168. * of named styles. The names are referenced by the cellstyle, which is stored
  169. * in <mxCell.style> with the following format: [stylename;|key=value;]. The
  170. * string is resolved to a collection of key, value pairs, where the keys are
  171. * overridden with the values in the string.
  172. *
  173. * When introducing a new shape, the name under which the shape is registered
  174. * must be used in the stylesheet. There are three ways of doing this:
  175. *
  176. * - By changing the default style, so that all vertices will use the new
  177. * shape
  178. * - By defining a new style, so that only vertices with the respective
  179. * cellstyle will use the new shape
  180. * - By using shape=box in the cellstyle's optional list of key, value pairs
  181. * to be overridden
  182. *
  183. * In the first case, the code to fetch and modify the default style for
  184. * vertices is as follows:
  185. *
  186. * (code)
  187. * var style = graph.getStylesheet().getDefaultVertexStyle();
  188. * style[mxConstants.STYLE_SHAPE] = 'box';
  189. * (end)
  190. *
  191. * The code takes the default vertex style, which is used for all vertices that
  192. * do not have a specific cellstyle, and modifies the value for the shape-key
  193. * in-place to use the new BoxShape for drawing vertices. This is done by
  194. * assigning the box value in the second line, which refers to the name of the
  195. * BoxShape in the cell renderer.
  196. *
  197. * In the second case, a collection of key, value pairs is created and then
  198. * added to the stylesheet under a new name. In order to distinguish the
  199. * shapename and the stylename we'll use boxstyle for the stylename:
  200. *
  201. * (code)
  202. * var style = new Object();
  203. * style[mxConstants.STYLE_SHAPE] = 'box';
  204. * style[mxConstants.STYLE_STROKECOLOR] = '#000000';
  205. * style[mxConstants.STYLE_FONTCOLOR] = '#000000';
  206. * graph.getStylesheet().putCellStyle('boxstyle', style);
  207. * (end)
  208. *
  209. * The code adds a new style with the name boxstyle to the stylesheet. To use
  210. * this style with a cell, it must be referenced from the cellstyle as follows:
  211. *
  212. * (code)
  213. * var vertex = graph.insertVertex(parent, null, 'Hello, World!', 20, 20, 80, 20,
  214. * 'boxstyle');
  215. * (end)
  216. *
  217. * To summarize, each new shape must be registered in the <mxCellRenderer> with
  218. * a unique name. That name is then used as the value of the shape-key in a
  219. * default or custom style. If there are multiple custom shapes, then there
  220. * should be a separate style for each shape.
  221. *
  222. * Inheriting Styles:
  223. *
  224. * For fill-, stroke-, gradient-, font- and indicatorColors special keywords
  225. * can be used. The inherit keyword for one of these colors will inherit the
  226. * color for the same key from the parent cell. The swimlane keyword does the
  227. * same, but inherits from the nearest swimlane in the ancestor hierarchy.
  228. * Finally, the indicated keyword will use the color of the indicator as the
  229. * color for the given key.
  230. *
  231. * Scrollbars:
  232. *
  233. * The <containers> overflow CSS property defines if scrollbars are used to
  234. * display the graph. For values of 'auto' or 'scroll', the scrollbars will
  235. * be shown. Note that the <resizeContainer> flag is normally not used
  236. * together with scrollbars, as it will resize the container to match the
  237. * size of the graph after each change.
  238. *
  239. * Multiplicities and Validation:
  240. *
  241. * To control the possible connections in mxGraph, <getEdgeValidationError> is
  242. * used. The default implementation of the function uses <multiplicities>,
  243. * which is an array of <mxMultiplicity>. Using this class allows to establish
  244. * simple multiplicities, which are enforced by the graph.
  245. *
  246. * The <mxMultiplicity> uses <mxCell.is> to determine for which terminals it
  247. * applies. The default implementation of <mxCell.is> works with DOM nodes (XML
  248. * nodes) and checks if the given type parameter matches the nodeName of the
  249. * node (case insensitive). Optionally, an attributename and value can be
  250. * specified which are also checked.
  251. *
  252. * <getEdgeValidationError> is called whenever the connectivity of an edge
  253. * changes. It returns an empty string or an error message if the edge is
  254. * invalid or null if the edge is valid. If the returned string is not empty
  255. * then it is displayed as an error message.
  256. *
  257. * <mxMultiplicity> allows to specify the multiplicity between a terminal and
  258. * its possible neighbors. For example, if any rectangle may only be connected
  259. * to, say, a maximum of two circles you can add the following rule to
  260. * <multiplicities>:
  261. *
  262. * (code)
  263. * graph.multiplicities.push(new mxMultiplicity(
  264. * true, 'rectangle', null, null, 0, 2, ['circle'],
  265. * 'Only 2 targets allowed',
  266. * 'Only shape targets allowed'));
  267. * (end)
  268. *
  269. * This will display the first error message whenever a rectangle is connected
  270. * to more than two circles and the second error message if a rectangle is
  271. * connected to anything but a circle.
  272. *
  273. * For certain multiplicities, such as a minimum of 1 connection, which cannot
  274. * be enforced at cell creation time (unless the cell is created together with
  275. * the connection), mxGraph offers <validate> which checks all multiplicities
  276. * for all cells and displays the respective error messages in an overlay icon
  277. * on the cells.
  278. *
  279. * If a cell is collapsed and contains validation errors, a respective warning
  280. * icon is attached to the collapsed cell.
  281. *
  282. * Auto-Layout:
  283. *
  284. * For automatic layout, the <getLayout> hook is provided in <mxLayoutManager>.
  285. * It can be overridden to return a layout algorithm for the children of a
  286. * given cell.
  287. *
  288. * Unconnected edges:
  289. *
  290. * The default values for all switches are designed to meet the requirements of
  291. * general diagram drawing applications. A very typical set of settings to
  292. * avoid edges that are not connected is the following:
  293. *
  294. * (code)
  295. * graph.setAllowDanglingEdges(false);
  296. * graph.setDisconnectOnMove(false);
  297. * (end)
  298. *
  299. * Setting the <cloneInvalidEdges> switch to true is optional. This switch
  300. * controls if edges are inserted after a copy, paste or clone-drag if they are
  301. * invalid. For example, edges are invalid if copied or control-dragged without
  302. * having selected the corresponding terminals and allowDanglingEdges is
  303. * false, in which case the edges will not be cloned if the switch is false.
  304. *
  305. * Output:
  306. *
  307. * To produce an XML representation for a diagram, the following code can be
  308. * used.
  309. *
  310. * (code)
  311. * var enc = new mxCodec(mxUtils.createXmlDocument());
  312. * var node = enc.encode(graph.getModel());
  313. * (end)
  314. *
  315. * This will produce an XML node than can be handled using the DOM API or
  316. * turned into a string representation using the following code:
  317. *
  318. * (code)
  319. * var xml = mxUtils.getXml(node);
  320. * (end)
  321. *
  322. * To obtain a formatted string, mxUtils.getPrettyXml can be used instead.
  323. *
  324. * This string can now be stored in a local persistent storage (for example
  325. * using Google Gears) or it can be passed to a backend using mxUtils.post as
  326. * follows. The url variable is the URL of the Java servlet, PHP page or HTTP
  327. * handler, depending on the server.
  328. *
  329. * (code)
  330. * var xmlString = encodeURIComponent(mxUtils.getXml(node));
  331. * mxUtils.post(url, 'xml='+xmlString, function(req)
  332. * {
  333. * // Process server response using req of type mxXmlRequest
  334. * });
  335. * (end)
  336. *
  337. * Input:
  338. *
  339. * To load an XML representation of a diagram into an existing graph object
  340. * mxUtils.load can be used as follows. The url variable is the URL of the Java
  341. * servlet, PHP page or HTTP handler that produces the XML string.
  342. *
  343. * (code)
  344. * var xmlDoc = mxUtils.load(url).getXml();
  345. * var node = xmlDoc.documentElement;
  346. * var dec = new mxCodec(node.ownerDocument);
  347. * dec.decode(node, graph.getModel());
  348. * (end)
  349. *
  350. * For creating a page that loads the client and a diagram using a single
  351. * request please refer to the deployment examples in the backends.
  352. *
  353. * Functional dependencies:
  354. *
  355. * (see images/callgraph.png)
  356. *
  357. * Resources:
  358. *
  359. * resources/graph - Language resources for mxGraph
  360. *
  361. * Group: Events
  362. *
  363. * Event: mxEvent.ROOT
  364. *
  365. * Fires if the root in the model has changed. This event has no properties.
  366. *
  367. * Event: mxEvent.ALIGN_CELLS
  368. *
  369. * Fires between begin- and endUpdate in <alignCells>. The <code>cells</code>
  370. * and <code>align</code> properties contain the respective arguments that were
  371. * passed to <alignCells>.
  372. *
  373. * Event: mxEvent.FLIP_EDGE
  374. *
  375. * Fires between begin- and endUpdate in <flipEdge>. The <code>edge</code>
  376. * property contains the edge passed to <flipEdge>.
  377. *
  378. * Event: mxEvent.ORDER_CELLS
  379. *
  380. * Fires between begin- and endUpdate in <orderCells>. The <code>cells</code>
  381. * and <code>back</code> properties contain the respective arguments that were
  382. * passed to <orderCells>.
  383. *
  384. * Event: mxEvent.CELLS_ORDERED
  385. *
  386. * Fires between begin- and endUpdate in <cellsOrdered>. The <code>cells</code>
  387. * and <code>back</code> arguments contain the respective arguments that were
  388. * passed to <cellsOrdered>.
  389. *
  390. * Event: mxEvent.GROUP_CELLS
  391. *
  392. * Fires between begin- and endUpdate in <groupCells>. The <code>group</code>,
  393. * <code>cells</code> and <code>border</code> arguments contain the respective
  394. * arguments that were passed to <groupCells>.
  395. *
  396. * Event: mxEvent.UNGROUP_CELLS
  397. *
  398. * Fires between begin- and endUpdate in <ungroupCells>. The <code>cells</code>
  399. * property contains the array of cells that was passed to <ungroupCells>.
  400. *
  401. * Event: mxEvent.REMOVE_CELLS_FROM_PARENT
  402. *
  403. * Fires between begin- and endUpdate in <removeCellsFromParent>. The
  404. * <code>cells</code> property contains the array of cells that was passed to
  405. * <removeCellsFromParent>.
  406. *
  407. * Event: mxEvent.ADD_CELLS
  408. *
  409. * Fires between begin- and endUpdate in <addCells>. The <code>cells</code>,
  410. * <code>parent</code>, <code>index</code>, <code>source</code> and
  411. * <code>target</code> properties contain the respective arguments that were
  412. * passed to <addCells>.
  413. *
  414. * Event: mxEvent.CELLS_ADDED
  415. *
  416. * Fires between begin- and endUpdate in <cellsAdded>. The <code>cells</code>,
  417. * <code>parent</code>, <code>index</code>, <code>source</code>,
  418. * <code>target</code> and <code>absolute</code> properties contain the
  419. * respective arguments that were passed to <cellsAdded>.
  420. *
  421. * Event: mxEvent.REMOVE_CELLS
  422. *
  423. * Fires between begin- and endUpdate in <removeCells>. The <code>cells</code>
  424. * and <code>includeEdges</code> arguments contain the respective arguments
  425. * that were passed to <removeCells>.
  426. *
  427. * Event: mxEvent.CELLS_REMOVED
  428. *
  429. * Fires between begin- and endUpdate in <cellsRemoved>. The <code>cells</code>
  430. * argument contains the array of cells that was removed.
  431. *
  432. * Event: mxEvent.SPLIT_EDGE
  433. *
  434. * Fires between begin- and endUpdate in <splitEdge>. The <code>edge</code>
  435. * property contains the edge to be splitted, the <code>cells</code>,
  436. * <code>newEdge</code>, <code>dx</code> and <code>dy</code> properties contain
  437. * the respective arguments that were passed to <splitEdge>.
  438. *
  439. * Event: mxEvent.TOGGLE_CELLS
  440. *
  441. * Fires between begin- and endUpdate in <toggleCells>. The <code>show</code>,
  442. * <code>cells</code> and <code>includeEdges</code> properties contain the
  443. * respective arguments that were passed to <toggleCells>.
  444. *
  445. * Event: mxEvent.FOLD_CELLS
  446. *
  447. * Fires between begin- and endUpdate in <foldCells>. The
  448. * <code>collapse</code>, <code>cells</code> and <code>recurse</code>
  449. * properties contain the respective arguments that were passed to <foldCells>.
  450. *
  451. * Event: mxEvent.CELLS_FOLDED
  452. *
  453. * Fires between begin- and endUpdate in cellsFolded. The
  454. * <code>collapse</code>, <code>cells</code> and <code>recurse</code>
  455. * properties contain the respective arguments that were passed to
  456. * <cellsFolded>.
  457. *
  458. * Event: mxEvent.UPDATE_CELL_SIZE
  459. *
  460. * Fires between begin- and endUpdate in <updateCellSize>. The
  461. * <code>cell</code> and <code>ignoreChildren</code> properties contain the
  462. * respective arguments that were passed to <updateCellSize>.
  463. *
  464. * Event: mxEvent.RESIZE_CELLS
  465. *
  466. * Fires between begin- and endUpdate in <resizeCells>. The <code>cells</code>
  467. * and <code>bounds</code> properties contain the respective arguments that
  468. * were passed to <resizeCells>.
  469. *
  470. * Event: mxEvent.CELLS_RESIZED
  471. *
  472. * Fires between begin- and endUpdate in <cellsResized>. The <code>cells</code>
  473. * and <code>bounds</code> properties contain the respective arguments that
  474. * were passed to <cellsResized>.
  475. *
  476. * Event: mxEvent.MOVE_CELLS
  477. *
  478. * Fires between begin- and endUpdate in <moveCells>. The <code>cells</code>,
  479. * <code>dx</code>, <code>dy</code>, <code>clone</code>, <code>target</code>
  480. * and <code>event</code> properties contain the respective arguments that
  481. * were passed to <moveCells>.
  482. *
  483. * Event: mxEvent.CELLS_MOVED
  484. *
  485. * Fires between begin- and endUpdate in <cellsMoved>. The <code>cells</code>,
  486. * <code>dx</code>, <code>dy</code> and <code>disconnect</code> properties
  487. * contain the respective arguments that were passed to <cellsMoved>.
  488. *
  489. * Event: mxEvent.CONNECT_CELL
  490. *
  491. * Fires between begin- and endUpdate in <connectCell>. The <code>edge</code>,
  492. * <code>terminal</code> and <code>source</code> properties contain the
  493. * respective arguments that were passed to <connectCell>.
  494. *
  495. * Event: mxEvent.CELL_CONNECTED
  496. *
  497. * Fires between begin- and endUpdate in <cellConnected>. The
  498. * <code>edge</code>, <code>terminal</code> and <code>source</code> properties
  499. * contain the respective arguments that were passed to <cellConnected>.
  500. *
  501. * Event: mxEvent.REFRESH
  502. *
  503. * Fires after <refresh> was executed. This event has no properties.
  504. *
  505. * Event: mxEvent.CLICK
  506. *
  507. * Fires in <click> after a click event. The <code>event</code> property
  508. * contains the original mouse event and <code>cell</code> property contains
  509. * the cell under the mouse or null if the background was clicked.
  510. *
  511. * Event: mxEvent.DOUBLE_CLICK
  512. *
  513. * Fires in <dblClick> after a double click. The <code>event</code> property
  514. * contains the original mouse event and the <code>cell</code> property
  515. * contains the cell under the mouse or null if the background was clicked.
  516. *
  517. * Event: mxEvent.GESTURE
  518. *
  519. * Fires in <fireGestureEvent> after a touch gesture. The <code>event</code>
  520. * property contains the original gesture end event and the <code>cell</code>
  521. * property contains the optional cell associated with the gesture.
  522. *
  523. * Event: mxEvent.TAP_AND_HOLD
  524. *
  525. * Fires in <tapAndHold> if a tap and hold event was detected. The <code>event</code>
  526. * property contains the initial touch event and the <code>cell</code> property
  527. * contains the cell under the mouse or null if the background was clicked.
  528. *
  529. * Event: mxEvent.FIRE_MOUSE_EVENT
  530. *
  531. * Fires in <fireMouseEvent> before the mouse listeners are invoked. The
  532. * <code>eventName</code> property contains the event name and the
  533. * <code>event</code> property contains the <mxMouseEvent>.
  534. *
  535. * Event: mxEvent.SIZE
  536. *
  537. * Fires after <sizeDidChange> was executed. The <code>bounds</code> property
  538. * contains the new graph bounds.
  539. *
  540. * Event: mxEvent.START_EDITING
  541. *
  542. * Fires before the in-place editor starts in <startEditingAtCell>. The
  543. * <code>cell</code> property contains the cell that is being edited and the
  544. * <code>event</code> property contains the optional event argument that was
  545. * passed to <startEditingAtCell>.
  546. *
  547. * Event: mxEvent.EDITING_STARTED
  548. *
  549. * Fires after the in-place editor starts in <startEditingAtCell>. The
  550. * <code>cell</code> property contains the cell that is being edited and the
  551. * <code>event</code> property contains the optional event argument that was
  552. * passed to <startEditingAtCell>.
  553. *
  554. * Event: mxEvent.EDITING_STOPPED
  555. *
  556. * Fires after the in-place editor stops in <stopEditing>.
  557. *
  558. * Event: mxEvent.LABEL_CHANGED
  559. *
  560. * Fires between begin- and endUpdate in <cellLabelChanged>. The
  561. * <code>cell</code> property contains the cell, the <code>value</code>
  562. * property contains the new value for the cell, the <code>old</code> property
  563. * contains the old value and the optional <code>event</code> property contains
  564. * the mouse event that started the edit.
  565. *
  566. * Event: mxEvent.ADD_OVERLAY
  567. *
  568. * Fires after an overlay is added in <addCellOverlay>. The <code>cell</code>
  569. * property contains the cell and the <code>overlay</code> property contains
  570. * the <mxCellOverlay> that was added.
  571. *
  572. * Event: mxEvent.REMOVE_OVERLAY
  573. *
  574. * Fires after an overlay is removed in <removeCellOverlay> and
  575. * <removeCellOverlays>. The <code>cell</code> property contains the cell and
  576. * the <code>overlay</code> property contains the <mxCellOverlay> that was
  577. * removed.
  578. *
  579. * Constructor: mxGraph
  580. *
  581. * Constructs a new mxGraph in the specified container. Model is an optional
  582. * mxGraphModel. If no model is provided, a new mxGraphModel instance is
  583. * used as the model. The container must have a valid owner document prior
  584. * to calling this function in Internet Explorer. RenderHint is a string to
  585. * affect the display performance and rendering in IE, but not in SVG-based
  586. * browsers. The parameter is mapped to <dialect>, which may
  587. * be one of <mxConstants.DIALECT_SVG> for SVG-based browsers,
  588. * <mxConstants.DIALECT_STRICTHTML> for fastest display mode,
  589. * <mxConstants.DIALECT_PREFERHTML> for faster display mode,
  590. * <mxConstants.DIALECT_MIXEDHTML> for fast and <mxConstants.DIALECT_VML>
  591. * for exact display mode (slowest). The dialects are defined in mxConstants.
  592. * The default values are DIALECT_SVG for SVG-based browsers and
  593. * DIALECT_MIXED for IE.
  594. *
  595. * The possible values for the renderingHint parameter are explained below:
  596. *
  597. * fast - The parameter is based on the fact that the display performance is
  598. * highly improved in IE if the VML is not contained within a VML group
  599. * element. The lack of a group element only slightly affects the display while
  600. * panning, but improves the performance by almost a factor of 2, while keeping
  601. * the display sufficiently accurate. This also allows to render certain shapes as HTML
  602. * if the display accuracy is not affected, which is implemented by
  603. * <mxShape.isMixedModeHtml>. This is the default setting and is mapped to
  604. * DIALECT_MIXEDHTML.
  605. * faster - Same as fast, but more expensive shapes are avoided. This is
  606. * controlled by <mxShape.preferModeHtml>. The default implementation will
  607. * avoid gradients and rounded rectangles, but more significant shapes, such
  608. * as rhombus, ellipse, actor and cylinder will be rendered accurately. This
  609. * setting is mapped to DIALECT_PREFERHTML.
  610. * fastest - Almost anything will be rendered in Html. This allows for
  611. * rectangles, labels and images. This setting is mapped to
  612. * DIALECT_STRICTHTML.
  613. * exact - If accurate panning is required and if the diagram is small (up
  614. * to 100 cells), then this value should be used. In this mode, a group is
  615. * created that contains the VML. This allows for accurate panning and is
  616. * mapped to DIALECT_VML.
  617. *
  618. * Example:
  619. *
  620. * To create a graph inside a DOM node with an id of graph:
  621. * (code)
  622. * var container = document.getElementById('graph');
  623. * var graph = new mxGraph(container);
  624. * (end)
  625. *
  626. * Parameters:
  627. *
  628. * container - Optional DOM node that acts as a container for the graph.
  629. * If this is null then the container can be initialized later using
  630. * <init>.
  631. * model - Optional <mxGraphModel> that constitutes the graph data.
  632. * renderHint - Optional string that specifies the display accuracy and
  633. * performance. Default is mxConstants.DIALECT_MIXEDHTML (for IE).
  634. * stylesheet - Optional <mxStylesheet> to be used in the graph.
  635. */
  636. function mxGraph(container, model, renderHint, stylesheet)
  637. {
  638. // Initializes the variable in case the prototype has been
  639. // modified to hold some listeners (which is possible because
  640. // the createHandlers call is executed regardless of the
  641. // arguments passed into the ctor).
  642. this.mouseListeners = null;
  643. // Converts the renderHint into a dialect
  644. this.renderHint = renderHint;
  645. if (mxClient.IS_SVG)
  646. {
  647. this.dialect = mxConstants.DIALECT_SVG;
  648. }
  649. else if (renderHint == mxConstants.RENDERING_HINT_EXACT && mxClient.IS_VML)
  650. {
  651. this.dialect = mxConstants.DIALECT_VML;
  652. }
  653. else if (renderHint == mxConstants.RENDERING_HINT_FASTEST)
  654. {
  655. this.dialect = mxConstants.DIALECT_STRICTHTML;
  656. }
  657. else if (renderHint == mxConstants.RENDERING_HINT_FASTER)
  658. {
  659. this.dialect = mxConstants.DIALECT_PREFERHTML;
  660. }
  661. else // default for VML
  662. {
  663. this.dialect = mxConstants.DIALECT_MIXEDHTML;
  664. }
  665. // Initializes the main members that do not require a container
  666. this.model = (model != null) ? model : new mxGraphModel();
  667. this.multiplicities = [];
  668. this.imageBundles = [];
  669. this.cellRenderer = this.createCellRenderer();
  670. this.setSelectionModel(this.createSelectionModel());
  671. this.setStylesheet((stylesheet != null) ? stylesheet : this.createStylesheet());
  672. this.view = this.createGraphView();
  673. // Adds a graph model listener to update the view
  674. this.graphModelChangeListener = mxUtils.bind(this, function(sender, evt)
  675. {
  676. this.graphModelChanged(evt.getProperty('edit').changes);
  677. });
  678. this.model.addListener(mxEvent.CHANGE, this.graphModelChangeListener);
  679. // Installs basic event handlers with disabled default settings.
  680. this.createHandlers();
  681. // Initializes the display if a container was specified
  682. if (container != null)
  683. {
  684. this.init(container);
  685. }
  686. this.view.revalidate();
  687. };
  688. /**
  689. * Installs the required language resources at class
  690. * loading time.
  691. */
  692. if (mxLoadResources)
  693. {
  694. mxResources.add(mxClient.basePath + '/resources/graph');
  695. }
  696. else
  697. {
  698. mxClient.defaultBundles.push(mxClient.basePath + '/resources/graph');
  699. }
  700. /**
  701. * Extends mxEventSource.
  702. */
  703. mxGraph.prototype = new mxEventSource();
  704. mxGraph.prototype.constructor = mxGraph;
  705. /**
  706. * Group: Variables
  707. */
  708. /**
  709. * Variable: mouseListeners
  710. *
  711. * Holds the mouse event listeners. See <fireMouseEvent>.
  712. */
  713. mxGraph.prototype.mouseListeners = null;
  714. /**
  715. * Variable: isMouseDown
  716. *
  717. * Holds the state of the mouse button.
  718. */
  719. mxGraph.prototype.isMouseDown = false;
  720. /**
  721. * Variable: model
  722. *
  723. * Holds the <mxGraphModel> that contains the cells to be displayed.
  724. */
  725. mxGraph.prototype.model = null;
  726. /**
  727. * Variable: view
  728. *
  729. * Holds the <mxGraphView> that caches the <mxCellStates> for the cells.
  730. */
  731. mxGraph.prototype.view = null;
  732. /**
  733. * Variable: stylesheet
  734. *
  735. * Holds the <mxStylesheet> that defines the appearance of the cells.
  736. *
  737. *
  738. * Example:
  739. *
  740. * Use the following code to read a stylesheet into an existing graph.
  741. *
  742. * (code)
  743. * var req = mxUtils.load('stylesheet.xml');
  744. * var root = req.getDocumentElement();
  745. * var dec = new mxCodec(root.ownerDocument);
  746. * dec.decode(root, graph.stylesheet);
  747. * (end)
  748. */
  749. mxGraph.prototype.stylesheet = null;
  750. /**
  751. * Variable: selectionModel
  752. *
  753. * Holds the <mxGraphSelectionModel> that models the current selection.
  754. */
  755. mxGraph.prototype.selectionModel = null;
  756. /**
  757. * Variable: cellEditor
  758. *
  759. * Holds the <mxCellEditor> that is used as the in-place editing.
  760. */
  761. mxGraph.prototype.cellEditor = null;
  762. /**
  763. * Variable: cellRenderer
  764. *
  765. * Holds the <mxCellRenderer> for rendering the cells in the graph.
  766. */
  767. mxGraph.prototype.cellRenderer = null;
  768. /**
  769. * Variable: multiplicities
  770. *
  771. * An array of <mxMultiplicities> describing the allowed
  772. * connections in a graph.
  773. */
  774. mxGraph.prototype.multiplicities = null;
  775. /**
  776. * Variable: renderHint
  777. *
  778. * RenderHint as it was passed to the constructor.
  779. */
  780. mxGraph.prototype.renderHint = null;
  781. /**
  782. * Variable: dialect
  783. *
  784. * Dialect to be used for drawing the graph. Possible values are all
  785. * constants in <mxConstants> with a DIALECT-prefix.
  786. */
  787. mxGraph.prototype.dialect = null;
  788. /**
  789. * Variable: gridSize
  790. *
  791. * Specifies the grid size. Default is 10.
  792. */
  793. mxGraph.prototype.gridSize = 10;
  794. /**
  795. * Variable: gridEnabled
  796. *
  797. * Specifies if the grid is enabled. This is used in <snap>. Default is
  798. * true.
  799. */
  800. mxGraph.prototype.gridEnabled = true;
  801. /**
  802. * Variable: portsEnabled
  803. *
  804. * Specifies if ports are enabled. This is used in <cellConnected> to update
  805. * the respective style. Default is true.
  806. */
  807. mxGraph.prototype.portsEnabled = true;
  808. /**
  809. * Variable: nativeDoubleClickEnabled
  810. *
  811. * Specifies if native double click events should be detected. Default is true.
  812. */
  813. mxGraph.prototype.nativeDblClickEnabled = true;
  814. /**
  815. * Variable: doubleTapEnabled
  816. *
  817. * Specifies if double taps on touch-based devices should be handled as a
  818. * double click. Default is true.
  819. */
  820. mxGraph.prototype.doubleTapEnabled = true;
  821. /**
  822. * Variable: doubleTapTimeout
  823. *
  824. * Specifies the timeout for double taps and non-native double clicks. Default
  825. * is 500 ms.
  826. */
  827. mxGraph.prototype.doubleTapTimeout = 500;
  828. /**
  829. * Variable: doubleTapTolerance
  830. *
  831. * Specifies the tolerance for double taps and double clicks in quirks mode.
  832. * Default is 25 pixels.
  833. */
  834. mxGraph.prototype.doubleTapTolerance = 25;
  835. /**
  836. * Variable: lastTouchX
  837. *
  838. * Holds the x-coordinate of the last touch event for double tap detection.
  839. */
  840. mxGraph.prototype.lastTouchY = 0;
  841. /**
  842. * Variable: lastTouchX
  843. *
  844. * Holds the y-coordinate of the last touch event for double tap detection.
  845. */
  846. mxGraph.prototype.lastTouchY = 0;
  847. /**
  848. * Variable: lastTouchTime
  849. *
  850. * Holds the time of the last touch event for double click detection.
  851. */
  852. mxGraph.prototype.lastTouchTime = 0;
  853. /**
  854. * Variable: tapAndHoldEnabled
  855. *
  856. * Specifies if tap and hold should be used for starting connections on touch-based
  857. * devices. Default is true.
  858. */
  859. mxGraph.prototype.tapAndHoldEnabled = true;
  860. /**
  861. * Variable: tapAndHoldDelay
  862. *
  863. * Specifies the time for a tap and hold. Default is 500 ms.
  864. */
  865. mxGraph.prototype.tapAndHoldDelay = 500;
  866. /**
  867. * Variable: tapAndHoldInProgress
  868. *
  869. * True if the timer for tap and hold events is running.
  870. */
  871. mxGraph.prototype.tapAndHoldInProgress = false;
  872. /**
  873. * Variable: tapAndHoldValid
  874. *
  875. * True as long as the timer is running and the touch events
  876. * stay within the given <tapAndHoldTolerance>.
  877. */
  878. mxGraph.prototype.tapAndHoldValid = false;
  879. /**
  880. * Variable: initialTouchX
  881. *
  882. * Holds the x-coordinate of the intial touch event for tap and hold.
  883. */
  884. mxGraph.prototype.initialTouchX = 0;
  885. /**
  886. * Variable: initialTouchY
  887. *
  888. * Holds the y-coordinate of the intial touch event for tap and hold.
  889. */
  890. mxGraph.prototype.initialTouchY = 0;
  891. /**
  892. * Variable: tolerance
  893. *
  894. * Tolerance for a move to be handled as a single click.
  895. * Default is 4 pixels.
  896. */
  897. mxGraph.prototype.tolerance = 4;
  898. /**
  899. * Variable: defaultOverlap
  900. *
  901. * Value returned by <getOverlap> if <isAllowOverlapParent> returns
  902. * true for the given cell. <getOverlap> is used in <constrainChild> if
  903. * <isConstrainChild> returns true. The value specifies the
  904. * portion of the child which is allowed to overlap the parent.
  905. */
  906. mxGraph.prototype.defaultOverlap = 0.5;
  907. /**
  908. * Variable: defaultParent
  909. *
  910. * Specifies the default parent to be used to insert new cells.
  911. * This is used in <getDefaultParent>. Default is null.
  912. */
  913. mxGraph.prototype.defaultParent = null;
  914. /**
  915. * Variable: alternateEdgeStyle
  916. *
  917. * Specifies the alternate edge style to be used if the main control point
  918. * on an edge is being doubleclicked. Default is null.
  919. */
  920. mxGraph.prototype.alternateEdgeStyle = null;
  921. /**
  922. * Variable: backgroundImage
  923. *
  924. * Specifies the <mxImage> to be returned by <getBackgroundImage>. Default
  925. * is null.
  926. *
  927. * Example:
  928. *
  929. * (code)
  930. * var img = new mxImage('http://www.example.com/maps/examplemap.jpg', 1024, 768);
  931. * graph.setBackgroundImage(img);
  932. * graph.view.validate();
  933. * (end)
  934. */
  935. mxGraph.prototype.backgroundImage = null;
  936. /**
  937. * Variable: pageVisible
  938. *
  939. * Specifies if the background page should be visible. Default is false.
  940. * Not yet implemented.
  941. */
  942. mxGraph.prototype.pageVisible = false;
  943. /**
  944. * Variable: pageBreaksVisible
  945. *
  946. * Specifies if a dashed line should be drawn between multiple pages. Default
  947. * is false. If you change this value while a graph is being displayed then you
  948. * should call <sizeDidChange> to force an update of the display.
  949. */
  950. mxGraph.prototype.pageBreaksVisible = false;
  951. /**
  952. * Variable: pageBreakColor
  953. *
  954. * Specifies the color for page breaks. Default is 'gray'.
  955. */
  956. mxGraph.prototype.pageBreakColor = 'gray';
  957. /**
  958. * Variable: pageBreakDashed
  959. *
  960. * Specifies the page breaks should be dashed. Default is true.
  961. */
  962. mxGraph.prototype.pageBreakDashed = true;
  963. /**
  964. * Variable: minPageBreakDist
  965. *
  966. * Specifies the minimum distance for page breaks to be visible. Default is
  967. * 20 (in pixels).
  968. */
  969. mxGraph.prototype.minPageBreakDist = 20;
  970. /**
  971. * Variable: preferPageSize
  972. *
  973. * Specifies if the graph size should be rounded to the next page number in
  974. * <sizeDidChange>. This is only used if the graph container has scrollbars.
  975. * Default is false.
  976. */
  977. mxGraph.prototype.preferPageSize = false;
  978. /**
  979. * Variable: pageFormat
  980. *
  981. * Specifies the page format for the background page. Default is
  982. * <mxConstants.PAGE_FORMAT_A4_PORTRAIT>. This is used as the default in
  983. * <mxPrintPreview> and for painting the background page if <pageVisible> is
  984. * true and the pagebreaks if <pageBreaksVisible> is true.
  985. */
  986. mxGraph.prototype.pageFormat = mxConstants.PAGE_FORMAT_A4_PORTRAIT;
  987. /**
  988. * Variable: pageScale
  989. *
  990. * Specifies the scale of the background page. Default is 1.5.
  991. * Not yet implemented.
  992. */
  993. mxGraph.prototype.pageScale = 1.5;
  994. /**
  995. * Variable: enabled
  996. *
  997. * Specifies the return value for <isEnabled>. Default is true.
  998. */
  999. mxGraph.prototype.enabled = true;
  1000. /**
  1001. * Variable: escapeEnabled
  1002. *
  1003. * Specifies if <mxKeyHandler> should invoke <escape> when the escape key
  1004. * is pressed. Default is true.
  1005. */
  1006. mxGraph.prototype.escapeEnabled = true;
  1007. /**
  1008. * Variable: invokesStopCellEditing
  1009. *
  1010. * If true, when editing is to be stopped by way of selection changing,
  1011. * data in diagram changing or other means stopCellEditing is invoked, and
  1012. * changes are saved. This is implemented in a focus handler in
  1013. * <mxCellEditor>. Default is true.
  1014. */
  1015. mxGraph.prototype.invokesStopCellEditing = true;
  1016. /**
  1017. * Variable: enterStopsCellEditing
  1018. *
  1019. * If true, pressing the enter key without pressing control or shift will stop
  1020. * editing and accept the new value. This is used in <mxCellEditor> to stop
  1021. * cell editing. Note: You can always use F2 and escape to stop editing.
  1022. * Default is false.
  1023. */
  1024. mxGraph.prototype.enterStopsCellEditing = false;
  1025. /**
  1026. * Variable: useScrollbarsForPanning
  1027. *
  1028. * Specifies if scrollbars should be used for panning in <panGraph> if
  1029. * any scrollbars are available. If scrollbars are enabled in CSS, but no
  1030. * scrollbars appear because the graph is smaller than the container size,
  1031. * then no panning occurs if this is true. Default is true.
  1032. */
  1033. mxGraph.prototype.useScrollbarsForPanning = true;
  1034. /**
  1035. * Variable: exportEnabled
  1036. *
  1037. * Specifies the return value for <canExportCell>. Default is true.
  1038. */
  1039. mxGraph.prototype.exportEnabled = true;
  1040. /**
  1041. * Variable: importEnabled
  1042. *
  1043. * Specifies the return value for <canImportCell>. Default is true.
  1044. */
  1045. mxGraph.prototype.importEnabled = true;
  1046. /**
  1047. * Variable: cellsLocked
  1048. *
  1049. * Specifies the return value for <isCellLocked>. Default is false.
  1050. */
  1051. mxGraph.prototype.cellsLocked = false;
  1052. /**
  1053. * Variable: cellsCloneable
  1054. *
  1055. * Specifies the return value for <isCellCloneable>. Default is true.
  1056. */
  1057. mxGraph.prototype.cellsCloneable = true;
  1058. /**
  1059. * Variable: foldingEnabled
  1060. *
  1061. * Specifies if folding (collapse and expand via an image icon in the graph
  1062. * should be enabled). Default is true.
  1063. */
  1064. mxGraph.prototype.foldingEnabled = true;
  1065. /**
  1066. * Variable: cellsEditable
  1067. *
  1068. * Specifies the return value for <isCellEditable>. Default is true.
  1069. */
  1070. mxGraph.prototype.cellsEditable = true;
  1071. /**
  1072. * Variable: cellsDeletable
  1073. *
  1074. * Specifies the return value for <isCellDeletable>. Default is true.
  1075. */
  1076. mxGraph.prototype.cellsDeletable = true;
  1077. /**
  1078. * Variable: cellsMovable
  1079. *
  1080. * Specifies the return value for <isCellMovable>. Default is true.
  1081. */
  1082. mxGraph.prototype.cellsMovable = true;
  1083. /**
  1084. * Variable: edgeLabelsMovable
  1085. *
  1086. * Specifies the return value for edges in <isLabelMovable>. Default is true.
  1087. */
  1088. mxGraph.prototype.edgeLabelsMovable = true;
  1089. /**
  1090. * Variable: vertexLabelsMovable
  1091. *
  1092. * Specifies the return value for vertices in <isLabelMovable>. Default is false.
  1093. */
  1094. mxGraph.prototype.vertexLabelsMovable = false;
  1095. /**
  1096. * Variable: dropEnabled
  1097. *
  1098. * Specifies the return value for <isDropEnabled>. Default is false.
  1099. */
  1100. mxGraph.prototype.dropEnabled = false;
  1101. /**
  1102. * Variable: splitEnabled
  1103. *
  1104. * Specifies if dropping onto edges should be enabled. This is ignored if
  1105. * <dropEnabled> is false. If enabled, it will call <splitEdge> to carry
  1106. * out the drop operation. Default is true.
  1107. */
  1108. mxGraph.prototype.splitEnabled = true;
  1109. /**
  1110. * Variable: cellsResizable
  1111. *
  1112. * Specifies the return value for <isCellResizable>. Default is true.
  1113. */
  1114. mxGraph.prototype.cellsResizable = true;
  1115. /**
  1116. * Variable: cellsBendable
  1117. *
  1118. * Specifies the return value for <isCellsBendable>. Default is true.
  1119. */
  1120. mxGraph.prototype.cellsBendable = true;
  1121. /**
  1122. * Variable: cellsSelectable
  1123. *
  1124. * Specifies the return value for <isCellSelectable>. Default is true.
  1125. */
  1126. mxGraph.prototype.cellsSelectable = true;
  1127. /**
  1128. * Variable: cellsDisconnectable
  1129. *
  1130. * Specifies the return value for <isCellDisconntable>. Default is true.
  1131. */
  1132. mxGraph.prototype.cellsDisconnectable = true;
  1133. /**
  1134. * Variable: autoSizeCells
  1135. *
  1136. * Specifies if the graph should automatically update the cell size after an
  1137. * edit. This is used in <isAutoSizeCell>. Default is false.
  1138. */
  1139. mxGraph.prototype.autoSizeCells = false;
  1140. /**
  1141. * Variable: autoSizeCellsOnAdd
  1142. *
  1143. * Specifies if autoSize style should be applied when cells are added. Default is false.
  1144. */
  1145. mxGraph.prototype.autoSizeCellsOnAdd = false;
  1146. /**
  1147. * Variable: autoScroll
  1148. *
  1149. * Specifies if the graph should automatically scroll if the mouse goes near
  1150. * the container edge while dragging. This is only taken into account if the
  1151. * container has scrollbars. Default is true.
  1152. *
  1153. * If you need this to work without scrollbars then set <ignoreScrollbars> to
  1154. * true. Please consult the <ignoreScrollbars> for details. In general, with
  1155. * no scrollbars, the use of <allowAutoPanning> is recommended.
  1156. */
  1157. mxGraph.prototype.autoScroll = true;
  1158. /**
  1159. * Variable: ignoreScrollbars
  1160. *
  1161. * Specifies if the graph should automatically scroll regardless of the
  1162. * scrollbars. This will scroll the container using positive values for
  1163. * scroll positions (ie usually only rightwards and downwards). To avoid
  1164. * possible conflicts with panning, set <translateToScrollPosition> to true.
  1165. */
  1166. mxGraph.prototype.ignoreScrollbars = false;
  1167. /**
  1168. * Variable: translateToScrollPosition
  1169. *
  1170. * Specifies if the graph should automatically convert the current scroll
  1171. * position to a translate in the graph view when a mouseUp event is received.
  1172. * This can be used to avoid conflicts when using <autoScroll> and
  1173. * <ignoreScrollbars> with no scrollbars in the container.
  1174. */
  1175. mxGraph.prototype.translateToScrollPosition = false;
  1176. /**
  1177. * Variable: timerAutoScroll
  1178. *
  1179. * Specifies if autoscrolling should be carried out via mxPanningManager even
  1180. * if the container has scrollbars. This disables <scrollPointToVisible> and
  1181. * uses <mxPanningManager> instead. If this is true then <autoExtend> is
  1182. * disabled. It should only be used with a scroll buffer or when scollbars
  1183. * are visible and scrollable in all directions. Default is false.
  1184. */
  1185. mxGraph.prototype.timerAutoScroll = false;
  1186. /**
  1187. * Variable: allowAutoPanning
  1188. *
  1189. * Specifies if panning via <panGraph> should be allowed to implement autoscroll
  1190. * if no scrollbars are available in <scrollPointToVisible>. To enable panning
  1191. * inside the container, near the edge, set <mxPanningManager.border> to a
  1192. * positive value. Default is false.
  1193. */
  1194. mxGraph.prototype.allowAutoPanning = false;
  1195. /**
  1196. * Variable: autoExtend
  1197. *
  1198. * Specifies if the size of the graph should be automatically extended if the
  1199. * mouse goes near the container edge while dragging. This is only taken into
  1200. * account if the container has scrollbars. Default is true. See <autoScroll>.
  1201. */
  1202. mxGraph.prototype.autoExtend = true;
  1203. /**
  1204. * Variable: maximumGraphBounds
  1205. *
  1206. * <mxRectangle> that specifies the area in which all cells in the diagram
  1207. * should be placed. Uses in <getMaximumGraphBounds>. Use a width or height of
  1208. * 0 if you only want to give a upper, left corner.
  1209. */
  1210. mxGraph.prototype.maximumGraphBounds = null;
  1211. /**
  1212. * Variable: minimumGraphSize
  1213. *
  1214. * <mxRectangle> that specifies the minimum size of the graph. This is ignored
  1215. * if the graph container has no scrollbars. Default is null.
  1216. */
  1217. mxGraph.prototype.minimumGraphSize = null;
  1218. /**
  1219. * Variable: minimumContainerSize
  1220. *
  1221. * <mxRectangle> that specifies the minimum size of the <container> if
  1222. * <resizeContainer> is true.
  1223. */
  1224. mxGraph.prototype.minimumContainerSize = null;
  1225. /**
  1226. * Variable: maximumContainerSize
  1227. *
  1228. * <mxRectangle> that specifies the maximum size of the container if
  1229. * <resizeContainer> is true.
  1230. */
  1231. mxGraph.prototype.maximumContainerSize = null;
  1232. /**
  1233. * Variable: resizeContainer
  1234. *
  1235. * Specifies if the container should be resized to the graph size when
  1236. * the graph size has changed. Default is false.
  1237. */
  1238. mxGraph.prototype.resizeContainer = false;
  1239. /**
  1240. * Variable: border
  1241. *
  1242. * Border to be added to the bottom and right side when the container is
  1243. * being resized after the graph has been changed. Default is 0.
  1244. */
  1245. mxGraph.prototype.border = 0;
  1246. /**
  1247. * Variable: keepEdgesInForeground
  1248. *
  1249. * Specifies if edges should appear in the foreground regardless of their order
  1250. * in the model. If <keepEdgesInForeground> and <keepEdgesInBackground> are
  1251. * both true then the normal order is applied. Default is false.
  1252. */
  1253. mxGraph.prototype.keepEdgesInForeground = false;
  1254. /**
  1255. * Variable: keepEdgesInBackground
  1256. *
  1257. * Specifies if edges should appear in the background regardless of their order
  1258. * in the model. If <keepEdgesInForeground> and <keepEdgesInBackground> are
  1259. * both true then the normal order is applied. Default is false.
  1260. */
  1261. mxGraph.prototype.keepEdgesInBackground = false;
  1262. /**
  1263. * Variable: allowNegativeCoordinates
  1264. *
  1265. * Specifies if negative coordinates for vertices are allowed. Default is true.
  1266. */
  1267. mxGraph.prototype.allowNegativeCoordinates = true;
  1268. /**
  1269. * Variable: constrainChildren
  1270. *
  1271. * Specifies if a child should be constrained inside the parent bounds after a
  1272. * move or resize of the child. Default is true.
  1273. */
  1274. mxGraph.prototype.constrainChildren = true;
  1275. /**
  1276. * Variable: constrainRelativeChildren
  1277. *
  1278. * Specifies if child cells with relative geometries should be constrained
  1279. * inside the parent bounds, if <constrainChildren> is true, and/or the
  1280. * <maximumGraphBounds>. Default is false.
  1281. */
  1282. mxGraph.prototype.constrainRelativeChildren = false;
  1283. /**
  1284. * Variable: extendParents
  1285. *
  1286. * Specifies if a parent should contain the child bounds after a resize of
  1287. * the child. Default is true. This has precedence over <constrainChildren>.
  1288. */
  1289. mxGraph.prototype.extendParents = true;
  1290. /**
  1291. * Variable: extendParentsOnAdd
  1292. *
  1293. * Specifies if parents should be extended according to the <extendParents>
  1294. * switch if cells are added. Default is true.
  1295. */
  1296. mxGraph.prototype.extendParentsOnAdd = true;
  1297. /**
  1298. * Variable: extendParentsOnAdd
  1299. *
  1300. * Specifies if parents should be extended according to the <extendParents>
  1301. * switch if cells are added. Default is false for backwards compatiblity.
  1302. */
  1303. mxGraph.prototype.extendParentsOnMove = false;
  1304. /**
  1305. * Variable: recursiveResize
  1306. *
  1307. * Specifies the return value for <isRecursiveResize>. Default is
  1308. * false for backwards compatiblity.
  1309. */
  1310. mxGraph.prototype.recursiveResize = false;
  1311. /**
  1312. * Variable: collapseToPreferredSize
  1313. *
  1314. * Specifies if the cell size should be changed to the preferred size when
  1315. * a cell is first collapsed. Default is true.
  1316. */
  1317. mxGraph.prototype.collapseToPreferredSize = true;
  1318. /**
  1319. * Variable: zoomFactor
  1320. *
  1321. * Specifies the factor used for <zoomIn> and <zoomOut>. Default is 1.2
  1322. * (120%).
  1323. */
  1324. mxGraph.prototype.zoomFactor = 1.2;
  1325. /**
  1326. * Variable: keepSelectionVisibleOnZoom
  1327. *
  1328. * Specifies if the viewport should automatically contain the selection cells
  1329. * after a zoom operation. Default is false.
  1330. */
  1331. mxGraph.prototype.keepSelectionVisibleOnZoom = false;
  1332. /**
  1333. * Variable: centerZoom
  1334. *
  1335. * Specifies if the zoom operations should go into the center of the actual
  1336. * diagram rather than going from top, left. Default is true.
  1337. */
  1338. mxGraph.prototype.centerZoom = true;
  1339. /**
  1340. * Variable: resetViewOnRootChange
  1341. *
  1342. * Specifies if the scale and translate should be reset if the root changes in
  1343. * the model. Default is true.
  1344. */
  1345. mxGraph.prototype.resetViewOnRootChange = true;
  1346. /**
  1347. * Variable: resetEdgesOnResize
  1348. *
  1349. * Specifies if edge control points should be reset after the resize of a
  1350. * connected cell. Default is false.
  1351. */
  1352. mxGraph.prototype.resetEdgesOnResize = false;
  1353. /**
  1354. * Variable: resetEdgesOnMove
  1355. *
  1356. * Specifies if edge control points should be reset after the move of a
  1357. * connected cell. Default is false.
  1358. */
  1359. mxGraph.prototype.resetEdgesOnMove = false;
  1360. /**
  1361. * Variable: resetEdgesOnConnect
  1362. *
  1363. * Specifies if edge control points should be reset after the the edge has been
  1364. * reconnected. Default is true.
  1365. */
  1366. mxGraph.prototype.resetEdgesOnConnect = true;
  1367. /**
  1368. * Variable: allowLoops
  1369. *
  1370. * Specifies if loops (aka self-references) are allowed. Default is false.
  1371. */
  1372. mxGraph.prototype.allowLoops = false;
  1373. /**
  1374. * Variable: defaultLoopStyle
  1375. *
  1376. * <mxEdgeStyle> to be used for loops. This is a fallback for loops if the
  1377. * <mxConstants.STYLE_LOOP> is undefined. Default is <mxEdgeStyle.Loop>.
  1378. */
  1379. mxGraph.prototype.defaultLoopStyle = mxEdgeStyle.Loop;
  1380. /**
  1381. * Variable: multigraph
  1382. *
  1383. * Specifies if multiple edges in the same direction between the same pair of
  1384. * vertices are allowed. Default is true.
  1385. */
  1386. mxGraph.prototype.multigraph = true;
  1387. /**
  1388. * Variable: connectableEdges
  1389. *
  1390. * Specifies if edges are connectable. Default is false. This overrides the
  1391. * connectable field in edges.
  1392. */
  1393. mxGraph.prototype.connectableEdges = false;
  1394. /**
  1395. * Variable: allowDanglingEdges
  1396. *
  1397. * Specifies if edges with disconnected terminals are allowed in the graph.
  1398. * Default is true.
  1399. */
  1400. mxGraph.prototype.allowDanglingEdges = true;
  1401. /**
  1402. * Variable: cloneInvalidEdges
  1403. *
  1404. * Specifies if edges that are cloned should be validated and only inserted
  1405. * if they are valid. Default is true.
  1406. */
  1407. mxGraph.prototype.cloneInvalidEdges = false;
  1408. /**
  1409. * Variable: disconnectOnMove
  1410. *
  1411. * Specifies if edges should be disconnected from their terminals when they
  1412. * are moved. Default is true.
  1413. */
  1414. mxGraph.prototype.disconnectOnMove = true;
  1415. /**
  1416. * Variable: labelsVisible
  1417. *
  1418. * Specifies if labels should be visible. This is used in <getLabel>. Default
  1419. * is true.
  1420. */
  1421. mxGraph.prototype.labelsVisible = true;
  1422. /**
  1423. * Variable: htmlLabels
  1424. *
  1425. * Specifies the return value for <isHtmlLabel>. Default is false.
  1426. */
  1427. mxGraph.prototype.htmlLabels = false;
  1428. /**
  1429. * Variable: swimlaneSelectionEnabled
  1430. *
  1431. * Specifies if swimlanes should be selectable via the content if the
  1432. * mouse is released. Default is true.
  1433. */
  1434. mxGraph.prototype.swimlaneSelectionEnabled = true;
  1435. /**
  1436. * Variable: swimlaneNesting
  1437. *
  1438. * Specifies if nesting of swimlanes is allowed. Default is true.
  1439. */
  1440. mxGraph.prototype.swimlaneNesting = true;
  1441. /**
  1442. * Variable: swimlaneIndicatorColorAttribute
  1443. *
  1444. * The attribute used to find the color for the indicator if the indicator
  1445. * color is set to 'swimlane'. Default is <mxConstants.STYLE_FILLCOLOR>.
  1446. */
  1447. mxGraph.prototype.swimlaneIndicatorColorAttribute = mxConstants.STYLE_FILLCOLOR;
  1448. /**
  1449. * Variable: imageBundles
  1450. *
  1451. * Holds the list of image bundles.
  1452. */
  1453. mxGraph.prototype.imageBundles = null;
  1454. /**
  1455. * Variable: minFitScale
  1456. *
  1457. * Specifies the minimum scale to be applied in <fit>. Default is 0.1. Set this
  1458. * to null to allow any value.
  1459. */
  1460. mxGraph.prototype.minFitScale = 0.1;
  1461. /**
  1462. * Variable: maxFitScale
  1463. *
  1464. * Specifies the maximum scale to be applied in <fit>. Default is 8. Set this
  1465. * to null to allow any value.
  1466. */
  1467. mxGraph.prototype.maxFitScale = 8;
  1468. /**
  1469. * Variable: panDx
  1470. *
  1471. * Current horizontal panning value. Default is 0.
  1472. */
  1473. mxGraph.prototype.panDx = 0;
  1474. /**
  1475. * Variable: panDy
  1476. *
  1477. * Current vertical panning value. Default is 0.
  1478. */
  1479. mxGraph.prototype.panDy = 0;
  1480. /**
  1481. * Variable: collapsedImage
  1482. *
  1483. * Specifies the <mxImage> to indicate a collapsed state.
  1484. * Default value is mxClient.imageBasePath + '/collapsed.gif'
  1485. */
  1486. mxGraph.prototype.collapsedImage = new mxImage(mxClient.imageBasePath + '/collapsed.gif', 9, 9);
  1487. /**
  1488. * Variable: expandedImage
  1489. *
  1490. * Specifies the <mxImage> to indicate a expanded state.
  1491. * Default value is mxClient.imageBasePath + '/expanded.gif'
  1492. */
  1493. mxGraph.prototype.expandedImage = new mxImage(mxClient.imageBasePath + '/expanded.gif', 9, 9);
  1494. /**
  1495. * Variable: warningImage
  1496. *
  1497. * Specifies the <mxImage> for the image to be used to display a warning
  1498. * overlay. See <setCellWarning>. Default value is mxClient.imageBasePath +
  1499. * '/warning'. The extension for the image depends on the platform. It is
  1500. * '.png' on the Mac and '.gif' on all other platforms.
  1501. */
  1502. mxGraph.prototype.warningImage = new mxImage(mxClient.imageBasePath + '/warning'+
  1503. ((mxClient.IS_MAC) ? '.png' : '.gif'), 16, 16);
  1504. /**
  1505. * Variable: alreadyConnectedResource
  1506. *
  1507. * Specifies the resource key for the error message to be displayed in
  1508. * non-multigraphs when two vertices are already connected. If the resource
  1509. * for this key does not exist then the value is used as the error message.
  1510. * Default is 'alreadyConnected'.
  1511. */
  1512. mxGraph.prototype.alreadyConnectedResource = (mxClient.language != 'none') ? 'alreadyConnected' : '';
  1513. /**
  1514. * Variable: containsValidationErrorsResource
  1515. *
  1516. * Specifies the resource key for the warning message to be displayed when
  1517. * a collapsed cell contains validation errors. If the resource for this
  1518. * key does not exist then the value is used as the warning message.
  1519. * Default is 'containsValidationErrors'.
  1520. */
  1521. mxGraph.prototype.containsValidationErrorsResource = (mxClient.language != 'none') ? 'containsValidationErrors' : '';
  1522. /**
  1523. * Variable: collapseExpandResource
  1524. *
  1525. * Specifies the resource key for the tooltip on the collapse/expand icon.
  1526. * If the resource for this key does not exist then the value is used as
  1527. * the tooltip. Default is 'collapse-expand'.
  1528. */
  1529. mxGraph.prototype.collapseExpandResource = (mxClient.language != 'none') ? 'collapse-expand' : '';
  1530. /**
  1531. * Function: init
  1532. *
  1533. * Initializes the <container> and creates the respective datastructures.
  1534. *
  1535. * Parameters:
  1536. *
  1537. * container - DOM node that will contain the graph display.
  1538. */
  1539. mxGraph.prototype.init = function(container)
  1540. {
  1541. this.container = container;
  1542. // Initializes the in-place editor
  1543. this.cellEditor = this.createCellEditor();
  1544. // Initializes the container using the view
  1545. this.view.init();
  1546. // Updates the size of the container for the current graph
  1547. this.sizeDidChange();
  1548. // Hides tooltips and resets tooltip timer if mouse leaves container
  1549. mxEvent.addListener(container, 'mouseleave', mxUtils.bind(this, function(evt)
  1550. {
  1551. if (this.tooltipHandler != null && this.tooltipHandler.div != null &&
  1552. this.tooltipHandler.div != evt.relatedTarget)
  1553. {
  1554. this.tooltipHandler.hide();
  1555. }
  1556. }));
  1557. // Automatic deallocation of memory
  1558. if (mxClient.IS_IE)
  1559. {
  1560. mxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
  1561. {
  1562. this.destroy();
  1563. }));
  1564. // Disable shift-click for text
  1565. mxEvent.addListener(container, 'selectstart',
  1566. mxUtils.bind(this, function(evt)
  1567. {
  1568. return this.isEditing() || (!this.isMouseDown && !mxEvent.isShiftDown(evt));
  1569. })
  1570. );
  1571. }
  1572. // Workaround for missing last shape and connect preview in IE8 standards
  1573. // mode if no initial graph displayed or no label for shape defined
  1574. if (document.documentMode == 8)
  1575. {
  1576. container.insertAdjacentHTML('beforeend', '<' + mxClient.VML_PREFIX + ':group' +
  1577. ' style="DISPLAY: none;"></' + mxClient.VML_PREFIX + ':group>');
  1578. }
  1579. };
  1580. /**
  1581. * Function: createHandlers
  1582. *
  1583. * Creates the tooltip-, panning-, connection- and graph-handler (in this
  1584. * order). This is called in the constructor before <init> is called.
  1585. */
  1586. mxGraph.prototype.createHandlers = function()
  1587. {
  1588. this.tooltipHandler = this.createTooltipHandler();
  1589. this.tooltipHandler.setEnabled(false);
  1590. this.selectionCellsHandler = this.createSelectionCellsHandler();
  1591. this.connectionHandler = this.createConnectionHandler();
  1592. this.connectionHandler.setEnabled(false);
  1593. this.graphHandler = this.createGraphHandler();
  1594. this.panningHandler = this.createPanningHandler();
  1595. this.panningHandler.panningEnabled = false;
  1596. this.popupMenuHandler = this.createPopupMenuHandler();
  1597. };
  1598. /**
  1599. * Function: createTooltipHandler
  1600. *
  1601. * Creates and returns a new <mxTooltipHandler> to be used in this graph.
  1602. */
  1603. mxGraph.prototype.createTooltipHandler = function()
  1604. {
  1605. return new mxTooltipHandler(this);
  1606. };
  1607. /**
  1608. * Function: createSelectionCellsHandler
  1609. *
  1610. * Creates and returns a new <mxTooltipHandler> to be used in this graph.
  1611. */
  1612. mxGraph.prototype.createSelectionCellsHandler = function()
  1613. {
  1614. return new mxSelectionCellsHandler(this);
  1615. };
  1616. /**
  1617. * Function: createConnectionHandler
  1618. *
  1619. * Creates and returns a new <mxConnectionHandler> to be used in this graph.
  1620. */
  1621. mxGraph.prototype.createConnectionHandler = function()
  1622. {
  1623. return new mxConnectionHandler(this);
  1624. };
  1625. /**
  1626. * Function: createGraphHandler
  1627. *
  1628. * Creates and returns a new <mxGraphHandler> to be used in this graph.
  1629. */
  1630. mxGraph.prototype.createGraphHandler = function()
  1631. {
  1632. return new mxGraphHandler(this);
  1633. };
  1634. /**
  1635. * Function: createPanningHandler
  1636. *
  1637. * Creates and returns a new <mxPanningHandler> to be used in this graph.
  1638. */
  1639. mxGraph.prototype.createPanningHandler = function()
  1640. {
  1641. return new mxPanningHandler(this);
  1642. };
  1643. /**
  1644. * Function: createPopupMenuHandler
  1645. *
  1646. * Creates and returns a new <mxPopupMenuHandler> to be used in this graph.
  1647. */
  1648. mxGraph.prototype.createPopupMenuHandler = function()
  1649. {
  1650. return new mxPopupMenuHandler(this);
  1651. };
  1652. /**
  1653. * Function: createSelectionModel
  1654. *
  1655. * Creates a new <mxGraphSelectionModel> to be used in this graph.
  1656. */
  1657. mxGraph.prototype.createSelectionModel = function()
  1658. {
  1659. return new mxGraphSelectionModel(this);
  1660. };
  1661. /**
  1662. * Function: createStylesheet
  1663. *
  1664. * Creates a new <mxGraphSelectionModel> to be used in this graph.
  1665. */
  1666. mxGraph.prototype.createStylesheet = function()
  1667. {
  1668. return new mxStylesheet();
  1669. };
  1670. /**
  1671. * Function: createGraphView
  1672. *
  1673. * Creates a new <mxGraphView> to be used in this graph.
  1674. */
  1675. mxGraph.prototype.createGraphView = function()
  1676. {
  1677. return new mxGraphView(this);
  1678. };
  1679. /**
  1680. * Function: createCellRenderer
  1681. *
  1682. * Creates a new <mxCellRenderer> to be used in this graph.
  1683. */
  1684. mxGraph.prototype.createCellRenderer = function()
  1685. {
  1686. return new mxCellRenderer();
  1687. };
  1688. /**
  1689. * Function: createCellEditor
  1690. *
  1691. * Creates a new <mxCellEditor> to be used in this graph.
  1692. */
  1693. mxGraph.prototype.createCellEditor = function()
  1694. {
  1695. return new mxCellEditor(this);
  1696. };
  1697. /**
  1698. * Function: getModel
  1699. *
  1700. * Returns the <mxGraphModel> that contains the cells.
  1701. */
  1702. mxGraph.prototype.getModel = function()
  1703. {
  1704. return this.model;
  1705. };
  1706. /**
  1707. * Function: getView
  1708. *
  1709. * Returns the <mxGraphView> that contains the <mxCellStates>.
  1710. */
  1711. mxGraph.prototype.getView = function()
  1712. {
  1713. return this.view;
  1714. };
  1715. /**
  1716. * Function: getStylesheet
  1717. *
  1718. * Returns the <mxStylesheet> that defines the style.
  1719. */
  1720. mxGraph.prototype.getStylesheet = function()
  1721. {
  1722. return this.stylesheet;
  1723. };
  1724. /**
  1725. * Function: setStylesheet
  1726. *
  1727. * Sets the <mxStylesheet> that defines the style.
  1728. */
  1729. mxGraph.prototype.setStylesheet = function(stylesheet)
  1730. {
  1731. this.stylesheet = stylesheet;
  1732. };
  1733. /**
  1734. * Function: getSelectionModel
  1735. *
  1736. * Returns the <mxGraphSelectionModel> that contains the selection.
  1737. */
  1738. mxGraph.prototype.getSelectionModel = function()
  1739. {
  1740. return this.selectionModel;
  1741. };
  1742. /**
  1743. * Function: setSelectionModel
  1744. *
  1745. * Sets the <mxSelectionModel> that contains the selection.
  1746. */
  1747. mxGraph.prototype.setSelectionModel = function(selectionModel)
  1748. {
  1749. this.selectionModel = selectionModel;
  1750. };
  1751. /**
  1752. * Function: getSelectionCellsForChanges
  1753. *
  1754. * Returns the cells to be selected for the given array of changes.
  1755. *
  1756. * Parameters:
  1757. *
  1758. * ignoreFn - Optional function that takes a change and returns true if the
  1759. * change should be ignored.
  1760. *
  1761. */
  1762. mxGraph.prototype.getSelectionCellsForChanges = function(changes, ignoreFn)
  1763. {
  1764. var dict = new mxDictionary();
  1765. var cells = [];
  1766. var addCell = mxUtils.bind(this, function(cell)
  1767. {
  1768. if (!dict.get(cell) && this.model.contains(cell))
  1769. {
  1770. if (this.model.isEdge(cell) || this.model.isVertex(cell))
  1771. {
  1772. dict.put(cell, true);
  1773. cells.push(cell);
  1774. }
  1775. else
  1776. {
  1777. var childCount = this.model.getChildCount(cell);
  1778. for (var i = 0; i < childCount; i++)
  1779. {
  1780. addCell(this.model.getChildAt(cell, i));
  1781. }
  1782. }
  1783. }
  1784. });
  1785. for (var i = 0; i < changes.length; i++)
  1786. {
  1787. var change = changes[i];
  1788. if (change.constructor != mxRootChange &&
  1789. (ignoreFn == null || !ignoreFn(change)))
  1790. {
  1791. var cell = null;
  1792. if (change instanceof mxChildChange)
  1793. {
  1794. cell = change.child;
  1795. }
  1796. else if (change.cell != null &&
  1797. change.cell instanceof mxCell)
  1798. {
  1799. cell = change.cell;
  1800. }
  1801. if (cell != null)
  1802. {
  1803. addCell(cell);
  1804. }
  1805. }
  1806. }
  1807. return cells;
  1808. };
  1809. /**
  1810. * Function: graphModelChanged
  1811. *
  1812. * Called when the graph model changes. Invokes <processChange> on each
  1813. * item of the given array to update the view accordingly.
  1814. *
  1815. * Parameters:
  1816. *
  1817. * changes - Array that contains the individual changes.
  1818. */
  1819. mxGraph.prototype.graphModelChanged = function(changes)
  1820. {
  1821. for (var i = 0; i < changes.length; i++)
  1822. {
  1823. this.processChange(changes[i]);
  1824. }
  1825. this.updateSelection();
  1826. this.view.validate();
  1827. this.sizeDidChange();
  1828. };
  1829. /**
  1830. * Function: updateSelection
  1831. *
  1832. * Removes selection cells that are not in the model from the selection.
  1833. */
  1834. mxGraph.prototype.updateSelection = function()
  1835. {
  1836. var cells = this.getSelectionCells();
  1837. var removed = [];
  1838. for (var i = 0; i < cells.length; i++)
  1839. {
  1840. if (!this.model.contains(cells[i]) || !this.isCellVisible(cells[i]))
  1841. {
  1842. removed.push(cells[i]);
  1843. }
  1844. else
  1845. {
  1846. var par = this.model.getParent(cells[i]);
  1847. while (par != null && par != this.view.currentRoot)
  1848. {
  1849. if (this.isCellCollapsed(par) || !this.isCellVisible(par))
  1850. {
  1851. removed.push(cells[i]);
  1852. break;
  1853. }
  1854. par = this.model.getParent(par);
  1855. }
  1856. }
  1857. }
  1858. this.removeSelectionCells(removed);
  1859. };
  1860. /**
  1861. * Function: processChange
  1862. *
  1863. * Processes the given change and invalidates the respective cached data
  1864. * in <view>. This fires a <root> event if the root has changed in the
  1865. * model.
  1866. *
  1867. * Parameters:
  1868. *
  1869. * change - Object that represents the change on the model.
  1870. */
  1871. mxGraph.prototype.processChange = function(change)
  1872. {
  1873. // Resets the view settings, removes all cells and clears
  1874. // the selection if the root changes.
  1875. if (change instanceof mxRootChange)
  1876. {
  1877. this.clearSelection();
  1878. this.setDefaultParent(null);
  1879. this.removeStateForCell(change.previous);
  1880. if (this.resetViewOnRootChange)
  1881. {
  1882. this.view.scale = 1;
  1883. this.view.translate.x = 0;
  1884. this.view.translate.y = 0;
  1885. }
  1886. this.fireEvent(new mxEventObject(mxEvent.ROOT));
  1887. }
  1888. // Adds or removes a child to the view by online invaliding
  1889. // the minimal required portions of the cache, namely, the
  1890. // old and new parent and the child.
  1891. else if (change instanceof mxChildChange)
  1892. {
  1893. var newParent = this.model.getParent(change.child);
  1894. this.view.invalidate(change.child, true, true);
  1895. if (!this.model.contains(newParent) || this.isCellCollapsed(newParent))
  1896. {
  1897. this.view.invalidate(change.child, true, true);
  1898. this.removeStateForCell(change.child);
  1899. // Handles special case of current root of view being removed
  1900. if (this.view.currentRoot == change.child)
  1901. {
  1902. this.home();
  1903. }
  1904. }
  1905. if (newParent != change.previous)
  1906. {
  1907. // Refreshes the collapse/expand icons on the parents
  1908. if (newParent != null)
  1909. {
  1910. this.view.invalidate(newParent, false, false);
  1911. }
  1912. if (change.previous != null)
  1913. {
  1914. this.view.invalidate(change.previous, false, false);
  1915. }
  1916. }
  1917. }
  1918. // Handles two special cases where the shape does not need to be
  1919. // recreated from scratch, it only needs to be invalidated.
  1920. else if (change instanceof mxTerminalChange || change instanceof mxGeometryChange)
  1921. {
  1922. // Checks if the geometry has changed to avoid unnessecary revalidation
  1923. if (change instanceof mxTerminalChange || ((change.previous == null && change.geometry != null) ||
  1924. (change.previous != null && !change.previous.equals(change.geometry))))
  1925. {
  1926. this.view.invalidate(change.cell);
  1927. }
  1928. }
  1929. // Handles two special cases where only the shape, but no
  1930. // descendants need to be recreated
  1931. else if (change instanceof mxValueChange)
  1932. {
  1933. this.view.invalidate(change.cell, false, false);
  1934. }
  1935. // Requires a new mxShape in JavaScript
  1936. else if (change instanceof mxStyleChange)
  1937. {
  1938. this.view.invalidate(change.cell, true, true);
  1939. var state = this.view.getState(change.cell);
  1940. if (state != null)
  1941. {
  1942. state.invalidStyle = true;
  1943. }
  1944. }
  1945. // Removes the state from the cache by default
  1946. else if (change.cell != null && change.cell instanceof mxCell)
  1947. {
  1948. this.removeStateForCell(change.cell);
  1949. }
  1950. };
  1951. /**
  1952. * Function: removeStateForCell
  1953. *
  1954. * Removes all cached information for the given cell and its descendants.
  1955. * This is called when a cell was removed from the model.
  1956. *
  1957. * Paramters:
  1958. *
  1959. * cell - <mxCell> that was removed from the model.
  1960. */
  1961. mxGraph.prototype.removeStateForCell = function(cell)
  1962. {
  1963. var childCount = this.model.getChildCount(cell);
  1964. for (var i = 0; i < childCount; i++)
  1965. {
  1966. this.removeStateForCell(this.model.getChildAt(cell, i));
  1967. }
  1968. this.view.invalidate(cell, false, true);
  1969. this.view.removeState(cell);
  1970. };
  1971. /**
  1972. * Group: Overlays
  1973. */
  1974. /**
  1975. * Function: addCellOverlay
  1976. *
  1977. * Adds an <mxCellOverlay> for the specified cell. This method fires an
  1978. * <addoverlay> event and returns the new <mxCellOverlay>.
  1979. *
  1980. * Parameters:
  1981. *
  1982. * cell - <mxCell> to add the overlay for.
  1983. * overlay - <mxCellOverlay> to be added for the cell.
  1984. */
  1985. mxGraph.prototype.addCellOverlay = function(cell, overlay)
  1986. {
  1987. if (cell.overlays == null)
  1988. {
  1989. cell.overlays = [];
  1990. }
  1991. cell.overlays.push(overlay);
  1992. var state = this.view.getState(cell);
  1993. // Immediately updates the cell display if the state exists
  1994. if (state != null)
  1995. {
  1996. this.cellRenderer.redraw(state);
  1997. }
  1998. this.fireEvent(new mxEventObject(mxEvent.ADD_OVERLAY,
  1999. 'cell', cell, 'overlay', overlay));
  2000. return overlay;
  2001. };
  2002. /**
  2003. * Function: getCellOverlays
  2004. *
  2005. * Returns the array of <mxCellOverlays> for the given cell or null, if
  2006. * no overlays are defined.
  2007. *
  2008. * Parameters:
  2009. *
  2010. * cell - <mxCell> whose overlays should be returned.
  2011. */
  2012. mxGraph.prototype.getCellOverlays = function(cell)
  2013. {
  2014. return cell.overlays;
  2015. };
  2016. /**
  2017. * Function: removeCellOverlay
  2018. *
  2019. * Removes and returns the given <mxCellOverlay> from the given cell. This
  2020. * method fires a <removeoverlay> event. If no overlay is given, then all
  2021. * overlays are removed using <removeOverlays>.
  2022. *
  2023. * Parameters:
  2024. *
  2025. * cell - <mxCell> whose overlay should be removed.
  2026. * overlay - Optional <mxCellOverlay> to be removed.
  2027. */
  2028. mxGraph.prototype.removeCellOverlay = function(cell, overlay)
  2029. {
  2030. if (overlay == null)
  2031. {
  2032. this.removeCellOverlays(cell);
  2033. }
  2034. else
  2035. {
  2036. var index = mxUtils.indexOf(cell.overlays, overlay);
  2037. if (index >= 0)
  2038. {
  2039. cell.overlays.splice(index, 1);
  2040. if (cell.overlays.length == 0)
  2041. {
  2042. cell.overlays = null;
  2043. }
  2044. // Immediately updates the cell display if the state exists
  2045. var state = this.view.getState(cell);
  2046. if (state != null)
  2047. {
  2048. this.cellRenderer.redraw(state);
  2049. }
  2050. this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
  2051. 'cell', cell, 'overlay', overlay));
  2052. }
  2053. else
  2054. {
  2055. overlay = null;
  2056. }
  2057. }
  2058. return overlay;
  2059. };
  2060. /**
  2061. * Function: removeCellOverlays
  2062. *
  2063. * Removes all <mxCellOverlays> from the given cell. This method
  2064. * fires a <removeoverlay> event for each <mxCellOverlay> and returns
  2065. * the array of <mxCellOverlays> that was removed from the cell.
  2066. *
  2067. * Parameters:
  2068. *
  2069. * cell - <mxCell> whose overlays should be removed
  2070. */
  2071. mxGraph.prototype.removeCellOverlays = function(cell)
  2072. {
  2073. var overlays = cell.overlays;
  2074. if (overlays != null)
  2075. {
  2076. cell.overlays = null;
  2077. // Immediately updates the cell display if the state exists
  2078. var state = this.view.getState(cell);
  2079. if (state != null)
  2080. {
  2081. this.cellRenderer.redraw(state);
  2082. }
  2083. for (var i = 0; i < overlays.length; i++)
  2084. {
  2085. this.fireEvent(new mxEventObject(mxEvent.REMOVE_OVERLAY,
  2086. 'cell', cell, 'overlay', overlays[i]));
  2087. }
  2088. }
  2089. return overlays;
  2090. };
  2091. /**
  2092. * Function: clearCellOverlays
  2093. *
  2094. * Removes all <mxCellOverlays> in the graph for the given cell and all its
  2095. * descendants. If no cell is specified then all overlays are removed from
  2096. * the graph. This implementation uses <removeCellOverlays> to remove the
  2097. * overlays from the individual cells.
  2098. *
  2099. * Parameters:
  2100. *
  2101. * cell - Optional <mxCell> that represents the root of the subtree to
  2102. * remove the overlays from. Default is the root in the model.
  2103. */
  2104. mxGraph.prototype.clearCellOverlays = function(cell)
  2105. {
  2106. cell = (cell != null) ? cell : this.model.getRoot();
  2107. this.removeCellOverlays(cell);
  2108. // Recursively removes all overlays from the children
  2109. var childCount = this.model.getChildCount(cell);
  2110. for (var i = 0; i < childCount; i++)
  2111. {
  2112. var child = this.model.getChildAt(cell, i);
  2113. this.clearCellOverlays(child); // recurse
  2114. }
  2115. };
  2116. /**
  2117. * Function: setCellWarning
  2118. *
  2119. * Creates an overlay for the given cell using the warning and image or
  2120. * <warningImage> and returns the new <mxCellOverlay>. The warning is
  2121. * displayed as a tooltip in a red font and may contain HTML markup. If
  2122. * the warning is null or a zero length string, then all overlays are
  2123. * removed from the cell.
  2124. *
  2125. * Example:
  2126. *
  2127. * (code)
  2128. * graph.setCellWarning(cell, '<b>Warning:</b>: Hello, World!');
  2129. * (end)
  2130. *
  2131. * Parameters:
  2132. *
  2133. * cell - <mxCell> whose warning should be set.
  2134. * warning - String that represents the warning to be displayed.
  2135. * img - Optional <mxImage> to be used for the overlay. Default is
  2136. * <warningImage>.
  2137. * isSelect - Optional boolean indicating if a click on the overlay
  2138. * should select the corresponding cell. Default is false.
  2139. */
  2140. mxGraph.prototype.setCellWarning = function(cell, warning, img, isSelect)
  2141. {
  2142. if (warning != null && warning.length > 0)
  2143. {
  2144. img = (img != null) ? img : this.warningImage;
  2145. // Creates the overlay with the image and warning
  2146. var overlay = new mxCellOverlay(img,
  2147. '<font color=red>'+warning+'</font>');
  2148. // Adds a handler for single mouseclicks to select the cell
  2149. if (isSelect)
  2150. {
  2151. overlay.addListener(mxEvent.CLICK,
  2152. mxUtils.bind(this, function(sender, evt)
  2153. {
  2154. if (this.isEnabled())
  2155. {
  2156. this.setSelectionCell(cell);
  2157. }
  2158. })
  2159. );
  2160. }
  2161. // Sets and returns the overlay in the graph
  2162. return this.addCellOverlay(cell, overlay);
  2163. }
  2164. else
  2165. {
  2166. this.removeCellOverlays(cell);
  2167. }
  2168. return null;
  2169. };
  2170. /**
  2171. * Group: In-place editing
  2172. */
  2173. /**
  2174. * Function: startEditing
  2175. *
  2176. * Calls <startEditingAtCell> using the given cell or the first selection
  2177. * cell.
  2178. *
  2179. * Parameters:
  2180. *
  2181. * evt - Optional mouse event that triggered the editing.
  2182. */
  2183. mxGraph.prototype.startEditing = function(evt)
  2184. {
  2185. this.startEditingAtCell(null, evt);
  2186. };
  2187. /**
  2188. * Function: startEditingAtCell
  2189. *
  2190. * Fires a <startEditing> event and invokes <mxCellEditor.startEditing>
  2191. * on <editor>. After editing was started, a <editingStarted> event is
  2192. * fired.
  2193. *
  2194. * Parameters:
  2195. *
  2196. * cell - <mxCell> to start the in-place editor for.
  2197. * evt - Optional mouse event that triggered the editing.
  2198. */
  2199. mxGraph.prototype.startEditingAtCell = function(cell, evt)
  2200. {
  2201. if (evt == null || !mxEvent.isMultiTouchEvent(evt))
  2202. {
  2203. if (cell == null)
  2204. {
  2205. cell = this.getSelectionCell();
  2206. if (cell != null && !this.isCellEditable(cell))
  2207. {
  2208. cell = null;
  2209. }
  2210. }
  2211. if (cell != null)
  2212. {
  2213. this.fireEvent(new mxEventObject(mxEvent.START_EDITING,
  2214. 'cell', cell, 'event', evt));
  2215. this.cellEditor.startEditing(cell, evt);
  2216. this.fireEvent(new mxEventObject(mxEvent.EDITING_STARTED,
  2217. 'cell', cell, 'event', evt));
  2218. }
  2219. }
  2220. };
  2221. /**
  2222. * Function: getEditingValue
  2223. *
  2224. * Returns the initial value for in-place editing. This implementation
  2225. * returns <convertValueToString> for the given cell. If this function is
  2226. * overridden, then <mxGraphModel.valueForCellChanged> should take care
  2227. * of correctly storing the actual new value inside the user object.
  2228. *
  2229. * Parameters:
  2230. *
  2231. * cell - <mxCell> for which the initial editing value should be returned.
  2232. * evt - Optional mouse event that triggered the editor.
  2233. */
  2234. mxGraph.prototype.getEditingValue = function(cell, evt)
  2235. {
  2236. return this.convertValueToString(cell);
  2237. };
  2238. /**
  2239. * Function: stopEditing
  2240. *
  2241. * Stops the current editing and fires a <editingStopped> event.
  2242. *
  2243. * Parameters:
  2244. *
  2245. * cancel - Boolean that specifies if the current editing value
  2246. * should be stored.
  2247. */
  2248. mxGraph.prototype.stopEditing = function(cancel)
  2249. {
  2250. this.cellEditor.stopEditing(cancel);
  2251. this.fireEvent(new mxEventObject(mxEvent.EDITING_STOPPED, 'cancel', cancel));
  2252. };
  2253. /**
  2254. * Function: labelChanged
  2255. *
  2256. * Sets the label of the specified cell to the given value using
  2257. * <cellLabelChanged> and fires <mxEvent.LABEL_CHANGED> while the
  2258. * transaction is in progress. Returns the cell whose label was changed.
  2259. *
  2260. * Parameters:
  2261. *
  2262. * cell - <mxCell> whose label should be changed.
  2263. * value - New label to be assigned.
  2264. * evt - Optional event that triggered the change.
  2265. */
  2266. mxGraph.prototype.labelChanged = function(cell, value, evt)
  2267. {
  2268. this.model.beginUpdate();
  2269. try
  2270. {
  2271. var old = cell.value;
  2272. this.cellLabelChanged(cell, value, this.isAutoSizeCell(cell));
  2273. this.fireEvent(new mxEventObject(mxEvent.LABEL_CHANGED,
  2274. 'cell', cell, 'value', value, 'old', old, 'event', evt));
  2275. }
  2276. finally
  2277. {
  2278. this.model.endUpdate();
  2279. }
  2280. return cell;
  2281. };
  2282. /**
  2283. * Function: cellLabelChanged
  2284. *
  2285. * Sets the new label for a cell. If autoSize is true then
  2286. * <cellSizeUpdated> will be called.
  2287. *
  2288. * In the following example, the function is extended to map changes to
  2289. * attributes in an XML node, as shown in <convertValueToString>.
  2290. * Alternatively, the handling of this can be implemented as shown in
  2291. * <mxGraphModel.valueForCellChanged> without the need to clone the
  2292. * user object.
  2293. *
  2294. * (code)
  2295. * var graphCellLabelChanged = graph.cellLabelChanged;
  2296. * graph.cellLabelChanged = function(cell, newValue, autoSize)
  2297. * {
  2298. * // Cloned for correct undo/redo
  2299. * var elt = cell.value.cloneNode(true);
  2300. * elt.setAttribute('label', newValue);
  2301. *
  2302. * newValue = elt;
  2303. * graphCellLabelChanged.apply(this, arguments);
  2304. * };
  2305. * (end)
  2306. *
  2307. * Parameters:
  2308. *
  2309. * cell - <mxCell> whose label should be changed.
  2310. * value - New label to be assigned.
  2311. * autoSize - Boolean that specifies if <cellSizeUpdated> should be called.
  2312. */
  2313. mxGraph.prototype.cellLabelChanged = function(cell, value, autoSize)
  2314. {
  2315. this.model.beginUpdate();
  2316. try
  2317. {
  2318. this.model.setValue(cell, value);
  2319. if (autoSize)
  2320. {
  2321. this.cellSizeUpdated(cell, false);
  2322. }
  2323. }
  2324. finally
  2325. {
  2326. this.model.endUpdate();
  2327. }
  2328. };
  2329. /**
  2330. * Group: Event processing
  2331. */
  2332. /**
  2333. * Function: escape
  2334. *
  2335. * Processes an escape keystroke.
  2336. *
  2337. * Parameters:
  2338. *
  2339. * evt - Mouseevent that represents the keystroke.
  2340. */
  2341. mxGraph.prototype.escape = function(evt)
  2342. {
  2343. this.fireEvent(new mxEventObject(mxEvent.ESCAPE, 'event', evt));
  2344. };
  2345. /**
  2346. * Function: click
  2347. *
  2348. * Processes a singleclick on an optional cell and fires a <click> event.
  2349. * The click event is fired initially. If the graph is enabled and the
  2350. * event has not been consumed, then the cell is selected using
  2351. * <selectCellForEvent> or the selection is cleared using
  2352. * <clearSelection>. The events consumed state is set to true if the
  2353. * corresponding <mxMouseEvent> has been consumed.
  2354. *
  2355. * To handle a click event, use the following code.
  2356. *
  2357. * (code)
  2358. * graph.addListener(mxEvent.CLICK, function(sender, evt)
  2359. * {
  2360. * var e = evt.getProperty('event'); // mouse event
  2361. * var cell = evt.getProperty('cell'); // cell may be null
  2362. *
  2363. * if (cell != null)
  2364. * {
  2365. * // Do something useful with cell and consume the event
  2366. * evt.consume();
  2367. * }
  2368. * });
  2369. * (end)
  2370. *
  2371. * Parameters:
  2372. *
  2373. * me - <mxMouseEvent> that represents the single click.
  2374. */
  2375. mxGraph.prototype.click = function(me)
  2376. {
  2377. var evt = me.getEvent();
  2378. var cell = me.getCell();
  2379. var mxe = new mxEventObject(mxEvent.CLICK, 'event', evt, 'cell', cell);
  2380. if (me.isConsumed())
  2381. {
  2382. mxe.consume();
  2383. }
  2384. this.fireEvent(mxe);
  2385. if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed())
  2386. {
  2387. if (cell != null)
  2388. {
  2389. if (this.isTransparentClickEvent(evt))
  2390. {
  2391. var active = false;
  2392. var tmp = this.getCellAt(me.graphX, me.graphY, null, null, null,
  2393. mxUtils.bind(this, function(state)
  2394. {
  2395. var selected = this.isCellSelected(state.cell);
  2396. active = active || selected;
  2397. return !active || selected || (state.cell != cell &&
  2398. this.model.isAncestor(state.cell, cell));
  2399. }));
  2400. if (tmp != null)
  2401. {
  2402. cell = tmp;
  2403. }
  2404. }
  2405. }
  2406. else if (this.isSwimlaneSelectionEnabled())
  2407. {
  2408. cell = this.getSwimlaneAt(me.getGraphX(), me.getGraphY());
  2409. if (cell != null && (!this.isToggleEvent(evt) ||
  2410. !mxEvent.isAltDown(evt)))
  2411. {
  2412. var temp = cell;
  2413. var swimlanes = [];
  2414. while (temp != null)
  2415. {
  2416. temp = this.model.getParent(temp);
  2417. var state = this.view.getState(temp);
  2418. if (this.isSwimlane(temp) && state != null)
  2419. {
  2420. swimlanes.push(temp);
  2421. }
  2422. }
  2423. // Selects ancestors for selected swimlanes
  2424. if (swimlanes.length > 0)
  2425. {
  2426. swimlanes = swimlanes.reverse();
  2427. swimlanes.splice(0, 0, cell);
  2428. swimlanes.push(cell);
  2429. for (var i = 0; i < swimlanes.length - 1; i++)
  2430. {
  2431. if (this.isCellSelected(swimlanes[i]))
  2432. {
  2433. cell = swimlanes[(this.isToggleEvent(evt)) ?
  2434. i : i + 1];
  2435. }
  2436. }
  2437. }
  2438. }
  2439. }
  2440. if (cell != null)
  2441. {
  2442. this.selectCellForEvent(cell, evt);
  2443. }
  2444. else if (!this.isToggleEvent(evt))
  2445. {
  2446. this.clearSelection();
  2447. }
  2448. }
  2449. };
  2450. /**
  2451. * Function: isSiblingSelected
  2452. *
  2453. * Returns true if any sibling of the given cell is selected.
  2454. */
  2455. mxGraph.prototype.isSiblingSelected = function(cell)
  2456. {
  2457. var model = this.model;
  2458. var parent = model.getParent(cell);
  2459. var childCount = model.getChildCount(parent);
  2460. for (var i = 0; i < childCount; i++)
  2461. {
  2462. var child = model.getChildAt(parent, i);
  2463. if (cell != child && this.isCellSelected(child))
  2464. {
  2465. return true;
  2466. }
  2467. }
  2468. return false;
  2469. };
  2470. /**
  2471. * Function: dblClick
  2472. *
  2473. * Processes a doubleclick on an optional cell and fires a <dblclick>
  2474. * event. The event is fired initially. If the graph is enabled and the
  2475. * event has not been consumed, then <edit> is called with the given
  2476. * cell. The event is ignored if no cell was specified.
  2477. *
  2478. * Example for overriding this method.
  2479. *
  2480. * (code)
  2481. * graph.dblClick = function(evt, cell)
  2482. * {
  2483. * var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell);
  2484. * this.fireEvent(mxe);
  2485. *
  2486. * if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed())
  2487. * {
  2488. * mxUtils.alert('Hello, World!');
  2489. * mxe.consume();
  2490. * }
  2491. * }
  2492. * (end)
  2493. *
  2494. * Example listener for this event.
  2495. *
  2496. * (code)
  2497. * graph.addListener(mxEvent.DOUBLE_CLICK, function(sender, evt)
  2498. * {
  2499. * var cell = evt.getProperty('cell');
  2500. * // do something with the cell and consume the
  2501. * // event to prevent in-place editing from start
  2502. * });
  2503. * (end)
  2504. *
  2505. * Parameters:
  2506. *
  2507. * evt - Mouseevent that represents the doubleclick.
  2508. * cell - Optional <mxCell> under the mousepointer.
  2509. */
  2510. mxGraph.prototype.dblClick = function(evt, cell)
  2511. {
  2512. var mxe = new mxEventObject(mxEvent.DOUBLE_CLICK, 'event', evt, 'cell', cell);
  2513. this.fireEvent(mxe);
  2514. // Handles the event if it has not been consumed
  2515. if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() &&
  2516. cell != null && this.isCellEditable(cell) && !this.isEditing(cell))
  2517. {
  2518. this.startEditingAtCell(cell, evt);
  2519. mxEvent.consume(evt);
  2520. }
  2521. };
  2522. /**
  2523. * Function: tapAndHold
  2524. *
  2525. * Handles the <mxMouseEvent> by highlighting the <mxCellState>.
  2526. *
  2527. * Parameters:
  2528. *
  2529. * me - <mxMouseEvent> that represents the touch event.
  2530. * state - Optional <mxCellState> that is associated with the event.
  2531. */
  2532. mxGraph.prototype.tapAndHold = function(me)
  2533. {
  2534. var evt = me.getEvent();
  2535. var mxe = new mxEventObject(mxEvent.TAP_AND_HOLD, 'event', evt, 'cell', me.getCell());
  2536. // LATER: Check if event should be consumed if me is consumed
  2537. this.fireEvent(mxe);
  2538. if (mxe.isConsumed())
  2539. {
  2540. // Resets the state of the panning handler
  2541. this.panningHandler.panningTrigger = false;
  2542. }
  2543. // Handles the event if it has not been consumed
  2544. if (this.isEnabled() && !mxEvent.isConsumed(evt) && !mxe.isConsumed() && this.connectionHandler.isEnabled())
  2545. {
  2546. var state = this.view.getState(this.connectionHandler.marker.getCell(me));
  2547. if (state != null)
  2548. {
  2549. this.connectionHandler.marker.currentColor = this.connectionHandler.marker.validColor;
  2550. this.connectionHandler.marker.markedState = state;
  2551. this.connectionHandler.marker.mark();
  2552. this.connectionHandler.first = new mxPoint(me.getGraphX(), me.getGraphY());
  2553. this.connectionHandler.edgeState = this.connectionHandler.createEdgeState(me);
  2554. this.connectionHandler.previous = state;
  2555. this.connectionHandler.fireEvent(new mxEventObject(mxEvent.START, 'state', this.connectionHandler.previous));
  2556. }
  2557. }
  2558. };
  2559. /**
  2560. * Function: scrollPointToVisible
  2561. *
  2562. * Scrolls the graph to the given point, extending the graph container if
  2563. * specified.
  2564. */
  2565. mxGraph.prototype.scrollPointToVisible = function(x, y, extend, border)
  2566. {
  2567. if (!this.timerAutoScroll && (this.ignoreScrollbars || mxUtils.hasScrollbars(this.container)))
  2568. {
  2569. var c = this.container;
  2570. border = (border != null) ? border : 20;
  2571. if (x >= c.scrollLeft && y >= c.scrollTop && x <= c.scrollLeft + c.clientWidth &&
  2572. y <= c.scrollTop + c.clientHeight)
  2573. {
  2574. var dx = c.scrollLeft + c.clientWidth - x;
  2575. if (dx < border)
  2576. {
  2577. var old = c.scrollLeft;
  2578. c.scrollLeft += border - dx;
  2579. // Automatically extends the canvas size to the bottom, right
  2580. // if the event is outside of the canvas and the edge of the
  2581. // canvas has been reached. Notes: Needs fix for IE.
  2582. if (extend && old == c.scrollLeft)
  2583. {
  2584. if (this.dialect == mxConstants.DIALECT_SVG)
  2585. {
  2586. var root = this.view.getDrawPane().ownerSVGElement;
  2587. var width = this.container.scrollWidth + border - dx;
  2588. // Updates the clipping region. This is an expensive
  2589. // operation that should not be executed too often.
  2590. root.style.width = width + 'px';
  2591. }
  2592. else
  2593. {
  2594. var width = Math.max(c.clientWidth, c.scrollWidth) + border - dx;
  2595. var canvas = this.view.getCanvas();
  2596. canvas.style.width = width + 'px';
  2597. }
  2598. c.scrollLeft += border - dx;
  2599. }
  2600. }
  2601. else
  2602. {
  2603. dx = x - c.scrollLeft;
  2604. if (dx < border)
  2605. {
  2606. c.scrollLeft -= border - dx;
  2607. }
  2608. }
  2609. var dy = c.scrollTop + c.clientHeight - y;
  2610. if (dy < border)
  2611. {
  2612. var old = c.scrollTop;
  2613. c.scrollTop += border - dy;
  2614. if (old == c.scrollTop && extend)
  2615. {
  2616. if (this.dialect == mxConstants.DIALECT_SVG)
  2617. {
  2618. var root = this.view.getDrawPane().ownerSVGElement;
  2619. var height = this.container.scrollHeight + border - dy;
  2620. // Updates the clipping region. This is an expensive
  2621. // operation that should not be executed too often.
  2622. root.style.height = height + 'px';
  2623. }
  2624. else
  2625. {
  2626. var height = Math.max(c.clientHeight, c.scrollHeight) + border - dy;
  2627. var canvas = this.view.getCanvas();
  2628. canvas.style.height = height + 'px';
  2629. }
  2630. c.scrollTop += border - dy;
  2631. }
  2632. }
  2633. else
  2634. {
  2635. dy = y - c.scrollTop;
  2636. if (dy < border)
  2637. {
  2638. c.scrollTop -= border - dy;
  2639. }
  2640. }
  2641. }
  2642. }
  2643. else if (this.allowAutoPanning && !this.panningHandler.isActive())
  2644. {
  2645. if (this.panningManager == null)
  2646. {
  2647. this.panningManager = this.createPanningManager();
  2648. }
  2649. this.panningManager.panTo(x + this.panDx, y + this.panDy);
  2650. }
  2651. };
  2652. /**
  2653. * Function: createPanningManager
  2654. *
  2655. * Creates and returns an <mxPanningManager>.
  2656. */
  2657. mxGraph.prototype.createPanningManager = function()
  2658. {
  2659. return new mxPanningManager(this);
  2660. };
  2661. /**
  2662. * Function: getBorderSizes
  2663. *
  2664. * Returns the size of the border and padding on all four sides of the
  2665. * container. The left, top, right and bottom borders are stored in the x, y,
  2666. * width and height of the returned <mxRectangle>, respectively.
  2667. */
  2668. mxGraph.prototype.getBorderSizes = function()
  2669. {
  2670. var css = mxUtils.getCurrentStyle(this.container);
  2671. return new mxRectangle(mxUtils.parseCssNumber(css.paddingLeft) +
  2672. ((css.borderLeftStyle != 'none') ? mxUtils.parseCssNumber(css.borderLeftWidth) : 0),
  2673. mxUtils.parseCssNumber(css.paddingTop) +
  2674. ((css.borderTopStyle != 'none') ? mxUtils.parseCssNumber(css.borderTopWidth) : 0),
  2675. mxUtils.parseCssNumber(css.paddingRight) +
  2676. ((css.borderRightStyle != 'none') ? mxUtils.parseCssNumber(css.borderRightWidth) : 0),
  2677. mxUtils.parseCssNumber(css.paddingBottom) +
  2678. ((css.borderBottomStyle != 'none') ? mxUtils.parseCssNumber(css.borderBottomWidth) : 0));
  2679. };
  2680. /**
  2681. * Function: getPreferredPageSize
  2682. *
  2683. * Returns the preferred size of the background page if <preferPageSize> is true.
  2684. */
  2685. mxGraph.prototype.getPreferredPageSize = function(bounds, width, height)
  2686. {
  2687. var scale = this.view.scale;
  2688. var tr = this.view.translate;
  2689. var fmt = this.pageFormat;
  2690. var ps = this.pageScale;
  2691. var page = new mxRectangle(0, 0, Math.ceil(fmt.width * ps), Math.ceil(fmt.height * ps));
  2692. var hCount = (this.pageBreaksVisible) ? Math.ceil(width / page.width) : 1;
  2693. var vCount = (this.pageBreaksVisible) ? Math.ceil(height / page.height) : 1;
  2694. return new mxRectangle(0, 0, hCount * page.width + 2 + tr.x, vCount * page.height + 2 + tr.y);
  2695. };
  2696. /**
  2697. * Function: fit
  2698. *
  2699. * Scales the graph such that the complete diagram fits into <container> and
  2700. * returns the current scale in the view. To fit an initial graph prior to
  2701. * rendering, set <mxGraphView.rendering> to false prior to changing the model
  2702. * and execute the following after changing the model.
  2703. *
  2704. * (code)
  2705. * graph.fit();
  2706. * graph.view.rendering = true;
  2707. * graph.refresh();
  2708. * (end)
  2709. *
  2710. * To fit and center the graph, the following code can be used.
  2711. *
  2712. * (code)
  2713. * var margin = 2;
  2714. * var max = 3;
  2715. *
  2716. * var bounds = graph.getGraphBounds();
  2717. * var cw = graph.container.clientWidth - margin;
  2718. * var ch = graph.container.clientHeight - margin;
  2719. * var w = bounds.width / graph.view.scale;
  2720. * var h = bounds.height / graph.view.scale;
  2721. * var s = Math.min(max, Math.min(cw / w, ch / h));
  2722. *
  2723. * graph.view.scaleAndTranslate(s,
  2724. * (margin + cw - w * s) / (2 * s) - bounds.x / graph.view.scale,
  2725. * (margin + ch - h * s) / (2 * s) - bounds.y / graph.view.scale);
  2726. * (end)
  2727. *
  2728. * Parameters:
  2729. *
  2730. * border - Optional number that specifies the border. Default is <border>.
  2731. * keepOrigin - Optional boolean that specifies if the translate should be
  2732. * changed. Default is false.
  2733. * margin - Optional margin in pixels. Default is 0.
  2734. * enabled - Optional boolean that specifies if the scale should be set or
  2735. * just returned. Default is true.
  2736. * ignoreWidth - Optional boolean that specifies if the width should be
  2737. * ignored. Default is false.
  2738. * ignoreHeight - Optional boolean that specifies if the height should be
  2739. * ignored. Default is false.
  2740. * maxHeight - Optional maximum height.
  2741. */
  2742. mxGraph.prototype.fit = function(border, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight)
  2743. {
  2744. if (this.container != null)
  2745. {
  2746. border = (border != null) ? border : this.getBorder();
  2747. keepOrigin = (keepOrigin != null) ? keepOrigin : false;
  2748. margin = (margin != null) ? margin : 0;
  2749. enabled = (enabled != null) ? enabled : true;
  2750. ignoreWidth = (ignoreWidth != null) ? ignoreWidth : false;
  2751. ignoreHeight = (ignoreHeight != null) ? ignoreHeight : false;
  2752. // Adds spacing and border from css
  2753. var cssBorder = this.getBorderSizes();
  2754. var w1 = this.container.offsetWidth - cssBorder.x - cssBorder.width - 1;
  2755. var h1 = (maxHeight != null) ? maxHeight : this.container.offsetHeight - cssBorder.y - cssBorder.height - 1;
  2756. var bounds = this.view.getGraphBounds();
  2757. if (bounds.width > 0 && bounds.height > 0)
  2758. {
  2759. if (keepOrigin && bounds.x != null && bounds.y != null)
  2760. {
  2761. bounds = bounds.clone();
  2762. bounds.width += bounds.x;
  2763. bounds.height += bounds.y;
  2764. bounds.x = 0;
  2765. bounds.y = 0;
  2766. }
  2767. // LATER: Use unscaled bounding boxes to fix rounding errors
  2768. var s = this.view.scale;
  2769. var w2 = bounds.width / s;
  2770. var h2 = bounds.height / s;
  2771. // Fits to the size of the background image if required
  2772. if (this.backgroundImage != null)
  2773. {
  2774. w2 = Math.max(w2, this.backgroundImage.width - bounds.x / s);
  2775. h2 = Math.max(h2, this.backgroundImage.height - bounds.y / s);
  2776. }
  2777. var b = ((keepOrigin) ? border : 2 * border) + margin + 1;
  2778. w1 -= b;
  2779. h1 -= b;
  2780. var s2 = (((ignoreWidth) ? h1 / h2 : (ignoreHeight) ? w1 / w2 :
  2781. Math.min(w1 / w2, h1 / h2)));
  2782. if (this.minFitScale != null)
  2783. {
  2784. s2 = Math.max(s2, this.minFitScale);
  2785. }
  2786. if (this.maxFitScale != null)
  2787. {
  2788. s2 = Math.min(s2, this.maxFitScale);
  2789. }
  2790. if (enabled)
  2791. {
  2792. if (!keepOrigin)
  2793. {
  2794. if (!mxUtils.hasScrollbars(this.container))
  2795. {
  2796. var x0 = (bounds.x != null) ? Math.floor(this.view.translate.x - bounds.x / s + border / s2 + margin / 2) : border;
  2797. var y0 = (bounds.y != null) ? Math.floor(this.view.translate.y - bounds.y / s + border / s2 + margin / 2) : border;
  2798. this.view.scaleAndTranslate(s2, x0, y0);
  2799. }
  2800. else
  2801. {
  2802. this.view.setScale(s2);
  2803. var b2 = this.getGraphBounds();
  2804. if (b2.x != null)
  2805. {
  2806. this.container.scrollLeft = b2.x;
  2807. }
  2808. if (b2.y != null)
  2809. {
  2810. this.container.scrollTop = b2.y;
  2811. }
  2812. }
  2813. }
  2814. else if (this.view.scale != s2)
  2815. {
  2816. this.view.setScale(s2);
  2817. }
  2818. }
  2819. else
  2820. {
  2821. return s2;
  2822. }
  2823. }
  2824. }
  2825. return this.view.scale;
  2826. };
  2827. /**
  2828. * Function: sizeDidChange
  2829. *
  2830. * Called when the size of the graph has changed. This implementation fires
  2831. * a <size> event after updating the clipping region of the SVG element in
  2832. * SVG-bases browsers.
  2833. */
  2834. mxGraph.prototype.sizeDidChange = function()
  2835. {
  2836. var bounds = this.getGraphBounds();
  2837. if (this.container != null)
  2838. {
  2839. var border = this.getBorder();
  2840. var width = Math.max(0, bounds.x) + bounds.width + 2 * border;
  2841. var height = Math.max(0, bounds.y) + bounds.height + 2 * border;
  2842. if (this.minimumContainerSize != null)
  2843. {
  2844. width = Math.max(width, this.minimumContainerSize.width);
  2845. height = Math.max(height, this.minimumContainerSize.height);
  2846. }
  2847. if (this.resizeContainer)
  2848. {
  2849. this.doResizeContainer(width, height);
  2850. }
  2851. if (this.preferPageSize || (!mxClient.IS_IE && this.pageVisible))
  2852. {
  2853. var size = this.getPreferredPageSize(bounds, Math.max(1, width), Math.max(1, height));
  2854. if (size != null)
  2855. {
  2856. width = size.width * this.view.scale;
  2857. height = size.height * this.view.scale;
  2858. }
  2859. }
  2860. if (this.minimumGraphSize != null)
  2861. {
  2862. width = Math.max(width, this.minimumGraphSize.width * this.view.scale);
  2863. height = Math.max(height, this.minimumGraphSize.height * this.view.scale);
  2864. }
  2865. width = Math.ceil(width);
  2866. height = Math.ceil(height);
  2867. if (this.dialect == mxConstants.DIALECT_SVG)
  2868. {
  2869. var root = this.view.getDrawPane().ownerSVGElement;
  2870. if (root != null)
  2871. {
  2872. root.style.minWidth = Math.max(1, width) + 'px';
  2873. root.style.minHeight = Math.max(1, height) + 'px';
  2874. root.style.width = '100%';
  2875. root.style.height = '100%';
  2876. }
  2877. }
  2878. else
  2879. {
  2880. if (mxClient.IS_QUIRKS)
  2881. {
  2882. // Quirks mode does not support minWidth/-Height
  2883. this.view.updateHtmlCanvasSize(Math.max(1, width), Math.max(1, height));
  2884. }
  2885. else
  2886. {
  2887. this.view.canvas.style.minWidth = Math.max(1, width) + 'px';
  2888. this.view.canvas.style.minHeight = Math.max(1, height) + 'px';
  2889. }
  2890. }
  2891. this.updatePageBreaks(this.pageBreaksVisible, width, height);
  2892. }
  2893. this.fireEvent(new mxEventObject(mxEvent.SIZE, 'bounds', bounds));
  2894. };
  2895. /**
  2896. * Function: doResizeContainer
  2897. *
  2898. * Resizes the container for the given graph width and height.
  2899. */
  2900. mxGraph.prototype.doResizeContainer = function(width, height)
  2901. {
  2902. if (this.maximumContainerSize != null)
  2903. {
  2904. width = Math.min(this.maximumContainerSize.width, width);
  2905. height = Math.min(this.maximumContainerSize.height, height);
  2906. }
  2907. this.container.style.width = Math.ceil(width) + 'px';
  2908. this.container.style.height = Math.ceil(height) + 'px';
  2909. };
  2910. /**
  2911. * Function: updatePageBreaks
  2912. *
  2913. * Invokes from <sizeDidChange> to redraw the page breaks.
  2914. *
  2915. * Parameters:
  2916. *
  2917. * visible - Boolean that specifies if page breaks should be shown.
  2918. * width - Specifies the width of the container in pixels.
  2919. * height - Specifies the height of the container in pixels.
  2920. */
  2921. mxGraph.prototype.updatePageBreaks = function(visible, width, height)
  2922. {
  2923. var scale = this.view.scale;
  2924. var tr = this.view.translate;
  2925. var fmt = this.pageFormat;
  2926. var ps = scale * this.pageScale;
  2927. var bounds = new mxRectangle(0, 0, fmt.width * ps, fmt.height * ps);
  2928. var gb = mxRectangle.fromRectangle(this.getGraphBounds());
  2929. gb.width = Math.max(1, gb.width);
  2930. gb.height = Math.max(1, gb.height);
  2931. bounds.x = Math.floor((gb.x - tr.x * scale) / bounds.width) * bounds.width + tr.x * scale;
  2932. bounds.y = Math.floor((gb.y - tr.y * scale) / bounds.height) * bounds.height + tr.y * scale;
  2933. gb.width = Math.ceil((gb.width + (gb.x - bounds.x)) / bounds.width) * bounds.width;
  2934. gb.height = Math.ceil((gb.height + (gb.y - bounds.y)) / bounds.height) * bounds.height;
  2935. // Does not show page breaks if the scale is too small
  2936. visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;
  2937. var horizontalCount = (visible) ? Math.ceil(gb.height / bounds.height) + 1 : 0;
  2938. var verticalCount = (visible) ? Math.ceil(gb.width / bounds.width) + 1 : 0;
  2939. var right = (verticalCount - 1) * bounds.width;
  2940. var bottom = (horizontalCount - 1) * bounds.height;
  2941. if (this.horizontalPageBreaks == null && horizontalCount > 0)
  2942. {
  2943. this.horizontalPageBreaks = [];
  2944. }
  2945. if (this.verticalPageBreaks == null && verticalCount > 0)
  2946. {
  2947. this.verticalPageBreaks = [];
  2948. }
  2949. var drawPageBreaks = mxUtils.bind(this, function(breaks)
  2950. {
  2951. if (breaks != null)
  2952. {
  2953. var count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount;
  2954. for (var i = 0; i <= count; i++)
  2955. {
  2956. var pts = (breaks == this.horizontalPageBreaks) ?
  2957. [new mxPoint(Math.round(bounds.x), Math.round(bounds.y + i * bounds.height)),
  2958. new mxPoint(Math.round(bounds.x + right), Math.round(bounds.y + i * bounds.height))] :
  2959. [new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y)),
  2960. new mxPoint(Math.round(bounds.x + i * bounds.width), Math.round(bounds.y + bottom))];
  2961. if (breaks[i] != null)
  2962. {
  2963. breaks[i].points = pts;
  2964. breaks[i].redraw();
  2965. }
  2966. else
  2967. {
  2968. var pageBreak = new mxPolyline(pts, this.pageBreakColor);
  2969. pageBreak.dialect = this.dialect;
  2970. pageBreak.pointerEvents = false;
  2971. pageBreak.isDashed = this.pageBreakDashed;
  2972. pageBreak.init(this.view.backgroundPane);
  2973. pageBreak.redraw();
  2974. breaks[i] = pageBreak;
  2975. }
  2976. }
  2977. for (var i = count; i < breaks.length; i++)
  2978. {
  2979. breaks[i].destroy();
  2980. }
  2981. breaks.splice(count, breaks.length - count);
  2982. }
  2983. });
  2984. drawPageBreaks(this.horizontalPageBreaks);
  2985. drawPageBreaks(this.verticalPageBreaks);
  2986. };
  2987. /**
  2988. * Group: Cell styles
  2989. */
  2990. /**
  2991. * Function: getCurrentCellStyle
  2992. *
  2993. * Returns the style for the given cell from the cell state, if one exists,
  2994. * or using <getCellStyle>.
  2995. *
  2996. * Parameters:
  2997. *
  2998. * cell - <mxCell> whose style should be returned as an array.
  2999. * ignoreState - Optional boolean that specifies if the cell state should be ignored.
  3000. */
  3001. mxGraph.prototype.getCurrentCellStyle = function(cell, ignoreState)
  3002. {
  3003. var state = (ignoreState) ? null : this.view.getState(cell);
  3004. return (state != null) ? state.style : this.getCellStyle(cell);
  3005. };
  3006. /**
  3007. * Function: getCellStyle
  3008. *
  3009. * Returns an array of key, value pairs representing the cell style for the
  3010. * given cell. If no string is defined in the model that specifies the
  3011. * style, then the default style for the cell is returned or an empty object,
  3012. * if no style can be found. Note: You should try and get the cell state
  3013. * for the given cell and use the cached style in the state before using
  3014. * this method.
  3015. *
  3016. * Parameters:
  3017. *
  3018. * cell - <mxCell> whose style should be returned as an array.
  3019. */
  3020. mxGraph.prototype.getCellStyle = function(cell)
  3021. {
  3022. var stylename = this.model.getStyle(cell);
  3023. var style = null;
  3024. // Gets the default style for the cell
  3025. if (this.model.isEdge(cell))
  3026. {
  3027. style = this.stylesheet.getDefaultEdgeStyle();
  3028. }
  3029. else
  3030. {
  3031. style = this.stylesheet.getDefaultVertexStyle();
  3032. }
  3033. // Resolves the stylename using the above as the default
  3034. if (stylename != null)
  3035. {
  3036. style = this.postProcessCellStyle(this.stylesheet.getCellStyle(stylename, style));
  3037. }
  3038. // Returns a non-null value if no style can be found
  3039. if (style == null)
  3040. {
  3041. style = new Object();
  3042. }
  3043. return style;
  3044. };
  3045. /**
  3046. * Function: postProcessCellStyle
  3047. *
  3048. * Tries to resolve the value for the image style in the image bundles and
  3049. * turns short data URIs as defined in mxImageBundle to data URIs as
  3050. * defined in RFC 2397 of the IETF.
  3051. */
  3052. mxGraph.prototype.postProcessCellStyle = function(style)
  3053. {
  3054. if (style != null)
  3055. {
  3056. var key = style[mxConstants.STYLE_IMAGE];
  3057. var image = this.getImageFromBundles(key);
  3058. if (image != null)
  3059. {
  3060. style[mxConstants.STYLE_IMAGE] = image;
  3061. }
  3062. else
  3063. {
  3064. image = key;
  3065. }
  3066. // Converts short data uris to normal data uris
  3067. if (image != null && image.substring(0, 11) == 'data:image/')
  3068. {
  3069. if (image.substring(0, 20) == 'data:image/svg+xml,<')
  3070. {
  3071. // Required for FF and IE11
  3072. image = image.substring(0, 19) + encodeURIComponent(image.substring(19));
  3073. }
  3074. else if (image.substring(0, 22) != 'data:image/svg+xml,%3C')
  3075. {
  3076. var comma = image.indexOf(',');
  3077. // Adds base64 encoding prefix if needed
  3078. if (comma > 0 && image.substring(comma - 7, comma + 1) != ';base64,')
  3079. {
  3080. image = image.substring(0, comma) + ';base64,'
  3081. + image.substring(comma + 1);
  3082. }
  3083. }
  3084. style[mxConstants.STYLE_IMAGE] = image;
  3085. }
  3086. }
  3087. return style;
  3088. };
  3089. /**
  3090. * Function: setCellStyle
  3091. *
  3092. * Sets the style of the specified cells. If no cells are given, then the
  3093. * selection cells are changed.
  3094. *
  3095. * Parameters:
  3096. *
  3097. * style - String representing the new style of the cells.
  3098. * cells - Optional array of <mxCells> to set the style for. Default is the
  3099. * selection cells.
  3100. */
  3101. mxGraph.prototype.setCellStyle = function(style, cells)
  3102. {
  3103. cells = cells || this.getSelectionCells();
  3104. if (cells != null)
  3105. {
  3106. this.model.beginUpdate();
  3107. try
  3108. {
  3109. for (var i = 0; i < cells.length; i++)
  3110. {
  3111. this.model.setStyle(cells[i], style);
  3112. }
  3113. }
  3114. finally
  3115. {
  3116. this.model.endUpdate();
  3117. }
  3118. }
  3119. };
  3120. /**
  3121. * Function: toggleCellStyle
  3122. *
  3123. * Toggles the boolean value for the given key in the style of the given cell
  3124. * and returns the new value as 0 or 1. If no cell is specified then the
  3125. * selection cell is used.
  3126. *
  3127. * Parameter:
  3128. *
  3129. * key - String representing the key for the boolean value to be toggled.
  3130. * defaultValue - Optional boolean default value if no value is defined.
  3131. * Default is false.
  3132. * cell - Optional <mxCell> whose style should be modified. Default is
  3133. * the selection cell.
  3134. */
  3135. mxGraph.prototype.toggleCellStyle = function(key, defaultValue, cell)
  3136. {
  3137. cell = cell || this.getSelectionCell();
  3138. return this.toggleCellStyles(key, defaultValue, [cell]);
  3139. };
  3140. /**
  3141. * Function: toggleCellStyles
  3142. *
  3143. * Toggles the boolean value for the given key in the style of the given cells
  3144. * and returns the new value as 0 or 1. If no cells are specified, then the
  3145. * selection cells are used. For example, this can be used to toggle
  3146. * <mxConstants.STYLE_ROUNDED> or any other style with a boolean value.
  3147. *
  3148. * Parameter:
  3149. *
  3150. * key - String representing the key for the boolean value to be toggled.
  3151. * defaultValue - Optional boolean default value if no value is defined.
  3152. * Default is false.
  3153. * cells - Optional array of <mxCells> whose styles should be modified.
  3154. * Default is the selection cells.
  3155. */
  3156. mxGraph.prototype.toggleCellStyles = function(key, defaultValue, cells)
  3157. {
  3158. defaultValue = (defaultValue != null) ? defaultValue : false;
  3159. cells = cells || this.getSelectionCells();
  3160. var value = null;
  3161. if (cells != null && cells.length > 0)
  3162. {
  3163. var style = this.getCurrentCellStyle(cells[0]);
  3164. value = (mxUtils.getValue(style, key, defaultValue)) ? 0 : 1;
  3165. this.setCellStyles(key, value, cells);
  3166. }
  3167. return value;
  3168. };
  3169. /**
  3170. * Function: setCellStyles
  3171. *
  3172. * Sets the key to value in the styles of the given cells. This will modify
  3173. * the existing cell styles in-place and override any existing assignment
  3174. * for the given key. If no cells are specified, then the selection cells
  3175. * are changed. If no value is specified, then the respective key is
  3176. * removed from the styles.
  3177. *
  3178. * Parameters:
  3179. *
  3180. * key - String representing the key to be assigned.
  3181. * value - String representing the new value for the key.
  3182. * cells - Optional array of <mxCells> to change the style for. Default is
  3183. * the selection cells.
  3184. */
  3185. mxGraph.prototype.setCellStyles = function(key, value, cells)
  3186. {
  3187. cells = cells || this.getSelectionCells();
  3188. mxUtils.setCellStyles(this.model, cells, key, value);
  3189. };
  3190. /**
  3191. * Function: toggleCellStyleFlags
  3192. *
  3193. * Toggles the given bit for the given key in the styles of the specified
  3194. * cells.
  3195. *
  3196. * Parameters:
  3197. *
  3198. * key - String representing the key to toggle the flag in.
  3199. * flag - Integer that represents the bit to be toggled.
  3200. * cells - Optional array of <mxCells> to change the style for. Default is
  3201. * the selection cells.
  3202. */
  3203. mxGraph.prototype.toggleCellStyleFlags = function(key, flag, cells)
  3204. {
  3205. this.setCellStyleFlags(key, flag, null, cells);
  3206. };
  3207. /**
  3208. * Function: setCellStyleFlags
  3209. *
  3210. * Sets or toggles the given bit for the given key in the styles of the
  3211. * specified cells.
  3212. *
  3213. * Parameters:
  3214. *
  3215. * key - String representing the key to toggle the flag in.
  3216. * flag - Integer that represents the bit to be toggled.
  3217. * value - Boolean value to be used or null if the value should be toggled.
  3218. * cells - Optional array of <mxCells> to change the style for. Default is
  3219. * the selection cells.
  3220. */
  3221. mxGraph.prototype.setCellStyleFlags = function(key, flag, value, cells)
  3222. {
  3223. cells = cells || this.getSelectionCells();
  3224. if (cells != null && cells.length > 0)
  3225. {
  3226. if (value == null)
  3227. {
  3228. var style = this.getCurrentCellStyle(cells[0]);
  3229. var current = parseInt(style[key] || 0);
  3230. value = !((current & flag) == flag);
  3231. }
  3232. mxUtils.setCellStyleFlags(this.model, cells, key, flag, value);
  3233. }
  3234. };
  3235. /**
  3236. * Group: Cell alignment and orientation
  3237. */
  3238. /**
  3239. * Function: alignCells
  3240. *
  3241. * Aligns the given cells vertically or horizontally according to the given
  3242. * alignment using the optional parameter as the coordinate.
  3243. *
  3244. * Parameters:
  3245. *
  3246. * align - Specifies the alignment. Possible values are all constants in
  3247. * mxConstants with an ALIGN prefix.
  3248. * cells - Array of <mxCells> to be aligned.
  3249. * param - Optional coordinate for the alignment.
  3250. */
  3251. mxGraph.prototype.alignCells = function(align, cells, param)
  3252. {
  3253. if (cells == null)
  3254. {
  3255. cells = this.getSelectionCells();
  3256. }
  3257. if (cells != null && cells.length > 1)
  3258. {
  3259. // Finds the required coordinate for the alignment
  3260. if (param == null)
  3261. {
  3262. for (var i = 0; i < cells.length; i++)
  3263. {
  3264. var state = this.view.getState(cells[i]);
  3265. if (state != null && !this.model.isEdge(cells[i]))
  3266. {
  3267. if (param == null)
  3268. {
  3269. if (align == mxConstants.ALIGN_CENTER)
  3270. {
  3271. param = state.x + state.width / 2;
  3272. break;
  3273. }
  3274. else if (align == mxConstants.ALIGN_RIGHT)
  3275. {
  3276. param = state.x + state.width;
  3277. }
  3278. else if (align == mxConstants.ALIGN_TOP)
  3279. {
  3280. param = state.y;
  3281. }
  3282. else if (align == mxConstants.ALIGN_MIDDLE)
  3283. {
  3284. param = state.y + state.height / 2;
  3285. break;
  3286. }
  3287. else if (align == mxConstants.ALIGN_BOTTOM)
  3288. {
  3289. param = state.y + state.height;
  3290. }
  3291. else
  3292. {
  3293. param = state.x;
  3294. }
  3295. }
  3296. else
  3297. {
  3298. if (align == mxConstants.ALIGN_RIGHT)
  3299. {
  3300. param = Math.max(param, state.x + state.width);
  3301. }
  3302. else if (align == mxConstants.ALIGN_TOP)
  3303. {
  3304. param = Math.min(param, state.y);
  3305. }
  3306. else if (align == mxConstants.ALIGN_BOTTOM)
  3307. {
  3308. param = Math.max(param, state.y + state.height);
  3309. }
  3310. else
  3311. {
  3312. param = Math.min(param, state.x);
  3313. }
  3314. }
  3315. }
  3316. }
  3317. }
  3318. // Aligns the cells to the coordinate
  3319. if (param != null)
  3320. {
  3321. var s = this.view.scale;
  3322. this.model.beginUpdate();
  3323. try
  3324. {
  3325. for (var i = 0; i < cells.length; i++)
  3326. {
  3327. var state = this.view.getState(cells[i]);
  3328. if (state != null)
  3329. {
  3330. var geo = this.getCellGeometry(cells[i]);
  3331. if (geo != null && !this.model.isEdge(cells[i]))
  3332. {
  3333. geo = geo.clone();
  3334. if (align == mxConstants.ALIGN_CENTER)
  3335. {
  3336. geo.x += (param - state.x - state.width / 2) / s;
  3337. }
  3338. else if (align == mxConstants.ALIGN_RIGHT)
  3339. {
  3340. geo.x += (param - state.x - state.width) / s;
  3341. }
  3342. else if (align == mxConstants.ALIGN_TOP)
  3343. {
  3344. geo.y += (param - state.y) / s;
  3345. }
  3346. else if (align == mxConstants.ALIGN_MIDDLE)
  3347. {
  3348. geo.y += (param - state.y - state.height / 2) / s;
  3349. }
  3350. else if (align == mxConstants.ALIGN_BOTTOM)
  3351. {
  3352. geo.y += (param - state.y - state.height) / s;
  3353. }
  3354. else
  3355. {
  3356. geo.x += (param - state.x) / s;
  3357. }
  3358. this.resizeCell(cells[i], geo);
  3359. }
  3360. }
  3361. }
  3362. this.fireEvent(new mxEventObject(mxEvent.ALIGN_CELLS,
  3363. 'align', align, 'cells', cells));
  3364. }
  3365. finally
  3366. {
  3367. this.model.endUpdate();
  3368. }
  3369. }
  3370. }
  3371. return cells;
  3372. };
  3373. /**
  3374. * Function: flipEdge
  3375. *
  3376. * Toggles the style of the given edge between null (or empty) and
  3377. * <alternateEdgeStyle>. This method fires <mxEvent.FLIP_EDGE> while the
  3378. * transaction is in progress. Returns the edge that was flipped.
  3379. *
  3380. * Here is an example that overrides this implementation to invert the
  3381. * value of <mxConstants.STYLE_ELBOW> without removing any existing styles.
  3382. *
  3383. * (code)
  3384. * graph.flipEdge = function(edge)
  3385. * {
  3386. * if (edge != null)
  3387. * {
  3388. * var style = this.getCurrentCellStyle(edge);
  3389. * var elbow = mxUtils.getValue(style, mxConstants.STYLE_ELBOW,
  3390. * mxConstants.ELBOW_HORIZONTAL);
  3391. * var value = (elbow == mxConstants.ELBOW_HORIZONTAL) ?
  3392. * mxConstants.ELBOW_VERTICAL : mxConstants.ELBOW_HORIZONTAL;
  3393. * this.setCellStyles(mxConstants.STYLE_ELBOW, value, [edge]);
  3394. * }
  3395. * };
  3396. * (end)
  3397. *
  3398. * Parameters:
  3399. *
  3400. * edge - <mxCell> whose style should be changed.
  3401. */
  3402. mxGraph.prototype.flipEdge = function(edge)
  3403. {
  3404. if (edge != null &&
  3405. this.alternateEdgeStyle != null)
  3406. {
  3407. this.model.beginUpdate();
  3408. try
  3409. {
  3410. var style = this.model.getStyle(edge);
  3411. if (style == null || style.length == 0)
  3412. {
  3413. this.model.setStyle(edge, this.alternateEdgeStyle);
  3414. }
  3415. else
  3416. {
  3417. this.model.setStyle(edge, null);
  3418. }
  3419. // Removes all existing control points
  3420. this.resetEdge(edge);
  3421. this.fireEvent(new mxEventObject(mxEvent.FLIP_EDGE, 'edge', edge));
  3422. }
  3423. finally
  3424. {
  3425. this.model.endUpdate();
  3426. }
  3427. }
  3428. return edge;
  3429. };
  3430. /**
  3431. * Function: addImageBundle
  3432. *
  3433. * Adds the specified <mxImageBundle>.
  3434. */
  3435. mxGraph.prototype.addImageBundle = function(bundle)
  3436. {
  3437. this.imageBundles.push(bundle);
  3438. };
  3439. /**
  3440. * Function: removeImageBundle
  3441. *
  3442. * Removes the specified <mxImageBundle>.
  3443. */
  3444. mxGraph.prototype.removeImageBundle = function(bundle)
  3445. {
  3446. var tmp = [];
  3447. for (var i = 0; i < this.imageBundles.length; i++)
  3448. {
  3449. if (this.imageBundles[i] != bundle)
  3450. {
  3451. tmp.push(this.imageBundles[i]);
  3452. }
  3453. }
  3454. this.imageBundles = tmp;
  3455. };
  3456. /**
  3457. * Function: getImageFromBundles
  3458. *
  3459. * Searches all <imageBundles> for the specified key and returns the value
  3460. * for the first match or null if the key is not found.
  3461. */
  3462. mxGraph.prototype.getImageFromBundles = function(key)
  3463. {
  3464. if (key != null)
  3465. {
  3466. for (var i = 0; i < this.imageBundles.length; i++)
  3467. {
  3468. var image = this.imageBundles[i].getImage(key);
  3469. if (image != null)
  3470. {
  3471. return image;
  3472. }
  3473. }
  3474. }
  3475. return null;
  3476. };
  3477. /**
  3478. * Group: Order
  3479. */
  3480. /**
  3481. * Function: orderCells
  3482. *
  3483. * Moves the given cells to the front or back. The change is carried out
  3484. * using <cellsOrdered>. This method fires <mxEvent.ORDER_CELLS> while the
  3485. * transaction is in progress.
  3486. *
  3487. * Parameters:
  3488. *
  3489. * back - Boolean that specifies if the cells should be moved to back.
  3490. * cells - Array of <mxCells> to move to the background. If null is
  3491. * specified then the selection cells are used.
  3492. */
  3493. mxGraph.prototype.orderCells = function(back, cells)
  3494. {
  3495. if (cells == null)
  3496. {
  3497. cells = mxUtils.sortCells(this.getSelectionCells(), true);
  3498. }
  3499. this.model.beginUpdate();
  3500. try
  3501. {
  3502. this.cellsOrdered(cells, back);
  3503. this.fireEvent(new mxEventObject(mxEvent.ORDER_CELLS,
  3504. 'back', back, 'cells', cells));
  3505. }
  3506. finally
  3507. {
  3508. this.model.endUpdate();
  3509. }
  3510. return cells;
  3511. };
  3512. /**
  3513. * Function: cellsOrdered
  3514. *
  3515. * Moves the given cells to the front or back. This method fires
  3516. * <mxEvent.CELLS_ORDERED> while the transaction is in progress.
  3517. *
  3518. * Parameters:
  3519. *
  3520. * cells - Array of <mxCells> whose order should be changed.
  3521. * back - Boolean that specifies if the cells should be moved to back.
  3522. */
  3523. mxGraph.prototype.cellsOrdered = function(cells, back)
  3524. {
  3525. if (cells != null)
  3526. {
  3527. this.model.beginUpdate();
  3528. try
  3529. {
  3530. for (var i = 0; i < cells.length; i++)
  3531. {
  3532. var parent = this.model.getParent(cells[i]);
  3533. if (back)
  3534. {
  3535. this.model.add(parent, cells[i], i);
  3536. }
  3537. else
  3538. {
  3539. this.model.add(parent, cells[i],
  3540. this.model.getChildCount(parent) - 1);
  3541. }
  3542. }
  3543. this.fireEvent(new mxEventObject(mxEvent.CELLS_ORDERED,
  3544. 'back', back, 'cells', cells));
  3545. }
  3546. finally
  3547. {
  3548. this.model.endUpdate();
  3549. }
  3550. }
  3551. };
  3552. /**
  3553. * Group: Grouping
  3554. */
  3555. /**
  3556. * Function: groupCells
  3557. *
  3558. * Adds the cells into the given group. The change is carried out using
  3559. * <cellsAdded>, <cellsMoved> and <cellsResized>. This method fires
  3560. * <mxEvent.GROUP_CELLS> while the transaction is in progress. Returns the
  3561. * new group. A group is only created if there is at least one entry in the
  3562. * given array of cells.
  3563. *
  3564. * Parameters:
  3565. *
  3566. * group - <mxCell> that represents the target group. If null is specified
  3567. * then a new group is created using <createGroupCell>.
  3568. * border - Optional integer that specifies the border between the child
  3569. * area and the group bounds. Default is 0.
  3570. * cells - Optional array of <mxCells> to be grouped. If null is specified
  3571. * then the selection cells are used.
  3572. */
  3573. mxGraph.prototype.groupCells = function(group, border, cells)
  3574. {
  3575. if (cells == null)
  3576. {
  3577. cells = mxUtils.sortCells(this.getSelectionCells(), true);
  3578. }
  3579. cells = this.getCellsForGroup(cells);
  3580. if (group == null)
  3581. {
  3582. group = this.createGroupCell(cells);
  3583. }
  3584. var bounds = this.getBoundsForGroup(group, cells, border);
  3585. if (cells.length > 1 && bounds != null)
  3586. {
  3587. // Uses parent of group or previous parent of first child
  3588. var parent = this.model.getParent(group);
  3589. if (parent == null)
  3590. {
  3591. parent = this.model.getParent(cells[0]);
  3592. }
  3593. this.model.beginUpdate();
  3594. try
  3595. {
  3596. // Checks if the group has a geometry and
  3597. // creates one if one does not exist
  3598. if (this.getCellGeometry(group) == null)
  3599. {
  3600. this.model.setGeometry(group, new mxGeometry());
  3601. }
  3602. // Adds the group into the parent
  3603. var index = this.model.getChildCount(parent);
  3604. this.cellsAdded([group], parent, index, null, null, false, false, false);
  3605. // Adds the children into the group and moves
  3606. index = this.model.getChildCount(group);
  3607. this.cellsAdded(cells, group, index, null, null, false, false, false);
  3608. this.cellsMoved(cells, -bounds.x, -bounds.y, false, false, false);
  3609. // Resizes the group
  3610. this.cellsResized([group], [bounds], false);
  3611. this.fireEvent(new mxEventObject(mxEvent.GROUP_CELLS,
  3612. 'group', group, 'border', border, 'cells', cells));
  3613. }
  3614. finally
  3615. {
  3616. this.model.endUpdate();
  3617. }
  3618. }
  3619. return group;
  3620. };
  3621. /**
  3622. * Function: getCellsForGroup
  3623. *
  3624. * Returns the cells with the same parent as the first cell
  3625. * in the given array.
  3626. */
  3627. mxGraph.prototype.getCellsForGroup = function(cells)
  3628. {
  3629. var result = [];
  3630. if (cells != null && cells.length > 0)
  3631. {
  3632. var parent = this.model.getParent(cells[0]);
  3633. result.push(cells[0]);
  3634. // Filters selection cells with the same parent
  3635. for (var i = 1; i < cells.length; i++)
  3636. {
  3637. if (this.model.getParent(cells[i]) == parent)
  3638. {
  3639. result.push(cells[i]);
  3640. }
  3641. }
  3642. }
  3643. return result;
  3644. };
  3645. /**
  3646. * Function: getBoundsForGroup
  3647. *
  3648. * Returns the bounds to be used for the given group and children.
  3649. */
  3650. mxGraph.prototype.getBoundsForGroup = function(group, children, border)
  3651. {
  3652. var result = this.getBoundingBoxFromGeometry(children, true);
  3653. if (result != null)
  3654. {
  3655. if (this.isSwimlane(group))
  3656. {
  3657. var size = this.getStartSize(group);
  3658. result.x -= size.width;
  3659. result.y -= size.height;
  3660. result.width += size.width;
  3661. result.height += size.height;
  3662. }
  3663. // Adds the border
  3664. if (border != null)
  3665. {
  3666. result.x -= border;
  3667. result.y -= border;
  3668. result.width += 2 * border;
  3669. result.height += 2 * border;
  3670. }
  3671. }
  3672. return result;
  3673. };
  3674. /**
  3675. * Function: createGroupCell
  3676. *
  3677. * Hook for creating the group cell to hold the given array of <mxCells> if
  3678. * no group cell was given to the <group> function.
  3679. *
  3680. * The following code can be used to set the style of new group cells.
  3681. *
  3682. * (code)
  3683. * var graphCreateGroupCell = graph.createGroupCell;
  3684. * graph.createGroupCell = function(cells)
  3685. * {
  3686. * var group = graphCreateGroupCell.apply(this, arguments);
  3687. * group.setStyle('group');
  3688. *
  3689. * return group;
  3690. * };
  3691. */
  3692. mxGraph.prototype.createGroupCell = function(cells)
  3693. {
  3694. var group = new mxCell('');
  3695. group.setVertex(true);
  3696. group.setConnectable(false);
  3697. return group;
  3698. };
  3699. /**
  3700. * Function: ungroupCells
  3701. *
  3702. * Ungroups the given cells by moving the children the children to their
  3703. * parents parent and removing the empty groups. Returns the children that
  3704. * have been removed from the groups.
  3705. *
  3706. * Parameters:
  3707. *
  3708. * cells - Array of cells to be ungrouped. If null is specified then the
  3709. * selection cells are used.
  3710. */
  3711. mxGraph.prototype.ungroupCells = function(cells)
  3712. {
  3713. var result = [];
  3714. if (cells == null)
  3715. {
  3716. cells = this.getCellsForUngroup();
  3717. }
  3718. if (cells != null && cells.length > 0)
  3719. {
  3720. this.model.beginUpdate();
  3721. try
  3722. {
  3723. for (var i = 0; i < cells.length; i++)
  3724. {
  3725. var children = this.model.getChildren(cells[i]);
  3726. if (children != null && children.length > 0)
  3727. {
  3728. children = children.slice();
  3729. var parent = this.model.getParent(cells[i]);
  3730. var index = this.model.getChildCount(parent);
  3731. this.cellsAdded(children, parent, index, null, null, true);
  3732. result = result.concat(children);
  3733. // Fix relative child cells
  3734. for (var j = 0; j < children.length; j++)
  3735. {
  3736. var state = this.view.getState(children[j]);
  3737. var geo = this.getCellGeometry(children[j]);
  3738. if (state != null && geo != null && geo.relative)
  3739. {
  3740. geo = geo.clone();
  3741. geo.x = state.origin.x;
  3742. geo.y = state.origin.y;
  3743. geo.relative = false;
  3744. this.model.setGeometry(children[j], geo);
  3745. }
  3746. }
  3747. }
  3748. }
  3749. this.removeCellsAfterUngroup(cells);
  3750. this.fireEvent(new mxEventObject(mxEvent.UNGROUP_CELLS, 'cells', cells));
  3751. }
  3752. finally
  3753. {
  3754. this.model.endUpdate();
  3755. }
  3756. }
  3757. return result;
  3758. };
  3759. /**
  3760. * Function: getCellsForUngroup
  3761. *
  3762. * Returns the selection cells that can be ungrouped.
  3763. */
  3764. mxGraph.prototype.getCellsForUngroup = function()
  3765. {
  3766. var cells = this.getSelectionCells();
  3767. // Finds the cells with children
  3768. var tmp = [];
  3769. for (var i = 0; i < cells.length; i++)
  3770. {
  3771. if (this.model.isVertex(cells[i]) &&
  3772. this.model.getChildCount(cells[i]) > 0)
  3773. {
  3774. tmp.push(cells[i]);
  3775. }
  3776. }
  3777. return tmp;
  3778. };
  3779. /**
  3780. * Function: removeCellsAfterUngroup
  3781. *
  3782. * Hook to remove the groups after <ungroupCells>.
  3783. *
  3784. * Parameters:
  3785. *
  3786. * cells - Array of <mxCells> that were ungrouped.
  3787. */
  3788. mxGraph.prototype.removeCellsAfterUngroup = function(cells)
  3789. {
  3790. this.cellsRemoved(this.addAllEdges(cells));
  3791. };
  3792. /**
  3793. * Function: removeCellsFromParent
  3794. *
  3795. * Removes the specified cells from their parents and adds them to the
  3796. * default parent. Returns the cells that were removed from their parents.
  3797. *
  3798. * Parameters:
  3799. *
  3800. * cells - Array of <mxCells> to be removed from their parents.
  3801. */
  3802. mxGraph.prototype.removeCellsFromParent = function(cells)
  3803. {
  3804. if (cells == null)
  3805. {
  3806. cells = this.getSelectionCells();
  3807. }
  3808. this.model.beginUpdate();
  3809. try
  3810. {
  3811. var parent = this.getDefaultParent();
  3812. var index = this.model.getChildCount(parent);
  3813. this.cellsAdded(cells, parent, index, null, null, true);
  3814. this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS_FROM_PARENT, 'cells', cells));
  3815. }
  3816. finally
  3817. {
  3818. this.model.endUpdate();
  3819. }
  3820. return cells;
  3821. };
  3822. /**
  3823. * Function: updateGroupBounds
  3824. *
  3825. * Updates the bounds of the given groups to include all children and returns
  3826. * the passed-in cells. Call this with the groups in parent to child order,
  3827. * top-most group first, the cells are processed in reverse order and cells
  3828. * with no children are ignored.
  3829. *
  3830. * Parameters:
  3831. *
  3832. * cells - The groups whose bounds should be updated. If this is null, then
  3833. * the selection cells are used.
  3834. * border - Optional border to be added in the group. Default is 0.
  3835. * moveGroup - Optional boolean that allows the group to be moved. Default
  3836. * is false.
  3837. * topBorder - Optional top border to be added in the group. Default is 0.
  3838. * rightBorder - Optional top border to be added in the group. Default is 0.
  3839. * bottomBorder - Optional top border to be added in the group. Default is 0.
  3840. * leftBorder - Optional top border to be added in the group. Default is 0.
  3841. */
  3842. mxGraph.prototype.updateGroupBounds = function(cells, border, moveGroup, topBorder, rightBorder, bottomBorder, leftBorder)
  3843. {
  3844. if (cells == null)
  3845. {
  3846. cells = this.getSelectionCells();
  3847. }
  3848. border = (border != null) ? border : 0;
  3849. moveGroup = (moveGroup != null) ? moveGroup : false;
  3850. topBorder = (topBorder != null) ? topBorder : 0;
  3851. rightBorder = (rightBorder != null) ? rightBorder : 0;
  3852. bottomBorder = (bottomBorder != null) ? bottomBorder : 0;
  3853. leftBorder = (leftBorder != null) ? leftBorder : 0;
  3854. this.model.beginUpdate();
  3855. try
  3856. {
  3857. for (var i = cells.length - 1; i >= 0; i--)
  3858. {
  3859. var geo = this.getCellGeometry(cells[i]);
  3860. if (geo != null)
  3861. {
  3862. var children = this.getChildCells(cells[i]);
  3863. if (children != null && children.length > 0)
  3864. {
  3865. var bounds = this.getBoundingBoxFromGeometry(children, true);
  3866. if (bounds != null && bounds.width > 0 && bounds.height > 0)
  3867. {
  3868. // Adds the size of the title area for swimlanes
  3869. var size = (this.isSwimlane(cells[i])) ?
  3870. this.getActualStartSize(cells[i], true) : new mxRectangle();
  3871. geo = geo.clone();
  3872. if (moveGroup)
  3873. {
  3874. geo.x = Math.round(geo.x + bounds.x - border - size.x - leftBorder);
  3875. geo.y = Math.round(geo.y + bounds.y - border - size.y - topBorder);
  3876. }
  3877. geo.width = Math.round(bounds.width + 2 * border + size.x + leftBorder + rightBorder + size.width);
  3878. geo.height = Math.round(bounds.height + 2 * border + size.y + topBorder + bottomBorder + size.height);
  3879. this.model.setGeometry(cells[i], geo);
  3880. this.moveCells(children, border + size.x - bounds.x + leftBorder,
  3881. border + size.y - bounds.y + topBorder);
  3882. }
  3883. }
  3884. }
  3885. }
  3886. }
  3887. finally
  3888. {
  3889. this.model.endUpdate();
  3890. }
  3891. return cells;
  3892. };
  3893. /**
  3894. * Function: getBoundingBox
  3895. *
  3896. * Returns the bounding box for the given array of <mxCells>. The bounding box for
  3897. * each cell and its descendants is computed using <mxGraphView.getBoundingBox>.
  3898. *
  3899. * Parameters:
  3900. *
  3901. * cells - Array of <mxCells> whose bounding box should be returned.
  3902. */
  3903. mxGraph.prototype.getBoundingBox = function(cells)
  3904. {
  3905. var result = null;
  3906. if (cells != null && cells.length > 0)
  3907. {
  3908. for (var i = 0; i < cells.length; i++)
  3909. {
  3910. if (this.model.isVertex(cells[i]) || this.model.isEdge(cells[i]))
  3911. {
  3912. var bbox = this.view.getBoundingBox(this.view.getState(cells[i]), true);
  3913. if (bbox != null)
  3914. {
  3915. if (result == null)
  3916. {
  3917. result = mxRectangle.fromRectangle(bbox);
  3918. }
  3919. else
  3920. {
  3921. result.add(bbox);
  3922. }
  3923. }
  3924. }
  3925. }
  3926. }
  3927. return result;
  3928. };
  3929. /**
  3930. * Group: Cell cloning, insertion and removal
  3931. */
  3932. /**
  3933. * Function: cloneCell
  3934. *
  3935. * Returns the clone for the given cell. Uses <cloneCells>.
  3936. *
  3937. * Parameters:
  3938. *
  3939. * cell - <mxCell> to be cloned.
  3940. * allowInvalidEdges - Optional boolean that specifies if invalid edges
  3941. * should be cloned. Default is true.
  3942. * mapping - Optional mapping for existing clones.
  3943. * keepPosition - Optional boolean indicating if the position of the cells should
  3944. * be updated to reflect the lost parent cell. Default is false.
  3945. */
  3946. mxGraph.prototype.cloneCell = function(cell, allowInvalidEdges, mapping, keepPosition)
  3947. {
  3948. return this.cloneCells([cell], allowInvalidEdges, mapping, keepPosition)[0];
  3949. };
  3950. /**
  3951. * Function: cloneCells
  3952. *
  3953. * Returns the clones for the given cells. The clones are created recursively
  3954. * using <mxGraphModel.cloneCells>. If the terminal of an edge is not in the
  3955. * given array, then the respective end is assigned a terminal point and the
  3956. * terminal is removed.
  3957. *
  3958. * Parameters:
  3959. *
  3960. * cells - Array of <mxCells> to be cloned.
  3961. * allowInvalidEdges - Optional boolean that specifies if invalid edges
  3962. * should be cloned. Default is true.
  3963. * mapping - Optional mapping for existing clones.
  3964. * keepPosition - Optional boolean indicating if the position of the cells should
  3965. * be updated to reflect the lost parent cell. Default is false.
  3966. */
  3967. mxGraph.prototype.cloneCells = function(cells, allowInvalidEdges, mapping, keepPosition)
  3968. {
  3969. allowInvalidEdges = (allowInvalidEdges != null) ? allowInvalidEdges : true;
  3970. var clones = null;
  3971. if (cells != null)
  3972. {
  3973. // Creates a dictionary for fast lookups
  3974. var dict = new mxDictionary();
  3975. var tmp = [];
  3976. for (var i = 0; i < cells.length; i++)
  3977. {
  3978. dict.put(cells[i], true);
  3979. tmp.push(cells[i]);
  3980. }
  3981. if (tmp.length > 0)
  3982. {
  3983. var scale = this.view.scale;
  3984. var trans = this.view.translate;
  3985. clones = this.model.cloneCells(cells, true, mapping);
  3986. for (var i = 0; i < cells.length; i++)
  3987. {
  3988. if (!allowInvalidEdges && this.model.isEdge(clones[i]) &&
  3989. this.getEdgeValidationError(clones[i],
  3990. this.model.getTerminal(clones[i], true),
  3991. this.model.getTerminal(clones[i], false)) != null)
  3992. {
  3993. clones[i] = null;
  3994. }
  3995. else
  3996. {
  3997. var g = this.model.getGeometry(clones[i]);
  3998. if (g != null)
  3999. {
  4000. var state = this.view.getState(cells[i]);
  4001. var pstate = this.view.getState(this.model.getParent(cells[i]));
  4002. if (state != null && pstate != null)
  4003. {
  4004. var dx = (keepPosition) ? 0 : pstate.origin.x;
  4005. var dy = (keepPosition) ? 0 : pstate.origin.y;
  4006. if (this.model.isEdge(clones[i]))
  4007. {
  4008. var pts = state.absolutePoints;
  4009. if (pts != null)
  4010. {
  4011. // Checks if the source is cloned or sets the terminal point
  4012. var src = this.model.getTerminal(cells[i], true);
  4013. while (src != null && !dict.get(src))
  4014. {
  4015. src = this.model.getParent(src);
  4016. }
  4017. if (src == null && pts[0] != null)
  4018. {
  4019. g.setTerminalPoint(
  4020. new mxPoint(pts[0].x / scale - trans.x,
  4021. pts[0].y / scale - trans.y), true);
  4022. }
  4023. // Checks if the target is cloned or sets the terminal point
  4024. var trg = this.model.getTerminal(cells[i], false);
  4025. while (trg != null && !dict.get(trg))
  4026. {
  4027. trg = this.model.getParent(trg);
  4028. }
  4029. var n = pts.length - 1;
  4030. if (trg == null && pts[n] != null)
  4031. {
  4032. g.setTerminalPoint(
  4033. new mxPoint(pts[n].x / scale - trans.x,
  4034. pts[n].y / scale - trans.y), false);
  4035. }
  4036. // Translates the control points
  4037. var points = g.points;
  4038. if (points != null)
  4039. {
  4040. for (var j = 0; j < points.length; j++)
  4041. {
  4042. points[j].x += dx;
  4043. points[j].y += dy;
  4044. }
  4045. }
  4046. }
  4047. }
  4048. else
  4049. {
  4050. g.translate(dx, dy);
  4051. }
  4052. }
  4053. }
  4054. }
  4055. }
  4056. }
  4057. else
  4058. {
  4059. clones = [];
  4060. }
  4061. }
  4062. return clones;
  4063. };
  4064. /**
  4065. * Function: insertVertex
  4066. *
  4067. * Adds a new vertex into the given parent <mxCell> using value as the user
  4068. * object and the given coordinates as the <mxGeometry> of the new vertex.
  4069. * The id and style are used for the respective properties of the new
  4070. * <mxCell>, which is returned.
  4071. *
  4072. * When adding new vertices from a mouse event, one should take into
  4073. * account the offset of the graph container and the scale and translation
  4074. * of the view in order to find the correct unscaled, untranslated
  4075. * coordinates using <mxGraph.getPointForEvent> as follows:
  4076. *
  4077. * (code)
  4078. * var pt = graph.getPointForEvent(evt);
  4079. * var parent = graph.getDefaultParent();
  4080. * graph.insertVertex(parent, null,
  4081. * 'Hello, World!', x, y, 220, 30);
  4082. * (end)
  4083. *
  4084. * For adding image cells, the style parameter can be assigned as
  4085. *
  4086. * (code)
  4087. * stylename;image=imageUrl
  4088. * (end)
  4089. *
  4090. * See <mxGraph> for more information on using images.
  4091. *
  4092. * Parameters:
  4093. *
  4094. * parent - <mxCell> that specifies the parent of the new vertex.
  4095. * id - Optional string that defines the Id of the new vertex.
  4096. * value - Object to be used as the user object.
  4097. * x - Integer that defines the x coordinate of the vertex.
  4098. * y - Integer that defines the y coordinate of the vertex.
  4099. * width - Integer that defines the width of the vertex.
  4100. * height - Integer that defines the height of the vertex.
  4101. * style - Optional string that defines the cell style.
  4102. * relative - Optional boolean that specifies if the geometry is relative.
  4103. * Default is false.
  4104. */
  4105. mxGraph.prototype.insertVertex = function(parent, id, value,
  4106. x, y, width, height, style, relative)
  4107. {
  4108. var vertex = this.createVertex(parent, id, value, x, y, width, height, style, relative);
  4109. return this.addCell(vertex, parent);
  4110. };
  4111. /**
  4112. * Function: createVertex
  4113. *
  4114. * Hook method that creates the new vertex for <insertVertex>.
  4115. */
  4116. mxGraph.prototype.createVertex = function(parent, id, value,
  4117. x, y, width, height, style, relative)
  4118. {
  4119. // Creates the geometry for the vertex
  4120. var geometry = new mxGeometry(x, y, width, height);
  4121. geometry.relative = (relative != null) ? relative : false;
  4122. // Creates the vertex
  4123. var vertex = new mxCell(value, geometry, style);
  4124. vertex.setId(id);
  4125. vertex.setVertex(true);
  4126. vertex.setConnectable(true);
  4127. return vertex;
  4128. };
  4129. /**
  4130. * Function: insertEdge
  4131. *
  4132. * Adds a new edge into the given parent <mxCell> using value as the user
  4133. * object and the given source and target as the terminals of the new edge.
  4134. * The id and style are used for the respective properties of the new
  4135. * <mxCell>, which is returned.
  4136. *
  4137. * Parameters:
  4138. *
  4139. * parent - <mxCell> that specifies the parent of the new edge.
  4140. * id - Optional string that defines the Id of the new edge.
  4141. * value - JavaScript object to be used as the user object.
  4142. * source - <mxCell> that defines the source of the edge.
  4143. * target - <mxCell> that defines the target of the edge.
  4144. * style - Optional string that defines the cell style.
  4145. */
  4146. mxGraph.prototype.insertEdge = function(parent, id, value, source, target, style)
  4147. {
  4148. var edge = this.createEdge(parent, id, value, source, target, style);
  4149. return this.addEdge(edge, parent, source, target);
  4150. };
  4151. /**
  4152. * Function: createEdge
  4153. *
  4154. * Hook method that creates the new edge for <insertEdge>. This
  4155. * implementation does not set the source and target of the edge, these
  4156. * are set when the edge is added to the model.
  4157. *
  4158. */
  4159. mxGraph.prototype.createEdge = function(parent, id, value, source, target, style)
  4160. {
  4161. // Creates the edge
  4162. var edge = new mxCell(value, new mxGeometry(), style);
  4163. edge.setId(id);
  4164. edge.setEdge(true);
  4165. edge.geometry.relative = true;
  4166. return edge;
  4167. };
  4168. /**
  4169. * Function: addEdge
  4170. *
  4171. * Adds the edge to the parent and connects it to the given source and
  4172. * target terminals. This is a shortcut method. Returns the edge that was
  4173. * added.
  4174. *
  4175. * Parameters:
  4176. *
  4177. * edge - <mxCell> to be inserted into the given parent.
  4178. * parent - <mxCell> that represents the new parent. If no parent is
  4179. * given then the default parent is used.
  4180. * source - Optional <mxCell> that represents the source terminal.
  4181. * target - Optional <mxCell> that represents the target terminal.
  4182. * index - Optional index to insert the cells at. Default is to append.
  4183. */
  4184. mxGraph.prototype.addEdge = function(edge, parent, source, target, index)
  4185. {
  4186. return this.addCell(edge, parent, index, source, target);
  4187. };
  4188. /**
  4189. * Function: addCell
  4190. *
  4191. * Adds the cell to the parent and connects it to the given source and
  4192. * target terminals. This is a shortcut method. Returns the cell that was
  4193. * added.
  4194. *
  4195. * Parameters:
  4196. *
  4197. * cell - <mxCell> to be inserted into the given parent.
  4198. * parent - <mxCell> that represents the new parent. If no parent is
  4199. * given then the default parent is used.
  4200. * index - Optional index to insert the cells at. Default is to append.
  4201. * source - Optional <mxCell> that represents the source terminal.
  4202. * target - Optional <mxCell> that represents the target terminal.
  4203. */
  4204. mxGraph.prototype.addCell = function(cell, parent, index, source, target)
  4205. {
  4206. return this.addCells([cell], parent, index, source, target)[0];
  4207. };
  4208. /**
  4209. * Function: addCells
  4210. *
  4211. * Adds the cells to the parent at the given index, connecting each cell to
  4212. * the optional source and target terminal. The change is carried out using
  4213. * <cellsAdded>. This method fires <mxEvent.ADD_CELLS> while the
  4214. * transaction is in progress. Returns the cells that were added.
  4215. *
  4216. * Parameters:
  4217. *
  4218. * cells - Array of <mxCells> to be inserted.
  4219. * parent - <mxCell> that represents the new parent. If no parent is
  4220. * given then the default parent is used.
  4221. * index - Optional index to insert the cells at. Default is to append.
  4222. * source - Optional source <mxCell> for all inserted cells.
  4223. * target - Optional target <mxCell> for all inserted cells.
  4224. * absolute - Optional boolean indicating of cells should be kept at
  4225. * their absolute position. Default is false.
  4226. */
  4227. mxGraph.prototype.addCells = function(cells, parent, index, source, target, absolute)
  4228. {
  4229. if (parent == null)
  4230. {
  4231. parent = this.getDefaultParent();
  4232. }
  4233. if (index == null)
  4234. {
  4235. index = this.model.getChildCount(parent);
  4236. }
  4237. this.model.beginUpdate();
  4238. try
  4239. {
  4240. this.cellsAdded(cells, parent, index, source, target, (absolute != null) ? absolute : false, true);
  4241. this.fireEvent(new mxEventObject(mxEvent.ADD_CELLS, 'cells', cells,
  4242. 'parent', parent, 'index', index, 'source', source, 'target', target));
  4243. }
  4244. finally
  4245. {
  4246. this.model.endUpdate();
  4247. }
  4248. return cells;
  4249. };
  4250. /**
  4251. * Function: cellsAdded
  4252. *
  4253. * Adds the specified cells to the given parent. This method fires
  4254. * <mxEvent.CELLS_ADDED> while the transaction is in progress.
  4255. */
  4256. mxGraph.prototype.cellsAdded = function(cells, parent, index, source, target, absolute, constrain, extend)
  4257. {
  4258. if (cells != null && parent != null && index != null)
  4259. {
  4260. this.model.beginUpdate();
  4261. try
  4262. {
  4263. var parentState = (absolute) ? this.view.getState(parent) : null;
  4264. var o1 = (parentState != null) ? parentState.origin : null;
  4265. var zero = new mxPoint(0, 0);
  4266. for (var i = 0; i < cells.length; i++)
  4267. {
  4268. if (cells[i] == null)
  4269. {
  4270. index--;
  4271. }
  4272. else
  4273. {
  4274. var previous = this.model.getParent(cells[i]);
  4275. // Keeps the cell at its absolute location
  4276. if (o1 != null && cells[i] != parent && parent != previous)
  4277. {
  4278. var oldState = this.view.getState(previous);
  4279. var o2 = (oldState != null) ? oldState.origin : zero;
  4280. var geo = this.model.getGeometry(cells[i]);
  4281. if (geo != null)
  4282. {
  4283. var dx = o2.x - o1.x;
  4284. var dy = o2.y - o1.y;
  4285. // FIXME: Cells should always be inserted first before any other edit
  4286. // to avoid forward references in sessions.
  4287. geo = geo.clone();
  4288. geo.translate(dx, dy);
  4289. if (!geo.relative && this.model.isVertex(cells[i]) &&
  4290. !this.isAllowNegativeCoordinates())
  4291. {
  4292. geo.x = Math.max(0, geo.x);
  4293. geo.y = Math.max(0, geo.y);
  4294. }
  4295. this.model.setGeometry(cells[i], geo);
  4296. }
  4297. }
  4298. // Decrements all following indices
  4299. // if cell is already in parent
  4300. if (parent == previous && index + i > this.model.getChildCount(parent))
  4301. {
  4302. index--;
  4303. }
  4304. this.model.add(parent, cells[i], index + i);
  4305. if (this.autoSizeCellsOnAdd)
  4306. {
  4307. this.autoSizeCell(cells[i], true);
  4308. }
  4309. // Extends the parent or constrains the child
  4310. if ((extend == null || extend) &&
  4311. this.isExtendParentsOnAdd(cells[i]) && this.isExtendParent(cells[i]))
  4312. {
  4313. this.extendParent(cells[i]);
  4314. }
  4315. // Additionally constrains the child after extending the parent
  4316. if (constrain == null || constrain)
  4317. {
  4318. this.constrainChild(cells[i]);
  4319. }
  4320. // Sets the source terminal
  4321. if (source != null)
  4322. {
  4323. this.cellConnected(cells[i], source, true);
  4324. }
  4325. // Sets the target terminal
  4326. if (target != null)
  4327. {
  4328. this.cellConnected(cells[i], target, false);
  4329. }
  4330. }
  4331. }
  4332. this.fireEvent(new mxEventObject(mxEvent.CELLS_ADDED, 'cells', cells,
  4333. 'parent', parent, 'index', index, 'source', source, 'target', target,
  4334. 'absolute', absolute));
  4335. }
  4336. finally
  4337. {
  4338. this.model.endUpdate();
  4339. }
  4340. }
  4341. };
  4342. /**
  4343. * Function: autoSizeCell
  4344. *
  4345. * Resizes the specified cell to just fit around the its label and/or children
  4346. *
  4347. * Parameters:
  4348. *
  4349. * cell - <mxCells> to be resized.
  4350. * recurse - Optional boolean which specifies if all descendants should be
  4351. * autosized. Default is true.
  4352. */
  4353. mxGraph.prototype.autoSizeCell = function(cell, recurse)
  4354. {
  4355. recurse = (recurse != null) ? recurse : true;
  4356. if (recurse)
  4357. {
  4358. var childCount = this.model.getChildCount(cell);
  4359. for (var i = 0; i < childCount; i++)
  4360. {
  4361. this.autoSizeCell(this.model.getChildAt(cell, i));
  4362. }
  4363. }
  4364. if (this.getModel().isVertex(cell) && this.isAutoSizeCell(cell))
  4365. {
  4366. this.updateCellSize(cell);
  4367. }
  4368. };
  4369. /**
  4370. * Function: removeCells
  4371. *
  4372. * Removes the given cells from the graph including all connected edges if
  4373. * includeEdges is true. The change is carried out using <cellsRemoved>.
  4374. * This method fires <mxEvent.REMOVE_CELLS> while the transaction is in
  4375. * progress. The removed cells are returned as an array.
  4376. *
  4377. * Parameters:
  4378. *
  4379. * cells - Array of <mxCells> to remove. If null is specified then the
  4380. * selection cells which are deletable are used.
  4381. * includeEdges - Optional boolean which specifies if all connected edges
  4382. * should be removed as well. Default is true.
  4383. */
  4384. mxGraph.prototype.removeCells = function(cells, includeEdges)
  4385. {
  4386. includeEdges = (includeEdges != null) ? includeEdges : true;
  4387. if (cells == null)
  4388. {
  4389. cells = this.getDeletableCells(this.getSelectionCells());
  4390. }
  4391. // Adds all edges to the cells
  4392. if (includeEdges)
  4393. {
  4394. // FIXME: Remove duplicate cells in result or do not add if
  4395. // in cells or descendant of cells
  4396. cells = this.getDeletableCells(this.addAllEdges(cells));
  4397. }
  4398. else
  4399. {
  4400. cells = cells.slice();
  4401. // Removes edges that are currently not
  4402. // visible as those cannot be updated
  4403. var edges = this.getDeletableCells(this.getAllEdges(cells));
  4404. var dict = new mxDictionary();
  4405. for (var i = 0; i < cells.length; i++)
  4406. {
  4407. dict.put(cells[i], true);
  4408. }
  4409. for (var i = 0; i < edges.length; i++)
  4410. {
  4411. if (this.view.getState(edges[i]) == null &&
  4412. !dict.get(edges[i]))
  4413. {
  4414. dict.put(edges[i], true);
  4415. cells.push(edges[i]);
  4416. }
  4417. }
  4418. }
  4419. this.model.beginUpdate();
  4420. try
  4421. {
  4422. this.cellsRemoved(cells);
  4423. this.fireEvent(new mxEventObject(mxEvent.REMOVE_CELLS,
  4424. 'cells', cells, 'includeEdges', includeEdges));
  4425. }
  4426. finally
  4427. {
  4428. this.model.endUpdate();
  4429. }
  4430. return cells;
  4431. };
  4432. /**
  4433. * Function: cellsRemoved
  4434. *
  4435. * Removes the given cells from the model. This method fires
  4436. * <mxEvent.CELLS_REMOVED> while the transaction is in progress.
  4437. *
  4438. * Parameters:
  4439. *
  4440. * cells - Array of <mxCells> to remove.
  4441. */
  4442. mxGraph.prototype.cellsRemoved = function(cells)
  4443. {
  4444. if (cells != null && cells.length > 0)
  4445. {
  4446. var scale = this.view.scale;
  4447. var tr = this.view.translate;
  4448. this.model.beginUpdate();
  4449. try
  4450. {
  4451. // Creates hashtable for faster lookup
  4452. var dict = new mxDictionary();
  4453. for (var i = 0; i < cells.length; i++)
  4454. {
  4455. dict.put(cells[i], true);
  4456. }
  4457. for (var i = 0; i < cells.length; i++)
  4458. {
  4459. // Disconnects edges which are not being removed
  4460. var edges = this.getAllEdges([cells[i]]);
  4461. var disconnectTerminal = mxUtils.bind(this, function(edge, source)
  4462. {
  4463. var geo = this.model.getGeometry(edge);
  4464. if (geo != null)
  4465. {
  4466. // Checks if terminal is being removed
  4467. var terminal = this.model.getTerminal(edge, source);
  4468. var connected = false;
  4469. var tmp = terminal;
  4470. while (tmp != null)
  4471. {
  4472. if (cells[i] == tmp)
  4473. {
  4474. connected = true;
  4475. break;
  4476. }
  4477. tmp = this.model.getParent(tmp);
  4478. }
  4479. if (connected)
  4480. {
  4481. geo = geo.clone();
  4482. var state = this.view.getState(edge);
  4483. if (state != null && state.absolutePoints != null)
  4484. {
  4485. var pts = state.absolutePoints;
  4486. var n = (source) ? 0 : pts.length - 1;
  4487. geo.setTerminalPoint(new mxPoint(
  4488. pts[n].x / scale - tr.x - state.origin.x,
  4489. pts[n].y / scale - tr.y - state.origin.y), source);
  4490. }
  4491. else
  4492. {
  4493. // Fallback to center of terminal if routing
  4494. // points are not available to add new point
  4495. // KNOWN: Should recurse to find parent offset
  4496. // of edge for nested groups but invisible edges
  4497. // should be removed in removeCells step
  4498. var tstate = this.view.getState(terminal);
  4499. if (tstate != null)
  4500. {
  4501. geo.setTerminalPoint(new mxPoint(
  4502. tstate.getCenterX() / scale - tr.x,
  4503. tstate.getCenterY() / scale - tr.y), source);
  4504. }
  4505. }
  4506. this.model.setGeometry(edge, geo);
  4507. this.model.setTerminal(edge, null, source);
  4508. }
  4509. }
  4510. });
  4511. for (var j = 0; j < edges.length; j++)
  4512. {
  4513. if (!dict.get(edges[j]))
  4514. {
  4515. dict.put(edges[j], true);
  4516. disconnectTerminal(edges[j], true);
  4517. disconnectTerminal(edges[j], false);
  4518. }
  4519. }
  4520. this.model.remove(cells[i]);
  4521. }
  4522. this.fireEvent(new mxEventObject(mxEvent.CELLS_REMOVED, 'cells', cells));
  4523. }
  4524. finally
  4525. {
  4526. this.model.endUpdate();
  4527. }
  4528. }
  4529. };
  4530. /**
  4531. * Function: splitEdge
  4532. *
  4533. * Splits the given edge by adding the newEdge between the previous source
  4534. * and the given cell and reconnecting the source of the given edge to the
  4535. * given cell. This method fires <mxEvent.SPLIT_EDGE> while the transaction
  4536. * is in progress. Returns the new edge that was inserted.
  4537. *
  4538. * Parameters:
  4539. *
  4540. * edge - <mxCell> that represents the edge to be splitted.
  4541. * cells - <mxCells> that represents the cells to insert into the edge.
  4542. * newEdge - <mxCell> that represents the edge to be inserted.
  4543. * dx - Optional integer that specifies the vector to move the cells.
  4544. * dy - Optional integer that specifies the vector to move the cells.
  4545. * x - Integer that specifies the x-coordinate of the drop location.
  4546. * y - Integer that specifies the y-coordinate of the drop location.
  4547. * parent - Optional parent to insert the cell. If null the parent of
  4548. * the edge is used.
  4549. */
  4550. mxGraph.prototype.splitEdge = function(edge, cells, newEdge, dx, dy, x, y, parent)
  4551. {
  4552. dx = dx || 0;
  4553. dy = dy || 0;
  4554. parent = (parent != null) ? parent : this.model.getParent(edge);
  4555. var source = this.model.getTerminal(edge, true);
  4556. this.model.beginUpdate();
  4557. try
  4558. {
  4559. if (newEdge == null)
  4560. {
  4561. newEdge = this.cloneCell(edge);
  4562. // Removes waypoints before/after new cell
  4563. var state = this.view.getState(edge);
  4564. var geo = this.getCellGeometry(newEdge);
  4565. if (geo != null && geo.points != null && state != null)
  4566. {
  4567. var t = this.view.translate;
  4568. var s = this.view.scale;
  4569. var idx = mxUtils.findNearestSegment(state, (dx + t.x) * s, (dy + t.y) * s);
  4570. geo.points = geo.points.slice(0, idx);
  4571. geo = this.getCellGeometry(edge);
  4572. if (geo != null && geo.points != null)
  4573. {
  4574. geo = geo.clone();
  4575. geo.points = geo.points.slice(idx);
  4576. this.model.setGeometry(edge, geo);
  4577. }
  4578. }
  4579. }
  4580. this.cellsMoved(cells, dx, dy, false, false);
  4581. this.cellsAdded(cells, parent, this.model.getChildCount(parent), null, null,
  4582. true);
  4583. this.cellsAdded([newEdge], parent, this.model.getChildCount(parent),
  4584. source, cells[0], false);
  4585. this.cellConnected(edge, cells[0], true);
  4586. this.fireEvent(new mxEventObject(mxEvent.SPLIT_EDGE, 'edge', edge,
  4587. 'cells', cells, 'newEdge', newEdge, 'dx', dx, 'dy', dy));
  4588. }
  4589. finally
  4590. {
  4591. this.model.endUpdate();
  4592. }
  4593. return newEdge;
  4594. };
  4595. /**
  4596. * Group: Cell visibility
  4597. */
  4598. /**
  4599. * Function: toggleCells
  4600. *
  4601. * Sets the visible state of the specified cells and all connected edges
  4602. * if includeEdges is true. The change is carried out using <cellsToggled>.
  4603. * This method fires <mxEvent.TOGGLE_CELLS> while the transaction is in
  4604. * progress. Returns the cells whose visible state was changed.
  4605. *
  4606. * Parameters:
  4607. *
  4608. * show - Boolean that specifies the visible state to be assigned.
  4609. * cells - Array of <mxCells> whose visible state should be changed. If
  4610. * null is specified then the selection cells are used.
  4611. * includeEdges - Optional boolean indicating if the visible state of all
  4612. * connected edges should be changed as well. Default is true.
  4613. */
  4614. mxGraph.prototype.toggleCells = function(show, cells, includeEdges)
  4615. {
  4616. if (cells == null)
  4617. {
  4618. cells = this.getSelectionCells();
  4619. }
  4620. // Adds all connected edges recursively
  4621. if (includeEdges)
  4622. {
  4623. cells = this.addAllEdges(cells);
  4624. }
  4625. this.model.beginUpdate();
  4626. try
  4627. {
  4628. this.cellsToggled(cells, show);
  4629. this.fireEvent(new mxEventObject(mxEvent.TOGGLE_CELLS,
  4630. 'show', show, 'cells', cells, 'includeEdges', includeEdges));
  4631. }
  4632. finally
  4633. {
  4634. this.model.endUpdate();
  4635. }
  4636. return cells;
  4637. };
  4638. /**
  4639. * Function: cellsToggled
  4640. *
  4641. * Sets the visible state of the specified cells.
  4642. *
  4643. * Parameters:
  4644. *
  4645. * cells - Array of <mxCells> whose visible state should be changed.
  4646. * show - Boolean that specifies the visible state to be assigned.
  4647. */
  4648. mxGraph.prototype.cellsToggled = function(cells, show)
  4649. {
  4650. if (cells != null && cells.length > 0)
  4651. {
  4652. this.model.beginUpdate();
  4653. try
  4654. {
  4655. for (var i = 0; i < cells.length; i++)
  4656. {
  4657. this.model.setVisible(cells[i], show);
  4658. }
  4659. }
  4660. finally
  4661. {
  4662. this.model.endUpdate();
  4663. }
  4664. }
  4665. };
  4666. /**
  4667. * Group: Folding
  4668. */
  4669. /**
  4670. * Function: foldCells
  4671. *
  4672. * Sets the collapsed state of the specified cells and all descendants
  4673. * if recurse is true. The change is carried out using <cellsFolded>.
  4674. * This method fires <mxEvent.FOLD_CELLS> while the transaction is in
  4675. * progress. Returns the cells whose collapsed state was changed.
  4676. *
  4677. * Parameters:
  4678. *
  4679. * collapsed - Boolean indicating the collapsed state to be assigned.
  4680. * recurse - Optional boolean indicating if the collapsed state of all
  4681. * descendants should be set. Default is false.
  4682. * cells - Array of <mxCells> whose collapsed state should be set. If
  4683. * null is specified then the foldable selection cells are used.
  4684. * checkFoldable - Optional boolean indicating of isCellFoldable should be
  4685. * checked. Default is false.
  4686. * evt - Optional native event that triggered the invocation.
  4687. */
  4688. mxGraph.prototype.foldCells = function(collapse, recurse, cells, checkFoldable, evt)
  4689. {
  4690. recurse = (recurse != null) ? recurse : false;
  4691. if (cells == null)
  4692. {
  4693. cells = this.getFoldableCells(this.getSelectionCells(), collapse);
  4694. }
  4695. this.stopEditing(false);
  4696. this.model.beginUpdate();
  4697. try
  4698. {
  4699. this.cellsFolded(cells, collapse, recurse, checkFoldable);
  4700. this.fireEvent(new mxEventObject(mxEvent.FOLD_CELLS,
  4701. 'collapse', collapse, 'recurse', recurse, 'cells', cells));
  4702. }
  4703. finally
  4704. {
  4705. this.model.endUpdate();
  4706. }
  4707. return cells;
  4708. };
  4709. /**
  4710. * Function: cellsFolded
  4711. *
  4712. * Sets the collapsed state of the specified cells. This method fires
  4713. * <mxEvent.CELLS_FOLDED> while the transaction is in progress. Returns the
  4714. * cells whose collapsed state was changed.
  4715. *
  4716. * Parameters:
  4717. *
  4718. * cells - Array of <mxCells> whose collapsed state should be set.
  4719. * collapsed - Boolean indicating the collapsed state to be assigned.
  4720. * recurse - Boolean indicating if the collapsed state of all descendants
  4721. * should be set.
  4722. * checkFoldable - Optional boolean indicating of isCellFoldable should be
  4723. * checked. Default is false.
  4724. */
  4725. mxGraph.prototype.cellsFolded = function(cells, collapse, recurse, checkFoldable)
  4726. {
  4727. if (cells != null && cells.length > 0)
  4728. {
  4729. this.model.beginUpdate();
  4730. try
  4731. {
  4732. for (var i = 0; i < cells.length; i++)
  4733. {
  4734. if ((!checkFoldable || this.isCellFoldable(cells[i], collapse)) &&
  4735. collapse != this.isCellCollapsed(cells[i]))
  4736. {
  4737. this.model.setCollapsed(cells[i], collapse);
  4738. this.swapBounds(cells[i], collapse);
  4739. if (this.isExtendParent(cells[i]))
  4740. {
  4741. this.extendParent(cells[i]);
  4742. }
  4743. if (recurse)
  4744. {
  4745. var children = this.model.getChildren(cells[i]);
  4746. this.cellsFolded(children, collapse, recurse);
  4747. }
  4748. this.constrainChild(cells[i]);
  4749. }
  4750. }
  4751. this.fireEvent(new mxEventObject(mxEvent.CELLS_FOLDED,
  4752. 'cells', cells, 'collapse', collapse, 'recurse', recurse));
  4753. }
  4754. finally
  4755. {
  4756. this.model.endUpdate();
  4757. }
  4758. }
  4759. };
  4760. /**
  4761. * Function: swapBounds
  4762. *
  4763. * Swaps the alternate and the actual bounds in the geometry of the given
  4764. * cell invoking <updateAlternateBounds> before carrying out the swap.
  4765. *
  4766. * Parameters:
  4767. *
  4768. * cell - <mxCell> for which the bounds should be swapped.
  4769. * willCollapse - Boolean indicating if the cell is going to be collapsed.
  4770. */
  4771. mxGraph.prototype.swapBounds = function(cell, willCollapse)
  4772. {
  4773. if (cell != null)
  4774. {
  4775. var geo = this.model.getGeometry(cell);
  4776. if (geo != null)
  4777. {
  4778. geo = geo.clone();
  4779. this.updateAlternateBounds(cell, geo, willCollapse);
  4780. geo.swap();
  4781. this.model.setGeometry(cell, geo);
  4782. }
  4783. }
  4784. };
  4785. /**
  4786. * Function: updateAlternateBounds
  4787. *
  4788. * Updates or sets the alternate bounds in the given geometry for the given
  4789. * cell depending on whether the cell is going to be collapsed. If no
  4790. * alternate bounds are defined in the geometry and
  4791. * <collapseToPreferredSize> is true, then the preferred size is used for
  4792. * the alternate bounds. The top, left corner is always kept at the same
  4793. * location.
  4794. *
  4795. * Parameters:
  4796. *
  4797. * cell - <mxCell> for which the geometry is being udpated.
  4798. * g - <mxGeometry> for which the alternate bounds should be updated.
  4799. * willCollapse - Boolean indicating if the cell is going to be collapsed.
  4800. */
  4801. mxGraph.prototype.updateAlternateBounds = function(cell, geo, willCollapse)
  4802. {
  4803. if (cell != null && geo != null)
  4804. {
  4805. var style = this.getCurrentCellStyle(cell);
  4806. if (geo.alternateBounds == null)
  4807. {
  4808. var bounds = geo;
  4809. if (this.collapseToPreferredSize)
  4810. {
  4811. var tmp = this.getPreferredSizeForCell(cell);
  4812. if (tmp != null)
  4813. {
  4814. bounds = tmp;
  4815. var startSize = mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE);
  4816. if (startSize > 0)
  4817. {
  4818. bounds.height = Math.max(bounds.height, startSize);
  4819. }
  4820. }
  4821. }
  4822. geo.alternateBounds = new mxRectangle(0, 0, bounds.width, bounds.height);
  4823. }
  4824. if (geo.alternateBounds != null)
  4825. {
  4826. geo.alternateBounds.x = geo.x;
  4827. geo.alternateBounds.y = geo.y;
  4828. var alpha = mxUtils.toRadians(style[mxConstants.STYLE_ROTATION] || 0);
  4829. if (alpha != 0)
  4830. {
  4831. var dx = geo.alternateBounds.getCenterX() - geo.getCenterX();
  4832. var dy = geo.alternateBounds.getCenterY() - geo.getCenterY();
  4833. var cos = Math.cos(alpha);
  4834. var sin = Math.sin(alpha);
  4835. var dx2 = cos * dx - sin * dy;
  4836. var dy2 = sin * dx + cos * dy;
  4837. geo.alternateBounds.x += dx2 - dx;
  4838. geo.alternateBounds.y += dy2 - dy;
  4839. }
  4840. }
  4841. }
  4842. };
  4843. /**
  4844. * Function: addAllEdges
  4845. *
  4846. * Returns an array with the given cells and all edges that are connected
  4847. * to a cell or one of its descendants.
  4848. */
  4849. mxGraph.prototype.addAllEdges = function(cells)
  4850. {
  4851. var allCells = cells.slice();
  4852. return mxUtils.removeDuplicates(allCells.concat(this.getAllEdges(cells)));
  4853. };
  4854. /**
  4855. * Function: getAllEdges
  4856. *
  4857. * Returns all edges connected to the given cells or its descendants.
  4858. */
  4859. mxGraph.prototype.getAllEdges = function(cells)
  4860. {
  4861. var edges = [];
  4862. if (cells != null)
  4863. {
  4864. for (var i = 0; i < cells.length; i++)
  4865. {
  4866. var edgeCount = this.model.getEdgeCount(cells[i]);
  4867. for (var j = 0; j < edgeCount; j++)
  4868. {
  4869. edges.push(this.model.getEdgeAt(cells[i], j));
  4870. }
  4871. // Recurses
  4872. var children = this.model.getChildren(cells[i]);
  4873. edges = edges.concat(this.getAllEdges(children));
  4874. }
  4875. }
  4876. return edges;
  4877. };
  4878. /**
  4879. * Group: Cell sizing
  4880. */
  4881. /**
  4882. * Function: updateCellSize
  4883. *
  4884. * Updates the size of the given cell in the model using <cellSizeUpdated>.
  4885. * This method fires <mxEvent.UPDATE_CELL_SIZE> while the transaction is in
  4886. * progress. Returns the cell whose size was updated.
  4887. *
  4888. * Parameters:
  4889. *
  4890. * cell - <mxCell> whose size should be updated.
  4891. */
  4892. mxGraph.prototype.updateCellSize = function(cell, ignoreChildren)
  4893. {
  4894. ignoreChildren = (ignoreChildren != null) ? ignoreChildren : false;
  4895. this.model.beginUpdate();
  4896. try
  4897. {
  4898. this.cellSizeUpdated(cell, ignoreChildren);
  4899. this.fireEvent(new mxEventObject(mxEvent.UPDATE_CELL_SIZE,
  4900. 'cell', cell, 'ignoreChildren', ignoreChildren));
  4901. }
  4902. finally
  4903. {
  4904. this.model.endUpdate();
  4905. }
  4906. return cell;
  4907. };
  4908. /**
  4909. * Function: cellSizeUpdated
  4910. *
  4911. * Updates the size of the given cell in the model using
  4912. * <getPreferredSizeForCell> to get the new size.
  4913. *
  4914. * Parameters:
  4915. *
  4916. * cell - <mxCell> for which the size should be changed.
  4917. */
  4918. mxGraph.prototype.cellSizeUpdated = function(cell, ignoreChildren)
  4919. {
  4920. if (cell != null)
  4921. {
  4922. this.model.beginUpdate();
  4923. try
  4924. {
  4925. var size = this.getPreferredSizeForCell(cell);
  4926. var geo = this.model.getGeometry(cell);
  4927. if (size != null && geo != null)
  4928. {
  4929. var collapsed = this.isCellCollapsed(cell);
  4930. geo = geo.clone();
  4931. if (this.isSwimlane(cell))
  4932. {
  4933. var style = this.getCellStyle(cell);
  4934. var cellStyle = this.model.getStyle(cell);
  4935. if (cellStyle == null)
  4936. {
  4937. cellStyle = '';
  4938. }
  4939. if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  4940. {
  4941. cellStyle = mxUtils.setStyle(cellStyle,
  4942. mxConstants.STYLE_STARTSIZE, size.height + 8);
  4943. if (collapsed)
  4944. {
  4945. geo.height = size.height + 8;
  4946. }
  4947. geo.width = size.width;
  4948. }
  4949. else
  4950. {
  4951. cellStyle = mxUtils.setStyle(cellStyle,
  4952. mxConstants.STYLE_STARTSIZE, size.width + 8);
  4953. if (collapsed)
  4954. {
  4955. geo.width = size.width + 8;
  4956. }
  4957. geo.height = size.height;
  4958. }
  4959. this.model.setStyle(cell, cellStyle);
  4960. }
  4961. else
  4962. {
  4963. var state = this.view.createState(cell);
  4964. var align = (state.style[mxConstants.STYLE_ALIGN] || mxConstants.ALIGN_CENTER);
  4965. if (align == mxConstants.ALIGN_RIGHT)
  4966. {
  4967. geo.x += geo.width - size.width;
  4968. }
  4969. else if (align == mxConstants.ALIGN_CENTER)
  4970. {
  4971. geo.x += Math.round((geo.width - size.width) / 2);
  4972. }
  4973. var valign = this.getVerticalAlign(state);
  4974. if (valign == mxConstants.ALIGN_BOTTOM)
  4975. {
  4976. geo.y += geo.height - size.height;
  4977. }
  4978. else if (valign == mxConstants.ALIGN_MIDDLE)
  4979. {
  4980. geo.y += Math.round((geo.height - size.height) / 2);
  4981. }
  4982. geo.width = size.width;
  4983. geo.height = size.height;
  4984. }
  4985. if (!ignoreChildren && !collapsed)
  4986. {
  4987. var bounds = this.view.getBounds(this.model.getChildren(cell));
  4988. if (bounds != null)
  4989. {
  4990. var tr = this.view.translate;
  4991. var scale = this.view.scale;
  4992. var width = (bounds.x + bounds.width) / scale - geo.x - tr.x;
  4993. var height = (bounds.y + bounds.height) / scale - geo.y - tr.y;
  4994. geo.width = Math.max(geo.width, width);
  4995. geo.height = Math.max(geo.height, height);
  4996. }
  4997. }
  4998. this.cellsResized([cell], [geo], false);
  4999. }
  5000. }
  5001. finally
  5002. {
  5003. this.model.endUpdate();
  5004. }
  5005. }
  5006. };
  5007. /**
  5008. * Function: getPreferredSizeForCell
  5009. *
  5010. * Returns the preferred width and height of the given <mxCell> as an
  5011. * <mxRectangle>. To implement a minimum width, add a new style eg.
  5012. * minWidth in the vertex and override this method as follows.
  5013. *
  5014. * (code)
  5015. * var graphGetPreferredSizeForCell = graph.getPreferredSizeForCell;
  5016. * graph.getPreferredSizeForCell = function(cell)
  5017. * {
  5018. * var result = graphGetPreferredSizeForCell.apply(this, arguments);
  5019. * var style = this.getCellStyle(cell);
  5020. *
  5021. * if (style['minWidth'] > 0)
  5022. * {
  5023. * result.width = Math.max(style['minWidth'], result.width);
  5024. * }
  5025. *
  5026. * return result;
  5027. * };
  5028. * (end)
  5029. *
  5030. * Parameters:
  5031. *
  5032. * cell - <mxCell> for which the preferred size should be returned.
  5033. * textWidth - Optional maximum text width for word wrapping.
  5034. */
  5035. mxGraph.prototype.getPreferredSizeForCell = function(cell, textWidth)
  5036. {
  5037. var result = null;
  5038. if (cell != null)
  5039. {
  5040. var state = this.view.createState(cell);
  5041. var style = state.style;
  5042. if (!this.model.isEdge(cell))
  5043. {
  5044. var fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
  5045. var dx = 0;
  5046. var dy = 0;
  5047. // Adds dimension of image if shape is a label
  5048. if (this.getImage(state) != null || style[mxConstants.STYLE_IMAGE] != null)
  5049. {
  5050. if (style[mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_LABEL)
  5051. {
  5052. if (style[mxConstants.STYLE_VERTICAL_ALIGN] == mxConstants.ALIGN_MIDDLE)
  5053. {
  5054. dx += parseFloat(style[mxConstants.STYLE_IMAGE_WIDTH]) || mxLabel.prototype.imageSize;
  5055. }
  5056. if (style[mxConstants.STYLE_ALIGN] != mxConstants.ALIGN_CENTER)
  5057. {
  5058. dy += parseFloat(style[mxConstants.STYLE_IMAGE_HEIGHT]) || mxLabel.prototype.imageSize;
  5059. }
  5060. }
  5061. }
  5062. // Adds spacings
  5063. dx += 2 * (style[mxConstants.STYLE_SPACING] || 0);
  5064. dx += style[mxConstants.STYLE_SPACING_LEFT] || 0;
  5065. dx += style[mxConstants.STYLE_SPACING_RIGHT] || 0;
  5066. dy += 2 * (style[mxConstants.STYLE_SPACING] || 0);
  5067. dy += style[mxConstants.STYLE_SPACING_TOP] || 0;
  5068. dy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0;
  5069. // Add spacing for collapse/expand icon
  5070. // LATER: Check alignment and use constants
  5071. // for image spacing
  5072. var image = this.getFoldingImage(state);
  5073. if (image != null)
  5074. {
  5075. dx += image.width + 8;
  5076. }
  5077. // Adds space for label
  5078. var value = this.cellRenderer.getLabelValue(state);
  5079. if (value != null && value.length > 0)
  5080. {
  5081. if (!this.isHtmlLabel(state.cell))
  5082. {
  5083. value = mxUtils.htmlEntities(value, false);
  5084. }
  5085. value = value.replace(/\n/g, '<br>');
  5086. var size = mxUtils.getSizeForString(value, fontSize,
  5087. style[mxConstants.STYLE_FONTFAMILY], textWidth,
  5088. style[mxConstants.STYLE_FONTSTYLE]);
  5089. var width = size.width + dx;
  5090. var height = size.height + dy;
  5091. if (!mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  5092. {
  5093. var tmp = height;
  5094. height = width;
  5095. width = tmp;
  5096. }
  5097. if (this.gridEnabled)
  5098. {
  5099. width = this.snap(width + this.gridSize / 2);
  5100. height = this.snap(height + this.gridSize / 2);
  5101. }
  5102. result = new mxRectangle(0, 0, width, height);
  5103. }
  5104. else
  5105. {
  5106. var gs2 = 4 * this.gridSize;
  5107. result = new mxRectangle(0, 0, gs2, gs2);
  5108. }
  5109. }
  5110. }
  5111. return result;
  5112. };
  5113. /**
  5114. * Function: resizeCell
  5115. *
  5116. * Sets the bounds of the given cell using <resizeCells>. Returns the
  5117. * cell which was passed to the function.
  5118. *
  5119. * Parameters:
  5120. *
  5121. * cell - <mxCell> whose bounds should be changed.
  5122. * bounds - <mxRectangle> that represents the new bounds.
  5123. */
  5124. mxGraph.prototype.resizeCell = function(cell, bounds, recurse)
  5125. {
  5126. return this.resizeCells([cell], [bounds], recurse)[0];
  5127. };
  5128. /**
  5129. * Function: resizeCells
  5130. *
  5131. * Sets the bounds of the given cells and fires a <mxEvent.RESIZE_CELLS>
  5132. * event while the transaction is in progress. Returns the cells which
  5133. * have been passed to the function.
  5134. *
  5135. * Parameters:
  5136. *
  5137. * cells - Array of <mxCells> whose bounds should be changed.
  5138. * bounds - Array of <mxRectangles> that represent the new bounds.
  5139. */
  5140. mxGraph.prototype.resizeCells = function(cells, bounds, recurse)
  5141. {
  5142. recurse = (recurse != null) ? recurse : this.isRecursiveResize();
  5143. this.model.beginUpdate();
  5144. try
  5145. {
  5146. var prev = this.cellsResized(cells, bounds, recurse);
  5147. this.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS,
  5148. 'cells', cells, 'bounds', bounds, 'previous', prev));
  5149. }
  5150. finally
  5151. {
  5152. this.model.endUpdate();
  5153. }
  5154. return cells;
  5155. };
  5156. /**
  5157. * Function: cellsResized
  5158. *
  5159. * Sets the bounds of the given cells and fires a <mxEvent.CELLS_RESIZED>
  5160. * event. If <extendParents> is true, then the parent is extended if a
  5161. * child size is changed so that it overlaps with the parent.
  5162. *
  5163. * The following example shows how to control group resizes to make sure
  5164. * that all child cells stay within the group.
  5165. *
  5166. * (code)
  5167. * graph.addListener(mxEvent.CELLS_RESIZED, function(sender, evt)
  5168. * {
  5169. * var cells = evt.getProperty('cells');
  5170. *
  5171. * if (cells != null)
  5172. * {
  5173. * for (var i = 0; i < cells.length; i++)
  5174. * {
  5175. * if (graph.getModel().getChildCount(cells[i]) > 0)
  5176. * {
  5177. * var geo = graph.getCellGeometry(cells[i]);
  5178. *
  5179. * if (geo != null)
  5180. * {
  5181. * var children = graph.getChildCells(cells[i], true, true);
  5182. * var bounds = graph.getBoundingBoxFromGeometry(children, true);
  5183. *
  5184. * geo = geo.clone();
  5185. * geo.width = Math.max(geo.width, bounds.width);
  5186. * geo.height = Math.max(geo.height, bounds.height);
  5187. *
  5188. * graph.getModel().setGeometry(cells[i], geo);
  5189. * }
  5190. * }
  5191. * }
  5192. * }
  5193. * });
  5194. * (end)
  5195. *
  5196. * Parameters:
  5197. *
  5198. * cells - Array of <mxCells> whose bounds should be changed.
  5199. * bounds - Array of <mxRectangles> that represent the new bounds.
  5200. * recurse - Optional boolean that specifies if the children should be resized.
  5201. */
  5202. mxGraph.prototype.cellsResized = function(cells, bounds, recurse)
  5203. {
  5204. recurse = (recurse != null) ? recurse : false;
  5205. var prev = [];
  5206. if (cells != null && bounds != null && cells.length == bounds.length)
  5207. {
  5208. this.model.beginUpdate();
  5209. try
  5210. {
  5211. for (var i = 0; i < cells.length; i++)
  5212. {
  5213. prev.push(this.cellResized(cells[i], bounds[i], false, recurse));
  5214. if (this.isExtendParent(cells[i]))
  5215. {
  5216. this.extendParent(cells[i]);
  5217. }
  5218. this.constrainChild(cells[i]);
  5219. }
  5220. if (this.resetEdgesOnResize)
  5221. {
  5222. this.resetEdges(cells);
  5223. }
  5224. this.fireEvent(new mxEventObject(mxEvent.CELLS_RESIZED,
  5225. 'cells', cells, 'bounds', bounds, 'previous', prev));
  5226. }
  5227. finally
  5228. {
  5229. this.model.endUpdate();
  5230. }
  5231. }
  5232. return prev;
  5233. };
  5234. /**
  5235. * Function: cellResized
  5236. *
  5237. * Resizes the parents recursively so that they contain the complete area
  5238. * of the resized child cell.
  5239. *
  5240. * Parameters:
  5241. *
  5242. * cell - <mxCell> whose bounds should be changed.
  5243. * bounds - <mxRectangles> that represent the new bounds.
  5244. * ignoreRelative - Boolean that indicates if relative cells should be ignored.
  5245. * recurse - Optional boolean that specifies if the children should be resized.
  5246. */
  5247. mxGraph.prototype.cellResized = function(cell, bounds, ignoreRelative, recurse)
  5248. {
  5249. var prev = this.model.getGeometry(cell);
  5250. if (prev != null && (prev.x != bounds.x || prev.y != bounds.y ||
  5251. prev.width != bounds.width || prev.height != bounds.height))
  5252. {
  5253. var geo = prev.clone();
  5254. if (!ignoreRelative && geo.relative)
  5255. {
  5256. var offset = geo.offset;
  5257. if (offset != null)
  5258. {
  5259. offset.x += bounds.x - geo.x;
  5260. offset.y += bounds.y - geo.y;
  5261. }
  5262. }
  5263. else
  5264. {
  5265. geo.x = bounds.x;
  5266. geo.y = bounds.y;
  5267. }
  5268. geo.width = bounds.width;
  5269. geo.height = bounds.height;
  5270. if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
  5271. {
  5272. geo.x = Math.max(0, geo.x);
  5273. geo.y = Math.max(0, geo.y);
  5274. }
  5275. this.model.beginUpdate();
  5276. try
  5277. {
  5278. if (recurse)
  5279. {
  5280. this.resizeChildCells(cell, geo);
  5281. }
  5282. this.model.setGeometry(cell, geo);
  5283. this.constrainChildCells(cell);
  5284. }
  5285. finally
  5286. {
  5287. this.model.endUpdate();
  5288. }
  5289. }
  5290. return prev;
  5291. };
  5292. /**
  5293. * Function: resizeChildCells
  5294. *
  5295. * Resizes the child cells of the given cell for the given new geometry with
  5296. * respect to the current geometry of the cell.
  5297. *
  5298. * Parameters:
  5299. *
  5300. * cell - <mxCell> that has been resized.
  5301. * newGeo - <mxGeometry> that represents the new bounds.
  5302. */
  5303. mxGraph.prototype.resizeChildCells = function(cell, newGeo)
  5304. {
  5305. var geo = this.model.getGeometry(cell);
  5306. var dx = (geo.width != 0) ? newGeo.width / geo.width : 1;
  5307. var dy = (geo.height != 0) ? newGeo.height / geo.height : 1;
  5308. var childCount = this.model.getChildCount(cell);
  5309. for (var i = 0; i < childCount; i++)
  5310. {
  5311. this.scaleCell(this.model.getChildAt(cell, i), dx, dy, true);
  5312. }
  5313. };
  5314. /**
  5315. * Function: constrainChildCells
  5316. *
  5317. * Constrains the children of the given cell using <constrainChild>.
  5318. *
  5319. * Parameters:
  5320. *
  5321. * cell - <mxCell> that has been resized.
  5322. */
  5323. mxGraph.prototype.constrainChildCells = function(cell)
  5324. {
  5325. var childCount = this.model.getChildCount(cell);
  5326. for (var i = 0; i < childCount; i++)
  5327. {
  5328. this.constrainChild(this.model.getChildAt(cell, i));
  5329. }
  5330. };
  5331. /**
  5332. * Function: scaleCell
  5333. *
  5334. * Scales the points, position and size of the given cell according to the
  5335. * given vertical and horizontal scaling factors.
  5336. *
  5337. * Parameters:
  5338. *
  5339. * cell - <mxCell> whose geometry should be scaled.
  5340. * dx - Horizontal scaling factor.
  5341. * dy - Vertical scaling factor.
  5342. * recurse - Boolean indicating if the child cells should be scaled.
  5343. */
  5344. mxGraph.prototype.scaleCell = function(cell, dx, dy, recurse)
  5345. {
  5346. var geo = this.model.getGeometry(cell);
  5347. if (geo != null)
  5348. {
  5349. var style = this.getCurrentCellStyle(cell);
  5350. geo = geo.clone();
  5351. // Stores values for restoring based on style
  5352. var x = geo.x;
  5353. var y = geo.y
  5354. var w = geo.width;
  5355. var h = geo.height;
  5356. geo.scale(dx, dy, style[mxConstants.STYLE_ASPECT] == 'fixed');
  5357. if (style[mxConstants.STYLE_RESIZE_WIDTH] == '1')
  5358. {
  5359. geo.width = w * dx;
  5360. }
  5361. else if (style[mxConstants.STYLE_RESIZE_WIDTH] == '0')
  5362. {
  5363. geo.width = w;
  5364. }
  5365. if (style[mxConstants.STYLE_RESIZE_HEIGHT] == '1')
  5366. {
  5367. geo.height = h * dy;
  5368. }
  5369. else if (style[mxConstants.STYLE_RESIZE_HEIGHT] == '0')
  5370. {
  5371. geo.height = h;
  5372. }
  5373. if (!this.isCellMovable(cell))
  5374. {
  5375. geo.x = x;
  5376. geo.y = y;
  5377. }
  5378. if (!this.isCellResizable(cell))
  5379. {
  5380. geo.width = w;
  5381. geo.height = h;
  5382. }
  5383. if (this.model.isVertex(cell))
  5384. {
  5385. this.cellResized(cell, geo, true, recurse);
  5386. }
  5387. else
  5388. {
  5389. this.model.setGeometry(cell, geo);
  5390. }
  5391. }
  5392. };
  5393. /**
  5394. * Function: extendParent
  5395. *
  5396. * Resizes the parents recursively so that they contain the complete area
  5397. * of the resized child cell.
  5398. *
  5399. * Parameters:
  5400. *
  5401. * cell - <mxCell> that has been resized.
  5402. */
  5403. mxGraph.prototype.extendParent = function(cell)
  5404. {
  5405. if (cell != null)
  5406. {
  5407. var parent = this.model.getParent(cell);
  5408. var p = this.getCellGeometry(parent);
  5409. if (parent != null && p != null && !this.isCellCollapsed(parent))
  5410. {
  5411. var geo = this.getCellGeometry(cell);
  5412. if (geo != null && !geo.relative &&
  5413. (p.width < geo.x + geo.width ||
  5414. p.height < geo.y + geo.height))
  5415. {
  5416. p = p.clone();
  5417. p.width = Math.max(p.width, geo.x + geo.width);
  5418. p.height = Math.max(p.height, geo.y + geo.height);
  5419. this.cellsResized([parent], [p], false);
  5420. }
  5421. }
  5422. }
  5423. };
  5424. /**
  5425. * Group: Cell moving
  5426. */
  5427. /**
  5428. * Function: importCells
  5429. *
  5430. * Clones and inserts the given cells into the graph using the move
  5431. * method and returns the inserted cells. This shortcut is used if
  5432. * cells are inserted via datatransfer.
  5433. *
  5434. * Parameters:
  5435. *
  5436. * cells - Array of <mxCells> to be imported.
  5437. * dx - Integer that specifies the x-coordinate of the vector. Default is 0.
  5438. * dy - Integer that specifies the y-coordinate of the vector. Default is 0.
  5439. * target - <mxCell> that represents the new parent of the cells.
  5440. * evt - Mouseevent that triggered the invocation.
  5441. * mapping - Optional mapping for existing clones.
  5442. */
  5443. mxGraph.prototype.importCells = function(cells, dx, dy, target, evt, mapping)
  5444. {
  5445. return this.moveCells(cells, dx, dy, true, target, evt, mapping);
  5446. };
  5447. /**
  5448. * Function: moveCells
  5449. *
  5450. * Moves or clones the specified cells and moves the cells or clones by the
  5451. * given amount, adding them to the optional target cell. The evt is the
  5452. * mouse event as the mouse was released. The change is carried out using
  5453. * <cellsMoved>. This method fires <mxEvent.MOVE_CELLS> while the
  5454. * transaction is in progress. Returns the cells that were moved.
  5455. *
  5456. * Use the following code to move all cells in the graph.
  5457. *
  5458. * (code)
  5459. * graph.moveCells(graph.getChildCells(null, true, true), 10, 10);
  5460. * (end)
  5461. *
  5462. * Parameters:
  5463. *
  5464. * cells - Array of <mxCells> to be moved, cloned or added to the target.
  5465. * dx - Integer that specifies the x-coordinate of the vector. Default is 0.
  5466. * dy - Integer that specifies the y-coordinate of the vector. Default is 0.
  5467. * clone - Boolean indicating if the cells should be cloned. Default is false.
  5468. * target - <mxCell> that represents the new parent of the cells.
  5469. * evt - Mouseevent that triggered the invocation.
  5470. * mapping - Optional mapping for existing clones.
  5471. */
  5472. mxGraph.prototype.moveCells = function(cells, dx, dy, clone, target, evt, mapping)
  5473. {
  5474. dx = (dx != null) ? dx : 0;
  5475. dy = (dy != null) ? dy : 0;
  5476. clone = (clone != null) ? clone : false;
  5477. if (cells != null && (dx != 0 || dy != 0 || clone || target != null))
  5478. {
  5479. // Removes descendants with ancestors in cells to avoid multiple moving
  5480. cells = this.model.getTopmostCells(cells);
  5481. var origCells = cells;
  5482. this.model.beginUpdate();
  5483. try
  5484. {
  5485. // Faster cell lookups to remove relative edge labels with selected
  5486. // terminals to avoid explicit and implicit move at same time
  5487. var dict = new mxDictionary();
  5488. for (var i = 0; i < cells.length; i++)
  5489. {
  5490. dict.put(cells[i], true);
  5491. }
  5492. var isSelected = mxUtils.bind(this, function(cell)
  5493. {
  5494. while (cell != null)
  5495. {
  5496. if (dict.get(cell))
  5497. {
  5498. return true;
  5499. }
  5500. cell = this.model.getParent(cell);
  5501. }
  5502. return false;
  5503. });
  5504. // Removes relative edge labels with selected terminals
  5505. var checked = [];
  5506. for (var i = 0; i < cells.length; i++)
  5507. {
  5508. var geo = this.getCellGeometry(cells[i]);
  5509. var parent = this.model.getParent(cells[i]);
  5510. if ((geo == null || !geo.relative) || !this.model.isEdge(parent) ||
  5511. (!isSelected(this.model.getTerminal(parent, true)) &&
  5512. !isSelected(this.model.getTerminal(parent, false))))
  5513. {
  5514. checked.push(cells[i]);
  5515. }
  5516. }
  5517. cells = checked;
  5518. if (clone)
  5519. {
  5520. cells = this.cloneCells(cells, this.isCloneInvalidEdges(), mapping);
  5521. if (target == null)
  5522. {
  5523. target = this.getDefaultParent();
  5524. }
  5525. }
  5526. // FIXME: Cells should always be inserted first before any other edit
  5527. // to avoid forward references in sessions.
  5528. // Need to disable allowNegativeCoordinates if target not null to
  5529. // allow for temporary negative numbers until cellsAdded is called.
  5530. var previous = this.isAllowNegativeCoordinates();
  5531. if (target != null)
  5532. {
  5533. this.setAllowNegativeCoordinates(true);
  5534. }
  5535. this.cellsMoved(cells, dx, dy, !clone && this.isDisconnectOnMove()
  5536. && this.isAllowDanglingEdges(), target == null,
  5537. this.isExtendParentsOnMove() && target == null);
  5538. this.setAllowNegativeCoordinates(previous);
  5539. if (target != null)
  5540. {
  5541. var index = this.model.getChildCount(target);
  5542. this.cellsAdded(cells, target, index, null, null, true);
  5543. // Restores parent edge on cloned edge labels
  5544. if (clone)
  5545. {
  5546. for (var i = 0; i < cells.length; i++)
  5547. {
  5548. var geo = this.getCellGeometry(cells[i]);
  5549. var parent = this.model.getParent(origCells[i]);
  5550. if (geo != null && geo.relative &&
  5551. this.model.isEdge(parent) &&
  5552. this.model.contains(parent))
  5553. {
  5554. this.model.add(parent, cells[i]);
  5555. }
  5556. }
  5557. }
  5558. }
  5559. // Dispatches a move event
  5560. this.fireEvent(new mxEventObject(mxEvent.MOVE_CELLS, 'cells', cells,
  5561. 'dx', dx, 'dy', dy, 'clone', clone, 'target', target, 'event', evt));
  5562. }
  5563. finally
  5564. {
  5565. this.model.endUpdate();
  5566. }
  5567. }
  5568. return cells;
  5569. };
  5570. /**
  5571. * Function: cellsMoved
  5572. *
  5573. * Moves the specified cells by the given vector, disconnecting the cells
  5574. * using disconnectGraph is disconnect is true. This method fires
  5575. * <mxEvent.CELLS_MOVED> while the transaction is in progress.
  5576. */
  5577. mxGraph.prototype.cellsMoved = function(cells, dx, dy, disconnect, constrain, extend)
  5578. {
  5579. if (cells != null && (dx != 0 || dy != 0))
  5580. {
  5581. extend = (extend != null) ? extend : false;
  5582. this.model.beginUpdate();
  5583. try
  5584. {
  5585. if (disconnect)
  5586. {
  5587. this.disconnectGraph(cells);
  5588. }
  5589. for (var i = 0; i < cells.length; i++)
  5590. {
  5591. this.translateCell(cells[i], dx, dy);
  5592. if (extend && this.isExtendParent(cells[i]))
  5593. {
  5594. this.extendParent(cells[i]);
  5595. }
  5596. else if (constrain)
  5597. {
  5598. this.constrainChild(cells[i]);
  5599. }
  5600. }
  5601. if (this.resetEdgesOnMove)
  5602. {
  5603. this.resetEdges(cells);
  5604. }
  5605. this.fireEvent(new mxEventObject(mxEvent.CELLS_MOVED,
  5606. 'cells', cells, 'dx', dx, 'dy', dy, 'disconnect', disconnect));
  5607. }
  5608. finally
  5609. {
  5610. this.model.endUpdate();
  5611. }
  5612. }
  5613. };
  5614. /**
  5615. * Function: translateCell
  5616. *
  5617. * Translates the geometry of the given cell and stores the new,
  5618. * translated geometry in the model as an atomic change.
  5619. */
  5620. mxGraph.prototype.translateCell = function(cell, dx, dy)
  5621. {
  5622. var geo = this.model.getGeometry(cell);
  5623. if (geo != null)
  5624. {
  5625. dx = parseFloat(dx);
  5626. dy = parseFloat(dy);
  5627. geo = geo.clone();
  5628. geo.translate(dx, dy);
  5629. if (!geo.relative && this.model.isVertex(cell) && !this.isAllowNegativeCoordinates())
  5630. {
  5631. geo.x = Math.max(0, parseFloat(geo.x));
  5632. geo.y = Math.max(0, parseFloat(geo.y));
  5633. }
  5634. if (geo.relative && !this.model.isEdge(cell))
  5635. {
  5636. var parent = this.model.getParent(cell);
  5637. var angle = 0;
  5638. if (this.model.isVertex(parent))
  5639. {
  5640. var style = this.getCurrentCellStyle(parent);
  5641. angle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
  5642. }
  5643. if (angle != 0)
  5644. {
  5645. var rad = mxUtils.toRadians(-angle);
  5646. var cos = Math.cos(rad);
  5647. var sin = Math.sin(rad);
  5648. var pt = mxUtils.getRotatedPoint(new mxPoint(dx, dy), cos, sin, new mxPoint(0, 0));
  5649. dx = pt.x;
  5650. dy = pt.y;
  5651. }
  5652. if (geo.offset == null)
  5653. {
  5654. geo.offset = new mxPoint(dx, dy);
  5655. }
  5656. else
  5657. {
  5658. geo.offset.x = parseFloat(geo.offset.x) + dx;
  5659. geo.offset.y = parseFloat(geo.offset.y) + dy;
  5660. }
  5661. }
  5662. this.model.setGeometry(cell, geo);
  5663. }
  5664. };
  5665. /**
  5666. * Function: getCellContainmentArea
  5667. *
  5668. * Returns the <mxRectangle> inside which a cell is to be kept.
  5669. *
  5670. * Parameters:
  5671. *
  5672. * cell - <mxCell> for which the area should be returned.
  5673. */
  5674. mxGraph.prototype.getCellContainmentArea = function(cell)
  5675. {
  5676. if (cell != null && !this.model.isEdge(cell))
  5677. {
  5678. var parent = this.model.getParent(cell);
  5679. if (parent != null && parent != this.getDefaultParent())
  5680. {
  5681. var g = this.model.getGeometry(parent);
  5682. if (g != null)
  5683. {
  5684. var x = 0;
  5685. var y = 0;
  5686. var w = g.width;
  5687. var h = g.height;
  5688. if (this.isSwimlane(parent))
  5689. {
  5690. var size = this.getStartSize(parent);
  5691. var style = this.getCurrentCellStyle(parent);
  5692. var dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  5693. var flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
  5694. var flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
  5695. if (dir == mxConstants.DIRECTION_SOUTH || dir == mxConstants.DIRECTION_NORTH)
  5696. {
  5697. var tmp = size.width;
  5698. size.width = size.height;
  5699. size.height = tmp;
  5700. }
  5701. if ((dir == mxConstants.DIRECTION_EAST && !flipV) || (dir == mxConstants.DIRECTION_NORTH && !flipH) ||
  5702. (dir == mxConstants.DIRECTION_WEST && flipV) || (dir == mxConstants.DIRECTION_SOUTH && flipH))
  5703. {
  5704. x = size.width;
  5705. y = size.height;
  5706. }
  5707. w -= size.width;
  5708. h -= size.height;
  5709. }
  5710. return new mxRectangle(x, y, w, h);
  5711. }
  5712. }
  5713. }
  5714. return null;
  5715. };
  5716. /**
  5717. * Function: getMaximumGraphBounds
  5718. *
  5719. * Returns the bounds inside which the diagram should be kept as an
  5720. * <mxRectangle>.
  5721. */
  5722. mxGraph.prototype.getMaximumGraphBounds = function()
  5723. {
  5724. return this.maximumGraphBounds;
  5725. };
  5726. /**
  5727. * Function: constrainChild
  5728. *
  5729. * Keeps the given cell inside the bounds returned by
  5730. * <getCellContainmentArea> for its parent, according to the rules defined by
  5731. * <getOverlap> and <isConstrainChild>. This modifies the cell's geometry
  5732. * in-place and does not clone it.
  5733. *
  5734. * Parameters:
  5735. *
  5736. * cells - <mxCell> which should be constrained.
  5737. * sizeFirst - Specifies if the size should be changed first. Default is true.
  5738. */
  5739. mxGraph.prototype.constrainChild = function(cell, sizeFirst)
  5740. {
  5741. sizeFirst = (sizeFirst != null) ? sizeFirst : true;
  5742. if (cell != null)
  5743. {
  5744. var geo = this.getCellGeometry(cell);
  5745. if (geo != null && (this.isConstrainRelativeChildren() || !geo.relative))
  5746. {
  5747. var parent = this.model.getParent(cell);
  5748. var pgeo = this.getCellGeometry(parent);
  5749. var max = this.getMaximumGraphBounds();
  5750. // Finds parent offset
  5751. if (max != null)
  5752. {
  5753. var off = this.getBoundingBoxFromGeometry([parent], false);
  5754. if (off != null)
  5755. {
  5756. max = mxRectangle.fromRectangle(max);
  5757. max.x -= off.x;
  5758. max.y -= off.y;
  5759. }
  5760. }
  5761. if (this.isConstrainChild(cell))
  5762. {
  5763. var tmp = this.getCellContainmentArea(cell);
  5764. if (tmp != null)
  5765. {
  5766. var overlap = this.getOverlap(cell);
  5767. if (overlap > 0)
  5768. {
  5769. tmp = mxRectangle.fromRectangle(tmp);
  5770. tmp.x -= tmp.width * overlap;
  5771. tmp.y -= tmp.height * overlap;
  5772. tmp.width += 2 * tmp.width * overlap;
  5773. tmp.height += 2 * tmp.height * overlap;
  5774. }
  5775. // Find the intersection between max and tmp
  5776. if (max == null)
  5777. {
  5778. max = tmp;
  5779. }
  5780. else
  5781. {
  5782. max = mxRectangle.fromRectangle(max);
  5783. max.intersect(tmp);
  5784. }
  5785. }
  5786. }
  5787. if (max != null)
  5788. {
  5789. var cells = [cell];
  5790. if (!this.isCellCollapsed(cell))
  5791. {
  5792. var desc = this.model.getDescendants(cell);
  5793. for (var i = 0; i < desc.length; i++)
  5794. {
  5795. if (this.isCellVisible(desc[i]))
  5796. {
  5797. cells.push(desc[i]);
  5798. }
  5799. }
  5800. }
  5801. var bbox = this.getBoundingBoxFromGeometry(cells, false);
  5802. if (bbox != null)
  5803. {
  5804. geo = geo.clone();
  5805. // Cumulative horizontal movement
  5806. var dx = 0;
  5807. if (geo.width > max.width)
  5808. {
  5809. dx = geo.width - max.width;
  5810. geo.width -= dx;
  5811. }
  5812. if (bbox.x + bbox.width > max.x + max.width)
  5813. {
  5814. dx -= bbox.x + bbox.width - max.x - max.width - dx;
  5815. }
  5816. // Cumulative vertical movement
  5817. var dy = 0;
  5818. if (geo.height > max.height)
  5819. {
  5820. dy = geo.height - max.height;
  5821. geo.height -= dy;
  5822. }
  5823. if (bbox.y + bbox.height > max.y + max.height)
  5824. {
  5825. dy -= bbox.y + bbox.height - max.y - max.height - dy;
  5826. }
  5827. if (bbox.x < max.x)
  5828. {
  5829. dx -= bbox.x - max.x;
  5830. }
  5831. if (bbox.y < max.y)
  5832. {
  5833. dy -= bbox.y - max.y;
  5834. }
  5835. if (dx != 0 || dy != 0)
  5836. {
  5837. if (geo.relative)
  5838. {
  5839. // Relative geometries are moved via absolute offset
  5840. if (geo.offset == null)
  5841. {
  5842. geo.offset = new mxPoint();
  5843. }
  5844. geo.offset.x += dx;
  5845. geo.offset.y += dy;
  5846. }
  5847. else
  5848. {
  5849. geo.x += dx;
  5850. geo.y += dy;
  5851. }
  5852. }
  5853. this.model.setGeometry(cell, geo);
  5854. }
  5855. }
  5856. }
  5857. }
  5858. };
  5859. /**
  5860. * Function: resetEdges
  5861. *
  5862. * Resets the control points of the edges that are connected to the given
  5863. * cells if not both ends of the edge are in the given cells array.
  5864. *
  5865. * Parameters:
  5866. *
  5867. * cells - Array of <mxCells> for which the connected edges should be
  5868. * reset.
  5869. */
  5870. mxGraph.prototype.resetEdges = function(cells)
  5871. {
  5872. if (cells != null)
  5873. {
  5874. // Prepares faster cells lookup
  5875. var dict = new mxDictionary();
  5876. for (var i = 0; i < cells.length; i++)
  5877. {
  5878. dict.put(cells[i], true);
  5879. }
  5880. this.model.beginUpdate();
  5881. try
  5882. {
  5883. for (var i = 0; i < cells.length; i++)
  5884. {
  5885. var edges = this.model.getEdges(cells[i]);
  5886. if (edges != null)
  5887. {
  5888. for (var j = 0; j < edges.length; j++)
  5889. {
  5890. var state = this.view.getState(edges[j]);
  5891. var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[j], true);
  5892. var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[j], false);
  5893. // Checks if one of the terminals is not in the given array
  5894. if (!dict.get(source) || !dict.get(target))
  5895. {
  5896. this.resetEdge(edges[j]);
  5897. }
  5898. }
  5899. }
  5900. this.resetEdges(this.model.getChildren(cells[i]));
  5901. }
  5902. }
  5903. finally
  5904. {
  5905. this.model.endUpdate();
  5906. }
  5907. }
  5908. };
  5909. /**
  5910. * Function: resetEdge
  5911. *
  5912. * Resets the control points of the given edge.
  5913. *
  5914. * Parameters:
  5915. *
  5916. * edge - <mxCell> whose points should be reset.
  5917. */
  5918. mxGraph.prototype.resetEdge = function(edge)
  5919. {
  5920. var geo = this.model.getGeometry(edge);
  5921. // Resets the control points
  5922. if (geo != null && geo.points != null && geo.points.length > 0)
  5923. {
  5924. geo = geo.clone();
  5925. geo.points = [];
  5926. this.model.setGeometry(edge, geo);
  5927. }
  5928. return edge;
  5929. };
  5930. /**
  5931. * Group: Cell connecting and connection constraints
  5932. */
  5933. /**
  5934. * Function: getOutlineConstraint
  5935. *
  5936. * Returns the constraint used to connect to the outline of the given state.
  5937. */
  5938. mxGraph.prototype.getOutlineConstraint = function(point, terminalState, me)
  5939. {
  5940. if (terminalState.shape != null)
  5941. {
  5942. var bounds = this.view.getPerimeterBounds(terminalState);
  5943. var direction = terminalState.style[mxConstants.STYLE_DIRECTION];
  5944. if (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
  5945. {
  5946. bounds.x += bounds.width / 2 - bounds.height / 2;
  5947. bounds.y += bounds.height / 2 - bounds.width / 2;
  5948. var tmp = bounds.width;
  5949. bounds.width = bounds.height;
  5950. bounds.height = tmp;
  5951. }
  5952. var alpha = mxUtils.toRadians(terminalState.shape.getShapeRotation());
  5953. if (alpha != 0)
  5954. {
  5955. var cos = Math.cos(-alpha);
  5956. var sin = Math.sin(-alpha);
  5957. var ct = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
  5958. point = mxUtils.getRotatedPoint(point, cos, sin, ct);
  5959. }
  5960. var sx = 1;
  5961. var sy = 1;
  5962. var dx = 0;
  5963. var dy = 0;
  5964. // LATER: Add flipping support for image shapes
  5965. if (this.getModel().isVertex(terminalState.cell))
  5966. {
  5967. var flipH = terminalState.style[mxConstants.STYLE_FLIPH];
  5968. var flipV = terminalState.style[mxConstants.STYLE_FLIPV];
  5969. // Legacy support for stencilFlipH/V
  5970. if (terminalState.shape != null && terminalState.shape.stencil != null)
  5971. {
  5972. flipH = mxUtils.getValue(terminalState.style, 'stencilFlipH', 0) == 1 || flipH;
  5973. flipV = mxUtils.getValue(terminalState.style, 'stencilFlipV', 0) == 1 || flipV;
  5974. }
  5975. if (direction == mxConstants.DIRECTION_NORTH || direction == mxConstants.DIRECTION_SOUTH)
  5976. {
  5977. var tmp = flipH;
  5978. flipH = flipV;
  5979. flipV = tmp;
  5980. }
  5981. if (flipH)
  5982. {
  5983. sx = -1;
  5984. dx = -bounds.width;
  5985. }
  5986. if (flipV)
  5987. {
  5988. sy = -1;
  5989. dy = -bounds.height ;
  5990. }
  5991. }
  5992. point = new mxPoint((point.x - bounds.x) * sx - dx + bounds.x, (point.y - bounds.y) * sy - dy + bounds.y);
  5993. var x = (bounds.width == 0) ? 0 : Math.round((point.x - bounds.x) * 1000 / bounds.width) / 1000;
  5994. var y = (bounds.height == 0) ? 0 : Math.round((point.y - bounds.y) * 1000 / bounds.height) / 1000;
  5995. return new mxConnectionConstraint(new mxPoint(x, y), false);
  5996. }
  5997. return null;
  5998. };
  5999. /**
  6000. * Function: getAllConnectionConstraints
  6001. *
  6002. * Returns an array of all <mxConnectionConstraints> for the given terminal. If
  6003. * the shape of the given terminal is a <mxStencilShape> then the constraints
  6004. * of the corresponding <mxStencil> are returned.
  6005. *
  6006. * Parameters:
  6007. *
  6008. * terminal - <mxCellState> that represents the terminal.
  6009. * source - Boolean that specifies if the terminal is the source or target.
  6010. */
  6011. mxGraph.prototype.getAllConnectionConstraints = function(terminal, source)
  6012. {
  6013. if (terminal != null && terminal.shape != null && terminal.shape.stencil != null)
  6014. {
  6015. return terminal.shape.stencil.constraints;
  6016. }
  6017. return null;
  6018. };
  6019. /**
  6020. * Function: getConnectionConstraint
  6021. *
  6022. * Returns an <mxConnectionConstraint> that describes the given connection
  6023. * point. This result can then be passed to <getConnectionPoint>.
  6024. *
  6025. * Parameters:
  6026. *
  6027. * edge - <mxCellState> that represents the edge.
  6028. * terminal - <mxCellState> that represents the terminal.
  6029. * source - Boolean indicating if the terminal is the source or target.
  6030. */
  6031. mxGraph.prototype.getConnectionConstraint = function(edge, terminal, source)
  6032. {
  6033. var point = null;
  6034. var x = edge.style[(source) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];
  6035. if (x != null)
  6036. {
  6037. var y = edge.style[(source) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
  6038. if (y != null)
  6039. {
  6040. point = new mxPoint(parseFloat(x), parseFloat(y));
  6041. }
  6042. }
  6043. var perimeter = false;
  6044. var dx = 0, dy = 0;
  6045. if (point != null)
  6046. {
  6047. perimeter = mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_EXIT_PERIMETER :
  6048. mxConstants.STYLE_ENTRY_PERIMETER, true);
  6049. //Add entry/exit offset
  6050. dx = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DX : mxConstants.STYLE_ENTRY_DX]);
  6051. dy = parseFloat(edge.style[(source) ? mxConstants.STYLE_EXIT_DY : mxConstants.STYLE_ENTRY_DY]);
  6052. dx = isFinite(dx)? dx : 0;
  6053. dy = isFinite(dy)? dy : 0;
  6054. }
  6055. return new mxConnectionConstraint(point, perimeter, null, dx, dy);
  6056. };
  6057. /**
  6058. * Function: setConnectionConstraint
  6059. *
  6060. * Sets the <mxConnectionConstraint> that describes the given connection point.
  6061. * If no constraint is given then nothing is changed. To remove an existing
  6062. * constraint from the given edge, use an empty constraint instead.
  6063. *
  6064. * Parameters:
  6065. *
  6066. * edge - <mxCell> that represents the edge.
  6067. * terminal - <mxCell> that represents the terminal.
  6068. * source - Boolean indicating if the terminal is the source or target.
  6069. * constraint - Optional <mxConnectionConstraint> to be used for this
  6070. * connection.
  6071. */
  6072. mxGraph.prototype.setConnectionConstraint = function(edge, terminal, source, constraint)
  6073. {
  6074. if (constraint != null)
  6075. {
  6076. this.model.beginUpdate();
  6077. try
  6078. {
  6079. if (constraint == null || constraint.point == null)
  6080. {
  6081. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
  6082. mxConstants.STYLE_ENTRY_X, null, [edge]);
  6083. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
  6084. mxConstants.STYLE_ENTRY_Y, null, [edge]);
  6085. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
  6086. mxConstants.STYLE_ENTRY_DX, null, [edge]);
  6087. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
  6088. mxConstants.STYLE_ENTRY_DY, null, [edge]);
  6089. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  6090. mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
  6091. }
  6092. else if (constraint.point != null)
  6093. {
  6094. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_X :
  6095. mxConstants.STYLE_ENTRY_X, constraint.point.x, [edge]);
  6096. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_Y :
  6097. mxConstants.STYLE_ENTRY_Y, constraint.point.y, [edge]);
  6098. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DX :
  6099. mxConstants.STYLE_ENTRY_DX, constraint.dx, [edge]);
  6100. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_DY :
  6101. mxConstants.STYLE_ENTRY_DY, constraint.dy, [edge]);
  6102. // Only writes 0 since 1 is default
  6103. if (!constraint.perimeter)
  6104. {
  6105. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  6106. mxConstants.STYLE_ENTRY_PERIMETER, '0', [edge]);
  6107. }
  6108. else
  6109. {
  6110. this.setCellStyles((source) ? mxConstants.STYLE_EXIT_PERIMETER :
  6111. mxConstants.STYLE_ENTRY_PERIMETER, null, [edge]);
  6112. }
  6113. }
  6114. }
  6115. finally
  6116. {
  6117. this.model.endUpdate();
  6118. }
  6119. }
  6120. };
  6121. /**
  6122. * Function: getConnectionPoint
  6123. *
  6124. * Returns the nearest point in the list of absolute points or the center
  6125. * of the opposite terminal.
  6126. *
  6127. * Parameters:
  6128. *
  6129. * vertex - <mxCellState> that represents the vertex.
  6130. * constraint - <mxConnectionConstraint> that represents the connection point
  6131. * constraint as returned by <getConnectionConstraint>.
  6132. */
  6133. mxGraph.prototype.getConnectionPoint = function(vertex, constraint, round)
  6134. {
  6135. round = (round != null) ? round : true;
  6136. var point = null;
  6137. if (vertex != null && constraint.point != null)
  6138. {
  6139. var bounds = this.view.getPerimeterBounds(vertex);
  6140. var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
  6141. var direction = vertex.style[mxConstants.STYLE_DIRECTION];
  6142. var r1 = 0;
  6143. // Bounds need to be rotated by 90 degrees for further computation
  6144. if (direction != null && mxUtils.getValue(vertex.style,
  6145. mxConstants.STYLE_ANCHOR_POINT_DIRECTION, 1) == 1)
  6146. {
  6147. if (direction == mxConstants.DIRECTION_NORTH)
  6148. {
  6149. r1 += 270;
  6150. }
  6151. else if (direction == mxConstants.DIRECTION_WEST)
  6152. {
  6153. r1 += 180;
  6154. }
  6155. else if (direction == mxConstants.DIRECTION_SOUTH)
  6156. {
  6157. r1 += 90;
  6158. }
  6159. // Bounds need to be rotated by 90 degrees for further computation
  6160. if (direction == mxConstants.DIRECTION_NORTH ||
  6161. direction == mxConstants.DIRECTION_SOUTH)
  6162. {
  6163. bounds.rotate90();
  6164. }
  6165. }
  6166. var scale = this.view.scale;
  6167. point = new mxPoint(bounds.x + constraint.point.x * bounds.width + constraint.dx * scale,
  6168. bounds.y + constraint.point.y * bounds.height + constraint.dy * scale);
  6169. // Rotation for direction before projection on perimeter
  6170. var r2 = vertex.style[mxConstants.STYLE_ROTATION] || 0;
  6171. if (constraint.perimeter)
  6172. {
  6173. if (r1 != 0)
  6174. {
  6175. // Only 90 degrees steps possible here so no trig needed
  6176. var cos = 0;
  6177. var sin = 0;
  6178. if (r1 == 90)
  6179. {
  6180. sin = 1;
  6181. }
  6182. else if (r1 == 180)
  6183. {
  6184. cos = -1;
  6185. }
  6186. else if (r1 == 270)
  6187. {
  6188. sin = -1;
  6189. }
  6190. point = mxUtils.getRotatedPoint(point, cos, sin, cx);
  6191. }
  6192. point = this.view.getPerimeterPoint(vertex, point, false);
  6193. }
  6194. else
  6195. {
  6196. r2 += r1;
  6197. if (this.getModel().isVertex(vertex.cell))
  6198. {
  6199. var flipH = vertex.style[mxConstants.STYLE_FLIPH] == 1;
  6200. var flipV = vertex.style[mxConstants.STYLE_FLIPV] == 1;
  6201. // Legacy support for stencilFlipH/V
  6202. if (vertex.shape != null && vertex.shape.stencil != null)
  6203. {
  6204. flipH = (mxUtils.getValue(vertex.style, 'stencilFlipH', 0) == 1) || flipH;
  6205. flipV = (mxUtils.getValue(vertex.style, 'stencilFlipV', 0) == 1) || flipV;
  6206. }
  6207. if (direction == mxConstants.DIRECTION_NORTH ||
  6208. direction == mxConstants.DIRECTION_SOUTH)
  6209. {
  6210. var temp = flipH;
  6211. flipH = flipV
  6212. flipV = temp;
  6213. }
  6214. if (flipH)
  6215. {
  6216. point.x = 2 * bounds.getCenterX() - point.x;
  6217. }
  6218. if (flipV)
  6219. {
  6220. point.y = 2 * bounds.getCenterY() - point.y;
  6221. }
  6222. }
  6223. }
  6224. // Generic rotation after projection on perimeter
  6225. if (r2 != 0 && point != null)
  6226. {
  6227. var rad = mxUtils.toRadians(r2);
  6228. var cos = Math.cos(rad);
  6229. var sin = Math.sin(rad);
  6230. point = mxUtils.getRotatedPoint(point, cos, sin, cx);
  6231. }
  6232. }
  6233. if (round && point != null)
  6234. {
  6235. point.x = Math.round(point.x);
  6236. point.y = Math.round(point.y);
  6237. }
  6238. return point;
  6239. };
  6240. /**
  6241. * Function: connectCell
  6242. *
  6243. * Connects the specified end of the given edge to the given terminal
  6244. * using <cellConnected> and fires <mxEvent.CONNECT_CELL> while the
  6245. * transaction is in progress. Returns the updated edge.
  6246. *
  6247. * Parameters:
  6248. *
  6249. * edge - <mxCell> whose terminal should be updated.
  6250. * terminal - <mxCell> that represents the new terminal to be used.
  6251. * source - Boolean indicating if the new terminal is the source or target.
  6252. * constraint - Optional <mxConnectionConstraint> to be used for this
  6253. * connection.
  6254. */
  6255. mxGraph.prototype.connectCell = function(edge, terminal, source, constraint)
  6256. {
  6257. this.model.beginUpdate();
  6258. try
  6259. {
  6260. var previous = this.model.getTerminal(edge, source);
  6261. this.cellConnected(edge, terminal, source, constraint);
  6262. this.fireEvent(new mxEventObject(mxEvent.CONNECT_CELL,
  6263. 'edge', edge, 'terminal', terminal, 'source', source,
  6264. 'previous', previous));
  6265. }
  6266. finally
  6267. {
  6268. this.model.endUpdate();
  6269. }
  6270. return edge;
  6271. };
  6272. /**
  6273. * Function: cellConnected
  6274. *
  6275. * Sets the new terminal for the given edge and resets the edge points if
  6276. * <resetEdgesOnConnect> is true. This method fires
  6277. * <mxEvent.CELL_CONNECTED> while the transaction is in progress.
  6278. *
  6279. * Parameters:
  6280. *
  6281. * edge - <mxCell> whose terminal should be updated.
  6282. * terminal - <mxCell> that represents the new terminal to be used.
  6283. * source - Boolean indicating if the new terminal is the source or target.
  6284. * constraint - <mxConnectionConstraint> to be used for this connection.
  6285. */
  6286. mxGraph.prototype.cellConnected = function(edge, terminal, source, constraint)
  6287. {
  6288. if (edge != null)
  6289. {
  6290. this.model.beginUpdate();
  6291. try
  6292. {
  6293. var previous = this.model.getTerminal(edge, source);
  6294. // Updates the constraint
  6295. this.setConnectionConstraint(edge, terminal, source, constraint);
  6296. // Checks if the new terminal is a port, uses the ID of the port in the
  6297. // style and the parent of the port as the actual terminal of the edge.
  6298. if (this.isPortsEnabled())
  6299. {
  6300. var id = null;
  6301. if (this.isPort(terminal))
  6302. {
  6303. id = terminal.getId();
  6304. terminal = this.getTerminalForPort(terminal, source);
  6305. }
  6306. // Sets or resets all previous information for connecting to a child port
  6307. var key = (source) ? mxConstants.STYLE_SOURCE_PORT :
  6308. mxConstants.STYLE_TARGET_PORT;
  6309. this.setCellStyles(key, id, [edge]);
  6310. }
  6311. this.model.setTerminal(edge, terminal, source);
  6312. if (this.resetEdgesOnConnect)
  6313. {
  6314. this.resetEdge(edge);
  6315. }
  6316. this.fireEvent(new mxEventObject(mxEvent.CELL_CONNECTED,
  6317. 'edge', edge, 'terminal', terminal, 'source', source,
  6318. 'previous', previous));
  6319. }
  6320. finally
  6321. {
  6322. this.model.endUpdate();
  6323. }
  6324. }
  6325. };
  6326. /**
  6327. * Function: disconnectGraph
  6328. *
  6329. * Disconnects the given edges from the terminals which are not in the
  6330. * given array.
  6331. *
  6332. * Parameters:
  6333. *
  6334. * cells - Array of <mxCells> to be disconnected.
  6335. */
  6336. mxGraph.prototype.disconnectGraph = function(cells)
  6337. {
  6338. if (cells != null)
  6339. {
  6340. this.model.beginUpdate();
  6341. try
  6342. {
  6343. var scale = this.view.scale;
  6344. var tr = this.view.translate;
  6345. // Fast lookup for finding cells in array
  6346. var dict = new mxDictionary();
  6347. for (var i = 0; i < cells.length; i++)
  6348. {
  6349. dict.put(cells[i], true);
  6350. }
  6351. for (var i = 0; i < cells.length; i++)
  6352. {
  6353. if (this.model.isEdge(cells[i]))
  6354. {
  6355. var geo = this.model.getGeometry(cells[i]);
  6356. if (geo != null)
  6357. {
  6358. var state = this.view.getState(cells[i]);
  6359. var pstate = this.view.getState(
  6360. this.model.getParent(cells[i]));
  6361. if (state != null &&
  6362. pstate != null)
  6363. {
  6364. geo = geo.clone();
  6365. var dx = -pstate.origin.x;
  6366. var dy = -pstate.origin.y;
  6367. var pts = state.absolutePoints;
  6368. var src = this.model.getTerminal(cells[i], true);
  6369. if (src != null && this.isCellDisconnectable(cells[i], src, true))
  6370. {
  6371. while (src != null && !dict.get(src))
  6372. {
  6373. src = this.model.getParent(src);
  6374. }
  6375. if (src == null)
  6376. {
  6377. geo.setTerminalPoint(
  6378. new mxPoint(pts[0].x / scale - tr.x + dx,
  6379. pts[0].y / scale - tr.y + dy), true);
  6380. this.model.setTerminal(cells[i], null, true);
  6381. }
  6382. }
  6383. var trg = this.model.getTerminal(cells[i], false);
  6384. if (trg != null && this.isCellDisconnectable(cells[i], trg, false))
  6385. {
  6386. while (trg != null && !dict.get(trg))
  6387. {
  6388. trg = this.model.getParent(trg);
  6389. }
  6390. if (trg == null)
  6391. {
  6392. var n = pts.length - 1;
  6393. geo.setTerminalPoint(
  6394. new mxPoint(pts[n].x / scale - tr.x + dx,
  6395. pts[n].y / scale - tr.y + dy), false);
  6396. this.model.setTerminal(cells[i], null, false);
  6397. }
  6398. }
  6399. this.model.setGeometry(cells[i], geo);
  6400. }
  6401. }
  6402. }
  6403. }
  6404. }
  6405. finally
  6406. {
  6407. this.model.endUpdate();
  6408. }
  6409. }
  6410. };
  6411. /**
  6412. * Group: Drilldown
  6413. */
  6414. /**
  6415. * Function: getCurrentRoot
  6416. *
  6417. * Returns the current root of the displayed cell hierarchy. This is a
  6418. * shortcut to <mxGraphView.currentRoot> in <view>.
  6419. */
  6420. mxGraph.prototype.getCurrentRoot = function()
  6421. {
  6422. return this.view.currentRoot;
  6423. };
  6424. /**
  6425. * Function: getTranslateForRoot
  6426. *
  6427. * Returns the translation to be used if the given cell is the root cell as
  6428. * an <mxPoint>. This implementation returns null.
  6429. *
  6430. * Example:
  6431. *
  6432. * To keep the children at their absolute position while stepping into groups,
  6433. * this function can be overridden as follows.
  6434. *
  6435. * (code)
  6436. * var offset = new mxPoint(0, 0);
  6437. *
  6438. * while (cell != null)
  6439. * {
  6440. * var geo = this.model.getGeometry(cell);
  6441. *
  6442. * if (geo != null)
  6443. * {
  6444. * offset.x -= geo.x;
  6445. * offset.y -= geo.y;
  6446. * }
  6447. *
  6448. * cell = this.model.getParent(cell);
  6449. * }
  6450. *
  6451. * return offset;
  6452. * (end)
  6453. *
  6454. * Parameters:
  6455. *
  6456. * cell - <mxCell> that represents the root.
  6457. */
  6458. mxGraph.prototype.getTranslateForRoot = function(cell)
  6459. {
  6460. return null;
  6461. };
  6462. /**
  6463. * Function: isPort
  6464. *
  6465. * Returns true if the given cell is a "port", that is, when connecting to
  6466. * it, the cell returned by getTerminalForPort should be used as the
  6467. * terminal and the port should be referenced by the ID in either the
  6468. * mxConstants.STYLE_SOURCE_PORT or the or the
  6469. * mxConstants.STYLE_TARGET_PORT. Note that a port should not be movable.
  6470. * This implementation always returns false.
  6471. *
  6472. * A typical implementation is the following:
  6473. *
  6474. * (code)
  6475. * graph.isPort = function(cell)
  6476. * {
  6477. * var geo = this.getCellGeometry(cell);
  6478. *
  6479. * return (geo != null) ? geo.relative : false;
  6480. * };
  6481. * (end)
  6482. *
  6483. * Parameters:
  6484. *
  6485. * cell - <mxCell> that represents the port.
  6486. */
  6487. mxGraph.prototype.isPort = function(cell)
  6488. {
  6489. return false;
  6490. };
  6491. /**
  6492. * Function: getTerminalForPort
  6493. *
  6494. * Returns the terminal to be used for a given port. This implementation
  6495. * always returns the parent cell.
  6496. *
  6497. * Parameters:
  6498. *
  6499. * cell - <mxCell> that represents the port.
  6500. * source - If the cell is the source or target port.
  6501. */
  6502. mxGraph.prototype.getTerminalForPort = function(cell, source)
  6503. {
  6504. return this.model.getParent(cell);
  6505. };
  6506. /**
  6507. * Function: getChildOffsetForCell
  6508. *
  6509. * Returns the offset to be used for the cells inside the given cell. The
  6510. * root and layer cells may be identified using <mxGraphModel.isRoot> and
  6511. * <mxGraphModel.isLayer>. For all other current roots, the
  6512. * <mxGraphView.currentRoot> field points to the respective cell, so that
  6513. * the following holds: cell == this.view.currentRoot. This implementation
  6514. * returns null.
  6515. *
  6516. * Parameters:
  6517. *
  6518. * cell - <mxCell> whose offset should be returned.
  6519. */
  6520. mxGraph.prototype.getChildOffsetForCell = function(cell)
  6521. {
  6522. return null;
  6523. };
  6524. /**
  6525. * Function: enterGroup
  6526. *
  6527. * Uses the given cell as the root of the displayed cell hierarchy. If no
  6528. * cell is specified then the selection cell is used. The cell is only used
  6529. * if <isValidRoot> returns true.
  6530. *
  6531. * Parameters:
  6532. *
  6533. * cell - Optional <mxCell> to be used as the new root. Default is the
  6534. * selection cell.
  6535. */
  6536. mxGraph.prototype.enterGroup = function(cell)
  6537. {
  6538. cell = cell || this.getSelectionCell();
  6539. if (cell != null && this.isValidRoot(cell))
  6540. {
  6541. this.view.setCurrentRoot(cell);
  6542. this.clearSelection();
  6543. }
  6544. };
  6545. /**
  6546. * Function: exitGroup
  6547. *
  6548. * Changes the current root to the next valid root in the displayed cell
  6549. * hierarchy.
  6550. */
  6551. mxGraph.prototype.exitGroup = function()
  6552. {
  6553. var root = this.model.getRoot();
  6554. var current = this.getCurrentRoot();
  6555. if (current != null)
  6556. {
  6557. var next = this.model.getParent(current);
  6558. // Finds the next valid root in the hierarchy
  6559. while (next != root && !this.isValidRoot(next) &&
  6560. this.model.getParent(next) != root)
  6561. {
  6562. next = this.model.getParent(next);
  6563. }
  6564. // Clears the current root if the new root is
  6565. // the model's root or one of the layers.
  6566. if (next == root || this.model.getParent(next) == root)
  6567. {
  6568. this.view.setCurrentRoot(null);
  6569. }
  6570. else
  6571. {
  6572. this.view.setCurrentRoot(next);
  6573. }
  6574. var state = this.view.getState(current);
  6575. // Selects the previous root in the graph
  6576. if (state != null)
  6577. {
  6578. this.setSelectionCell(current);
  6579. }
  6580. }
  6581. };
  6582. /**
  6583. * Function: home
  6584. *
  6585. * Uses the root of the model as the root of the displayed cell hierarchy
  6586. * and selects the previous root.
  6587. */
  6588. mxGraph.prototype.home = function()
  6589. {
  6590. var current = this.getCurrentRoot();
  6591. if (current != null)
  6592. {
  6593. this.view.setCurrentRoot(null);
  6594. var state = this.view.getState(current);
  6595. if (state != null)
  6596. {
  6597. this.setSelectionCell(current);
  6598. }
  6599. }
  6600. };
  6601. /**
  6602. * Function: isValidRoot
  6603. *
  6604. * Returns true if the given cell is a valid root for the cell display
  6605. * hierarchy. This implementation returns true for all non-null values.
  6606. *
  6607. * Parameters:
  6608. *
  6609. * cell - <mxCell> which should be checked as a possible root.
  6610. */
  6611. mxGraph.prototype.isValidRoot = function(cell)
  6612. {
  6613. return (cell != null);
  6614. };
  6615. /**
  6616. * Group: Graph display
  6617. */
  6618. /**
  6619. * Function: getGraphBounds
  6620. *
  6621. * Returns the bounds of the visible graph. Shortcut to
  6622. * <mxGraphView.getGraphBounds>. See also: <getBoundingBoxFromGeometry>.
  6623. */
  6624. mxGraph.prototype.getGraphBounds = function()
  6625. {
  6626. return this.view.getGraphBounds();
  6627. };
  6628. /**
  6629. * Function: getCellBounds
  6630. *
  6631. * Returns the scaled, translated bounds for the given cell. See
  6632. * <mxGraphView.getBounds> for arrays.
  6633. *
  6634. * Parameters:
  6635. *
  6636. * cell - <mxCell> whose bounds should be returned.
  6637. * includeEdge - Optional boolean that specifies if the bounds of
  6638. * the connected edges should be included. Default is false.
  6639. * includeDescendants - Optional boolean that specifies if the bounds
  6640. * of all descendants should be included. Default is false.
  6641. */
  6642. mxGraph.prototype.getCellBounds = function(cell, includeEdges, includeDescendants)
  6643. {
  6644. var cells = [cell];
  6645. // Includes all connected edges
  6646. if (includeEdges)
  6647. {
  6648. cells = cells.concat(this.model.getEdges(cell));
  6649. }
  6650. var result = this.view.getBounds(cells);
  6651. // Recursively includes the bounds of the children
  6652. if (includeDescendants)
  6653. {
  6654. var childCount = this.model.getChildCount(cell);
  6655. for (var i = 0; i < childCount; i++)
  6656. {
  6657. var tmp = this.getCellBounds(this.model.getChildAt(cell, i),
  6658. includeEdges, true);
  6659. if (result != null)
  6660. {
  6661. result.add(tmp);
  6662. }
  6663. else
  6664. {
  6665. result = tmp;
  6666. }
  6667. }
  6668. }
  6669. return result;
  6670. };
  6671. /**
  6672. * Function: getBoundingBoxFromGeometry
  6673. *
  6674. * Returns the bounding box for the geometries of the vertices in the
  6675. * given array of cells. This can be used to find the graph bounds during
  6676. * a layout operation (ie. before the last endUpdate) as follows:
  6677. *
  6678. * (code)
  6679. * var cells = graph.getChildCells(graph.getDefaultParent(), true, true);
  6680. * var bounds = graph.getBoundingBoxFromGeometry(cells, true);
  6681. * (end)
  6682. *
  6683. * This can then be used to move cells to the origin:
  6684. *
  6685. * (code)
  6686. * if (bounds.x < 0 || bounds.y < 0)
  6687. * {
  6688. * graph.moveCells(cells, -Math.min(bounds.x, 0), -Math.min(bounds.y, 0))
  6689. * }
  6690. * (end)
  6691. *
  6692. * Or to translate the graph view:
  6693. *
  6694. * (code)
  6695. * if (bounds.x < 0 || bounds.y < 0)
  6696. * {
  6697. * graph.view.setTranslate(-Math.min(bounds.x, 0), -Math.min(bounds.y, 0));
  6698. * }
  6699. * (end)
  6700. *
  6701. * Parameters:
  6702. *
  6703. * cells - Array of <mxCells> whose bounds should be returned.
  6704. * includeEdges - Specifies if edge bounds should be included by computing
  6705. * the bounding box for all points in geometry. Default is false.
  6706. */
  6707. mxGraph.prototype.getBoundingBoxFromGeometry = function(cells, includeEdges)
  6708. {
  6709. includeEdges = (includeEdges != null) ? includeEdges : false;
  6710. var result = null;
  6711. if (cells != null)
  6712. {
  6713. for (var i = 0; i < cells.length; i++)
  6714. {
  6715. if (includeEdges || this.model.isVertex(cells[i]))
  6716. {
  6717. // Computes the bounding box for the points in the geometry
  6718. var geo = this.getCellGeometry(cells[i]);
  6719. if (geo != null)
  6720. {
  6721. var bbox = null;
  6722. if (this.model.isEdge(cells[i]))
  6723. {
  6724. var addPoint = function(pt)
  6725. {
  6726. if (pt != null)
  6727. {
  6728. if (tmp == null)
  6729. {
  6730. tmp = new mxRectangle(pt.x, pt.y, 0, 0);
  6731. }
  6732. else
  6733. {
  6734. tmp.add(new mxRectangle(pt.x, pt.y, 0, 0));
  6735. }
  6736. }
  6737. };
  6738. if (this.model.getTerminal(cells[i], true) == null)
  6739. {
  6740. addPoint(geo.getTerminalPoint(true));
  6741. }
  6742. if (this.model.getTerminal(cells[i], false) == null)
  6743. {
  6744. addPoint(geo.getTerminalPoint(false));
  6745. }
  6746. var pts = geo.points;
  6747. if (pts != null && pts.length > 0)
  6748. {
  6749. var tmp = new mxRectangle(pts[0].x, pts[0].y, 0, 0);
  6750. for (var j = 1; j < pts.length; j++)
  6751. {
  6752. addPoint(pts[j]);
  6753. }
  6754. }
  6755. bbox = tmp;
  6756. }
  6757. else
  6758. {
  6759. var parent = this.model.getParent(cells[i]);
  6760. if (geo.relative)
  6761. {
  6762. if (this.model.isVertex(parent) && parent != this.view.currentRoot)
  6763. {
  6764. var tmp = this.getBoundingBoxFromGeometry([parent], false);
  6765. if (tmp != null)
  6766. {
  6767. bbox = new mxRectangle(geo.x * tmp.width, geo.y * tmp.height, geo.width, geo.height);
  6768. if (mxUtils.indexOf(cells, parent) >= 0)
  6769. {
  6770. bbox.x += tmp.x;
  6771. bbox.y += tmp.y;
  6772. }
  6773. }
  6774. }
  6775. }
  6776. else
  6777. {
  6778. bbox = mxRectangle.fromRectangle(geo);
  6779. if (this.model.isVertex(parent) && mxUtils.indexOf(cells, parent) >= 0)
  6780. {
  6781. var tmp = this.getBoundingBoxFromGeometry([parent], false);
  6782. if (tmp != null)
  6783. {
  6784. bbox.x += tmp.x;
  6785. bbox.y += tmp.y;
  6786. }
  6787. }
  6788. }
  6789. if (bbox != null && geo.offset != null)
  6790. {
  6791. bbox.x += geo.offset.x;
  6792. bbox.y += geo.offset.y;
  6793. }
  6794. var style = this.getCurrentCellStyle(cells[i]);
  6795. if (bbox != null)
  6796. {
  6797. var angle = mxUtils.getValue(style, mxConstants.STYLE_ROTATION, 0);
  6798. if (angle != 0)
  6799. {
  6800. bbox = mxUtils.getBoundingBox(bbox, angle);
  6801. }
  6802. }
  6803. }
  6804. if (bbox != null)
  6805. {
  6806. if (result == null)
  6807. {
  6808. result = mxRectangle.fromRectangle(bbox);
  6809. }
  6810. else
  6811. {
  6812. result.add(bbox);
  6813. }
  6814. }
  6815. }
  6816. }
  6817. }
  6818. }
  6819. return result;
  6820. };
  6821. /**
  6822. * Function: refresh
  6823. *
  6824. * Clears all cell states or the states for the hierarchy starting at the
  6825. * given cell and validates the graph. This fires a refresh event as the
  6826. * last step.
  6827. *
  6828. * Parameters:
  6829. *
  6830. * cell - Optional <mxCell> for which the cell states should be cleared.
  6831. */
  6832. mxGraph.prototype.refresh = function(cell)
  6833. {
  6834. this.view.clear(cell, cell == null);
  6835. this.view.validate();
  6836. this.sizeDidChange();
  6837. this.fireEvent(new mxEventObject(mxEvent.REFRESH));
  6838. };
  6839. /**
  6840. * Function: snap
  6841. *
  6842. * Snaps the given numeric value to the grid if <gridEnabled> is true.
  6843. *
  6844. * Parameters:
  6845. *
  6846. * value - Numeric value to be snapped to the grid.
  6847. */
  6848. mxGraph.prototype.snap = function(value)
  6849. {
  6850. if (this.gridEnabled)
  6851. {
  6852. value = Math.round(value / this.gridSize ) * this.gridSize;
  6853. }
  6854. return value;
  6855. };
  6856. /**
  6857. * Function: snapDelta
  6858. *
  6859. * Snaps the given delta with the given scaled bounds.
  6860. */
  6861. mxGraph.prototype.snapDelta = function(delta, bounds, ignoreGrid, ignoreHorizontal, ignoreVertical)
  6862. {
  6863. var t = this.view.translate;
  6864. var s = this.view.scale;
  6865. if (!ignoreGrid && this.gridEnabled)
  6866. {
  6867. var tol = this.gridSize * s * 0.5;
  6868. if (!ignoreHorizontal)
  6869. {
  6870. var tx = bounds.x - (this.snap(bounds.x / s - t.x) + t.x) * s;
  6871. if (Math.abs(delta.x- tx) < tol)
  6872. {
  6873. delta.x = 0;
  6874. }
  6875. else
  6876. {
  6877. delta.x = this.snap(delta.x / s) * s - tx;
  6878. }
  6879. }
  6880. if (!ignoreVertical)
  6881. {
  6882. var ty = bounds.y - (this.snap(bounds.y / s - t.y) + t.y) * s;
  6883. if (Math.abs(delta.y - ty) < tol)
  6884. {
  6885. delta.y = 0;
  6886. }
  6887. else
  6888. {
  6889. delta.y = this.snap(delta.y / s) * s - ty;
  6890. }
  6891. }
  6892. }
  6893. else
  6894. {
  6895. var tol = 0.5 * s;
  6896. if (!ignoreHorizontal)
  6897. {
  6898. var tx = bounds.x - (Math.round(bounds.x / s - t.x) + t.x) * s;
  6899. if (Math.abs(delta.x - tx) < tol)
  6900. {
  6901. delta.x = 0;
  6902. }
  6903. else
  6904. {
  6905. delta.x = Math.round(delta.x / s) * s - tx;
  6906. }
  6907. }
  6908. if (!ignoreVertical)
  6909. {
  6910. var ty = bounds.y - (Math.round(bounds.y / s - t.y) + t.y) * s;
  6911. if (Math.abs(delta.y - ty) < tol)
  6912. {
  6913. delta.y = 0;
  6914. }
  6915. else
  6916. {
  6917. delta.y = Math.round(delta.y / s) * s - ty;
  6918. }
  6919. }
  6920. }
  6921. return delta;
  6922. };
  6923. /**
  6924. * Function: panGraph
  6925. *
  6926. * Shifts the graph display by the given amount. This is used to preview
  6927. * panning operations, use <mxGraphView.setTranslate> to set a persistent
  6928. * translation of the view. Fires <mxEvent.PAN>.
  6929. *
  6930. * Parameters:
  6931. *
  6932. * dx - Amount to shift the graph along the x-axis.
  6933. * dy - Amount to shift the graph along the y-axis.
  6934. */
  6935. mxGraph.prototype.panGraph = function(dx, dy)
  6936. {
  6937. if (this.useScrollbarsForPanning && mxUtils.hasScrollbars(this.container))
  6938. {
  6939. this.container.scrollLeft = -dx;
  6940. this.container.scrollTop = -dy;
  6941. }
  6942. else
  6943. {
  6944. var canvas = this.view.getCanvas();
  6945. if (this.dialect == mxConstants.DIALECT_SVG)
  6946. {
  6947. // Puts everything inside the container in a DIV so that it
  6948. // can be moved without changing the state of the container
  6949. if (dx == 0 && dy == 0)
  6950. {
  6951. // Workaround for ignored removeAttribute on SVG element in IE9 standards
  6952. if (mxClient.IS_IE)
  6953. {
  6954. canvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
  6955. }
  6956. else
  6957. {
  6958. canvas.removeAttribute('transform');
  6959. }
  6960. if (this.shiftPreview1 != null)
  6961. {
  6962. var child = this.shiftPreview1.firstChild;
  6963. while (child != null)
  6964. {
  6965. var next = child.nextSibling;
  6966. this.container.appendChild(child);
  6967. child = next;
  6968. }
  6969. if (this.shiftPreview1.parentNode != null)
  6970. {
  6971. this.shiftPreview1.parentNode.removeChild(this.shiftPreview1);
  6972. }
  6973. this.shiftPreview1 = null;
  6974. this.container.appendChild(canvas.parentNode);
  6975. child = this.shiftPreview2.firstChild;
  6976. while (child != null)
  6977. {
  6978. var next = child.nextSibling;
  6979. this.container.appendChild(child);
  6980. child = next;
  6981. }
  6982. if (this.shiftPreview2.parentNode != null)
  6983. {
  6984. this.shiftPreview2.parentNode.removeChild(this.shiftPreview2);
  6985. }
  6986. this.shiftPreview2 = null;
  6987. }
  6988. }
  6989. else
  6990. {
  6991. canvas.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
  6992. if (this.shiftPreview1 == null)
  6993. {
  6994. // Needs two divs for stuff before and after the SVG element
  6995. this.shiftPreview1 = document.createElement('div');
  6996. this.shiftPreview1.style.position = 'absolute';
  6997. this.shiftPreview1.style.overflow = 'visible';
  6998. this.shiftPreview2 = document.createElement('div');
  6999. this.shiftPreview2.style.position = 'absolute';
  7000. this.shiftPreview2.style.overflow = 'visible';
  7001. var current = this.shiftPreview1;
  7002. var child = this.container.firstChild;
  7003. while (child != null)
  7004. {
  7005. var next = child.nextSibling;
  7006. // SVG element is moved via transform attribute
  7007. if (child != canvas.parentNode)
  7008. {
  7009. current.appendChild(child);
  7010. }
  7011. else
  7012. {
  7013. current = this.shiftPreview2;
  7014. }
  7015. child = next;
  7016. }
  7017. // Inserts elements only if not empty
  7018. if (this.shiftPreview1.firstChild != null)
  7019. {
  7020. this.container.insertBefore(this.shiftPreview1, canvas.parentNode);
  7021. }
  7022. if (this.shiftPreview2.firstChild != null)
  7023. {
  7024. this.container.appendChild(this.shiftPreview2);
  7025. }
  7026. }
  7027. this.shiftPreview1.style.left = dx + 'px';
  7028. this.shiftPreview1.style.top = dy + 'px';
  7029. this.shiftPreview2.style.left = dx + 'px';
  7030. this.shiftPreview2.style.top = dy + 'px';
  7031. }
  7032. }
  7033. else
  7034. {
  7035. canvas.style.left = dx + 'px';
  7036. canvas.style.top = dy + 'px';
  7037. }
  7038. this.panDx = dx;
  7039. this.panDy = dy;
  7040. this.fireEvent(new mxEventObject(mxEvent.PAN));
  7041. }
  7042. };
  7043. /**
  7044. * Function: zoomIn
  7045. *
  7046. * Zooms into the graph by <zoomFactor>.
  7047. */
  7048. mxGraph.prototype.zoomIn = function()
  7049. {
  7050. this.zoom(this.zoomFactor);
  7051. };
  7052. /**
  7053. * Function: zoomOut
  7054. *
  7055. * Zooms out of the graph by <zoomFactor>.
  7056. */
  7057. mxGraph.prototype.zoomOut = function()
  7058. {
  7059. this.zoom(1 / this.zoomFactor);
  7060. };
  7061. /**
  7062. * Function: zoomActual
  7063. *
  7064. * Resets the zoom and panning in the view.
  7065. */
  7066. mxGraph.prototype.zoomActual = function()
  7067. {
  7068. if (this.view.scale == 1)
  7069. {
  7070. this.view.setTranslate(0, 0);
  7071. }
  7072. else
  7073. {
  7074. this.view.translate.x = 0;
  7075. this.view.translate.y = 0;
  7076. this.view.setScale(1);
  7077. }
  7078. };
  7079. /**
  7080. * Function: zoomTo
  7081. *
  7082. * Zooms the graph to the given scale with an optional boolean center
  7083. * argument, which is passd to <zoom>.
  7084. */
  7085. mxGraph.prototype.zoomTo = function(scale, center)
  7086. {
  7087. this.zoom(scale / this.view.scale, center);
  7088. };
  7089. /**
  7090. * Function: center
  7091. *
  7092. * Centers the graph in the container.
  7093. *
  7094. * Parameters:
  7095. *
  7096. * horizontal - Optional boolean that specifies if the graph should be centered
  7097. * horizontally. Default is true.
  7098. * vertical - Optional boolean that specifies if the graph should be centered
  7099. * vertically. Default is true.
  7100. * cx - Optional float that specifies the horizontal center. Default is 0.5.
  7101. * cy - Optional float that specifies the vertical center. Default is 0.5.
  7102. */
  7103. mxGraph.prototype.center = function(horizontal, vertical, cx, cy)
  7104. {
  7105. horizontal = (horizontal != null) ? horizontal : true;
  7106. vertical = (vertical != null) ? vertical : true;
  7107. cx = (cx != null) ? cx : 0.5;
  7108. cy = (cy != null) ? cy : 0.5;
  7109. var hasScrollbars = mxUtils.hasScrollbars(this.container);
  7110. var padding = 2 * this.getBorder();
  7111. var cw = this.container.clientWidth - padding;
  7112. var ch = this.container.clientHeight - padding;
  7113. var bounds = this.getGraphBounds();
  7114. var t = this.view.translate;
  7115. var s = this.view.scale;
  7116. var dx = (horizontal) ? cw - bounds.width : 0;
  7117. var dy = (vertical) ? ch - bounds.height : 0;
  7118. if (!hasScrollbars)
  7119. {
  7120. this.view.setTranslate((horizontal) ? Math.floor(t.x - bounds.x * s + dx * cx / s) : t.x,
  7121. (vertical) ? Math.floor(t.y - bounds.y * s + dy * cy / s) : t.y);
  7122. }
  7123. else
  7124. {
  7125. bounds.x -= t.x;
  7126. bounds.y -= t.y;
  7127. var sw = this.container.scrollWidth;
  7128. var sh = this.container.scrollHeight;
  7129. if (sw > cw)
  7130. {
  7131. dx = 0;
  7132. }
  7133. if (sh > ch)
  7134. {
  7135. dy = 0;
  7136. }
  7137. this.view.setTranslate(Math.floor(dx / 2 - bounds.x), Math.floor(dy / 2 - bounds.y));
  7138. this.container.scrollLeft = (sw - cw) / 2;
  7139. this.container.scrollTop = (sh - ch) / 2;
  7140. }
  7141. };
  7142. /**
  7143. * Function: zoom
  7144. *
  7145. * Zooms the graph using the given factor. Center is an optional boolean
  7146. * argument that keeps the graph scrolled to the center. If the center argument
  7147. * is omitted, then <centerZoom> will be used as its value.
  7148. */
  7149. mxGraph.prototype.zoom = function(factor, center)
  7150. {
  7151. center = (center != null) ? center : this.centerZoom;
  7152. var scale = Math.round(this.view.scale * factor * 100) / 100;
  7153. var state = this.view.getState(this.getSelectionCell());
  7154. factor = scale / this.view.scale;
  7155. if (this.keepSelectionVisibleOnZoom && state != null)
  7156. {
  7157. var rect = new mxRectangle(state.x * factor, state.y * factor,
  7158. state.width * factor, state.height * factor);
  7159. // Refreshes the display only once if a scroll is carried out
  7160. this.view.scale = scale;
  7161. if (!this.scrollRectToVisible(rect))
  7162. {
  7163. this.view.revalidate();
  7164. // Forces an event to be fired but does not revalidate again
  7165. this.view.setScale(scale);
  7166. }
  7167. }
  7168. else
  7169. {
  7170. var hasScrollbars = mxUtils.hasScrollbars(this.container);
  7171. if (center && !hasScrollbars)
  7172. {
  7173. var dx = this.container.offsetWidth;
  7174. var dy = this.container.offsetHeight;
  7175. if (factor > 1)
  7176. {
  7177. var f = (factor - 1) / (scale * 2);
  7178. dx *= -f;
  7179. dy *= -f;
  7180. }
  7181. else
  7182. {
  7183. var f = (1 / factor - 1) / (this.view.scale * 2);
  7184. dx *= f;
  7185. dy *= f;
  7186. }
  7187. this.view.scaleAndTranslate(scale,
  7188. this.view.translate.x + dx,
  7189. this.view.translate.y + dy);
  7190. }
  7191. else
  7192. {
  7193. // Allows for changes of translate and scrollbars during setscale
  7194. var tx = this.view.translate.x;
  7195. var ty = this.view.translate.y;
  7196. var sl = this.container.scrollLeft;
  7197. var st = this.container.scrollTop;
  7198. this.view.setScale(scale);
  7199. if (hasScrollbars)
  7200. {
  7201. var dx = 0;
  7202. var dy = 0;
  7203. if (center)
  7204. {
  7205. dx = this.container.offsetWidth * (factor - 1) / 2;
  7206. dy = this.container.offsetHeight * (factor - 1) / 2;
  7207. }
  7208. this.container.scrollLeft = (this.view.translate.x - tx) * this.view.scale + Math.round(sl * factor + dx);
  7209. this.container.scrollTop = (this.view.translate.y - ty) * this.view.scale + Math.round(st * factor + dy);
  7210. }
  7211. }
  7212. }
  7213. };
  7214. /**
  7215. * Function: zoomToRect
  7216. *
  7217. * Zooms the graph to the specified rectangle. If the rectangle does not have same aspect
  7218. * ratio as the display container, it is increased in the smaller relative dimension only
  7219. * until the aspect match. The original rectangle is centralised within this expanded one.
  7220. *
  7221. * Note that the input rectangular must be un-scaled and un-translated.
  7222. *
  7223. * Parameters:
  7224. *
  7225. * rect - The un-scaled and un-translated rectangluar region that should be just visible
  7226. * after the operation
  7227. */
  7228. mxGraph.prototype.zoomToRect = function(rect)
  7229. {
  7230. var scaleX = this.container.clientWidth / rect.width;
  7231. var scaleY = this.container.clientHeight / rect.height;
  7232. var aspectFactor = scaleX / scaleY;
  7233. // Remove any overlap of the rect outside the client area
  7234. rect.x = Math.max(0, rect.x);
  7235. rect.y = Math.max(0, rect.y);
  7236. var rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
  7237. var rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
  7238. rect.width = rectRight - rect.x;
  7239. rect.height = rectBottom - rect.y;
  7240. // The selection area has to be increased to the same aspect
  7241. // ratio as the container, centred around the centre point of the
  7242. // original rect passed in.
  7243. if (aspectFactor < 1.0)
  7244. {
  7245. // Height needs increasing
  7246. var newHeight = rect.height / aspectFactor;
  7247. var deltaHeightBuffer = (newHeight - rect.height) / 2.0;
  7248. rect.height = newHeight;
  7249. // Assign up to half the buffer to the upper part of the rect, not crossing 0
  7250. // put the rest on the bottom
  7251. var upperBuffer = Math.min(rect.y , deltaHeightBuffer);
  7252. rect.y = rect.y - upperBuffer;
  7253. // Check if the bottom has extended too far
  7254. rectBottom = Math.min(this.container.scrollHeight, rect.y + rect.height);
  7255. rect.height = rectBottom - rect.y;
  7256. }
  7257. else
  7258. {
  7259. // Width needs increasing
  7260. var newWidth = rect.width * aspectFactor;
  7261. var deltaWidthBuffer = (newWidth - rect.width) / 2.0;
  7262. rect.width = newWidth;
  7263. // Assign up to half the buffer to the upper part of the rect, not crossing 0
  7264. // put the rest on the bottom
  7265. var leftBuffer = Math.min(rect.x , deltaWidthBuffer);
  7266. rect.x = rect.x - leftBuffer;
  7267. // Check if the right hand side has extended too far
  7268. rectRight = Math.min(this.container.scrollWidth, rect.x + rect.width);
  7269. rect.width = rectRight - rect.x;
  7270. }
  7271. var scale = this.container.clientWidth / rect.width;
  7272. var newScale = this.view.scale * scale;
  7273. if (!mxUtils.hasScrollbars(this.container))
  7274. {
  7275. this.view.scaleAndTranslate(newScale, (this.view.translate.x - rect.x / this.view.scale), (this.view.translate.y - rect.y / this.view.scale));
  7276. }
  7277. else
  7278. {
  7279. this.view.setScale(newScale);
  7280. this.container.scrollLeft = Math.round(rect.x * scale);
  7281. this.container.scrollTop = Math.round(rect.y * scale);
  7282. }
  7283. };
  7284. /**
  7285. * Function: scrollCellToVisible
  7286. *
  7287. * Pans the graph so that it shows the given cell. Optionally the cell may
  7288. * be centered in the container.
  7289. *
  7290. * To center a given graph if the <container> has no scrollbars, use the following code.
  7291. *
  7292. * [code]
  7293. * var bounds = graph.getGraphBounds();
  7294. * graph.view.setTranslate(-bounds.x - (bounds.width - container.clientWidth) / 2,
  7295. * -bounds.y - (bounds.height - container.clientHeight) / 2);
  7296. * [/code]
  7297. *
  7298. * Parameters:
  7299. *
  7300. * cell - <mxCell> to be made visible.
  7301. * center - Optional boolean flag. Default is false.
  7302. */
  7303. mxGraph.prototype.scrollCellToVisible = function(cell, center)
  7304. {
  7305. var x = -this.view.translate.x;
  7306. var y = -this.view.translate.y;
  7307. var state = this.view.getState(cell);
  7308. if (state != null)
  7309. {
  7310. var bounds = new mxRectangle(x + state.x, y + state.y, state.width,
  7311. state.height);
  7312. if (center && this.container != null)
  7313. {
  7314. var w = this.container.clientWidth;
  7315. var h = this.container.clientHeight;
  7316. bounds.x = bounds.getCenterX() - w / 2;
  7317. bounds.width = w;
  7318. bounds.y = bounds.getCenterY() - h / 2;
  7319. bounds.height = h;
  7320. }
  7321. var tr = new mxPoint(this.view.translate.x, this.view.translate.y);
  7322. if (this.scrollRectToVisible(bounds))
  7323. {
  7324. // Triggers an update via the view's event source
  7325. var tr2 = new mxPoint(this.view.translate.x, this.view.translate.y);
  7326. this.view.translate.x = tr.x;
  7327. this.view.translate.y = tr.y;
  7328. this.view.setTranslate(tr2.x, tr2.y);
  7329. }
  7330. }
  7331. };
  7332. /**
  7333. * Function: scrollRectToVisible
  7334. *
  7335. * Pans the graph so that it shows the given rectangle.
  7336. *
  7337. * Parameters:
  7338. *
  7339. * rect - <mxRectangle> to be made visible.
  7340. */
  7341. mxGraph.prototype.scrollRectToVisible = function(rect)
  7342. {
  7343. var isChanged = false;
  7344. if (rect != null)
  7345. {
  7346. var w = this.container.offsetWidth;
  7347. var h = this.container.offsetHeight;
  7348. var widthLimit = Math.min(w, rect.width);
  7349. var heightLimit = Math.min(h, rect.height);
  7350. if (mxUtils.hasScrollbars(this.container))
  7351. {
  7352. var c = this.container;
  7353. rect.x += this.view.translate.x;
  7354. rect.y += this.view.translate.y;
  7355. var dx = c.scrollLeft - rect.x;
  7356. var ddx = Math.max(dx - c.scrollLeft, 0);
  7357. if (dx > 0)
  7358. {
  7359. c.scrollLeft -= dx + 2;
  7360. }
  7361. else
  7362. {
  7363. dx = rect.x + widthLimit - c.scrollLeft - c.clientWidth;
  7364. if (dx > 0)
  7365. {
  7366. c.scrollLeft += dx + 2;
  7367. }
  7368. }
  7369. var dy = c.scrollTop - rect.y;
  7370. var ddy = Math.max(0, dy - c.scrollTop);
  7371. if (dy > 0)
  7372. {
  7373. c.scrollTop -= dy + 2;
  7374. }
  7375. else
  7376. {
  7377. dy = rect.y + heightLimit - c.scrollTop - c.clientHeight;
  7378. if (dy > 0)
  7379. {
  7380. c.scrollTop += dy + 2;
  7381. }
  7382. }
  7383. if (!this.useScrollbarsForPanning && (ddx != 0 || ddy != 0))
  7384. {
  7385. this.view.setTranslate(ddx, ddy);
  7386. }
  7387. }
  7388. else
  7389. {
  7390. var x = -this.view.translate.x;
  7391. var y = -this.view.translate.y;
  7392. var s = this.view.scale;
  7393. if (rect.x + widthLimit > x + w)
  7394. {
  7395. this.view.translate.x -= (rect.x + widthLimit - w - x) / s;
  7396. isChanged = true;
  7397. }
  7398. if (rect.y + heightLimit > y + h)
  7399. {
  7400. this.view.translate.y -= (rect.y + heightLimit - h - y) / s;
  7401. isChanged = true;
  7402. }
  7403. if (rect.x < x)
  7404. {
  7405. this.view.translate.x += (x - rect.x) / s;
  7406. isChanged = true;
  7407. }
  7408. if (rect.y < y)
  7409. {
  7410. this.view.translate.y += (y - rect.y) / s;
  7411. isChanged = true;
  7412. }
  7413. if (isChanged)
  7414. {
  7415. this.view.refresh();
  7416. // Repaints selection marker (ticket 18)
  7417. if (this.selectionCellsHandler != null)
  7418. {
  7419. this.selectionCellsHandler.refresh();
  7420. }
  7421. }
  7422. }
  7423. }
  7424. return isChanged;
  7425. };
  7426. /**
  7427. * Function: getCellGeometry
  7428. *
  7429. * Returns the <mxGeometry> for the given cell. This implementation uses
  7430. * <mxGraphModel.getGeometry>. Subclasses can override this to implement
  7431. * specific geometries for cells in only one graph, that is, it can return
  7432. * geometries that depend on the current state of the view.
  7433. *
  7434. * Parameters:
  7435. *
  7436. * cell - <mxCell> whose geometry should be returned.
  7437. */
  7438. mxGraph.prototype.getCellGeometry = function(cell)
  7439. {
  7440. return this.model.getGeometry(cell);
  7441. };
  7442. /**
  7443. * Function: isCellVisible
  7444. *
  7445. * Returns true if the given cell is visible in this graph. This
  7446. * implementation uses <mxGraphModel.isVisible>. Subclassers can override
  7447. * this to implement specific visibility for cells in only one graph, that
  7448. * is, without affecting the visible state of the cell.
  7449. *
  7450. * When using dynamic filter expressions for cell visibility, then the
  7451. * graph should be revalidated after the filter expression has changed.
  7452. *
  7453. * Parameters:
  7454. *
  7455. * cell - <mxCell> whose visible state should be returned.
  7456. */
  7457. mxGraph.prototype.isCellVisible = function(cell)
  7458. {
  7459. return this.model.isVisible(cell);
  7460. };
  7461. /**
  7462. * Function: isCellCollapsed
  7463. *
  7464. * Returns true if the given cell is collapsed in this graph. This
  7465. * implementation uses <mxGraphModel.isCollapsed>. Subclassers can override
  7466. * this to implement specific collapsed states for cells in only one graph,
  7467. * that is, without affecting the collapsed state of the cell.
  7468. *
  7469. * When using dynamic filter expressions for the collapsed state, then the
  7470. * graph should be revalidated after the filter expression has changed.
  7471. *
  7472. * Parameters:
  7473. *
  7474. * cell - <mxCell> whose collapsed state should be returned.
  7475. */
  7476. mxGraph.prototype.isCellCollapsed = function(cell)
  7477. {
  7478. return this.model.isCollapsed(cell);
  7479. };
  7480. /**
  7481. * Function: isCellConnectable
  7482. *
  7483. * Returns true if the given cell is connectable in this graph. This
  7484. * implementation uses <mxGraphModel.isConnectable>. Subclassers can override
  7485. * this to implement specific connectable states for cells in only one graph,
  7486. * that is, without affecting the connectable state of the cell in the model.
  7487. *
  7488. * Parameters:
  7489. *
  7490. * cell - <mxCell> whose connectable state should be returned.
  7491. */
  7492. mxGraph.prototype.isCellConnectable = function(cell)
  7493. {
  7494. return this.model.isConnectable(cell);
  7495. };
  7496. /**
  7497. * Function: isOrthogonal
  7498. *
  7499. * Returns true if perimeter points should be computed such that the
  7500. * resulting edge has only horizontal or vertical segments.
  7501. *
  7502. * Parameters:
  7503. *
  7504. * edge - <mxCellState> that represents the edge.
  7505. */
  7506. mxGraph.prototype.isOrthogonal = function(edge)
  7507. {
  7508. var orthogonal = edge.style[mxConstants.STYLE_ORTHOGONAL];
  7509. if (orthogonal != null)
  7510. {
  7511. return orthogonal;
  7512. }
  7513. var tmp = this.view.getEdgeStyle(edge);
  7514. return tmp == mxEdgeStyle.SegmentConnector ||
  7515. tmp == mxEdgeStyle.ElbowConnector ||
  7516. tmp == mxEdgeStyle.SideToSide ||
  7517. tmp == mxEdgeStyle.TopToBottom ||
  7518. tmp == mxEdgeStyle.EntityRelation ||
  7519. tmp == mxEdgeStyle.OrthConnector;
  7520. };
  7521. /**
  7522. * Function: isLoop
  7523. *
  7524. * Returns true if the given cell state is a loop.
  7525. *
  7526. * Parameters:
  7527. *
  7528. * state - <mxCellState> that represents a potential loop.
  7529. */
  7530. mxGraph.prototype.isLoop = function(state)
  7531. {
  7532. var src = state.getVisibleTerminalState(true);
  7533. var trg = state.getVisibleTerminalState(false);
  7534. return (src != null && src == trg);
  7535. };
  7536. /**
  7537. * Function: isCloneEvent
  7538. *
  7539. * Returns true if the given event is a clone event. This implementation
  7540. * returns true if control is pressed.
  7541. */
  7542. mxGraph.prototype.isCloneEvent = function(evt)
  7543. {
  7544. return mxEvent.isControlDown(evt);
  7545. };
  7546. /**
  7547. * Function: isTransparentClickEvent
  7548. *
  7549. * Hook for implementing click-through behaviour on selected cells. If this
  7550. * returns true the cell behind the selected cell will be selected. This
  7551. * implementation returns false;
  7552. */
  7553. mxGraph.prototype.isTransparentClickEvent = function(evt)
  7554. {
  7555. return false;
  7556. };
  7557. /**
  7558. * Function: isToggleEvent
  7559. *
  7560. * Returns true if the given event is a toggle event. This implementation
  7561. * returns true if the meta key (Cmd) is pressed on Macs or if control is
  7562. * pressed on any other platform.
  7563. */
  7564. mxGraph.prototype.isToggleEvent = function(evt)
  7565. {
  7566. return (mxClient.IS_MAC) ? mxEvent.isMetaDown(evt) : mxEvent.isControlDown(evt);
  7567. };
  7568. /**
  7569. * Function: isGridEnabledEvent
  7570. *
  7571. * Returns true if the given mouse event should be aligned to the grid.
  7572. */
  7573. mxGraph.prototype.isGridEnabledEvent = function(evt)
  7574. {
  7575. return evt != null && !mxEvent.isAltDown(evt);
  7576. };
  7577. /**
  7578. * Function: isConstrainedEvent
  7579. *
  7580. * Returns true if the given mouse event should be aligned to the grid.
  7581. */
  7582. mxGraph.prototype.isConstrainedEvent = function(evt)
  7583. {
  7584. return mxEvent.isShiftDown(evt);
  7585. };
  7586. /**
  7587. * Function: isIgnoreTerminalEvent
  7588. *
  7589. * Returns true if the given mouse event should not allow any connections to be
  7590. * made. This implementation returns false.
  7591. */
  7592. mxGraph.prototype.isIgnoreTerminalEvent = function(evt)
  7593. {
  7594. return false;
  7595. };
  7596. /**
  7597. * Group: Validation
  7598. */
  7599. /**
  7600. * Function: validationAlert
  7601. *
  7602. * Displays the given validation error in a dialog. This implementation uses
  7603. * mxUtils.alert.
  7604. */
  7605. mxGraph.prototype.validationAlert = function(message)
  7606. {
  7607. mxUtils.alert(message);
  7608. };
  7609. /**
  7610. * Function: isEdgeValid
  7611. *
  7612. * Checks if the return value of <getEdgeValidationError> for the given
  7613. * arguments is null.
  7614. *
  7615. * Parameters:
  7616. *
  7617. * edge - <mxCell> that represents the edge to validate.
  7618. * source - <mxCell> that represents the source terminal.
  7619. * target - <mxCell> that represents the target terminal.
  7620. */
  7621. mxGraph.prototype.isEdgeValid = function(edge, source, target)
  7622. {
  7623. return this.getEdgeValidationError(edge, source, target) == null;
  7624. };
  7625. /**
  7626. * Function: getEdgeValidationError
  7627. *
  7628. * Returns the validation error message to be displayed when inserting or
  7629. * changing an edges' connectivity. A return value of null means the edge
  7630. * is valid, a return value of '' means it's not valid, but do not display
  7631. * an error message. Any other (non-empty) string returned from this method
  7632. * is displayed as an error message when trying to connect an edge to a
  7633. * source and target. This implementation uses the <multiplicities>, and
  7634. * checks <multigraph>, <allowDanglingEdges> and <allowLoops> to generate
  7635. * validation errors.
  7636. *
  7637. * For extending this method with specific checks for source/target cells,
  7638. * the method can be extended as follows. Returning an empty string means
  7639. * the edge is invalid with no error message, a non-null string specifies
  7640. * the error message, and null means the edge is valid.
  7641. *
  7642. * (code)
  7643. * graph.getEdgeValidationError = function(edge, source, target)
  7644. * {
  7645. * if (source != null && target != null &&
  7646. * this.model.getValue(source) != null &&
  7647. * this.model.getValue(target) != null)
  7648. * {
  7649. * if (target is not valid for source)
  7650. * {
  7651. * return 'Invalid Target';
  7652. * }
  7653. * }
  7654. *
  7655. * // "Supercall"
  7656. * return mxGraph.prototype.getEdgeValidationError.apply(this, arguments);
  7657. * }
  7658. * (end)
  7659. *
  7660. * Parameters:
  7661. *
  7662. * edge - <mxCell> that represents the edge to validate.
  7663. * source - <mxCell> that represents the source terminal.
  7664. * target - <mxCell> that represents the target terminal.
  7665. */
  7666. mxGraph.prototype.getEdgeValidationError = function(edge, source, target)
  7667. {
  7668. if (edge != null && !this.isAllowDanglingEdges() && (source == null || target == null))
  7669. {
  7670. return '';
  7671. }
  7672. if (edge != null && this.model.getTerminal(edge, true) == null &&
  7673. this.model.getTerminal(edge, false) == null)
  7674. {
  7675. return null;
  7676. }
  7677. // Checks if we're dealing with a loop
  7678. if (!this.allowLoops && source == target && source != null)
  7679. {
  7680. return '';
  7681. }
  7682. // Checks if the connection is generally allowed
  7683. if (!this.isValidConnection(source, target))
  7684. {
  7685. return '';
  7686. }
  7687. if (source != null && target != null)
  7688. {
  7689. var error = '';
  7690. // Checks if the cells are already connected
  7691. // and adds an error message if required
  7692. if (!this.multigraph)
  7693. {
  7694. var tmp = this.model.getEdgesBetween(source, target, true);
  7695. // Checks if the source and target are not connected by another edge
  7696. if (tmp.length > 1 || (tmp.length == 1 && tmp[0] != edge))
  7697. {
  7698. error += (mxResources.get(this.alreadyConnectedResource) ||
  7699. this.alreadyConnectedResource)+'\n';
  7700. }
  7701. }
  7702. // Gets the number of outgoing edges from the source
  7703. // and the number of incoming edges from the target
  7704. // without counting the edge being currently changed.
  7705. var sourceOut = this.model.getDirectedEdgeCount(source, true, edge);
  7706. var targetIn = this.model.getDirectedEdgeCount(target, false, edge);
  7707. // Checks the change against each multiplicity rule
  7708. if (this.multiplicities != null)
  7709. {
  7710. for (var i = 0; i < this.multiplicities.length; i++)
  7711. {
  7712. var err = this.multiplicities[i].check(this, edge, source,
  7713. target, sourceOut, targetIn);
  7714. if (err != null)
  7715. {
  7716. error += err;
  7717. }
  7718. }
  7719. }
  7720. // Validates the source and target terminals independently
  7721. var err = this.validateEdge(edge, source, target);
  7722. if (err != null)
  7723. {
  7724. error += err;
  7725. }
  7726. return (error.length > 0) ? error : null;
  7727. }
  7728. return (this.allowDanglingEdges) ? null : '';
  7729. };
  7730. /**
  7731. * Function: validateEdge
  7732. *
  7733. * Hook method for subclassers to return an error message for the given
  7734. * edge and terminals. This implementation returns null.
  7735. *
  7736. * Parameters:
  7737. *
  7738. * edge - <mxCell> that represents the edge to validate.
  7739. * source - <mxCell> that represents the source terminal.
  7740. * target - <mxCell> that represents the target terminal.
  7741. */
  7742. mxGraph.prototype.validateEdge = function(edge, source, target)
  7743. {
  7744. return null;
  7745. };
  7746. /**
  7747. * Function: validateGraph
  7748. *
  7749. * Validates the graph by validating each descendant of the given cell or
  7750. * the root of the model. Context is an object that contains the validation
  7751. * state for the complete validation run. The validation errors are
  7752. * attached to their cells using <setCellWarning>. Returns null in the case of
  7753. * successful validation or an array of strings (warnings) in the case of
  7754. * failed validations.
  7755. *
  7756. * Paramters:
  7757. *
  7758. * cell - Optional <mxCell> to start the validation recursion. Default is
  7759. * the graph root.
  7760. * context - Object that represents the global validation state.
  7761. */
  7762. mxGraph.prototype.validateGraph = function(cell, context)
  7763. {
  7764. cell = (cell != null) ? cell : this.model.getRoot();
  7765. context = (context != null) ? context : new Object();
  7766. var isValid = true;
  7767. var childCount = this.model.getChildCount(cell);
  7768. for (var i = 0; i < childCount; i++)
  7769. {
  7770. var tmp = this.model.getChildAt(cell, i);
  7771. var ctx = context;
  7772. if (this.isValidRoot(tmp))
  7773. {
  7774. ctx = new Object();
  7775. }
  7776. var warn = this.validateGraph(tmp, ctx);
  7777. if (warn != null)
  7778. {
  7779. this.setCellWarning(tmp, warn.replace(/\n/g, '<br>'));
  7780. }
  7781. else
  7782. {
  7783. this.setCellWarning(tmp, null);
  7784. }
  7785. isValid = isValid && warn == null;
  7786. }
  7787. var warning = '';
  7788. // Adds error for invalid children if collapsed (children invisible)
  7789. if (this.isCellCollapsed(cell) && !isValid)
  7790. {
  7791. warning += (mxResources.get(this.containsValidationErrorsResource) ||
  7792. this.containsValidationErrorsResource) + '\n';
  7793. }
  7794. // Checks edges and cells using the defined multiplicities
  7795. if (this.model.isEdge(cell))
  7796. {
  7797. warning += this.getEdgeValidationError(cell,
  7798. this.model.getTerminal(cell, true),
  7799. this.model.getTerminal(cell, false)) || '';
  7800. }
  7801. else
  7802. {
  7803. warning += this.getCellValidationError(cell) || '';
  7804. }
  7805. // Checks custom validation rules
  7806. var err = this.validateCell(cell, context);
  7807. if (err != null)
  7808. {
  7809. warning += err;
  7810. }
  7811. // Updates the display with the warning icons
  7812. // before any potential alerts are displayed.
  7813. // LATER: Move this into addCellOverlay. Redraw
  7814. // should check if overlay was added or removed.
  7815. if (this.model.getParent(cell) == null)
  7816. {
  7817. this.view.validate();
  7818. }
  7819. return (warning.length > 0 || !isValid) ? warning : null;
  7820. };
  7821. /**
  7822. * Function: getCellValidationError
  7823. *
  7824. * Checks all <multiplicities> that cannot be enforced while the graph is
  7825. * being modified, namely, all multiplicities that require a minimum of
  7826. * 1 edge.
  7827. *
  7828. * Parameters:
  7829. *
  7830. * cell - <mxCell> for which the multiplicities should be checked.
  7831. */
  7832. mxGraph.prototype.getCellValidationError = function(cell)
  7833. {
  7834. var outCount = this.model.getDirectedEdgeCount(cell, true);
  7835. var inCount = this.model.getDirectedEdgeCount(cell, false);
  7836. var value = this.model.getValue(cell);
  7837. var error = '';
  7838. if (this.multiplicities != null)
  7839. {
  7840. for (var i = 0; i < this.multiplicities.length; i++)
  7841. {
  7842. var rule = this.multiplicities[i];
  7843. if (rule.source && mxUtils.isNode(value, rule.type,
  7844. rule.attr, rule.value) && (outCount > rule.max ||
  7845. outCount < rule.min))
  7846. {
  7847. error += rule.countError + '\n';
  7848. }
  7849. else if (!rule.source && mxUtils.isNode(value, rule.type,
  7850. rule.attr, rule.value) && (inCount > rule.max ||
  7851. inCount < rule.min))
  7852. {
  7853. error += rule.countError + '\n';
  7854. }
  7855. }
  7856. }
  7857. return (error.length > 0) ? error : null;
  7858. };
  7859. /**
  7860. * Function: validateCell
  7861. *
  7862. * Hook method for subclassers to return an error message for the given
  7863. * cell and validation context. This implementation returns null. Any HTML
  7864. * breaks will be converted to linefeeds in the calling method.
  7865. *
  7866. * Parameters:
  7867. *
  7868. * cell - <mxCell> that represents the cell to validate.
  7869. * context - Object that represents the global validation state.
  7870. */
  7871. mxGraph.prototype.validateCell = function(cell, context)
  7872. {
  7873. return null;
  7874. };
  7875. /**
  7876. * Group: Graph appearance
  7877. */
  7878. /**
  7879. * Function: getBackgroundImage
  7880. *
  7881. * Returns the <backgroundImage> as an <mxImage>.
  7882. */
  7883. mxGraph.prototype.getBackgroundImage = function()
  7884. {
  7885. return this.backgroundImage;
  7886. };
  7887. /**
  7888. * Function: setBackgroundImage
  7889. *
  7890. * Sets the new <backgroundImage>.
  7891. *
  7892. * Parameters:
  7893. *
  7894. * image - New <mxImage> to be used for the background.
  7895. */
  7896. mxGraph.prototype.setBackgroundImage = function(image)
  7897. {
  7898. this.backgroundImage = image;
  7899. };
  7900. /**
  7901. * Function: getFoldingImage
  7902. *
  7903. * Returns the <mxImage> used to display the collapsed state of
  7904. * the specified cell state. This returns null for all edges.
  7905. */
  7906. mxGraph.prototype.getFoldingImage = function(state)
  7907. {
  7908. if (state != null && this.foldingEnabled && !this.getModel().isEdge(state.cell))
  7909. {
  7910. var tmp = this.isCellCollapsed(state.cell);
  7911. if (this.isCellFoldable(state.cell, !tmp))
  7912. {
  7913. return (tmp) ? this.collapsedImage : this.expandedImage;
  7914. }
  7915. }
  7916. return null;
  7917. };
  7918. /**
  7919. * Function: convertValueToString
  7920. *
  7921. * Returns the textual representation for the given cell. This
  7922. * implementation returns the nodename or string-representation of the user
  7923. * object.
  7924. *
  7925. * Example:
  7926. *
  7927. * The following returns the label attribute from the cells user
  7928. * object if it is an XML node.
  7929. *
  7930. * (code)
  7931. * graph.convertValueToString = function(cell)
  7932. * {
  7933. * return cell.getAttribute('label');
  7934. * }
  7935. * (end)
  7936. *
  7937. * See also: <cellLabelChanged>.
  7938. *
  7939. * Parameters:
  7940. *
  7941. * cell - <mxCell> whose textual representation should be returned.
  7942. */
  7943. mxGraph.prototype.convertValueToString = function(cell)
  7944. {
  7945. var value = this.model.getValue(cell);
  7946. if (value != null)
  7947. {
  7948. if (mxUtils.isNode(value))
  7949. {
  7950. return value.nodeName;
  7951. }
  7952. else if (typeof(value.toString) == 'function')
  7953. {
  7954. return value.toString();
  7955. }
  7956. }
  7957. return '';
  7958. };
  7959. /**
  7960. * Function: getLabel
  7961. *
  7962. * Returns a string or DOM node that represents the label for the given
  7963. * cell. This implementation uses <convertValueToString> if <labelsVisible>
  7964. * is true. Otherwise it returns an empty string.
  7965. *
  7966. * To truncate a label to match the size of the cell, the following code
  7967. * can be used.
  7968. *
  7969. * (code)
  7970. * graph.getLabel = function(cell)
  7971. * {
  7972. * var label = mxGraph.prototype.getLabel.apply(this, arguments);
  7973. *
  7974. * if (label != null && this.model.isVertex(cell))
  7975. * {
  7976. * var geo = this.getCellGeometry(cell);
  7977. *
  7978. * if (geo != null)
  7979. * {
  7980. * var max = parseInt(geo.width / 8);
  7981. *
  7982. * if (label.length > max)
  7983. * {
  7984. * label = label.substring(0, max)+'...';
  7985. * }
  7986. * }
  7987. * }
  7988. * return mxUtils.htmlEntities(label);
  7989. * }
  7990. * (end)
  7991. *
  7992. * A resize listener is needed in the graph to force a repaint of the label
  7993. * after a resize.
  7994. *
  7995. * (code)
  7996. * graph.addListener(mxEvent.RESIZE_CELLS, function(sender, evt)
  7997. * {
  7998. * var cells = evt.getProperty('cells');
  7999. *
  8000. * for (var i = 0; i < cells.length; i++)
  8001. * {
  8002. * this.view.removeState(cells[i]);
  8003. * }
  8004. * });
  8005. * (end)
  8006. *
  8007. * Parameters:
  8008. *
  8009. * cell - <mxCell> whose label should be returned.
  8010. */
  8011. mxGraph.prototype.getLabel = function(cell)
  8012. {
  8013. var result = '';
  8014. if (this.labelsVisible && cell != null)
  8015. {
  8016. var style = this.getCurrentCellStyle(cell);
  8017. if (!mxUtils.getValue(style, mxConstants.STYLE_NOLABEL, false))
  8018. {
  8019. result = this.convertValueToString(cell);
  8020. }
  8021. }
  8022. return result;
  8023. };
  8024. /**
  8025. * Function: isHtmlLabel
  8026. *
  8027. * Returns true if the label must be rendered as HTML markup. The default
  8028. * implementation returns <htmlLabels>.
  8029. *
  8030. * Parameters:
  8031. *
  8032. * cell - <mxCell> whose label should be displayed as HTML markup.
  8033. */
  8034. mxGraph.prototype.isHtmlLabel = function(cell)
  8035. {
  8036. return this.isHtmlLabels();
  8037. };
  8038. /**
  8039. * Function: isHtmlLabels
  8040. *
  8041. * Returns <htmlLabels>.
  8042. */
  8043. mxGraph.prototype.isHtmlLabels = function()
  8044. {
  8045. return this.htmlLabels;
  8046. };
  8047. /**
  8048. * Function: setHtmlLabels
  8049. *
  8050. * Sets <htmlLabels>.
  8051. */
  8052. mxGraph.prototype.setHtmlLabels = function(value)
  8053. {
  8054. this.htmlLabels = value;
  8055. };
  8056. /**
  8057. * Function: isWrapping
  8058. *
  8059. * This enables wrapping for HTML labels.
  8060. *
  8061. * Returns true if no white-space CSS style directive should be used for
  8062. * displaying the given cells label. This implementation returns true if
  8063. * <mxConstants.STYLE_WHITE_SPACE> in the style of the given cell is 'wrap'.
  8064. *
  8065. * This is used as a workaround for IE ignoring the white-space directive
  8066. * of child elements if the directive appears in a parent element. It
  8067. * should be overridden to return true if a white-space directive is used
  8068. * in the HTML markup that represents the given cells label. In order for
  8069. * HTML markup to work in labels, <isHtmlLabel> must also return true
  8070. * for the given cell.
  8071. *
  8072. * Example:
  8073. *
  8074. * (code)
  8075. * graph.getLabel = function(cell)
  8076. * {
  8077. * var tmp = mxGraph.prototype.getLabel.apply(this, arguments); // "supercall"
  8078. *
  8079. * if (this.model.isEdge(cell))
  8080. * {
  8081. * tmp = '<div style="width: 150px; white-space:normal;">'+tmp+'</div>';
  8082. * }
  8083. *
  8084. * return tmp;
  8085. * }
  8086. *
  8087. * graph.isWrapping = function(state)
  8088. * {
  8089. * return this.model.isEdge(state.cell);
  8090. * }
  8091. * (end)
  8092. *
  8093. * Makes sure no edge label is wider than 150 pixels, otherwise the content
  8094. * is wrapped. Note: No width must be specified for wrapped vertex labels as
  8095. * the vertex defines the width in its geometry.
  8096. *
  8097. * Parameters:
  8098. *
  8099. * state - <mxCell> whose label should be wrapped.
  8100. */
  8101. mxGraph.prototype.isWrapping = function(cell)
  8102. {
  8103. return this.getCurrentCellStyle(cell)[mxConstants.STYLE_WHITE_SPACE] == 'wrap';
  8104. };
  8105. /**
  8106. * Function: isLabelClipped
  8107. *
  8108. * Returns true if the overflow portion of labels should be hidden. If this
  8109. * returns true then vertex labels will be clipped to the size of the vertices.
  8110. * This implementation returns true if <mxConstants.STYLE_OVERFLOW> in the
  8111. * style of the given cell is 'hidden'.
  8112. *
  8113. * Parameters:
  8114. *
  8115. * state - <mxCell> whose label should be clipped.
  8116. */
  8117. mxGraph.prototype.isLabelClipped = function(cell)
  8118. {
  8119. return this.getCurrentCellStyle(cell)[mxConstants.STYLE_OVERFLOW] == 'hidden';
  8120. };
  8121. /**
  8122. * Function: getTooltip
  8123. *
  8124. * Returns the string or DOM node that represents the tooltip for the given
  8125. * state, node and coordinate pair. This implementation checks if the given
  8126. * node is a folding icon or overlay and returns the respective tooltip. If
  8127. * this does not result in a tooltip, the handler for the cell is retrieved
  8128. * from <selectionCellsHandler> and the optional getTooltipForNode method is
  8129. * called. If no special tooltip exists here then <getTooltipForCell> is used
  8130. * with the cell in the given state as the argument to return a tooltip for the
  8131. * given state.
  8132. *
  8133. * Parameters:
  8134. *
  8135. * state - <mxCellState> whose tooltip should be returned.
  8136. * node - DOM node that is currently under the mouse.
  8137. * x - X-coordinate of the mouse.
  8138. * y - Y-coordinate of the mouse.
  8139. */
  8140. mxGraph.prototype.getTooltip = function(state, node, x, y)
  8141. {
  8142. var tip = null;
  8143. if (state != null)
  8144. {
  8145. // Checks if the mouse is over the folding icon
  8146. if (state.control != null && (node == state.control.node ||
  8147. node.parentNode == state.control.node))
  8148. {
  8149. tip = this.collapseExpandResource;
  8150. tip = mxUtils.htmlEntities(mxResources.get(tip) || tip).replace(/\\n/g, '<br>');
  8151. }
  8152. if (tip == null && state.overlays != null)
  8153. {
  8154. state.overlays.visit(function(id, shape)
  8155. {
  8156. // LATER: Exit loop if tip is not null
  8157. if (tip == null && (node == shape.node || node.parentNode == shape.node))
  8158. {
  8159. tip = shape.overlay.toString();
  8160. }
  8161. });
  8162. }
  8163. if (tip == null)
  8164. {
  8165. var handler = this.selectionCellsHandler.getHandler(state.cell);
  8166. if (handler != null && typeof(handler.getTooltipForNode) == 'function')
  8167. {
  8168. tip = handler.getTooltipForNode(node);
  8169. }
  8170. }
  8171. if (tip == null)
  8172. {
  8173. tip = this.getTooltipForCell(state.cell);
  8174. }
  8175. }
  8176. return tip;
  8177. };
  8178. /**
  8179. * Function: getTooltipForCell
  8180. *
  8181. * Returns the string or DOM node to be used as the tooltip for the given
  8182. * cell. This implementation uses the cells getTooltip function if it
  8183. * exists, or else it returns <convertValueToString> for the cell.
  8184. *
  8185. * Example:
  8186. *
  8187. * (code)
  8188. * graph.getTooltipForCell = function(cell)
  8189. * {
  8190. * return 'Hello, World!';
  8191. * }
  8192. * (end)
  8193. *
  8194. * Replaces all tooltips with the string Hello, World!
  8195. *
  8196. * Parameters:
  8197. *
  8198. * cell - <mxCell> whose tooltip should be returned.
  8199. */
  8200. mxGraph.prototype.getTooltipForCell = function(cell)
  8201. {
  8202. var tip = null;
  8203. if (cell != null && cell.getTooltip != null)
  8204. {
  8205. tip = cell.getTooltip();
  8206. }
  8207. else
  8208. {
  8209. tip = this.convertValueToString(cell);
  8210. }
  8211. return tip;
  8212. };
  8213. /**
  8214. * Function: getLinkForCell
  8215. *
  8216. * Returns the string to be used as the link for the given cell. This
  8217. * implementation returns null.
  8218. *
  8219. * Parameters:
  8220. *
  8221. * cell - <mxCell> whose tooltip should be returned.
  8222. */
  8223. mxGraph.prototype.getLinkForCell = function(cell)
  8224. {
  8225. return null;
  8226. };
  8227. /**
  8228. * Function: getCursorForMouseEvent
  8229. *
  8230. * Returns the cursor value to be used for the CSS of the shape for the
  8231. * given event. This implementation calls <getCursorForCell>.
  8232. *
  8233. * Parameters:
  8234. *
  8235. * me - <mxMouseEvent> whose cursor should be returned.
  8236. */
  8237. mxGraph.prototype.getCursorForMouseEvent = function(me)
  8238. {
  8239. return this.getCursorForCell(me.getCell());
  8240. };
  8241. /**
  8242. * Function: getCursorForCell
  8243. *
  8244. * Returns the cursor value to be used for the CSS of the shape for the
  8245. * given cell. This implementation returns null.
  8246. *
  8247. * Parameters:
  8248. *
  8249. * cell - <mxCell> whose cursor should be returned.
  8250. */
  8251. mxGraph.prototype.getCursorForCell = function(cell)
  8252. {
  8253. return null;
  8254. };
  8255. /**
  8256. * Function: getStartSize
  8257. *
  8258. * Returns the start size of the given swimlane, that is, the width or
  8259. * height of the part that contains the title, depending on the
  8260. * horizontal style. The return value is an <mxRectangle> with either
  8261. * width or height set as appropriate.
  8262. *
  8263. * Parameters:
  8264. *
  8265. * swimlane - <mxCell> whose start size should be returned.
  8266. * ignoreState - Optional boolean that specifies if cell state should be ignored.
  8267. */
  8268. mxGraph.prototype.getStartSize = function(swimlane, ignoreState)
  8269. {
  8270. var result = new mxRectangle();
  8271. var style = this.getCurrentCellStyle(swimlane, ignoreState);
  8272. var size = parseInt(mxUtils.getValue(style,
  8273. mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE));
  8274. if (mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true))
  8275. {
  8276. result.height = size;
  8277. }
  8278. else
  8279. {
  8280. result.width = size;
  8281. }
  8282. return result;
  8283. };
  8284. /**
  8285. * Function: getSwimlaneDirection
  8286. *
  8287. * Returns the direction for the given swimlane style.
  8288. */
  8289. mxGraph.prototype.getSwimlaneDirection = function(style)
  8290. {
  8291. var dir = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
  8292. var flipH = mxUtils.getValue(style, mxConstants.STYLE_FLIPH, 0) == 1;
  8293. var flipV = mxUtils.getValue(style, mxConstants.STYLE_FLIPV, 0) == 1;
  8294. var h = mxUtils.getValue(style, mxConstants.STYLE_HORIZONTAL, true);
  8295. var n = (h) ? 0 : 3;
  8296. if (dir == mxConstants.DIRECTION_NORTH)
  8297. {
  8298. n--;
  8299. }
  8300. else if (dir == mxConstants.DIRECTION_WEST)
  8301. {
  8302. n += 2;
  8303. }
  8304. else if (dir == mxConstants.DIRECTION_SOUTH)
  8305. {
  8306. n += 1;
  8307. }
  8308. var mod = mxUtils.mod(n, 2);
  8309. if (flipH && mod == 1)
  8310. {
  8311. n += 2;
  8312. }
  8313. if (flipV && mod == 0)
  8314. {
  8315. n += 2;
  8316. }
  8317. return [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST,
  8318. mxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST]
  8319. [mxUtils.mod(n, 4)];
  8320. };
  8321. /**
  8322. * Function: getActualStartSize
  8323. *
  8324. * Returns the actual start size of the given swimlane taking into account
  8325. * direction and horizontal and vertial flip styles. The start size is
  8326. * returned as an <mxRectangle> where top, left, bottom, right start sizes
  8327. * are returned as x, y, height and width, respectively.
  8328. *
  8329. * Parameters:
  8330. *
  8331. * swimlane - <mxCell> whose start size should be returned.
  8332. * ignoreState - Optional boolean that specifies if cell state should be ignored.
  8333. */
  8334. mxGraph.prototype.getActualStartSize = function(swimlane, ignoreState)
  8335. {
  8336. var result = new mxRectangle();
  8337. if (this.isSwimlane(swimlane, ignoreState))
  8338. {
  8339. var style = this.getCurrentCellStyle(swimlane, ignoreState);
  8340. var size = parseInt(mxUtils.getValue(style, mxConstants.STYLE_STARTSIZE,
  8341. mxConstants.DEFAULT_STARTSIZE));
  8342. var dir = this.getSwimlaneDirection(style);
  8343. if (dir == mxConstants.DIRECTION_NORTH)
  8344. {
  8345. result.y = size;
  8346. }
  8347. else if (dir == mxConstants.DIRECTION_WEST)
  8348. {
  8349. result.x = size;
  8350. }
  8351. else if (dir == mxConstants.DIRECTION_SOUTH)
  8352. {
  8353. result.height = size;
  8354. }
  8355. else
  8356. {
  8357. result.width = size;
  8358. }
  8359. }
  8360. return result;
  8361. };
  8362. /**
  8363. * Function: getImage
  8364. *
  8365. * Returns the image URL for the given cell state. This implementation
  8366. * returns the value stored under <mxConstants.STYLE_IMAGE> in the cell
  8367. * style.
  8368. *
  8369. * Parameters:
  8370. *
  8371. * state - <mxCellState> whose image URL should be returned.
  8372. */
  8373. mxGraph.prototype.getImage = function(state)
  8374. {
  8375. return (state != null && state.style != null) ? state.style[mxConstants.STYLE_IMAGE] : null;
  8376. };
  8377. /**
  8378. * Function: isTransparentState
  8379. *
  8380. * Returns true if the given state has no stroke- or fillcolor and no image.
  8381. *
  8382. * Parameters:
  8383. *
  8384. * state - <mxCellState> to check.
  8385. */
  8386. mxGraph.prototype.isTransparentState = function(state)
  8387. {
  8388. var result = false;
  8389. if (state != null)
  8390. {
  8391. var stroke = mxUtils.getValue(state.style, mxConstants.STYLE_STROKECOLOR, mxConstants.NONE);
  8392. var fill = mxUtils.getValue(state.style, mxConstants.STYLE_FILLCOLOR, mxConstants.NONE);
  8393. result = stroke == mxConstants.NONE && fill == mxConstants.NONE && this.getImage(state) == null;
  8394. }
  8395. return result;
  8396. };
  8397. /**
  8398. * Function: getVerticalAlign
  8399. *
  8400. * Returns the vertical alignment for the given cell state. This
  8401. * implementation returns the value stored under
  8402. * <mxConstants.STYLE_VERTICAL_ALIGN> in the cell style.
  8403. *
  8404. * Parameters:
  8405. *
  8406. * state - <mxCellState> whose vertical alignment should be
  8407. * returned.
  8408. */
  8409. mxGraph.prototype.getVerticalAlign = function(state)
  8410. {
  8411. return (state != null && state.style != null) ?
  8412. (state.style[mxConstants.STYLE_VERTICAL_ALIGN] ||
  8413. mxConstants.ALIGN_MIDDLE) : null;
  8414. };
  8415. /**
  8416. * Function: getIndicatorColor
  8417. *
  8418. * Returns the indicator color for the given cell state. This
  8419. * implementation returns the value stored under
  8420. * <mxConstants.STYLE_INDICATOR_COLOR> in the cell style.
  8421. *
  8422. * Parameters:
  8423. *
  8424. * state - <mxCellState> whose indicator color should be
  8425. * returned.
  8426. */
  8427. mxGraph.prototype.getIndicatorColor = function(state)
  8428. {
  8429. return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_COLOR] : null;
  8430. };
  8431. /**
  8432. * Function: getIndicatorGradientColor
  8433. *
  8434. * Returns the indicator gradient color for the given cell state. This
  8435. * implementation returns the value stored under
  8436. * <mxConstants.STYLE_INDICATOR_GRADIENTCOLOR> in the cell style.
  8437. *
  8438. * Parameters:
  8439. *
  8440. * state - <mxCellState> whose indicator gradient color should be
  8441. * returned.
  8442. */
  8443. mxGraph.prototype.getIndicatorGradientColor = function(state)
  8444. {
  8445. return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_GRADIENTCOLOR] : null;
  8446. };
  8447. /**
  8448. * Function: getIndicatorShape
  8449. *
  8450. * Returns the indicator shape for the given cell state. This
  8451. * implementation returns the value stored under
  8452. * <mxConstants.STYLE_INDICATOR_SHAPE> in the cell style.
  8453. *
  8454. * Parameters:
  8455. *
  8456. * state - <mxCellState> whose indicator shape should be returned.
  8457. */
  8458. mxGraph.prototype.getIndicatorShape = function(state)
  8459. {
  8460. return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_SHAPE] : null;
  8461. };
  8462. /**
  8463. * Function: getIndicatorImage
  8464. *
  8465. * Returns the indicator image for the given cell state. This
  8466. * implementation returns the value stored under
  8467. * <mxConstants.STYLE_INDICATOR_IMAGE> in the cell style.
  8468. *
  8469. * Parameters:
  8470. *
  8471. * state - <mxCellState> whose indicator image should be returned.
  8472. */
  8473. mxGraph.prototype.getIndicatorImage = function(state)
  8474. {
  8475. return (state != null && state.style != null) ? state.style[mxConstants.STYLE_INDICATOR_IMAGE] : null;
  8476. };
  8477. /**
  8478. * Function: getBorder
  8479. *
  8480. * Returns the value of <border>.
  8481. */
  8482. mxGraph.prototype.getBorder = function()
  8483. {
  8484. return this.border;
  8485. };
  8486. /**
  8487. * Function: setBorder
  8488. *
  8489. * Sets the value of <border>.
  8490. *
  8491. * Parameters:
  8492. *
  8493. * value - Positive integer that represents the border to be used.
  8494. */
  8495. mxGraph.prototype.setBorder = function(value)
  8496. {
  8497. this.border = value;
  8498. };
  8499. /**
  8500. * Function: isSwimlane
  8501. *
  8502. * Returns true if the given cell is a swimlane in the graph. A swimlane is
  8503. * a container cell with some specific behaviour. This implementation
  8504. * checks if the shape associated with the given cell is a <mxSwimlane>.
  8505. *
  8506. * Parameters:
  8507. *
  8508. * cell - <mxCell> to be checked.
  8509. * ignoreState - Optional boolean that specifies if the cell state should be ignored.
  8510. */
  8511. mxGraph.prototype.isSwimlane = function(cell, ignoreState)
  8512. {
  8513. if (cell != null && this.model.getParent(cell) != this.model.getRoot() &&
  8514. !this.model.isEdge(cell))
  8515. {
  8516. return this.getCurrentCellStyle(cell, ignoreState)
  8517. [mxConstants.STYLE_SHAPE] == mxConstants.SHAPE_SWIMLANE;
  8518. }
  8519. return false;
  8520. };
  8521. /**
  8522. * Group: Graph behaviour
  8523. */
  8524. /**
  8525. * Function: isResizeContainer
  8526. *
  8527. * Returns <resizeContainer>.
  8528. */
  8529. mxGraph.prototype.isResizeContainer = function()
  8530. {
  8531. return this.resizeContainer;
  8532. };
  8533. /**
  8534. * Function: setResizeContainer
  8535. *
  8536. * Sets <resizeContainer>.
  8537. *
  8538. * Parameters:
  8539. *
  8540. * value - Boolean indicating if the container should be resized.
  8541. */
  8542. mxGraph.prototype.setResizeContainer = function(value)
  8543. {
  8544. this.resizeContainer = value;
  8545. };
  8546. /**
  8547. * Function: isEnabled
  8548. *
  8549. * Returns true if the graph is <enabled>.
  8550. */
  8551. mxGraph.prototype.isEnabled = function()
  8552. {
  8553. return this.enabled;
  8554. };
  8555. /**
  8556. * Function: setEnabled
  8557. *
  8558. * Specifies if the graph should allow any interactions. This
  8559. * implementation updates <enabled>.
  8560. *
  8561. * Parameters:
  8562. *
  8563. * value - Boolean indicating if the graph should be enabled.
  8564. */
  8565. mxGraph.prototype.setEnabled = function(value)
  8566. {
  8567. this.enabled = value;
  8568. };
  8569. /**
  8570. * Function: isEscapeEnabled
  8571. *
  8572. * Returns <escapeEnabled>.
  8573. */
  8574. mxGraph.prototype.isEscapeEnabled = function()
  8575. {
  8576. return this.escapeEnabled;
  8577. };
  8578. /**
  8579. * Function: setEscapeEnabled
  8580. *
  8581. * Sets <escapeEnabled>.
  8582. *
  8583. * Parameters:
  8584. *
  8585. * enabled - Boolean indicating if escape should be enabled.
  8586. */
  8587. mxGraph.prototype.setEscapeEnabled = function(value)
  8588. {
  8589. this.escapeEnabled = value;
  8590. };
  8591. /**
  8592. * Function: isInvokesStopCellEditing
  8593. *
  8594. * Returns <invokesStopCellEditing>.
  8595. */
  8596. mxGraph.prototype.isInvokesStopCellEditing = function()
  8597. {
  8598. return this.invokesStopCellEditing;
  8599. };
  8600. /**
  8601. * Function: setInvokesStopCellEditing
  8602. *
  8603. * Sets <invokesStopCellEditing>.
  8604. */
  8605. mxGraph.prototype.setInvokesStopCellEditing = function(value)
  8606. {
  8607. this.invokesStopCellEditing = value;
  8608. };
  8609. /**
  8610. * Function: isEnterStopsCellEditing
  8611. *
  8612. * Returns <enterStopsCellEditing>.
  8613. */
  8614. mxGraph.prototype.isEnterStopsCellEditing = function()
  8615. {
  8616. return this.enterStopsCellEditing;
  8617. };
  8618. /**
  8619. * Function: setEnterStopsCellEditing
  8620. *
  8621. * Sets <enterStopsCellEditing>.
  8622. */
  8623. mxGraph.prototype.setEnterStopsCellEditing = function(value)
  8624. {
  8625. this.enterStopsCellEditing = value;
  8626. };
  8627. /**
  8628. * Function: isCellLocked
  8629. *
  8630. * Returns true if the given cell may not be moved, sized, bended,
  8631. * disconnected, edited or selected. This implementation returns true for
  8632. * all vertices with a relative geometry if <locked> is false.
  8633. *
  8634. * Parameters:
  8635. *
  8636. * cell - <mxCell> whose locked state should be returned.
  8637. */
  8638. mxGraph.prototype.isCellLocked = function(cell)
  8639. {
  8640. var geometry = this.model.getGeometry(cell);
  8641. return this.isCellsLocked() || (geometry != null && this.model.isVertex(cell) && geometry.relative);
  8642. };
  8643. /**
  8644. * Function: isCellsLocked
  8645. *
  8646. * Returns true if the given cell may not be moved, sized, bended,
  8647. * disconnected, edited or selected. This implementation returns true for
  8648. * all vertices with a relative geometry if <locked> is false.
  8649. *
  8650. * Parameters:
  8651. *
  8652. * cell - <mxCell> whose locked state should be returned.
  8653. */
  8654. mxGraph.prototype.isCellsLocked = function()
  8655. {
  8656. return this.cellsLocked;
  8657. };
  8658. /**
  8659. * Function: setCellsLocked
  8660. *
  8661. * Sets if any cell may be moved, sized, bended, disconnected, edited or
  8662. * selected.
  8663. *
  8664. * Parameters:
  8665. *
  8666. * value - Boolean that defines the new value for <cellsLocked>.
  8667. */
  8668. mxGraph.prototype.setCellsLocked = function(value)
  8669. {
  8670. this.cellsLocked = value;
  8671. };
  8672. /**
  8673. * Function: getCloneableCells
  8674. *
  8675. * Returns the cells which may be exported in the given array of cells.
  8676. */
  8677. mxGraph.prototype.getCloneableCells = function(cells)
  8678. {
  8679. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  8680. {
  8681. return this.isCellCloneable(cell);
  8682. }));
  8683. };
  8684. /**
  8685. * Function: isCellCloneable
  8686. *
  8687. * Returns true if the given cell is cloneable. This implementation returns
  8688. * <isCellsCloneable> for all cells unless a cell style specifies
  8689. * <mxConstants.STYLE_CLONEABLE> to be 0.
  8690. *
  8691. * Parameters:
  8692. *
  8693. * cell - Optional <mxCell> whose cloneable state should be returned.
  8694. */
  8695. mxGraph.prototype.isCellCloneable = function(cell)
  8696. {
  8697. var style = this.getCurrentCellStyle(cell);
  8698. return this.isCellsCloneable() && style[mxConstants.STYLE_CLONEABLE] != 0;
  8699. };
  8700. /**
  8701. * Function: isCellsCloneable
  8702. *
  8703. * Returns <cellsCloneable>, that is, if the graph allows cloning of cells
  8704. * by using control-drag.
  8705. */
  8706. mxGraph.prototype.isCellsCloneable = function()
  8707. {
  8708. return this.cellsCloneable;
  8709. };
  8710. /**
  8711. * Function: setCellsCloneable
  8712. *
  8713. * Specifies if the graph should allow cloning of cells by holding down the
  8714. * control key while cells are being moved. This implementation updates
  8715. * <cellsCloneable>.
  8716. *
  8717. * Parameters:
  8718. *
  8719. * value - Boolean indicating if the graph should be cloneable.
  8720. */
  8721. mxGraph.prototype.setCellsCloneable = function(value)
  8722. {
  8723. this.cellsCloneable = value;
  8724. };
  8725. /**
  8726. * Function: getExportableCells
  8727. *
  8728. * Returns the cells which may be exported in the given array of cells.
  8729. */
  8730. mxGraph.prototype.getExportableCells = function(cells)
  8731. {
  8732. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  8733. {
  8734. return this.canExportCell(cell);
  8735. }));
  8736. };
  8737. /**
  8738. * Function: canExportCell
  8739. *
  8740. * Returns true if the given cell may be exported to the clipboard. This
  8741. * implementation returns <exportEnabled> for all cells.
  8742. *
  8743. * Parameters:
  8744. *
  8745. * cell - <mxCell> that represents the cell to be exported.
  8746. */
  8747. mxGraph.prototype.canExportCell = function(cell)
  8748. {
  8749. return this.exportEnabled;
  8750. };
  8751. /**
  8752. * Function: getImportableCells
  8753. *
  8754. * Returns the cells which may be imported in the given array of cells.
  8755. */
  8756. mxGraph.prototype.getImportableCells = function(cells)
  8757. {
  8758. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  8759. {
  8760. return this.canImportCell(cell);
  8761. }));
  8762. };
  8763. /**
  8764. * Function: canImportCell
  8765. *
  8766. * Returns true if the given cell may be imported from the clipboard.
  8767. * This implementation returns <importEnabled> for all cells.
  8768. *
  8769. * Parameters:
  8770. *
  8771. * cell - <mxCell> that represents the cell to be imported.
  8772. */
  8773. mxGraph.prototype.canImportCell = function(cell)
  8774. {
  8775. return this.importEnabled;
  8776. };
  8777. /**
  8778. * Function: isCellSelectable
  8779. *
  8780. * Returns true if the given cell is selectable. This implementation
  8781. * returns <cellsSelectable>.
  8782. *
  8783. * To add a new style for making cells (un)selectable, use the following code.
  8784. *
  8785. * (code)
  8786. * mxGraph.prototype.isCellSelectable = function(cell)
  8787. * {
  8788. * var style = this.getCurrentCellStyle(cell);
  8789. *
  8790. * return this.isCellsSelectable() && !this.isCellLocked(cell) && style['selectable'] != 0;
  8791. * };
  8792. * (end)
  8793. *
  8794. * You can then use the new style as shown in this example.
  8795. *
  8796. * (code)
  8797. * graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30, 'selectable=0');
  8798. * (end)
  8799. *
  8800. * Parameters:
  8801. *
  8802. * cell - <mxCell> whose selectable state should be returned.
  8803. */
  8804. mxGraph.prototype.isCellSelectable = function(cell)
  8805. {
  8806. return this.isCellsSelectable();
  8807. };
  8808. /**
  8809. * Function: isCellsSelectable
  8810. *
  8811. * Returns <cellsSelectable>.
  8812. */
  8813. mxGraph.prototype.isCellsSelectable = function()
  8814. {
  8815. return this.cellsSelectable;
  8816. };
  8817. /**
  8818. * Function: setCellsSelectable
  8819. *
  8820. * Sets <cellsSelectable>.
  8821. */
  8822. mxGraph.prototype.setCellsSelectable = function(value)
  8823. {
  8824. this.cellsSelectable = value;
  8825. };
  8826. /**
  8827. * Function: getDeletableCells
  8828. *
  8829. * Returns the cells which may be exported in the given array of cells.
  8830. */
  8831. mxGraph.prototype.getDeletableCells = function(cells)
  8832. {
  8833. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  8834. {
  8835. return this.isCellDeletable(cell);
  8836. }));
  8837. };
  8838. /**
  8839. * Function: isCellDeletable
  8840. *
  8841. * Returns true if the given cell is moveable. This returns
  8842. * <cellsDeletable> for all given cells if a cells style does not specify
  8843. * <mxConstants.STYLE_DELETABLE> to be 0.
  8844. *
  8845. * Parameters:
  8846. *
  8847. * cell - <mxCell> whose deletable state should be returned.
  8848. */
  8849. mxGraph.prototype.isCellDeletable = function(cell)
  8850. {
  8851. var style = this.getCurrentCellStyle(cell);
  8852. return this.isCellsDeletable() && style[mxConstants.STYLE_DELETABLE] != 0;
  8853. };
  8854. /**
  8855. * Function: isCellsDeletable
  8856. *
  8857. * Returns <cellsDeletable>.
  8858. */
  8859. mxGraph.prototype.isCellsDeletable = function()
  8860. {
  8861. return this.cellsDeletable;
  8862. };
  8863. /**
  8864. * Function: setCellsDeletable
  8865. *
  8866. * Sets <cellsDeletable>.
  8867. *
  8868. * Parameters:
  8869. *
  8870. * value - Boolean indicating if the graph should allow deletion of cells.
  8871. */
  8872. mxGraph.prototype.setCellsDeletable = function(value)
  8873. {
  8874. this.cellsDeletable = value;
  8875. };
  8876. /**
  8877. * Function: isLabelMovable
  8878. *
  8879. * Returns true if the given edges's label is moveable. This returns
  8880. * <movable> for all given cells if <isLocked> does not return true
  8881. * for the given cell.
  8882. *
  8883. * Parameters:
  8884. *
  8885. * cell - <mxCell> whose label should be moved.
  8886. */
  8887. mxGraph.prototype.isLabelMovable = function(cell)
  8888. {
  8889. return !this.isCellLocked(cell) &&
  8890. ((this.model.isEdge(cell) && this.edgeLabelsMovable) ||
  8891. (this.model.isVertex(cell) && this.vertexLabelsMovable));
  8892. };
  8893. /**
  8894. * Function: isCellRotatable
  8895. *
  8896. * Returns true if the given cell is rotatable. This returns true for the given
  8897. * cell if its style does not specify <mxConstants.STYLE_ROTATABLE> to be 0.
  8898. *
  8899. * Parameters:
  8900. *
  8901. * cell - <mxCell> whose rotatable state should be returned.
  8902. */
  8903. mxGraph.prototype.isCellRotatable = function(cell)
  8904. {
  8905. var style = this.getCurrentCellStyle(cell);
  8906. return style[mxConstants.STYLE_ROTATABLE] != 0;
  8907. };
  8908. /**
  8909. * Function: getMovableCells
  8910. *
  8911. * Returns the cells which are movable in the given array of cells.
  8912. */
  8913. mxGraph.prototype.getMovableCells = function(cells)
  8914. {
  8915. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  8916. {
  8917. return this.isCellMovable(cell);
  8918. }));
  8919. };
  8920. /**
  8921. * Function: isCellMovable
  8922. *
  8923. * Returns true if the given cell is moveable. This returns <cellsMovable>
  8924. * for all given cells if <isCellLocked> does not return true for the given
  8925. * cell and its style does not specify <mxConstants.STYLE_MOVABLE> to be 0.
  8926. *
  8927. * Parameters:
  8928. *
  8929. * cell - <mxCell> whose movable state should be returned.
  8930. */
  8931. mxGraph.prototype.isCellMovable = function(cell)
  8932. {
  8933. var style = this.getCurrentCellStyle(cell);
  8934. return this.isCellsMovable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0;
  8935. };
  8936. /**
  8937. * Function: isCellsMovable
  8938. *
  8939. * Returns <cellsMovable>.
  8940. */
  8941. mxGraph.prototype.isCellsMovable = function()
  8942. {
  8943. return this.cellsMovable;
  8944. };
  8945. /**
  8946. * Function: setCellsMovable
  8947. *
  8948. * Specifies if the graph should allow moving of cells. This implementation
  8949. * updates <cellsMsovable>.
  8950. *
  8951. * Parameters:
  8952. *
  8953. * value - Boolean indicating if the graph should allow moving of cells.
  8954. */
  8955. mxGraph.prototype.setCellsMovable = function(value)
  8956. {
  8957. this.cellsMovable = value;
  8958. };
  8959. /**
  8960. * Function: isGridEnabled
  8961. *
  8962. * Returns <gridEnabled> as a boolean.
  8963. */
  8964. mxGraph.prototype.isGridEnabled = function()
  8965. {
  8966. return this.gridEnabled;
  8967. };
  8968. /**
  8969. * Function: setGridEnabled
  8970. *
  8971. * Specifies if the grid should be enabled.
  8972. *
  8973. * Parameters:
  8974. *
  8975. * value - Boolean indicating if the grid should be enabled.
  8976. */
  8977. mxGraph.prototype.setGridEnabled = function(value)
  8978. {
  8979. this.gridEnabled = value;
  8980. };
  8981. /**
  8982. * Function: isPortsEnabled
  8983. *
  8984. * Returns <portsEnabled> as a boolean.
  8985. */
  8986. mxGraph.prototype.isPortsEnabled = function()
  8987. {
  8988. return this.portsEnabled;
  8989. };
  8990. /**
  8991. * Function: setPortsEnabled
  8992. *
  8993. * Specifies if the ports should be enabled.
  8994. *
  8995. * Parameters:
  8996. *
  8997. * value - Boolean indicating if the ports should be enabled.
  8998. */
  8999. mxGraph.prototype.setPortsEnabled = function(value)
  9000. {
  9001. this.portsEnabled = value;
  9002. };
  9003. /**
  9004. * Function: getGridSize
  9005. *
  9006. * Returns <gridSize>.
  9007. */
  9008. mxGraph.prototype.getGridSize = function()
  9009. {
  9010. return this.gridSize;
  9011. };
  9012. /**
  9013. * Function: setGridSize
  9014. *
  9015. * Sets <gridSize>.
  9016. */
  9017. mxGraph.prototype.setGridSize = function(value)
  9018. {
  9019. this.gridSize = value;
  9020. };
  9021. /**
  9022. * Function: getTolerance
  9023. *
  9024. * Returns <tolerance>.
  9025. */
  9026. mxGraph.prototype.getTolerance = function()
  9027. {
  9028. return this.tolerance;
  9029. };
  9030. /**
  9031. * Function: setTolerance
  9032. *
  9033. * Sets <tolerance>.
  9034. */
  9035. mxGraph.prototype.setTolerance = function(value)
  9036. {
  9037. this.tolerance = value;
  9038. };
  9039. /**
  9040. * Function: isVertexLabelsMovable
  9041. *
  9042. * Returns <vertexLabelsMovable>.
  9043. */
  9044. mxGraph.prototype.isVertexLabelsMovable = function()
  9045. {
  9046. return this.vertexLabelsMovable;
  9047. };
  9048. /**
  9049. * Function: setVertexLabelsMovable
  9050. *
  9051. * Sets <vertexLabelsMovable>.
  9052. */
  9053. mxGraph.prototype.setVertexLabelsMovable = function(value)
  9054. {
  9055. this.vertexLabelsMovable = value;
  9056. };
  9057. /**
  9058. * Function: isEdgeLabelsMovable
  9059. *
  9060. * Returns <edgeLabelsMovable>.
  9061. */
  9062. mxGraph.prototype.isEdgeLabelsMovable = function()
  9063. {
  9064. return this.edgeLabelsMovable;
  9065. };
  9066. /**
  9067. * Function: isEdgeLabelsMovable
  9068. *
  9069. * Sets <edgeLabelsMovable>.
  9070. */
  9071. mxGraph.prototype.setEdgeLabelsMovable = function(value)
  9072. {
  9073. this.edgeLabelsMovable = value;
  9074. };
  9075. /**
  9076. * Function: isSwimlaneNesting
  9077. *
  9078. * Returns <swimlaneNesting> as a boolean.
  9079. */
  9080. mxGraph.prototype.isSwimlaneNesting = function()
  9081. {
  9082. return this.swimlaneNesting;
  9083. };
  9084. /**
  9085. * Function: setSwimlaneNesting
  9086. *
  9087. * Specifies if swimlanes can be nested by drag and drop. This is only
  9088. * taken into account if dropEnabled is true.
  9089. *
  9090. * Parameters:
  9091. *
  9092. * value - Boolean indicating if swimlanes can be nested.
  9093. */
  9094. mxGraph.prototype.setSwimlaneNesting = function(value)
  9095. {
  9096. this.swimlaneNesting = value;
  9097. };
  9098. /**
  9099. * Function: isSwimlaneSelectionEnabled
  9100. *
  9101. * Returns <swimlaneSelectionEnabled> as a boolean.
  9102. */
  9103. mxGraph.prototype.isSwimlaneSelectionEnabled = function()
  9104. {
  9105. return this.swimlaneSelectionEnabled;
  9106. };
  9107. /**
  9108. * Function: setSwimlaneSelectionEnabled
  9109. *
  9110. * Specifies if swimlanes should be selected if the mouse is released
  9111. * over their content area.
  9112. *
  9113. * Parameters:
  9114. *
  9115. * value - Boolean indicating if swimlanes content areas
  9116. * should be selected when the mouse is released over them.
  9117. */
  9118. mxGraph.prototype.setSwimlaneSelectionEnabled = function(value)
  9119. {
  9120. this.swimlaneSelectionEnabled = value;
  9121. };
  9122. /**
  9123. * Function: isMultigraph
  9124. *
  9125. * Returns <multigraph> as a boolean.
  9126. */
  9127. mxGraph.prototype.isMultigraph = function()
  9128. {
  9129. return this.multigraph;
  9130. };
  9131. /**
  9132. * Function: setMultigraph
  9133. *
  9134. * Specifies if the graph should allow multiple connections between the
  9135. * same pair of vertices.
  9136. *
  9137. * Parameters:
  9138. *
  9139. * value - Boolean indicating if the graph allows multiple connections
  9140. * between the same pair of vertices.
  9141. */
  9142. mxGraph.prototype.setMultigraph = function(value)
  9143. {
  9144. this.multigraph = value;
  9145. };
  9146. /**
  9147. * Function: isAllowLoops
  9148. *
  9149. * Returns <allowLoops> as a boolean.
  9150. */
  9151. mxGraph.prototype.isAllowLoops = function()
  9152. {
  9153. return this.allowLoops;
  9154. };
  9155. /**
  9156. * Function: setAllowDanglingEdges
  9157. *
  9158. * Specifies if dangling edges are allowed, that is, if edges are allowed
  9159. * that do not have a source and/or target terminal defined.
  9160. *
  9161. * Parameters:
  9162. *
  9163. * value - Boolean indicating if dangling edges are allowed.
  9164. */
  9165. mxGraph.prototype.setAllowDanglingEdges = function(value)
  9166. {
  9167. this.allowDanglingEdges = value;
  9168. };
  9169. /**
  9170. * Function: isAllowDanglingEdges
  9171. *
  9172. * Returns <allowDanglingEdges> as a boolean.
  9173. */
  9174. mxGraph.prototype.isAllowDanglingEdges = function()
  9175. {
  9176. return this.allowDanglingEdges;
  9177. };
  9178. /**
  9179. * Function: setConnectableEdges
  9180. *
  9181. * Specifies if edges should be connectable.
  9182. *
  9183. * Parameters:
  9184. *
  9185. * value - Boolean indicating if edges should be connectable.
  9186. */
  9187. mxGraph.prototype.setConnectableEdges = function(value)
  9188. {
  9189. this.connectableEdges = value;
  9190. };
  9191. /**
  9192. * Function: isConnectableEdges
  9193. *
  9194. * Returns <connectableEdges> as a boolean.
  9195. */
  9196. mxGraph.prototype.isConnectableEdges = function()
  9197. {
  9198. return this.connectableEdges;
  9199. };
  9200. /**
  9201. * Function: setCloneInvalidEdges
  9202. *
  9203. * Specifies if edges should be inserted when cloned but not valid wrt.
  9204. * <getEdgeValidationError>. If false such edges will be silently ignored.
  9205. *
  9206. * Parameters:
  9207. *
  9208. * value - Boolean indicating if cloned invalid edges should be
  9209. * inserted into the graph or ignored.
  9210. */
  9211. mxGraph.prototype.setCloneInvalidEdges = function(value)
  9212. {
  9213. this.cloneInvalidEdges = value;
  9214. };
  9215. /**
  9216. * Function: isCloneInvalidEdges
  9217. *
  9218. * Returns <cloneInvalidEdges> as a boolean.
  9219. */
  9220. mxGraph.prototype.isCloneInvalidEdges = function()
  9221. {
  9222. return this.cloneInvalidEdges;
  9223. };
  9224. /**
  9225. * Function: setAllowLoops
  9226. *
  9227. * Specifies if loops are allowed.
  9228. *
  9229. * Parameters:
  9230. *
  9231. * value - Boolean indicating if loops are allowed.
  9232. */
  9233. mxGraph.prototype.setAllowLoops = function(value)
  9234. {
  9235. this.allowLoops = value;
  9236. };
  9237. /**
  9238. * Function: isDisconnectOnMove
  9239. *
  9240. * Returns <disconnectOnMove> as a boolean.
  9241. */
  9242. mxGraph.prototype.isDisconnectOnMove = function()
  9243. {
  9244. return this.disconnectOnMove;
  9245. };
  9246. /**
  9247. * Function: setDisconnectOnMove
  9248. *
  9249. * Specifies if edges should be disconnected when moved. (Note: Cloned
  9250. * edges are always disconnected.)
  9251. *
  9252. * Parameters:
  9253. *
  9254. * value - Boolean indicating if edges should be disconnected
  9255. * when moved.
  9256. */
  9257. mxGraph.prototype.setDisconnectOnMove = function(value)
  9258. {
  9259. this.disconnectOnMove = value;
  9260. };
  9261. /**
  9262. * Function: isDropEnabled
  9263. *
  9264. * Returns <dropEnabled> as a boolean.
  9265. */
  9266. mxGraph.prototype.isDropEnabled = function()
  9267. {
  9268. return this.dropEnabled;
  9269. };
  9270. /**
  9271. * Function: setDropEnabled
  9272. *
  9273. * Specifies if the graph should allow dropping of cells onto or into other
  9274. * cells.
  9275. *
  9276. * Parameters:
  9277. *
  9278. * dropEnabled - Boolean indicating if the graph should allow dropping
  9279. * of cells into other cells.
  9280. */
  9281. mxGraph.prototype.setDropEnabled = function(value)
  9282. {
  9283. this.dropEnabled = value;
  9284. };
  9285. /**
  9286. * Function: isSplitEnabled
  9287. *
  9288. * Returns <splitEnabled> as a boolean.
  9289. */
  9290. mxGraph.prototype.isSplitEnabled = function()
  9291. {
  9292. return this.splitEnabled;
  9293. };
  9294. /**
  9295. * Function: setSplitEnabled
  9296. *
  9297. * Specifies if the graph should allow dropping of cells onto or into other
  9298. * cells.
  9299. *
  9300. * Parameters:
  9301. *
  9302. * dropEnabled - Boolean indicating if the graph should allow dropping
  9303. * of cells into other cells.
  9304. */
  9305. mxGraph.prototype.setSplitEnabled = function(value)
  9306. {
  9307. this.splitEnabled = value;
  9308. };
  9309. /**
  9310. * Function: isCellResizable
  9311. *
  9312. * Returns true if the given cell is resizable. This returns
  9313. * <cellsResizable> for all given cells if <isCellLocked> does not return
  9314. * true for the given cell and its style does not specify
  9315. * <mxConstants.STYLE_RESIZABLE> to be 0.
  9316. *
  9317. * Parameters:
  9318. *
  9319. * cell - <mxCell> whose resizable state should be returned.
  9320. */
  9321. mxGraph.prototype.isCellResizable = function(cell)
  9322. {
  9323. var style = this.getCurrentCellStyle(cell);
  9324. return this.isCellsResizable() && !this.isCellLocked(cell) &&
  9325. mxUtils.getValue(style, mxConstants.STYLE_RESIZABLE, '1') != '0';
  9326. };
  9327. /**
  9328. * Function: isCellsResizable
  9329. *
  9330. * Returns <cellsResizable>.
  9331. */
  9332. mxGraph.prototype.isCellsResizable = function()
  9333. {
  9334. return this.cellsResizable;
  9335. };
  9336. /**
  9337. * Function: setCellsResizable
  9338. *
  9339. * Specifies if the graph should allow resizing of cells. This
  9340. * implementation updates <cellsResizable>.
  9341. *
  9342. * Parameters:
  9343. *
  9344. * value - Boolean indicating if the graph should allow resizing of
  9345. * cells.
  9346. */
  9347. mxGraph.prototype.setCellsResizable = function(value)
  9348. {
  9349. this.cellsResizable = value;
  9350. };
  9351. /**
  9352. * Function: isTerminalPointMovable
  9353. *
  9354. * Returns true if the given terminal point is movable. This is independent
  9355. * from <isCellConnectable> and <isCellDisconnectable> and controls if terminal
  9356. * points can be moved in the graph if the edge is not connected. Note that it
  9357. * is required for this to return true to connect unconnected edges. This
  9358. * implementation returns true.
  9359. *
  9360. * Parameters:
  9361. *
  9362. * cell - <mxCell> whose terminal point should be moved.
  9363. * source - Boolean indicating if the source or target terminal should be moved.
  9364. */
  9365. mxGraph.prototype.isTerminalPointMovable = function(cell, source)
  9366. {
  9367. return true;
  9368. };
  9369. /**
  9370. * Function: isCellBendable
  9371. *
  9372. * Returns true if the given cell is bendable. This returns <cellsBendable>
  9373. * for all given cells if <isLocked> does not return true for the given
  9374. * cell and its style does not specify <mxConstants.STYLE_BENDABLE> to be 0.
  9375. *
  9376. * Parameters:
  9377. *
  9378. * cell - <mxCell> whose bendable state should be returned.
  9379. */
  9380. mxGraph.prototype.isCellBendable = function(cell)
  9381. {
  9382. var style = this.getCurrentCellStyle(cell);
  9383. return this.isCellsBendable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_BENDABLE] != 0;
  9384. };
  9385. /**
  9386. * Function: isCellsBendable
  9387. *
  9388. * Returns <cellsBenadable>.
  9389. */
  9390. mxGraph.prototype.isCellsBendable = function()
  9391. {
  9392. return this.cellsBendable;
  9393. };
  9394. /**
  9395. * Function: setCellsBendable
  9396. *
  9397. * Specifies if the graph should allow bending of edges. This
  9398. * implementation updates <bendable>.
  9399. *
  9400. * Parameters:
  9401. *
  9402. * value - Boolean indicating if the graph should allow bending of
  9403. * edges.
  9404. */
  9405. mxGraph.prototype.setCellsBendable = function(value)
  9406. {
  9407. this.cellsBendable = value;
  9408. };
  9409. /**
  9410. * Function: isCellEditable
  9411. *
  9412. * Returns true if the given cell is editable. This returns <cellsEditable> for
  9413. * all given cells if <isCellLocked> does not return true for the given cell
  9414. * and its style does not specify <mxConstants.STYLE_EDITABLE> to be 0.
  9415. *
  9416. * Parameters:
  9417. *
  9418. * cell - <mxCell> whose editable state should be returned.
  9419. */
  9420. mxGraph.prototype.isCellEditable = function(cell)
  9421. {
  9422. var style = this.getCurrentCellStyle(cell);
  9423. return this.isCellsEditable() && !this.isCellLocked(cell) && style[mxConstants.STYLE_EDITABLE] != 0;
  9424. };
  9425. /**
  9426. * Function: isCellsEditable
  9427. *
  9428. * Returns <cellsEditable>.
  9429. */
  9430. mxGraph.prototype.isCellsEditable = function()
  9431. {
  9432. return this.cellsEditable;
  9433. };
  9434. /**
  9435. * Function: setCellsEditable
  9436. *
  9437. * Specifies if the graph should allow in-place editing for cell labels.
  9438. * This implementation updates <cellsEditable>.
  9439. *
  9440. * Parameters:
  9441. *
  9442. * value - Boolean indicating if the graph should allow in-place
  9443. * editing.
  9444. */
  9445. mxGraph.prototype.setCellsEditable = function(value)
  9446. {
  9447. this.cellsEditable = value;
  9448. };
  9449. /**
  9450. * Function: isCellDisconnectable
  9451. *
  9452. * Returns true if the given cell is disconnectable from the source or
  9453. * target terminal. This returns <isCellsDisconnectable> for all given
  9454. * cells if <isCellLocked> does not return true for the given cell.
  9455. *
  9456. * Parameters:
  9457. *
  9458. * cell - <mxCell> whose disconnectable state should be returned.
  9459. * terminal - <mxCell> that represents the source or target terminal.
  9460. * source - Boolean indicating if the source or target terminal is to be
  9461. * disconnected.
  9462. */
  9463. mxGraph.prototype.isCellDisconnectable = function(cell, terminal, source)
  9464. {
  9465. return this.isCellsDisconnectable() && !this.isCellLocked(cell);
  9466. };
  9467. /**
  9468. * Function: isCellsDisconnectable
  9469. *
  9470. * Returns <cellsDisconnectable>.
  9471. */
  9472. mxGraph.prototype.isCellsDisconnectable = function()
  9473. {
  9474. return this.cellsDisconnectable;
  9475. };
  9476. /**
  9477. * Function: setCellsDisconnectable
  9478. *
  9479. * Sets <cellsDisconnectable>.
  9480. */
  9481. mxGraph.prototype.setCellsDisconnectable = function(value)
  9482. {
  9483. this.cellsDisconnectable = value;
  9484. };
  9485. /**
  9486. * Function: isValidSource
  9487. *
  9488. * Returns true if the given cell is a valid source for new connections.
  9489. * This implementation returns true for all non-null values and is
  9490. * called by is called by <isValidConnection>.
  9491. *
  9492. * Parameters:
  9493. *
  9494. * cell - <mxCell> that represents a possible source or null.
  9495. */
  9496. mxGraph.prototype.isValidSource = function(cell)
  9497. {
  9498. return (cell == null && this.allowDanglingEdges) ||
  9499. (cell != null && (!this.model.isEdge(cell) ||
  9500. this.connectableEdges) && this.isCellConnectable(cell));
  9501. };
  9502. /**
  9503. * Function: isValidTarget
  9504. *
  9505. * Returns <isValidSource> for the given cell. This is called by
  9506. * <isValidConnection>.
  9507. *
  9508. * Parameters:
  9509. *
  9510. * cell - <mxCell> that represents a possible target or null.
  9511. */
  9512. mxGraph.prototype.isValidTarget = function(cell)
  9513. {
  9514. return this.isValidSource(cell);
  9515. };
  9516. /**
  9517. * Function: isValidConnection
  9518. *
  9519. * Returns true if the given target cell is a valid target for source.
  9520. * This is a boolean implementation for not allowing connections between
  9521. * certain pairs of vertices and is called by <getEdgeValidationError>.
  9522. * This implementation returns true if <isValidSource> returns true for
  9523. * the source and <isValidTarget> returns true for the target.
  9524. *
  9525. * Parameters:
  9526. *
  9527. * source - <mxCell> that represents the source cell.
  9528. * target - <mxCell> that represents the target cell.
  9529. */
  9530. mxGraph.prototype.isValidConnection = function(source, target)
  9531. {
  9532. return this.isValidSource(source) && this.isValidTarget(target);
  9533. };
  9534. /**
  9535. * Function: setConnectable
  9536. *
  9537. * Specifies if the graph should allow new connections. This implementation
  9538. * updates <mxConnectionHandler.enabled> in <connectionHandler>.
  9539. *
  9540. * Parameters:
  9541. *
  9542. * connectable - Boolean indicating if new connections should be allowed.
  9543. */
  9544. mxGraph.prototype.setConnectable = function(connectable)
  9545. {
  9546. this.connectionHandler.setEnabled(connectable);
  9547. };
  9548. /**
  9549. * Function: isConnectable
  9550. *
  9551. * Returns true if the <connectionHandler> is enabled.
  9552. */
  9553. mxGraph.prototype.isConnectable = function()
  9554. {
  9555. return this.connectionHandler.isEnabled();
  9556. };
  9557. /**
  9558. * Function: setTooltips
  9559. *
  9560. * Specifies if tooltips should be enabled. This implementation updates
  9561. * <mxTooltipHandler.enabled> in <tooltipHandler>.
  9562. *
  9563. * Parameters:
  9564. *
  9565. * enabled - Boolean indicating if tooltips should be enabled.
  9566. */
  9567. mxGraph.prototype.setTooltips = function (enabled)
  9568. {
  9569. this.tooltipHandler.setEnabled(enabled);
  9570. };
  9571. /**
  9572. * Function: setPanning
  9573. *
  9574. * Specifies if panning should be enabled. This implementation updates
  9575. * <mxPanningHandler.panningEnabled> in <panningHandler>.
  9576. *
  9577. * Parameters:
  9578. *
  9579. * enabled - Boolean indicating if panning should be enabled.
  9580. */
  9581. mxGraph.prototype.setPanning = function(enabled)
  9582. {
  9583. this.panningHandler.panningEnabled = enabled;
  9584. };
  9585. /**
  9586. * Function: isEditing
  9587. *
  9588. * Returns true if the given cell is currently being edited.
  9589. * If no cell is specified then this returns true if any
  9590. * cell is currently being edited.
  9591. *
  9592. * Parameters:
  9593. *
  9594. * cell - <mxCell> that should be checked.
  9595. */
  9596. mxGraph.prototype.isEditing = function(cell)
  9597. {
  9598. if (this.cellEditor != null)
  9599. {
  9600. var editingCell = this.cellEditor.getEditingCell();
  9601. return (cell == null) ? editingCell != null : cell == editingCell;
  9602. }
  9603. return false;
  9604. };
  9605. /**
  9606. * Function: isAutoSizeCell
  9607. *
  9608. * Returns true if the size of the given cell should automatically be
  9609. * updated after a change of the label. This implementation returns
  9610. * <autoSizeCells> or checks if the cell style does specify
  9611. * <mxConstants.STYLE_AUTOSIZE> to be 1.
  9612. *
  9613. * Parameters:
  9614. *
  9615. * cell - <mxCell> that should be resized.
  9616. */
  9617. mxGraph.prototype.isAutoSizeCell = function(cell)
  9618. {
  9619. var style = this.getCurrentCellStyle(cell);
  9620. return this.isAutoSizeCells() || style[mxConstants.STYLE_AUTOSIZE] == 1;
  9621. };
  9622. /**
  9623. * Function: isAutoSizeCells
  9624. *
  9625. * Returns <autoSizeCells>.
  9626. */
  9627. mxGraph.prototype.isAutoSizeCells = function()
  9628. {
  9629. return this.autoSizeCells;
  9630. };
  9631. /**
  9632. * Function: setAutoSizeCells
  9633. *
  9634. * Specifies if cell sizes should be automatically updated after a label
  9635. * change. This implementation sets <autoSizeCells> to the given parameter.
  9636. * To update the size of cells when the cells are added, set
  9637. * <autoSizeCellsOnAdd> to true.
  9638. *
  9639. * Parameters:
  9640. *
  9641. * value - Boolean indicating if cells should be resized
  9642. * automatically.
  9643. */
  9644. mxGraph.prototype.setAutoSizeCells = function(value)
  9645. {
  9646. this.autoSizeCells = value;
  9647. };
  9648. /**
  9649. * Function: isExtendParent
  9650. *
  9651. * Returns true if the parent of the given cell should be extended if the
  9652. * child has been resized so that it overlaps the parent. This
  9653. * implementation returns <isExtendParents> if the cell is not an edge.
  9654. *
  9655. * Parameters:
  9656. *
  9657. * cell - <mxCell> that has been resized.
  9658. */
  9659. mxGraph.prototype.isExtendParent = function(cell)
  9660. {
  9661. return !this.getModel().isEdge(cell) && this.isExtendParents();
  9662. };
  9663. /**
  9664. * Function: isExtendParents
  9665. *
  9666. * Returns <extendParents>.
  9667. */
  9668. mxGraph.prototype.isExtendParents = function()
  9669. {
  9670. return this.extendParents;
  9671. };
  9672. /**
  9673. * Function: setExtendParents
  9674. *
  9675. * Sets <extendParents>.
  9676. *
  9677. * Parameters:
  9678. *
  9679. * value - New boolean value for <extendParents>.
  9680. */
  9681. mxGraph.prototype.setExtendParents = function(value)
  9682. {
  9683. this.extendParents = value;
  9684. };
  9685. /**
  9686. * Function: isExtendParentsOnAdd
  9687. *
  9688. * Returns <extendParentsOnAdd>.
  9689. */
  9690. mxGraph.prototype.isExtendParentsOnAdd = function(cell)
  9691. {
  9692. return this.extendParentsOnAdd;
  9693. };
  9694. /**
  9695. * Function: setExtendParentsOnAdd
  9696. *
  9697. * Sets <extendParentsOnAdd>.
  9698. *
  9699. * Parameters:
  9700. *
  9701. * value - New boolean value for <extendParentsOnAdd>.
  9702. */
  9703. mxGraph.prototype.setExtendParentsOnAdd = function(value)
  9704. {
  9705. this.extendParentsOnAdd = value;
  9706. };
  9707. /**
  9708. * Function: isExtendParentsOnMove
  9709. *
  9710. * Returns <extendParentsOnMove>.
  9711. */
  9712. mxGraph.prototype.isExtendParentsOnMove = function()
  9713. {
  9714. return this.extendParentsOnMove;
  9715. };
  9716. /**
  9717. * Function: setExtendParentsOnMove
  9718. *
  9719. * Sets <extendParentsOnMove>.
  9720. *
  9721. * Parameters:
  9722. *
  9723. * value - New boolean value for <extendParentsOnAdd>.
  9724. */
  9725. mxGraph.prototype.setExtendParentsOnMove = function(value)
  9726. {
  9727. this.extendParentsOnMove = value;
  9728. };
  9729. /**
  9730. * Function: isRecursiveResize
  9731. *
  9732. * Returns <recursiveResize>.
  9733. *
  9734. * Parameters:
  9735. *
  9736. * state - <mxCellState> that is being resized.
  9737. */
  9738. mxGraph.prototype.isRecursiveResize = function(state)
  9739. {
  9740. return this.recursiveResize;
  9741. };
  9742. /**
  9743. * Function: setRecursiveResize
  9744. *
  9745. * Sets <recursiveResize>.
  9746. *
  9747. * Parameters:
  9748. *
  9749. * value - New boolean value for <recursiveResize>.
  9750. */
  9751. mxGraph.prototype.setRecursiveResize = function(value)
  9752. {
  9753. this.recursiveResize = value;
  9754. };
  9755. /**
  9756. * Function: isConstrainChild
  9757. *
  9758. * Returns true if the given cell should be kept inside the bounds of its
  9759. * parent according to the rules defined by <getOverlap> and
  9760. * <isAllowOverlapParent>. This implementation returns false for all children
  9761. * of edges and <isConstrainChildren> otherwise.
  9762. *
  9763. * Parameters:
  9764. *
  9765. * cell - <mxCell> that should be constrained.
  9766. */
  9767. mxGraph.prototype.isConstrainChild = function(cell)
  9768. {
  9769. return this.isConstrainChildren() && !this.getModel().isEdge(this.getModel().getParent(cell));
  9770. };
  9771. /**
  9772. * Function: isConstrainChildren
  9773. *
  9774. * Returns <constrainChildren>.
  9775. */
  9776. mxGraph.prototype.isConstrainChildren = function()
  9777. {
  9778. return this.constrainChildren;
  9779. };
  9780. /**
  9781. * Function: setConstrainChildren
  9782. *
  9783. * Sets <constrainChildren>.
  9784. */
  9785. mxGraph.prototype.setConstrainChildren = function(value)
  9786. {
  9787. this.constrainChildren = value;
  9788. };
  9789. /**
  9790. * Function: isConstrainRelativeChildren
  9791. *
  9792. * Returns <constrainRelativeChildren>.
  9793. */
  9794. mxGraph.prototype.isConstrainRelativeChildren = function()
  9795. {
  9796. return this.constrainRelativeChildren;
  9797. };
  9798. /**
  9799. * Function: setConstrainRelativeChildren
  9800. *
  9801. * Sets <constrainRelativeChildren>.
  9802. */
  9803. mxGraph.prototype.setConstrainRelativeChildren = function(value)
  9804. {
  9805. this.constrainRelativeChildren = value;
  9806. };
  9807. /**
  9808. * Function: isConstrainChildren
  9809. *
  9810. * Returns <allowNegativeCoordinates>.
  9811. */
  9812. mxGraph.prototype.isAllowNegativeCoordinates = function()
  9813. {
  9814. return this.allowNegativeCoordinates;
  9815. };
  9816. /**
  9817. * Function: setConstrainChildren
  9818. *
  9819. * Sets <allowNegativeCoordinates>.
  9820. */
  9821. mxGraph.prototype.setAllowNegativeCoordinates = function(value)
  9822. {
  9823. this.allowNegativeCoordinates = value;
  9824. };
  9825. /**
  9826. * Function: getOverlap
  9827. *
  9828. * Returns a decimal number representing the amount of the width and height
  9829. * of the given cell that is allowed to overlap its parent. A value of 0
  9830. * means all children must stay inside the parent, 1 means the child is
  9831. * allowed to be placed outside of the parent such that it touches one of
  9832. * the parents sides. If <isAllowOverlapParent> returns false for the given
  9833. * cell, then this method returns 0.
  9834. *
  9835. * Parameters:
  9836. *
  9837. * cell - <mxCell> for which the overlap ratio should be returned.
  9838. */
  9839. mxGraph.prototype.getOverlap = function(cell)
  9840. {
  9841. return (this.isAllowOverlapParent(cell)) ? this.defaultOverlap : 0;
  9842. };
  9843. /**
  9844. * Function: isAllowOverlapParent
  9845. *
  9846. * Returns true if the given cell is allowed to be placed outside of the
  9847. * parents area.
  9848. *
  9849. * Parameters:
  9850. *
  9851. * cell - <mxCell> that represents the child to be checked.
  9852. */
  9853. mxGraph.prototype.isAllowOverlapParent = function(cell)
  9854. {
  9855. return false;
  9856. };
  9857. /**
  9858. * Function: getFoldableCells
  9859. *
  9860. * Returns the cells which are movable in the given array of cells.
  9861. */
  9862. mxGraph.prototype.getFoldableCells = function(cells, collapse)
  9863. {
  9864. return this.model.filterCells(cells, mxUtils.bind(this, function(cell)
  9865. {
  9866. return this.isCellFoldable(cell, collapse);
  9867. }));
  9868. };
  9869. /**
  9870. * Function: isCellFoldable
  9871. *
  9872. * Returns true if the given cell is foldable. This implementation
  9873. * returns true if the cell has at least one child and its style
  9874. * does not specify <mxConstants.STYLE_FOLDABLE> to be 0.
  9875. *
  9876. * Parameters:
  9877. *
  9878. * cell - <mxCell> whose foldable state should be returned.
  9879. */
  9880. mxGraph.prototype.isCellFoldable = function(cell, collapse)
  9881. {
  9882. var style = this.getCurrentCellStyle(cell);
  9883. return this.model.getChildCount(cell) > 0 && style[mxConstants.STYLE_FOLDABLE] != 0;
  9884. };
  9885. /**
  9886. * Function: isValidDropTarget
  9887. *
  9888. * Returns true if the given cell is a valid drop target for the specified
  9889. * cells. If <splitEnabled> is true then this returns <isSplitTarget> for
  9890. * the given arguments else it returns true if the cell is not collapsed
  9891. * and its child count is greater than 0.
  9892. *
  9893. * Parameters:
  9894. *
  9895. * cell - <mxCell> that represents the possible drop target.
  9896. * cells - <mxCells> that should be dropped into the target.
  9897. * evt - Mouseevent that triggered the invocation.
  9898. */
  9899. mxGraph.prototype.isValidDropTarget = function(cell, cells, evt)
  9900. {
  9901. return cell != null && ((this.isSplitEnabled() &&
  9902. this.isSplitTarget(cell, cells, evt)) || (!this.model.isEdge(cell) &&
  9903. (this.isSwimlane(cell) || (this.model.getChildCount(cell) > 0 &&
  9904. !this.isCellCollapsed(cell)))));
  9905. };
  9906. /**
  9907. * Function: isSplitTarget
  9908. *
  9909. * Returns true if the given edge may be splitted into two edges with the
  9910. * given cell as a new terminal between the two.
  9911. *
  9912. * Parameters:
  9913. *
  9914. * target - <mxCell> that represents the edge to be splitted.
  9915. * cells - <mxCells> that should split the edge.
  9916. * evt - Mouseevent that triggered the invocation.
  9917. */
  9918. mxGraph.prototype.isSplitTarget = function(target, cells, evt)
  9919. {
  9920. if (this.model.isEdge(target) && cells != null && cells.length == 1 &&
  9921. this.isCellConnectable(cells[0]) && this.getEdgeValidationError(target,
  9922. this.model.getTerminal(target, true), cells[0]) == null)
  9923. {
  9924. var src = this.model.getTerminal(target, true);
  9925. var trg = this.model.getTerminal(target, false);
  9926. return (!this.model.isAncestor(cells[0], src) &&
  9927. !this.model.isAncestor(cells[0], trg));
  9928. }
  9929. return false;
  9930. };
  9931. /**
  9932. * Function: getDropTarget
  9933. *
  9934. * Returns the given cell if it is a drop target for the given cells or the
  9935. * nearest ancestor that may be used as a drop target for the given cells.
  9936. * If the given array contains a swimlane and <swimlaneNesting> is false
  9937. * then this always returns null. If no cell is given, then the bottommost
  9938. * swimlane at the location of the given event is returned.
  9939. *
  9940. * This function should only be used if <isDropEnabled> returns true.
  9941. *
  9942. * Parameters:
  9943. *
  9944. * cells - Array of <mxCells> which are to be dropped onto the target.
  9945. * evt - Mouseevent for the drag and drop.
  9946. * cell - <mxCell> that is under the mousepointer.
  9947. * clone - Optional boolean to indicate of cells will be cloned.
  9948. */
  9949. mxGraph.prototype.getDropTarget = function(cells, evt, cell, clone)
  9950. {
  9951. if (!this.isSwimlaneNesting())
  9952. {
  9953. for (var i = 0; i < cells.length; i++)
  9954. {
  9955. if (this.isSwimlane(cells[i]))
  9956. {
  9957. return null;
  9958. }
  9959. }
  9960. }
  9961. var pt = mxUtils.convertPoint(this.container,
  9962. mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  9963. pt.x -= this.panDx;
  9964. pt.y -= this.panDy;
  9965. var swimlane = this.getSwimlaneAt(pt.x, pt.y);
  9966. if (cell == null)
  9967. {
  9968. cell = swimlane;
  9969. }
  9970. else if (swimlane != null)
  9971. {
  9972. // Checks if the cell is an ancestor of the swimlane
  9973. // under the mouse and uses the swimlane in that case
  9974. var tmp = this.model.getParent(swimlane);
  9975. while (tmp != null && this.isSwimlane(tmp) && tmp != cell)
  9976. {
  9977. tmp = this.model.getParent(tmp);
  9978. }
  9979. if (tmp == cell)
  9980. {
  9981. cell = swimlane;
  9982. }
  9983. }
  9984. while (cell != null && !this.isValidDropTarget(cell, cells, evt) &&
  9985. !this.model.isLayer(cell))
  9986. {
  9987. cell = this.model.getParent(cell);
  9988. }
  9989. // Checks if parent is dropped into child if not cloning
  9990. if (clone == null || !clone)
  9991. {
  9992. var parent = cell;
  9993. while (parent != null && mxUtils.indexOf(cells, parent) < 0)
  9994. {
  9995. parent = this.model.getParent(parent);
  9996. }
  9997. }
  9998. return (!this.model.isLayer(cell) && parent == null) ? cell : null;
  9999. };
  10000. /**
  10001. * Group: Cell retrieval
  10002. */
  10003. /**
  10004. * Function: getDefaultParent
  10005. *
  10006. * Returns <defaultParent> or <mxGraphView.currentRoot> or the first child
  10007. * child of <mxGraphModel.root> if both are null. The value returned by
  10008. * this function should be used as the parent for new cells (aka default
  10009. * layer).
  10010. */
  10011. mxGraph.prototype.getDefaultParent = function()
  10012. {
  10013. var parent = this.getCurrentRoot();
  10014. if (parent == null)
  10015. {
  10016. parent = this.defaultParent;
  10017. if (parent == null)
  10018. {
  10019. var root = this.model.getRoot();
  10020. parent = this.model.getChildAt(root, 0);
  10021. }
  10022. }
  10023. return parent;
  10024. };
  10025. /**
  10026. * Function: setDefaultParent
  10027. *
  10028. * Sets the <defaultParent> to the given cell. Set this to null to return
  10029. * the first child of the root in getDefaultParent.
  10030. */
  10031. mxGraph.prototype.setDefaultParent = function(cell)
  10032. {
  10033. this.defaultParent = cell;
  10034. };
  10035. /**
  10036. * Function: getSwimlane
  10037. *
  10038. * Returns the nearest ancestor of the given cell which is a swimlane, or
  10039. * the given cell, if it is itself a swimlane.
  10040. *
  10041. * Parameters:
  10042. *
  10043. * cell - <mxCell> for which the ancestor swimlane should be returned.
  10044. */
  10045. mxGraph.prototype.getSwimlane = function(cell)
  10046. {
  10047. while (cell != null && !this.isSwimlane(cell))
  10048. {
  10049. cell = this.model.getParent(cell);
  10050. }
  10051. return cell;
  10052. };
  10053. /**
  10054. * Function: getSwimlaneAt
  10055. *
  10056. * Returns the bottom-most swimlane that intersects the given point (x, y)
  10057. * in the cell hierarchy that starts at the given parent.
  10058. *
  10059. * Parameters:
  10060. *
  10061. * x - X-coordinate of the location to be checked.
  10062. * y - Y-coordinate of the location to be checked.
  10063. * parent - <mxCell> that should be used as the root of the recursion.
  10064. * Default is <defaultParent>.
  10065. */
  10066. mxGraph.prototype.getSwimlaneAt = function (x, y, parent)
  10067. {
  10068. if (parent == null)
  10069. {
  10070. parent = this.getCurrentRoot();
  10071. if (parent == null)
  10072. {
  10073. parent = this.model.getRoot();
  10074. }
  10075. }
  10076. if (parent != null)
  10077. {
  10078. var childCount = this.model.getChildCount(parent);
  10079. for (var i = 0; i < childCount; i++)
  10080. {
  10081. var child = this.model.getChildAt(parent, i);
  10082. if (child != null)
  10083. {
  10084. var result = this.getSwimlaneAt(x, y, child);
  10085. if (result != null)
  10086. {
  10087. return result;
  10088. }
  10089. else if (this.isCellVisible(child) && this.isSwimlane(child))
  10090. {
  10091. var state = this.view.getState(child);
  10092. if (this.intersects(state, x, y))
  10093. {
  10094. return child;
  10095. }
  10096. }
  10097. }
  10098. }
  10099. }
  10100. return null;
  10101. };
  10102. /**
  10103. * Function: getCellAt
  10104. *
  10105. * Returns the bottom-most cell that intersects the given point (x, y) in
  10106. * the cell hierarchy starting at the given parent. This will also return
  10107. * swimlanes if the given location intersects the content area of the
  10108. * swimlane. If this is not desired, then the <hitsSwimlaneContent> may be
  10109. * used if the returned cell is a swimlane to determine if the location
  10110. * is inside the content area or on the actual title of the swimlane.
  10111. *
  10112. * Parameters:
  10113. *
  10114. * x - X-coordinate of the location to be checked.
  10115. * y - Y-coordinate of the location to be checked.
  10116. * parent - <mxCell> that should be used as the root of the recursion.
  10117. * Default is current root of the view or the root of the model.
  10118. * vertices - Optional boolean indicating if vertices should be returned.
  10119. * Default is true.
  10120. * edges - Optional boolean indicating if edges should be returned. Default
  10121. * is true.
  10122. * ignoreFn - Optional function that returns true if cell should be ignored.
  10123. * The function is passed the cell state and the x and y parameter.
  10124. */
  10125. mxGraph.prototype.getCellAt = function(x, y, parent, vertices, edges, ignoreFn)
  10126. {
  10127. vertices = (vertices != null) ? vertices : true;
  10128. edges = (edges != null) ? edges : true;
  10129. if (parent == null)
  10130. {
  10131. parent = this.getCurrentRoot();
  10132. if (parent == null)
  10133. {
  10134. parent = this.getModel().getRoot();
  10135. }
  10136. }
  10137. if (parent != null)
  10138. {
  10139. var childCount = this.model.getChildCount(parent);
  10140. for (var i = childCount - 1; i >= 0; i--)
  10141. {
  10142. var cell = this.model.getChildAt(parent, i);
  10143. var result = this.getCellAt(x, y, cell, vertices, edges, ignoreFn);
  10144. if (result != null)
  10145. {
  10146. return result;
  10147. }
  10148. else if (this.isCellVisible(cell) && (edges && this.model.isEdge(cell) ||
  10149. vertices && this.model.isVertex(cell)))
  10150. {
  10151. var state = this.view.getState(cell);
  10152. if (state != null && (ignoreFn == null || !ignoreFn(state, x, y)) &&
  10153. this.intersects(state, x, y))
  10154. {
  10155. return cell;
  10156. }
  10157. }
  10158. }
  10159. }
  10160. return null;
  10161. };
  10162. /**
  10163. * Function: intersects
  10164. *
  10165. * Returns the bottom-most cell that intersects the given point (x, y) in
  10166. * the cell hierarchy that starts at the given parent.
  10167. *
  10168. * Parameters:
  10169. *
  10170. * state - <mxCellState> that represents the cell state.
  10171. * x - X-coordinate of the location to be checked.
  10172. * y - Y-coordinate of the location to be checked.
  10173. */
  10174. mxGraph.prototype.intersects = function(state, x, y)
  10175. {
  10176. if (state != null)
  10177. {
  10178. var pts = state.absolutePoints;
  10179. if (pts != null)
  10180. {
  10181. var t2 = this.tolerance * this.tolerance;
  10182. var pt = pts[0];
  10183. for (var i = 1; i < pts.length; i++)
  10184. {
  10185. var next = pts[i];
  10186. var dist = mxUtils.ptSegDistSq(pt.x, pt.y, next.x, next.y, x, y);
  10187. if (dist <= t2)
  10188. {
  10189. return true;
  10190. }
  10191. pt = next;
  10192. }
  10193. }
  10194. else
  10195. {
  10196. var alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
  10197. if (alpha != 0)
  10198. {
  10199. var cos = Math.cos(-alpha);
  10200. var sin = Math.sin(-alpha);
  10201. var cx = new mxPoint(state.getCenterX(), state.getCenterY());
  10202. var pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
  10203. x = pt.x;
  10204. y = pt.y;
  10205. }
  10206. if (mxUtils.contains(state, x, y))
  10207. {
  10208. return true;
  10209. }
  10210. }
  10211. }
  10212. return false;
  10213. };
  10214. /**
  10215. * Function: hitsSwimlaneContent
  10216. *
  10217. * Returns true if the given coordinate pair is inside the content
  10218. * are of the given swimlane.
  10219. *
  10220. * Parameters:
  10221. *
  10222. * swimlane - <mxCell> that specifies the swimlane.
  10223. * x - X-coordinate of the mouse event.
  10224. * y - Y-coordinate of the mouse event.
  10225. */
  10226. mxGraph.prototype.hitsSwimlaneContent = function(swimlane, x, y)
  10227. {
  10228. var state = this.getView().getState(swimlane);
  10229. var size = this.getStartSize(swimlane);
  10230. if (state != null)
  10231. {
  10232. var scale = this.getView().getScale();
  10233. x -= state.x;
  10234. y -= state.y;
  10235. if (size.width > 0 && x > 0 && x > size.width * scale)
  10236. {
  10237. return true;
  10238. }
  10239. else if (size.height > 0 && y > 0 && y > size.height * scale)
  10240. {
  10241. return true;
  10242. }
  10243. }
  10244. return false;
  10245. };
  10246. /**
  10247. * Function: getChildVertices
  10248. *
  10249. * Returns the visible child vertices of the given parent.
  10250. *
  10251. * Parameters:
  10252. *
  10253. * parent - <mxCell> whose children should be returned.
  10254. */
  10255. mxGraph.prototype.getChildVertices = function(parent)
  10256. {
  10257. return this.getChildCells(parent, true, false);
  10258. };
  10259. /**
  10260. * Function: getChildEdges
  10261. *
  10262. * Returns the visible child edges of the given parent.
  10263. *
  10264. * Parameters:
  10265. *
  10266. * parent - <mxCell> whose child vertices should be returned.
  10267. */
  10268. mxGraph.prototype.getChildEdges = function(parent)
  10269. {
  10270. return this.getChildCells(parent, false, true);
  10271. };
  10272. /**
  10273. * Function: getChildCells
  10274. *
  10275. * Returns the visible child vertices or edges in the given parent. If
  10276. * vertices and edges is false, then all children are returned.
  10277. *
  10278. * Parameters:
  10279. *
  10280. * parent - <mxCell> whose children should be returned.
  10281. * vertices - Optional boolean that specifies if child vertices should
  10282. * be returned. Default is false.
  10283. * edges - Optional boolean that specifies if child edges should
  10284. * be returned. Default is false.
  10285. */
  10286. mxGraph.prototype.getChildCells = function(parent, vertices, edges)
  10287. {
  10288. parent = (parent != null) ? parent : this.getDefaultParent();
  10289. vertices = (vertices != null) ? vertices : false;
  10290. edges = (edges != null) ? edges : false;
  10291. var cells = this.model.getChildCells(parent, vertices, edges);
  10292. var result = [];
  10293. // Filters out the non-visible child cells
  10294. for (var i = 0; i < cells.length; i++)
  10295. {
  10296. if (this.isCellVisible(cells[i]))
  10297. {
  10298. result.push(cells[i]);
  10299. }
  10300. }
  10301. return result;
  10302. };
  10303. /**
  10304. * Function: getConnections
  10305. *
  10306. * Returns all visible edges connected to the given cell without loops.
  10307. *
  10308. * Parameters:
  10309. *
  10310. * cell - <mxCell> whose connections should be returned.
  10311. * parent - Optional parent of the opposite end for a connection to be
  10312. * returned.
  10313. */
  10314. mxGraph.prototype.getConnections = function(cell, parent)
  10315. {
  10316. return this.getEdges(cell, parent, true, true, false);
  10317. };
  10318. /**
  10319. * Function: getIncomingEdges
  10320. *
  10321. * Returns the visible incoming edges for the given cell. If the optional
  10322. * parent argument is specified, then only child edges of the given parent
  10323. * are returned.
  10324. *
  10325. * Parameters:
  10326. *
  10327. * cell - <mxCell> whose incoming edges should be returned.
  10328. * parent - Optional parent of the opposite end for an edge to be
  10329. * returned.
  10330. */
  10331. mxGraph.prototype.getIncomingEdges = function(cell, parent)
  10332. {
  10333. return this.getEdges(cell, parent, true, false, false);
  10334. };
  10335. /**
  10336. * Function: getOutgoingEdges
  10337. *
  10338. * Returns the visible outgoing edges for the given cell. If the optional
  10339. * parent argument is specified, then only child edges of the given parent
  10340. * are returned.
  10341. *
  10342. * Parameters:
  10343. *
  10344. * cell - <mxCell> whose outgoing edges should be returned.
  10345. * parent - Optional parent of the opposite end for an edge to be
  10346. * returned.
  10347. */
  10348. mxGraph.prototype.getOutgoingEdges = function(cell, parent)
  10349. {
  10350. return this.getEdges(cell, parent, false, true, false);
  10351. };
  10352. /**
  10353. * Function: getEdges
  10354. *
  10355. * Returns the incoming and/or outgoing edges for the given cell.
  10356. * If the optional parent argument is specified, then only edges are returned
  10357. * where the opposite is in the given parent cell. If at least one of incoming
  10358. * or outgoing is true, then loops are ignored, if both are false, then all
  10359. * edges connected to the given cell are returned including loops.
  10360. *
  10361. * Parameters:
  10362. *
  10363. * cell - <mxCell> whose edges should be returned.
  10364. * parent - Optional parent of the opposite end for an edge to be
  10365. * returned.
  10366. * incoming - Optional boolean that specifies if incoming edges should
  10367. * be included in the result. Default is true.
  10368. * outgoing - Optional boolean that specifies if outgoing edges should
  10369. * be included in the result. Default is true.
  10370. * includeLoops - Optional boolean that specifies if loops should be
  10371. * included in the result. Default is true.
  10372. * recurse - Optional boolean the specifies if the parent specified only
  10373. * need be an ancestral parent, true, or the direct parent, false.
  10374. * Default is false
  10375. */
  10376. mxGraph.prototype.getEdges = function(cell, parent, incoming, outgoing, includeLoops, recurse)
  10377. {
  10378. incoming = (incoming != null) ? incoming : true;
  10379. outgoing = (outgoing != null) ? outgoing : true;
  10380. includeLoops = (includeLoops != null) ? includeLoops : true;
  10381. recurse = (recurse != null) ? recurse : false;
  10382. var edges = [];
  10383. var isCollapsed = this.isCellCollapsed(cell);
  10384. var childCount = this.model.getChildCount(cell);
  10385. for (var i = 0; i < childCount; i++)
  10386. {
  10387. var child = this.model.getChildAt(cell, i);
  10388. if (isCollapsed || !this.isCellVisible(child))
  10389. {
  10390. edges = edges.concat(this.model.getEdges(child, incoming, outgoing));
  10391. }
  10392. }
  10393. edges = edges.concat(this.model.getEdges(cell, incoming, outgoing));
  10394. var result = [];
  10395. for (var i = 0; i < edges.length; i++)
  10396. {
  10397. var state = this.view.getState(edges[i]);
  10398. var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  10399. var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  10400. if ((includeLoops && source == target) || ((source != target) && ((incoming &&
  10401. target == cell && (parent == null || this.isValidAncestor(source, parent, recurse))) ||
  10402. (outgoing && source == cell && (parent == null ||
  10403. this.isValidAncestor(target, parent, recurse))))))
  10404. {
  10405. result.push(edges[i]);
  10406. }
  10407. }
  10408. return result;
  10409. };
  10410. /**
  10411. * Function: isValidAncestor
  10412. *
  10413. * Returns whether or not the specified parent is a valid
  10414. * ancestor of the specified cell, either direct or indirectly
  10415. * based on whether ancestor recursion is enabled.
  10416. *
  10417. * Parameters:
  10418. *
  10419. * cell - <mxCell> the possible child cell
  10420. * parent - <mxCell> the possible parent cell
  10421. * recurse - boolean whether or not to recurse the child ancestors
  10422. */
  10423. mxGraph.prototype.isValidAncestor = function(cell, parent, recurse)
  10424. {
  10425. return (recurse ? this.model.isAncestor(parent, cell) : this.model
  10426. .getParent(cell) == parent);
  10427. };
  10428. /**
  10429. * Function: getOpposites
  10430. *
  10431. * Returns all distinct visible opposite cells for the specified terminal
  10432. * on the given edges.
  10433. *
  10434. * Parameters:
  10435. *
  10436. * edges - Array of <mxCells> that contains the edges whose opposite
  10437. * terminals should be returned.
  10438. * terminal - Terminal that specifies the end whose opposite should be
  10439. * returned.
  10440. * sources - Optional boolean that specifies if source terminals should be
  10441. * included in the result. Default is true.
  10442. * targets - Optional boolean that specifies if targer terminals should be
  10443. * included in the result. Default is true.
  10444. */
  10445. mxGraph.prototype.getOpposites = function(edges, terminal, sources, targets)
  10446. {
  10447. sources = (sources != null) ? sources : true;
  10448. targets = (targets != null) ? targets : true;
  10449. var terminals = [];
  10450. // Fast lookup to avoid duplicates in terminals array
  10451. var dict = new mxDictionary();
  10452. if (edges != null)
  10453. {
  10454. for (var i = 0; i < edges.length; i++)
  10455. {
  10456. var state = this.view.getState(edges[i]);
  10457. var source = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  10458. var target = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  10459. // Checks if the terminal is the source of the edge and if the
  10460. // target should be stored in the result
  10461. if (source == terminal && target != null && target != terminal && targets)
  10462. {
  10463. if (!dict.get(target))
  10464. {
  10465. dict.put(target, true);
  10466. terminals.push(target);
  10467. }
  10468. }
  10469. // Checks if the terminal is the taget of the edge and if the
  10470. // source should be stored in the result
  10471. else if (target == terminal && source != null && source != terminal && sources)
  10472. {
  10473. if (!dict.get(source))
  10474. {
  10475. dict.put(source, true);
  10476. terminals.push(source);
  10477. }
  10478. }
  10479. }
  10480. }
  10481. return terminals;
  10482. };
  10483. /**
  10484. * Function: getEdgesBetween
  10485. *
  10486. * Returns the edges between the given source and target. This takes into
  10487. * account collapsed and invisible cells and returns the connected edges
  10488. * as displayed on the screen.
  10489. *
  10490. * Parameters:
  10491. *
  10492. * source -
  10493. * target -
  10494. * directed -
  10495. */
  10496. mxGraph.prototype.getEdgesBetween = function(source, target, directed)
  10497. {
  10498. directed = (directed != null) ? directed : false;
  10499. var edges = this.getEdges(source);
  10500. var result = [];
  10501. // Checks if the edge is connected to the correct
  10502. // cell and returns the first match
  10503. for (var i = 0; i < edges.length; i++)
  10504. {
  10505. var state = this.view.getState(edges[i]);
  10506. var src = (state != null) ? state.getVisibleTerminal(true) : this.view.getVisibleTerminal(edges[i], true);
  10507. var trg = (state != null) ? state.getVisibleTerminal(false) : this.view.getVisibleTerminal(edges[i], false);
  10508. if ((src == source && trg == target) || (!directed && src == target && trg == source))
  10509. {
  10510. result.push(edges[i]);
  10511. }
  10512. }
  10513. return result;
  10514. };
  10515. /**
  10516. * Function: getPointForEvent
  10517. *
  10518. * Returns an <mxPoint> representing the given event in the unscaled,
  10519. * non-translated coordinate space of <container> and applies the grid.
  10520. *
  10521. * Parameters:
  10522. *
  10523. * evt - Mousevent that contains the mouse pointer location.
  10524. * addOffset - Optional boolean that specifies if the position should be
  10525. * offset by half of the <gridSize>. Default is true.
  10526. */
  10527. mxGraph.prototype.getPointForEvent = function(evt, addOffset)
  10528. {
  10529. var p = mxUtils.convertPoint(this.container,
  10530. mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  10531. var s = this.view.scale;
  10532. var tr = this.view.translate;
  10533. var off = (addOffset != false) ? this.gridSize / 2 : 0;
  10534. p.x = this.snap(p.x / s - tr.x - off);
  10535. p.y = this.snap(p.y / s - tr.y - off);
  10536. return p;
  10537. };
  10538. /**
  10539. * Function: getCells
  10540. *
  10541. * Returns the child vertices and edges of the given parent that are contained
  10542. * in the given rectangle. The result is added to the optional result array,
  10543. * which is returned. If no result array is specified then a new array is
  10544. * created and returned.
  10545. *
  10546. * Parameters:
  10547. *
  10548. * x - X-coordinate of the rectangle.
  10549. * y - Y-coordinate of the rectangle.
  10550. * width - Width of the rectangle.
  10551. * height - Height of the rectangle.
  10552. * parent - <mxCell> that should be used as the root of the recursion.
  10553. * Default is current root of the view or the root of the model.
  10554. * result - Optional array to store the result in.
  10555. * intersection - Optional <mxRectangle> to check vertices for intersection.
  10556. * ignoreFn - Optional function to check if a cell state is ignored.
  10557. * includeDescendants - Optional boolean flag to add descendants to the result.
  10558. * Default is false.
  10559. */
  10560. mxGraph.prototype.getCells = function(x, y, width, height, parent, result, intersection, ignoreFn, includeDescendants)
  10561. {
  10562. result = (result != null) ? result : [];
  10563. if (width > 0 || height > 0 || intersection != null)
  10564. {
  10565. var model = this.getModel();
  10566. var right = x + width;
  10567. var bottom = y + height;
  10568. if (parent == null)
  10569. {
  10570. parent = this.getCurrentRoot();
  10571. if (parent == null)
  10572. {
  10573. parent = model.getRoot();
  10574. }
  10575. }
  10576. if (parent != null)
  10577. {
  10578. var childCount = model.getChildCount(parent);
  10579. for (var i = 0; i < childCount; i++)
  10580. {
  10581. var cell = model.getChildAt(parent, i);
  10582. var state = this.view.getState(cell);
  10583. if (state != null && this.isCellVisible(cell) &&
  10584. (ignoreFn == null || !ignoreFn(state)))
  10585. {
  10586. var deg = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0;
  10587. var box = state;
  10588. if (deg != 0)
  10589. {
  10590. box = mxUtils.getBoundingBox(box, deg);
  10591. }
  10592. var hit = (intersection != null && model.isVertex(cell) && mxUtils.intersects(intersection, box)) ||
  10593. (intersection == null && (model.isEdge(cell) || model.isVertex(cell)) &&
  10594. box.x >= x && box.y + box.height <= bottom &&
  10595. box.y >= y && box.x + box.width <= right);
  10596. if (hit)
  10597. {
  10598. result.push(cell);
  10599. }
  10600. if (!hit || includeDescendants)
  10601. {
  10602. this.getCells(x, y, width, height, cell, result, intersection, ignoreFn, includeDescendants);
  10603. }
  10604. }
  10605. }
  10606. }
  10607. }
  10608. return result;
  10609. };
  10610. /**
  10611. * Function: getCellsBeyond
  10612. *
  10613. * Returns the children of the given parent that are contained in the
  10614. * halfpane from the given point (x0, y0) rightwards or downwards
  10615. * depending on rightHalfpane and bottomHalfpane.
  10616. *
  10617. * Parameters:
  10618. *
  10619. * x0 - X-coordinate of the origin.
  10620. * y0 - Y-coordinate of the origin.
  10621. * parent - Optional <mxCell> whose children should be checked. Default is
  10622. * <defaultParent>.
  10623. * rightHalfpane - Boolean indicating if the cells in the right halfpane
  10624. * from the origin should be returned.
  10625. * bottomHalfpane - Boolean indicating if the cells in the bottom halfpane
  10626. * from the origin should be returned.
  10627. */
  10628. mxGraph.prototype.getCellsBeyond = function(x0, y0, parent, rightHalfpane, bottomHalfpane)
  10629. {
  10630. var result = [];
  10631. if (rightHalfpane || bottomHalfpane)
  10632. {
  10633. if (parent == null)
  10634. {
  10635. parent = this.getDefaultParent();
  10636. }
  10637. if (parent != null)
  10638. {
  10639. var childCount = this.model.getChildCount(parent);
  10640. for (var i = 0; i < childCount; i++)
  10641. {
  10642. var child = this.model.getChildAt(parent, i);
  10643. var state = this.view.getState(child);
  10644. if (this.isCellVisible(child) && state != null)
  10645. {
  10646. if ((!rightHalfpane || state.x >= x0) &&
  10647. (!bottomHalfpane || state.y >= y0))
  10648. {
  10649. result.push(child);
  10650. }
  10651. }
  10652. }
  10653. }
  10654. }
  10655. return result;
  10656. };
  10657. /**
  10658. * Function: findTreeRoots
  10659. *
  10660. * Returns all children in the given parent which do not have incoming
  10661. * edges. If the result is empty then the with the greatest difference
  10662. * between incoming and outgoing edges is returned.
  10663. *
  10664. * Parameters:
  10665. *
  10666. * parent - <mxCell> whose children should be checked.
  10667. * isolate - Optional boolean that specifies if edges should be ignored if
  10668. * the opposite end is not a child of the given parent cell. Default is
  10669. * false.
  10670. * invert - Optional boolean that specifies if outgoing or incoming edges
  10671. * should be counted for a tree root. If false then outgoing edges will be
  10672. * counted. Default is false.
  10673. */
  10674. mxGraph.prototype.findTreeRoots = function(parent, isolate, invert)
  10675. {
  10676. isolate = (isolate != null) ? isolate : false;
  10677. invert = (invert != null) ? invert : false;
  10678. var roots = [];
  10679. if (parent != null)
  10680. {
  10681. var model = this.getModel();
  10682. var childCount = model.getChildCount(parent);
  10683. var best = null;
  10684. var maxDiff = 0;
  10685. for (var i=0; i<childCount; i++)
  10686. {
  10687. var cell = model.getChildAt(parent, i);
  10688. if (this.model.isVertex(cell) && this.isCellVisible(cell))
  10689. {
  10690. var conns = this.getConnections(cell, (isolate) ? parent : null);
  10691. var fanOut = 0;
  10692. var fanIn = 0;
  10693. for (var j = 0; j < conns.length; j++)
  10694. {
  10695. var src = this.view.getVisibleTerminal(conns[j], true);
  10696. if (src == cell)
  10697. {
  10698. fanOut++;
  10699. }
  10700. else
  10701. {
  10702. fanIn++;
  10703. }
  10704. }
  10705. if ((invert && fanOut == 0 && fanIn > 0) ||
  10706. (!invert && fanIn == 0 && fanOut > 0))
  10707. {
  10708. roots.push(cell);
  10709. }
  10710. var diff = (invert) ? fanIn - fanOut : fanOut - fanIn;
  10711. if (diff > maxDiff)
  10712. {
  10713. maxDiff = diff;
  10714. best = cell;
  10715. }
  10716. }
  10717. }
  10718. if (roots.length == 0 && best != null)
  10719. {
  10720. roots.push(best);
  10721. }
  10722. }
  10723. return roots;
  10724. };
  10725. /**
  10726. * Function: traverse
  10727. *
  10728. * Traverses the (directed) graph invoking the given function for each
  10729. * visited vertex and edge. The function is invoked with the current vertex
  10730. * and the incoming edge as a parameter. This implementation makes sure
  10731. * each vertex is only visited once. The function may return false if the
  10732. * traversal should stop at the given vertex.
  10733. *
  10734. * Example:
  10735. *
  10736. * (code)
  10737. * mxLog.show();
  10738. * var cell = graph.getSelectionCell();
  10739. * graph.traverse(cell, false, function(vertex, edge)
  10740. * {
  10741. * mxLog.debug(graph.getLabel(vertex));
  10742. * });
  10743. * (end)
  10744. *
  10745. * Parameters:
  10746. *
  10747. * vertex - <mxCell> that represents the vertex where the traversal starts.
  10748. * directed - Optional boolean indicating if edges should only be traversed
  10749. * from source to target. Default is true.
  10750. * func - Visitor function that takes the current vertex and the incoming
  10751. * edge as arguments. The traversal stops if the function returns false.
  10752. * edge - Optional <mxCell> that represents the incoming edge. This is
  10753. * null for the first step of the traversal.
  10754. * visited - Optional <mxDictionary> from cells to true for the visited cells.
  10755. * inverse - Optional boolean to traverse in inverse direction. Default is false.
  10756. * This is ignored if directed is false.
  10757. */
  10758. mxGraph.prototype.traverse = function(vertex, directed, func, edge, visited, inverse)
  10759. {
  10760. if (func != null && vertex != null)
  10761. {
  10762. directed = (directed != null) ? directed : true;
  10763. inverse = (inverse != null) ? inverse : false;
  10764. visited = visited || new mxDictionary();
  10765. if (!visited.get(vertex))
  10766. {
  10767. visited.put(vertex, true);
  10768. var result = func(vertex, edge);
  10769. if (result == null || result)
  10770. {
  10771. var edgeCount = this.model.getEdgeCount(vertex);
  10772. if (edgeCount > 0)
  10773. {
  10774. for (var i = 0; i < edgeCount; i++)
  10775. {
  10776. var e = this.model.getEdgeAt(vertex, i);
  10777. var isSource = this.model.getTerminal(e, true) == vertex;
  10778. if (!directed || (!inverse == isSource))
  10779. {
  10780. var next = this.model.getTerminal(e, !isSource);
  10781. this.traverse(next, directed, func, e, visited, inverse);
  10782. }
  10783. }
  10784. }
  10785. }
  10786. }
  10787. }
  10788. };
  10789. /**
  10790. * Group: Selection
  10791. */
  10792. /**
  10793. * Function: isCellSelected
  10794. *
  10795. * Returns true if the given cell is selected.
  10796. *
  10797. * Parameters:
  10798. *
  10799. * cell - <mxCell> for which the selection state should be returned.
  10800. */
  10801. mxGraph.prototype.isCellSelected = function(cell)
  10802. {
  10803. return this.getSelectionModel().isSelected(cell);
  10804. };
  10805. /**
  10806. * Function: isSelectionEmpty
  10807. *
  10808. * Returns true if the selection is empty.
  10809. */
  10810. mxGraph.prototype.isSelectionEmpty = function()
  10811. {
  10812. return this.getSelectionModel().isEmpty();
  10813. };
  10814. /**
  10815. * Function: clearSelection
  10816. *
  10817. * Clears the selection using <mxGraphSelectionModel.clear>.
  10818. */
  10819. mxGraph.prototype.clearSelection = function()
  10820. {
  10821. return this.getSelectionModel().clear();
  10822. };
  10823. /**
  10824. * Function: getSelectionCount
  10825. *
  10826. * Returns the number of selected cells.
  10827. */
  10828. mxGraph.prototype.getSelectionCount = function()
  10829. {
  10830. return this.getSelectionModel().cells.length;
  10831. };
  10832. /**
  10833. * Function: getSelectionCell
  10834. *
  10835. * Returns the first cell from the array of selected <mxCells>.
  10836. */
  10837. mxGraph.prototype.getSelectionCell = function()
  10838. {
  10839. return this.getSelectionModel().cells[0];
  10840. };
  10841. /**
  10842. * Function: getSelectionCells
  10843. *
  10844. * Returns the array of selected <mxCells>.
  10845. */
  10846. mxGraph.prototype.getSelectionCells = function()
  10847. {
  10848. return this.getSelectionModel().cells.slice();
  10849. };
  10850. /**
  10851. * Function: setSelectionCell
  10852. *
  10853. * Sets the selection cell.
  10854. *
  10855. * Parameters:
  10856. *
  10857. * cell - <mxCell> to be selected.
  10858. */
  10859. mxGraph.prototype.setSelectionCell = function(cell)
  10860. {
  10861. this.getSelectionModel().setCell(cell);
  10862. };
  10863. /**
  10864. * Function: setSelectionCells
  10865. *
  10866. * Sets the selection cell.
  10867. *
  10868. * Parameters:
  10869. *
  10870. * cells - Array of <mxCells> to be selected.
  10871. */
  10872. mxGraph.prototype.setSelectionCells = function(cells)
  10873. {
  10874. this.getSelectionModel().setCells(cells);
  10875. };
  10876. /**
  10877. * Function: addSelectionCell
  10878. *
  10879. * Adds the given cell to the selection.
  10880. *
  10881. * Parameters:
  10882. *
  10883. * cell - <mxCell> to be add to the selection.
  10884. */
  10885. mxGraph.prototype.addSelectionCell = function(cell)
  10886. {
  10887. this.getSelectionModel().addCell(cell);
  10888. };
  10889. /**
  10890. * Function: addSelectionCells
  10891. *
  10892. * Adds the given cells to the selection.
  10893. *
  10894. * Parameters:
  10895. *
  10896. * cells - Array of <mxCells> to be added to the selection.
  10897. */
  10898. mxGraph.prototype.addSelectionCells = function(cells)
  10899. {
  10900. this.getSelectionModel().addCells(cells);
  10901. };
  10902. /**
  10903. * Function: removeSelectionCell
  10904. *
  10905. * Removes the given cell from the selection.
  10906. *
  10907. * Parameters:
  10908. *
  10909. * cell - <mxCell> to be removed from the selection.
  10910. */
  10911. mxGraph.prototype.removeSelectionCell = function(cell)
  10912. {
  10913. this.getSelectionModel().removeCell(cell);
  10914. };
  10915. /**
  10916. * Function: removeSelectionCells
  10917. *
  10918. * Removes the given cells from the selection.
  10919. *
  10920. * Parameters:
  10921. *
  10922. * cells - Array of <mxCells> to be removed from the selection.
  10923. */
  10924. mxGraph.prototype.removeSelectionCells = function(cells)
  10925. {
  10926. this.getSelectionModel().removeCells(cells);
  10927. };
  10928. /**
  10929. * Function: selectRegion
  10930. *
  10931. * Selects and returns the cells inside the given rectangle for the
  10932. * specified event.
  10933. *
  10934. * Parameters:
  10935. *
  10936. * rect - <mxRectangle> that represents the region to be selected.
  10937. * evt - Mouseevent that triggered the selection.
  10938. */
  10939. mxGraph.prototype.selectRegion = function(rect, evt)
  10940. {
  10941. var cells = this.getCells(rect.x, rect.y, rect.width, rect.height);
  10942. this.selectCellsForEvent(cells, evt);
  10943. return cells;
  10944. };
  10945. /**
  10946. * Function: selectNextCell
  10947. *
  10948. * Selects the next cell.
  10949. */
  10950. mxGraph.prototype.selectNextCell = function()
  10951. {
  10952. this.selectCell(true);
  10953. };
  10954. /**
  10955. * Function: selectPreviousCell
  10956. *
  10957. * Selects the previous cell.
  10958. */
  10959. mxGraph.prototype.selectPreviousCell = function()
  10960. {
  10961. this.selectCell();
  10962. };
  10963. /**
  10964. * Function: selectParentCell
  10965. *
  10966. * Selects the parent cell.
  10967. */
  10968. mxGraph.prototype.selectParentCell = function()
  10969. {
  10970. this.selectCell(false, true);
  10971. };
  10972. /**
  10973. * Function: selectChildCell
  10974. *
  10975. * Selects the first child cell.
  10976. */
  10977. mxGraph.prototype.selectChildCell = function()
  10978. {
  10979. this.selectCell(false, false, true);
  10980. };
  10981. /**
  10982. * Function: selectCell
  10983. *
  10984. * Selects the next, parent, first child or previous cell, if all arguments
  10985. * are false.
  10986. *
  10987. * Parameters:
  10988. *
  10989. * isNext - Boolean indicating if the next cell should be selected.
  10990. * isParent - Boolean indicating if the parent cell should be selected.
  10991. * isChild - Boolean indicating if the first child cell should be selected.
  10992. */
  10993. mxGraph.prototype.selectCell = function(isNext, isParent, isChild)
  10994. {
  10995. var sel = this.selectionModel;
  10996. var cell = (sel.cells.length > 0) ? sel.cells[0] : null;
  10997. if (sel.cells.length > 1)
  10998. {
  10999. sel.clear();
  11000. }
  11001. var parent = (cell != null) ?
  11002. this.model.getParent(cell) :
  11003. this.getDefaultParent();
  11004. var childCount = this.model.getChildCount(parent);
  11005. if (cell == null && childCount > 0)
  11006. {
  11007. var child = this.model.getChildAt(parent, 0);
  11008. this.setSelectionCell(child);
  11009. }
  11010. else if ((cell == null || isParent) &&
  11011. this.view.getState(parent) != null &&
  11012. this.model.getGeometry(parent) != null)
  11013. {
  11014. if (this.getCurrentRoot() != parent)
  11015. {
  11016. this.setSelectionCell(parent);
  11017. }
  11018. }
  11019. else if (cell != null && isChild)
  11020. {
  11021. var tmp = this.model.getChildCount(cell);
  11022. if (tmp > 0)
  11023. {
  11024. var child = this.model.getChildAt(cell, 0);
  11025. this.setSelectionCell(child);
  11026. }
  11027. }
  11028. else if (childCount > 0)
  11029. {
  11030. var i = parent.getIndex(cell);
  11031. if (isNext)
  11032. {
  11033. i++;
  11034. var child = this.model.getChildAt(parent, i % childCount);
  11035. this.setSelectionCell(child);
  11036. }
  11037. else
  11038. {
  11039. i--;
  11040. var index = (i < 0) ? childCount - 1 : i;
  11041. var child = this.model.getChildAt(parent, index);
  11042. this.setSelectionCell(child);
  11043. }
  11044. }
  11045. };
  11046. /**
  11047. * Function: selectAll
  11048. *
  11049. * Selects all children of the given parent cell or the children of the
  11050. * default parent if no parent is specified. To select leaf vertices and/or
  11051. * edges use <selectCells>.
  11052. *
  11053. * Parameters:
  11054. *
  11055. * parent - Optional <mxCell> whose children should be selected.
  11056. * Default is <defaultParent>.
  11057. * descendants - Optional boolean specifying whether all descendants should be
  11058. * selected. Default is false.
  11059. */
  11060. mxGraph.prototype.selectAll = function(parent, descendants)
  11061. {
  11062. parent = parent || this.getDefaultParent();
  11063. var cells = (descendants) ? this.model.filterDescendants(mxUtils.bind(this, function(cell)
  11064. {
  11065. return cell != parent && this.view.getState(cell) != null;
  11066. }), parent) : this.model.getChildren(parent);
  11067. if (cells != null)
  11068. {
  11069. this.setSelectionCells(cells);
  11070. }
  11071. };
  11072. /**
  11073. * Function: selectVertices
  11074. *
  11075. * Select all vertices inside the given parent or the default parent.
  11076. */
  11077. mxGraph.prototype.selectVertices = function(parent, selectGroups)
  11078. {
  11079. this.selectCells(true, false, parent, selectGroups);
  11080. };
  11081. /**
  11082. * Function: selectVertices
  11083. *
  11084. * Select all vertices inside the given parent or the default parent.
  11085. */
  11086. mxGraph.prototype.selectEdges = function(parent)
  11087. {
  11088. this.selectCells(false, true, parent);
  11089. };
  11090. /**
  11091. * Function: selectCells
  11092. *
  11093. * Selects all vertices and/or edges depending on the given boolean
  11094. * arguments recursively, starting at the given parent or the default
  11095. * parent if no parent is specified. Use <selectAll> to select all cells.
  11096. * For vertices, only cells with no children are selected.
  11097. *
  11098. * Parameters:
  11099. *
  11100. * vertices - Boolean indicating if vertices should be selected.
  11101. * edges - Boolean indicating if edges should be selected.
  11102. * parent - Optional <mxCell> that acts as the root of the recursion.
  11103. * Default is <defaultParent>.
  11104. * selectGroups - Optional boolean that specifies if groups should be
  11105. * selected. Default is false.
  11106. */
  11107. mxGraph.prototype.selectCells = function(vertices, edges, parent, selectGroups)
  11108. {
  11109. parent = parent || this.getDefaultParent();
  11110. var filter = mxUtils.bind(this, function(cell)
  11111. {
  11112. return this.view.getState(cell) != null &&
  11113. (((selectGroups || this.model.getChildCount(cell) == 0) &&
  11114. this.model.isVertex(cell) && vertices
  11115. && !this.model.isEdge(this.model.getParent(cell))) ||
  11116. (this.model.isEdge(cell) && edges));
  11117. });
  11118. var cells = this.model.filterDescendants(filter, parent);
  11119. if (cells != null)
  11120. {
  11121. this.setSelectionCells(cells);
  11122. }
  11123. };
  11124. /**
  11125. * Function: selectCellForEvent
  11126. *
  11127. * Selects the given cell by either adding it to the selection or
  11128. * replacing the selection depending on whether the given mouse event is a
  11129. * toggle event.
  11130. *
  11131. * Parameters:
  11132. *
  11133. * cell - <mxCell> to be selected.
  11134. * evt - Optional mouseevent that triggered the selection.
  11135. */
  11136. mxGraph.prototype.selectCellForEvent = function(cell, evt)
  11137. {
  11138. var isSelected = this.isCellSelected(cell);
  11139. if (this.isToggleEvent(evt))
  11140. {
  11141. if (isSelected)
  11142. {
  11143. this.removeSelectionCell(cell);
  11144. }
  11145. else
  11146. {
  11147. this.addSelectionCell(cell);
  11148. }
  11149. }
  11150. else if (!isSelected || this.getSelectionCount() != 1)
  11151. {
  11152. this.setSelectionCell(cell);
  11153. }
  11154. };
  11155. /**
  11156. * Function: selectCellsForEvent
  11157. *
  11158. * Selects the given cells by either adding them to the selection or
  11159. * replacing the selection depending on whether the given mouse event is a
  11160. * toggle event.
  11161. *
  11162. * Parameters:
  11163. *
  11164. * cells - Array of <mxCells> to be selected.
  11165. * evt - Optional mouseevent that triggered the selection.
  11166. */
  11167. mxGraph.prototype.selectCellsForEvent = function(cells, evt)
  11168. {
  11169. if (this.isToggleEvent(evt))
  11170. {
  11171. this.addSelectionCells(cells);
  11172. }
  11173. else
  11174. {
  11175. this.setSelectionCells(cells);
  11176. }
  11177. };
  11178. /**
  11179. * Group: Selection state
  11180. */
  11181. /**
  11182. * Function: createHandler
  11183. *
  11184. * Creates a new handler for the given cell state. This implementation
  11185. * returns a new <mxEdgeHandler> of the corresponding cell is an edge,
  11186. * otherwise it returns an <mxVertexHandler>.
  11187. *
  11188. * Parameters:
  11189. *
  11190. * state - <mxCellState> whose handler should be created.
  11191. */
  11192. mxGraph.prototype.createHandler = function(state)
  11193. {
  11194. var result = null;
  11195. if (state != null)
  11196. {
  11197. if (this.model.isEdge(state.cell))
  11198. {
  11199. var source = state.getVisibleTerminalState(true);
  11200. var target = state.getVisibleTerminalState(false);
  11201. var geo = this.getCellGeometry(state.cell);
  11202. var edgeStyle = this.view.getEdgeStyle(state, (geo != null) ? geo.points : null, source, target);
  11203. result = this.createEdgeHandler(state, edgeStyle);
  11204. }
  11205. else
  11206. {
  11207. result = this.createVertexHandler(state);
  11208. }
  11209. }
  11210. return result;
  11211. };
  11212. /**
  11213. * Function: createVertexHandler
  11214. *
  11215. * Hooks to create a new <mxVertexHandler> for the given <mxCellState>.
  11216. *
  11217. * Parameters:
  11218. *
  11219. * state - <mxCellState> to create the handler for.
  11220. */
  11221. mxGraph.prototype.createVertexHandler = function(state)
  11222. {
  11223. return new mxVertexHandler(state);
  11224. };
  11225. /**
  11226. * Function: createEdgeHandler
  11227. *
  11228. * Hooks to create a new <mxEdgeHandler> for the given <mxCellState>.
  11229. *
  11230. * Parameters:
  11231. *
  11232. * state - <mxCellState> to create the handler for.
  11233. */
  11234. mxGraph.prototype.createEdgeHandler = function(state, edgeStyle)
  11235. {
  11236. var result = null;
  11237. if (edgeStyle == mxEdgeStyle.Loop ||
  11238. edgeStyle == mxEdgeStyle.ElbowConnector ||
  11239. edgeStyle == mxEdgeStyle.SideToSide ||
  11240. edgeStyle == mxEdgeStyle.TopToBottom)
  11241. {
  11242. result = this.createElbowEdgeHandler(state);
  11243. }
  11244. else if (edgeStyle == mxEdgeStyle.SegmentConnector ||
  11245. edgeStyle == mxEdgeStyle.OrthConnector)
  11246. {
  11247. result = this.createEdgeSegmentHandler(state);
  11248. }
  11249. else
  11250. {
  11251. result = new mxEdgeHandler(state);
  11252. }
  11253. return result;
  11254. };
  11255. /**
  11256. * Function: createEdgeSegmentHandler
  11257. *
  11258. * Hooks to create a new <mxEdgeSegmentHandler> for the given <mxCellState>.
  11259. *
  11260. * Parameters:
  11261. *
  11262. * state - <mxCellState> to create the handler for.
  11263. */
  11264. mxGraph.prototype.createEdgeSegmentHandler = function(state)
  11265. {
  11266. return new mxEdgeSegmentHandler(state);
  11267. };
  11268. /**
  11269. * Function: createElbowEdgeHandler
  11270. *
  11271. * Hooks to create a new <mxElbowEdgeHandler> for the given <mxCellState>.
  11272. *
  11273. * Parameters:
  11274. *
  11275. * state - <mxCellState> to create the handler for.
  11276. */
  11277. mxGraph.prototype.createElbowEdgeHandler = function(state)
  11278. {
  11279. return new mxElbowEdgeHandler(state);
  11280. };
  11281. /**
  11282. * Group: Graph events
  11283. */
  11284. /**
  11285. * Function: addMouseListener
  11286. *
  11287. * Adds a listener to the graph event dispatch loop. The listener
  11288. * must implement the mouseDown, mouseMove and mouseUp methods
  11289. * as shown in the <mxMouseEvent> class.
  11290. *
  11291. * Parameters:
  11292. *
  11293. * listener - Listener to be added to the graph event listeners.
  11294. */
  11295. mxGraph.prototype.addMouseListener = function(listener)
  11296. {
  11297. if (this.mouseListeners == null)
  11298. {
  11299. this.mouseListeners = [];
  11300. }
  11301. this.mouseListeners.push(listener);
  11302. };
  11303. /**
  11304. * Function: removeMouseListener
  11305. *
  11306. * Removes the specified graph listener.
  11307. *
  11308. * Parameters:
  11309. *
  11310. * listener - Listener to be removed from the graph event listeners.
  11311. */
  11312. mxGraph.prototype.removeMouseListener = function(listener)
  11313. {
  11314. if (this.mouseListeners != null)
  11315. {
  11316. for (var i = 0; i < this.mouseListeners.length; i++)
  11317. {
  11318. if (this.mouseListeners[i] == listener)
  11319. {
  11320. this.mouseListeners.splice(i, 1);
  11321. break;
  11322. }
  11323. }
  11324. }
  11325. };
  11326. /**
  11327. * Function: updateMouseEvent
  11328. *
  11329. * Sets the graphX and graphY properties if the given <mxMouseEvent> if
  11330. * required and returned the event.
  11331. *
  11332. * Parameters:
  11333. *
  11334. * me - <mxMouseEvent> to be updated.
  11335. * evtName - Name of the mouse event.
  11336. */
  11337. mxGraph.prototype.updateMouseEvent = function(me, evtName)
  11338. {
  11339. if (me.graphX == null || me.graphY == null)
  11340. {
  11341. var pt = mxUtils.convertPoint(this.container, me.getX(), me.getY());
  11342. me.graphX = pt.x - this.panDx;
  11343. me.graphY = pt.y - this.panDy;
  11344. // Searches for rectangles using method if native hit detection is disabled on shape
  11345. if (me.getCell() == null && this.isMouseDown && evtName == mxEvent.MOUSE_MOVE)
  11346. {
  11347. me.state = this.view.getState(this.getCellAt(pt.x, pt.y, null, null, null, function(state)
  11348. {
  11349. return state.shape == null || state.shape.paintBackground != mxRectangleShape.prototype.paintBackground ||
  11350. mxUtils.getValue(state.style, mxConstants.STYLE_POINTER_EVENTS, '1') == '1' ||
  11351. (state.shape.fill != null && state.shape.fill != mxConstants.NONE);
  11352. }));
  11353. }
  11354. }
  11355. return me;
  11356. };
  11357. /**
  11358. * Function: getStateForEvent
  11359. *
  11360. * Returns the state for the given touch event.
  11361. */
  11362. mxGraph.prototype.getStateForTouchEvent = function(evt)
  11363. {
  11364. var x = mxEvent.getClientX(evt);
  11365. var y = mxEvent.getClientY(evt);
  11366. // Dispatches the drop event to the graph which
  11367. // consumes and executes the source function
  11368. var pt = mxUtils.convertPoint(this.container, x, y);
  11369. return this.view.getState(this.getCellAt(pt.x, pt.y));
  11370. };
  11371. /**
  11372. * Function: isEventIgnored
  11373. *
  11374. * Returns true if the event should be ignored in <fireMouseEvent>.
  11375. */
  11376. mxGraph.prototype.isEventIgnored = function(evtName, me, sender)
  11377. {
  11378. var mouseEvent = mxEvent.isMouseEvent(me.getEvent());
  11379. var result = false;
  11380. // Drops events that are fired more than once
  11381. if (me.getEvent() == this.lastEvent)
  11382. {
  11383. result = true;
  11384. }
  11385. else
  11386. {
  11387. this.lastEvent = me.getEvent();
  11388. }
  11389. // Installs event listeners to capture the complete gesture from the event source
  11390. // for non-MS touch events as a workaround for all events for the same geture being
  11391. // fired from the event source even if that was removed from the DOM.
  11392. if (this.eventSource != null && evtName != mxEvent.MOUSE_MOVE)
  11393. {
  11394. mxEvent.removeGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
  11395. this.mouseMoveRedirect = null;
  11396. this.mouseUpRedirect = null;
  11397. this.eventSource = null;
  11398. }
  11399. else if (!mxClient.IS_GC && this.eventSource != null && me.getSource() != this.eventSource)
  11400. {
  11401. result = true;
  11402. }
  11403. else if (mxClient.IS_TOUCH && evtName == mxEvent.MOUSE_DOWN &&
  11404. !mouseEvent && !mxEvent.isPenEvent(me.getEvent()))
  11405. {
  11406. this.eventSource = me.getSource();
  11407. this.mouseMoveRedirect = mxUtils.bind(this, function(evt)
  11408. {
  11409. this.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
  11410. });
  11411. this.mouseUpRedirect = mxUtils.bind(this, function(evt)
  11412. {
  11413. this.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt, this.getStateForTouchEvent(evt)));
  11414. });
  11415. mxEvent.addGestureListeners(this.eventSource, null, this.mouseMoveRedirect, this.mouseUpRedirect);
  11416. }
  11417. // Factored out the workarounds for FF to make it easier to override/remove
  11418. // Note this method has side-effects!
  11419. if (this.isSyntheticEventIgnored(evtName, me, sender))
  11420. {
  11421. result = true;
  11422. }
  11423. // Never fires mouseUp/-Down for double clicks
  11424. if (!mxEvent.isPopupTrigger(this.lastEvent) && evtName != mxEvent.MOUSE_MOVE && this.lastEvent.detail == 2)
  11425. {
  11426. return true;
  11427. }
  11428. // Filters out of sequence events or mixed event types during a gesture
  11429. if (evtName == mxEvent.MOUSE_UP && this.isMouseDown)
  11430. {
  11431. this.isMouseDown = false;
  11432. }
  11433. else if (evtName == mxEvent.MOUSE_DOWN && !this.isMouseDown)
  11434. {
  11435. this.isMouseDown = true;
  11436. this.isMouseTrigger = mouseEvent;
  11437. }
  11438. // Drops mouse events that are fired during touch gestures as a workaround for Webkit
  11439. // and mouse events that are not in sync with the current internal button state
  11440. else if (!result && (((!mxClient.IS_FF || evtName != mxEvent.MOUSE_MOVE) &&
  11441. this.isMouseDown && this.isMouseTrigger != mouseEvent) ||
  11442. (evtName == mxEvent.MOUSE_DOWN && this.isMouseDown) ||
  11443. (evtName == mxEvent.MOUSE_UP && !this.isMouseDown)))
  11444. {
  11445. result = true;
  11446. }
  11447. if (!result && evtName == mxEvent.MOUSE_DOWN)
  11448. {
  11449. this.lastMouseX = me.getX();
  11450. this.lastMouseY = me.getY();
  11451. }
  11452. return result;
  11453. };
  11454. /**
  11455. * Function: isSyntheticEventIgnored
  11456. *
  11457. * Hook for ignoring synthetic mouse events after touchend in Firefox.
  11458. */
  11459. mxGraph.prototype.isSyntheticEventIgnored = function(evtName, me, sender)
  11460. {
  11461. var result = false;
  11462. var mouseEvent = mxEvent.isMouseEvent(me.getEvent());
  11463. // LATER: This does not cover all possible cases that can go wrong in FF
  11464. if (this.ignoreMouseEvents && mouseEvent && evtName != mxEvent.MOUSE_MOVE)
  11465. {
  11466. this.ignoreMouseEvents = evtName != mxEvent.MOUSE_UP;
  11467. result = true;
  11468. }
  11469. else if (mxClient.IS_FF && !mouseEvent && evtName == mxEvent.MOUSE_UP)
  11470. {
  11471. this.ignoreMouseEvents = true;
  11472. }
  11473. return result;
  11474. };
  11475. /**
  11476. * Function: isEventSourceIgnored
  11477. *
  11478. * Returns true if the event should be ignored in <fireMouseEvent>. This
  11479. * implementation returns true for select, option and input (if not of type
  11480. * checkbox, radio, button, submit or file) event sources if the event is not
  11481. * a mouse event or a left mouse button press event.
  11482. *
  11483. * Parameters:
  11484. *
  11485. * evtName - The name of the event.
  11486. * me - <mxMouseEvent> that should be ignored.
  11487. */
  11488. mxGraph.prototype.isEventSourceIgnored = function(evtName, me)
  11489. {
  11490. var source = me.getSource();
  11491. var name = (source.nodeName != null) ? source.nodeName.toLowerCase() : '';
  11492. var candidate = !mxEvent.isMouseEvent(me.getEvent()) || mxEvent.isLeftMouseButton(me.getEvent());
  11493. return evtName == mxEvent.MOUSE_DOWN && candidate && (name == 'select' || name == 'option' ||
  11494. (name == 'input' && source.type != 'checkbox' && source.type != 'radio' &&
  11495. source.type != 'button' && source.type != 'submit' && source.type != 'file'));
  11496. };
  11497. /**
  11498. * Function: getEventState
  11499. *
  11500. * Returns the <mxCellState> to be used when firing the mouse event for the
  11501. * given state. This implementation returns the given state.
  11502. *
  11503. * Parameters:
  11504. *
  11505. * <mxCellState> - State whose event source should be returned.
  11506. */
  11507. mxGraph.prototype.getEventState = function(state)
  11508. {
  11509. return state;
  11510. };
  11511. /**
  11512. * Function: fireMouseEvent
  11513. *
  11514. * Dispatches the given event in the graph event dispatch loop. Possible
  11515. * event names are <mxEvent.MOUSE_DOWN>, <mxEvent.MOUSE_MOVE> and
  11516. * <mxEvent.MOUSE_UP>. All listeners are invoked for all events regardless
  11517. * of the consumed state of the event.
  11518. *
  11519. * Parameters:
  11520. *
  11521. * evtName - String that specifies the type of event to be dispatched.
  11522. * me - <mxMouseEvent> to be fired.
  11523. * sender - Optional sender argument. Default is this.
  11524. */
  11525. mxGraph.prototype.fireMouseEvent = function(evtName, me, sender)
  11526. {
  11527. if (this.isEventSourceIgnored(evtName, me))
  11528. {
  11529. if (this.tooltipHandler != null)
  11530. {
  11531. this.tooltipHandler.hide();
  11532. }
  11533. return;
  11534. }
  11535. if (sender == null)
  11536. {
  11537. sender = this;
  11538. }
  11539. // Updates the graph coordinates in the event
  11540. me = this.updateMouseEvent(me, evtName);
  11541. // Detects and processes double taps for touch-based devices which do not have native double click events
  11542. // or where detection of double click is not always possible (quirks, IE10+). Note that this can only handle
  11543. // double clicks on cells because the sequence of events in IE prevents detection on the background, it fires
  11544. // two mouse ups, one of which without a cell but no mousedown for the second click which means we cannot
  11545. // detect which mouseup(s) are part of the first click, ie we do not know when the first click ends.
  11546. if ((!this.nativeDblClickEnabled && !mxEvent.isPopupTrigger(me.getEvent())) || (this.doubleTapEnabled &&
  11547. mxClient.IS_TOUCH && (mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent()))))
  11548. {
  11549. var currentTime = new Date().getTime();
  11550. // NOTE: Second mouseDown for double click missing in quirks mode
  11551. if ((!mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_DOWN) || (mxClient.IS_QUIRKS && evtName == mxEvent.MOUSE_UP && !this.fireDoubleClick))
  11552. {
  11553. if (this.lastTouchEvent != null && this.lastTouchEvent != me.getEvent() &&
  11554. currentTime - this.lastTouchTime < this.doubleTapTimeout &&
  11555. Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
  11556. Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance &&
  11557. this.doubleClickCounter < 2)
  11558. {
  11559. this.doubleClickCounter++;
  11560. var doubleClickFired = false;
  11561. if (evtName == mxEvent.MOUSE_UP)
  11562. {
  11563. if (me.getCell() == this.lastTouchCell && this.lastTouchCell != null)
  11564. {
  11565. this.lastTouchTime = 0;
  11566. var cell = this.lastTouchCell;
  11567. this.lastTouchCell = null;
  11568. // Fires native dblclick event via event source
  11569. // NOTE: This fires two double click events on edges in quirks mode. While
  11570. // trying to fix this, we realized that nativeDoubleClick can be disabled for
  11571. // quirks and IE10+ (or we didn't find the case mentioned above where it
  11572. // would not work), ie. all double clicks seem to be working without this.
  11573. if (mxClient.IS_QUIRKS)
  11574. {
  11575. me.getSource().fireEvent('ondblclick');
  11576. }
  11577. this.dblClick(me.getEvent(), cell);
  11578. doubleClickFired = true;
  11579. }
  11580. }
  11581. else
  11582. {
  11583. this.fireDoubleClick = true;
  11584. this.lastTouchTime = 0;
  11585. }
  11586. // Do not ignore mouse up in quirks in this case
  11587. if (!mxClient.IS_QUIRKS || doubleClickFired)
  11588. {
  11589. mxEvent.consume(me.getEvent());
  11590. return;
  11591. }
  11592. }
  11593. else if (this.lastTouchEvent == null || this.lastTouchEvent != me.getEvent())
  11594. {
  11595. this.lastTouchCell = me.getCell();
  11596. this.lastTouchX = me.getX();
  11597. this.lastTouchY = me.getY();
  11598. this.lastTouchTime = currentTime;
  11599. this.lastTouchEvent = me.getEvent();
  11600. this.doubleClickCounter = 0;
  11601. }
  11602. }
  11603. else if ((this.isMouseDown || evtName == mxEvent.MOUSE_UP) && this.fireDoubleClick)
  11604. {
  11605. this.fireDoubleClick = false;
  11606. var cell = this.lastTouchCell;
  11607. this.lastTouchCell = null;
  11608. this.isMouseDown = false;
  11609. // Workaround for Chrome/Safari not firing native double click events for double touch on background
  11610. var valid = (cell != null) || ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
  11611. (mxClient.IS_GC || mxClient.IS_SF));
  11612. if (valid && Math.abs(this.lastTouchX - me.getX()) < this.doubleTapTolerance &&
  11613. Math.abs(this.lastTouchY - me.getY()) < this.doubleTapTolerance)
  11614. {
  11615. this.dblClick(me.getEvent(), cell);
  11616. }
  11617. else
  11618. {
  11619. mxEvent.consume(me.getEvent());
  11620. }
  11621. return;
  11622. }
  11623. }
  11624. if (!this.isEventIgnored(evtName, me, sender))
  11625. {
  11626. // Updates the event state via getEventState
  11627. me.state = this.getEventState(me.getState());
  11628. this.fireEvent(new mxEventObject(mxEvent.FIRE_MOUSE_EVENT, 'eventName', evtName, 'event', me));
  11629. if ((mxClient.IS_OP || mxClient.IS_SF || mxClient.IS_GC || mxClient.IS_IE11 ||
  11630. (mxClient.IS_IE && mxClient.IS_SVG) || me.getEvent().target != this.container))
  11631. {
  11632. if (evtName == mxEvent.MOUSE_MOVE && this.isMouseDown && this.autoScroll && !mxEvent.isMultiTouchEvent(me.getEvent))
  11633. {
  11634. this.scrollPointToVisible(me.getGraphX(), me.getGraphY(), this.autoExtend);
  11635. }
  11636. else if (evtName == mxEvent.MOUSE_UP && this.ignoreScrollbars && this.translateToScrollPosition &&
  11637. (this.container.scrollLeft != 0 || this.container.scrollTop != 0))
  11638. {
  11639. var s = this.view.scale;
  11640. var tr = this.view.translate;
  11641. this.view.setTranslate(tr.x - this.container.scrollLeft / s, tr.y - this.container.scrollTop / s);
  11642. this.container.scrollLeft = 0;
  11643. this.container.scrollTop = 0;
  11644. }
  11645. if (this.mouseListeners != null)
  11646. {
  11647. var args = [sender, me];
  11648. // Does not change returnValue in Opera
  11649. if (!me.getEvent().preventDefault)
  11650. {
  11651. me.getEvent().returnValue = true;
  11652. }
  11653. for (var i = 0; i < this.mouseListeners.length; i++)
  11654. {
  11655. var l = this.mouseListeners[i];
  11656. if (evtName == mxEvent.MOUSE_DOWN)
  11657. {
  11658. l.mouseDown.apply(l, args);
  11659. }
  11660. else if (evtName == mxEvent.MOUSE_MOVE)
  11661. {
  11662. l.mouseMove.apply(l, args);
  11663. }
  11664. else if (evtName == mxEvent.MOUSE_UP)
  11665. {
  11666. l.mouseUp.apply(l, args);
  11667. }
  11668. }
  11669. }
  11670. // Invokes the click handler
  11671. if (evtName == mxEvent.MOUSE_UP)
  11672. {
  11673. this.click(me);
  11674. }
  11675. }
  11676. // Detects tapAndHold events using a timer
  11677. if ((mxEvent.isTouchEvent(me.getEvent()) || mxEvent.isPenEvent(me.getEvent())) &&
  11678. evtName == mxEvent.MOUSE_DOWN && this.tapAndHoldEnabled && !this.tapAndHoldInProgress)
  11679. {
  11680. this.tapAndHoldInProgress = true;
  11681. this.initialTouchX = me.getGraphX();
  11682. this.initialTouchY = me.getGraphY();
  11683. var handler = function()
  11684. {
  11685. if (this.tapAndHoldValid)
  11686. {
  11687. this.tapAndHold(me);
  11688. }
  11689. this.tapAndHoldInProgress = false;
  11690. this.tapAndHoldValid = false;
  11691. };
  11692. if (this.tapAndHoldThread)
  11693. {
  11694. window.clearTimeout(this.tapAndHoldThread);
  11695. }
  11696. this.tapAndHoldThread = window.setTimeout(mxUtils.bind(this, handler), this.tapAndHoldDelay);
  11697. this.tapAndHoldValid = true;
  11698. }
  11699. else if (evtName == mxEvent.MOUSE_UP)
  11700. {
  11701. this.tapAndHoldInProgress = false;
  11702. this.tapAndHoldValid = false;
  11703. }
  11704. else if (this.tapAndHoldValid)
  11705. {
  11706. this.tapAndHoldValid =
  11707. Math.abs(this.initialTouchX - me.getGraphX()) < this.tolerance &&
  11708. Math.abs(this.initialTouchY - me.getGraphY()) < this.tolerance;
  11709. }
  11710. // Stops editing for all events other than from cellEditor
  11711. if (evtName == mxEvent.MOUSE_DOWN && this.isEditing() && !this.cellEditor.isEventSource(me.getEvent()))
  11712. {
  11713. this.stopEditing(!this.isInvokesStopCellEditing());
  11714. }
  11715. this.consumeMouseEvent(evtName, me, sender);
  11716. }
  11717. };
  11718. /**
  11719. * Function: consumeMouseEvent
  11720. *
  11721. * Consumes the given <mxMouseEvent> if it's a touchStart event.
  11722. */
  11723. mxGraph.prototype.consumeMouseEvent = function(evtName, me, sender)
  11724. {
  11725. // Workaround for duplicate click in Windows 8 with Chrome/FF/Opera with touch
  11726. if (evtName == mxEvent.MOUSE_DOWN && mxEvent.isTouchEvent(me.getEvent()))
  11727. {
  11728. me.consume(false);
  11729. }
  11730. };
  11731. /**
  11732. * Function: fireGestureEvent
  11733. *
  11734. * Dispatches a <mxEvent.GESTURE> event. The following example will resize the
  11735. * cell under the mouse based on the scale property of the native touch event.
  11736. *
  11737. * (code)
  11738. * graph.addListener(mxEvent.GESTURE, function(sender, eo)
  11739. * {
  11740. * var evt = eo.getProperty('event');
  11741. * var state = graph.view.getState(eo.getProperty('cell'));
  11742. *
  11743. * if (graph.isEnabled() && graph.isCellResizable(state.cell) && Math.abs(1 - evt.scale) > 0.2)
  11744. * {
  11745. * var scale = graph.view.scale;
  11746. * var tr = graph.view.translate;
  11747. *
  11748. * var w = state.width * evt.scale;
  11749. * var h = state.height * evt.scale;
  11750. * var x = state.x - (w - state.width) / 2;
  11751. * var y = state.y - (h - state.height) / 2;
  11752. *
  11753. * var bounds = new mxRectangle(graph.snap(x / scale) - tr.x,
  11754. * graph.snap(y / scale) - tr.y, graph.snap(w / scale), graph.snap(h / scale));
  11755. * graph.resizeCell(state.cell, bounds);
  11756. * eo.consume();
  11757. * }
  11758. * });
  11759. * (end)
  11760. *
  11761. * Parameters:
  11762. *
  11763. * evt - Gestureend event that represents the gesture.
  11764. * cell - Optional <mxCell> associated with the gesture.
  11765. */
  11766. mxGraph.prototype.fireGestureEvent = function(evt, cell)
  11767. {
  11768. // Resets double tap event handling when gestures take place
  11769. this.lastTouchTime = 0;
  11770. this.fireEvent(new mxEventObject(mxEvent.GESTURE, 'event', evt, 'cell', cell));
  11771. };
  11772. /**
  11773. * Function: destroy
  11774. *
  11775. * Destroys the graph and all its resources.
  11776. */
  11777. mxGraph.prototype.destroy = function()
  11778. {
  11779. if (!this.destroyed)
  11780. {
  11781. this.destroyed = true;
  11782. if (this.tooltipHandler != null)
  11783. {
  11784. this.tooltipHandler.destroy();
  11785. }
  11786. if (this.selectionCellsHandler != null)
  11787. {
  11788. this.selectionCellsHandler.destroy();
  11789. }
  11790. if (this.panningHandler != null)
  11791. {
  11792. this.panningHandler.destroy();
  11793. }
  11794. if (this.popupMenuHandler != null)
  11795. {
  11796. this.popupMenuHandler.destroy();
  11797. }
  11798. if (this.connectionHandler != null)
  11799. {
  11800. this.connectionHandler.destroy();
  11801. }
  11802. if (this.graphHandler != null)
  11803. {
  11804. this.graphHandler.destroy();
  11805. }
  11806. if (this.cellEditor != null)
  11807. {
  11808. this.cellEditor.destroy();
  11809. }
  11810. if (this.view != null)
  11811. {
  11812. this.view.destroy();
  11813. }
  11814. if (this.model != null && this.graphModelChangeListener != null)
  11815. {
  11816. this.model.removeListener(this.graphModelChangeListener);
  11817. this.graphModelChangeListener = null;
  11818. }
  11819. this.container = null;
  11820. }
  11821. };
  11822. __mxOutput.mxGraph = typeof mxGraph !== 'undefined' ? mxGraph : undefined;