~panisson/gephi/graphstreaming

« back to all changes in this revision

Viewing changes to PreviewPlugin/src/org/gephi/preview/plugin/renderers/EdgeLabelRenderer.java

  • Committer: Andre Panisson
  • Date: 2011-10-03 16:02:56 UTC
  • mfrom: (1433.1.1060 gephi)
  • Revision ID: panisson@gmail.com-20111003160256-s6215ky1vtyubl7d
Merge with main branch, revision 2492

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2008-2011 Gephi
 
3
Authors : Yudi Xue <yudi.xue@usask.ca>, Mathieu Bastian
 
4
Website : http://www.gephi.org
 
5
 
 
6
This file is part of Gephi.
 
7
 
 
8
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
9
 
 
10
Copyright 2011 Gephi Consortium. All rights reserved.
 
11
 
 
12
The contents of this file are subject to the terms of either the GNU
 
13
General Public License Version 3 only ("GPL") or the Common
 
14
Development and Distribution License("CDDL") (collectively, the
 
15
"License"). You may not use this file except in compliance with the
 
16
License. You can obtain a copy of the License at
 
17
http://gephi.org/about/legal/license-notice/
 
18
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
 
19
specific language governing permissions and limitations under the
 
20
License.  When distributing the software, include this License Header
 
21
Notice in each file and include the License files at
 
22
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
 
23
License Header, with the fields enclosed by brackets [] replaced by
 
24
your own identifying information:
 
25
"Portions Copyrighted [year] [name of copyright owner]"
 
26
 
 
27
If you wish your version of this file to be governed by only the CDDL
 
28
or only the GPL Version 3, indicate your decision by adding
 
29
"[Contributor] elects to include this software in this distribution
 
30
under the [CDDL or GPL Version 3] license." If you do not indicate a
 
31
single choice of license, a recipient has the option to distribute
 
32
your version of this file under either the CDDL, the GPL Version 3 or
 
33
to extend the choice of license to its licensees as provided above.
 
34
However, if you add GPL Version 3 code and therefore, elected the GPL
 
35
Version 3 license, then the option applies only if the new code is
 
36
made subject to such option by the copyright holder.
 
37
 
 
38
Contributor(s):
 
39
 
 
40
Portions Copyrighted 2011 Gephi Consortium.
 
41
 */
 
42
package org.gephi.preview.plugin.renderers;
 
43
 
 
44
import com.itextpdf.text.pdf.BaseFont;
 
45
import com.itextpdf.text.pdf.PdfContentByte;
 
46
import com.itextpdf.text.pdf.PdfGState;
 
47
import java.awt.BasicStroke;
 
48
import java.awt.Color;
 
49
import java.awt.Font;
 
50
import java.awt.FontMetrics;
 
51
import java.awt.Graphics2D;
 
52
import java.awt.Shape;
 
53
import java.awt.font.FontRenderContext;
 
54
import java.awt.font.GlyphVector;
 
55
import org.gephi.graph.api.Edge;
 
56
import org.gephi.preview.api.Item;
 
57
import org.gephi.preview.api.PDFTarget;
 
58
import org.gephi.preview.api.PreviewModel;
 
59
import org.gephi.preview.api.PreviewProperties;
 
60
import org.gephi.preview.api.PreviewProperty;
 
61
import org.gephi.preview.api.ProcessingTarget;
 
62
import org.gephi.preview.api.RenderTarget;
 
63
import org.gephi.preview.api.SVGTarget;
 
64
 
 
65
import org.gephi.preview.plugin.items.EdgeItem;
 
66
import org.gephi.preview.plugin.items.EdgeLabelItem;
 
67
 
 
68
import org.gephi.preview.plugin.items.NodeItem;
 
69
import org.gephi.preview.spi.Renderer;
 
70
import org.gephi.preview.types.DependantColor;
 
71
import org.gephi.preview.types.DependantOriginalColor;
 
72
import org.gephi.preview.types.EdgeColor;
 
73
import org.openide.util.NbBundle;
 
74
import org.openide.util.lookup.ServiceProvider;
 
75
import org.w3c.dom.Element;
 
76
import org.w3c.dom.Text;
 
77
import processing.core.PGraphics;
 
78
import processing.core.PGraphicsJava2D;
 
79
import processing.core.PVector;
 
80
 
 
81
/**
 
82
 *
 
83
 * @author Yudi Xue, Mathieu Bastian
 
84
 */
 
85
@ServiceProvider(service = Renderer.class, position = 500)
 
86
public class EdgeLabelRenderer implements Renderer {
 
87
    //Custom properties
 
88
 
 
89
    public static final String EDGE_COLOR = "edge.label.edgeColor";
 
90
    public static final String LABEL_X = "edge.label.x";
 
91
    public static final String LABEL_Y = "edge.label.y";
 
92
    //Default values
 
93
    protected final boolean defaultShowLabels = true;
 
94
    protected final Font defaultFont = new Font("Arial", Font.PLAIN, 10);
 
95
    protected final boolean defaultShorten = false;
 
96
    protected final DependantOriginalColor defaultColor = new DependantOriginalColor(DependantOriginalColor.Mode.ORIGINAL);
 
97
    protected final int defaultMaxChar = 30;
 
98
    protected final float defaultOutlineSize = 2;
 
99
    protected final DependantColor defaultOutlineColor = new DependantColor(Color.WHITE);
 
100
    protected final float defaultOutlineOpacity = 40;
 
101
    //Font cache
 
102
    protected Font font;
 
103
 
 
104
    public void preProcess(PreviewModel previewModel) {
 
105
        PreviewProperties properties = previewModel.getProperties();
 
106
        if (properties.getBooleanValue(PreviewProperty.EDGE_LABEL_SHORTEN)) {
 
107
            //Shorten labels
 
108
            Item[] EdgeLabelsItems = previewModel.getItems(Item.EDGE_LABEL);
 
109
 
 
110
            int maxChars = properties.getIntValue(PreviewProperty.EDGE_LABEL_MAX_CHAR);
 
111
            for (Item item : EdgeLabelsItems) {
 
112
                String label = item.getData(EdgeLabelItem.LABEL);
 
113
                if (label.length() >= maxChars + 3) {
 
114
                    label = label.substring(0, maxChars) + "...";
 
115
                    item.setData(EdgeLabelItem.LABEL, label);
 
116
                }
 
117
            }
 
118
        }
 
119
 
 
120
        //Put parent color, and calculate position
 
121
        for (Item item : previewModel.getItems(Item.EDGE_LABEL)) {
 
122
            Edge edge = (Edge) item.getSource();
 
123
            Item edgeItem = previewModel.getItem(Item.EDGE, edge);
 
124
            
 
125
            EdgeColor edgeColor = (EdgeColor) properties.getValue(PreviewProperty.EDGE_COLOR);  
 
126
            NodeItem sourceItem = (NodeItem) edgeItem.getData(EdgeRenderer.SOURCE);
 
127
            NodeItem targetItem = (NodeItem) edgeItem.getData(EdgeRenderer.TARGET);
 
128
            Color color = edgeColor.getColor((Color) item.getData(EdgeItem.COLOR),
 
129
                (Color) sourceItem.getData(NodeItem.COLOR),
 
130
                (Color) targetItem.getData(NodeItem.COLOR));
 
131
            item.setData(EDGE_COLOR, color);
 
132
            if (edge.isSelfLoop()) {
 
133
                //Middle
 
134
                Float x = sourceItem.getData(NodeItem.X);
 
135
                Float y = sourceItem.getData(NodeItem.Y);
 
136
                Float size = sourceItem.getData(NodeItem.SIZE);
 
137
 
 
138
                PVector v1 = new PVector(x, y);
 
139
                v1.add(size, -size, 0);
 
140
 
 
141
                PVector v2 = new PVector(x, y);
 
142
                v2.add(size, size, 0);
 
143
 
 
144
                PVector middle = bezierPoint(x, y, v1.x, v1.y, v2.x, v2.y, x, y, 0.5f);
 
145
                item.setData(LABEL_X, middle.x);
 
146
                item.setData(LABEL_Y, middle.y);
 
147
 
 
148
            } else if (properties.getBooleanValue(PreviewProperty.EDGE_CURVED)) {
 
149
                //Middle of the curve
 
150
                Float x1 = sourceItem.getData(NodeItem.X);
 
151
                Float x2 = targetItem.getData(NodeItem.X);
 
152
                Float y1 = sourceItem.getData(NodeItem.Y);
 
153
                Float y2 = targetItem.getData(NodeItem.Y);
 
154
 
 
155
                //Curved edgs
 
156
                PVector direction = new PVector(x2, y2);
 
157
                direction.sub(new PVector(x1, y1));
 
158
                float length = direction.mag();
 
159
                direction.normalize();
 
160
 
 
161
                float factor = properties.getFloatValue(EdgeRenderer.BEZIER_CURVENESS) * length;
 
162
 
 
163
                // normal vector to the edge
 
164
                PVector n = new PVector(direction.y, -direction.x);
 
165
                n.mult(factor);
 
166
 
 
167
                // first control point
 
168
                PVector v1 = new PVector(direction.x, direction.y);
 
169
                v1.mult(factor);
 
170
                v1.add(new PVector(x1, y1));
 
171
                v1.add(n);
 
172
 
 
173
                // second control point
 
174
                PVector v2 = new PVector(direction.x, direction.y);
 
175
                v2.mult(-factor);
 
176
                v2.add(new PVector(x2, y2));
 
177
                v2.add(n);
 
178
 
 
179
                PVector middle = bezierPoint(x1, y1, v1.x, v1.y, v2.x, v2.y, x2, y2, 0.5f);
 
180
                item.setData(LABEL_X, middle.x);
 
181
                item.setData(LABEL_Y, middle.y);
 
182
            } else {
 
183
                Float x = ((Float) sourceItem.getData(NodeItem.X) + (Float) targetItem.getData(NodeItem.X)) / 2f;
 
184
                Float y = ((Float) sourceItem.getData(NodeItem.Y) + (Float) targetItem.getData(NodeItem.Y)) / 2f;
 
185
                item.setData(LABEL_X, x);
 
186
                item.setData(LABEL_Y, y);
 
187
            }
 
188
        }
 
189
 
 
190
        //Property font
 
191
        font = properties.getFontValue(PreviewProperty.EDGE_LABEL_FONT);
 
192
    }
 
193
 
 
194
    public void render(Item item, RenderTarget target, PreviewProperties properties) {
 
195
        Edge edge = (Edge) item.getSource();
 
196
        //Label
 
197
        Color edgeColor = item.getData(EDGE_COLOR);
 
198
        Color color = item.getData(EdgeLabelItem.COLOR);
 
199
        DependantOriginalColor propColor = properties.getValue(PreviewProperty.EDGE_LABEL_COLOR);
 
200
        color = propColor.getColor(edgeColor, color);
 
201
        String label = item.getData(EdgeLabelItem.LABEL);
 
202
        Float x = item.getData(LABEL_X);
 
203
        Float y = item.getData(LABEL_Y);
 
204
 
 
205
        //Outline
 
206
        DependantColor outlineDependantColor = properties.getValue(PreviewProperty.EDGE_LABEL_OUTLINE_COLOR);
 
207
        Float outlineSize = properties.getFloatValue(PreviewProperty.EDGE_LABEL_OUTLINE_SIZE);
 
208
        outlineSize = outlineSize * (font.getSize() / 32f);
 
209
        int outlineAlpha = (int) ((properties.getFloatValue(PreviewProperty.EDGE_LABEL_OUTLINE_OPACITY) / 100f) * 255f);
 
210
        if (outlineAlpha > 255) {
 
211
            outlineAlpha = 255;
 
212
        }
 
213
        Color outlineColor = outlineDependantColor.getColor(edgeColor);
 
214
        outlineColor = new Color(outlineColor.getRed(), outlineColor.getGreen(), outlineColor.getBlue(), outlineAlpha);
 
215
 
 
216
        if (target instanceof ProcessingTarget) {
 
217
            renderProcessing((ProcessingTarget) target, label, x, y, color, outlineSize, outlineColor);
 
218
        } else if (target instanceof SVGTarget) {
 
219
            renderSVG((SVGTarget) target, edge, label, x, y, color, outlineSize, outlineColor);
 
220
        } else if (target instanceof PDFTarget) {
 
221
            renderPDF(((PDFTarget) target), label, x, y, color, outlineSize, outlineColor);
 
222
        }
 
223
    }
 
224
 
 
225
    public void renderProcessing(ProcessingTarget target, String label, float x, float y, Color color, float outlineSize, Color outlineColor) {
 
226
        PGraphics graphics = target.getGraphics();
 
227
        Graphics2D g2 = ((PGraphicsJava2D) graphics).g2;
 
228
        graphics.textAlign(PGraphics.CENTER, PGraphics.CENTER);
 
229
 
 
230
        g2.setFont(font);
 
231
 
 
232
        FontMetrics fm = g2.getFontMetrics();
 
233
        float posX = x - fm.stringWidth(label) / 2f;
 
234
        float posY = y + fm.getAscent() / 2f;
 
235
 
 
236
        if (outlineSize > 0) {
 
237
            FontRenderContext frc = g2.getFontRenderContext();
 
238
            GlyphVector gv = font.createGlyphVector(frc, label);
 
239
            Shape glyph = gv.getOutline(posX, posY);
 
240
            g2.setColor(outlineColor);
 
241
            g2.setStroke(new BasicStroke(outlineSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
 
242
            g2.draw(glyph);
 
243
        }
 
244
 
 
245
        g2.setColor(color);
 
246
        g2.drawString(label, posX, posY);
 
247
    }
 
248
 
 
249
    public void renderSVG(SVGTarget target, Edge edge, String label, float x, float y, Color color, float outlineSize, Color outlineColor) {
 
250
        Text labelText = target.createTextNode(label);
 
251
 
 
252
        if (outlineSize > 0) {
 
253
            Text labelTextOutline = target.createTextNode(label);
 
254
            Element outlineElem = target.createElement("text");
 
255
            outlineElem.setAttribute("class", edge.getEdgeData().getId());
 
256
            outlineElem.setAttribute("x", String.valueOf(x));
 
257
            outlineElem.setAttribute("y", String.valueOf(y));
 
258
            outlineElem.setAttribute("style", "text-anchor: middle; dominant-baseline: central;");
 
259
            outlineElem.setAttribute("fill", target.toHexString(color));
 
260
            outlineElem.setAttribute("font-family", font.getFamily());
 
261
            outlineElem.setAttribute("font-size", font.getSize() + "");
 
262
            outlineElem.setAttribute("stroke", target.toHexString(outlineColor));
 
263
            outlineElem.setAttribute("stroke-width", (outlineSize * target.getScaleRatio()) + "px");
 
264
            outlineElem.setAttribute("stroke-linecap", "round");
 
265
            outlineElem.setAttribute("stroke-linejoin", "round");
 
266
            outlineElem.setAttribute("stroke-opacity", String.valueOf(outlineColor.getAlpha() / 255f));
 
267
            outlineElem.appendChild(labelTextOutline);
 
268
            target.getTopElement(SVGTarget.TOP_NODE_LABELS_OUTLINE).appendChild(outlineElem);
 
269
        }
 
270
 
 
271
        Element labelElem = target.createElement("text");
 
272
        labelElem.setAttribute("class", edge.getEdgeData().getId());
 
273
        labelElem.setAttribute("x", x + "");
 
274
        labelElem.setAttribute("y", y + "");
 
275
        labelElem.setAttribute("style", "text-anchor: middle; dominant-baseline: central;");
 
276
        labelElem.setAttribute("fill", target.toHexString(color));
 
277
        labelElem.setAttribute("font-family", font.getFamily());
 
278
        labelElem.setAttribute("font-size", font.getSize() + "");
 
279
        labelElem.appendChild(labelText);
 
280
        target.getTopElement(SVGTarget.TOP_EDGE_LABELS).appendChild(labelElem);
 
281
    }
 
282
 
 
283
    public void renderPDF(PDFTarget target, String label, float x, float y, Color color, float outlineSize, Color outlineColor) {
 
284
        PdfContentByte cb = target.getContentByte();
 
285
        cb.setRGBColorFill(color.getRed(), color.getGreen(), color.getBlue());
 
286
        BaseFont bf = target.getBaseFont(font);
 
287
        float textHeight = getTextHeight(bf, font.getSize(), label);
 
288
        if (outlineSize > 0) {
 
289
            cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE);
 
290
            cb.setRGBColorStroke(outlineColor.getRed(), outlineColor.getGreen(), outlineColor.getBlue());
 
291
            cb.setLineWidth(outlineSize);
 
292
            cb.setLineJoin(PdfContentByte.LINE_JOIN_ROUND);
 
293
            cb.setLineCap(PdfContentByte.LINE_CAP_ROUND);
 
294
            if (outlineColor.getAlpha() < 255) {
 
295
                cb.saveState();
 
296
                float alpha = outlineColor.getAlpha() / 255f;
 
297
                PdfGState gState = new PdfGState();
 
298
                gState.setStrokeOpacity(alpha);
 
299
                cb.setGState(gState);
 
300
            }
 
301
            cb.beginText();
 
302
            cb.setFontAndSize(bf, font.getSize());
 
303
            cb.showTextAligned(PdfContentByte.ALIGN_CENTER, label, x, -y - (textHeight / 2f), 0f);
 
304
            cb.endText();
 
305
            if (outlineColor.getAlpha() < 255) {
 
306
                cb.restoreState();
 
307
            }
 
308
        }
 
309
        cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
 
310
        cb.beginText();
 
311
        cb.setFontAndSize(bf, font.getSize());
 
312
        cb.showTextAligned(PdfContentByte.ALIGN_CENTER, label, x, -y - (textHeight / 2f), 0f);
 
313
        cb.endText();
 
314
    }
 
315
 
 
316
    private float getTextHeight(BaseFont baseFont, float fontSize, String text) {
 
317
        float ascend = baseFont.getAscentPoint(text, fontSize);
 
318
        float descend = baseFont.getDescentPoint(text, fontSize);
 
319
        return ascend + descend;
 
320
    }
 
321
 
 
322
    public PreviewProperty[] getProperties() {
 
323
        return new PreviewProperty[]{
 
324
                    PreviewProperty.createProperty(this, PreviewProperty.SHOW_EDGE_LABELS, Boolean.class,
 
325
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.display.displayName"),
 
326
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.display.description"),
 
327
                    PreviewProperty.CATEGORY_EDGE_LABELS).setValue(defaultShowLabels),
 
328
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_FONT, Font.class,
 
329
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.font.displayName"),
 
330
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.font.description"),
 
331
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultFont),
 
332
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_COLOR, DependantOriginalColor.class,
 
333
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.color.displayName"),
 
334
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.color.description"),
 
335
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultColor),
 
336
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_SHORTEN, Boolean.class,
 
337
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.shorten.displayName"),
 
338
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.shorten.description"),
 
339
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultShorten),
 
340
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_MAX_CHAR, Integer.class,
 
341
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.maxchar.displayName"),
 
342
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.maxchar.description"),
 
343
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultMaxChar),
 
344
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_OUTLINE_SIZE, Float.class,
 
345
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineSize.displayName"),
 
346
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineSize.description"),
 
347
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultOutlineSize),
 
348
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_OUTLINE_COLOR, DependantColor.class,
 
349
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineColor.displayName"),
 
350
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineColor.description"),
 
351
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultOutlineColor),
 
352
                    PreviewProperty.createProperty(this, PreviewProperty.EDGE_LABEL_OUTLINE_OPACITY, Float.class,
 
353
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineOpacity.displayName"),
 
354
                    NbBundle.getMessage(EdgeLabelRenderer.class, "EdgeLabelRenderer.property.outlineOpacity.description"),
 
355
                    PreviewProperty.CATEGORY_EDGE_LABELS, PreviewProperty.SHOW_EDGE_LABELS).setValue(defaultOutlineOpacity),};
 
356
    }
 
357
 
 
358
    public boolean isRendererForitem(Item item, PreviewProperties properties) {
 
359
        return item instanceof EdgeLabelItem && properties.getBooleanValue(PreviewProperty.SHOW_EDGE_LABELS)
 
360
                && !properties.getBooleanValue(PreviewProperty.MOVING);
 
361
    }
 
362
 
 
363
    protected PVector bezierPoint(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float c) {
 
364
        PVector ab = linearInterpolation(x1, y1, x2, y2, c);
 
365
        PVector bc = linearInterpolation(x2, y2, x3, y3, c);
 
366
        PVector cd = linearInterpolation(x3, y3, x4, y4, c);
 
367
        PVector abbc = linearInterpolation(ab.x, ab.y, bc.x, bc.y, c);
 
368
        PVector bccd = linearInterpolation(bc.x, bc.y, cd.x, cd.y, c);
 
369
        return linearInterpolation(abbc.x, abbc.y, bccd.x, bccd.y, c);
 
370
    }
 
371
 
 
372
    protected PVector linearInterpolation(float x1, float y1, float x2, float y2, float c) {
 
373
        PVector r = new PVector(x1 + (x2 - x1) * c, y1 + (y2 - y1) * c);
 
374
        return r;
 
375
    }
 
376
}