com.mxgraph.canvas.mxVmlCanvas Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jgraphx Show documentation
Show all versions of jgraphx Show documentation
JGraphX Swing Component - Java Graph Visualization Library
This is a binary & source redistribution of the original, unmodified JGraphX library originating from:
"https://github.com/jgraph/jgraphx/archive/v3.4.1.3.zip".
The purpose of this redistribution is to make the library available to other Maven projects.
/**
* $Id: mxVmlCanvas.java,v 1.53 2011/03/17 10:40:57 gaudenz Exp $
* Copyright (c) 2007, Gaudenz Alder
*/
package com.mxgraph.canvas;
import java.awt.Rectangle;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxCellState;
/**
* An implementation of a canvas that uses VML for painting.
*/
public class mxVmlCanvas extends mxBasicCanvas
{
/**
* Holds the HTML document that represents the canvas.
*/
protected Document document;
/**
* Constructs a new VML canvas for the specified dimension and scale.
*/
public mxVmlCanvas()
{
this(null);
}
/**
* Constructs a new VML canvas for the specified bounds, scale and
* background color.
*/
public mxVmlCanvas(Document document)
{
setDocument(document);
}
/**
*
*/
public void setDocument(Document document)
{
this.document = document;
}
/**
* Returns a reference to the document that represents the canvas.
*
* @return Returns the document.
*/
public Document getDocument()
{
return document;
}
/**
*
*/
public void appendVmlElement(Element node)
{
if (document != null)
{
Node body = document.getDocumentElement().getFirstChild()
.getNextSibling();
if (body != null)
{
body.appendChild(node);
}
}
}
/* (non-Javadoc)
* @see com.mxgraph.canvas.mxICanvas#drawCell()
*/
public Object drawCell(mxCellState state)
{
Map style = state.getStyle();
Element elem = null;
if (state.getAbsolutePointCount() > 1)
{
List pts = state.getAbsolutePoints();
// Transpose all points by cloning into a new array
pts = mxUtils.translatePoints(pts, translate.x, translate.y);
// Draws the line
elem = drawLine(pts, style);
Element strokeNode = document.createElement("v:stroke");
// Draws the markers
String start = mxUtils.getString(style,
mxConstants.STYLE_STARTARROW);
String end = mxUtils.getString(style, mxConstants.STYLE_ENDARROW);
if (start != null || end != null)
{
if (start != null)
{
strokeNode.setAttribute("startarrow", start);
String startWidth = "medium";
String startLength = "medium";
double startSize = mxUtils.getFloat(style,
mxConstants.STYLE_STARTSIZE,
mxConstants.DEFAULT_MARKERSIZE)
* scale;
if (startSize < 6)
{
startWidth = "narrow";
startLength = "short";
}
else if (startSize > 10)
{
startWidth = "wide";
startLength = "long";
}
strokeNode.setAttribute("startarrowwidth", startWidth);
strokeNode.setAttribute("startarrowlength", startLength);
}
if (end != null)
{
strokeNode.setAttribute("endarrow", end);
String endWidth = "medium";
String endLength = "medium";
double endSize = mxUtils.getFloat(style,
mxConstants.STYLE_ENDSIZE,
mxConstants.DEFAULT_MARKERSIZE)
* scale;
if (endSize < 6)
{
endWidth = "narrow";
endLength = "short";
}
else if (endSize > 10)
{
endWidth = "wide";
endLength = "long";
}
strokeNode.setAttribute("endarrowwidth", endWidth);
strokeNode.setAttribute("endarrowlength", endLength);
}
}
if (mxUtils.isTrue(style, mxConstants.STYLE_DASHED))
{
strokeNode.setAttribute("dashstyle", "2 2");
}
elem.appendChild(strokeNode);
}
else
{
int x = (int) state.getX() + translate.x;
int y = (int) state.getY() + translate.y;
int w = (int) state.getWidth();
int h = (int) state.getHeight();
if (!mxUtils.getString(style, mxConstants.STYLE_SHAPE, "").equals(
mxConstants.SHAPE_SWIMLANE))
{
elem = drawShape(x, y, w, h, style);
if (mxUtils.isTrue(style, mxConstants.STYLE_DASHED))
{
Element strokeNode = document.createElement("v:stroke");
strokeNode.setAttribute("dashstyle", "2 2");
elem.appendChild(strokeNode);
}
}
else
{
int start = (int) Math.round(mxUtils.getInt(style,
mxConstants.STYLE_STARTSIZE,
mxConstants.DEFAULT_STARTSIZE)
* scale);
// Removes some styles to draw the content area
Map cloned = new Hashtable(
style);
cloned.remove(mxConstants.STYLE_FILLCOLOR);
cloned.remove(mxConstants.STYLE_ROUNDED);
if (mxUtils.isTrue(style, mxConstants.STYLE_HORIZONTAL, true))
{
elem = drawShape(x, y, w, start, style);
drawShape(x, y + start, w, h - start, cloned);
}
else
{
elem = drawShape(x, y, start, h, style);
drawShape(x + start, y, w - start, h, cloned);
}
}
}
return elem;
}
/*
* (non-Javadoc)
* @see com.mxgraph.canvas.mxICanvas#drawLabel()
*/
public Object drawLabel(String label, mxCellState state, boolean html)
{
mxRectangle bounds = state.getLabelBounds();
if (drawLabels && bounds != null)
{
int x = (int) bounds.getX() + translate.x;
int y = (int) bounds.getY() + translate.y;
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
Map style = state.getStyle();
return drawText(label, x, y, w, h, style);
}
return null;
}
/**
* Draws the shape specified with the STYLE_SHAPE key in the given style.
*
* @param x X-coordinate of the shape.
* @param y Y-coordinate of the shape.
* @param w Width of the shape.
* @param h Height of the shape.
* @param style Style of the the shape.
*/
public Element drawShape(int x, int y, int w, int h,
Map style)
{
String fillColor = mxUtils
.getString(style, mxConstants.STYLE_FILLCOLOR);
String strokeColor = mxUtils.getString(style,
mxConstants.STYLE_STROKECOLOR);
float strokeWidth = (float) (mxUtils.getFloat(style,
mxConstants.STYLE_STROKEWIDTH, 1) * scale);
// Draws the shape
String shape = mxUtils.getString(style, mxConstants.STYLE_SHAPE);
Element elem = null;
if (shape.equals(mxConstants.SHAPE_IMAGE))
{
String img = getImageForStyle(style);
if (img != null)
{
elem = document.createElement("v:img");
elem.setAttribute("src", img);
}
}
else if (shape.equals(mxConstants.SHAPE_LINE))
{
String direction = mxUtils.getString(style,
mxConstants.STYLE_DIRECTION, mxConstants.DIRECTION_EAST);
String points = null;
if (direction.equals(mxConstants.DIRECTION_EAST)
|| direction.equals(mxConstants.DIRECTION_WEST))
{
int mid = Math.round(h / 2);
points = "m 0 " + mid + " l " + w + " " + mid;
}
else
{
int mid = Math.round(w / 2);
points = "m " + mid + " 0 L " + mid + " " + h;
}
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_ELLIPSE))
{
elem = document.createElement("v:oval");
}
else if (shape.equals(mxConstants.SHAPE_DOUBLE_ELLIPSE))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
int inset = (int) ((3 + strokeWidth) * scale);
String points = "ar 0 0 " + w + " " + h + " 0 " + (h / 2) + " "
+ (w / 2) + " " + (h / 2) + " e ar " + inset + " " + inset
+ " " + (w - inset) + " " + (h - inset) + " 0 " + (h / 2)
+ " " + (w / 2) + " " + (h / 2);
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_RHOMBUS))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
String points = "m " + (w / 2) + " 0 l " + w + " " + (h / 2)
+ " l " + (w / 2) + " " + h + " l 0 " + (h / 2);
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_TRIANGLE))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
String direction = mxUtils.getString(style,
mxConstants.STYLE_DIRECTION, "");
String points = null;
if (direction.equals(mxConstants.DIRECTION_NORTH))
{
points = "m 0 " + h + " l " + (w / 2) + " 0 " + " l " + w + " "
+ h;
}
else if (direction.equals(mxConstants.DIRECTION_SOUTH))
{
points = "m 0 0 l " + (w / 2) + " " + h + " l " + w + " 0";
}
else if (direction.equals(mxConstants.DIRECTION_WEST))
{
points = "m " + w + " 0 l " + w + " " + (h / 2) + " l " + w
+ " " + h;
}
else
// east
{
points = "m 0 0 l " + w + " " + (h / 2) + " l 0 " + h;
}
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_HEXAGON))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
String direction = mxUtils.getString(style,
mxConstants.STYLE_DIRECTION, "");
String points = null;
if (direction.equals(mxConstants.DIRECTION_NORTH)
|| direction.equals(mxConstants.DIRECTION_SOUTH))
{
points = "m " + (int) (0.5 * w) + " 0 l " + w + " "
+ (int) (0.25 * h) + " l " + w + " " + (int) (0.75 * h)
+ " l " + (int) (0.5 * w) + " " + h + " l 0 "
+ (int) (0.75 * h) + " l 0 " + (int) (0.25 * h);
}
else
{
points = "m " + (int) (0.25 * w) + " 0 l " + (int) (0.75 * w)
+ " 0 l " + w + " " + (int) (0.5 * h) + " l "
+ (int) (0.75 * w) + " " + h + " l " + (int) (0.25 * w)
+ " " + h + " l 0 " + (int) (0.5 * h);
}
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_CLOUD))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
String points = "m " + (int) (0.25 * w) + " " + (int) (0.25 * h)
+ " c " + (int) (0.05 * w) + " " + (int) (0.25 * h) + " 0 "
+ (int) (0.5 * h) + " " + (int) (0.16 * w) + " "
+ (int) (0.55 * h) + " c 0 " + (int) (0.66 * h) + " "
+ (int) (0.18 * w) + " " + (int) (0.9 * h) + " "
+ (int) (0.31 * w) + " " + (int) (0.8 * h) + " c "
+ (int) (0.4 * w) + " " + (h) + " " + (int) (0.7 * w) + " "
+ (h) + " " + (int) (0.8 * w) + " " + (int) (0.8 * h)
+ " c " + (w) + " " + (int) (0.8 * h) + " " + (w) + " "
+ (int) (0.6 * h) + " " + (int) (0.875 * w) + " "
+ (int) (0.5 * h) + " c " + (w) + " " + (int) (0.3 * h)
+ " " + (int) (0.8 * w) + " " + (int) (0.1 * h) + " "
+ (int) (0.625 * w) + " " + (int) (0.2 * h) + " c "
+ (int) (0.5 * w) + " " + (int) (0.05 * h) + " "
+ (int) (0.3 * w) + " " + (int) (0.05 * h) + " "
+ (int) (0.25 * w) + " " + (int) (0.25 * h);
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_ACTOR))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
double width3 = w / 3;
String points = "m 0 " + (h) + " C 0 " + (3 * h / 5) + " 0 "
+ (2 * h / 5) + " " + (w / 2) + " " + (2 * h / 5) + " c "
+ (int) (w / 2 - width3) + " " + (2 * h / 5) + " "
+ (int) (w / 2 - width3) + " 0 " + (w / 2) + " 0 c "
+ (int) (w / 2 + width3) + " 0 " + (int) (w / 2 + width3)
+ " " + (2 * h / 5) + " " + (w / 2) + " " + (2 * h / 5)
+ " c " + (w) + " " + (2 * h / 5) + " " + (w) + " "
+ (3 * h / 5) + " " + (w) + " " + (h);
elem.setAttribute("path", points + " x e");
}
else if (shape.equals(mxConstants.SHAPE_CYLINDER))
{
elem = document.createElement("v:shape");
elem.setAttribute("coordsize", w + " " + h);
double dy = Math.min(40, Math.floor(h / 5));
String points = "m 0 " + (int) (dy) + " C 0 " + (int) (dy / 3)
+ " " + (w) + " " + (int) (dy / 3) + " " + (w) + " "
+ (int) (dy) + " L " + (w) + " " + (int) (h - dy) + " C "
+ (w) + " " + (int) (h + dy / 3) + " 0 "
+ (int) (h + dy / 3) + " 0 " + (int) (h - dy) + " x e"
+ " m 0 " + (int) (dy) + " C 0 " + (int) (2 * dy) + " "
+ (w) + " " + (int) (2 * dy) + " " + (w) + " " + (int) (dy);
elem.setAttribute("path", points + " e");
}
else
{
if (mxUtils.isTrue(style, mxConstants.STYLE_ROUNDED, false))
{
elem = document.createElement("v:roundrect");
elem.setAttribute("arcsize",
(mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) + "%");
}
else
{
elem = document.createElement("v:rect");
}
}
String s = "position:absolute;left:" + String.valueOf(x) + "px;top:"
+ String.valueOf(y) + "px;width:" + String.valueOf(w)
+ "px;height:" + String.valueOf(h) + "px;";
// Applies rotation
double rotation = mxUtils.getDouble(style, mxConstants.STYLE_ROTATION);
if (rotation != 0)
{
s += "rotation:" + rotation + ";";
}
elem.setAttribute("style", s);
// Adds the shadow element
if (mxUtils.isTrue(style, mxConstants.STYLE_SHADOW, false)
&& fillColor != null)
{
Element shadow = document.createElement("v:shadow");
shadow.setAttribute("on", "true");
shadow.setAttribute("color", mxConstants.W3C_SHADOWCOLOR);
elem.appendChild(shadow);
}
float opacity = mxUtils.getFloat(style, mxConstants.STYLE_OPACITY, 100);
// Applies opacity to fill
if (fillColor != null)
{
Element fill = document.createElement("v:fill");
fill.setAttribute("color", fillColor);
if (opacity != 100)
{
fill.setAttribute("opacity", String.valueOf(opacity / 100));
}
elem.appendChild(fill);
}
else
{
elem.setAttribute("filled", "false");
}
// Applies opacity to stroke
if (strokeColor != null)
{
elem.setAttribute("strokecolor", strokeColor);
Element stroke = document.createElement("v:stroke");
if (opacity != 100)
{
stroke.setAttribute("opacity", String.valueOf(opacity / 100));
}
elem.appendChild(stroke);
}
else
{
elem.setAttribute("stroked", "false");
}
elem.setAttribute("strokeweight", String.valueOf(strokeWidth) + "px");
appendVmlElement(elem);
return elem;
}
/**
* Draws the given lines as segments between all points of the given list
* of mxPoints.
*
* @param pts List of points that define the line.
* @param style Style to be used for painting the line.
*/
public Element drawLine(List pts, Map style)
{
String strokeColor = mxUtils.getString(style,
mxConstants.STYLE_STROKECOLOR);
float strokeWidth = (float) (mxUtils.getFloat(style,
mxConstants.STYLE_STROKEWIDTH, 1) * scale);
Element elem = document.createElement("v:shape");
if (strokeColor != null && strokeWidth > 0)
{
mxPoint pt = pts.get(0);
Rectangle r = new Rectangle(pt.getPoint());
StringBuilder buf = new StringBuilder("m " + Math.round(pt.getX())
+ " " + Math.round(pt.getY()));
for (int i = 1; i < pts.size(); i++)
{
pt = pts.get(i);
buf.append(" l " + Math.round(pt.getX()) + " "
+ Math.round(pt.getY()));
r = r.union(new Rectangle(pt.getPoint()));
}
String d = buf.toString();
elem.setAttribute("path", d);
elem.setAttribute("filled", "false");
elem.setAttribute("strokecolor", strokeColor);
elem.setAttribute("strokeweight", String.valueOf(strokeWidth)
+ "px");
String s = "position:absolute;" + "left:" + String.valueOf(r.x)
+ "px;" + "top:" + String.valueOf(r.y) + "px;" + "width:"
+ String.valueOf(r.width) + "px;" + "height:"
+ String.valueOf(r.height) + "px;";
elem.setAttribute("style", s);
elem.setAttribute("coordorigin",
String.valueOf(r.x) + " " + String.valueOf(r.y));
elem.setAttribute("coordsize", String.valueOf(r.width) + " "
+ String.valueOf(r.height));
}
appendVmlElement(elem);
return elem;
}
/**
* Draws the specified text either using drawHtmlString or using drawString.
*
* @param text Text to be painted.
* @param x X-coordinate of the text.
* @param y Y-coordinate of the text.
* @param w Width of the text.
* @param h Height of the text.
* @param style Style to be used for painting the text.
*/
public Element drawText(String text, int x, int y, int w, int h,
Map style)
{
Element table = mxUtils.createTable(document, text, x, y, w, h, scale,
style);
appendVmlElement(table);
return table;
}
}