提交 56b5e660 编写于 作者: J Jérémy Subtil

Compute the preview canvas size from the rendered elements

上级 7095e542
......@@ -42,15 +42,14 @@
package org.gephi.preview;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import org.gephi.preview.api.CanvasSize;
import org.gephi.preview.api.G2DTarget;
import org.gephi.preview.api.PreviewController;
import org.gephi.preview.api.PreviewModel;
......@@ -162,7 +161,6 @@ public class G2DRenderTargetBuilder implements RenderTargetBuilder {
public static class G2DGraphics {
private final PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class);
private PreviewModel model;
private boolean inited;
//Drawing
private final Image image;
......@@ -186,11 +184,11 @@ public class G2DRenderTargetBuilder implements RenderTargetBuilder {
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
}
public void refresh(PreviewModel previewModel, RenderTarget target) {
this.model = previewModel;
if (model != null) {
background = model.getProperties().getColorValue(PreviewProperty.BACKGROUND_COLOR);
initAppletLayout();
public void refresh(PreviewModel m, RenderTarget target) {
if (m != null) {
background = m.getProperties()
.getColorValue(PreviewProperty.BACKGROUND_COLOR);
initAppletLayout(m);
g2.clearRect(0, 0, width, height);
g2.setTransform(new AffineTransform());
......@@ -251,23 +249,22 @@ public class G2DRenderTargetBuilder implements RenderTargetBuilder {
* Initializes the preview applet layout according to the graph's
* dimension.
*/
private void initAppletLayout() {
private void initAppletLayout(PreviewModel m) {
// graphSheet.setMargin(MARGIN);
if (!inited && model != null && model.getDimensions() != null && model.getTopLeftPosition() != null) {
if (!inited) {
// initializes zoom
Dimension dimensions = model.getDimensions();
Point topLeftPostition = model.getTopLeftPosition();
Vector box = new Vector((float) dimensions.getWidth(), (float) dimensions.getHeight());
CanvasSize cs = m.getGraphicsCanvasSize();
Vector box = new Vector(cs.getWidth(), cs.getHeight());
float ratioWidth = width / box.x;
float ratioHeight = height / box.y;
scaling = ratioWidth < ratioHeight ? ratioWidth : ratioHeight;
// initializes move
Vector semiBox = Vector.div(box, 2);
Vector topLeftVector = new Vector((float) topLeftPostition.x, (float) topLeftPostition.y);
Vector center = new Vector(width / 2f, height / 2f);
Vector scaledCenter = Vector.add(topLeftVector, semiBox);
Vector topLeft = new Vector(cs.getX(), cs.getY());
Vector center = new Vector(width / 2F, height / 2F);
Vector scaledCenter = Vector.add(topLeft, semiBox);
trans.set(center);
trans.sub(scaledCenter);
// lastMove.set(trans);
......
......@@ -42,11 +42,11 @@ Portions Copyrighted 2011 Gephi Consortium.
package org.gephi.preview;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import java.awt.geom.AffineTransform;
import org.gephi.preview.api.CanvasSize;
import org.gephi.preview.api.PDFTarget;
import org.gephi.preview.api.PreviewModel;
import org.gephi.preview.api.PreviewProperties;
......@@ -60,40 +60,43 @@ import org.openide.util.lookup.ServiceProvider;
/**
* Default implementation to PDFRenderTargetBuilder.
*
*
* @author Mathieu Bastian
*/
@ServiceProvider(service = RenderTargetBuilder.class)
public class PDFRenderTargetBuilder implements RenderTargetBuilder {
@Override
public String getName() {
return RenderTarget.PDF_TARGET;
}
@Override
public RenderTarget buildRenderTarget(PreviewModel previewModel) {
double width = previewModel.getDimensions().getWidth();
double height = previewModel.getDimensions().getHeight();
width = Math.max(1, width);
height = Math.max(1, height);
int topLeftX = previewModel.getTopLeftPosition().x;
int topLeftY = previewModel.getTopLeftPosition().y;
CanvasSize cs = previewModel.getGraphicsCanvasSize();
PreviewProperties properties = previewModel.getProperties();
float marginBottom = properties.getFloatValue(PDFTarget.MARGIN_BOTTOM);
float marginLeft = properties.getFloatValue(PDFTarget.MARGIN_LEFT);
float marginRight = properties.getFloatValue(PDFTarget.MARGIN_RIGHT);
float marginTop = properties.getFloatValue(PDFTarget.MARGIN_TOP);
Rectangle pageSize = properties.getValue(PDFTarget.PAGESIZE);
com.itextpdf.text.Rectangle pageSize
= properties.getValue(PDFTarget.PAGESIZE);
boolean landscape = properties.getBooleanValue(PDFTarget.LANDSCAPE);
PdfContentByte cb = properties.getValue(PDFTarget.PDF_CONTENT_BYTE);
PDFRenderTargetImpl renderTarget = new PDFRenderTargetImpl(cb, width, height, topLeftX, topLeftY,
pageSize, marginLeft, marginRight, marginTop, marginBottom, landscape);
PDFRenderTargetImpl renderTarget = new PDFRenderTargetImpl(
cb,
cs,
pageSize,
marginLeft,
marginRight,
marginTop,
marginBottom,
landscape);
return renderTarget;
}
public static class PDFRenderTargetImpl extends AbstractRenderTarget implements PDFTarget {
private final PdfContentByte cb;
private static boolean fontRegistered = false;
//Parameters
......@@ -102,10 +105,17 @@ public class PDFRenderTargetBuilder implements RenderTargetBuilder {
private final float marginLeft;
private final float marginRight;
private final boolean landscape;
private final Rectangle pageSize;
public PDFRenderTargetImpl(PdfContentByte cb, double width, double height, double topLeftX, double topLeftY,
Rectangle size, float marginLeft, float marginRight, float marginTop, float marginBottom, boolean landscape) {
private final com.itextpdf.text.Rectangle pageSize;
public PDFRenderTargetImpl(
PdfContentByte cb,
CanvasSize cs,
com.itextpdf.text.Rectangle size,
float marginLeft,
float marginRight,
float marginTop,
float marginBottom,
boolean landscape) {
this.cb = cb;
this.marginTop = marginTop;
this.marginLeft = marginLeft;
......@@ -113,35 +123,35 @@ public class PDFRenderTargetBuilder implements RenderTargetBuilder {
this.marginRight = marginRight;
this.pageSize = size;
this.landscape = landscape;
double centerX = topLeftX + width / 2;
double centerY = topLeftY + height / 2;
double centerX = cs.getX() + cs.getWidth() / 2;
double centerY = cs.getY() + cs.getHeight() / 2;
//Transform
double pageWidth = size.getWidth() - marginLeft - marginRight;
double pageHeight = size.getHeight() - marginTop - marginBottom;
double ratioWidth = pageWidth / width;
double ratioHeight = pageHeight / height;
double ratioWidth = pageWidth / cs.getWidth();
double ratioHeight = pageHeight / cs.getHeight();
double scale = (float) (ratioWidth < ratioHeight ? ratioWidth : ratioHeight);
double translateX = (marginLeft + pageWidth / 2.) / scale;
double translateY = (marginBottom + pageHeight / 2.) / scale;
cb.transform(AffineTransform.getTranslateInstance(-centerX * scale, centerY * scale));
cb.transform(AffineTransform.getScaleInstance(scale, scale));
cb.transform(AffineTransform.getTranslateInstance(translateX, translateY));
FontFactory.register("/org/gephi/preview/fonts/LiberationSans.ttf", "ArialMT");
}
@Override
public PdfContentByte getContentByte() {
return this.cb;
}
@Override
public BaseFont getBaseFont(java.awt.Font font) {
try {
if (font != null) {
BaseFont baseFont = null;
BaseFont baseFont;
if (!font.getFontName().equals(FontFactory.COURIER)
&& !font.getFontName().equals(FontFactory.COURIER_BOLD)
&& !font.getFontName().equals(FontFactory.COURIER_OBLIQUE)
......@@ -159,28 +169,28 @@ public class PDFRenderTargetBuilder implements RenderTargetBuilder {
&& !font.getFontName().equals(FontFactory.COURIER_BOLD)
&& !font.getFontName().equals(FontFactory.COURIER_BOLD)
&& !font.getFontName().equals(FontFactory.COURIER_BOLD)) {
com.itextpdf.text.Font itextFont = FontFactory.getFont(font.getFontName(), BaseFont.IDENTITY_H, font.getSize(), font.getStyle());
baseFont = itextFont.getBaseFont();
if (baseFont == null && !PDFRenderTargetImpl.fontRegistered) {
if (progressTicket != null) {
String displayName = progressTicket.getDisplayName();
Progress.setDisplayName(progressTicket, NbBundle.getMessage(PDFRenderTargetImpl.class, "PDFRenderTargetImpl.font.registration"));
registerFonts();
Progress.setDisplayName(progressTicket, displayName);
}
itextFont = FontFactory.getFont(font.getFontName(), BaseFont.IDENTITY_H, font.getSize(), font.getStyle());
baseFont = itextFont.getBaseFont();
PDFRenderTargetImpl.fontRegistered = true;
}
} else {
com.itextpdf.text.Font itextFont = FontFactory.getFont(font.getFontName(), BaseFont.IDENTITY_H, font.getSize(), font.getStyle());
baseFont = itextFont.getBaseFont();
}
if (baseFont != null) {
return baseFont;
}
......@@ -192,7 +202,7 @@ public class PDFRenderTargetBuilder implements RenderTargetBuilder {
}
return null;
}
private void registerFonts() {
FontFactory.registerDirectories();
if (Utilities.isMac()) {
......@@ -205,34 +215,34 @@ public class PDFRenderTargetBuilder implements RenderTargetBuilder {
FontFactory.registerDirectory(adobeFonts);
}
}
@Override
public float getMarginBottom() {
return marginBottom;
}
@Override
public float getMarginLeft() {
return marginLeft;
}
@Override
public float getMarginRight() {
return marginRight;
}
@Override
public float getMarginTop() {
return marginTop;
}
@Override
public boolean isLandscape() {
return landscape;
}
@Override
public Rectangle getPageSize() {
public com.itextpdf.text.Rectangle getPageSize() {
return pageSize;
}
}
......
......@@ -41,8 +41,6 @@
*/
package org.gephi.preview;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import org.gephi.graph.api.*;
......@@ -182,10 +180,6 @@ public class PreviewControllerImpl implements PreviewController {
graphModel.destroyView(graph.getView());
}
//Refresh dimensions
updateDimensions(previewModel, previewModel.getItems(Item.NODE));
//Pre process renderers
for (Renderer r : renderers) {
r.preProcess(model);
......@@ -202,42 +196,6 @@ public class PreviewControllerImpl implements PreviewController {
return false;
}
public void updateDimensions(PreviewModelImpl model, Item[] nodeItems) {
float margin = model.getProperties().getFloatValue(PreviewProperty.MARGIN); //percentage
float topLeftX = 0f;
float topLeftY = 0f;
float bottomRightX = 0f;
float bottomRightY = 0f;
for (Item nodeItem : nodeItems) {
float x = (Float) nodeItem.getData("x");
float y = (Float) nodeItem.getData("y");
float s = ((Float) nodeItem.getData("size")) / 2f;
if (x - s < topLeftX) {
topLeftX = x - s;
}
if (y - s < topLeftY) {
topLeftY = y - s;
}
if (x + s > bottomRightX) {
bottomRightX = x + s;
}
if (y + s > bottomRightY) {
bottomRightY = y + s;
}
}
float marginWidth = (bottomRightX - topLeftX) * (margin / 100f);
float marginHeight = (bottomRightY - topLeftY) * (margin / 100f);
topLeftX -= marginWidth;
topLeftY -= marginHeight;
bottomRightX += marginWidth;
bottomRightY += marginHeight;
model.setDimensions(new Dimension((int) (bottomRightX - topLeftX), (int) (bottomRightY - topLeftY)));
model.setTopLeftPosition(new Point((int) topLeftX, (int) topLeftY));
}
@Override
public void render(RenderTarget target) {
PreviewModelImpl m = getModel();
......
......@@ -41,8 +41,7 @@
*/
package org.gephi.preview;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.beans.PropertyEditorManager;
import java.util.*;
import java.util.Map.Entry;
......@@ -81,9 +80,6 @@ public class PreviewModelImpl implements PreviewModel {
private PreviewMouseListener[] enabledMouseListeners;
//Properties
private PreviewProperties properties;
//Dimensions
private Dimension dimensions;
private Point topLeftPosition;
public PreviewModelImpl(Workspace workspace) {
this(workspace, null);
......@@ -233,10 +229,6 @@ public class PreviewModelImpl implements PreviewModel {
sourceMap.put(item.getSource(), item);
} else if (value instanceof List) {
((List) value).add(item);
} else {
List<Item> list = new ArrayList<Item>();
list.add((Item) value);
list.add(item);
}
}
} else {
......@@ -281,21 +273,24 @@ public class PreviewModelImpl implements PreviewModel {
}
@Override
public Dimension getDimensions() {
return dimensions;
}
@Override
public Point getTopLeftPosition() {
return topLeftPosition;
}
public void setDimensions(Dimension dimensions) {
this.dimensions = dimensions;
}
public void setTopLeftPosition(Point topLeftPosition) {
this.topLeftPosition = topLeftPosition;
public CanvasSize getGraphicsCanvasSize() {
Rectangle.Float rect = new Rectangle.Float();
for (Renderer r : getManagedEnabledRenderers()) {
for (String type : getItemTypes()) {
for (Item item : getItems(type)) {
if (r.isRendererForitem(item, getProperties())) {
CanvasSize cs = r.getCanvasSize(item, getProperties());
Rectangle.Float itemRect = new Rectangle.Float(
cs.getX(),
cs.getY(),
cs.getWidth(),
cs.getHeight());
java.awt.geom.Rectangle2D.union(rect, itemRect, rect);
}
}
}
}
return new CanvasSize(rect.x, rect.y, rect.width, rect.height);
}
@Override
......@@ -362,8 +357,8 @@ public class PreviewModelImpl implements PreviewModel {
@Override
public void setManagedRenderers(ManagedRenderer[] managedRenderers) {
//Validate no null ManagedRenderers
for (int i = 0; i < managedRenderers.length; i++) {
if (managedRenderers[i] == null) {
for (ManagedRenderer managedRenderer : managedRenderers) {
if (managedRenderer == null) {
throw new IllegalArgumentException("managedRenderers should not contain null values");
}
}
......
......@@ -51,6 +51,7 @@ import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.gephi.preview.api.CanvasSize;
import org.gephi.preview.api.PreviewModel;
import org.gephi.preview.api.RenderTarget;
import org.gephi.preview.api.SVGTarget;
......@@ -71,15 +72,12 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
@Override
public RenderTarget buildRenderTarget(PreviewModel previewModel) {
int width = (int) previewModel.getDimensions().getWidth();
int height = (int) previewModel.getDimensions().getHeight();
width = Math.max(1, width);
height = Math.max(1, height);
int topLeftX = previewModel.getTopLeftPosition().x;
int topLeftY = previewModel.getTopLeftPosition().y;
boolean scaleStrokes = previewModel.getProperties().getBooleanValue(SVGTarget.SCALE_STROKES);
SVGRenderTargetImpl renderTarget = new SVGRenderTargetImpl(width, height, topLeftX, topLeftY, scaleStrokes);
CanvasSize cs = previewModel.getGraphicsCanvasSize();
boolean scaleStrokes = previewModel.getProperties()
.getBooleanValue(SVGTarget.SCALE_STROKES);
SVGRenderTargetImpl renderTarget
= new SVGRenderTargetImpl(cs, scaleStrokes);
return renderTarget;
}
......@@ -88,13 +86,14 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
return RenderTarget.SVG_TARGET;
}
public static class SVGRenderTargetImpl extends AbstractRenderTarget implements SVGTarget {
public static class SVGRenderTargetImpl
extends AbstractRenderTarget implements SVGTarget {
private Document document;
private final Document document;
private float scaleRatio = 1f;
private Map<String, Element> topElements = new HashMap<String, Element>();
private final Map<String, Element> topElements = new HashMap<String, Element>();
public SVGRenderTargetImpl(int width, int height, int topLeftX, int topLeftY, boolean scaleStrokes) {
public SVGRenderTargetImpl(CanvasSize cs, boolean scaleStrokes) {
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
DocumentType doctype = impl.createDocumentType(
"-//W3C//DTD SVG 1.1//EN",
......@@ -111,27 +110,36 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
builder.build(ctx, document);
//Dimension
SupportSize supportSize = new SupportSize(595, 841, LengthUnit.PIXELS);
if (width > height) {
supportSize = new SupportSize(width * supportSize.getHeightInt() / height, supportSize.getHeightInt(), LengthUnit.PIXELS);
} else if (height > width) {
supportSize = new SupportSize(supportSize.getWidthInt(), height * supportSize.getWidthInt() / width, LengthUnit.PIXELS);
SupportSize ss = new SupportSize(595F, 841F, LengthUnit.PIXELS);
if (cs.getWidth() > cs.getHeight()) {
ss = new SupportSize(
cs.getWidth() * ss.getHeightFloat() / cs.getHeight(),
ss.getHeightFloat(),
LengthUnit.PIXELS);
} else if (cs.getHeight() > cs.getWidth()) {
ss = new SupportSize(
ss.getWidthFloat(),
cs.getHeight() * ss.getWidthFloat() / cs.getWidth(),
LengthUnit.PIXELS);
}
// root element
Element svgRoot = document.getDocumentElement();
svgRoot.setAttributeNS(null, "width", supportSize.getWidth());
svgRoot.setAttributeNS(null, "height", supportSize.getHeight());
svgRoot.setAttributeNS(null, "width", cs.getWidth() + "");
svgRoot.setAttributeNS(null, "height", cs.getHeight() + "");
svgRoot.setAttributeNS(null, "version", "1.1");
svgRoot.setAttributeNS(null, "viewBox", String.format(Locale.ENGLISH, "%d %d %d %d",
topLeftX,
topLeftY,
width,
height));
svgRoot.setAttributeNS(
null,
"viewBox",
String.format(Locale.ENGLISH, "%f %f %f %f",
cs.getX(),
cs.getY(),
cs.getWidth(),
cs.getHeight()));
//Scale & ratio
if (scaleStrokes) {
scaleRatio = supportSize.getWidthInt() / (float) width;
scaleRatio = ss.getWidthFloat() / cs.getWidth();
}
}
......@@ -190,8 +198,8 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
*/
public static class SupportSize {
private final Integer width;
private final Integer height;
private final float width;
private final float height;
private final LengthUnit lengthUnit;
/**
......@@ -201,17 +209,17 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
* @param height the support's height
* @param lengthUnit the lenght unit
*/
public SupportSize(int width, int height, LengthUnit lengthUnit) {
public SupportSize(float width, float height, LengthUnit lengthUnit) {
this.width = width;
this.height = height;
this.lengthUnit = lengthUnit;
}
}
public Integer getWidthInt() {
public float getWidthFloat() {
return width;
}
public Integer getHeightInt() {
public float getHeightFloat() {
return height;
}
......@@ -221,7 +229,7 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
* @return the support's width
*/
public String getWidth() {
return width.toString() + lengthUnit.toString();
return width + lengthUnit.toString();
}
/**
......@@ -230,7 +238,7 @@ public class SVGRenderTargetBuilder implements RenderTargetBuilder {
* @return the support's height
*/
public String getHeight() {
return height.toString() + lengthUnit.toString();
return height + lengthUnit.toString();
}
}
......
/*
Copyright 2008-2011 Gephi
Authors : Jeremy Subtil
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.preview.api;
/**
* A canvas size, with a top left coordinate, a width and an heigth.
*
* @author Jeremy Subtil
*/
public class CanvasSize {
private final float x;
private final float y;
private final float width;
private final float height;
/**
* Constructor.
*
* @param x The x coordinate of the top left position
* @param y The y coordinate of the top left position
* @param width The canvas width
* @param height The canvas height
*/
public CanvasSize(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
* Constructs the default <code>CanvasSize</code>, with both width and
* height equal to zero.
*/
public CanvasSize() {
this(0F, 0F, 0F, 0F);
}
/**
* Return the x coordinate of the top left position.
*
* @return the x coordinate of the top left position
*/
public float getX() {
return x;
}
/**
* Returns the y coordinate of the top left position.
*
* @return the y coordinate of the top left position
*/
public float getY() {
return y;
}
/**
* Returs the canvas width.
*
* @return the canvas width
*/
public float getWidth() {
return width;
}
/**
* Returs the canvas height.
*
* @return the canvas height
*/
public float getHeight() {
return height;
}
}
......@@ -41,8 +41,6 @@
*/
package org.gephi.preview.api;
import java.awt.Dimension;
import java.awt.Point;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.Node;
......@@ -137,16 +135,9 @@ public interface PreviewModel {
public PreviewMouseListener[] getEnabledMouseListeners();
/**
* Returns the width and height of the graph in the graph coordinates.
* Computes the graphics canvas size.
*
* @return the graph dimensions
* @return the graphics canvas size
*/
public Dimension getDimensions();
/**
* Returns the top left position in the graph coordinate (i.e. not the preview coordinates).
*
* @return the top left position point
*/
public Point getTopLeftPosition();
public CanvasSize getGraphicsCanvasSize();
}
......@@ -61,7 +61,7 @@ import org.gephi.preview.api.*;
* <code>render()</code> which is called many times.</li>
* <li>The <code>isRendererForitem()</code> is then used to determine which renderer
* should be used to render an item. The method provides an access to the preview
* properties. For instance, if the properties says the edge display is disabled,
* properties. For instance, if the properties says the edge display is disabled,
* the edge renderer should return <code>false</code> for every item. Note that
* nothing avoids several renderer to returns <code>true</code> for the same item.</li>
* <li>The <code>render()</code> method is finally called for every item which
......@@ -99,7 +99,7 @@ import org.gephi.preview.api.*;
* @author Yudi Xue, Mathieu Bastian
*/
public interface Renderer {
/**
* Provides an user friendly name for the renderer.
* This name will appear in the renderers manager UI.
......@@ -109,14 +109,14 @@ public interface Renderer {
/**
* This method is called before rendering for all renderers and initializes
* items' additional attributes or run complex algorithms.
* items' additional attributes or run complex algorithms.
* <p>
* This method has access to any item using the <code>getItems()</code> methods
* of the preview model.
* <p>
* No data should be stored in the renderer itself but put in items using
* No data should be stored in the renderer itself but put in items using
* {@link Item#setData(java.lang.String, java.lang.Object)}. Global states can
* be stored in properties using
* be stored in properties using
* {@link PreviewProperties#putValue(java.lang.String, java.lang.Object)}.
* @param previewModel the model to get items from
*/
......@@ -126,25 +126,25 @@ public interface Renderer {
* Render <code>item</code> to <code>target</code> using the global properties
* and item data.
* <p>
* The target can be one of the default target {@link G2DTarget},
* {@link SVGTarget} or {@link PDFTarget}. Each target contains an access to
* The target can be one of the default target {@link G2DTarget},
* {@link SVGTarget} or {@link PDFTarget}. Each target contains an access to
* it's drawing canvas so the renderer can draw visual items.
* @param item the item to be rendered
* @param target the target to render the item on
* @param properties the central properties
*/
public void render(Item item, RenderTarget target, PreviewProperties properties);
/**
* Returns all associated properties for this renderer. Properties can be built
* using static <code>PreviewProperty.createProperty()</code> methods.
*
* using static <code>PreviewProperty.createProperty()</code> methods.
*
* @return a properties array
*/
public PreviewProperty[] getProperties();
/**
* Based on <code>properties</code>, determine whether this renderer is
* Based on <code>properties</code>, determine whether this renderer is
* valid to render <code>Item</code>.
* <p>
* Additional states in <code>properties</code> helps to make a decision,
......@@ -161,7 +161,7 @@ public interface Renderer {
* renderer, <code>false</code> otherwise
*/
public boolean isRendererForitem(Item item, PreviewProperties properties);
/**
* Based on the <code>itemBuilder</code> class and the <code>properties</code>,
* determine whether this renderer needs the given <code>itemBuilder</code> to be
......@@ -172,7 +172,7 @@ public interface Renderer {
* You can simply return true if the builder builds items that this renderer renders,
* but you can also check the current properties to see if your renderer is going to produce any graphic.
* <p>
*
*
* Additional states in <code>properties</code> helps to make a decision,
* including:
* <ul>
......@@ -182,8 +182,21 @@ public interface Renderer {
* other than the node renderer usually render nothing while the user is moving
* to speeds things up.</li></ul>
* @param itemBuilder builder that your renderer may need
* @param properties Current properties
* @param properties the current properties
* @return <code>true</code> if you are going to use built items for rendering, <code>false</code> otherwise
*/
public boolean needsItemBuilder(ItemBuilder itemBuilder, PreviewProperties properties);
/**
* Compute the canvas size of the item to render.
*
* The returned <code>CanvasSize</code> has to embed the whole item to
* render. If the canvas size cannot be computed, a <code>CanvasSize</code>
* with both width and height equlal to zero is returned.
*
* @param item the item to get the canvas size
* @param properties the current properties
* @return the item canvas size
*/
public CanvasSize getCanvasSize(Item item, PreviewProperties properties);
}
......@@ -47,7 +47,7 @@ import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.util.Locale;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Node;
import org.gephi.preview.api.*;
import org.gephi.preview.plugin.builders.EdgeBuilder;
import org.gephi.preview.plugin.builders.NodeBuilder;
......@@ -55,7 +55,6 @@ import org.gephi.preview.plugin.items.EdgeItem;
import org.gephi.preview.plugin.items.NodeItem;
import org.gephi.preview.spi.ItemBuilder;
import org.gephi.preview.spi.Renderer;
import org.gephi.preview.types.EdgeColor;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.w3c.dom.Element;
......@@ -77,93 +76,43 @@ public class ArrowRenderer implements Renderer {
}
@Override
public void render(Item item, RenderTarget target, PreviewProperties properties) {
float size = properties.getFloatValue(PreviewProperty.ARROW_SIZE);
if (size > 0) {
//Get nodes
Item sourceItem = item.getData(EdgeRenderer.SOURCE);
Item targetItem = item.getData(EdgeRenderer.TARGET);
//Weight and color
Double weight = item.getData(EdgeItem.WEIGHT);
EdgeColor edgeColor = (EdgeColor) properties.getValue(PreviewProperty.EDGE_COLOR);
Color color = edgeColor.getColor((Color) item.getData(EdgeItem.COLOR),
(Color) sourceItem.getData(NodeItem.COLOR),
(Color) targetItem.getData(NodeItem.COLOR));
int alpha = (int) ((properties.getFloatValue(PreviewProperty.EDGE_OPACITY) / 100f) * 255f);
color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
//Size and radius
float radius = properties.getFloatValue(PreviewProperty.EDGE_RADIUS);
size *= weight;
radius = -(radius + (Float) targetItem.getData(NodeItem.SIZE) / 2f + Math.max(0, properties.getFloatValue(PreviewProperty.NODE_BORDER_WIDTH)));
//Avoid arrow from passing the node's center:
if (radius > 0) {
radius = 0;
}
//3 points
Float x1 = sourceItem.getData(NodeItem.X);
Float x2 = targetItem.getData(NodeItem.X);
Float y1 = sourceItem.getData(NodeItem.Y);
Float y2 = targetItem.getData(NodeItem.Y);
if (properties.getBooleanValue(PreviewProperty.EDGE_CURVED)) {
} else {
renderStraight(target, item, x1, y1, x2, y2, radius, size, color);
}
}
}
public void renderStraight(RenderTarget target, Item item, float x1, float y1, float x2, float y2, float radius, float size, Color color) {
Edge edge = (Edge) item.getSource();
Vector direction = new Vector(x2, y2);
direction.sub(new Vector(x1, y1));
direction.normalize();
Vector p1 = new Vector(direction.x, direction.y);
p1.mult(radius);
p1.add(new Vector(x2, y2));
Vector p1r = new Vector(direction.x, direction.y);
p1r.mult(radius - size);
p1r.add(new Vector(x2, y2));
Vector p2 = new Vector(-direction.y, direction.x);
p2.mult(size * BASE_RATIO);
p2.add(p1r);
Vector p3 = new Vector(direction.y, -direction.x);
p3.mult(size * BASE_RATIO);
p3.add(p1r);
public void render(
final Item item,
final RenderTarget target,
final PreviewProperties properties) {
final Helper h = new Helper(item, properties);
final Color color = EdgeRenderer.getColor(item, properties);
if (target instanceof G2DTarget) {
Graphics2D graphics = ((G2DTarget) target).getGraphics();
graphics.setColor(color);
GeneralPath gpath = new GeneralPath();
gpath.moveTo(p1.x, p1.y);
gpath.lineTo(p2.x, p2.y);
gpath.lineTo(p3.x, p3.y);
final GeneralPath gpath = new GeneralPath();
gpath.moveTo(h.p1.x, h.p1.y);
gpath.lineTo(h.p2.x, h.p2.y);
gpath.lineTo(h.p3.x, h.p3.y);
gpath.closePath();
graphics.fill(gpath);
} else if (target instanceof SVGTarget) {
SVGTarget svgTarget = (SVGTarget) target;
Element arrowElem = svgTarget.createElement("polyline");
arrowElem.setAttribute("points", String.format(Locale.ENGLISH, "%f,%f %f,%f %f,%f",
p1.x, p1.y, p2.x, p2.y, p3.x, p3.y));
arrowElem.setAttribute("class", edge.getSource().getId() + " " + edge.getTarget().getId());
final SVGTarget svgTarget = (SVGTarget) target;
final Element arrowElem = svgTarget.createElement("polyline");
arrowElem.setAttribute("points", String.format(
Locale.ENGLISH,
"%f,%f %f,%f %f,%f",
h.p1.x, h.p1.y, h.p2.x, h.p2.y, h.p3.x, h.p3.y));
arrowElem.setAttribute("class", String.format(
"%s %s",
((Node) h.sourceItem.getSource()).getId(),
((Node) h.targetItem.getSource()).getId()));
arrowElem.setAttribute("fill", svgTarget.toHexString(color));
arrowElem.setAttribute("fill-opacity", (color.getAlpha() / 255f) + "");
arrowElem.setAttribute("stroke", "none");
svgTarget.getTopElement(SVGTarget.TOP_ARROWS).appendChild(arrowElem);
} else if (target instanceof PDFTarget) {
PDFTarget pdfTarget = (PDFTarget) target;
PdfContentByte cb = pdfTarget.getContentByte();
cb.moveTo(p1.x, -p1.y);
cb.lineTo(p2.x, -p2.y);
cb.lineTo(p3.x, -p3.y);
final PDFTarget pdfTarget = (PDFTarget) target;
final PdfContentByte cb = pdfTarget.getContentByte();
cb.moveTo(h.p1.x, -h.p1.y);
cb.lineTo(h.p2.x, -h.p2.y);
cb.lineTo(h.p3.x, -h.p3.y);
cb.closePath();
cb.setRGBColorFill(color.getRed(), color.getGreen(), color.getBlue());
if (color.getAlpha() < 255) {
......@@ -180,6 +129,20 @@ public class ArrowRenderer implements Renderer {
}
}
@Override
public CanvasSize getCanvasSize(
final Item item,
final PreviewProperties properties) {
final Helper h = new Helper(item, properties);
final float minX = Math.min(Math.min(h.p1.x, h.p2.x), h.p3.x);
final float minY = Math.min(Math.min(h.p1.y, h.p2.y), h.p3.y);
final float maxX = Math.max(Math.max(h.p1.x, h.p2.x), h.p3.x);
final float maxY = Math.max(Math.max(h.p1.y, h.p2.y), h.p3.y);
return properties.getBooleanValue(PreviewProperty.EDGE_CURVED)
? new CanvasSize()
: new CanvasSize(minX, minY, maxX - minX, maxY - minY);
}
@Override
public PreviewProperty[] getProperties() {
return new PreviewProperty[]{
......@@ -190,21 +153,83 @@ public class ArrowRenderer implements Renderer {
}
private boolean showArrows(PreviewProperties properties) {
return properties.getBooleanValue(PreviewProperty.SHOW_EDGES) && properties.getBooleanValue(PreviewProperty.DIRECTED) && !properties.getBooleanValue(PreviewProperty.MOVING);
return properties.getBooleanValue(PreviewProperty.SHOW_EDGES)
&& properties.getBooleanValue(PreviewProperty.DIRECTED)
&& !properties.getBooleanValue(PreviewProperty.EDGE_CURVED)
&& !properties.getBooleanValue(PreviewProperty.MOVING);
}
@Override
public boolean isRendererForitem(Item item, PreviewProperties properties) {
return item instanceof EdgeItem && showArrows(properties) && (Boolean) item.getData(EdgeItem.DIRECTED) && !(Boolean) item.getData(EdgeItem.SELF_LOOP);
return item instanceof EdgeItem
&& showArrows(properties)
&& (Boolean) item.getData(EdgeItem.DIRECTED)
&& !(Boolean) item.getData(EdgeItem.SELF_LOOP);
}
@Override
public boolean needsItemBuilder(ItemBuilder itemBuilder, PreviewProperties properties) {
return (itemBuilder instanceof EdgeBuilder || itemBuilder instanceof NodeBuilder) && showArrows(properties);//Needs some properties of nodes
return (itemBuilder instanceof EdgeBuilder
|| itemBuilder instanceof NodeBuilder)
&& showArrows(properties);//Needs some properties of nodes
}
@Override
public String getDisplayName() {
return NbBundle.getMessage(ArrowRenderer.class, "ArrowRenderer.name");
}
private class Helper {
public final Item sourceItem;
public final Item targetItem;
public final Vector p1;
public final Vector p2;
public final Vector p3;
public Helper(
final Item item,
final PreviewProperties properties) {
sourceItem = item.getData(EdgeRenderer.SOURCE);
targetItem = item.getData(EdgeRenderer.TARGET);
final Float x1 = sourceItem.getData(NodeItem.X);
final Float x2 = targetItem.getData(NodeItem.X);
final Float y1 = sourceItem.getData(NodeItem.Y);
final Float y2 = targetItem.getData(NodeItem.Y);
final Double weight = item.getData(EdgeItem.WEIGHT);
final float size = properties.getFloatValue(PreviewProperty.ARROW_SIZE)
* weight.floatValue();
float radius = -(properties.getFloatValue(PreviewProperty.EDGE_RADIUS)
+ (Float) targetItem.getData(NodeItem.SIZE) / 2f
+ Math.max(0, properties.getFloatValue(
PreviewProperty.NODE_BORDER_WIDTH)));
//Avoid arrow from passing the node's center:
if (radius > 0) {
radius = 0;
}
final Vector direction = new Vector(x2, y2);
direction.sub(new Vector(x1, y1));
direction.normalize();
p1 = new Vector(direction.x, direction.y);
p1.mult(radius);
p1.add(new Vector(x2, y2));
final Vector p1r = new Vector(direction.x, direction.y);
p1r.mult(radius - size);
p1r.add(new Vector(x2, y2));
p2 = new Vector(-direction.y, direction.x);
p2.mult(size * BASE_RATIO);
p2.add(p1r);
p3 = new Vector(direction.y, -direction.x);
p3.mult(size * BASE_RATIO);
p3.add(p1r);
}
}
}
......@@ -44,7 +44,12 @@ package org.gephi.preview.plugin.renderers;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import java.awt.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import org.gephi.graph.api.Edge;
......@@ -211,6 +216,14 @@ public class EdgeLabelRenderer implements Renderer {
}
}
@Override
public CanvasSize getCanvasSize(
final Item item,
final PreviewProperties properties) {
//FIXME Compute the label canvas
return new CanvasSize();
}
public void renderG2D(G2DTarget target, String label, float x, float y, Color color, float outlineSize, Color outlineColor) {
Graphics2D graphics = target.getGraphics();
......
......@@ -44,7 +44,12 @@ package org.gephi.preview.plugin.renderers;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import java.awt.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
......@@ -185,6 +190,14 @@ public class NodeLabelRenderer implements Renderer {
}
}
@Override
public CanvasSize getCanvasSize(
final Item item,
final PreviewProperties properties) {
//FIXME Compute the label canvas
return new CanvasSize();
}
public void renderG2D(G2DTarget target, String label, float x, float y, int fontSize, Color color, float outlineSize, Color outlineColor, boolean showBox, Color boxColor) {
Graphics2D graphics = target.getGraphics();
......
......@@ -85,6 +85,23 @@ public class NodeRenderer implements Renderer {
}
}
@Override
public CanvasSize getCanvasSize(
final Item item,
final PreviewProperties properties) {
final float x = item.getData(NodeItem.X);
final float y = item.getData(NodeItem.Y);
final float s = (Float) item.getData(NodeItem.SIZE)
+ properties.getFloatValue(PreviewProperty.NODE_BORDER_WIDTH);
final float r = s / 2F;
final int intS = Math.round(s);
return new CanvasSize(
Math.round(x - r),
Math.round(y - r),
intS,
intS);
}
public void renderG2D(Item item, G2DTarget target, PreviewProperties properties) {
//Params
Float x = item.getData(NodeItem.X);
......@@ -138,7 +155,9 @@ public class NodeRenderer implements Renderer {
nodeElem.setAttribute("fill-opacity", "" + alpha);
if (borderSize > 0) {
nodeElem.setAttribute("stroke", target.toHexString(borderColor));
nodeElem.setAttribute("stroke-width", new Float(borderSize * target.getScaleRatio()).toString());
nodeElem.setAttribute(
"stroke-width",
Float.toString(borderSize * target.getScaleRatio()));
nodeElem.setAttribute("stroke-opacity", "" + alpha);
}
target.getTopElement(SVGTarget.TOP_NODES).appendChild(nodeElem);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册