public void rotate(double theta, boolean flipH, boolean flipV, double cx, double cy) { cx += state.dx; cy += state.dy; cx *= state.scale; cy *= state.scale; state.g.rotate(Math.toRadians(theta), cx, cy); // This implementation uses custom scale/translate and built-in rotation // Rotation state is part of the AffineTransform in state.transform if (flipH && flipV) { theta += 180; } else if (flipH ^ flipV) { double tx = (flipH) ? cx : 0; int sx = (flipH) ? -1 : 1; double ty = (flipV) ? cy : 0; int sy = (flipV) ? -1 : 1; state.g.translate(tx, ty); state.g.scale(sx, sy); state.g.translate(-tx, -ty); } state.theta = theta; state.rotationCx = cx; state.rotationCy = cy; state.flipH = flipH; state.flipV = flipV; }
/** Caches color conversion as it is expensive. */ public void setStrokeColor(String value) { // Lazy and cached instantiation strategy for all stroke properties if (state.strokeColorValue == null || !state.strokeColorValue.equals(value)) { state.strokeColorValue = value; state.strokeColor = null; } }
public void setFillColor(String value) { if (state.fillColorValue == null || !state.fillColorValue.equals(value)) { state.fillColorValue = value; state.fillColor = null; // Setting fill color resets gradient paint state.gradientPaint = null; } }
public void setGradient( String color1, String color2, double x, double y, double w, double h, String direction, double alpha1, double alpha2) { // LATER: Add lazy instantiation and check if paint already created float x1 = (float) ((state.dx + x) * state.scale); float y1 = (float) ((state.dy + y) * state.scale); float x2 = (float) x1; float y2 = (float) y1; h *= state.scale; w *= state.scale; if (direction == null || direction.length() == 0 || direction.equals(mxConstants.DIRECTION_SOUTH)) { y2 = (float) (y1 + h); } else if (direction.equals(mxConstants.DIRECTION_EAST)) { x2 = (float) (x1 + w); } else if (direction.equals(mxConstants.DIRECTION_NORTH)) { y1 = (float) (y1 + h); } else if (direction.equals(mxConstants.DIRECTION_WEST)) { x1 = (float) (x1 + w); } Color c1 = parseColor(color1); if (alpha1 != 1) { c1 = new Color(c1.getRed(), c1.getGreen(), c1.getBlue(), (int) (alpha1 * 255)); } Color c2 = parseColor(color2); if (alpha2 != 1) { c2 = new Color(c2.getRed(), c2.getGreen(), c2.getBlue(), (int) (alpha2 * 255)); } state.gradientPaint = new GradientPaint(x1, y1, c1, x2, y2, c2, true); // Resets fill color state.fillColorValue = null; }
protected void paintCurrentPath(boolean filled, boolean stroked) { if (currentPath != null) { if (stroked) { if (state.strokeColor == null) { state.strokeColor = parseColor(state.strokeColorValue); } if (state.strokeColor != null) { updateStroke(); } } if (filled) { if (state.gradientPaint == null && state.fillColor == null) { state.fillColor = parseColor(state.fillColorValue); } } if (state.shadow) { paintShadow(filled, stroked); } if (filled) { if (state.gradientPaint != null) { state.g.setPaint(state.gradientPaint); state.g.fill(currentPath); } else { if (state.fillColor == null) { state.fillColor = parseColor(state.fillColorValue); } if (state.fillColor != null) { state.g.setColor(state.fillColor); state.g.setPaint(null); state.g.fill(currentPath); } } } if (stroked && state.strokeColor != null) { state.g.setColor(state.strokeColor); state.g.draw(currentPath); } } }
/** Returns a clone of thec given state. */ protected CanvasState cloneState(CanvasState state) { try { return (CanvasState) state.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; }
/** Constructs a new graphics export canvas. */ public mxGraphicsCanvas2D(Graphics2D g) { setGraphics(g); state.g = g; // Initializes the cell renderer pane for drawing HTML markup try { rendererPane = new CellRendererPane(); } catch (Exception e) { // ignore } }
public void setDashPattern(String value) { if (value != null && value.length() > 0) { String[] tokens = value.split(" "); float[] dashpattern = new float[tokens.length]; for (int i = 0; i < tokens.length; i++) { dashpattern[i] = (float) (Float.parseFloat(tokens[i])); } state.dashPattern = dashpattern; } }
protected void paintShadow(boolean filled, boolean stroked) { if (state.shadowColor == null) { state.shadowColor = parseColor(state.shadowColorValue); } if (state.shadowColor != null) { double rad = -state.theta * (Math.PI / 180); double cos = Math.cos(rad); double sin = Math.sin(rad); double dx = state.shadowOffsetX * state.scale; double dy = state.shadowOffsetY * state.scale; if (state.flipH) { dx *= -1; } if (state.flipV) { dy *= -1; } double tx = dx * cos - dy * sin; double ty = dx * sin + dy * cos; state.g.setColor(state.shadowColor); state.g.translate(tx, ty); double alpha = state.alpha * state.shadowAlpha; Composite comp = state.g.getComposite(); state.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) (alpha))); if (filled && (state.gradientPaint != null || state.fillColor != null)) { state.g.fill(currentPath); } // FIXME: Overlaps with fill in composide mode if (stroked && state.strokeColor != null) { state.g.draw(currentPath); } state.g.translate(-tx, -ty); state.g.setComposite(comp); } }
public void setFontBorderColor(String value) { if (state.fontBorderColorValue == null || !state.fontBorderColorValue.equals(value)) { state.fontBorderColorValue = value; state.fontBorderColor = null; } }
public void setFontSize(double value) { if (value != state.fontSize) { state.fontSize = value; } }
public void setMiterLimit(double value) { if (value != state.miterLimit) { state.miterLimit = value; } }
public void setLineJoin(String value) { if (!state.lineJoin.equals(value)) { state.lineJoin = value; } }
public void setShadow(boolean value) { state.shadow = value; }
public void setAlpha(double value) { if (state.alpha != value) { state.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) (value))); state.alpha = value; } }
public void setStrokeWidth(double value) { // Lazy and cached instantiation strategy for all stroke properties if (value != state.strokeWidth) { state.strokeWidth = value; } }
public void setShadowAlpha(double value) { state.shadowAlpha = value; }
public void translate(double dx, double dy) { // This implementation uses custom scale/translate and built-in rotation state.dx += dx; state.dy += dy; }
public void scale(double value) { // This implementation uses custom scale/translate and built-in rotation state.scale = state.scale * value; }
/** Saves the current canvas state. */ public void save() { stack.push(state); state = cloneState(state); state.g = (Graphics2D) state.g.create(); }
public void setFontFamily(String value) { if (!state.fontFamily.equals(value)) { state.fontFamily = value; } }
public void setFontStyle(int value) { if (value != state.fontStyle) { state.fontStyle = value; } }
public void setDashed(boolean value) { // Lazy and cached instantiation strategy for all stroke properties if (value != state.dashed) { state.dashed = value; } }
public void setShadowColor(String value) { state.shadowColorValue = value; }
public void setLineCap(String value) { if (!state.lineCap.equals(value)) { state.lineCap = value; } }
/** Draws the given text. */ public void plainText( double x, double y, double w, double h, String str, String align, String valign, boolean wrap, String format, String overflow, boolean clip, double rotation) { if (state.fontColor == null) { state.fontColor = parseColor(state.fontColorValue); } if (state.fontColor != null) { x = (state.dx + x) * state.scale; y = (state.dy + y) * state.scale; w *= state.scale; h *= state.scale; // Font-metrics needed below this line Graphics2D g2 = createTextGraphics(x, y, w, h, rotation, clip, align, valign); FontMetrics fm = g2.getFontMetrics(); String[] lines = str.split("\n"); int[] stringWidths = new int[lines.length]; int textWidth = 0; for (int i = 0; i < lines.length; i++) { stringWidths[i] = fm.stringWidth(lines[i]); textWidth = Math.max(textWidth, stringWidths[i]); } int textHeight = (int) Math.round(lines.length * (fm.getFont().getSize() * mxConstants.LINE_HEIGHT)); if (clip && textHeight > h && h > 0) { textHeight = (int) h; } Point2D margin = getMargin(align, valign); x += margin.getX() * textWidth; y += margin.getY() * textHeight; if (state.fontBackgroundColorValue != null) { if (state.fontBackgroundColor == null) { state.fontBackgroundColor = parseColor(state.fontBackgroundColorValue); } if (state.fontBackgroundColor != null) { g2.setColor(state.fontBackgroundColor); g2.fillRect((int) Math.round(x), (int) Math.round(y - 1), textWidth + 1, textHeight + 2); } } if (state.fontBorderColorValue != null) { if (state.fontBorderColor == null) { state.fontBorderColor = parseColor(state.fontBorderColorValue); } if (state.fontBorderColor != null) { g2.setColor(state.fontBorderColor); g2.drawRect((int) Math.round(x), (int) Math.round(y - 1), textWidth + 1, textHeight + 2); } } g2.setColor(state.fontColor); y += fm.getHeight() - fm.getDescent() - (margin.getY() + 0.5); for (int i = 0; i < lines.length; i++) { double dx = 0; if (align != null) { if (align.equals(mxConstants.ALIGN_CENTER)) { dx = (textWidth - stringWidths[i]) / 2; } else if (align.equals(mxConstants.ALIGN_RIGHT)) { dx = textWidth - stringWidths[i]; } } // Adds support for underlined text via attributed character iterator if (!lines[i].isEmpty()) { if ((state.fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE) { AttributedString as = new AttributedString(lines[i]); as.addAttribute(TextAttribute.FONT, g2.getFont()); as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); g2.drawString(as.getIterator(), (int) Math.round(x + dx), (int) Math.round(y)); } else { g2.drawString(lines[i], (int) Math.round(x + dx), (int) Math.round(y)); } } y += (int) Math.round(fm.getFont().getSize() * mxConstants.LINE_HEIGHT); } } }
public void setShadowOffset(double dx, double dy) { state.shadowOffsetX = dx; state.shadowOffsetY = dy; }