📄 mxutils.java
字号:
/** * $Id: mxUtils.java,v 1.34 2009/04/05 09:22:44 gaudenz Exp $ * Copyright (c) 2007, Gaudenz Alder */package com.mxgraph.util;import java.awt.AlphaComposite;import java.awt.Color;import java.awt.Composite;import java.awt.Dimension;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Image;import java.awt.Rectangle;import java.awt.RenderingHints;import java.awt.font.FontRenderContext;import java.awt.font.GlyphVector;import java.awt.geom.Rectangle2D;import java.awt.image.BufferedImage;import java.awt.image.ImageObserver;import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.FileInputStream;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.StringReader;import java.net.URL;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Comparator;import java.util.Formatter;import java.util.Hashtable;import java.util.Iterator;import java.util.List;import java.util.SortedSet;import java.util.TreeSet;import javax.imageio.ImageIO;import javax.swing.text.html.HTMLDocument;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.transform.Result;import javax.xml.transform.Source;import javax.xml.transform.Transformer;import javax.xml.transform.TransformerFactory;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import javax.xml.xpath.XPath;import javax.xml.xpath.XPathConstants;import javax.xml.xpath.XPathExpressionException;import javax.xml.xpath.XPathFactory;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.Node;import org.xml.sax.InputSource;import com.mxgraph.io.mxCodecRegistry;import com.mxgraph.model.mxCellPath;import com.mxgraph.model.mxICell;import com.mxgraph.model.mxIGraphModel;import com.mxgraph.view.mxCellState;/** * Contains various helper methods for use with mxGraph. */public class mxUtils{ /** * Static Graphics used for Font Metrics. */ protected static transient Graphics fontGraphics; // Creates a renderer for HTML markup (only possible in // non-headless environment) static { try { fontGraphics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB) .getGraphics(); } catch (Exception e) { // ignore } } /** * Returns the size for the given label. If isHtml is true then any HTML * markup in the label is computed as HTML and all newlines inside the * HTML body are converted into linebreaks. */ public static mxRectangle getLabelSize(String label, Hashtable style, boolean isHtml) { mxRectangle size; if (isHtml) { size = getSizeForHtml(getBodyMarkup(label, true), style); } else { float fontSize = getFloat(style, mxConstants.STYLE_FONTSIZE, mxConstants.DEFAULT_FONTSIZE); String fontFamily = getString(style, mxConstants.STYLE_FONTFAMILY, mxConstants.DEFAULT_FONTFAMILY); int fontStyle = getInt(style, mxConstants.STYLE_FONTSTYLE); size = getSizeForString(label, fontSize, fontFamily, fontStyle); } return size; } /** * Returns the body part of the given HTML markup. */ public static String getBodyMarkup(String markup, boolean replaceLinefeeds) { String lowerCase = markup.toLowerCase(); int bodyStart = lowerCase.indexOf("<body>"); if (bodyStart >= 0) { bodyStart += 7; int bodyEnd = lowerCase.lastIndexOf("</body>"); if (bodyEnd > bodyStart) { markup = markup.substring(bodyStart, bodyEnd).trim(); } } if (replaceLinefeeds) { markup = markup.replaceAll("\n", "<br>"); } return markup; } /** * Returns the paint bounds for the given label. */ public static mxRectangle getLabelPaintBounds(String label, Hashtable style, boolean isHtml, mxPoint offset, mxRectangle vertexBounds, double scale) { mxRectangle size = mxUtils.getLabelSize(label, style, isHtml); double x = offset.getX(); double y = offset.getY(); double width = 0; double height = 0; if (vertexBounds != null) { x += vertexBounds.getX(); y += vertexBounds.getY(); // Limits the label to the swimlane title double start = mxUtils .getDouble(style, mxConstants.STYLE_STARTSIZE) * scale; if (start > 0) { if (mxUtils.isTrue(style, mxConstants.STYLE_HORIZONTAL, true)) { width += vertexBounds.getWidth(); height += start; } else { width += start; height += vertexBounds.getHeight(); } } else { width += vertexBounds.getWidth(); height += vertexBounds.getHeight(); } } return mxUtils.getScaledLabelBounds(x, y, size, width, height, style, scale); } /** * Returns the bounds for a label for the given location and size, taking * into account the alignment and spacing in the specified style, as well * as the width and height of the rectangle that contains the label. * (For edge labels this width and height is 0.) The scale is used to scale * the given size and the spacings in the specified style. */ public static mxRectangle getScaledLabelBounds(double x, double y, mxRectangle size, double outerWidth, double outerHeight, Hashtable style, double scale) { // Adds an inset of 3 pixels double inset = mxConstants.LABEL_INSET * scale; // Scales the size of the label double width = size.getWidth() * scale + 2 * inset; double height = size.getHeight() * scale + 2 * inset; // Gets the global spacing and orientation boolean horizontal = isTrue(style, mxConstants.STYLE_HORIZONTAL, true); int spacing = (int) (getInt(style, mxConstants.STYLE_SPACING) * scale); // Gets the alignment settings Object align = getString(style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER); Object valign = getString(style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE); // Gets the vertical spacing int top = (int) (getInt(style, mxConstants.STYLE_SPACING_TOP) * scale); int bottom = (int) (getInt(style, mxConstants.STYLE_SPACING_BOTTOM) * scale); // Gets the horizontal spacing int left = (int) (getInt(style, mxConstants.STYLE_SPACING_LEFT) * scale); int right = (int) (getInt(style, mxConstants.STYLE_SPACING_RIGHT) * scale); // Applies the orientation to the spacings and dimension if (!horizontal) { int tmp = top; top = right; right = bottom; bottom = left; left = tmp; double tmp2 = width; width = height; height = tmp2; } // Computes the position of the label for the horizontal alignment if ((horizontal && align.equals(mxConstants.ALIGN_CENTER)) || (!horizontal && valign.equals(mxConstants.ALIGN_MIDDLE))) { x += (outerWidth - width) / 2 + left - right; } else if ((horizontal && align.equals(mxConstants.ALIGN_RIGHT)) || (!horizontal && valign.equals(mxConstants.ALIGN_BOTTOM))) { x += outerWidth - width - spacing - right; } else { x += spacing + left; } // Computes the position of the label for the vertical alignment if ((!horizontal && align.equals(mxConstants.ALIGN_CENTER)) || (horizontal && valign.equals(mxConstants.ALIGN_MIDDLE))) { y += (outerHeight - height) / 2 + top - bottom; } else if ((!horizontal && align.equals(mxConstants.ALIGN_LEFT)) || (horizontal && valign.equals(mxConstants.ALIGN_BOTTOM))) { y += outerHeight - height - spacing - bottom; } else { y += spacing + top; } return new mxRectangle(x, y, width, height); } /** * Returns the size of the given text. * * @param text String whose size should be returned. * @return Returns the size of the given text. */ public static mxRectangle getSizeForString(String text) { return getSizeForString(text, 0); } /** * Returns the size of the given text. * * @param text String whose size should be returned. * @param fontSize Integer that specifies the font size in pixels. Default is * <mxConstants.DEFAULT_FONTSIZE>. * @return Returns the size of the given text. */ public static mxRectangle getSizeForString(String text, float fontSize) { return getSizeForString(text, fontSize, null); } /** * Returns an <mxRectangle> with the size (width and height in pixels) of * the given text. * * @param text String whose size should be returned. * @param fontSize Integer that specifies the font size in pixels. Default is * <mxConstants.DEFAULT_FONTSIZE>. * @param fontFamily String that specifies the name of the font famil.y Default * is <mxConstants.DEFAULT_FONTFAMILY>. * @return Returns the size of the given text. */ public static mxRectangle getSizeForString(String text, float fontSize, String fontFamily) { return getSizeForString(text, fontSize, fontFamily, 0); } /** * Returns an <mxRectangle> with the size (width and height in pixels) of * the given string. * * @param text String whose size should be returned. * @param fontSize Integer that specifies the font size in pixels. Default is * <mxConstants.DEFAULT_FONTSIZE>. * @param fontFamily String that specifies the name of the font famil.y Default * is <mxConstants.DEFAULT_FONTFAMILY>. * @param fontStyle Integer that specifies the font style. Default is 0. * @return Returns the size of the given text. */ public static mxRectangle getSizeForString(String text, float fontSize, String fontFamily, int fontStyle) { if (fontSize == 0) { fontSize = mxConstants.DEFAULT_FONTSIZE; } if (fontFamily == null) { fontFamily = mxConstants.DEFAULT_FONTFAMILY; } int swingFontStyle = ((fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) ? Font.BOLD : Font.PLAIN; swingFontStyle += ((fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) ? Font.ITALIC : Font.PLAIN; FontRenderContext frc = new FontRenderContext(null, false, false); Font font = new Font(fontFamily, swingFontStyle, (int) fontSize); FontMetrics metrics = null; if (fontGraphics != null) { metrics = fontGraphics.getFontMetrics(font); } double lineHeight = mxConstants.LINESPACING; if (metrics != null) { lineHeight += metrics.getHeight(); } else { lineHeight += fontSize * 1.27; } String[] lines = text.split("\n"); Rectangle2D boundingBox = null; for (int i = 0; i < lines.length; i++) { GlyphVector gv = font.createGlyphVector(frc, lines[i]); Rectangle2D bounds = gv.getVisualBounds(); if (boundingBox == null) { boundingBox = bounds; } else { boundingBox.setFrame(0, 0, Math.max(boundingBox.getWidth(), bounds.getWidth()), boundingBox.getHeight() + lineHeight); } } return new mxRectangle(boundingBox); } /** * Returns an mxRectangle with the size (width and height in pixels) of * the given HTML markup. * * @param markup HTML markup whose size should be returned. */ public static mxRectangle getSizeForHtml(String markup, Hashtable style) { mxLightweightTextPane textRenderer = mxLightweightTextPane .getSharedInstance(); if (textRenderer != null) { textRenderer.setStyledDocument(createHtmlDocument(style)); textRenderer.setText(markup); Dimension size = textRenderer.getPreferredSize(); return new mxRectangle(0, 0, size.width, size.height); } return getSizeForString(markup); } /** * Returns the bounding box for the rotated rectangle. */ public static mxRectangle getBoundingBox(mxRectangle rect, double rotation) { mxRectangle result = null; if (rect != null && rotation != 0) { double rad = Math.toRadians(rotation); double cos = Math.cos(rad); double sin = Math.sin(rad); mxPoint cx = new mxPoint(rect.getX() + rect.getWidth() / 2, rect .getY() + rect.getHeight() / 2); mxPoint p1 = new mxPoint(rect.getX(), rect.getY()); mxPoint p2 = new mxPoint(rect.getX() + rect.getWidth(), rect.getY()); mxPoint p3 = new mxPoint(p2.getX(), rect.getY() + rect.getHeight()); mxPoint p4 = new mxPoint(rect.getX(), p3.getY()); p1 = getRotatedPoint(p1, cos, sin, cx); p2 = getRotatedPoint(p2, cos, sin, cx); p3 = getRotatedPoint(p3, cos, sin, cx); p4 = getRotatedPoint(p4, cos, sin, cx); Rectangle tmp = new Rectangle((int) p1.getX(), (int) p1.getY(), 0, 0); tmp.add(p2.getPoint()); tmp.add(p3.getPoint()); tmp.add(p4.getPoint()); result = new mxRectangle(tmp); } return result; } /** * Rotates the given point by the given cos and sin. */ public static mxPoint getRotatedPoint(mxPoint pt, double cos, double sin) { return getRotatedPoint(pt, cos, sin, new mxPoint()); } /** * Rotates the given point by the given cos and sin. */ public static mxPoint getRotatedPoint(mxPoint pt, double cos, double sin, mxPoint c) { double x = pt.getX() - c.getX(); double y = pt.getY() - c.getY(); double x1 = x * cos - y * sin; double y1 = y * cos + x * sin; return new mxPoint(x1 + c.getX(), y1 + c.getY()); } /** * Draws the image inside the clip bounds to the given graphics object. */ public static void drawImageClip(Graphics g, BufferedImage image, ImageObserver observer) { Rectangle clip = g.getClipBounds(); if (clip != null) { int w = image.getWidth(); int h = image.getHeight(); int x = Math.max(0, Math.min(clip.x, w)); int y = Math.max(0, Math.min(clip.y, h)); w = Math.min(clip.width, w - x); h = Math.min(clip.height, h - y); if (w > 0 && h > 0) { // TODO: Support for normal images using fast subimage copies g.drawImage(image.getSubimage(x, y, w, h), clip.x, clip.y, observer); } } else { g.drawImage(image, 0, 0, observer); } } /** * */ public static void fillClippedRect(Graphics g, int x, int y, int width, int height) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -