/// <summary> /// Validates the given cell state. /// </summary> public void UpdateEdgeState(mxCellState state, mxGeometry geo, mxCellState source, mxCellState target) { // This will remove edges with no terminals and no terminal points // as such edges are invalid and produce NPEs in the edge styles. // Also removes connected edges that have no visible terminals. if ((graph.Model.GetTerminal(state.Cell, true) != null && source == null) || (source == null && geo.GetTerminalPoint(true) == null) || (graph.Model.GetTerminal(state.Cell, false) != null && target == null) || (target == null && geo.GetTerminalPoint(false) == null)) { RemoveState(state.Cell, true); } else { UpdateFixedTerminalPoints(state, source, target); UpdatePoints(state, geo.Points, source, target); UpdateFloatingTerminalPoints(state, source, target); if (state.AbsolutePointCount() < 2 || state.AbsolutePoints[0] == null || state .AbsolutePoints[state.AbsolutePointCount() - 1] == null) { // This will remove edges with invalid points from the list of states in the view. // Happens if the one of the terminals and the corresponding terminal point is null. RemoveState(state.Cell, true); } else { UpdateEdgeBounds(state); state.AbsoluteOffset = GetPoint(state, geo); } } }
/// <summary> /// Updates the terminal points in the given state after the edge style was /// computed for the edge. /// </summary> /// <param name="state">State whose terminal points should be updated.</param> /// <param name="source">State that represents the source terminal.</param> /// <param name="target">State that represents the target terminal.</param> public void UpdateFloatingTerminalPoints(mxCellState state, mxCellState source, mxCellState target) { mxPoint p0 = state.AbsolutePoints[0]; mxPoint pe = state.AbsolutePoints[state.AbsolutePointCount() - 1]; if (pe == null && target != null) { UpdateFloatingTerminalPoint(state, target, source, false); } if (p0 == null && source != null) { UpdateFloatingTerminalPoint(state, source, target, true); } }
/// <summary> /// Returns the bottom-most cell that intersects the given point (x, y) in /// the cell hierarchy that starts at the given parent. /// </summary> /// <param name="state"></param> /// <param name="rect"></param> /// <returns>Returns true if the given cell state and rectangle intersect.</returns> public bool Intersects(mxCellState state, Rectangle rect) { if (state != null) { // Checks if the label intersects if (state.LabelBounds != null && state.LabelBounds.GetRectangle().IntersectsWith(rect)) { return true; } int pointCount = state.AbsolutePointCount(); // Checks if the segments of the edge intersect if (pointCount > 0) { mxRectangle tmp = new mxRectangle(rect); tmp.Grow(tolerance); rect = tmp.GetRectangle(); mxPoint p0 = state.AbsolutePoints[0]; for (int i = 0; i < pointCount; i++) { mxPoint p1 = state.AbsolutePoints[i]; // FIXME: Implement line intersection check //if (rect.IntersectsLine(p0.X, p0.Y, p1.X, p1 // .Y)) // return true; p0 = p1; } } else { // Checks if the bounds of the shape intersect return state.GetRectangle().IntersectsWith(rect); } } return false; }
/// <summary> /// see com.mxgraph.mxICanvas.DrawCell() /// </summary> public override Object DrawCell(mxCellState state) { Dictionary<string, object> style = state.Style; GraphicsState graphicsState = g.Save(); // Applies the local translation g.TranslateTransform(translate.X, translate.Y); // Checks if the cell is an edge if (state.AbsolutePointCount() > 1) { DrawLine(state.AbsolutePoints, style); } else { Rectangle bounds = state.GetRectangle(); int x = bounds.X; int y = bounds.Y; int w = bounds.Width; int h = bounds.Height; // Applies the rotation on the graphics object and stores // the previous transform so that it can be restored float rotation = mxUtils.GetFloat(style, mxConstants.STYLE_ROTATION); if (rotation != 0) { int cx = x + w / 2; int cy = y + h / 2; g.TranslateTransform(cx, cy); g.RotateTransform(rotation); g.TranslateTransform(-cx, -cy); } // Draws a swimlane if start is > 0 string shape = mxUtils.GetString(style, mxConstants.STYLE_SHAPE, ""); if (!shape.Equals(mxConstants.SHAPE_SWIMLANE)) { // NOTE: Should draw built-in shapes first mxStencil stencil = mxStencilRegistry.GetStencil(shape); if (stencil != null) { stencil.PaintShape(this, state); } else { DrawShape(x, y, w, h, style); } } else { int start = (int)Math.Round(mxUtils.GetDouble(style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_STARTSIZE) * scale); // Removes some styles to draw the content area Dictionary<string, Object> cloned = new Dictionary<string, Object>(style); cloned.Remove(mxConstants.STYLE_FILLCOLOR); cloned.Remove(mxConstants.STYLE_ROUNDED); if (mxUtils.IsTrue(style, mxConstants.STYLE_HORIZONTAL, true)) { DrawShape(x, y, w, Math.Min(h, start), style); DrawShape(x, y + start, w, h - start, cloned); } else { DrawShape(x, y, Math.Min(w, start), h, style); DrawShape(x + start, y, w - start, h, cloned); } } } // Resets all changes to the graphics configuration g.Restore(graphicsState); return null; }