12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546 |
- /**
- * Copyright (c) 2006-2015, JGraph Ltd
- * Copyright (c) 2006-2015, Gaudenz Alder
- */
- /**
- * Class: mxEdgeHandler
- *
- * Graph event handler that reconnects edges and modifies control points and
- * the edge label location. Uses <mxTerminalMarker> for finding and
- * highlighting new source and target vertices. This handler is automatically
- * created in <mxGraph.createHandler> for each selected edge.
- *
- * To enable adding/removing control points, the following code can be used:
- *
- * (code)
- * mxEdgeHandler.prototype.addEnabled = true;
- * mxEdgeHandler.prototype.removeEnabled = true;
- * (end)
- *
- * Note: This experimental feature is not recommended for production use.
- *
- * Constructor: mxEdgeHandler
- *
- * Constructs an edge handler for the specified <mxCellState>.
- *
- * Parameters:
- *
- * state - <mxCellState> of the cell to be handled.
- */
- function mxEdgeHandler(state)
- {
- if (state != null && state.shape != null)
- {
- this.state = state;
- this.init();
-
- // Handles escape keystrokes
- this.escapeHandler = mxUtils.bind(this, function(sender, evt)
- {
- var dirty = this.index != null;
- this.reset();
-
- if (dirty)
- {
- this.graph.cellRenderer.redraw(this.state, false, state.view.isRendering());
- }
- });
-
- this.state.view.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
- }
- };
- /**
- * Variable: graph
- *
- * Reference to the enclosing <mxGraph>.
- */
- mxEdgeHandler.prototype.graph = null;
- /**
- * Variable: state
- *
- * Reference to the <mxCellState> being modified.
- */
- mxEdgeHandler.prototype.state = null;
- /**
- * Variable: marker
- *
- * Holds the <mxTerminalMarker> which is used for highlighting terminals.
- */
- mxEdgeHandler.prototype.marker = null;
- /**
- * Variable: constraintHandler
- *
- * Holds the <mxConstraintHandler> used for drawing and highlighting
- * constraints.
- */
- mxEdgeHandler.prototype.constraintHandler = null;
- /**
- * Variable: error
- *
- * Holds the current validation error while a connection is being changed.
- */
- mxEdgeHandler.prototype.error = null;
- /**
- * Variable: shape
- *
- * Holds the <mxShape> that represents the preview edge.
- */
- mxEdgeHandler.prototype.shape = null;
- /**
- * Variable: bends
- *
- * Holds the <mxShapes> that represent the points.
- */
- mxEdgeHandler.prototype.bends = null;
- /**
- * Variable: labelShape
- *
- * Holds the <mxShape> that represents the label position.
- */
- mxEdgeHandler.prototype.labelShape = null;
- /**
- * Variable: cloneEnabled
- *
- * Specifies if cloning by control-drag is enabled. Default is true.
- */
- mxEdgeHandler.prototype.cloneEnabled = true;
- /**
- * Variable: addEnabled
- *
- * Specifies if adding bends by shift-click is enabled. Default is false.
- * Note: This experimental feature is not recommended for production use.
- */
- mxEdgeHandler.prototype.addEnabled = false;
- /**
- * Variable: removeEnabled
- *
- * Specifies if removing bends by shift-click is enabled. Default is false.
- * Note: This experimental feature is not recommended for production use.
- */
- mxEdgeHandler.prototype.removeEnabled = false;
- /**
- * Variable: dblClickRemoveEnabled
- *
- * Specifies if removing bends by double click is enabled. Default is false.
- */
- mxEdgeHandler.prototype.dblClickRemoveEnabled = false;
- /**
- * Variable: mergeRemoveEnabled
- *
- * Specifies if removing bends by dropping them on other bends is enabled.
- * Default is false.
- */
- mxEdgeHandler.prototype.mergeRemoveEnabled = false;
- /**
- * Variable: straightRemoveEnabled
- *
- * Specifies if removing bends by creating straight segments should be enabled.
- * If enabled, this can be overridden by holding down the alt key while moving.
- * Default is false.
- */
- mxEdgeHandler.prototype.straightRemoveEnabled = false;
- /**
- * Variable: virtualBendsEnabled
- *
- * Specifies if virtual bends should be added in the center of each
- * segments. These bends can then be used to add new waypoints.
- * Default is false.
- */
- mxEdgeHandler.prototype.virtualBendsEnabled = false;
- /**
- * Variable: virtualBendOpacity
- *
- * Opacity to be used for virtual bends (see <virtualBendsEnabled>).
- * Default is 20.
- */
- mxEdgeHandler.prototype.virtualBendOpacity = 20;
- /**
- * Variable: parentHighlightEnabled
- *
- * Specifies if the parent should be highlighted if a child cell is selected.
- * Default is false.
- */
- mxEdgeHandler.prototype.parentHighlightEnabled = false;
- /**
- * Variable: preferHtml
- *
- * Specifies if bends should be added to the graph container. This is updated
- * in <init> based on whether the edge or one of its terminals has an HTML
- * label in the container.
- */
- mxEdgeHandler.prototype.preferHtml = false;
- /**
- * Variable: allowHandleBoundsCheck
- *
- * Specifies if the bounds of handles should be used for hit-detection in IE
- * Default is true.
- */
- mxEdgeHandler.prototype.allowHandleBoundsCheck = true;
- /**
- * Variable: snapToTerminals
- *
- * Specifies if waypoints should snap to the routing centers of terminals.
- * Default is false.
- */
- mxEdgeHandler.prototype.snapToTerminals = false;
- /**
- * Variable: handleImage
- *
- * Optional <mxImage> to be used as handles. Default is null.
- */
- mxEdgeHandler.prototype.handleImage = null;
- /**
- * Variable: tolerance
- *
- * Optional tolerance for hit-detection in <getHandleForEvent>. Default is 0.
- */
- mxEdgeHandler.prototype.tolerance = 0;
- /**
- * Variable: outlineConnect
- *
- * Specifies if connections to the outline of a highlighted target should be
- * enabled. This will allow to place the connection point along the outline of
- * the highlighted target. Default is false.
- */
- mxEdgeHandler.prototype.outlineConnect = false;
- /**
- * Variable: manageLabelHandle
- *
- * Specifies if the label handle should be moved if it intersects with another
- * handle. Uses <checkLabelHandle> for checking and moving. Default is false.
- */
- mxEdgeHandler.prototype.manageLabelHandle = false;
- /**
- * Function: init
- *
- * Initializes the shapes required for this edge handler.
- */
- mxEdgeHandler.prototype.init = function()
- {
- this.graph = this.state.view.graph;
- this.marker = this.createMarker();
- this.constraintHandler = new mxConstraintHandler(this.graph);
-
- // Clones the original points from the cell
- // and makes sure at least one point exists
- this.points = [];
-
- // Uses the absolute points of the state
- // for the initial configuration and preview
- this.abspoints = this.getSelectionPoints(this.state);
- this.shape = this.createSelectionShape(this.abspoints);
- this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
- mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
- this.shape.init(this.graph.getView().getOverlayPane());
- this.shape.pointerEvents = false;
- this.shape.setCursor(mxConstants.CURSOR_MOVABLE_EDGE);
- mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);
- // Updates preferHtml
- this.preferHtml = this.state.text != null &&
- this.state.text.node.parentNode == this.graph.container;
-
- if (!this.preferHtml)
- {
- // Checks source terminal
- var sourceState = this.state.getVisibleTerminalState(true);
-
- if (sourceState != null)
- {
- this.preferHtml = sourceState.text != null &&
- sourceState.text.node.parentNode == this.graph.container;
- }
-
- if (!this.preferHtml)
- {
- // Checks target terminal
- var targetState = this.state.getVisibleTerminalState(false);
-
- if (targetState != null)
- {
- this.preferHtml = targetState.text != null &&
- targetState.text.node.parentNode == this.graph.container;
- }
- }
- }
- // Creates bends for the non-routed absolute points
- // or bends that don't correspond to points
- if (this.graph.getSelectionCount() < mxGraphHandler.prototype.maxCells ||
- mxGraphHandler.prototype.maxCells <= 0)
- {
- this.bends = this.createBends();
- if (this.isVirtualBendsEnabled())
- {
- this.virtualBends = this.createVirtualBends();
- }
- }
- // Adds a rectangular handle for the label position
- this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
- this.labelShape = this.createLabelHandleShape();
- this.initBend(this.labelShape);
- this.labelShape.setCursor(mxConstants.CURSOR_LABEL_HANDLE);
-
- this.customHandles = this.createCustomHandles();
-
- this.updateParentHighlight();
- this.redraw();
- };
- /**
- * Function: isParentHighlightVisible
- *
- * Returns true if the parent highlight should be visible. This implementation
- * always returns true.
- */
- mxEdgeHandler.prototype.isParentHighlightVisible = mxVertexHandler.prototype.isParentHighlightVisible;
- /**
- * Function: updateParentHighlight
- *
- * Updates the highlight of the parent if <parentHighlightEnabled> is true.
- */
- mxEdgeHandler.prototype.updateParentHighlight = mxVertexHandler.prototype.updateParentHighlight;
- /**
- * Function: createCustomHandles
- *
- * Returns an array of custom handles. This implementation returns null.
- */
- mxEdgeHandler.prototype.createCustomHandles = function()
- {
- return null;
- };
- /**
- * Function: isVirtualBendsEnabled
- *
- * Returns true if virtual bends should be added. This returns true if
- * <virtualBendsEnabled> is true and the current style allows and
- * renders custom waypoints.
- */
- mxEdgeHandler.prototype.isVirtualBendsEnabled = function(evt)
- {
- return this.virtualBendsEnabled && (this.state.style[mxConstants.STYLE_EDGE] == null ||
- this.state.style[mxConstants.STYLE_EDGE] == mxConstants.NONE ||
- this.state.style[mxConstants.STYLE_NOEDGESTYLE] == 1) &&
- mxUtils.getValue(this.state.style, mxConstants.STYLE_SHAPE, null) != 'arrow';
- };
- /**
- * Function: isCellEnabled
- *
- * Returns true if the given cell allows new connections to be created. This implementation
- * always returns true.
- */
- mxEdgeHandler.prototype.isCellEnabled = function(cell)
- {
- return true;
- };
- /**
- * Function: isAddPointEvent
- *
- * Returns true if the given event is a trigger to add a new point. This
- * implementation returns true if shift is pressed.
- */
- mxEdgeHandler.prototype.isAddPointEvent = function(evt)
- {
- return mxEvent.isShiftDown(evt);
- };
- /**
- * Function: isRemovePointEvent
- *
- * Returns true if the given event is a trigger to remove a point. This
- * implementation returns true if shift is pressed.
- */
- mxEdgeHandler.prototype.isRemovePointEvent = function(evt)
- {
- return mxEvent.isShiftDown(evt);
- };
- /**
- * Function: getSelectionPoints
- *
- * Returns the list of points that defines the selection stroke.
- */
- mxEdgeHandler.prototype.getSelectionPoints = function(state)
- {
- return state.absolutePoints;
- };
- /**
- * Function: createParentHighlightShape
- *
- * Creates the shape used to draw the selection border.
- */
- mxEdgeHandler.prototype.createParentHighlightShape = function(bounds)
- {
- var shape = new mxRectangleShape(mxRectangle.fromRectangle(bounds),
- null, this.getSelectionColor());
- shape.strokewidth = this.getSelectionStrokeWidth();
- shape.isDashed = this.isSelectionDashed();
-
- return shape;
- };
- /**
- * Function: createSelectionShape
- *
- * Creates the shape used to draw the selection border.
- */
- mxEdgeHandler.prototype.createSelectionShape = function(points)
- {
- var shape = new this.state.shape.constructor();
- shape.outline = true;
- shape.apply(this.state);
-
- shape.isDashed = this.isSelectionDashed();
- shape.stroke = this.getSelectionColor();
- shape.isShadow = false;
-
- return shape;
- };
- /**
- * Function: getSelectionColor
- *
- * Returns <mxConstants.EDGE_SELECTION_COLOR>.
- */
- mxEdgeHandler.prototype.getSelectionColor = function()
- {
- return mxConstants.EDGE_SELECTION_COLOR;
- };
- /**
- * Function: getSelectionStrokeWidth
- *
- * Returns <mxConstants.EDGE_SELECTION_STROKEWIDTH>.
- */
- mxEdgeHandler.prototype.getSelectionStrokeWidth = function()
- {
- return mxConstants.EDGE_SELECTION_STROKEWIDTH;
- };
- /**
- * Function: isSelectionDashed
- *
- * Returns <mxConstants.EDGE_SELECTION_DASHED>.
- */
- mxEdgeHandler.prototype.isSelectionDashed = function()
- {
- return mxConstants.EDGE_SELECTION_DASHED;
- };
- /**
- * Function: isConnectableCell
- *
- * Returns true if the given cell is connectable. This is a hook to
- * disable floating connections. This implementation returns true.
- */
- mxEdgeHandler.prototype.isConnectableCell = function(cell)
- {
- return true;
- };
- /**
- * Function: getCellAt
- *
- * Creates and returns the <mxCellMarker> used in <marker>.
- */
- mxEdgeHandler.prototype.getCellAt = function(x, y)
- {
- return (!this.outlineConnect) ? this.graph.getCellAt(x, y) : null;
- };
- /**
- * Function: createMarker
- *
- * Creates and returns the <mxCellMarker> used in <marker>.
- */
- mxEdgeHandler.prototype.createMarker = function()
- {
- var marker = new mxCellMarker(this.graph);
- var self = this; // closure
- // Only returns edges if they are connectable and never returns
- // the edge that is currently being modified
- marker.getCell = function(me)
- {
- var cell = mxCellMarker.prototype.getCell.apply(this, arguments);
- // Checks for cell at preview point (with grid)
- if ((cell == self.state.cell || cell == null) && self.currentPoint != null)
- {
- cell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
- }
-
- // Uses connectable parent vertex if one exists
- if (cell != null && !this.graph.isCellConnectable(cell))
- {
- var parent = this.graph.getModel().getParent(cell);
-
- if (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
- {
- cell = parent;
- }
- }
-
- var model = self.graph.getModel();
-
- if ((this.graph.isSwimlane(cell) && self.currentPoint != null &&
- this.graph.hitsSwimlaneContent(cell, self.currentPoint.x, self.currentPoint.y)) ||
- (!self.isConnectableCell(cell)) || (cell == self.state.cell ||
- (cell != null && !self.graph.connectableEdges && model.isEdge(cell))) ||
- model.isAncestor(self.state.cell, cell))
- {
- cell = null;
- }
-
- if (!this.graph.isCellConnectable(cell))
- {
- cell = null;
- }
-
- return cell;
- };
- // Sets the highlight color according to validateConnection
- marker.isValidState = function(state)
- {
- var model = self.graph.getModel();
- var other = self.graph.view.getTerminalPort(state,
- self.graph.view.getState(model.getTerminal(self.state.cell,
- !self.isSource)), !self.isSource);
- var otherCell = (other != null) ? other.cell : null;
- var source = (self.isSource) ? state.cell : otherCell;
- var target = (self.isSource) ? otherCell : state.cell;
-
- // Updates the error message of the handler
- self.error = self.validateConnection(source, target);
- return self.error == null;
- };
-
- return marker;
- };
- /**
- * Function: validateConnection
- *
- * Returns the error message or an empty string if the connection for the
- * given source, target pair is not valid. Otherwise it returns null. This
- * implementation uses <mxGraph.getEdgeValidationError>.
- *
- * Parameters:
- *
- * source - <mxCell> that represents the source terminal.
- * target - <mxCell> that represents the target terminal.
- */
- mxEdgeHandler.prototype.validateConnection = function(source, target)
- {
- return this.graph.getEdgeValidationError(this.state.cell, source, target);
- };
- /**
- * Function: createBends
- *
- * Creates and returns the bends used for modifying the edge. This is
- * typically an array of <mxRectangleShapes>.
- */
- mxEdgeHandler.prototype.createBends = function()
- {
- var cell = this.state.cell;
- var bends = [];
- for (var i = 0; i < this.abspoints.length; i++)
- {
- if (this.isHandleVisible(i))
- {
- var source = i == 0;
- var target = i == this.abspoints.length - 1;
- var terminal = source || target;
- if (terminal || this.graph.isCellBendable(cell))
- {
- (mxUtils.bind(this, function(index)
- {
- var bend = this.createHandleShape(index);
- this.initBend(bend, mxUtils.bind(this, mxUtils.bind(this, function()
- {
- if (this.dblClickRemoveEnabled)
- {
- this.removePoint(this.state, index);
- }
- })));
-
- if (this.isHandleEnabled(i))
- {
- bend.setCursor((terminal) ? mxConstants.CURSOR_TERMINAL_HANDLE : mxConstants.CURSOR_BEND_HANDLE);
- }
-
- bends.push(bend);
-
- if (!terminal)
- {
- this.points.push(new mxPoint(0,0));
- bend.node.style.visibility = 'hidden';
- }
- }))(i);
- }
- }
- }
- return bends;
- };
- /**
- * Function: createVirtualBends
- *
- * Creates and returns the bends used for modifying the edge. This is
- * typically an array of <mxRectangleShapes>.
- */
- mxEdgeHandler.prototype.createVirtualBends = function()
- {
- var cell = this.state.cell;
- var last = this.abspoints[0];
- var bends = [];
- if (this.graph.isCellBendable(cell))
- {
- for (var i = 1; i < this.abspoints.length; i++)
- {
- (mxUtils.bind(this, function(bend)
- {
- this.initBend(bend);
- bend.setCursor(mxConstants.CURSOR_VIRTUAL_BEND_HANDLE);
- bends.push(bend);
- }))(this.createHandleShape());
- }
- }
- return bends;
- };
- /**
- * Function: isHandleEnabled
- *
- * Creates the shape used to display the given bend.
- */
- mxEdgeHandler.prototype.isHandleEnabled = function(index)
- {
- return true;
- };
- /**
- * Function: isHandleVisible
- *
- * Returns true if the handle at the given index is visible.
- */
- mxEdgeHandler.prototype.isHandleVisible = function(index)
- {
- var source = this.state.getVisibleTerminalState(true);
- var target = this.state.getVisibleTerminalState(false);
- var geo = this.graph.getCellGeometry(this.state.cell);
- var edgeStyle = (geo != null) ? this.graph.view.getEdgeStyle(this.state, geo.points, source, target) : null;
- return edgeStyle != mxEdgeStyle.EntityRelation || index == 0 || index == this.abspoints.length - 1;
- };
- /**
- * Function: createHandleShape
- *
- * Creates the shape used to display the given bend. Note that the index may be
- * null for special cases, such as when called from
- * <mxElbowEdgeHandler.createVirtualBend>. Only images and rectangles should be
- * returned if support for HTML labels with not foreign objects is required.
- * Index if null for virtual handles.
- */
- mxEdgeHandler.prototype.createHandleShape = function(index)
- {
- if (this.handleImage != null)
- {
- var shape = new mxImageShape(new mxRectangle(0, 0, this.handleImage.width, this.handleImage.height), this.handleImage.src);
-
- // Allows HTML rendering of the images
- shape.preserveImageAspect = false;
- return shape;
- }
- else
- {
- var s = mxConstants.HANDLE_SIZE;
-
- if (this.preferHtml)
- {
- s -= 1;
- }
-
- return new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
- }
- };
- /**
- * Function: createLabelHandleShape
- *
- * Creates the shape used to display the the label handle.
- */
- mxEdgeHandler.prototype.createLabelHandleShape = function()
- {
- if (this.labelHandleImage != null)
- {
- var shape = new mxImageShape(new mxRectangle(0, 0, this.labelHandleImage.width, this.labelHandleImage.height), this.labelHandleImage.src);
-
- // Allows HTML rendering of the images
- shape.preserveImageAspect = false;
- return shape;
- }
- else
- {
- var s = mxConstants.LABEL_HANDLE_SIZE;
- return new mxRectangleShape(new mxRectangle(0, 0, s, s), mxConstants.LABEL_HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
- }
- };
- /**
- * Function: initBend
- *
- * Helper method to initialize the given bend.
- *
- * Parameters:
- *
- * bend - <mxShape> that represents the bend to be initialized.
- */
- mxEdgeHandler.prototype.initBend = function(bend, dblClick)
- {
- if (this.preferHtml)
- {
- bend.dialect = mxConstants.DIALECT_STRICTHTML;
- bend.init(this.graph.container);
- }
- else
- {
- bend.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
- mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
- bend.init(this.graph.getView().getOverlayPane());
- }
- mxEvent.redirectMouseEvents(bend.node, this.graph, this.state,
- null, null, null, dblClick);
-
- // Fixes lost event tracking for images in quirks / IE8 standards
- if (mxClient.IS_QUIRKS || document.documentMode == 8)
- {
- mxEvent.addListener(bend.node, 'dragstart', function(evt)
- {
- mxEvent.consume(evt);
-
- return false;
- });
- }
-
- if (mxClient.IS_TOUCH)
- {
- bend.node.setAttribute('pointer-events', 'none');
- }
- };
- /**
- * Function: getHandleForEvent
- *
- * Returns the index of the handle for the given event.
- */
- mxEdgeHandler.prototype.getHandleForEvent = function(me)
- {
- var result = null;
-
- if (this.state != null)
- {
- // Connection highlight may consume events before they reach sizer handle
- var tol = (!mxEvent.isMouseEvent(me.getEvent())) ? this.tolerance : 1;
- var hit = (this.allowHandleBoundsCheck && (mxClient.IS_IE || tol > 0)) ?
- new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol) : null;
- var minDistSq = null;
-
- function checkShape(shape)
- {
- if (shape != null && shape.node != null && shape.node.style.display != 'none' &&
- shape.node.style.visibility != 'hidden' &&
- (me.isSource(shape) || (hit != null && mxUtils.intersects(shape.bounds, hit))))
- {
- var dx = me.getGraphX() - shape.bounds.getCenterX();
- var dy = me.getGraphY() - shape.bounds.getCenterY();
- var tmp = dx * dx + dy * dy;
-
- if (minDistSq == null || tmp <= minDistSq)
- {
- minDistSq = tmp;
-
- return true;
- }
- }
-
- return false;
- }
-
- if (this.customHandles != null && this.isCustomHandleEvent(me))
- {
- // Inverse loop order to match display order
- for (var i = this.customHandles.length - 1; i >= 0; i--)
- {
- if (checkShape(this.customHandles[i].shape))
- {
- // LATER: Return reference to active shape
- return mxEvent.CUSTOM_HANDLE - i;
- }
- }
- }
-
- if (me.isSource(this.state.text) || checkShape(this.labelShape))
- {
- result = mxEvent.LABEL_HANDLE;
- }
-
- if (this.bends != null)
- {
- for (var i = 0; i < this.bends.length; i++)
- {
- if (checkShape(this.bends[i]))
- {
- result = i;
- }
- }
- }
-
- if (this.virtualBends != null && this.isAddVirtualBendEvent(me))
- {
- for (var i = 0; i < this.virtualBends.length; i++)
- {
- if (checkShape(this.virtualBends[i]))
- {
- result = mxEvent.VIRTUAL_HANDLE - i;
- }
- }
- }
- }
- return result;
- };
- /**
- * Function: isAddVirtualBendEvent
- *
- * Returns true if the given event allows virtual bends to be added. This
- * implementation returns true.
- */
- mxEdgeHandler.prototype.isAddVirtualBendEvent = function(me)
- {
- return true;
- };
- /**
- * Function: isCustomHandleEvent
- *
- * Returns true if the given event allows custom handles to be changed. This
- * implementation returns true.
- */
- mxEdgeHandler.prototype.isCustomHandleEvent = function(me)
- {
- return true;
- };
- /**
- * Function: mouseDown
- *
- * Handles the event by checking if a special element of the handler
- * was clicked, in which case the index parameter is non-null. The
- * indices may be one of <LABEL_HANDLE> or the number of the respective
- * control point. The source and target points are used for reconnecting
- * the edge.
- */
- mxEdgeHandler.prototype.mouseDown = function(sender, me)
- {
- var handle = this.getHandleForEvent(me);
-
- if (this.bends != null && this.bends[handle] != null)
- {
- var b = this.bends[handle].bounds;
- this.snapPoint = new mxPoint(b.getCenterX(), b.getCenterY());
- }
-
- if (this.addEnabled && handle == null && this.isAddPointEvent(me.getEvent()))
- {
- this.addPoint(this.state, me.getEvent());
- me.consume();
- }
- else if (handle != null && !me.isConsumed() && this.graph.isEnabled())
- {
- if (this.removeEnabled && this.isRemovePointEvent(me.getEvent()))
- {
- this.removePoint(this.state, handle);
- }
- else if (handle != mxEvent.LABEL_HANDLE || this.graph.isLabelMovable(me.getCell()))
- {
- if (handle <= mxEvent.VIRTUAL_HANDLE)
- {
- mxUtils.setOpacity(this.virtualBends[mxEvent.VIRTUAL_HANDLE - handle].node, 100);
- }
-
- this.start(me.getX(), me.getY(), handle);
- }
-
- me.consume();
- }
- };
- /**
- * Function: start
- *
- * Starts the handling of the mouse gesture.
- */
- mxEdgeHandler.prototype.start = function(x, y, index)
- {
- this.startX = x;
- this.startY = y;
- this.isSource = (this.bends == null) ? false : index == 0;
- this.isTarget = (this.bends == null) ? false : index == this.bends.length - 1;
- this.isLabel = index == mxEvent.LABEL_HANDLE;
- if (this.isSource || this.isTarget)
- {
- var cell = this.state.cell;
- var terminal = this.graph.model.getTerminal(cell, this.isSource);
- if ((terminal == null && this.graph.isTerminalPointMovable(cell, this.isSource)) ||
- (terminal != null && this.graph.isCellDisconnectable(cell, terminal, this.isSource)))
- {
- this.index = index;
- }
- }
- else
- {
- this.index = index;
- }
-
- // Hides other custom handles
- if (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
- {
- if (this.customHandles != null)
- {
- for (var i = 0; i < this.customHandles.length; i++)
- {
- if (i != mxEvent.CUSTOM_HANDLE - this.index)
- {
- this.customHandles[i].setVisible(false);
- }
- }
- }
- }
- };
- /**
- * Function: clonePreviewState
- *
- * Returns a clone of the current preview state for the given point and terminal.
- */
- mxEdgeHandler.prototype.clonePreviewState = function(point, terminal)
- {
- return this.state.clone();
- };
- /**
- * Function: getSnapToTerminalTolerance
- *
- * Returns the tolerance for the guides. Default value is
- * gridSize * scale / 2.
- */
- mxEdgeHandler.prototype.getSnapToTerminalTolerance = function()
- {
- return this.graph.gridSize * this.graph.view.scale / 2;
- };
- /**
- * Function: updateHint
- *
- * Hook for subclassers do show details while the handler is active.
- */
- mxEdgeHandler.prototype.updateHint = function(me, point) { };
- /**
- * Function: removeHint
- *
- * Hooks for subclassers to hide details when the handler gets inactive.
- */
- mxEdgeHandler.prototype.removeHint = function() { };
- /**
- * Function: roundLength
- *
- * Hook for rounding the unscaled width or height. This uses Math.round.
- */
- mxEdgeHandler.prototype.roundLength = function(length)
- {
- return Math.round(length);
- };
- /**
- * Function: isSnapToTerminalsEvent
- *
- * Returns true if <snapToTerminals> is true and if alt is not pressed.
- */
- mxEdgeHandler.prototype.isSnapToTerminalsEvent = function(me)
- {
- return this.snapToTerminals && !mxEvent.isAltDown(me.getEvent());
- };
- /**
- * Function: getPointForEvent
- *
- * Returns the point for the given event.
- */
- mxEdgeHandler.prototype.getPointForEvent = function(me)
- {
- var view = this.graph.getView();
- var scale = view.scale;
- var point = new mxPoint(this.roundLength(me.getGraphX() / scale) * scale,
- this.roundLength(me.getGraphY() / scale) * scale);
-
- var tt = this.getSnapToTerminalTolerance();
- var overrideX = false;
- var overrideY = false;
-
- if (tt > 0 && this.isSnapToTerminalsEvent(me))
- {
- function snapToPoint(pt)
- {
- if (pt != null)
- {
- var x = pt.x;
- if (Math.abs(point.x - x) < tt)
- {
- point.x = x;
- overrideX = true;
- }
-
- var y = pt.y;
- if (Math.abs(point.y - y) < tt)
- {
- point.y = y;
- overrideY = true;
- }
- }
- }
-
- // Temporary function
- function snapToTerminal(terminal)
- {
- if (terminal != null)
- {
- snapToPoint.call(this, new mxPoint(view.getRoutingCenterX(terminal),
- view.getRoutingCenterY(terminal)));
- }
- };
- snapToTerminal.call(this, this.state.getVisibleTerminalState(true));
- snapToTerminal.call(this, this.state.getVisibleTerminalState(false));
- if (this.state.absolutePoints != null)
- {
- for (var i = 0; i < this.state.absolutePoints.length; i++)
- {
- snapToPoint.call(this, this.state.absolutePoints[i]);
- }
- }
- }
- if (this.graph.isGridEnabledEvent(me.getEvent()))
- {
- var tr = view.translate;
-
- if (!overrideX)
- {
- point.x = (this.graph.snap(point.x / scale - tr.x) + tr.x) * scale;
- }
-
- if (!overrideY)
- {
- point.y = (this.graph.snap(point.y / scale - tr.y) + tr.y) * scale;
- }
- }
-
- return point;
- };
- /**
- * Function: getPreviewTerminalState
- *
- * Updates the given preview state taking into account the state of the constraint handler.
- */
- mxEdgeHandler.prototype.getPreviewTerminalState = function(me)
- {
- this.constraintHandler.update(me, this.isSource, true, me.isSource(this.marker.highlight.shape) ? null : this.currentPoint);
-
- if (this.constraintHandler.currentFocus != null && this.constraintHandler.currentConstraint != null)
- {
- // Handles special case where grid is large and connection point is at actual point in which
- // case the outline is not followed as long as we're < gridSize / 2 away from that point
- if (this.marker.highlight != null && this.marker.highlight.state != null &&
- this.marker.highlight.state.cell == this.constraintHandler.currentFocus.cell)
- {
- // Direct repaint needed if cell already highlighted
- if (this.marker.highlight.shape.stroke != 'transparent')
- {
- this.marker.highlight.shape.stroke = 'transparent';
- this.marker.highlight.repaint();
- }
- }
- else
- {
- this.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
- }
-
- var model = this.graph.getModel();
- var other = this.graph.view.getTerminalPort(this.state,
- this.graph.view.getState(model.getTerminal(this.state.cell,
- !this.isSource)), !this.isSource);
- var otherCell = (other != null) ? other.cell : null;
- var source = (this.isSource) ? this.constraintHandler.currentFocus.cell : otherCell;
- var target = (this.isSource) ? otherCell : this.constraintHandler.currentFocus.cell;
-
- // Updates the error message of the handler
- this.error = this.validateConnection(source, target);
- var result = null;
-
- if (this.error == null)
- {
- result = this.constraintHandler.currentFocus;
- }
-
- if (this.error != null || (result != null &&
- !this.isCellEnabled(result.cell)))
- {
- this.constraintHandler.reset();
- }
-
- return result;
- }
- else if (!this.graph.isIgnoreTerminalEvent(me.getEvent()))
- {
- this.marker.process(me);
- var state = this.marker.getValidState();
-
- if (state != null && !this.isCellEnabled(state.cell))
- {
- this.constraintHandler.reset();
- this.marker.reset();
- }
-
- return this.marker.getValidState();
- }
- else
- {
- this.marker.reset();
-
- return null;
- }
- };
- /**
- * Function: getPreviewPoints
- *
- * Updates the given preview state taking into account the state of the constraint handler.
- *
- * Parameters:
- *
- * pt - <mxPoint> that contains the current pointer position.
- * me - Optional <mxMouseEvent> that contains the current event.
- */
- mxEdgeHandler.prototype.getPreviewPoints = function(pt, me)
- {
- var geometry = this.graph.getCellGeometry(this.state.cell);
- var points = (geometry.points != null) ? geometry.points.slice() : null;
- var point = new mxPoint(pt.x, pt.y);
- var result = null;
-
- if (!this.isSource && !this.isTarget)
- {
- this.convertPoint(point, false);
-
- if (points == null)
- {
- points = [point];
- }
- else
- {
- // Adds point from virtual bend
- if (this.index <= mxEvent.VIRTUAL_HANDLE)
- {
- points.splice(mxEvent.VIRTUAL_HANDLE - this.index, 0, point);
- }
- // Removes point if dragged on terminal point
- if (!this.isSource && !this.isTarget)
- {
- for (var i = 0; i < this.bends.length; i++)
- {
- if (i != this.index)
- {
- var bend = this.bends[i];
-
- if (bend != null && mxUtils.contains(bend.bounds, pt.x, pt.y))
- {
- if (this.index <= mxEvent.VIRTUAL_HANDLE)
- {
- points.splice(mxEvent.VIRTUAL_HANDLE - this.index, 1);
- }
- else
- {
- points.splice(this.index - 1, 1);
- }
-
- result = points;
- }
- }
- }
-
- // Removes point if user tries to straighten a segment
- if (result == null && this.straightRemoveEnabled && (me == null || !mxEvent.isAltDown(me.getEvent())))
- {
- var tol = this.graph.tolerance * this.graph.tolerance;
- var abs = this.state.absolutePoints.slice();
- abs[this.index] = pt;
-
- // Handes special case where removing waypoint affects tolerance (flickering)
- var src = this.state.getVisibleTerminalState(true);
-
- if (src != null)
- {
- var c = this.graph.getConnectionConstraint(this.state, src, true);
-
- // Checks if point is not fixed
- if (c == null || this.graph.getConnectionPoint(src, c) == null)
- {
- abs[0] = new mxPoint(src.view.getRoutingCenterX(src), src.view.getRoutingCenterY(src));
- }
- }
-
- var trg = this.state.getVisibleTerminalState(false);
-
- if (trg != null)
- {
- var c = this.graph.getConnectionConstraint(this.state, trg, false);
-
- // Checks if point is not fixed
- if (c == null || this.graph.getConnectionPoint(trg, c) == null)
- {
- abs[abs.length - 1] = new mxPoint(trg.view.getRoutingCenterX(trg), trg.view.getRoutingCenterY(trg));
- }
- }
- function checkRemove(idx, tmp)
- {
- if (idx > 0 && idx < abs.length - 1 &&
- mxUtils.ptSegDistSq(abs[idx - 1].x, abs[idx - 1].y,
- abs[idx + 1].x, abs[idx + 1].y, tmp.x, tmp.y) < tol)
- {
- points.splice(idx - 1, 1);
- result = points;
- }
- };
-
- // LATER: Check if other points can be removed if a segment is made straight
- checkRemove(this.index, pt);
- }
- }
-
- // Updates existing point
- if (result == null && this.index > mxEvent.VIRTUAL_HANDLE)
- {
- points[this.index - 1] = point;
- }
- }
- }
- else if (this.graph.resetEdgesOnConnect)
- {
- points = null;
- }
-
- return (result != null) ? result : points;
- };
- /**
- * Function: isOutlineConnectEvent
- *
- * Returns true if <outlineConnect> is true and the source of the event is the outline shape
- * or shift is pressed.
- */
- mxEdgeHandler.prototype.isOutlineConnectEvent = function(me)
- {
- var offset = mxUtils.getOffset(this.graph.container);
- var evt = me.getEvent();
-
- var clientX = mxEvent.getClientX(evt);
- var clientY = mxEvent.getClientY(evt);
-
- var doc = document.documentElement;
- var left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
- var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
-
- var gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
- var gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
- return this.outlineConnect && !mxEvent.isShiftDown(me.getEvent()) &&
- (me.isSource(this.marker.highlight.shape) ||
- (mxEvent.isAltDown(me.getEvent()) && me.getState() != null) ||
- this.marker.highlight.isHighlightAt(clientX, clientY) ||
- ((gridX != clientX || gridY != clientY) && me.getState() == null &&
- this.marker.highlight.isHighlightAt(gridX, gridY)));
- };
- /**
- * Function: updatePreviewState
- *
- * Updates the given preview state taking into account the state of the constraint handler.
- */
- mxEdgeHandler.prototype.updatePreviewState = function(edge, point, terminalState, me, outline)
- {
- // Computes the points for the edge style and terminals
- var sourceState = (this.isSource) ? terminalState : this.state.getVisibleTerminalState(true);
- var targetState = (this.isTarget) ? terminalState : this.state.getVisibleTerminalState(false);
-
- var sourceConstraint = this.graph.getConnectionConstraint(edge, sourceState, true);
- var targetConstraint = this.graph.getConnectionConstraint(edge, targetState, false);
- var constraint = this.constraintHandler.currentConstraint;
- if (constraint == null && outline)
- {
- if (terminalState != null)
- {
- // Handles special case where mouse is on outline away from actual end point
- // in which case the grid is ignored and mouse point is used instead
- if (me.isSource(this.marker.highlight.shape))
- {
- point = new mxPoint(me.getGraphX(), me.getGraphY());
- }
-
- constraint = this.graph.getOutlineConstraint(point, terminalState, me);
- this.constraintHandler.setFocus(me, terminalState, this.isSource);
- this.constraintHandler.currentConstraint = constraint;
- this.constraintHandler.currentPoint = point;
- }
- else
- {
- constraint = new mxConnectionConstraint();
- }
- }
-
- if (this.outlineConnect && this.marker.highlight != null && this.marker.highlight.shape != null)
- {
- var s = this.graph.view.scale;
-
- if (this.constraintHandler.currentConstraint != null &&
- this.constraintHandler.currentFocus != null)
- {
- this.marker.highlight.shape.stroke = (outline) ? mxConstants.OUTLINE_HIGHLIGHT_COLOR : 'transparent';
- this.marker.highlight.shape.strokewidth = mxConstants.OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
- this.marker.highlight.repaint();
- }
- else if (this.marker.hasValidState())
- {
- this.marker.highlight.shape.stroke = (this.graph.isCellConnectable(me.getCell()) &&
- this.marker.getValidState() != me.getState()) ?
- 'transparent' : mxConstants.DEFAULT_VALID_COLOR;
- this.marker.highlight.shape.strokewidth = mxConstants.HIGHLIGHT_STROKEWIDTH / s / s;
- this.marker.highlight.repaint();
- }
- }
-
- if (this.isSource)
- {
- sourceConstraint = constraint;
- }
- else if (this.isTarget)
- {
- targetConstraint = constraint;
- }
-
- if (this.isSource || this.isTarget)
- {
- if (constraint != null && constraint.point != null)
- {
- edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X] = constraint.point.x;
- edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y] = constraint.point.y;
- }
- else
- {
- delete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_X : mxConstants.STYLE_ENTRY_X];
- delete edge.style[(this.isSource) ? mxConstants.STYLE_EXIT_Y : mxConstants.STYLE_ENTRY_Y];
- }
- }
-
- edge.setVisibleTerminalState(sourceState, true);
- edge.setVisibleTerminalState(targetState, false);
-
- if (!this.isSource || sourceState != null)
- {
- edge.view.updateFixedTerminalPoint(edge, sourceState, true, sourceConstraint);
- }
-
- if (!this.isTarget || targetState != null)
- {
- edge.view.updateFixedTerminalPoint(edge, targetState, false, targetConstraint);
- }
-
- if ((this.isSource || this.isTarget) && terminalState == null)
- {
- edge.setAbsoluteTerminalPoint(point, this.isSource);
- if (this.marker.getMarkedState() == null)
- {
- this.error = (this.graph.allowDanglingEdges) ? null : '';
- }
- }
-
- edge.view.updatePoints(edge, this.points, sourceState, targetState);
- edge.view.updateFloatingTerminalPoints(edge, sourceState, targetState);
- };
- /**
- * Function: mouseMove
- *
- * Handles the event by updating the preview.
- */
- mxEdgeHandler.prototype.mouseMove = function(sender, me)
- {
- if (this.index != null && this.marker != null)
- {
- this.currentPoint = this.getPointForEvent(me);
- this.error = null;
-
- // Uses the current point from the constraint handler if available
- if (!this.graph.isIgnoreTerminalEvent(me.getEvent()) && mxEvent.isShiftDown(me.getEvent()) && this.snapPoint != null)
- {
- if (Math.abs(this.snapPoint.x - this.currentPoint.x) < Math.abs(this.snapPoint.y - this.currentPoint.y))
- {
- this.currentPoint.x = this.snapPoint.x;
- }
- else
- {
- this.currentPoint.y = this.snapPoint.y;
- }
- }
-
- if (this.index <= mxEvent.CUSTOM_HANDLE && this.index > mxEvent.VIRTUAL_HANDLE)
- {
- if (this.customHandles != null)
- {
- this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].processEvent(me);
- this.customHandles[mxEvent.CUSTOM_HANDLE - this.index].positionChanged();
-
- if (this.shape != null && this.shape.node != null)
- {
- this.shape.node.style.display = 'none';
- }
- }
- }
- else if (this.isLabel)
- {
- this.label.x = this.currentPoint.x;
- this.label.y = this.currentPoint.y;
- }
- else
- {
- this.points = this.getPreviewPoints(this.currentPoint, me);
- var terminalState = (this.isSource || this.isTarget) ? this.getPreviewTerminalState(me) : null;
-
- if (this.constraintHandler.currentConstraint != null &&
- this.constraintHandler.currentFocus != null &&
- this.constraintHandler.currentPoint != null)
- {
- this.currentPoint = this.constraintHandler.currentPoint.clone();
- }
- else if (this.outlineConnect)
- {
- // Need to check outline before cloning terminal state
- var outline = (this.isSource || this.isTarget) ? this.isOutlineConnectEvent(me) : false
-
- if (outline)
- {
- terminalState = this.marker.highlight.state;
- }
- else if (terminalState != null && terminalState != me.getState() &&
- this.graph.isCellConnectable(me.getCell()) &&
- this.marker.highlight.shape != null)
- {
- this.marker.highlight.shape.stroke = 'transparent';
- this.marker.highlight.repaint();
- terminalState = null;
- }
- }
-
- if (terminalState != null && !this.isCellEnabled(terminalState.cell))
- {
- terminalState = null;
- this.marker.reset();
- }
-
- var clone = this.clonePreviewState(this.currentPoint, (terminalState != null) ? terminalState.cell : null);
- this.updatePreviewState(clone, this.currentPoint, terminalState, me, outline);
- // Sets the color of the preview to valid or invalid, updates the
- // points of the preview and redraws
- var color = (this.error == null) ? this.marker.validColor : this.marker.invalidColor;
- this.setPreviewColor(color);
- this.abspoints = clone.absolutePoints;
- this.active = true;
- this.updateHint(me, this.currentPoint);
- }
- // This should go before calling isOutlineConnectEvent above. As a workaround
- // we add an offset of gridSize to the hint to avoid problem with hit detection
- // in highlight.isHighlightAt (which uses comonentFromPoint)
- this.drawPreview();
- mxEvent.consume(me.getEvent());
- me.consume();
- }
- // Workaround for disabling the connect highlight when over handle
- else if (mxClient.IS_IE && this.getHandleForEvent(me) != null)
- {
- me.consume(false);
- }
- };
- /**
- * Function: mouseUp
- *
- * Handles the event to applying the previewed changes on the edge by
- * using <moveLabel>, <connect> or <changePoints>.
- */
- mxEdgeHandler.prototype.mouseUp = function(sender, me)
- {
- // Workaround for wrong event source in Webkit
- if (this.index != null && this.marker != null)
- {
- if (this.shape != null && this.shape.node != null)
- {
- this.shape.node.style.display = '';
- }
-
- var edge = this.state.cell;
- var index = this.index;
- this.index = null;
- // Ignores event if mouse has not been moved
- if (me.getX() != this.startX || me.getY() != this.startY)
- {
- var clone = !this.graph.isIgnoreTerminalEvent(me.getEvent()) && this.graph.isCloneEvent(me.getEvent()) &&
- this.cloneEnabled && this.graph.isCellsCloneable();
-
- // Displays the reason for not carriying out the change
- // if there is an error message with non-zero length
- if (this.error != null)
- {
- if (this.error.length > 0)
- {
- this.graph.validationAlert(this.error);
- }
- }
- else if (index <= mxEvent.CUSTOM_HANDLE && index > mxEvent.VIRTUAL_HANDLE)
- {
- if (this.customHandles != null)
- {
- var model = this.graph.getModel();
-
- model.beginUpdate();
- try
- {
- this.customHandles[mxEvent.CUSTOM_HANDLE - index].execute(me);
-
- if (this.shape != null && this.shape.node != null)
- {
- this.shape.apply(this.state);
- this.shape.redraw();
- }
- }
- finally
- {
- model.endUpdate();
- }
- }
- }
- else if (this.isLabel)
- {
- this.moveLabel(this.state, this.label.x, this.label.y);
- }
- else if (this.isSource || this.isTarget)
- {
- var terminal = null;
-
- if (this.constraintHandler.currentConstraint != null &&
- this.constraintHandler.currentFocus != null)
- {
- terminal = this.constraintHandler.currentFocus.cell;
- }
-
- if (terminal == null && this.marker.hasValidState() && this.marker.highlight != null &&
- this.marker.highlight.shape != null &&
- this.marker.highlight.shape.stroke != 'transparent' &&
- this.marker.highlight.shape.stroke != 'white')
- {
- terminal = this.marker.validState.cell;
- }
-
- if (terminal != null)
- {
- var model = this.graph.getModel();
- var parent = model.getParent(edge);
-
- model.beginUpdate();
- try
- {
- // Clones and adds the cell
- if (clone)
- {
- var geo = model.getGeometry(edge);
- var clone = this.graph.cloneCell(edge);
- model.add(parent, clone, model.getChildCount(parent));
-
- if (geo != null)
- {
- geo = geo.clone();
- model.setGeometry(clone, geo);
- }
-
- var other = model.getTerminal(edge, !this.isSource);
- this.graph.connectCell(clone, other, !this.isSource);
-
- edge = clone;
- }
-
- edge = this.connect(edge, terminal, this.isSource, clone, me);
- }
- finally
- {
- model.endUpdate();
- }
- }
- else if (this.graph.isAllowDanglingEdges())
- {
- var pt = this.abspoints[(this.isSource) ? 0 : this.abspoints.length - 1];
- pt.x = this.roundLength(pt.x / this.graph.view.scale - this.graph.view.translate.x);
- pt.y = this.roundLength(pt.y / this.graph.view.scale - this.graph.view.translate.y);
- var pstate = this.graph.getView().getState(
- this.graph.getModel().getParent(edge));
-
- if (pstate != null)
- {
- pt.x -= pstate.origin.x;
- pt.y -= pstate.origin.y;
- }
-
- pt.x -= this.graph.panDx / this.graph.view.scale;
- pt.y -= this.graph.panDy / this.graph.view.scale;
-
- // Destroys and recreates this handler
- edge = this.changeTerminalPoint(edge, pt, this.isSource, clone);
- }
- }
- else if (this.active)
- {
- edge = this.changePoints(edge, this.points, clone);
- }
- else
- {
- this.graph.getView().invalidate(this.state.cell);
- this.graph.getView().validate(this.state.cell);
- }
- }
- else if (this.graph.isToggleEvent(me.getEvent()))
- {
- this.graph.selectCellForEvent(this.state.cell, me.getEvent());
- }
- // Resets the preview color the state of the handler if this
- // handler has not been recreated
- if (this.marker != null)
- {
- this.reset();
- // Updates the selection if the edge has been cloned
- if (edge != this.state.cell)
- {
- this.graph.setSelectionCell(edge);
- }
- }
- me.consume();
- }
- };
- /**
- * Function: reset
- *
- * Resets the state of this handler.
- */
- mxEdgeHandler.prototype.reset = function()
- {
- if (this.active)
- {
- this.refresh();
- }
-
- this.error = null;
- this.index = null;
- this.label = null;
- this.points = null;
- this.snapPoint = null;
- this.isLabel = false;
- this.isSource = false;
- this.isTarget = false;
- this.active = false;
-
- if (this.livePreview && this.sizers != null)
- {
- for (var i = 0; i < this.sizers.length; i++)
- {
- if (this.sizers[i] != null)
- {
- this.sizers[i].node.style.display = '';
- }
- }
- }
- if (this.marker != null)
- {
- this.marker.reset();
- }
-
- if (this.constraintHandler != null)
- {
- this.constraintHandler.reset();
- }
-
- if (this.customHandles != null)
- {
- for (var i = 0; i < this.customHandles.length; i++)
- {
- this.customHandles[i].reset();
- }
- }
- this.setPreviewColor(mxConstants.EDGE_SELECTION_COLOR);
- this.removeHint();
- this.redraw();
- };
- /**
- * Function: setPreviewColor
- *
- * Sets the color of the preview to the given value.
- */
- mxEdgeHandler.prototype.setPreviewColor = function(color)
- {
- if (this.shape != null)
- {
- this.shape.stroke = color;
- }
- };
- /**
- * Function: convertPoint
- *
- * Converts the given point in-place from screen to unscaled, untranslated
- * graph coordinates and applies the grid. Returns the given, modified
- * point instance.
- *
- * Parameters:
- *
- * point - <mxPoint> to be converted.
- * gridEnabled - Boolean that specifies if the grid should be applied.
- */
- mxEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
- {
- var scale = this.graph.getView().getScale();
- var tr = this.graph.getView().getTranslate();
-
- if (gridEnabled)
- {
- point.x = this.graph.snap(point.x);
- point.y = this.graph.snap(point.y);
- }
-
- point.x = Math.round(point.x / scale - tr.x);
- point.y = Math.round(point.y / scale - tr.y);
- var pstate = this.graph.getView().getState(
- this.graph.getModel().getParent(this.state.cell));
- if (pstate != null)
- {
- point.x -= pstate.origin.x;
- point.y -= pstate.origin.y;
- }
- return point;
- };
- /**
- * Function: moveLabel
- *
- * Changes the coordinates for the label of the given edge.
- *
- * Parameters:
- *
- * edge - <mxCell> that represents the edge.
- * x - Integer that specifies the x-coordinate of the new location.
- * y - Integer that specifies the y-coordinate of the new location.
- */
- mxEdgeHandler.prototype.moveLabel = function(edgeState, x, y)
- {
- var model = this.graph.getModel();
- var geometry = model.getGeometry(edgeState.cell);
-
- if (geometry != null)
- {
- var scale = this.graph.getView().scale;
- geometry = geometry.clone();
-
- if (geometry.relative)
- {
- // Resets the relative location stored inside the geometry
- var pt = this.graph.getView().getRelativePoint(edgeState, x, y);
- geometry.x = Math.round(pt.x * 10000) / 10000;
- geometry.y = Math.round(pt.y);
-
- // Resets the offset inside the geometry to find the offset
- // from the resulting point
- geometry.offset = new mxPoint(0, 0);
- var pt = this.graph.view.getPoint(edgeState, geometry);
- geometry.offset = new mxPoint(Math.round((x - pt.x) / scale), Math.round((y - pt.y) / scale));
- }
- else
- {
- var points = edgeState.absolutePoints;
- var p0 = points[0];
- var pe = points[points.length - 1];
-
- if (p0 != null && pe != null)
- {
- var cx = p0.x + (pe.x - p0.x) / 2;
- var cy = p0.y + (pe.y - p0.y) / 2;
-
- geometry.offset = new mxPoint(Math.round((x - cx) / scale), Math.round((y - cy) / scale));
- geometry.x = 0;
- geometry.y = 0;
- }
- }
- model.setGeometry(edgeState.cell, geometry);
- }
- };
- /**
- * Function: connect
- *
- * Changes the terminal or terminal point of the given edge in the graph
- * model.
- *
- * Parameters:
- *
- * edge - <mxCell> that represents the edge to be reconnected.
- * terminal - <mxCell> that represents the new terminal.
- * isSource - Boolean indicating if the new terminal is the source or
- * target terminal.
- * isClone - Boolean indicating if the new connection should be a clone of
- * the old edge.
- * me - <mxMouseEvent> that contains the mouse up event.
- */
- mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
- {
- var model = this.graph.getModel();
- var parent = model.getParent(edge);
-
- model.beginUpdate();
- try
- {
- var constraint = this.constraintHandler.currentConstraint;
-
- if (constraint == null)
- {
- constraint = new mxConnectionConstraint();
- }
- this.graph.connectCell(edge, terminal, isSource, constraint);
- }
- finally
- {
- model.endUpdate();
- }
-
- return edge;
- };
- /**
- * Function: changeTerminalPoint
- *
- * Changes the terminal point of the given edge.
- */
- mxEdgeHandler.prototype.changeTerminalPoint = function(edge, point, isSource, clone)
- {
- var model = this.graph.getModel();
- model.beginUpdate();
- try
- {
- if (clone)
- {
- var parent = model.getParent(edge);
- var terminal = model.getTerminal(edge, !isSource);
- edge = this.graph.cloneCell(edge);
- model.add(parent, edge, model.getChildCount(parent));
- model.setTerminal(edge, terminal, !isSource);
- }
- var geo = model.getGeometry(edge);
-
- if (geo != null)
- {
- geo = geo.clone();
- geo.setTerminalPoint(point, isSource);
- model.setGeometry(edge, geo);
- this.graph.connectCell(edge, null, isSource, new mxConnectionConstraint());
- }
- }
- finally
- {
- model.endUpdate();
- }
-
- return edge;
- };
- /**
- * Function: changePoints
- *
- * Changes the control points of the given edge in the graph model.
- */
- mxEdgeHandler.prototype.changePoints = function(edge, points, clone)
- {
- var model = this.graph.getModel();
- model.beginUpdate();
- try
- {
- if (clone)
- {
- var parent = model.getParent(edge);
- var source = model.getTerminal(edge, true);
- var target = model.getTerminal(edge, false);
- edge = this.graph.cloneCell(edge);
- model.add(parent, edge, model.getChildCount(parent));
- model.setTerminal(edge, source, true);
- model.setTerminal(edge, target, false);
- }
-
- var geo = model.getGeometry(edge);
-
- if (geo != null)
- {
- geo = geo.clone();
- geo.points = points;
-
- model.setGeometry(edge, geo);
- }
- }
- finally
- {
- model.endUpdate();
- }
-
- return edge;
- };
- /**
- * Function: addPoint
- *
- * Adds a control point for the given state and event.
- */
- mxEdgeHandler.prototype.addPoint = function(state, evt)
- {
- var pt = mxUtils.convertPoint(this.graph.container, mxEvent.getClientX(evt),
- mxEvent.getClientY(evt));
- var gridEnabled = this.graph.isGridEnabledEvent(evt);
- this.convertPoint(pt, gridEnabled);
- this.addPointAt(state, pt.x, pt.y);
- mxEvent.consume(evt);
- };
- /**
- * Function: addPointAt
- *
- * Adds a control point at the given point.
- */
- mxEdgeHandler.prototype.addPointAt = function(state, x, y)
- {
- var geo = this.graph.getCellGeometry(state.cell);
- var pt = new mxPoint(x, y);
-
- if (geo != null)
- {
- geo = geo.clone();
- var t = this.graph.view.translate;
- var s = this.graph.view.scale;
- var offset = new mxPoint(t.x * s, t.y * s);
-
- var parent = this.graph.model.getParent(this.state.cell);
-
- if (this.graph.model.isVertex(parent))
- {
- var pState = this.graph.view.getState(parent);
- offset = new mxPoint(pState.x, pState.y);
- }
-
- var index = mxUtils.findNearestSegment(state, pt.x * s + offset.x, pt.y * s + offset.y);
- if (geo.points == null)
- {
- geo.points = [pt];
- }
- else
- {
- geo.points.splice(index, 0, pt);
- }
-
- this.graph.getModel().setGeometry(state.cell, geo);
- this.refresh();
- this.redraw();
- }
- };
- /**
- * Function: removePoint
- *
- * Removes the control point at the given index from the given state.
- */
- mxEdgeHandler.prototype.removePoint = function(state, index)
- {
- if (index > 0 && index < this.abspoints.length - 1)
- {
- var geo = this.graph.getCellGeometry(this.state.cell);
-
- if (geo != null && geo.points != null)
- {
- geo = geo.clone();
- geo.points.splice(index - 1, 1);
- this.graph.getModel().setGeometry(state.cell, geo);
- this.refresh();
- this.redraw();
- }
- }
- };
- /**
- * Function: getHandleFillColor
- *
- * Returns the fillcolor for the handle at the given index.
- */
- mxEdgeHandler.prototype.getHandleFillColor = function(index)
- {
- var isSource = index == 0;
- var cell = this.state.cell;
- var terminal = this.graph.getModel().getTerminal(cell, isSource);
- var color = mxConstants.HANDLE_FILLCOLOR;
-
- if ((terminal != null && !this.graph.isCellDisconnectable(cell, terminal, isSource)) ||
- (terminal == null && !this.graph.isTerminalPointMovable(cell, isSource)))
- {
- color = mxConstants.LOCKED_HANDLE_FILLCOLOR;
- }
- else if (terminal != null && this.graph.isCellDisconnectable(cell, terminal, isSource))
- {
- color = mxConstants.CONNECT_HANDLE_FILLCOLOR;
- }
-
- return color;
- };
- /**
- * Function: redraw
- *
- * Redraws the preview, and the bends- and label control points.
- */
- mxEdgeHandler.prototype.redraw = function(ignoreHandles)
- {
- if (this.state != null)
- {
- this.abspoints = this.state.absolutePoints.slice();
- var g = this.graph.getModel().getGeometry(this.state.cell);
-
- if (g != null)
- {
- var pts = g.points;
-
- if (this.bends != null && this.bends.length > 0)
- {
- if (pts != null)
- {
- if (this.points == null)
- {
- this.points = [];
- }
-
- for (var i = 1; i < this.bends.length - 1; i++)
- {
- if (this.bends[i] != null && this.abspoints[i] != null)
- {
- this.points[i - 1] = pts[i - 1];
- }
- }
- }
- }
- }
-
- this.drawPreview();
-
- if (!ignoreHandles)
- {
- this.redrawHandles();
- }
- }
- };
- /**
- * Function: redrawHandles
- *
- * Redraws the handles.
- */
- mxEdgeHandler.prototype.redrawHandles = function()
- {
- var cell = this.state.cell;
- // Updates the handle for the label position
- var b = this.labelShape.bounds;
- this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
- this.labelShape.bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
- Math.round(this.label.y - b.height / 2), b.width, b.height);
- // Shows or hides the label handle depending on the label
- var lab = this.graph.getLabel(cell);
- this.labelShape.visible = (lab != null && lab.length > 0 && this.graph.isLabelMovable(cell));
-
- if (this.bends != null && this.bends.length > 0)
- {
- var n = this.abspoints.length - 1;
-
- var p0 = this.abspoints[0];
- var x0 = p0.x;
- var y0 = p0.y;
-
- b = this.bends[0].bounds;
- this.bends[0].bounds = new mxRectangle(Math.floor(x0 - b.width / 2),
- Math.floor(y0 - b.height / 2), b.width, b.height);
- this.bends[0].fill = this.getHandleFillColor(0);
- this.bends[0].redraw();
-
- if (this.manageLabelHandle)
- {
- this.checkLabelHandle(this.bends[0].bounds);
- }
-
- var pe = this.abspoints[n];
- var xn = pe.x;
- var yn = pe.y;
-
- var bn = this.bends.length - 1;
- b = this.bends[bn].bounds;
- this.bends[bn].bounds = new mxRectangle(Math.floor(xn - b.width / 2),
- Math.floor(yn - b.height / 2), b.width, b.height);
- this.bends[bn].fill = this.getHandleFillColor(bn);
- this.bends[bn].redraw();
-
- if (this.manageLabelHandle)
- {
- this.checkLabelHandle(this.bends[bn].bounds);
- }
-
- this.redrawInnerBends(p0, pe);
- }
- if (this.abspoints != null && this.virtualBends != null && this.virtualBends.length > 0)
- {
- var last = this.abspoints[0];
-
- for (var i = 0; i < this.virtualBends.length; i++)
- {
- if (this.virtualBends[i] != null && this.abspoints[i + 1] != null)
- {
- var pt = this.abspoints[i + 1];
- var b = this.virtualBends[i];
- var x = last.x + (pt.x - last.x) / 2;
- var y = last.y + (pt.y - last.y) / 2;
- b.bounds = new mxRectangle(Math.floor(x - b.bounds.width / 2),
- Math.floor(y - b.bounds.height / 2), b.bounds.width, b.bounds.height);
- b.redraw();
- mxUtils.setOpacity(b.node, this.virtualBendOpacity);
- last = pt;
-
- if (this.manageLabelHandle)
- {
- this.checkLabelHandle(b.bounds);
- }
- }
- }
- }
-
- if (this.labelShape != null)
- {
- this.labelShape.redraw();
- }
-
- if (this.customHandles != null)
- {
- for (var i = 0; i < this.customHandles.length; i++)
- {
- var temp = this.customHandles[i].shape.node.style.display;
- this.customHandles[i].redraw();
- this.customHandles[i].shape.node.style.display = temp;
- // Hides custom handles during text editing
- this.customHandles[i].shape.node.style.visibility =
- (this.isCustomHandleVisible(this.customHandles[i])) ?
- '' : 'hidden';
- }
- }
- };
- /**
- * Function: isCustomHandleVisible
- *
- * Returns true if the given custom handle is visible.
- */
- mxEdgeHandler.prototype.isCustomHandleVisible = function(handle)
- {
- return !this.graph.isEditing() && this.state.view.graph.getSelectionCount() == 1;
- };
- /**
- * Function: hideHandles
- *
- * Shortcut to <hideSizers>.
- */
- mxEdgeHandler.prototype.setHandlesVisible = function(visible)
- {
- if (this.bends != null)
- {
- for (var i = 0; i < this.bends.length; i++)
- {
- this.bends[i].node.style.display = (visible) ? '' : 'none';
- }
- }
-
- if (this.virtualBends != null)
- {
- for (var i = 0; i < this.virtualBends.length; i++)
- {
- this.virtualBends[i].node.style.display = (visible) ? '' : 'none';
- }
- }
- if (this.labelShape != null)
- {
- this.labelShape.node.style.display = (visible) ? '' : 'none';
- }
-
- if (this.customHandles != null)
- {
- for (var i = 0; i < this.customHandles.length; i++)
- {
- this.customHandles[i].setVisible(visible);
- }
- }
- };
- /**
- * Function: redrawInnerBends
- *
- * Updates and redraws the inner bends.
- *
- * Parameters:
- *
- * p0 - <mxPoint> that represents the location of the first point.
- * pe - <mxPoint> that represents the location of the last point.
- */
- mxEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
- {
- for (var i = 1; i < this.bends.length - 1; i++)
- {
- if (this.bends[i] != null)
- {
- if (this.abspoints[i] != null)
- {
- var x = this.abspoints[i].x;
- var y = this.abspoints[i].y;
-
- var b = this.bends[i].bounds;
- this.bends[i].node.style.visibility = 'visible';
- this.bends[i].bounds = new mxRectangle(Math.round(x - b.width / 2),
- Math.round(y - b.height / 2), b.width, b.height);
-
- if (this.manageLabelHandle)
- {
- this.checkLabelHandle(this.bends[i].bounds);
- }
- else if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(this.bends[i].bounds, this.labelShape.bounds))
- {
- w = mxConstants.HANDLE_SIZE + 3;
- h = mxConstants.HANDLE_SIZE + 3;
- this.bends[i].bounds = new mxRectangle(Math.round(x - w / 2), Math.round(y - h / 2), w, h);
- }
-
- this.bends[i].redraw();
- }
- else
- {
- this.bends[i].destroy();
- this.bends[i] = null;
- }
- }
- }
- };
- /**
- * Function: checkLabelHandle
- *
- * Checks if the label handle intersects the given bounds and moves it if it
- * intersects.
- */
- mxEdgeHandler.prototype.checkLabelHandle = function(b)
- {
- if (this.labelShape != null)
- {
- var b2 = this.labelShape.bounds;
-
- if (mxUtils.intersects(b, b2))
- {
- if (b.getCenterY() < b2.getCenterY())
- {
- b2.y = b.y + b.height;
- }
- else
- {
- b2.y = b.y - b2.height;
- }
- }
- }
- };
- /**
- * Function: drawPreview
- *
- * Redraws the preview.
- */
- mxEdgeHandler.prototype.drawPreview = function()
- {
- try
- {
- if (this.isLabel)
- {
- var b = this.labelShape.bounds;
- var bounds = new mxRectangle(Math.round(this.label.x - b.width / 2),
- Math.round(this.label.y - b.height / 2), b.width, b.height);
-
- if (!this.labelShape.bounds.equals(bounds))
- {
- this.labelShape.bounds = bounds;
- this.labelShape.redraw();
- }
- }
-
- if (this.shape != null && !mxUtils.equalPoints(this.shape.points, this.abspoints))
- {
- this.shape.apply(this.state);
- this.shape.points = this.abspoints.slice();
- this.shape.scale = this.state.view.scale;
- this.shape.isDashed = this.isSelectionDashed();
- this.shape.stroke = this.getSelectionColor();
- this.shape.strokewidth = this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale;
- this.shape.isShadow = false;
- this.shape.redraw();
- }
-
- this.updateParentHighlight();
- }
- catch (e)
- {
- // ignore
- }
- };
- /**
- * Function: refresh
- *
- * Refreshes the bends of this handler.
- */
- mxEdgeHandler.prototype.refresh = function()
- {
- if (this.state != null)
- {
- this.abspoints = this.getSelectionPoints(this.state);
- this.points = [];
-
- if (this.bends != null)
- {
- this.destroyBends(this.bends);
- this.bends = this.createBends();
- }
-
- if (this.virtualBends != null)
- {
- this.destroyBends(this.virtualBends);
- this.virtualBends = this.createVirtualBends();
- }
-
- if (this.customHandles != null)
- {
- this.destroyBends(this.customHandles);
- this.customHandles = this.createCustomHandles();
- }
-
- // Puts label node on top of bends
- if (this.labelShape != null && this.labelShape.node != null && this.labelShape.node.parentNode != null)
- {
- this.labelShape.node.parentNode.appendChild(this.labelShape.node);
- }
- }
- };
- /**
- * Function: isDestroyed
- *
- * Returns true if <destroy> was called.
- */
- mxEdgeHandler.prototype.isDestroyed = function()
- {
- return this.shape == null;
- };
- /**
- * Function: destroyBends
- *
- * Destroys all elements in <bends>.
- */
- mxEdgeHandler.prototype.destroyBends = function(bends)
- {
- if (bends != null)
- {
- for (var i = 0; i < bends.length; i++)
- {
- if (bends[i] != null)
- {
- bends[i].destroy();
- }
- }
- }
- };
- /**
- * Function: destroy
- *
- * Destroys the handler and all its resources and DOM nodes. This does
- * normally not need to be called as handlers are destroyed automatically
- * when the corresponding cell is deselected.
- */
- mxEdgeHandler.prototype.destroy = function()
- {
- if (this.escapeHandler != null)
- {
- this.state.view.graph.removeListener(this.escapeHandler);
- this.escapeHandler = null;
- }
-
- if (this.marker != null)
- {
- this.marker.destroy();
- this.marker = null;
- }
-
- if (this.shape != null)
- {
- this.shape.destroy();
- this.shape = null;
- }
-
- if (this.parentHighlight != null)
- {
- var parent = this.graph.model.getParent(this.state.cell);
- var pstate = this.graph.view.getState(parent);
- if (pstate != null && pstate.parentHighlight == this.parentHighlight)
- {
- pstate.parentHighlight = null;
- }
-
- this.parentHighlight.destroy();
- this.parentHighlight = null;
- }
-
- if (this.labelShape != null)
- {
- this.labelShape.destroy();
- this.labelShape = null;
- }
- if (this.constraintHandler != null)
- {
- this.constraintHandler.destroy();
- this.constraintHandler = null;
- }
-
- this.destroyBends(this.virtualBends);
- this.virtualBends = null;
-
- this.destroyBends(this.customHandles);
- this.customHandles = null;
- this.destroyBends(this.bends);
- this.bends = null;
-
- this.removeHint();
- };
- __mxOutput.mxEdgeHandler = typeof mxEdgeHandler !== 'undefined' ? mxEdgeHandler : undefined;
|