1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522 |
- /**
- * Copyright (c) 2006-2015, JGraph Ltd
- * Copyright (c) 2006-2015, Gaudenz Alder
- */
- var mxUtils =
- {
- /**
- * Class: mxUtils
- *
- * A singleton class that provides cross-browser helper methods.
- * This is a global functionality. To access the functions in this
- * class, use the global classname appended by the functionname.
- * You may have to load chrome://global/content/contentAreaUtils.js
- * to disable certain security restrictions in Mozilla for the <open>,
- * <save>, <saveAs> and <copy> function.
- *
- * For example, the following code displays an error message:
- *
- * (code)
- * mxUtils.error('Browser is not supported!', 200, false);
- * (end)
- *
- * Variable: errorResource
- *
- * Specifies the resource key for the title of the error window. If the
- * resource for this key does not exist then the value is used as
- * the title. Default is 'error'.
- */
- errorResource: (mxClient.language != 'none') ? 'error' : '',
-
- /**
- * Variable: closeResource
- *
- * Specifies the resource key for the label of the close button. If the
- * resource for this key does not exist then the value is used as
- * the label. Default is 'close'.
- */
- closeResource: (mxClient.language != 'none') ? 'close' : '',
- /**
- * Variable: errorImage
- *
- * Defines the image used for error dialogs.
- */
- errorImage: mxClient.imageBasePath + '/error.gif',
-
- /**
- * Function: removeCursors
- *
- * Removes the cursors from the style of the given DOM node and its
- * descendants.
- *
- * Parameters:
- *
- * element - DOM node to remove the cursor style from.
- */
- removeCursors: function(element)
- {
- if (element.style != null)
- {
- element.style.cursor = '';
- }
-
- var children = element.childNodes;
-
- if (children != null)
- {
- var childCount = children.length;
-
- for (var i = 0; i < childCount; i += 1)
- {
- mxUtils.removeCursors(children[i]);
- }
- }
- },
- /**
- * Function: getCurrentStyle
- *
- * Returns the current style of the specified element.
- *
- * Parameters:
- *
- * element - DOM node whose current style should be returned.
- */
- getCurrentStyle: function()
- {
- if (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 9))
- {
- return function(element)
- {
- return (element != null) ? element.currentStyle : null;
- };
- }
- else
- {
- return function(element)
- {
- return (element != null) ?
- window.getComputedStyle(element, '') :
- null;
- };
- }
- }(),
-
- /**
- * Function: parseCssNumber
- *
- * Parses the given CSS numeric value adding handling for the values thin,
- * medium and thick (2, 4 and 6).
- */
- parseCssNumber: function(value)
- {
- if (value == 'thin')
- {
- value = '2';
- }
- else if (value == 'medium')
- {
- value = '4';
- }
- else if (value == 'thick')
- {
- value = '6';
- }
-
- value = parseFloat(value);
-
- if (isNaN(value))
- {
- value = 0;
- }
-
- return value;
- },
- /**
- * Function: setPrefixedStyle
- *
- * Adds the given style with the standard name and an optional vendor prefix for the current
- * browser.
- *
- * (code)
- * mxUtils.setPrefixedStyle(node.style, 'transformOrigin', '0% 0%');
- * (end)
- */
- setPrefixedStyle: function()
- {
- var prefix = null;
-
- if (mxClient.IS_OT)
- {
- prefix = 'O';
- }
- else if (mxClient.IS_SF || mxClient.IS_GC)
- {
- prefix = 'Webkit';
- }
- else if (mxClient.IS_MT)
- {
- prefix = 'Moz';
- }
- else if (mxClient.IS_IE && document.documentMode >= 9 && document.documentMode < 10)
- {
- prefix = 'ms';
- }
- return function(style, name, value)
- {
- style[name] = value;
-
- if (prefix != null && name.length > 0)
- {
- name = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
- style[name] = value;
- }
- };
- }(),
-
- /**
- * Function: hasScrollbars
- *
- * Returns true if the overflow CSS property of the given node is either
- * scroll or auto.
- *
- * Parameters:
- *
- * node - DOM node whose style should be checked for scrollbars.
- */
- hasScrollbars: function(node)
- {
- var style = mxUtils.getCurrentStyle(node);
- return style != null && (style.overflow == 'scroll' || style.overflow == 'auto');
- },
-
- /**
- * Function: bind
- *
- * Returns a wrapper function that locks the execution scope of the given
- * function to the specified scope. Inside funct, the "this" keyword
- * becomes a reference to that scope.
- */
- bind: function(scope, funct)
- {
- return function()
- {
- return funct.apply(scope, arguments);
- };
- },
-
- /**
- * Function: eval
- *
- * Evaluates the given expression using eval and returns the JavaScript
- * object that represents the expression result. Supports evaluation of
- * expressions that define functions and returns the function object for
- * these expressions.
- *
- * Parameters:
- *
- * expr - A string that represents a JavaScript expression.
- */
- eval: function(expr)
- {
- var result = null;
- if (expr.indexOf('function') >= 0)
- {
- try
- {
- eval('var _mxJavaScriptExpression='+expr);
- result = _mxJavaScriptExpression;
- // TODO: Use delete here?
- _mxJavaScriptExpression = null;
- }
- catch (e)
- {
- mxLog.warn(e.message + ' while evaluating ' + expr);
- }
- }
- else
- {
- try
- {
- result = eval(expr);
- }
- catch (e)
- {
- mxLog.warn(e.message + ' while evaluating ' + expr);
- }
- }
-
- return result;
- },
-
- /**
- * Function: findNode
- *
- * Returns the first node where attr equals value.
- * This implementation does not use XPath.
- */
- findNode: function(node, attr, value)
- {
- if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
- {
- var tmp = node.getAttribute(attr);
-
- if (tmp != null && tmp == value)
- {
- return node;
- }
- }
-
- node = node.firstChild;
-
- while (node != null)
- {
- var result = mxUtils.findNode(node, attr, value);
-
- if (result != null)
- {
- return result;
- }
-
- node = node.nextSibling;
- }
-
- return null;
- },
- /**
- * Function: getFunctionName
- *
- * Returns the name for the given function.
- *
- * Parameters:
- *
- * f - JavaScript object that represents a function.
- */
- getFunctionName: function(f)
- {
- var str = null;
- if (f != null)
- {
- if (f.name != null)
- {
- str = f.name;
- }
- else
- {
- str = mxUtils.trim(f.toString());
-
- if (/^function\s/.test(str))
- {
- str = mxUtils.ltrim(str.substring(9));
- var idx2 = str.indexOf('(');
-
- if (idx2 > 0)
- {
- str = str.substring(0, idx2);
- }
- }
- }
- }
-
- return str;
- },
- /**
- * Function: indexOf
- *
- * Returns the index of obj in array or -1 if the array does not contain
- * the given object.
- *
- * Parameters:
- *
- * array - Array to check for the given obj.
- * obj - Object to find in the given array.
- */
- indexOf: function(array, obj)
- {
- if (array != null && obj != null)
- {
- for (var i = 0; i < array.length; i++)
- {
- if (array[i] == obj)
- {
- return i;
- }
- }
- }
-
- return -1;
- },
- /**
- * Function: forEach
- *
- * Calls the given function for each element of the given array and returns
- * the array.
- *
- * Parameters:
- *
- * array - Array that contains the elements.
- * fn - Function to be called for each object.
- */
- forEach: function(array, fn)
- {
- if (array != null && fn != null)
- {
- for (var i = 0; i < array.length; i++)
- {
- fn(array[i]);
- }
- }
-
- return array;
- },
- /**
- * Function: remove
- *
- * Removes all occurrences of the given object in the given array or
- * object. If there are multiple occurrences of the object, be they
- * associative or as an array entry, all occurrences are removed from
- * the array or deleted from the object. By removing the object from
- * the array, all elements following the removed element are shifted
- * by one step towards the beginning of the array.
- *
- * The length of arrays is not modified inside this function.
- *
- * Parameters:
- *
- * obj - Object to find in the given array.
- * array - Array to check for the given obj.
- */
- remove: function(obj, array)
- {
- var result = null;
-
- if (typeof(array) == 'object')
- {
- var index = mxUtils.indexOf(array, obj);
-
- while (index >= 0)
- {
- array.splice(index, 1);
- result = obj;
- index = mxUtils.indexOf(array, obj);
- }
- }
- for (var key in array)
- {
- if (array[key] == obj)
- {
- delete array[key];
- result = obj;
- }
- }
-
- return result;
- },
-
- /**
- * Function: isNode
- *
- * Returns true if the given value is an XML node with the node name
- * and if the optional attribute has the specified value.
- *
- * This implementation assumes that the given value is a DOM node if the
- * nodeType property is numeric, that is, if isNaN returns false for
- * value.nodeType.
- *
- * Parameters:
- *
- * value - Object that should be examined as a node.
- * nodeName - String that specifies the node name.
- * attributeName - Optional attribute name to check.
- * attributeValue - Optional attribute value to check.
- */
- isNode: function(value, nodeName, attributeName, attributeValue)
- {
- if (value != null && !isNaN(value.nodeType) && (nodeName == null ||
- value.nodeName.toLowerCase() == nodeName.toLowerCase()))
- {
- return attributeName == null ||
- value.getAttribute(attributeName) == attributeValue;
- }
-
- return false;
- },
-
- /**
- * Function: isAncestorNode
- *
- * Returns true if the given ancestor is an ancestor of the
- * given DOM node in the DOM. This also returns true if the
- * child is the ancestor.
- *
- * Parameters:
- *
- * ancestor - DOM node that represents the ancestor.
- * child - DOM node that represents the child.
- */
- isAncestorNode: function(ancestor, child)
- {
- var parent = child;
-
- while (parent != null)
- {
- if (parent == ancestor)
- {
- return true;
- }
- parent = parent.parentNode;
- }
-
- return false;
- },
- /**
- * Function: getChildNodes
- *
- * Returns an array of child nodes that are of the given node type.
- *
- * Parameters:
- *
- * node - Parent DOM node to return the children from.
- * nodeType - Optional node type to return. Default is
- * <mxConstants.NODETYPE_ELEMENT>.
- */
- getChildNodes: function(node, nodeType)
- {
- nodeType = nodeType || mxConstants.NODETYPE_ELEMENT;
-
- var children = [];
- var tmp = node.firstChild;
-
- while (tmp != null)
- {
- if (tmp.nodeType == nodeType)
- {
- children.push(tmp);
- }
-
- tmp = tmp.nextSibling;
- }
-
- return children;
- },
- /**
- * Function: importNode
- *
- * Cross browser implementation for document.importNode. Uses document.importNode
- * in all browsers but IE, where the node is cloned by creating a new node and
- * copying all attributes and children into it using importNode, recursively.
- *
- * Parameters:
- *
- * doc - Document to import the node into.
- * node - Node to be imported.
- * allChildren - If all children should be imported.
- */
- importNode: function(doc, node, allChildren)
- {
- if (mxClient.IS_IE && (document.documentMode == null || document.documentMode < 10))
- {
- return mxUtils.importNodeImplementation(doc, node, allChildren);
- }
- else
- {
- return doc.importNode(node, allChildren);
- }
- },
- /**
- * Function: importNodeImplementation
- *
- * Full DOM API implementation for importNode without using importNode API call.
- *
- * Parameters:
- *
- * doc - Document to import the node into.
- * node - Node to be imported.
- * allChildren - If all children should be imported.
- */
- importNodeImplementation: function(doc, node, allChildren)
- {
- switch (node.nodeType)
- {
- case 1: /* element */
- {
- var newNode = doc.createElement(node.nodeName);
-
- if (node.attributes && node.attributes.length > 0)
- {
- for (var i = 0; i < node.attributes.length; i++)
- {
- newNode.setAttribute(node.attributes[i].nodeName,
- node.getAttribute(node.attributes[i].nodeName));
- }
- }
-
- if (allChildren && node.childNodes && node.childNodes.length > 0)
- {
- for (var i = 0; i < node.childNodes.length; i++)
- {
- newNode.appendChild(mxUtils.importNodeImplementation(doc, node.childNodes[i], allChildren));
- }
- }
-
- return newNode;
- break;
- }
- case 3: /* text */
- case 4: /* cdata-section */
- case 8: /* comment */
- {
- return doc.createTextNode((node.nodeValue != null) ? node.nodeValue : node.value);
- break;
- }
- };
- },
- /**
- * Function: createXmlDocument
- *
- * Returns a new, empty XML document.
- */
- createXmlDocument: function()
- {
- var doc = null;
-
- if (document.implementation && document.implementation.createDocument)
- {
- doc = document.implementation.createDocument('', '', null);
- }
- else if ("ActiveXObject" in window)
- {
- doc = mxUtils.createMsXmlDocument();
- }
-
- return doc;
- },
- /**
- * Function: createMsXmlDocument
- *
- * Returns a new, empty Microsoft.XMLDOM document using ActiveXObject.
- */
- createMsXmlDocument: function()
- {
- var doc = new ActiveXObject('Microsoft.XMLDOM');
- doc.async = false;
- // Workaround for parsing errors with SVG DTD
- doc.validateOnParse = false;
- doc.resolveExternals = false;
-
- return doc;
- },
- /**
- * Function: parseXml
- *
- * Parses the specified XML string into a new XML document and returns the
- * new document.
- *
- * Example:
- *
- * (code)
- * var doc = mxUtils.parseXml(
- * '<mxGraphModel><root><MyDiagram id="0"><mxCell/></MyDiagram>'+
- * '<MyLayer id="1"><mxCell parent="0" /></MyLayer><MyObject id="2">'+
- * '<mxCell style="strokeColor=blue;fillColor=red" parent="1" vertex="1">'+
- * '<mxGeometry x="10" y="10" width="80" height="30" as="geometry"/>'+
- * '</mxCell></MyObject></root></mxGraphModel>');
- * (end)
- *
- * Parameters:
- *
- * xml - String that contains the XML data.
- */
- parseXml: function()
- {
- if (window.DOMParser)
- {
- return function(xml)
- {
- var parser = new DOMParser();
-
- return parser.parseFromString(xml, 'text/xml');
- };
- }
- else // IE<=9
- {
- return function(xml)
- {
- var doc = mxUtils.createMsXmlDocument();
- doc.loadXML(xml);
-
- return doc;
- };
- }
- }(),
- /**
- * Function: clearSelection
- *
- * Clears the current selection in the page.
- */
- clearSelection: function()
- {
- if (document.selection)
- {
- return function()
- {
- document.selection.empty();
- };
- }
- else if (window.getSelection)
- {
- return function()
- {
- if (window.getSelection().empty)
- {
- window.getSelection().empty();
- }
- else if (window.getSelection().removeAllRanges)
- {
- window.getSelection().removeAllRanges();
- }
- };
- }
- else
- {
- return function() { };
- }
- }(),
- /**
- * Function: removeWhitespace
- *
- * Removes the sibling text nodes for the given node that only consists
- * of tabs, newlines and spaces.
- *
- * Parameters:
- *
- * node - DOM node whose siblings should be removed.
- * before - Optional boolean that specifies the direction of the traversal.
- */
- removeWhitespace: function(node, before)
- {
- var tmp = (before) ? node.previousSibling : node.nextSibling;
-
- while (tmp != null && tmp.nodeType == mxConstants.NODETYPE_TEXT)
- {
- var next = (before) ? tmp.previousSibling : tmp.nextSibling;
- var text = mxUtils.getTextContent(tmp);
-
- if (mxUtils.trim(text).length == 0)
- {
- tmp.parentNode.removeChild(tmp);
- }
-
- tmp = next;
- }
- },
-
- /**
- * Function: htmlEntities
- *
- * Replaces characters (less than, greater than, newlines and quotes) with
- * their HTML entities in the given string and returns the result.
- *
- * Parameters:
- *
- * s - String that contains the characters to be converted.
- * newline - If newlines should be replaced. Default is true.
- */
- htmlEntities: function(s, newline)
- {
- s = String(s || '');
-
- s = s.replace(/&/g,'&'); // 38 26
- s = s.replace(/"/g,'"'); // 34 22
- s = s.replace(/\'/g,'''); // 39 27
- s = s.replace(/</g,'<'); // 60 3C
- s = s.replace(/>/g,'>'); // 62 3E
- if (newline == null || newline)
- {
- s = s.replace(/\n/g, '
');
- }
-
- return s;
- },
-
- /**
- * Function: isVml
- *
- * Returns true if the given node is in the VML namespace.
- *
- * Parameters:
- *
- * node - DOM node whose tag urn should be checked.
- */
- isVml: function(node)
- {
- return node != null && node.tagUrn == 'urn:schemas-microsoft-com:vml';
- },
- /**
- * Function: getXml
- *
- * Returns the XML content of the specified node. For Internet Explorer,
- * all \r\n\t[\t]* are removed from the XML string and the remaining \r\n
- * are replaced by \n. All \n are then replaced with linefeed, or 
 if
- * no linefeed is defined.
- *
- * Parameters:
- *
- * node - DOM node to return the XML for.
- * linefeed - Optional string that linefeeds are converted into. Default is
- * 

- */
- getXml: function(node, linefeed)
- {
- var xml = '';
-
- if (mxClient.IS_IE || mxClient.IS_IE11)
- {
- xml = mxUtils.getPrettyXml(node, '', '', '');
- }
- else if (window.XMLSerializer != null)
- {
- var xmlSerializer = new XMLSerializer();
- xml = xmlSerializer.serializeToString(node);
- }
- else if (node.xml != null)
- {
- xml = node.xml.replace(/\r\n\t[\t]*/g, '').
- replace(/>\r\n/g, '>').
- replace(/\r\n/g, '\n');
- }
- // Replaces linefeeds with HTML Entities.
- linefeed = linefeed || '
';
- xml = xml.replace(/\n/g, linefeed);
-
- return xml;
- },
-
- /**
- * Function: getPrettyXML
- *
- * Returns a pretty printed string that represents the XML tree for the
- * given node. This method should only be used to print XML for reading,
- * use <getXml> instead to obtain a string for processing.
- *
- * Parameters:
- *
- * node - DOM node to return the XML for.
- * tab - Optional string that specifies the indentation for one level.
- * Default is two spaces.
- * indent - Optional string that represents the current indentation.
- * Default is an empty string.
- * newline - Option string that represents a linefeed. Default is '\n'.
- */
- getPrettyXml: function(node, tab, indent, newline, ns)
- {
- var result = [];
-
- if (node != null)
- {
- tab = (tab != null) ? tab : ' ';
- indent = (indent != null) ? indent : '';
- newline = (newline != null) ? newline : '\n';
-
- if (node.namespaceURI != null && node.namespaceURI != ns)
- {
- ns = node.namespaceURI;
-
- if (node.getAttribute('xmlns') == null)
- {
- node.setAttribute('xmlns', node.namespaceURI);
- }
- }
-
- if (node.nodeType == mxConstants.NODETYPE_DOCUMENT)
- {
- result.push(mxUtils.getPrettyXml(node.documentElement, tab, indent, newline, ns));
- }
- else if (node.nodeType == mxConstants.NODETYPE_DOCUMENT_FRAGMENT)
- {
- var tmp = node.firstChild;
-
- if (tmp != null)
- {
- while (tmp != null)
- {
- result.push(mxUtils.getPrettyXml(tmp, tab, indent, newline, ns));
- tmp = tmp.nextSibling;
- }
- }
- }
- else if (node.nodeType == mxConstants.NODETYPE_COMMENT)
- {
- var value = mxUtils.getTextContent(node);
-
- if (value.length > 0)
- {
- result.push(indent + '<!--' + value + '-->' + newline);
- }
- }
- else if (node.nodeType == mxConstants.NODETYPE_TEXT)
- {
- var value = mxUtils.trim(mxUtils.getTextContent(node));
-
- if (value.length > 0)
- {
- result.push(indent + mxUtils.htmlEntities(value, false) + newline);
- }
- }
- else if (node.nodeType == mxConstants.NODETYPE_CDATA)
- {
- var value = mxUtils.getTextContent(node);
-
- if (value.length > 0)
- {
- result.push(indent + '<![CDATA[' + value + ']]' + newline);
- }
- }
- else
- {
- result.push(indent + '<' + node.nodeName);
-
- // Creates the string with the node attributes
- // and converts all HTML entities in the values
- var attrs = node.attributes;
-
- if (attrs != null)
- {
- for (var i = 0; i < attrs.length; i++)
- {
- var val = mxUtils.htmlEntities(attrs[i].value);
- result.push(' ' + attrs[i].nodeName + '="' + val + '"');
- }
- }
- // Recursively creates the XML string for each child
- // node and appends it here with an indentation
- var tmp = node.firstChild;
-
- if (tmp != null)
- {
- result.push('>' + newline);
-
- while (tmp != null)
- {
- result.push(mxUtils.getPrettyXml(tmp, tab, indent + tab, newline, ns));
- tmp = tmp.nextSibling;
- }
-
- result.push(indent + '</'+ node.nodeName + '>' + newline);
- }
- else
- {
- result.push(' />' + newline);
- }
- }
- }
-
- return result.join('');
- },
-
- /**
- * Function: extractTextWithWhitespace
- *
- * Returns the text content of the specified node.
- *
- * Parameters:
- *
- * elems - DOM nodes to return the text for.
- */
- extractTextWithWhitespace: function(elems)
- {
- // Known block elements for handling linefeeds (list is not complete)
- var blocks = ['BLOCKQUOTE', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'OL', 'P', 'PRE', 'TABLE', 'UL'];
- var ret = [];
-
- function doExtract(elts)
- {
- // Single break should be ignored
- if (elts.length == 1 && (elts[0].nodeName == 'BR' ||
- elts[0].innerHTML == '\n'))
- {
- return;
- }
-
- for (var i = 0; i < elts.length; i++)
- {
- var elem = elts[i];
- // DIV with a br or linefeed forces a linefeed
- if (elem.nodeName == 'BR' || elem.innerHTML == '\n' ||
- ((elts.length == 1 || i == 0) && (elem.nodeName == 'DIV' &&
- elem.innerHTML.toLowerCase() == '<br>')))
- {
- ret.push('\n');
- }
- else
- {
- if (elem.nodeType === 3 || elem.nodeType === 4)
- {
- if (elem.nodeValue.length > 0)
- {
- ret.push(elem.nodeValue);
- }
- }
- else if (elem.nodeType !== 8 && elem.childNodes.length > 0)
- {
- doExtract(elem.childNodes);
- }
-
- if (i < elts.length - 1 && mxUtils.indexOf(blocks, elts[i + 1].nodeName) >= 0)
- {
- ret.push('\n');
- }
- }
- }
- };
-
- doExtract(elems);
-
- return ret.join('');
- },
- /**
- * Function: replaceTrailingNewlines
- *
- * Replaces each trailing newline with the given pattern.
- */
- replaceTrailingNewlines: function(str, pattern)
- {
- // LATER: Check is this can be done with a regular expression
- var postfix = '';
-
- while (str.length > 0 && str.charAt(str.length - 1) == '\n')
- {
- str = str.substring(0, str.length - 1);
- postfix += pattern;
- }
-
- return str + postfix;
- },
- /**
- * Function: getTextContent
- *
- * Returns the text content of the specified node.
- *
- * Parameters:
- *
- * node - DOM node to return the text content for.
- */
- getTextContent: function(node)
- {
- // Only IE10-
- if (mxClient.IS_IE && node.innerText !== undefined)
- {
- return node.innerText;
- }
- else
- {
- return (node != null) ? node[(node.textContent === undefined) ? 'text' : 'textContent'] : '';
- }
- },
-
- /**
- * Function: setTextContent
- *
- * Sets the text content of the specified node.
- *
- * Parameters:
- *
- * node - DOM node to set the text content for.
- * text - String that represents the text content.
- */
- setTextContent: function(node, text)
- {
- if (node.innerText !== undefined)
- {
- node.innerText = text;
- }
- else
- {
- node[(node.textContent === undefined) ? 'text' : 'textContent'] = text;
- }
- },
-
- /**
- * Function: getInnerHtml
- *
- * Returns the inner HTML for the given node as a string or an empty string
- * if no node was specified. The inner HTML is the text representing all
- * children of the node, but not the node itself.
- *
- * Parameters:
- *
- * node - DOM node to return the inner HTML for.
- */
- getInnerHtml: function()
- {
- if (mxClient.IS_IE)
- {
- return function(node)
- {
- if (node != null)
- {
- return node.innerHTML;
- }
-
- return '';
- };
- }
- else
- {
- return function(node)
- {
- if (node != null)
- {
- var serializer = new XMLSerializer();
- return serializer.serializeToString(node);
- }
-
- return '';
- };
- }
- }(),
- /**
- * Function: getOuterHtml
- *
- * Returns the outer HTML for the given node as a string or an empty
- * string if no node was specified. The outer HTML is the text representing
- * all children of the node including the node itself.
- *
- * Parameters:
- *
- * node - DOM node to return the outer HTML for.
- */
- getOuterHtml: function()
- {
- if (mxClient.IS_IE)
- {
- return function(node)
- {
- if (node != null)
- {
- if (node.outerHTML != null)
- {
- return node.outerHTML;
- }
- else
- {
- var tmp = [];
- tmp.push('<'+node.nodeName);
-
- var attrs = node.attributes;
-
- if (attrs != null)
- {
- for (var i = 0; i < attrs.length; i++)
- {
- var value = attrs[i].value;
-
- if (value != null && value.length > 0)
- {
- tmp.push(' ');
- tmp.push(attrs[i].nodeName);
- tmp.push('="');
- tmp.push(value);
- tmp.push('"');
- }
- }
- }
-
- if (node.innerHTML.length == 0)
- {
- tmp.push('/>');
- }
- else
- {
- tmp.push('>');
- tmp.push(node.innerHTML);
- tmp.push('</'+node.nodeName+'>');
- }
-
- return tmp.join('');
- }
- }
-
- return '';
- };
- }
- else
- {
- return function(node)
- {
- if (node != null)
- {
- var serializer = new XMLSerializer();
- return serializer.serializeToString(node);
- }
-
- return '';
- };
- }
- }(),
-
- /**
- * Function: write
- *
- * Creates a text node for the given string and appends it to the given
- * parent. Returns the text node.
- *
- * Parameters:
- *
- * parent - DOM node to append the text node to.
- * text - String representing the text to be added.
- */
- write: function(parent, text)
- {
- var doc = parent.ownerDocument;
- var node = doc.createTextNode(text);
-
- if (parent != null)
- {
- parent.appendChild(node);
- }
-
- return node;
- },
-
- /**
- * Function: writeln
- *
- * Creates a text node for the given string and appends it to the given
- * parent with an additional linefeed. Returns the text node.
- *
- * Parameters:
- *
- * parent - DOM node to append the text node to.
- * text - String representing the text to be added.
- */
- writeln: function(parent, text)
- {
- var doc = parent.ownerDocument;
- var node = doc.createTextNode(text);
-
- if (parent != null)
- {
- parent.appendChild(node);
- parent.appendChild(document.createElement('br'));
- }
-
- return node;
- },
-
- /**
- * Function: br
- *
- * Appends a linebreak to the given parent and returns the linebreak.
- *
- * Parameters:
- *
- * parent - DOM node to append the linebreak to.
- */
- br: function(parent, count)
- {
- count = count || 1;
- var br = null;
-
- for (var i = 0; i < count; i++)
- {
- if (parent != null)
- {
- br = parent.ownerDocument.createElement('br');
- parent.appendChild(br);
- }
- }
-
- return br;
- },
-
- /**
- * Function: button
- *
- * Returns a new button with the given level and function as an onclick
- * event handler.
- *
- * (code)
- * document.body.appendChild(mxUtils.button('Test', function(evt)
- * {
- * alert('Hello, World!');
- * }));
- * (end)
- *
- * Parameters:
- *
- * label - String that represents the label of the button.
- * funct - Function to be called if the button is pressed.
- * doc - Optional document to be used for creating the button. Default is the
- * current document.
- */
- button: function(label, funct, doc)
- {
- doc = (doc != null) ? doc : document;
-
- var button = doc.createElement('button');
- mxUtils.write(button, label);
- mxEvent.addListener(button, 'click', function(evt)
- {
- funct(evt);
- });
-
- return button;
- },
-
- /**
- * Function: para
- *
- * Appends a new paragraph with the given text to the specified parent and
- * returns the paragraph.
- *
- * Parameters:
- *
- * parent - DOM node to append the text node to.
- * text - String representing the text for the new paragraph.
- */
- para: function(parent, text)
- {
- var p = document.createElement('p');
- mxUtils.write(p, text);
- if (parent != null)
- {
- parent.appendChild(p);
- }
-
- return p;
- },
- /**
- * Function: addTransparentBackgroundFilter
- *
- * Adds a transparent background to the filter of the given node. This
- * background can be used in IE8 standards mode (native IE8 only) to pass
- * events through the node.
- */
- addTransparentBackgroundFilter: function(node)
- {
- node.style.filter += 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' +
- mxClient.imageBasePath + '/transparent.gif\', sizingMethod=\'scale\')';
- },
- /**
- * Function: linkAction
- *
- * Adds a hyperlink to the specified parent that invokes action on the
- * specified editor.
- *
- * Parameters:
- *
- * parent - DOM node to contain the new link.
- * text - String that is used as the link label.
- * editor - <mxEditor> that will execute the action.
- * action - String that defines the name of the action to be executed.
- * pad - Optional left-padding for the link. Default is 0.
- */
- linkAction: function(parent, text, editor, action, pad)
- {
- return mxUtils.link(parent, text, function()
- {
- editor.execute(action);
- }, pad);
- },
- /**
- * Function: linkInvoke
- *
- * Adds a hyperlink to the specified parent that invokes the specified
- * function on the editor passing along the specified argument. The
- * function name is the name of a function of the editor instance,
- * not an action name.
- *
- * Parameters:
- *
- * parent - DOM node to contain the new link.
- * text - String that is used as the link label.
- * editor - <mxEditor> instance to execute the function on.
- * functName - String that represents the name of the function.
- * arg - Object that represents the argument to the function.
- * pad - Optional left-padding for the link. Default is 0.
- */
- linkInvoke: function(parent, text, editor, functName, arg, pad)
- {
- return mxUtils.link(parent, text, function()
- {
- editor[functName](arg);
- }, pad);
- },
-
- /**
- * Function: link
- *
- * Adds a hyperlink to the specified parent and invokes the given function
- * when the link is clicked.
- *
- * Parameters:
- *
- * parent - DOM node to contain the new link.
- * text - String that is used as the link label.
- * funct - Function to execute when the link is clicked.
- * pad - Optional left-padding for the link. Default is 0.
- */
- link: function(parent, text, funct, pad)
- {
- var a = document.createElement('span');
-
- a.style.color = 'blue';
- a.style.textDecoration = 'underline';
- a.style.cursor = 'pointer';
-
- if (pad != null)
- {
- a.style.paddingLeft = pad+'px';
- }
-
- mxEvent.addListener(a, 'click', funct);
- mxUtils.write(a, text);
-
- if (parent != null)
- {
- parent.appendChild(a);
- }
-
- return a;
- },
- /**
- * Function: getDocumentSize
- *
- * Returns the client size for the current document as an <mxRectangle>.
- */
- getDocumentSize: function()
- {
- var b = document.body;
- var d = document.documentElement;
-
- try
- {
- return new mxRectangle(0, 0, b.clientWidth || d.clientWidth, Math.max(b.clientHeight || 0, d.clientHeight));
- }
- catch (e)
- {
- return new mxRectangle();
- }
- },
-
- /**
- * Function: fit
- *
- * Makes sure the given node is inside the visible area of the window. This
- * is done by setting the left and top in the style.
- */
- fit: function(node)
- {
- var ds = mxUtils.getDocumentSize();
- var left = parseInt(node.offsetLeft);
- var width = parseInt(node.offsetWidth);
-
- var offset = mxUtils.getDocumentScrollOrigin(node.ownerDocument);
- var sl = offset.x;
- var st = offset.y;
- var b = document.body;
- var d = document.documentElement;
- var right = (sl) + ds.width;
-
- if (left + width > right)
- {
- node.style.left = Math.max(sl, right - width) + 'px';
- }
-
- var top = parseInt(node.offsetTop);
- var height = parseInt(node.offsetHeight);
-
- var bottom = st + ds.height;
-
- if (top + height > bottom)
- {
- node.style.top = Math.max(st, bottom - height) + 'px';
- }
- },
- /**
- * Function: load
- *
- * Loads the specified URL *synchronously* and returns the <mxXmlRequest>.
- * Throws an exception if the file cannot be loaded. See <mxUtils.get> for
- * an asynchronous implementation.
- *
- * Example:
- *
- * (code)
- * try
- * {
- * var req = mxUtils.load(filename);
- * var root = req.getDocumentElement();
- * // Process XML DOM...
- * }
- * catch (ex)
- * {
- * mxUtils.alert('Cannot load '+filename+': '+ex);
- * }
- * (end)
- *
- * Parameters:
- *
- * url - URL to get the data from.
- */
- load: function(url)
- {
- var req = new mxXmlRequest(url, null, 'GET', false);
- req.send();
-
- return req;
- },
- /**
- * Function: get
- *
- * Loads the specified URL *asynchronously* and invokes the given functions
- * depending on the request status. Returns the <mxXmlRequest> in use. Both
- * functions take the <mxXmlRequest> as the only parameter. See
- * <mxUtils.load> for a synchronous implementation.
- *
- * Example:
- *
- * (code)
- * mxUtils.get(url, function(req)
- * {
- * var node = req.getDocumentElement();
- * // Process XML DOM...
- * });
- * (end)
- *
- * So for example, to load a diagram into an existing graph model, the
- * following code is used.
- *
- * (code)
- * mxUtils.get(url, function(req)
- * {
- * var node = req.getDocumentElement();
- * var dec = new mxCodec(node.ownerDocument);
- * dec.decode(node, graph.getModel());
- * });
- * (end)
- *
- * Parameters:
- *
- * url - URL to get the data from.
- * onload - Optional function to execute for a successful response.
- * onerror - Optional function to execute on error.
- * binary - Optional boolean parameter that specifies if the request is
- * binary.
- * timeout - Optional timeout in ms before calling ontimeout.
- * ontimeout - Optional function to execute on timeout.
- * headers - Optional with headers, eg. {'Authorization': 'token xyz'}
- */
- get: function(url, onload, onerror, binary, timeout, ontimeout, headers)
- {
- var req = new mxXmlRequest(url, null, 'GET');
- var setRequestHeaders = req.setRequestHeaders;
-
- if (headers)
- {
- req.setRequestHeaders = function(request, params)
- {
- setRequestHeaders.apply(this, arguments);
-
- for (var key in headers)
- {
- request.setRequestHeader(key, headers[key]);
- }
- };
- }
-
- if (binary != null)
- {
- req.setBinary(binary);
- }
-
- req.send(onload, onerror, timeout, ontimeout);
-
- return req;
- },
- /**
- * Function: getAll
- *
- * Loads the URLs in the given array *asynchronously* and invokes the given function
- * if all requests returned with a valid 2xx status. The error handler is invoked
- * once on the first error or invalid response.
- *
- * Parameters:
- *
- * urls - Array of URLs to be loaded.
- * onload - Callback with array of <mxXmlRequests>.
- * onerror - Optional function to execute on error.
- */
- getAll: function(urls, onload, onerror)
- {
- var remain = urls.length;
- var result = [];
- var errors = 0;
- var err = function()
- {
- if (errors == 0 && onerror != null)
- {
- onerror();
- }
- errors++;
- };
-
- for (var i = 0; i < urls.length; i++)
- {
- (function(url, index)
- {
- mxUtils.get(url, function(req)
- {
- var status = req.getStatus();
-
- if (status < 200 || status > 299)
- {
- err();
- }
- else
- {
- result[index] = req;
- remain--;
-
- if (remain == 0)
- {
- onload(result);
- }
- }
- }, err);
- })(urls[i], i);
- }
-
- if (remain == 0)
- {
- onload(result);
- }
- },
-
- /**
- * Function: post
- *
- * Posts the specified params to the given URL *asynchronously* and invokes
- * the given functions depending on the request status. Returns the
- * <mxXmlRequest> in use. Both functions take the <mxXmlRequest> as the
- * only parameter. Make sure to use encodeURIComponent for the parameter
- * values.
- *
- * Example:
- *
- * (code)
- * mxUtils.post(url, 'key=value', function(req)
- * {
- * mxUtils.alert('Ready: '+req.isReady()+' Status: '+req.getStatus());
- * // Process req.getDocumentElement() using DOM API if OK...
- * });
- * (end)
- *
- * Parameters:
- *
- * url - URL to get the data from.
- * params - Parameters for the post request.
- * onload - Optional function to execute for a successful response.
- * onerror - Optional function to execute on error.
- */
- post: function(url, params, onload, onerror)
- {
- return new mxXmlRequest(url, params).send(onload, onerror);
- },
-
- /**
- * Function: submit
- *
- * Submits the given parameters to the specified URL using
- * <mxXmlRequest.simulate> and returns the <mxXmlRequest>.
- * Make sure to use encodeURIComponent for the parameter
- * values.
- *
- * Parameters:
- *
- * url - URL to get the data from.
- * params - Parameters for the form.
- * doc - Document to create the form in.
- * target - Target to send the form result to.
- */
- submit: function(url, params, doc, target)
- {
- return new mxXmlRequest(url, params).simulate(doc, target);
- },
-
- /**
- * Function: loadInto
- *
- * Loads the specified URL *asynchronously* into the specified document,
- * invoking onload after the document has been loaded. This implementation
- * does not use <mxXmlRequest>, but the document.load method.
- *
- * Parameters:
- *
- * url - URL to get the data from.
- * doc - The document to load the URL into.
- * onload - Function to execute when the URL has been loaded.
- */
- loadInto: function(url, doc, onload)
- {
- if (mxClient.IS_IE)
- {
- doc.onreadystatechange = function ()
- {
- if (doc.readyState == 4)
- {
- onload();
- }
- };
- }
- else
- {
- doc.addEventListener('load', onload, false);
- }
-
- doc.load(url);
- },
-
- /**
- * Function: getValue
- *
- * Returns the value for the given key in the given associative array or
- * the given default value if the value is null.
- *
- * Parameters:
- *
- * array - Associative array that contains the value for the key.
- * key - Key whose value should be returned.
- * defaultValue - Value to be returned if the value for the given
- * key is null.
- */
- getValue: function(array, key, defaultValue)
- {
- var value = (array != null) ? array[key] : null;
- if (value == null)
- {
- value = defaultValue;
- }
-
- return value;
- },
-
- /**
- * Function: getNumber
- *
- * Returns the numeric value for the given key in the given associative
- * array or the given default value (or 0) if the value is null. The value
- * is converted to a numeric value using the Number function.
- *
- * Parameters:
- *
- * array - Associative array that contains the value for the key.
- * key - Key whose value should be returned.
- * defaultValue - Value to be returned if the value for the given
- * key is null. Default is 0.
- */
- getNumber: function(array, key, defaultValue)
- {
- var value = (array != null) ? array[key] : null;
- if (value == null)
- {
- value = defaultValue || 0;
- }
-
- return Number(value);
- },
-
- /**
- * Function: getColor
- *
- * Returns the color value for the given key in the given associative
- * array or the given default value if the value is null. If the value
- * is <mxConstants.NONE> then null is returned.
- *
- * Parameters:
- *
- * array - Associative array that contains the value for the key.
- * key - Key whose value should be returned.
- * defaultValue - Value to be returned if the value for the given
- * key is null. Default is null.
- */
- getColor: function(array, key, defaultValue)
- {
- var value = (array != null) ? array[key] : null;
- if (value == null)
- {
- value = defaultValue;
- }
- else if (value == mxConstants.NONE)
- {
- value = null;
- }
-
- return value;
- },
- /**
- * Function: clone
- *
- * Recursively clones the specified object ignoring all fieldnames in the
- * given array of transient fields. <mxObjectIdentity.FIELD_NAME> is always
- * ignored by this function.
- *
- * Parameters:
- *
- * obj - Object to be cloned.
- * transients - Optional array of strings representing the fieldname to be
- * ignored.
- * shallow - Optional boolean argument to specify if a shallow clone should
- * be created, that is, one where all object references are not cloned or,
- * in other words, one where only atomic (strings, numbers) values are
- * cloned. Default is false.
- */
- clone: function(obj, transients, shallow)
- {
- shallow = (shallow != null) ? shallow : false;
- var clone = null;
-
- if (obj != null && typeof(obj.constructor) == 'function')
- {
- clone = new obj.constructor();
-
- for (var i in obj)
- {
- if (i != mxObjectIdentity.FIELD_NAME && (transients == null ||
- mxUtils.indexOf(transients, i) < 0))
- {
- if (!shallow && typeof(obj[i]) == 'object')
- {
- clone[i] = mxUtils.clone(obj[i]);
- }
- else
- {
- clone[i] = obj[i];
- }
- }
- }
- }
-
- return clone;
- },
- /**
- * Function: equalPoints
- *
- * Compares all mxPoints in the given lists.
- *
- * Parameters:
- *
- * a - Array of <mxPoints> to be compared.
- * b - Array of <mxPoints> to be compared.
- */
- equalPoints: function(a, b)
- {
- if ((a == null && b != null) || (a != null && b == null) ||
- (a != null && b != null && a.length != b.length))
- {
- return false;
- }
- else if (a != null && b != null)
- {
- for (var i = 0; i < a.length; i++)
- {
- if ((a[i] != null && b[i] == null) ||
- (a[i] == null && b[i] != null) ||
- (a[i] != null && b[i] != null &&
- (a[i].x != b[i].x || a[i].y != b[i].y)))
- {
- return false;
- }
- }
- }
-
- return true;
- },
- /**
- * Function: equalEntries
- *
- * Returns true if all properties of the given objects are equal. Values
- * with NaN are equal to NaN and unequal to any other value.
- *
- * Parameters:
- *
- * a - First object to be compared.
- * b - Second object to be compared.
- */
- equalEntries: function(a, b)
- {
- // Counts keys in b to check if all values have been compared
- var count = 0;
- if ((a == null && b != null) || (a != null && b == null) ||
- (a != null && b != null && a.length != b.length))
- {
- return false;
- }
- else if (a != null && b != null)
- {
- for (var key in b)
- {
- count++;
- }
-
- for (var key in a)
- {
- count--
-
- if ((!mxUtils.isNaN(a[key]) || !mxUtils.isNaN(b[key])) && a[key] != b[key])
- {
- return false;
- }
- }
- }
-
- return count == 0;
- },
-
- /**
- * Function: removeDuplicates
- *
- * Removes all duplicates from the given array.
- */
- removeDuplicates: function(arr)
- {
- var dict = new mxDictionary();
- var result = [];
-
- for (var i = 0; i < arr.length; i++)
- {
- if (!dict.get(arr[i]))
- {
- result.push(arr[i]);
- dict.put(arr[i], true);
- }
- }
- return result;
- },
-
- /**
- * Function: isNaN
- *
- * Returns true if the given value is of type number and isNaN returns true.
- */
- isNaN: function(value)
- {
- return typeof(value) == 'number' && isNaN(value);
- },
-
- /**
- * Function: extend
- *
- * Assigns a copy of the superclass prototype to the subclass prototype.
- * Note that this does not call the constructor of the superclass at this
- * point, the superclass constructor should be called explicitely in the
- * subclass constructor. Below is an example.
- *
- * (code)
- * MyGraph = function(container, model, renderHint, stylesheet)
- * {
- * mxGraph.call(this, container, model, renderHint, stylesheet);
- * }
- *
- * mxUtils.extend(MyGraph, mxGraph);
- * (end)
- *
- * Parameters:
- *
- * ctor - Constructor of the subclass.
- * superCtor - Constructor of the superclass.
- */
- extend: function(ctor, superCtor)
- {
- var f = function() {};
- f.prototype = superCtor.prototype;
-
- ctor.prototype = new f();
- ctor.prototype.constructor = ctor;
- },
- /**
- * Function: toString
- *
- * Returns a textual representation of the specified object.
- *
- * Parameters:
- *
- * obj - Object to return the string representation for.
- */
- toString: function(obj)
- {
- var output = '';
-
- for (var i in obj)
- {
- try
- {
- if (obj[i] == null)
- {
- output += i + ' = [null]\n';
- }
- else if (typeof(obj[i]) == 'function')
- {
- output += i + ' => [Function]\n';
- }
- else if (typeof(obj[i]) == 'object')
- {
- var ctor = mxUtils.getFunctionName(obj[i].constructor);
- output += i + ' => [' + ctor + ']\n';
- }
- else
- {
- output += i + ' = ' + obj[i] + '\n';
- }
- }
- catch (e)
- {
- output += i + '=' + e.message;
- }
- }
-
- return output;
- },
- /**
- * Function: toRadians
- *
- * Converts the given degree to radians.
- */
- toRadians: function(deg)
- {
- return Math.PI * deg / 180;
- },
- /**
- * Function: toDegree
- *
- * Converts the given radians to degree.
- */
- toDegree: function(rad)
- {
- return rad * 180 / Math.PI;
- },
-
- /**
- * Function: arcToCurves
- *
- * Converts the given arc to a series of curves.
- */
- arcToCurves: function(x0, y0, r1, r2, angle, largeArcFlag, sweepFlag, x, y)
- {
- x -= x0;
- y -= y0;
-
- if (r1 === 0 || r2 === 0)
- {
- return result;
- }
-
- var fS = sweepFlag;
- var psai = angle;
- r1 = Math.abs(r1);
- r2 = Math.abs(r2);
- var ctx = -x / 2;
- var cty = -y / 2;
- var cpsi = Math.cos(psai * Math.PI / 180);
- var spsi = Math.sin(psai * Math.PI / 180);
- var rxd = cpsi * ctx + spsi * cty;
- var ryd = -1 * spsi * ctx + cpsi * cty;
- var rxdd = rxd * rxd;
- var rydd = ryd * ryd;
- var r1x = r1 * r1;
- var r2y = r2 * r2;
- var lamda = rxdd / r1x + rydd / r2y;
- var sds;
-
- if (lamda > 1)
- {
- r1 = Math.sqrt(lamda) * r1;
- r2 = Math.sqrt(lamda) * r2;
- sds = 0;
- }
- else
- {
- var seif = 1;
-
- if (largeArcFlag === fS)
- {
- seif = -1;
- }
-
- sds = seif * Math.sqrt((r1x * r2y - r1x * rydd - r2y * rxdd) / (r1x * rydd + r2y * rxdd));
- }
-
- var txd = sds * r1 * ryd / r2;
- var tyd = -1 * sds * r2 * rxd / r1;
- var tx = cpsi * txd - spsi * tyd + x / 2;
- var ty = spsi * txd + cpsi * tyd + y / 2;
- var rad = Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1) - Math.atan2(0, 1);
- var s1 = (rad >= 0) ? rad : 2 * Math.PI + rad;
- rad = Math.atan2((-ryd - tyd) / r2, (-rxd - txd) / r1) - Math.atan2((ryd - tyd) / r2, (rxd - txd) / r1);
- var dr = (rad >= 0) ? rad : 2 * Math.PI + rad;
-
- if (fS == 0 && dr > 0)
- {
- dr -= 2 * Math.PI;
- }
- else if (fS != 0 && dr < 0)
- {
- dr += 2 * Math.PI;
- }
-
- var sse = dr * 2 / Math.PI;
- var seg = Math.ceil(sse < 0 ? -1 * sse : sse);
- var segr = dr / seg;
- var t = 8/3 * Math.sin(segr / 4) * Math.sin(segr / 4) / Math.sin(segr / 2);
- var cpsir1 = cpsi * r1;
- var cpsir2 = cpsi * r2;
- var spsir1 = spsi * r1;
- var spsir2 = spsi * r2;
- var mc = Math.cos(s1);
- var ms = Math.sin(s1);
- var x2 = -t * (cpsir1 * ms + spsir2 * mc);
- var y2 = -t * (spsir1 * ms - cpsir2 * mc);
- var x3 = 0;
- var y3 = 0;
- var result = [];
-
- for (var n = 0; n < seg; ++n)
- {
- s1 += segr;
- mc = Math.cos(s1);
- ms = Math.sin(s1);
-
- x3 = cpsir1 * mc - spsir2 * ms + tx;
- y3 = spsir1 * mc + cpsir2 * ms + ty;
- var dx = -t * (cpsir1 * ms + spsir2 * mc);
- var dy = -t * (spsir1 * ms - cpsir2 * mc);
-
- // CurveTo updates x0, y0 so need to restore it
- var index = n * 6;
- result[index] = Number(x2 + x0);
- result[index + 1] = Number(y2 + y0);
- result[index + 2] = Number(x3 - dx + x0);
- result[index + 3] = Number(y3 - dy + y0);
- result[index + 4] = Number(x3 + x0);
- result[index + 5] = Number(y3 + y0);
-
- x2 = x3 + dx;
- y2 = y3 + dy;
- }
-
- return result;
- },
- /**
- * Function: getBoundingBox
- *
- * Returns the bounding box for the rotated rectangle.
- *
- * Parameters:
- *
- * rect - <mxRectangle> to be rotated.
- * angle - Number that represents the angle (in degrees).
- * cx - Optional <mxPoint> that represents the rotation center. If no
- * rotation center is given then the center of rect is used.
- */
- getBoundingBox: function(rect, rotation, cx)
- {
- var result = null;
- if (rect != null && rotation != null && rotation != 0)
- {
- var rad = mxUtils.toRadians(rotation);
- var cos = Math.cos(rad);
- var sin = Math.sin(rad);
- cx = (cx != null) ? cx : new mxPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
- var p1 = new mxPoint(rect.x, rect.y);
- var p2 = new mxPoint(rect.x + rect.width, rect.y);
- var p3 = new mxPoint(p2.x, rect.y + rect.height);
- var p4 = new mxPoint(rect.x, p3.y);
- p1 = mxUtils.getRotatedPoint(p1, cos, sin, cx);
- p2 = mxUtils.getRotatedPoint(p2, cos, sin, cx);
- p3 = mxUtils.getRotatedPoint(p3, cos, sin, cx);
- p4 = mxUtils.getRotatedPoint(p4, cos, sin, cx);
- result = new mxRectangle(p1.x, p1.y, 0, 0);
- result.add(new mxRectangle(p2.x, p2.y, 0, 0));
- result.add(new mxRectangle(p3.x, p3.y, 0, 0));
- result.add(new mxRectangle(p4.x, p4.y, 0, 0));
- }
- return result;
- },
- /**
- * Function: getRotatedPoint
- *
- * Rotates the given point by the given cos and sin.
- */
- getRotatedPoint: function(pt, cos, sin, c)
- {
- c = (c != null) ? c : new mxPoint();
- var x = pt.x - c.x;
- var y = pt.y - c.y;
- var x1 = x * cos - y * sin;
- var y1 = y * cos + x * sin;
- return new mxPoint(x1 + c.x, y1 + c.y);
- },
-
- /**
- * Returns an integer mask of the port constraints of the given map
- * @param dict the style map to determine the port constraints for
- * @param defaultValue Default value to return if the key is undefined.
- * @return the mask of port constraint directions
- *
- * Parameters:
- *
- * terminal - <mxCelState> that represents the terminal.
- * edge - <mxCellState> that represents the edge.
- * source - Boolean that specifies if the terminal is the source terminal.
- * defaultValue - Default value to be returned.
- */
- getPortConstraints: function(terminal, edge, source, defaultValue)
- {
- var value = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT,
- mxUtils.getValue(edge.style, (source) ? mxConstants.STYLE_SOURCE_PORT_CONSTRAINT :
- mxConstants.STYLE_TARGET_PORT_CONSTRAINT, null));
-
- if (value == null)
- {
- return defaultValue;
- }
- else
- {
- var directions = value.toString();
- var returnValue = mxConstants.DIRECTION_MASK_NONE;
- var constraintRotationEnabled = mxUtils.getValue(terminal.style, mxConstants.STYLE_PORT_CONSTRAINT_ROTATION, 0);
- var rotation = 0;
-
- if (constraintRotationEnabled == 1)
- {
- rotation = mxUtils.getValue(terminal.style, mxConstants.STYLE_ROTATION, 0);
- }
-
- var quad = 0;
- if (rotation > 45)
- {
- quad = 1;
-
- if (rotation >= 135)
- {
- quad = 2;
- }
- }
- else if (rotation < -45)
- {
- quad = 3;
-
- if (rotation <= -135)
- {
- quad = 2;
- }
- }
- if (directions.indexOf(mxConstants.DIRECTION_NORTH) >= 0)
- {
- switch (quad)
- {
- case 0:
- returnValue |= mxConstants.DIRECTION_MASK_NORTH;
- break;
- case 1:
- returnValue |= mxConstants.DIRECTION_MASK_EAST;
- break;
- case 2:
- returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
- break;
- case 3:
- returnValue |= mxConstants.DIRECTION_MASK_WEST;
- break;
- }
- }
- if (directions.indexOf(mxConstants.DIRECTION_WEST) >= 0)
- {
- switch (quad)
- {
- case 0:
- returnValue |= mxConstants.DIRECTION_MASK_WEST;
- break;
- case 1:
- returnValue |= mxConstants.DIRECTION_MASK_NORTH;
- break;
- case 2:
- returnValue |= mxConstants.DIRECTION_MASK_EAST;
- break;
- case 3:
- returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
- break;
- }
- }
- if (directions.indexOf(mxConstants.DIRECTION_SOUTH) >= 0)
- {
- switch (quad)
- {
- case 0:
- returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
- break;
- case 1:
- returnValue |= mxConstants.DIRECTION_MASK_WEST;
- break;
- case 2:
- returnValue |= mxConstants.DIRECTION_MASK_NORTH;
- break;
- case 3:
- returnValue |= mxConstants.DIRECTION_MASK_EAST;
- break;
- }
- }
- if (directions.indexOf(mxConstants.DIRECTION_EAST) >= 0)
- {
- switch (quad)
- {
- case 0:
- returnValue |= mxConstants.DIRECTION_MASK_EAST;
- break;
- case 1:
- returnValue |= mxConstants.DIRECTION_MASK_SOUTH;
- break;
- case 2:
- returnValue |= mxConstants.DIRECTION_MASK_WEST;
- break;
- case 3:
- returnValue |= mxConstants.DIRECTION_MASK_NORTH;
- break;
- }
- }
- return returnValue;
- }
- },
-
- /**
- * Function: reversePortConstraints
- *
- * Reverse the port constraint bitmask. For example, north | east
- * becomes south | west
- */
- reversePortConstraints: function(constraint)
- {
- var result = 0;
-
- result = (constraint & mxConstants.DIRECTION_MASK_WEST) << 3;
- result |= (constraint & mxConstants.DIRECTION_MASK_NORTH) << 1;
- result |= (constraint & mxConstants.DIRECTION_MASK_SOUTH) >> 1;
- result |= (constraint & mxConstants.DIRECTION_MASK_EAST) >> 3;
-
- return result;
- },
-
- /**
- * Function: findNearestSegment
- *
- * Finds the index of the nearest segment on the given cell state for
- * the specified coordinate pair.
- */
- findNearestSegment: function(state, x, y)
- {
- var index = -1;
-
- if (state.absolutePoints.length > 0)
- {
- var last = state.absolutePoints[0];
- var min = null;
-
- for (var i = 1; i < state.absolutePoints.length; i++)
- {
- var current = state.absolutePoints[i];
- var dist = mxUtils.ptSegDistSq(last.x, last.y,
- current.x, current.y, x, y);
-
- if (min == null || dist < min)
- {
- min = dist;
- index = i - 1;
- }
- last = current;
- }
- }
-
- return index;
- },
- /**
- * Function: getDirectedBounds
- *
- * Adds the given margins to the given rectangle and rotates and flips the
- * rectangle according to the respective styles in style.
- */
- getDirectedBounds: function (rect, m, style, flipH, flipV)
- {
- var d = mxUtils.getValue(style, mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
- flipH = (flipH != null) ? flipH : mxUtils.getValue(style, mxConstants.STYLE_FLIPH, false);
- flipV = (flipV != null) ? flipV : mxUtils.getValue(style, mxConstants.STYLE_FLIPV, false);
- m.x = Math.round(Math.max(0, Math.min(rect.width, m.x)));
- m.y = Math.round(Math.max(0, Math.min(rect.height, m.y)));
- m.width = Math.round(Math.max(0, Math.min(rect.width, m.width)));
- m.height = Math.round(Math.max(0, Math.min(rect.height, m.height)));
-
- if ((flipV && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
- (flipH && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
- {
- var tmp = m.x;
- m.x = m.width;
- m.width = tmp;
- }
-
- if ((flipH && (d == mxConstants.DIRECTION_SOUTH || d == mxConstants.DIRECTION_NORTH)) ||
- (flipV && (d == mxConstants.DIRECTION_EAST || d == mxConstants.DIRECTION_WEST)))
- {
- var tmp = m.y;
- m.y = m.height;
- m.height = tmp;
- }
-
- var m2 = mxRectangle.fromRectangle(m);
-
- if (d == mxConstants.DIRECTION_SOUTH)
- {
- m2.y = m.x;
- m2.x = m.height;
- m2.width = m.y;
- m2.height = m.width;
- }
- else if (d == mxConstants.DIRECTION_WEST)
- {
- m2.y = m.height;
- m2.x = m.width;
- m2.width = m.x;
- m2.height = m.y;
- }
- else if (d == mxConstants.DIRECTION_NORTH)
- {
- m2.y = m.width;
- m2.x = m.y;
- m2.width = m.height;
- m2.height = m.x;
- }
-
- return new mxRectangle(rect.x + m2.x, rect.y + m2.y, rect.width - m2.width - m2.x, rect.height - m2.height - m2.y);
- },
- /**
- * Function: getPerimeterPoint
- *
- * Returns the intersection between the polygon defined by the array of
- * points and the line between center and point.
- */
- getPerimeterPoint: function (pts, center, point)
- {
- var min = null;
-
- for (var i = 0; i < pts.length - 1; i++)
- {
- var pt = mxUtils.intersection(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y,
- center.x, center.y, point.x, point.y);
-
- if (pt != null)
- {
- var dx = point.x - pt.x;
- var dy = point.y - pt.y;
- var ip = {p: pt, distSq: dy * dy + dx * dx};
-
- if (ip != null && (min == null || min.distSq > ip.distSq))
- {
- min = ip;
- }
- }
- }
-
- return (min != null) ? min.p : null;
- },
- /**
- * Function: rectangleIntersectsSegment
- *
- * Returns true if the given rectangle intersects the given segment.
- *
- * Parameters:
- *
- * bounds - <mxRectangle> that represents the rectangle.
- * p1 - <mxPoint> that represents the first point of the segment.
- * p2 - <mxPoint> that represents the second point of the segment.
- */
- rectangleIntersectsSegment: function(bounds, p1, p2)
- {
- var top = bounds.y;
- var left = bounds.x;
- var bottom = top + bounds.height;
- var right = left + bounds.width;
-
- // Find min and max X for the segment
- var minX = p1.x;
- var maxX = p2.x;
-
- if (p1.x > p2.x)
- {
- minX = p2.x;
- maxX = p1.x;
- }
-
- // Find the intersection of the segment's and rectangle's x-projections
- if (maxX > right)
- {
- maxX = right;
- }
-
- if (minX < left)
- {
- minX = left;
- }
-
- if (minX > maxX) // If their projections do not intersect return false
- {
- return false;
- }
-
- // Find corresponding min and max Y for min and max X we found before
- var minY = p1.y;
- var maxY = p2.y;
- var dx = p2.x - p1.x;
-
- if (Math.abs(dx) > 0.0000001)
- {
- var a = (p2.y - p1.y) / dx;
- var b = p1.y - a * p1.x;
- minY = a * minX + b;
- maxY = a * maxX + b;
- }
-
- if (minY > maxY)
- {
- var tmp = maxY;
- maxY = minY;
- minY = tmp;
- }
-
- // Find the intersection of the segment's and rectangle's y-projections
- if (maxY > bottom)
- {
- maxY = bottom;
- }
-
- if (minY < top)
- {
- minY = top;
- }
-
- if (minY > maxY) // If Y-projections do not intersect return false
- {
- return false;
- }
-
- return true;
- },
-
- /**
- * Function: contains
- *
- * Returns true if the specified point (x, y) is contained in the given rectangle.
- *
- * Parameters:
- *
- * bounds - <mxRectangle> that represents the area.
- * x - X-coordinate of the point.
- * y - Y-coordinate of the point.
- */
- contains: function(bounds, x, y)
- {
- return (bounds.x <= x && bounds.x + bounds.width >= x &&
- bounds.y <= y && bounds.y + bounds.height >= y);
- },
- /**
- * Function: intersects
- *
- * Returns true if the two rectangles intersect.
- *
- * Parameters:
- *
- * a - <mxRectangle> to be checked for intersection.
- * b - <mxRectangle> to be checked for intersection.
- */
- intersects: function(a, b)
- {
- var tw = a.width;
- var th = a.height;
- var rw = b.width;
- var rh = b.height;
-
- if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0)
- {
- return false;
- }
-
- var tx = a.x;
- var ty = a.y;
- var rx = b.x;
- var ry = b.y;
-
- rw += rx;
- rh += ry;
- tw += tx;
- th += ty;
- return ((rw < rx || rw > tx) &&
- (rh < ry || rh > ty) &&
- (tw < tx || tw > rx) &&
- (th < ty || th > ry));
- },
- /**
- * Function: intersectsHotspot
- *
- * Returns true if the state and the hotspot intersect.
- *
- * Parameters:
- *
- * state - <mxCellState>
- * x - X-coordinate.
- * y - Y-coordinate.
- * hotspot - Optional size of the hostpot.
- * min - Optional min size of the hostpot.
- * max - Optional max size of the hostpot.
- */
- intersectsHotspot: function(state, x, y, hotspot, min, max)
- {
- hotspot = (hotspot != null) ? hotspot : 1;
- min = (min != null) ? min : 0;
- max = (max != null) ? max : 0;
-
- if (hotspot > 0)
- {
- var cx = state.getCenterX();
- var cy = state.getCenterY();
- var w = state.width;
- var h = state.height;
-
- var start = mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE) * state.view.scale;
- if (start > 0)
- {
- if (mxUtils.getValue(state.style, mxConstants.STYLE_HORIZONTAL, true))
- {
- cy = state.y + start / 2;
- h = start;
- }
- else
- {
- cx = state.x + start / 2;
- w = start;
- }
- }
- w = Math.max(min, w * hotspot);
- h = Math.max(min, h * hotspot);
-
- if (max > 0)
- {
- w = Math.min(w, max);
- h = Math.min(h, max);
- }
-
- var rect = new mxRectangle(cx - w / 2, cy - h / 2, w, h);
- var alpha = mxUtils.toRadians(mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION) || 0);
-
- if (alpha != 0)
- {
- var cos = Math.cos(-alpha);
- var sin = Math.sin(-alpha);
- var cx = new mxPoint(state.getCenterX(), state.getCenterY());
- var pt = mxUtils.getRotatedPoint(new mxPoint(x, y), cos, sin, cx);
- x = pt.x;
- y = pt.y;
- }
-
- return mxUtils.contains(rect, x, y);
- }
-
- return true;
- },
- /**
- * Function: getOffset
- *
- * Returns the offset for the specified container as an <mxPoint>. The
- * offset is the distance from the top left corner of the container to the
- * top left corner of the document.
- *
- * Parameters:
- *
- * container - DOM node to return the offset for.
- * scollOffset - Optional boolean to add the scroll offset of the document.
- * Default is false.
- */
- getOffset: function(container, scrollOffset)
- {
- var offsetLeft = 0;
- var offsetTop = 0;
-
- // Ignores document scroll origin for fixed elements
- var fixed = false;
- var node = container;
- var b = document.body;
- var d = document.documentElement;
- while (node != null && node != b && node != d && !fixed)
- {
- var style = mxUtils.getCurrentStyle(node);
-
- if (style != null)
- {
- fixed = fixed || style.position == 'fixed';
- }
-
- node = node.parentNode;
- }
-
- if (!scrollOffset && !fixed)
- {
- var offset = mxUtils.getDocumentScrollOrigin(container.ownerDocument);
- offsetLeft += offset.x;
- offsetTop += offset.y;
- }
-
- var r = container.getBoundingClientRect();
-
- if (r != null)
- {
- offsetLeft += r.left;
- offsetTop += r.top;
- }
-
- return new mxPoint(offsetLeft, offsetTop);
- },
- /**
- * Function: getDocumentScrollOrigin
- *
- * Returns the scroll origin of the given document or the current document
- * if no document is given.
- */
- getDocumentScrollOrigin: function(doc)
- {
- if (mxClient.IS_QUIRKS)
- {
- return new mxPoint(doc.body.scrollLeft, doc.body.scrollTop);
- }
- else
- {
- var wnd = doc.defaultView || doc.parentWindow;
-
- var x = (wnd != null && window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
- var y = (wnd != null && window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
-
- return new mxPoint(x, y);
- }
- },
-
- /**
- * Function: getScrollOrigin
- *
- * Returns the top, left corner of the viewrect as an <mxPoint>.
- *
- * Parameters:
- *
- * node - DOM node whose scroll origin should be returned.
- * includeAncestors - Whether the scroll origin of the ancestors should be
- * included. Default is false.
- * includeDocument - Whether the scroll origin of the document should be
- * included. Default is true.
- */
- getScrollOrigin: function(node, includeAncestors, includeDocument)
- {
- includeAncestors = (includeAncestors != null) ? includeAncestors : false;
- includeDocument = (includeDocument != null) ? includeDocument : true;
-
- var doc = (node != null) ? node.ownerDocument : document;
- var b = doc.body;
- var d = doc.documentElement;
- var result = new mxPoint();
- var fixed = false;
- while (node != null && node != b && node != d)
- {
- if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop))
- {
- result.x += node.scrollLeft;
- result.y += node.scrollTop;
- }
-
- var style = mxUtils.getCurrentStyle(node);
-
- if (style != null)
- {
- fixed = fixed || style.position == 'fixed';
- }
- node = (includeAncestors) ? node.parentNode : null;
- }
- if (!fixed && includeDocument)
- {
- var origin = mxUtils.getDocumentScrollOrigin(doc);
- result.x += origin.x;
- result.y += origin.y;
- }
-
- return result;
- },
- /**
- * Function: convertPoint
- *
- * Converts the specified point (x, y) using the offset of the specified
- * container and returns a new <mxPoint> with the result.
- *
- * (code)
- * var pt = mxUtils.convertPoint(graph.container,
- * mxEvent.getClientX(evt), mxEvent.getClientY(evt));
- * (end)
- *
- * Parameters:
- *
- * container - DOM node to use for the offset.
- * x - X-coordinate of the point to be converted.
- * y - Y-coordinate of the point to be converted.
- */
- convertPoint: function(container, x, y)
- {
- var origin = mxUtils.getScrollOrigin(container, false);
- var offset = mxUtils.getOffset(container);
- offset.x -= origin.x;
- offset.y -= origin.y;
-
- return new mxPoint(x - offset.x, y - offset.y);
- },
-
- /**
- * Function: ltrim
- *
- * Strips all whitespaces from the beginning of the string. Without the
- * second parameter, this will trim these characters:
- *
- * - " " (ASCII 32 (0x20)), an ordinary space
- * - "\t" (ASCII 9 (0x09)), a tab
- * - "\n" (ASCII 10 (0x0A)), a new line (line feed)
- * - "\r" (ASCII 13 (0x0D)), a carriage return
- * - "\0" (ASCII 0 (0x00)), the NUL-byte
- * - "\x0B" (ASCII 11 (0x0B)), a vertical tab
- */
- ltrim: function(str, chars)
- {
- chars = chars || "\\s";
-
- return (str != null) ? str.replace(new RegExp("^[" + chars + "]+", "g"), "") : null;
- },
-
- /**
- * Function: rtrim
- *
- * Strips all whitespaces from the end of the string. Without the second
- * parameter, this will trim these characters:
- *
- * - " " (ASCII 32 (0x20)), an ordinary space
- * - "\t" (ASCII 9 (0x09)), a tab
- * - "\n" (ASCII 10 (0x0A)), a new line (line feed)
- * - "\r" (ASCII 13 (0x0D)), a carriage return
- * - "\0" (ASCII 0 (0x00)), the NUL-byte
- * - "\x0B" (ASCII 11 (0x0B)), a vertical tab
- */
- rtrim: function(str, chars)
- {
- chars = chars || "\\s";
-
- return (str != null) ? str.replace(new RegExp("[" + chars + "]+$", "g"), "") : null;
- },
-
- /**
- * Function: trim
- *
- * Strips all whitespaces from both end of the string.
- * Without the second parameter, Javascript function will trim these
- * characters:
- *
- * - " " (ASCII 32 (0x20)), an ordinary space
- * - "\t" (ASCII 9 (0x09)), a tab
- * - "\n" (ASCII 10 (0x0A)), a new line (line feed)
- * - "\r" (ASCII 13 (0x0D)), a carriage return
- * - "\0" (ASCII 0 (0x00)), the NUL-byte
- * - "\x0B" (ASCII 11 (0x0B)), a vertical tab
- */
- trim: function(str, chars)
- {
- return mxUtils.ltrim(mxUtils.rtrim(str, chars), chars);
- },
-
- /**
- * Function: isNumeric
- *
- * Returns true if the specified value is numeric, that is, if it is not
- * null, not an empty string, not a HEX number and isNaN returns false.
- *
- * Parameters:
- *
- * n - String representing the possibly numeric value.
- */
- isNumeric: function(n)
- {
- return !isNaN(parseFloat(n)) && isFinite(n) && (typeof(n) != 'string' || n.toLowerCase().indexOf('0x') < 0);
- },
- /**
- * Function: isInteger
- *
- * Returns true if the given value is an valid integer number.
- *
- * Parameters:
- *
- * n - String representing the possibly numeric value.
- */
- isInteger: function(n)
- {
- return String(parseInt(n)) === String(n);
- },
- /**
- * Function: mod
- *
- * Returns the remainder of division of n by m. You should use this instead
- * of the built-in operation as the built-in operation does not properly
- * handle negative numbers.
- */
- mod: function(n, m)
- {
- return ((n % m) + m) % m;
- },
- /**
- * Function: intersection
- *
- * Returns the intersection of two lines as an <mxPoint>.
- *
- * Parameters:
- *
- * x0 - X-coordinate of the first line's startpoint.
- * y0 - X-coordinate of the first line's startpoint.
- * x1 - X-coordinate of the first line's endpoint.
- * y1 - Y-coordinate of the first line's endpoint.
- * x2 - X-coordinate of the second line's startpoint.
- * y2 - Y-coordinate of the second line's startpoint.
- * x3 - X-coordinate of the second line's endpoint.
- * y3 - Y-coordinate of the second line's endpoint.
- */
- intersection: function (x0, y0, x1, y1, x2, y2, x3, y3)
- {
- var denom = ((y3 - y2) * (x1 - x0)) - ((x3 - x2) * (y1 - y0));
- var nume_a = ((x3 - x2) * (y0 - y2)) - ((y3 - y2) * (x0 - x2));
- var nume_b = ((x1 - x0) * (y0 - y2)) - ((y1 - y0) * (x0 - x2));
- var ua = nume_a / denom;
- var ub = nume_b / denom;
-
- if(ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0)
- {
- // Get the intersection point
- var x = x0 + ua * (x1 - x0);
- var y = y0 + ua * (y1 - y0);
-
- return new mxPoint(x, y);
- }
-
- // No intersection
- return null;
- },
-
- /**
- * Function: ptSegDistSq
- *
- * Returns the square distance between a segment and a point. To get the
- * distance between a point and a line (with infinite length) use
- * <mxUtils.ptLineDist>.
- *
- * Parameters:
- *
- * x1 - X-coordinate of the startpoint of the segment.
- * y1 - Y-coordinate of the startpoint of the segment.
- * x2 - X-coordinate of the endpoint of the segment.
- * y2 - Y-coordinate of the endpoint of the segment.
- * px - X-coordinate of the point.
- * py - Y-coordinate of the point.
- */
- ptSegDistSq: function(x1, y1, x2, y2, px, py)
- {
- x2 -= x1;
- y2 -= y1;
- px -= x1;
- py -= y1;
- var dotprod = px * x2 + py * y2;
- var projlenSq;
- if (dotprod <= 0.0)
- {
- projlenSq = 0.0;
- }
- else
- {
- px = x2 - px;
- py = y2 - py;
- dotprod = px * x2 + py * y2;
- if (dotprod <= 0.0)
- {
- projlenSq = 0.0;
- }
- else
- {
- projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
- }
- }
- var lenSq = px * px + py * py - projlenSq;
-
- if (lenSq < 0)
- {
- lenSq = 0;
- }
-
- return lenSq;
- },
-
- /**
- * Function: ptLineDist
- *
- * Returns the distance between a line defined by two points and a point.
- * To get the distance between a point and a segment (with a specific
- * length) use <mxUtils.ptSeqDistSq>.
- *
- * Parameters:
- *
- * x1 - X-coordinate of point 1 of the line.
- * y1 - Y-coordinate of point 1 of the line.
- * x2 - X-coordinate of point 1 of the line.
- * y2 - Y-coordinate of point 1 of the line.
- * px - X-coordinate of the point.
- * py - Y-coordinate of the point.
- */
- ptLineDist: function(x1, y1, x2, y2, px, py)
- {
- return Math.abs((y2 - y1) * px - (x2 - x1) * py + x2 * y1 - y2 * x1) /
- Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
- },
-
- /**
- * Function: relativeCcw
- *
- * Returns 1 if the given point on the right side of the segment, 0 if its
- * on the segment, and -1 if the point is on the left side of the segment.
- *
- * Parameters:
- *
- * x1 - X-coordinate of the startpoint of the segment.
- * y1 - Y-coordinate of the startpoint of the segment.
- * x2 - X-coordinate of the endpoint of the segment.
- * y2 - Y-coordinate of the endpoint of the segment.
- * px - X-coordinate of the point.
- * py - Y-coordinate of the point.
- */
- relativeCcw: function(x1, y1, x2, y2, px, py)
- {
- x2 -= x1;
- y2 -= y1;
- px -= x1;
- py -= y1;
- var ccw = px * y2 - py * x2;
-
- if (ccw == 0.0)
- {
- ccw = px * x2 + py * y2;
-
- if (ccw > 0.0)
- {
- px -= x2;
- py -= y2;
- ccw = px * x2 + py * y2;
-
- if (ccw < 0.0)
- {
- ccw = 0.0;
- }
- }
- }
-
- return (ccw < 0.0) ? -1 : ((ccw > 0.0) ? 1 : 0);
- },
-
- /**
- * Function: animateChanges
- *
- * See <mxEffects.animateChanges>. This is for backwards compatibility and
- * will be removed later.
- */
- animateChanges: function(graph, changes)
- {
- // LATER: Deprecated, remove this function
- mxEffects.animateChanges.apply(this, arguments);
- },
-
- /**
- * Function: cascadeOpacity
- *
- * See <mxEffects.cascadeOpacity>. This is for backwards compatibility and
- * will be removed later.
- */
- cascadeOpacity: function(graph, cell, opacity)
- {
- mxEffects.cascadeOpacity.apply(this, arguments);
- },
- /**
- * Function: fadeOut
- *
- * See <mxEffects.fadeOut>. This is for backwards compatibility and
- * will be removed later.
- */
- fadeOut: function(node, from, remove, step, delay, isEnabled)
- {
- mxEffects.fadeOut.apply(this, arguments);
- },
-
- /**
- * Function: setOpacity
- *
- * Sets the opacity of the specified DOM node to the given value in %.
- *
- * Parameters:
- *
- * node - DOM node to set the opacity for.
- * value - Opacity in %. Possible values are between 0 and 100.
- */
- setOpacity: function(node, value)
- {
- if (mxUtils.isVml(node))
- {
- if (value >= 100)
- {
- node.style.filter = '';
- }
- else
- {
- // TODO: Why is the division by 5 needed in VML?
- node.style.filter = 'alpha(opacity=' + (value/5) + ')';
- }
- }
- else if (mxClient.IS_IE && (typeof(document.documentMode) === 'undefined' || document.documentMode < 9))
- {
- if (value >= 100)
- {
- node.style.filter = '';
- }
- else
- {
- node.style.filter = 'alpha(opacity=' + value + ')';
- }
- }
- else
- {
- node.style.opacity = (value / 100);
- }
- },
- /**
- * Function: createImage
- *
- * Creates and returns an image (IMG node) or VML image (v:image) in IE6 in
- * quirks mode.
- *
- * Parameters:
- *
- * src - URL that points to the image to be displayed.
- */
- createImage: function(src)
- {
- var imageNode = null;
-
- if (mxClient.IS_IE6 && document.compatMode != 'CSS1Compat')
- {
- imageNode = document.createElement(mxClient.VML_PREFIX + ':image');
- imageNode.setAttribute('src', src);
- imageNode.style.borderStyle = 'none';
- }
- else
- {
- imageNode = document.createElement('img');
- imageNode.setAttribute('src', src);
- imageNode.setAttribute('border', '0');
- }
-
- return imageNode;
- },
- /**
- * Function: sortCells
- *
- * Sorts the given cells according to the order in the cell hierarchy.
- * Ascending is optional and defaults to true.
- */
- sortCells: function(cells, ascending)
- {
- ascending = (ascending != null) ? ascending : true;
- var lookup = new mxDictionary();
- cells.sort(function(o1, o2)
- {
- var p1 = lookup.get(o1);
-
- if (p1 == null)
- {
- p1 = mxCellPath.create(o1).split(mxCellPath.PATH_SEPARATOR);
- lookup.put(o1, p1);
- }
-
- var p2 = lookup.get(o2);
-
- if (p2 == null)
- {
- p2 = mxCellPath.create(o2).split(mxCellPath.PATH_SEPARATOR);
- lookup.put(o2, p2);
- }
-
- var comp = mxCellPath.compare(p1, p2);
-
- return (comp == 0) ? 0 : (((comp > 0) == ascending) ? 1 : -1);
- });
-
- return cells;
- },
- /**
- * Function: getStylename
- *
- * Returns the stylename in a style of the form [(stylename|key=value);] or
- * an empty string if the given style does not contain a stylename.
- *
- * Parameters:
- *
- * style - String of the form [(stylename|key=value);].
- */
- getStylename: function(style)
- {
- if (style != null)
- {
- var pairs = style.split(';');
- var stylename = pairs[0];
-
- if (stylename.indexOf('=') < 0)
- {
- return stylename;
- }
- }
-
- return '';
- },
- /**
- * Function: getStylenames
- *
- * Returns the stylenames in a style of the form [(stylename|key=value);]
- * or an empty array if the given style does not contain any stylenames.
- *
- * Parameters:
- *
- * style - String of the form [(stylename|key=value);].
- */
- getStylenames: function(style)
- {
- var result = [];
-
- if (style != null)
- {
- var pairs = style.split(';');
-
- for (var i = 0; i < pairs.length; i++)
- {
- if (pairs[i].indexOf('=') < 0)
- {
- result.push(pairs[i]);
- }
- }
- }
-
- return result;
- },
- /**
- * Function: indexOfStylename
- *
- * Returns the index of the given stylename in the given style. This
- * returns -1 if the given stylename does not occur (as a stylename) in the
- * given style, otherwise it returns the index of the first character.
- */
- indexOfStylename: function(style, stylename)
- {
- if (style != null && stylename != null)
- {
- var tokens = style.split(';');
- var pos = 0;
-
- for (var i = 0; i < tokens.length; i++)
- {
- if (tokens[i] == stylename)
- {
- return pos;
- }
-
- pos += tokens[i].length + 1;
- }
- }
- return -1;
- },
-
- /**
- * Function: addStylename
- *
- * Adds the specified stylename to the given style if it does not already
- * contain the stylename.
- */
- addStylename: function(style, stylename)
- {
- if (mxUtils.indexOfStylename(style, stylename) < 0)
- {
- if (style == null)
- {
- style = '';
- }
- else if (style.length > 0 && style.charAt(style.length - 1) != ';')
- {
- style += ';';
- }
-
- style += stylename;
- }
-
- return style;
- },
-
- /**
- * Function: removeStylename
- *
- * Removes all occurrences of the specified stylename in the given style
- * and returns the updated style. Trailing semicolons are not preserved.
- */
- removeStylename: function(style, stylename)
- {
- var result = [];
-
- if (style != null)
- {
- var tokens = style.split(';');
-
- for (var i = 0; i < tokens.length; i++)
- {
- if (tokens[i] != stylename)
- {
- result.push(tokens[i]);
- }
- }
- }
-
- return result.join(';');
- },
-
- /**
- * Function: removeAllStylenames
- *
- * Removes all stylenames from the given style and returns the updated
- * style.
- */
- removeAllStylenames: function(style)
- {
- var result = [];
-
- if (style != null)
- {
- var tokens = style.split(';');
-
- for (var i = 0; i < tokens.length; i++)
- {
- // Keeps the key, value assignments
- if (tokens[i].indexOf('=') >= 0)
- {
- result.push(tokens[i]);
- }
- }
- }
-
- return result.join(';');
- },
- /**
- * Function: setCellStyles
- *
- * Assigns the value for the given key in the styles of the given cells, or
- * removes the key from the styles if the value is null.
- *
- * Parameters:
- *
- * model - <mxGraphModel> to execute the transaction in.
- * cells - Array of <mxCells> to be updated.
- * key - Key of the style to be changed.
- * value - New value for the given key.
- */
- setCellStyles: function(model, cells, key, value)
- {
- if (cells != null && cells.length > 0)
- {
- model.beginUpdate();
- try
- {
- for (var i = 0; i < cells.length; i++)
- {
- if (cells[i] != null)
- {
- var style = mxUtils.setStyle(model.getStyle(cells[i]), key, value);
- model.setStyle(cells[i], style);
- }
- }
- }
- finally
- {
- model.endUpdate();
- }
- }
- },
-
- /**
- * Function: setStyle
- *
- * Adds or removes the given key, value pair to the style and returns the
- * new style. If value is null or zero length then the key is removed from
- * the style. This is for cell styles, not for CSS styles.
- *
- * Parameters:
- *
- * style - String of the form [(stylename|key=value);].
- * key - Key of the style to be changed.
- * value - New value for the given key.
- */
- setStyle: function(style, key, value)
- {
- var isValue = value != null && (typeof(value.length) == 'undefined' || value.length > 0);
-
- if (style == null || style.length == 0)
- {
- if (isValue)
- {
- style = key + '=' + value + ';';
- }
- }
- else
- {
- if (style.substring(0, key.length + 1) == key + '=')
- {
- var next = style.indexOf(';');
-
- if (isValue)
- {
- style = key + '=' + value + ((next < 0) ? ';' : style.substring(next));
- }
- else
- {
- style = (next < 0 || next == style.length - 1) ? '' : style.substring(next + 1);
- }
- }
- else
- {
- var index = style.indexOf(';' + key + '=');
-
- if (index < 0)
- {
- if (isValue)
- {
- var sep = (style.charAt(style.length - 1) == ';') ? '' : ';';
- style = style + sep + key + '=' + value + ';';
- }
- }
- else
- {
- var next = style.indexOf(';', index + 1);
-
- if (isValue)
- {
- style = style.substring(0, index + 1) + key + '=' + value + ((next < 0) ? ';' : style.substring(next));
- }
- else
- {
- style = style.substring(0, index) + ((next < 0) ? ';' : style.substring(next));
- }
- }
- }
- }
-
- return style;
- },
- /**
- * Function: setCellStyleFlags
- *
- * Sets or toggles the flag bit for the given key in the cell's styles.
- * If value is null then the flag is toggled.
- *
- * Example:
- *
- * (code)
- * var cells = graph.getSelectionCells();
- * mxUtils.setCellStyleFlags(graph.model,
- * cells,
- * mxConstants.STYLE_FONTSTYLE,
- * mxConstants.FONT_BOLD);
- * (end)
- *
- * Toggles the bold font style.
- *
- * Parameters:
- *
- * model - <mxGraphModel> that contains the cells.
- * cells - Array of <mxCells> to change the style for.
- * key - Key of the style to be changed.
- * flag - Integer for the bit to be changed.
- * value - Optional boolean value for the flag.
- */
- setCellStyleFlags: function(model, cells, key, flag, value)
- {
- if (cells != null && cells.length > 0)
- {
- model.beginUpdate();
- try
- {
- for (var i = 0; i < cells.length; i++)
- {
- if (cells[i] != null)
- {
- var style = mxUtils.setStyleFlag(
- model.getStyle(cells[i]),
- key, flag, value);
- model.setStyle(cells[i], style);
- }
- }
- }
- finally
- {
- model.endUpdate();
- }
- }
- },
-
- /**
- * Function: setStyleFlag
- *
- * Sets or removes the given key from the specified style and returns the
- * new style. If value is null then the flag is toggled.
- *
- * Parameters:
- *
- * style - String of the form [(stylename|key=value);].
- * key - Key of the style to be changed.
- * flag - Integer for the bit to be changed.
- * value - Optional boolean value for the given flag.
- */
- setStyleFlag: function(style, key, flag, value)
- {
- if (style == null || style.length == 0)
- {
- if (value || value == null)
- {
- style = key+'='+flag;
- }
- else
- {
- style = key+'=0';
- }
- }
- else
- {
- var index = style.indexOf(key+'=');
-
- if (index < 0)
- {
- var sep = (style.charAt(style.length-1) == ';') ? '' : ';';
- if (value || value == null)
- {
- style = style + sep + key + '=' + flag;
- }
- else
- {
- style = style + sep + key + '=0';
- }
- }
- else
- {
- var cont = style.indexOf(';', index);
- var tmp = '';
-
- if (cont < 0)
- {
- tmp = style.substring(index+key.length+1);
- }
- else
- {
- tmp = style.substring(index+key.length+1, cont);
- }
-
- if (value == null)
- {
- tmp = parseInt(tmp) ^ flag;
- }
- else if (value)
- {
- tmp = parseInt(tmp) | flag;
- }
- else
- {
- tmp = parseInt(tmp) & ~flag;
- }
-
- style = style.substring(0, index) + key + '=' + tmp +
- ((cont >= 0) ? style.substring(cont) : '');
- }
- }
-
- return style;
- },
-
- /**
- * Function: getAlignmentAsPoint
- *
- * Returns an <mxPoint> that represents the horizontal and vertical alignment
- * for numeric computations. X is -0.5 for center, -1 for right and 0 for
- * left alignment. Y is -0.5 for middle, -1 for bottom and 0 for top
- * alignment. Default values for missing arguments is top, left.
- */
- getAlignmentAsPoint: function(align, valign)
- {
- var dx = -0.5;
- var dy = -0.5;
-
- // Horizontal alignment
- if (align == mxConstants.ALIGN_LEFT)
- {
- dx = 0;
- }
- else if (align == mxConstants.ALIGN_RIGHT)
- {
- dx = -1;
- }
- // Vertical alignment
- if (valign == mxConstants.ALIGN_TOP)
- {
- dy = 0;
- }
- else if (valign == mxConstants.ALIGN_BOTTOM)
- {
- dy = -1;
- }
-
- return new mxPoint(dx, dy);
- },
-
- /**
- * Function: getSizeForString
- *
- * Returns an <mxRectangle> with the size (width and height in pixels) of
- * the given string. The string may contain HTML markup. Newlines should be
- * converted to <br> before calling this method. The caller is responsible
- * for sanitizing the HTML markup.
- *
- * Example:
- *
- * (code)
- * var label = graph.getLabel(cell).replace(/\n/g, "<br>");
- * var size = graph.getSizeForString(label);
- * (end)
- *
- * Parameters:
- *
- * text - String whose size should be returned.
- * fontSize - Integer that specifies the font size in pixels. Default is
- * <mxConstants.DEFAULT_FONTSIZE>.
- * fontFamily - String that specifies the name of the font family. Default
- * is <mxConstants.DEFAULT_FONTFAMILY>.
- * textWidth - Optional width for text wrapping.
- * fontStyle - Optional font style.
- */
- getSizeForString: function(text, fontSize, fontFamily, textWidth, fontStyle)
- {
- fontSize = (fontSize != null) ? fontSize : mxConstants.DEFAULT_FONTSIZE;
- fontFamily = (fontFamily != null) ? fontFamily : mxConstants.DEFAULT_FONTFAMILY;
- var div = document.createElement('div');
-
- // Sets the font size and family
- div.style.fontFamily = fontFamily;
- div.style.fontSize = Math.round(fontSize) + 'px';
- div.style.lineHeight = Math.round(fontSize * mxConstants.LINE_HEIGHT) + 'px';
-
- // Sets the font style
- if (fontStyle != null)
- {
- if ((fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD)
- {
- div.style.fontWeight = 'bold';
- }
-
- if ((fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC)
- {
- div.style.fontStyle = 'italic';
- }
-
- var txtDecor = [];
-
- if ((fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE)
- {
- txtDecor.push('underline');
- }
-
- if ((fontStyle & mxConstants.FONT_STRIKETHROUGH) == mxConstants.FONT_STRIKETHROUGH)
- {
- txtDecor.push('line-through');
- }
-
- if (txtDecor.length > 0)
- {
- div.style.textDecoration = txtDecor.join(' ');
- }
- }
-
- // Disables block layout and outside wrapping and hides the div
- div.style.position = 'absolute';
- div.style.visibility = 'hidden';
- div.style.display = (mxClient.IS_QUIRKS) ? 'inline' : 'inline-block';
- div.style.zoom = '1';
-
- if (textWidth != null)
- {
- div.style.width = textWidth + 'px';
- div.style.whiteSpace = 'normal';
- }
- else
- {
- div.style.whiteSpace = 'nowrap';
- }
-
- // Adds the text and inserts into DOM for updating of size
- div.innerHTML = text;
- document.body.appendChild(div);
-
- // Gets the size and removes from DOM
- var size = new mxRectangle(0, 0, div.offsetWidth, div.offsetHeight);
- document.body.removeChild(div);
-
- return size;
- },
-
- /**
- * Function: getViewXml
- */
- getViewXml: function(graph, scale, cells, x0, y0)
- {
- x0 = (x0 != null) ? x0 : 0;
- y0 = (y0 != null) ? y0 : 0;
- scale = (scale != null) ? scale : 1;
- if (cells == null)
- {
- var model = graph.getModel();
- cells = [model.getRoot()];
- }
-
- var view = graph.getView();
- var result = null;
- // Disables events on the view
- var eventsEnabled = view.isEventsEnabled();
- view.setEventsEnabled(false);
- // Workaround for label bounds not taken into account for image export.
- // Creates a temporary draw pane which is used for rendering the text.
- // Text rendering is required for finding the bounds of the labels.
- var drawPane = view.drawPane;
- var overlayPane = view.overlayPane;
- if (graph.dialect == mxConstants.DIALECT_SVG)
- {
- view.drawPane = document.createElementNS(mxConstants.NS_SVG, 'g');
- view.canvas.appendChild(view.drawPane);
- // Redirects cell overlays into temporary container
- view.overlayPane = document.createElementNS(mxConstants.NS_SVG, 'g');
- view.canvas.appendChild(view.overlayPane);
- }
- else
- {
- view.drawPane = view.drawPane.cloneNode(false);
- view.canvas.appendChild(view.drawPane);
-
- // Redirects cell overlays into temporary container
- view.overlayPane = view.overlayPane.cloneNode(false);
- view.canvas.appendChild(view.overlayPane);
- }
- // Resets the translation
- var translate = view.getTranslate();
- view.translate = new mxPoint(x0, y0);
- // Creates the temporary cell states in the view
- var temp = new mxTemporaryCellStates(graph.getView(), scale, cells);
- try
- {
- var enc = new mxCodec();
- result = enc.encode(graph.getView());
- }
- finally
- {
- temp.destroy();
- view.translate = translate;
- view.canvas.removeChild(view.drawPane);
- view.canvas.removeChild(view.overlayPane);
- view.drawPane = drawPane;
- view.overlayPane = overlayPane;
- view.setEventsEnabled(eventsEnabled);
- }
- return result;
- },
-
- /**
- * Function: getScaleForPageCount
- *
- * Returns the scale to be used for printing the graph with the given
- * bounds across the specifies number of pages with the given format. The
- * scale is always computed such that it given the given amount or fewer
- * pages in the print output. See <mxPrintPreview> for an example.
- *
- * Parameters:
- *
- * pageCount - Specifies the number of pages in the print output.
- * graph - <mxGraph> that should be printed.
- * pageFormat - Optional <mxRectangle> that specifies the page format.
- * Default is <mxConstants.PAGE_FORMAT_A4_PORTRAIT>.
- * border - The border along each side of every page.
- */
- getScaleForPageCount: function(pageCount, graph, pageFormat, border)
- {
- if (pageCount < 1)
- {
- // We can't work with less than 1 page, return no scale
- // change
- return 1;
- }
-
- pageFormat = (pageFormat != null) ? pageFormat : mxConstants.PAGE_FORMAT_A4_PORTRAIT;
- border = (border != null) ? border : 0;
-
- var availablePageWidth = pageFormat.width - (border * 2);
- var availablePageHeight = pageFormat.height - (border * 2);
- // Work out the number of pages required if the
- // graph is not scaled.
- var graphBounds = graph.getGraphBounds().clone();
- var sc = graph.getView().getScale();
- graphBounds.width /= sc;
- graphBounds.height /= sc;
- var graphWidth = graphBounds.width;
- var graphHeight = graphBounds.height;
- var scale = 1;
-
- // The ratio of the width/height for each printer page
- var pageFormatAspectRatio = availablePageWidth / availablePageHeight;
- // The ratio of the width/height for the graph to be printer
- var graphAspectRatio = graphWidth / graphHeight;
-
- // The ratio of horizontal pages / vertical pages for this
- // graph to maintain its aspect ratio on this page format
- var pagesAspectRatio = graphAspectRatio / pageFormatAspectRatio;
-
- // Factor the square root of the page count up and down
- // by the pages aspect ratio to obtain a horizontal and
- // vertical page count that adds up to the page count
- // and has the correct aspect ratio
- var pageRoot = Math.sqrt(pageCount);
- var pagesAspectRatioSqrt = Math.sqrt(pagesAspectRatio);
- var numRowPages = pageRoot * pagesAspectRatioSqrt;
- var numColumnPages = pageRoot / pagesAspectRatioSqrt;
- // These value are rarely more than 2 rounding downs away from
- // a total that meets the page count. In cases of one being less
- // than 1 page, the other value can be too high and take more iterations
- // In this case, just change that value to be the page count, since
- // we know the other value is 1
- if (numRowPages < 1 && numColumnPages > pageCount)
- {
- var scaleChange = numColumnPages / pageCount;
- numColumnPages = pageCount;
- numRowPages /= scaleChange;
- }
-
- if (numColumnPages < 1 && numRowPages > pageCount)
- {
- var scaleChange = numRowPages / pageCount;
- numRowPages = pageCount;
- numColumnPages /= scaleChange;
- }
- var currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);
- var numLoops = 0;
-
- // Iterate through while the rounded up number of pages comes to
- // a total greater than the required number
- while (currentTotalPages > pageCount)
- {
- // Round down the page count (rows or columns) that is
- // closest to its next integer down in percentage terms.
- // i.e. Reduce the page total by reducing the total
- // page area by the least possible amount
- var roundRowDownProportion = Math.floor(numRowPages) / numRowPages;
- var roundColumnDownProportion = Math.floor(numColumnPages) / numColumnPages;
-
- // If the round down proportion is, work out the proportion to
- // round down to 1 page less
- if (roundRowDownProportion == 1)
- {
- roundRowDownProportion = Math.floor(numRowPages-1) / numRowPages;
- }
- if (roundColumnDownProportion == 1)
- {
- roundColumnDownProportion = Math.floor(numColumnPages-1) / numColumnPages;
- }
-
- // Check which rounding down is smaller, but in the case of very small roundings
- // try the other dimension instead
- var scaleChange = 1;
-
- // Use the higher of the two values
- if (roundRowDownProportion > roundColumnDownProportion)
- {
- scaleChange = roundRowDownProportion;
- }
- else
- {
- scaleChange = roundColumnDownProportion;
- }
- numRowPages = numRowPages * scaleChange;
- numColumnPages = numColumnPages * scaleChange;
- currentTotalPages = Math.ceil(numRowPages) * Math.ceil(numColumnPages);
-
- numLoops++;
-
- if (numLoops > 10)
- {
- break;
- }
- }
- // Work out the scale from the number of row pages required
- // The column pages will give the same value
- var posterWidth = availablePageWidth * numRowPages;
- scale = posterWidth / graphWidth;
-
- // Allow for rounding errors
- return scale * 0.99999;
- },
-
- /**
- * Function: show
- *
- * Copies the styles and the markup from the graph's container into the
- * given document and removes all cursor styles. The document is returned.
- *
- * This function should be called from within the document with the graph.
- * If you experience problems with missing stylesheets in IE then try adding
- * the domain to the trusted sites.
- *
- * Parameters:
- *
- * graph - <mxGraph> to be copied.
- * doc - Document where the new graph is created.
- * x0 - X-coordinate of the graph view origin. Default is 0.
- * y0 - Y-coordinate of the graph view origin. Default is 0.
- * w - Optional width of the graph view.
- * h - Optional height of the graph view.
- */
- show: function(graph, doc, x0, y0, w, h)
- {
- x0 = (x0 != null) ? x0 : 0;
- y0 = (y0 != null) ? y0 : 0;
-
- if (doc == null)
- {
- var wnd = window.open();
- doc = wnd.document;
- }
- else
- {
- doc.open();
- }
- // Workaround for missing print output in IE9 standards
- if (document.documentMode == 9)
- {
- doc.writeln('<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=9"><![endif]-->');
- }
-
- var bounds = graph.getGraphBounds();
- var dx = Math.ceil(x0 - bounds.x);
- var dy = Math.ceil(y0 - bounds.y);
-
- if (w == null)
- {
- w = Math.ceil(bounds.width + x0) + Math.ceil(Math.ceil(bounds.x) - bounds.x);
- }
-
- if (h == null)
- {
- h = Math.ceil(bounds.height + y0) + Math.ceil(Math.ceil(bounds.y) - bounds.y);
- }
-
- // Needs a special way of creating the page so that no click is required
- // to refresh the contents after the external CSS styles have been loaded.
- // To avoid a click or programmatic refresh, the styleSheets[].cssText
- // property is copied over from the original document.
- if (mxClient.IS_IE || document.documentMode == 11)
- {
- var html = '<html><head>';
- var base = document.getElementsByTagName('base');
-
- for (var i = 0; i < base.length; i++)
- {
- html += base[i].outerHTML;
- }
- html += '<style>';
- // Copies the stylesheets without having to load them again
- for (var i = 0; i < document.styleSheets.length; i++)
- {
- try
- {
- html += document.styleSheets[i].cssText;
- }
- catch (e)
- {
- // ignore security exception
- }
- }
- html += '</style></head><body style="margin:0px;">';
-
- // Copies the contents of the graph container
- html += '<div style="position:absolute;overflow:hidden;width:' + w + 'px;height:' + h + 'px;"><div style="position:relative;left:' + dx + 'px;top:' + dy + 'px;">';
- html += graph.container.innerHTML;
- html += '</div></div></body><html>';
- doc.writeln(html);
- doc.close();
- }
- else
- {
- doc.writeln('<html><head>');
-
- var base = document.getElementsByTagName('base');
-
- for (var i = 0; i < base.length; i++)
- {
- doc.writeln(mxUtils.getOuterHtml(base[i]));
- }
-
- var links = document.getElementsByTagName('link');
-
- for (var i = 0; i < links.length; i++)
- {
- doc.writeln(mxUtils.getOuterHtml(links[i]));
- }
-
- var styles = document.getElementsByTagName('style');
-
- for (var i = 0; i < styles.length; i++)
- {
- doc.writeln(mxUtils.getOuterHtml(styles[i]));
- }
- doc.writeln('</head><body style="margin:0px;"></body></html>');
- doc.close();
- var outer = doc.createElement('div');
- outer.position = 'absolute';
- outer.overflow = 'hidden';
- outer.style.width = w + 'px';
- outer.style.height = h + 'px';
- // Required for HTML labels if foreignObjects are disabled
- var div = doc.createElement('div');
- div.style.position = 'absolute';
- div.style.left = dx + 'px';
- div.style.top = dy + 'px';
- var node = graph.container.firstChild;
- var svg = null;
-
- while (node != null)
- {
- var clone = node.cloneNode(true);
-
- if (node == graph.view.drawPane.ownerSVGElement)
- {
- outer.appendChild(clone);
- svg = clone;
- }
- else
- {
- div.appendChild(clone);
- }
-
- node = node.nextSibling;
- }
- doc.body.appendChild(outer);
-
- if (div.firstChild != null)
- {
- doc.body.appendChild(div);
- }
-
- if (svg != null)
- {
- svg.style.minWidth = '';
- svg.style.minHeight = '';
- svg.firstChild.setAttribute('transform', 'translate(' + dx + ',' + dy + ')');
- }
- }
-
- mxUtils.removeCursors(doc.body);
-
- return doc;
- },
-
- /**
- * Function: printScreen
- *
- * Prints the specified graph using a new window and the built-in print
- * dialog.
- *
- * This function should be called from within the document with the graph.
- *
- * Parameters:
- *
- * graph - <mxGraph> to be printed.
- */
- printScreen: function(graph)
- {
- var wnd = window.open();
- var bounds = graph.getGraphBounds();
- mxUtils.show(graph, wnd.document);
-
- var print = function()
- {
- wnd.focus();
- wnd.print();
- wnd.close();
- };
-
- // Workaround for Google Chrome which needs a bit of a
- // delay in order to render the SVG contents
- if (mxClient.IS_GC)
- {
- wnd.setTimeout(print, 500);
- }
- else
- {
- print();
- }
- },
-
- /**
- * Function: popup
- *
- * Shows the specified text content in a new <mxWindow> or a new browser
- * window if isInternalWindow is false.
- *
- * Parameters:
- *
- * content - String that specifies the text to be displayed.
- * isInternalWindow - Optional boolean indicating if an mxWindow should be
- * used instead of a new browser window. Default is false.
- */
- popup: function(content, isInternalWindow)
- {
- if (isInternalWindow)
- {
- var div = document.createElement('div');
-
- div.style.overflow = 'scroll';
- div.style.width = '636px';
- div.style.height = '460px';
-
- var pre = document.createElement('pre');
- pre.innerHTML = mxUtils.htmlEntities(content, false).
- replace(/\n/g,'<br>').replace(/ /g, ' ');
-
- div.appendChild(pre);
-
- var w = document.body.clientWidth;
- var h = Math.max(document.body.clientHeight || 0, document.documentElement.clientHeight)
- var wnd = new mxWindow('Popup Window', div,
- w/2-320, h/2-240, 640, 480, false, true);
- wnd.setClosable(true);
- wnd.setVisible(true);
- }
- else
- {
- // Wraps up the XML content in a textarea
- if (mxClient.IS_NS)
- {
- var wnd = window.open();
- wnd.document.writeln('<pre>'+mxUtils.htmlEntities(content)+'</pre');
- wnd.document.close();
- }
- else
- {
- var wnd = window.open();
- var pre = wnd.document.createElement('pre');
- pre.innerHTML = mxUtils.htmlEntities(content, false).
- replace(/\n/g,'<br>').replace(/ /g, ' ');
- wnd.document.body.appendChild(pre);
- }
- }
- },
-
- /**
- * Function: alert
- *
- * Displayss the given alert in a new dialog. This implementation uses the
- * built-in alert function. This is used to display validation errors when
- * connections cannot be changed or created.
- *
- * Parameters:
- *
- * message - String specifying the message to be displayed.
- */
- alert: function(message)
- {
- alert(message);
- },
-
- /**
- * Function: prompt
- *
- * Displays the given message in a prompt dialog. This implementation uses
- * the built-in prompt function.
- *
- * Parameters:
- *
- * message - String specifying the message to be displayed.
- * defaultValue - Optional string specifying the default value.
- */
- prompt: function(message, defaultValue)
- {
- return prompt(message, (defaultValue != null) ? defaultValue : '');
- },
-
- /**
- * Function: confirm
- *
- * Displays the given message in a confirm dialog. This implementation uses
- * the built-in confirm function.
- *
- * Parameters:
- *
- * message - String specifying the message to be displayed.
- */
- confirm: function(message)
- {
- return confirm(message);
- },
- /**
- * Function: error
- *
- * Displays the given error message in a new <mxWindow> of the given width.
- * If close is true then an additional close button is added to the window.
- * The optional icon specifies the icon to be used for the window. Default
- * is <mxUtils.errorImage>.
- *
- * Parameters:
- *
- * message - String specifying the message to be displayed.
- * width - Integer specifying the width of the window.
- * close - Optional boolean indicating whether to add a close button.
- * icon - Optional icon for the window decoration.
- */
- error: function(message, width, close, icon)
- {
- var div = document.createElement('div');
- div.style.padding = '20px';
- var img = document.createElement('img');
- img.setAttribute('src', icon || mxUtils.errorImage);
- img.setAttribute('valign', 'bottom');
- img.style.verticalAlign = 'middle';
- div.appendChild(img);
- div.appendChild(document.createTextNode('\u00a0')); //
- div.appendChild(document.createTextNode('\u00a0')); //
- div.appendChild(document.createTextNode('\u00a0')); //
- mxUtils.write(div, message);
- var w = document.body.clientWidth;
- var h = (document.body.clientHeight || document.documentElement.clientHeight);
- var warn = new mxWindow(mxResources.get(mxUtils.errorResource) ||
- mxUtils.errorResource, div, (w-width)/2, h/4, width, null,
- false, true);
- if (close)
- {
- mxUtils.br(div);
-
- var tmp = document.createElement('p');
- var button = document.createElement('button');
- if (mxClient.IS_IE)
- {
- button.style.cssText = 'float:right';
- }
- else
- {
- button.setAttribute('style', 'float:right');
- }
- mxEvent.addListener(button, 'click', function(evt)
- {
- warn.destroy();
- });
- mxUtils.write(button, mxResources.get(mxUtils.closeResource) ||
- mxUtils.closeResource);
-
- tmp.appendChild(button);
- div.appendChild(tmp);
-
- mxUtils.br(div);
-
- warn.setClosable(true);
- }
-
- warn.setVisible(true);
-
- return warn;
- },
- /**
- * Function: makeDraggable
- *
- * Configures the given DOM element to act as a drag source for the
- * specified graph. Returns a a new <mxDragSource>. If
- * <mxDragSource.guideEnabled> is enabled then the x and y arguments must
- * be used in funct to match the preview location.
- *
- * Example:
- *
- * (code)
- * var funct = function(graph, evt, cell, x, y)
- * {
- * if (graph.canImportCell(cell))
- * {
- * var parent = graph.getDefaultParent();
- * var vertex = null;
- *
- * graph.getModel().beginUpdate();
- * try
- * {
- * vertex = graph.insertVertex(parent, null, 'Hello', x, y, 80, 30);
- * }
- * finally
- * {
- * graph.getModel().endUpdate();
- * }
- *
- * graph.setSelectionCell(vertex);
- * }
- * }
- *
- * var img = document.createElement('img');
- * img.setAttribute('src', 'editors/images/rectangle.gif');
- * img.style.position = 'absolute';
- * img.style.left = '0px';
- * img.style.top = '0px';
- * img.style.width = '16px';
- * img.style.height = '16px';
- *
- * var dragImage = img.cloneNode(true);
- * dragImage.style.width = '32px';
- * dragImage.style.height = '32px';
- * mxUtils.makeDraggable(img, graph, funct, dragImage);
- * document.body.appendChild(img);
- * (end)
- *
- * Parameters:
- *
- * element - DOM element to make draggable.
- * graphF - <mxGraph> that acts as the drop target or a function that takes a
- * mouse event and returns the current <mxGraph>.
- * funct - Function to execute on a successful drop.
- * dragElement - Optional DOM node to be used for the drag preview.
- * dx - Optional horizontal offset between the cursor and the drag
- * preview.
- * dy - Optional vertical offset between the cursor and the drag
- * preview.
- * autoscroll - Optional boolean that specifies if autoscroll should be
- * used. Default is mxGraph.autoscroll.
- * scalePreview - Optional boolean that specifies if the preview element
- * should be scaled according to the graph scale. If this is true, then
- * the offsets will also be scaled. Default is false.
- * highlightDropTargets - Optional boolean that specifies if dropTargets
- * should be highlighted. Default is true.
- * getDropTarget - Optional function to return the drop target for a given
- * location (x, y). Default is mxGraph.getCellAt.
- */
- makeDraggable: function(element, graphF, funct, dragElement, dx, dy, autoscroll,
- scalePreview, highlightDropTargets, getDropTarget)
- {
- var dragSource = new mxDragSource(element, funct);
- dragSource.dragOffset = new mxPoint((dx != null) ? dx : 0,
- (dy != null) ? dy : mxConstants.TOOLTIP_VERTICAL_OFFSET);
- dragSource.autoscroll = autoscroll;
-
- // Cannot enable this by default. This needs to be enabled in the caller
- // if the funct argument uses the new x- and y-arguments.
- dragSource.setGuidesEnabled(false);
-
- if (highlightDropTargets != null)
- {
- dragSource.highlightDropTargets = highlightDropTargets;
- }
-
- // Overrides function to find drop target cell
- if (getDropTarget != null)
- {
- dragSource.getDropTarget = getDropTarget;
- }
-
- // Overrides function to get current graph
- dragSource.getGraphForEvent = function(evt)
- {
- return (typeof(graphF) == 'function') ? graphF(evt) : graphF;
- };
-
- // Translates switches into dragSource customizations
- if (dragElement != null)
- {
- dragSource.createDragElement = function()
- {
- return dragElement.cloneNode(true);
- };
-
- if (scalePreview)
- {
- dragSource.createPreviewElement = function(graph)
- {
- var elt = dragElement.cloneNode(true);
- var w = parseInt(elt.style.width);
- var h = parseInt(elt.style.height);
- elt.style.width = Math.round(w * graph.view.scale) + 'px';
- elt.style.height = Math.round(h * graph.view.scale) + 'px';
-
- return elt;
- };
- }
- }
-
- return dragSource;
- }
- };
- __mxOutput.mxUtils = typeof mxUtils !== 'undefined' ? mxUtils : undefined;
|