Package com.mxgraph.canvas

Source Code of com.mxgraph.canvas.mxGraphicsCanvas2D

package com.mxgraph.canvas;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Stack;

import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.util.mxUtils;

/**
*
*/
public class mxGraphicsCanvas2D implements mxICanvas2D
{

  /**
   * Specifies the image scaling quality. Default is Image.SCALE_SMOOTH.
   * See {@link #scaleImage(Image, int, int)}
   */
  public static int IMAGE_SCALING = Image.SCALE_SMOOTH;

  /**
   * Reference to the graphics instance for painting.
   */
  protected Graphics2D graphics;

  /**
   * Represents the current state of the canvas.
   */
  protected transient CanvasState state = new CanvasState();

  /**
   * Stack of states for save/restore.
   */
  protected transient Stack<CanvasState> stack = new Stack<CanvasState>();

  /**
   * Holds the current path.
   */
  protected transient GeneralPath currentPath;

  /**
   * Holds the current stroke.
   */
  protected transient Stroke currentStroke;

  /**
   * Holds the current font.
   */
  protected transient Font currentFont;

  /**
   * Holds the current value for the shadow color. This is used to hold the
   * input value of a shadow operation. The parsing result of this value is
   * cached in the global scope as it should be repeating.
   */
  protected transient String currentShadowValue;

  /**
   * Holds the current parsed shadow color. This holds the result of parsing
   * the currentShadowValue, which is an expensive operation.
   */
  protected transient Color currentShadowColor;

  /**
   * Constructs a new graphics export canvas.
   */
  public mxGraphicsCanvas2D(Graphics2D g)
  {
    setGraphics(g);
    state.g = g;
  }

  /**
   * Sets the graphics instance.
   */
  public void setGraphics(Graphics2D value)
  {
    graphics = value;
  }

  /**
   * Returns the graphics instance.
   */
  public Graphics2D getGraphics()
  {
    return graphics;
  }

  /**
   * Saves the current canvas state.
   */
  public void save()
  {
    stack.push(state);
    state = cloneState(state);
    state.g = (Graphics2D) state.g.create();
  }

  /**
   * Restores the last canvas state.
   */
  public void restore()
  {
    state = stack.pop();

    // TODO: Check if stroke is part of graphics state
    currentStroke = state.g.getStroke();
    currentFont = state.g.getFont();
  }

  /**
   * Returns a clone of thec given state.
   */
  protected CanvasState cloneState(CanvasState state)
  {
    try
    {
      return (CanvasState) state.clone();
    }
    catch (CloneNotSupportedException e)
    {
      e.printStackTrace();
    }

    return null;
  }

  /**
   *
   */
  public void scale(double value)
  {
    // This implementation uses custom scale/translate and built-in rotation
    state.scale = state.scale * 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 rotate(double theta, boolean flipH, boolean flipV, double cx,
      double cy)
  {
    cx += state.dx;
    cy += state.dy;

    cx *= state.scale;
    cy *= state.scale;

    // This implementation uses custom scale/translate and built-in rotation
    // Rotation state is part of the AffineTransform in state.transform
    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.g.rotate(Math.toRadians(theta), cx, cy);
  }

  /**
   *
   */
  public void setStrokeWidth(double value)
  {
    // Lazy and cached instantiation strategy for all stroke properties
    if (value * state.scale != state.strokeWidth)
    {
      state.strokeWidth = value * state.scale;

      // Invalidates cached stroke
      currentStroke = null;
    }
  }

  /**
   * Caches color conversion as it is expensive.
   */
  public void setStrokeColor(String value)
  {
    // Lazy and cached instantiation strategy for all stroke properties
    if (!state.strokeColorValue.equals(value))
    {
      state.strokeColorValue = value;
      state.strokeColor = null;
    }
  }

  /**
   *
   */
  public void setDashed(boolean value)
  {
    // Lazy and cached instantiation strategy for all stroke properties
    if (value != state.dashed)
    {
      state.dashed = value;

      // Invalidates cached stroke
      currentStroke = null;
    }
  }

  /**
   *
   */
  public void setDashPattern(String value)
  {
    // FIXME: Initial dash pattern (3, 3) isn't scaled
    if (!state.dashPattern.equals(value))
    {
      float[] dashpattern = null;

      if (state.dashed && state.dashPattern != null)
      {
        String[] tokens = value.split(" ");
        dashpattern = new float[tokens.length];

        for (int i = 0; i < tokens.length; i++)
        {
          dashpattern[i] = (float) (Float.parseFloat(tokens[i]) * state.scale);
        }
      }

      state.dashPattern = dashpattern;
      currentStroke = null;
    }
  }

  /**
   *
   */
  public void setLineCap(String value)
  {
    if (!state.lineCap.equals(value))
    {
      state.lineCap = value;
      currentStroke = null;
    }
  }

  /**
   *
   */
  public void setLineJoin(String value)
  {
    if (!state.lineJoin.equals(value))
    {
      state.lineJoin = value;
      currentStroke = null;
    }
  }

  /**
   *
   */
  public void setMiterLimit(double value)
  {
    if (value != state.miterLimit)
    {
      state.miterLimit = value;
      currentStroke = null;
    }
  }

  /**
   *
   */
  public void setFontSize(double value)
  {
    if (value != state.fontSize)
    {
      state.fontSize = value * state.scale;
      currentFont = null;
    }
  }

  /**
   *
   */
  public void setFontColor(String value)
  {
    if (!state.fontColorValue.equals(value))
    {
      state.fontColorValue = value;
      state.fontColor = null;
    }
  }

  /**
   *
   */
  public void setFontFamily(String value)
  {
    if (!state.fontFamily.equals(value))
    {
      state.fontFamily = value;
      currentFont = null;
    }
  }

  /**
   *
   */
  public void setFontStyle(int value)
  {
    if (value != state.fontStyle)
    {
      state.fontStyle = value;
      currentFont = null;
    }
  }

  /**
   *
   */
  public void setAlpha(double value)
  {
    if (state.alpha != value)
    {
      state.g.setComposite(AlphaComposite.getInstance(
          AlphaComposite.SRC_OVER, (float) (value)));
      state.alpha = value;
    }
  }

  /**
   *
   */
  public void setFillColor(String value)
  {
    if (!state.fillColorValue.equals(value))
    {
      state.fillColorValue = value;
      state.fillColor = null;

      // Setting fill color resets paint color
      state.paint = null;
    }
  }

  /**
   *
   */
  public void setGradient(String color1, String color2, double x, double y,
      double w, double h, String direction)
  {
    // 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);
    }

    state.paint = new GradientPaint(x1, y1, parseColor(color1), x2, y2,
        parseColor(color2), true);
  }

  /**
   * Helper method that uses {@link mxUtils#parseColor(String)}. Subclassers
   * can override this to implement caching for frequently used colors.
   */
  protected Color parseColor(String hex)
  {
    return mxUtils.parseColor(hex);
  }

  /**
   *
   */
  public void setGlassGradient(double x, double y, double w, double h)
  {
    double size = 0.4;
    x = state.dx + x * state.scale;
    y = state.dy + y * state.scale;
    h *= state.scale;
    w *= state.scale;

    state.paint = new GradientPaint((float) x, (float) y, new Color(1, 1,
        1, 0.9f), (float) (x), (float) (y + h * size), new Color(1, 1,
        1, 0.3f));
  }

  /**
   *
   */
  public void rect(double x, double y, double w, double h)
  {
    currentPath = new GeneralPath();
    currentPath.append(new Rectangle2D.Double(state.dx + x * state.scale,
        state.dy + y * state.scale, w * state.scale, h * state.scale),
        false);
  }

  /**
   * Implements a rounded rectangle using a path.
   */
  public void roundrect(double x, double y, double w, double h, double dx,
      double dy)
  {
    begin();
    moveTo(x + dx, y);
    lineTo(x + w - dx, y);
    quadTo(x + w, y, x + w, y + dy);
    lineTo(x + w, y + h - dy);
    quadTo(x + w, y + h, x + w - dx, y + h);
    lineTo(x + dx, y + h);
    quadTo(x, y + h, x, y + h - dy);
    lineTo(x, y + dy);
    quadTo(x, y, x + dx, y);
    end();
  }

  /**
   *
   */
  public void ellipse(double x, double y, double w, double h)
  {
    currentPath = new GeneralPath();
    currentPath.append(new Ellipse2D.Double(state.dx + x * state.scale,
        state.dy + y * state.scale, w * state.scale, h * state.scale),
        false);
  }

  /**
   *
   */
  public void image(double x, double y, double w, double h, String src,
      boolean aspect, boolean flipH, boolean flipV)
  {
    if (src != null && w > 0 && h > 0)
    {
      Image img = loadImage(src);

      if (img != null)
      {
        mxRectangle bounds = getImageBounds(img, x, y, w, h, aspect);
        img = scaleImage(img, (int) bounds.getWidth(),
            (int) bounds.getHeight());

        if (img != null)
        {
          createImageGraphics(bounds.getX(), bounds.getY(),
              bounds.getWidth(), bounds.getHeight(), flipH, flipV)
              .drawImage(img, (int) bounds.getX(),
                  (int) bounds.getY(), null);
        }
      }
    }
  }

  /**
   * Hook for image caching.
   */
  protected Image loadImage(String src)
  {
    return mxUtils.loadImage(src);
  }

  /**
   *
   */
  protected final mxRectangle getImageBounds(Image img, double x, double y,
      double w, double h, boolean aspect)
  {
    x = state.dx + x * state.scale;
    y = state.dy + y * state.scale;
    w *= state.scale;
    h *= state.scale;

    if (aspect)
    {
      double iw = img.getWidth(null);
      double ih = img.getHeight(null);
      double s = Math.min(w / iw, h / ih);
      int sw = (int) Math.round(iw * s);
      int sh = (int) Math.round(ih * s);
      x += (w - sw) / 2;
      y += (h - sh) / 2;
      w = sw;
      h = sh;
    }
    else
    {
      w = Math.round(w);
      h = Math.round(h);
    }

    return new mxRectangle(x, y, w, h);
  }

  /**
   * Uses {@link #IMAGE_SCALING} to scale the given image.
   */
  protected Image scaleImage(Image img, int w, int h)
  {
    return img.getScaledInstance(w, h, IMAGE_SCALING);
  }

  /**
   * Creates a graphic instance for rendering an image.
   */
  protected final Graphics2D createImageGraphics(double x, double y,
      double w, double h, boolean flipH, boolean flipV)
  {
    Graphics2D g2 = state.g;

    if (flipH || flipV)
    {
      g2 = (Graphics2D) g2.create();
      int sx = 1;
      int sy = 1;
      int dx = 0;
      int dy = 0;

      if (flipH)
      {
        sx = -1;
        dx = (int) (-w - 2 * x);
      }

      if (flipV)
      {
        sy = -1;
        dy = (int) (-h - 2 * y);
      }

      g2.scale(sx, sy);
      g2.translate(dx, dy);
    }

    return g2;
  }

  /**
   * Draws the given text.
   */
  public void text(double x, double y, double w, double h, String str,
      String align, String valign, boolean vertical)
  {
    if (!state.fontColorValue.equals(mxConstants.NONE))
    {
      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, vertical);
      FontMetrics fm = g2.getFontMetrics();
      String[] lines = str.split("\n");

      y = getVerticalTextPosition(x, y, w, h, align, valign, vertical,
          fm, lines);
      x = getHorizontalTextPosition(x, y, w, h, align, valign, vertical,
          fm, lines);

      for (int i = 0; i < lines.length; i++)
      {
        double dx = 0;

        if (align.equals(mxConstants.ALIGN_CENTER))
        {
          int sw = fm.stringWidth(lines[i]);
          dx = (w - sw) / 2;
        }
        else if (align.equals(mxConstants.ALIGN_RIGHT))
        {
          int sw = fm.stringWidth(lines[i]);
          dx = w - sw;
        }

        g2.drawString(lines[i], (int) Math.round(x + dx),
            (int) Math.round(y));
        y += fm.getHeight() + mxConstants.LINESPACING;
      }
    }
  }

  /**
   * Returns a new graphincs instance with the correct color and font for
   * text rendering.
   */
  protected final Graphics2D createTextGraphics(double x, double y, double w,
      double h, boolean vertical)
  {
    Graphics2D g2 = state.g;
    updateFont();

    if (vertical)
    {
      g2 = (Graphics2D) state.g.create();
      g2.rotate(-Math.PI / 2, x + w / 2, y + h / 2);
    }

    if (state.fontColor == null)
    {
      state.fontColor = parseColor(state.fontColorValue);
    }

    g2.setColor(state.fontColor);

    return g2;
  }

  /**
   *
   */
  protected double getVerticalTextPosition(double x, double y, double w,
      double h, String align, String valign, boolean vertical,
      FontMetrics fm, String[] lines)
  {
    double lineHeight = fm.getHeight() + mxConstants.LINESPACING;
    double textHeight = lines.length * lineHeight;
    double dy = h - textHeight;

    if (valign == null || valign.equals(mxConstants.ALIGN_MIDDLE))
    {
      y = y + dy / 2;
    }
    else if (valign.equals(mxConstants.ALIGN_TOP))
    {
      y = Math.max(y, y + dy / 2);
    }
    else if (valign.equals(mxConstants.ALIGN_BOTTOM))
    {
      y = Math.min(y, y + dy);
    }

    return y + fm.getHeight() * 0.75;
  }

  /**
   *
   */
  protected double getHorizontalTextPosition(double x, double y, double w,
      double h, String align, String valign, boolean vertical,
      FontMetrics fm, String[] lines)
  {
    if (align != null)
    {
      if (align.equals(mxConstants.ALIGN_LEFT))
      {
        x += mxConstants.LABEL_INSET * state.scale;
      }
      else if (align.equals(mxConstants.ALIGN_RIGHT))
      {
        x -= mxConstants.LABEL_INSET * state.scale;
      }
    }

    return x;
  }

  /**
   *
   */
  public void begin()
  {
    currentPath = new GeneralPath();
  }

  /**
   *
   */
  public void moveTo(double x, double y)
  {
    if (currentPath != null)
    {
      currentPath.moveTo((float) (state.dx + x * state.scale),
          (float) (state.dy + y * state.scale));
    }
  }

  /**
   *
   */
  public void lineTo(double x, double y)
  {
    if (currentPath != null)
    {
      currentPath.lineTo((float) (state.dx + x * state.scale),
          (float) (state.dy + y * state.scale));
    }
  }

  /**
   *
   */
  public void quadTo(double x1, double y1, double x2, double y2)
  {
    if (currentPath != null)
    {
      currentPath.quadTo((float) (state.dx + x1 * state.scale),
          (float) (state.dy + y1 * state.scale),
          (float) (state.dx + x2 * state.scale),
          (float) (state.dy + y2 * state.scale));
    }
  }

  /**
   *
   */
  public void curveTo(double x1, double y1, double x2, double y2, double x3,
      double y3)
  {
    if (currentPath != null)
    {
      currentPath.curveTo((float) (state.dx + x1 * state.scale),
          (float) (state.dy + y1 * state.scale),
          (float) (state.dx + x2 * state.scale),
          (float) (state.dy + y2 * state.scale),
          (float) (state.dx + x3 * state.scale),
          (float) (state.dy + y3 * state.scale));
    }
  }

  /**
   *
   */
  public void arcTo(double rx, double ry, double xAxisRotation,
      boolean largeArc, boolean sweep, double x, double y)
  {
    if (currentPath != null)
    {
      rx *= state.scale;
      ry *= state.scale;

      x = x * state.scale + state.dx;
      y = y * state.scale + state.dy;

      Point2D currentPoint = currentPath.getCurrentPoint();
      double x0 = currentPoint.getX();
      double y0 = currentPoint.getY();

      // Compute the half distance between the current and the final point
      double dx2 = (x0 - x) / 2.0;
      double dy2 = (y0 - y) / 2.0;
      // Convert angle from degrees to radians
      xAxisRotation = Math.toRadians(xAxisRotation % 360.0);
      double cosAngle = Math.cos(xAxisRotation);
      double sinAngle = Math.sin(xAxisRotation);

      //
      // Step 1 : Compute (x1, y1)
      //
      double x1 = (cosAngle * dx2 + sinAngle * dy2);
      double y1 = (-sinAngle * dx2 + cosAngle * dy2);
      // Ensure radii are large enough
      rx = Math.abs(rx);
      ry = Math.abs(ry);
      double Prx = rx * rx;
      double Pry = ry * ry;
      double Px1 = x1 * x1;
      double Py1 = y1 * y1;
      // check that radii are large enough
      double radiiCheck = Px1 / Prx + Py1 / Pry;

      if (radiiCheck > 1)
      {
        rx = Math.sqrt(radiiCheck) * rx;
        ry = Math.sqrt(radiiCheck) * ry;
        Prx = rx * rx;
        Pry = ry * ry;
      }

      //
      // Step 2 : Compute (cx1, cy1)
      //
      double sign = (largeArc == sweep) ? -1 : 1;
      double sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1))
          / ((Prx * Py1) + (Pry * Px1));
      sq = (sq < 0) ? 0 : sq;
      double coef = (sign * Math.sqrt(sq));
      double cx1 = coef * ((rx * y1) / ry);
      double cy1 = coef * -((ry * x1) / rx);

      //
      // Step 3 : Compute (cx, cy) from (cx1, cy1)
      //
      double sx2 = (x0 + x) / 2.0;
      double sy2 = (y0 + y) / 2.0;
      double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
      double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);

      //
      // Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
      //
      double ux = (x1 - cx1) / rx;
      double uy = (y1 - cy1) / ry;
      double vx = (-x1 - cx1) / rx;
      double vy = (-y1 - cy1) / ry;
      double p, n;
      // Compute the angle start
      n = Math.sqrt((ux * ux) + (uy * uy));
      p = ux; // (1 * ux) + (0 * uy)
      sign = (uy < 0) ? -1.0 : 1.0;
      double angleStart = Math.toDegrees(sign * Math.acos(p / n));

      // Compute the angle extent
      n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
      p = ux * vx + uy * vy;
      sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
      double angleExtent = Math.toDegrees(sign * Math.acos(p / n));

      if (!sweep && angleExtent > 0)
      {
        angleExtent -= 360f;
      }
      else if (sweep && angleExtent < 0)
      {
        angleExtent += 360f;
      }

      angleExtent %= 360f;
      angleStart %= 360f;

      Arc2D.Double arc = new Arc2D.Double();
      arc.x = cx - rx;
      arc.y = cy - ry;
      arc.width = rx * 2.0;
      arc.height = ry * 2.0;
      arc.start = -angleStart;
      arc.extent = -angleExtent;

      currentPath.append(arc, true);
    }
  }

  /**
   * This implementation is typically empty.
   */
  public void end()
  {
    // Do nothing
  }

  /**
   * Closes the current path.
   */
  public void close()
  {
    if (currentPath != null)
    {
      currentPath.closePath();
    }
  }

  /**
   *
   */
  public void stroke()
  {
    if (currentPath != null
        && !state.strokeColorValue.equals(mxConstants.NONE))
    {
      if (state.strokeColor == null)
      {
        state.strokeColor = parseColor(state.strokeColorValue);
      }

      updateStroke();
      state.g.setColor(state.strokeColor);
      state.g.draw(currentPath);
    }
  }

  /**
   *
   */
  public void fill()
  {
    if (currentPath != null
        && (!state.fillColorValue.equals(mxConstants.NONE) || state.paint != null))
    {
      if (state.paint != null)
      {
        state.g.setPaint(state.paint);
        state.paint = null;
      }
      else
      {
        if (state.fillColor == null)
        {
          state.fillColor = parseColor(state.fillColorValue);
        }

        state.g.setColor(state.fillColor);
        state.g.setPaint(null);
      }

      state.g.fill(currentPath);
    }
  }

  /**
   *
   */
  public void fillAndStroke()
  {
    fill();
    stroke();
  }

  /**
   *
   */
  public void shadow(String value)
  {
    if (value != null && currentPath != null)
    {
      if (currentShadowColor == null || currentShadowValue == null
          || !currentShadowValue.equals(value))
      {
        currentShadowColor = parseColor(value);
        currentShadowValue = value;
      }

      updateStroke();
      state.g.setColor(currentShadowColor);
      state.g.fill(currentPath);
      state.g.draw(currentPath);
    }
  }

  /**
   *
   */
  public void clip()
  {
    if (currentPath != null)
    {
      state.g.clip(currentPath);
    }
  }

  /**
   *
   */
  protected void updateFont()
  {
    // LATER: Make currentFont part of state
    if (currentFont == null)
    {
      int size = (int) Math.round(state.fontSize);
      int style = ((state.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) ? Font.BOLD
          : Font.PLAIN;
      style += ((state.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) ? Font.ITALIC
          : Font.PLAIN;

      currentFont = createFont(state.fontFamily, style, size);
      state.g.setFont(currentFont);
    }
  }

  /**
   * Hook for subclassers to implement font caching.
   */
  protected Font createFont(String family, int style, int size)
  {
    return new Font(family, style, size);
  }

  /**
   *
   */
  protected void updateStroke()
  {
    if (currentStroke == null)
    {
      int cap = BasicStroke.CAP_BUTT;

      if (state.lineCap.equals("round"))
      {
        cap = BasicStroke.CAP_ROUND;
      }
      else if (state.lineCap.equals("square"))
      {
        cap = BasicStroke.CAP_SQUARE;
      }

      int join = BasicStroke.JOIN_MITER;

      if (state.lineJoin.equals("round"))
      {
        join = BasicStroke.JOIN_ROUND;
      }
      else if (state.lineJoin.equals("bevel"))
      {
        join = BasicStroke.JOIN_BEVEL;
      }

      float miterlimit = (float) state.miterLimit;

      currentStroke = new BasicStroke((float) state.strokeWidth, cap,
          join, miterlimit,
          (state.dashed) ? state.dashPattern : null, 0);
      state.g.setStroke(currentStroke);
    }
  }

  /**
   *
   */
  protected class CanvasState implements Cloneable
  {
    /**
     *
     */
    protected double alpha = 1;

    /**
     *
     */
    protected double scale = 1;

    /**
     *
     */
    protected double dx = 0;

    /**
     *
     */
    protected double dy = 0;

    /**
     *
     */
    protected double miterLimit = 10;

    /**
     *
     */
    protected int fontStyle = 0;

    /**
     *
     */
    protected double fontSize = mxConstants.DEFAULT_FONTSIZE;

    /**
     *
     */
    protected String fontFamily = mxConstants.DEFAULT_FONTFAMILY;

    /**
     *
     */
    protected String fontColorValue = "#000000";

    /**
     *
     */
    protected Color fontColor;

    /**
     *
     */
    protected String lineCap = "flat";

    /**
     *
     */
    protected String lineJoin = "miter";

    /**
     *
     */
    protected double strokeWidth = 1;

    /**
     *
     */
    protected String strokeColorValue = mxConstants.NONE;

    /**
     *
     */
    protected Color strokeColor;

    /**
     *
     */
    protected String fillColorValue = mxConstants.NONE;

    /**
     *
     */
    protected Color fillColor;

    /**
     *
     */
    protected Paint paint;

    /**
     *
     */
    protected boolean dashed = false;

    /**
     *
     */
    protected float[] dashPattern = { 3, 3 };

    /**
     * Stores the actual state.
     */
    protected transient Graphics2D g;

    /**
     *
     */
    public Object clone() throws CloneNotSupportedException
    {
      return super.clone();
    }

  }

}
TOP

Related Classes of com.mxgraph.canvas.mxGraphicsCanvas2D

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.