📄 mxgraphview.java
字号:
{ state.absoluteOffset.setY(state.absoluteOffset.getY() - state.getHeight()); } else if (vertical.equals(mxConstants.ALIGN_BOTTOM)) { state.absoluteOffset.setY(state.absoluteOffset.getY() + state.getHeight()); } } /** * Validates the points for the state of the given cell recursively if the * cell is not collapsed and returns the bounding box of all visited states * as a rectangle. * * @param parentState Object that represents the state of the parent cell. * @param cell Cell for which the points in the state should be updated. * @return Returns the bounding box for the given cell. */ public mxRectangle validatePoints(mxCellState parentState, Object cell) { mxCellState state = getState(cell); double minX = 0; double minY = 0; double maxX = 0; double maxY = 0; mxIGraphModel model = graph.getModel(); boolean isEdge = model.isEdge(cell); if (state != null) { if (state.isInvalid()) { mxGeometry geo = graph.getCellGeometry(cell); if (isEdge) { Object source = getVisibleTerminal(cell, true); if (source != null && !model.isAncestor(source, cell)) { Object p = model.getParent(source); mxCellState pstate = getState(p); validatePoints(pstate, source); } Object target = getVisibleTerminal(cell, false); if (target != null && !model.isAncestor(target, cell)) { Object p = model.getParent(target); mxCellState pstate = getState(p); validatePoints(pstate, target); } setTerminalPoints(state); updatePoints(state, geo.getPoints(), source, target); updateTerminalPoints(state, source, target); updateEdgeBounds(state); state.setAbsoluteOffset(getPoint(state, geo)); } else if (geo != null && geo.isRelative() && parentState != null && model.isEdge(parentState.getCell())) { mxPoint origin = getPoint(parentState, geo); state.setX(origin.getX()); state.setY(origin.getY()); } state.setInvalid(false); } if (isEdge || model.isVertex(cell)) { updateLabelBounds(state); mxRectangle bb = updateBoundingBox(state); minX = bb.getX(); minY = bb.getY(); maxX = bb.getX() + bb.getWidth(); maxY = bb.getY() + bb.getHeight(); } } if (state != null && (!graph.isCellCollapsed(cell) || cell == currentRoot)) { int childCount = model.getChildCount(cell); for (int i = 0; i < childCount; i++) { Object child = model.getChildAt(cell, i); mxRectangle bounds = validatePoints(state, child); // TODO: Fix initial 0 for minX, minY (should be null) minX = Math.min(minX, bounds.getX()); minY = Math.min(minY, bounds.getY()); maxX = Math.max(maxX, bounds.getX() + bounds.getWidth()); maxY = Math.max(maxY, bounds.getY() + bounds.getHeight()); } } return new mxRectangle(minX, minY, maxX - minX, maxY - minY); } /** * Updates the label bounds in the given state. */ public void updateLabelBounds(mxCellState state) { Object cell = state.getCell(); Hashtable style = state.getStyle(); String label = graph.getLabel(cell); mxRectangle vertexBounds = (!graph.getModel().isEdge(cell)) ? state : null; state.setLabelBounds(mxUtils.getLabelPaintBounds(label, style, graph .isHtmlLabel(cell), state.getAbsoluteOffset(), vertexBounds, scale)); } /** * Updates the bounding box in the given cell state. * * @param state Cell state whose bounding box should be * updated. */ public mxRectangle updateBoundingBox(mxCellState state) { // Gets the cell bounds and adds shadows and markers mxRectangle rect = new mxRectangle(state); Hashtable style = state.getStyle(); // Adds extra pixels for the marker and stroke assuming // that the border stroke is centered around the bounds // and the first pixel is drawn inside the bounds double strokeWidth = Math.max(1, Math.round(mxUtils.getInt(style, mxConstants.STYLE_STROKEWIDTH, 1) * scale)); strokeWidth -= Math.max(1, strokeWidth / 2); if (graph.getModel().isEdge(state.getCell())) { int ms = 0; if (style.containsKey(mxConstants.STYLE_ENDARROW) || style.containsKey(mxConstants.STYLE_STARTARROW)) { ms = (int) Math.round(mxConstants.DEFAULT_MARKERSIZE * scale); } // Adds the strokewidth rect.grow(ms + strokeWidth); // Adds worst case border for an arrow shape if (mxUtils.getString(style, mxConstants.STYLE_SHAPE, "").equals( mxConstants.SHAPE_ARROW)) { rect.grow(mxConstants.ARROW_WIDTH / 2); } } else { rect.grow(strokeWidth); } // Adds extra pixels for the shadow if (mxUtils.isTrue(style, mxConstants.STYLE_SHADOW)) { rect.setWidth(rect.getWidth() + mxConstants.SHADOW_OFFSETX); rect.setHeight(rect.getHeight() + mxConstants.SHADOW_OFFSETY); } // Adds oversize images in labels if (mxUtils.getString(style, mxConstants.STYLE_SHAPE, "").equals( mxConstants.SHAPE_LABEL)) { if (mxUtils.getString(style, mxConstants.STYLE_IMAGE) != null) { double w = mxUtils.getInt(style, mxConstants.STYLE_IMAGE_WIDTH, mxConstants.DEFAULT_IMAGESIZE) * scale; double h = mxUtils.getInt(style, mxConstants.STYLE_IMAGE_HEIGHT, mxConstants.DEFAULT_IMAGESIZE) * scale; double x = state.getX(); double y = 0; String imgAlign = mxUtils .getString(style, mxConstants.STYLE_IMAGE_ALIGN, mxConstants.ALIGN_CENTER); String imgValign = mxUtils.getString(style, mxConstants.STYLE_IMAGE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE); if (imgAlign.equals(mxConstants.ALIGN_RIGHT)) { x += state.getWidth() - w; } else if (imgAlign.equals(mxConstants.ALIGN_CENTER)) { x += (state.getWidth() - w) / 2; } if (imgValign.equals(mxConstants.ALIGN_TOP)) { y = state.getY(); } else if (imgValign.equals(mxConstants.ALIGN_BOTTOM)) { y = state.getY() + state.getHeight() - h; } else { y = state.getY() + (state.getHeight() - h) / 2; } rect.add(new mxRectangle(x, y, w, h)); } } // Adds the rotated bounds to the bounding box if the // shape is rotated double rotation = mxUtils.getDouble(style, mxConstants.STYLE_ROTATION); mxRectangle bbox = mxUtils.getBoundingBox(rect, rotation); // Add the rotated bounding box to the non-rotated so // that all handles are also covered if (bbox != null) { rect.add(bbox); } // Unifies the cell bounds and the label bounds if (!graph.isLabelClipped(state.getCell())) { rect.add(state.getLabelBounds()); } state.setBoundingBox(rect); return rect; } /** * Sets the initial absolute terminal points in the given state. * * @param state Cell state whose initial terminal points should be * updated. */ public void setTerminalPoints(mxCellState state) { Object edge = state.getCell(); mxGeometry geo = graph.getCellGeometry(edge); mxPoint orig = state.getOrigin(); mxPoint pt = geo.getTerminalPoint(true); if (pt != null) { pt = new mxPoint(scale * (translate.getX() + pt.getX() + orig.getX()), scale * (translate.getY() + pt.getY() + orig.getY())); state.setAbsoluteTerminalPoint(pt, true); } else { state.setAbsoluteTerminalPoint(null, true); } pt = geo.getTerminalPoint(false); if (pt != null) { pt = new mxPoint(scale * (translate.getX() + pt.getX() + orig.getX()), scale * (translate.getY() + pt.getY() + orig.getY())); state.setAbsoluteTerminalPoint(pt, false); } else { state.setAbsoluteTerminalPoint(null, false); } } /** * Updates the absolute points in the given state using the specified array * of points as the relative points. * * @param state Cell state whose absolute points should be updated. * @param points Array of points that constitute the relative points. * @param source Cell that represents the visual source. * @param target Cell that represents the visual target. */ public void updatePoints(mxCellState state, List points, Object source, Object target) { if (state != null) { List pts = new ArrayList(); pts.add(state.getAbsolutePoint(0)); mxEdgeStyleFunction edgeStyle = getEdgeStyle(state, source, target); if (edgeStyle != null) { mxCellState src = getState(source); mxCellState trg = getState(target); edgeStyle.apply(state, src, trg, points, pts); } else if (points != null) { for (int i = 0; i < points.size(); i++) { Object tmp = points.get(i); if (tmp instanceof mxPoint) { mxPoint pt = (mxPoint) tmp; pts.add(transformControlPoint(state, pt)); } } } pts.add(state.getAbsolutePoint(state.getAbsolutePointCount() - 1)); state.setAbsolutePoints(pts); } } /** * Transforms the given control point to an absolute point. */ public mxPoint transformControlPoint(mxCellState state, mxPoint pt) { mxPoint origin = state.getOrigin(); return new mxPoint((pt.getX() + translate.getX() + origin.getX()) * scale, (pt.getY() + translate.getY() + origin.getY()) * scale); } /** * Returns the edge style function to be used to render the given edge * state. */ public mxEdgeStyleFunction getEdgeStyle(mxCellState edgeState, Object source, Object target) { Object edgeStyle = null; if (source != null && source == target) { edgeStyle = edgeState.getStyle().get(mxConstants.STYLE_LOOP); if (edgeStyle == null) { edgeStyle = graph.getDefaultLoopStyle(); } } else if (!mxUtils.isTrue(edgeState.getStyle(), mxConstants.STYLE_NOEDGESTYLE, false)) { edgeStyle = edgeState.getStyle().get(mxConstants.STYLE_EDGE); } // Converts string values to objects if (edgeStyle instanceof String) { String str = String.valueOf(edgeStyle); Object tmp = mxStyleRegistry.getValue(str); if (tmp == null) { tmp = mxUtils.eval(str); } edgeStyle = tmp; } if (edgeStyle instanceof mxEdgeStyleFunction) { return (mxEdgeStyleFunction) edgeStyle; } return null; } /** * Updates the terminal points in the given state. * * @param state Cell state whose terminal points should be updated. * @param source Cell that represents the visual source. * @param target Cell that represents the visual target. */ public void updateTerminalPoints(mxCellState state, Object source, Object target) { if (target != null) { updateTerminalPoint(state, target, source, false); } if (source != null) { updateTerminalPoint(state, source, target, true); } } /** * Updates the absolute terminal point in the given state for the given * start and end state, where start is the source if isSource is true. * * @param state Cell state whose terminal point should be updated. * @param start Cell state for the source or target terminal. * @param end Cell state for the opposite terminal. * @param isSource Boolean indicating if start is the state of the source * terminal. */ public void updateTerminalPoint(mxCellState state, Object start, Object end, boolean isSource) { int index = (isSource) ? 0 : state.getAbsolutePointCount() - 1; state.setAbsolutePoint(index, getPerimeterPoint(state, start, end, isSource)); } /** * Returns a point that defines the location of the connection point * between the edge represented by the given state and the source or target * end of the edge, depending on isSource. * * @param state Cell state of the connecting edge. * @param start Cell state for the source or target terminal. * @param end Cell state for the opposite terminal. * @param isSource Boolean indicating if start is the state of the source * terminal. * @return Returns the connection point between the edge and the terminal. */ public mxPoint getPerimeterPoint(mxCellState state, Object start, Object end, boolean isSource) { mxPoint point = null; mxCellState terminalState = getState(start); if (terminalState != null) { mxPerimeterFunction perimeter = getPerimeterFunction(terminalState); mxPoint next = getNextPoint(state, end, isSource); if (perimeter != null && next != null) { mxRectangle bounds = getPerimeterBounds(terminalState, state, isSource); if (bounds.getWidth() > 0 || bounds.getHeight() > 0) { point = perimeter.apply(bounds, state, terminalState, isSource, next); } } if (point == null) { point = getPoint(terminalState, null); } } return point; } /** * Returns the x-coordinate of the center point for automatic routing. * * @return Returns the x-coordinate of the routing center point. */ public double getRoutingCenterX(mxCellState state) { float f = (state.getStyle() != null) ? mxUtils.getFloat(state .getStyle(), mxConstants.STYLE_ROUTING_CENTER_X) : 0; return state.getCenterX() + f * state.getWidth(); } /** * Returns the y-coordinate of the center point for automatic routing. * * @return Returns the y-coordinate of the routing center point. */ public double getRoutingCenterY(mxCellState state) { float f = (state.getStyle() != null) ? mxUtils.getFloat(state .getStyle(), mxConstants.STYLE_ROUTING_CENTER_Y) : 0; return state.getCenterY() + f * state.getHeight(); } /** * Returns the perimeter bounds for the given terminal, edge pair. */ public mxRectangle getPerimeterBounds(mxCellState terminal, mxCellState edge, boolean isSource) { double border = 0; if (edge != null) { border = mxUtils.getDouble(edge.getStyle(), mxConstants.STYLE_PERIMETER_SPACING); border += mxUtils.getDouble(edge.getStyle(), (isSource) ? mxConstants.STYLE_SOURCE_PERIMETER_SPACING : mxConstants.STYLE_TARGET_PERIMETER_SPACING); } if (terminal != null) { border += mxUtils.getDouble(terminal.getStyle(), mxConstants.STYLE_PERIMETER_SPACING); } return terminal.getPerimeterBounds(border * scale); } /** * Returns the perimeter function for the given state. */ public mxPerimeterFunction getPerimeterFunction(mxCellState state) { Object perimeter = state.getStyle().get(mxConstants.STYLE_PERIMETER); // Converts string values to objects if (perimeter instanceof String) { String str = String.valueOf(perimeter); Object tmp = mxStyleRegistry.getValue(str); if (tmp == null) { tmp = mxUtils.eval(str); } perimeter = tmp; } if (perimeter instanceof mxPerimeterFunction) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -