![JAR search and dependency download from the Maven repository](/logo.png)
org.graphstream.ui.j2dviewer.J2DGraphRenderer.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gs-ui Show documentation
Show all versions of gs-ui Show documentation
The GraphStream library. With GraphStream you deal with
graphs. Static and Dynamic. You create them from scratch, from a file
or any source. You display and render them.
The newest version!
/*
* Copyright 2006 - 2015
* Stefan Balev
* Julien Baudry
* Antoine Dutot
* Yoann Pigné
* Guilhelm Savin
*
* This file is part of GraphStream .
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
package org.graphstream.ui.j2dviewer
import java.awt.{Container, Graphics2D}
import java.util.ArrayList
import java.io.{File, IOException}
import java.awt.image.BufferedImage
import java.util.logging.Logger
import scala.collection.JavaConversions._
import org.graphstream.ui.geom.Point3
import org.graphstream.graph.Element
import org.graphstream.ui.swingViewer.{GraphRenderer, LayerRenderer}
import org.graphstream.ui.graphicGraph.{GraphicGraph, GraphicElement, GraphicNode, GraphicEdge, GraphicSprite, StyleGroup, StyleGroupListener}
import org.graphstream.ui.graphicGraph.stylesheet.Selector
import org.graphstream.ui.util.Selection
import org.graphstream.ui.j2dviewer.renderer._
import javax.imageio.ImageIO
import org.graphstream.ui.util.FPSLogger
import org.graphstream.ui.swingViewer.util.Graphics2DOutput
object J2DGraphRenderer {
val DEFAULT_RENDERER = "j2d_def_rndr";
}
/**
* 2D renderer.
*
* The role of this class is to equip each style group with a specific renderer and
* to call these renderer to redraw the graph when needed. The renderers then equip
* each node, edge and sprite with a skeleton that gives is main geometry, then
* selects a shape according to the group style. The shape will be "applied" to
* each element to draw in the group. The shape will be moved and scaled according
* to the skeleton.
*
* A render pass begins by using the camera instance to set up the projection (allows
* to pass from graph units to pixels, make a rotation a zoom or a translation) and
* render each style group once for the shadows, and once for the real rendering
* in Z order.
*
* This class also handles a "selection" object that represents the current selection
* and renders it.
*
* The renderer uses a backend so that it can adapt to multiple rendering
* targets (here Swing and OpenGL). As the shapes are finally responsible
* for drawing the graph, the backend is also responsible for the shape
* creation.
*/
class J2DGraphRenderer extends GraphRenderer with StyleGroupListener {
// Attribute
/** Set the view on the view port defined by the metrics. */
protected var camera:Camera = null
/** The graph to render. */
protected var graph:GraphicGraph = null
/** The current selection. */
protected val selection = new Selection
/** The layer renderer for the background (under the graph), can be null. */
protected var backRenderer:LayerRenderer = null
/** The layer renderer for the foreground (above the graph), can be null. */
protected var foreRenderer:LayerRenderer = null
/** The rendering backend. */
protected var backend:Backend = null
protected var fpsLogger:FPSLogger = null
// Construction
def open(graph:GraphicGraph, drawingSurface:Container) {
if( this.graph == null ) {
this.graph = graph
this.backend = new BackendJ2D // choose it according to some setting
this.camera = new Camera(graph)
graph.getStyleGroups.addListener(this)
backend.open(drawingSurface)
} else {
throw new RuntimeException("renderer already open, use close() first")
}
}
def close() {
if(graph != null) {
if(fpsLogger ne null) {
fpsLogger.close
fpsLogger = null
}
removeRenderers
backend.close
graph.getStyleGroups.removeListener(this)
graph = null
backend = null
camera = null
}
}
// Access
def getCamera():org.graphstream.ui.view.Camera = camera
def findNodeOrSpriteAt(x:Double, y:Double):GraphicElement = camera.findNodeOrSpriteAt(graph, x, y)
def allNodesOrSpritesIn(x1:Double, y1:Double, x2:Double, y2:Double):ArrayList[GraphicElement] = camera.allNodesOrSpritesIn(graph, x1, y1, x2, y2)
def renderingSurface:Container = backend.drawingSurface
// Access -- Renderer bindings
/** Get (and assign if needed) a style renderer to the graphic graph. The renderer will be reused then. */
protected def getStyleRenderer(graph:GraphicGraph):GraphBackgroundRenderer = {
if(graph.getStyle.getRenderer("dr") == null)
graph.getStyle.addRenderer("dr", new GraphBackgroundRenderer(graph, graph.getStyle))
graph.getStyle.getRenderer("dr").asInstanceOf[GraphBackgroundRenderer]
}
/** Get (and assign if needed) a style renderer to a style group. The renderer will be reused then. */
protected def getStyleRenderer(style:StyleGroup):StyleRenderer = {
if( style.getRenderer("dr") == null)
style.addRenderer("dr", StyleRenderer(style, this))
style.getRenderer("dr").asInstanceOf[StyleRenderer]
}
/** Get (and assign if needed) the style renderer associated with the style group of the element. */
protected def getStyleRenderer(element:GraphicElement):StyleRenderer = {
getStyleRenderer(element.getStyle)
}
/** Remove all the registered renderers from the graphic graph. */
protected def removeRenderers() {
graph.getStyle.removeRenderer("dr")
graph.getNodeIterator.foreach { node:GraphicNode => node.getStyle.removeRenderer("dr") }
graph.getEdgeIterator.foreach { edge:GraphicEdge => edge.getStyle.removeRenderer("dr") }
graph.getSpriteIterator.foreach { sprite:GraphicSprite => sprite.getStyle.removeRenderer("dr") }
}
// Command
def beginSelectionAt(x:Double, y:Double) {
selection.active = true
selection.begins(x, y)
Logger.getLogger(this.getClass.getSimpleName).fine("Selection begins at %f %f.".format(x, y))
}
def selectionGrowsAt(x:Double, y:Double) {
selection.grows(x, y)
}
def endSelectionAt(x:Double, y:Double) {
selection.grows(x, y)
selection.active = false
}
def moveElementAtPx(element:GraphicElement, x:Double, y:Double) {
val p = camera.transformPxToGu(x, y)
element.move(p.x, p.y, element.getZ)
}
// Commands -- Rendering
def render(g:Graphics2D, x:Int, y:Int, width:Int, height:Int) {
if(graph != null) {
startFrame
// Verify this view is not closed, the Swing repaint mechanism may trigger 1 or 2
// calls to this after being closed.
if(backend eq null)
backend = new BackendJ2D // TODO choose it according to some setting ...
backend.prepareNewFrame(g)
camera.setBackend(backend)
val sgs = graph.getStyleGroups
setupGraphics
graph.computeBounds
camera.setBounds(graph)
camera.setViewport(x, y, width, height)
getStyleRenderer(graph).render(backend, camera, width, height)
renderBackLayer
camera.pushView(graph)
sgs.shadows.foreach {
getStyleRenderer(_).renderShadow(backend, camera)
}
sgs.zIndex.foreach { groups =>
groups.foreach { group =>
if(group.getType != Selector.Type.GRAPH) {
getStyleRenderer(group).render(backend, camera)
}
}
}
camera.popView
renderForeLayer
if( selection.renderer == null ) selection.renderer = new SelectionRenderer( selection, graph )
selection.renderer.render(backend, camera, width, height )
endFrame
}
}
protected def startFrame() {
if((fpsLogger eq null) && graph.hasLabel("ui.log")) {
fpsLogger = new FPSLogger(graph.getLabel("ui.log"))
}
if(! (fpsLogger eq null))
fpsLogger.beginFrame
}
protected def endFrame() {
if(! (fpsLogger eq null))
fpsLogger.endFrame
}
protected def renderBackLayer() { if(backRenderer ne null) renderLayer(backRenderer) }
protected def renderForeLayer() { if(foreRenderer ne null) renderLayer(foreRenderer) }
/** Render a back or from layer. */
protected def renderLayer(renderer:LayerRenderer) {
val metrics = camera.metrics
renderer.render(backend.graphics2D, graph, metrics.ratioPx2Gu,
metrics.viewport(2).toInt,
metrics.viewport(3).toInt,
metrics.loVisible.x,
metrics.loVisible.y,
metrics.hiVisible.x,
metrics.hiVisible.y)
}
/** Setup the graphic pipeline before drawing. */
protected def setupGraphics() {
backend.setAntialias(graph.hasAttribute("ui.antialias"))
backend.setQuality(graph.hasAttribute("ui.quality"))
}
def screenshot(filename:String, width:Int, height:Int) {
if(filename.toLowerCase.endsWith("png")) {
val img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
render(img.createGraphics, 0, 0, width, height)
val file = new File(filename)
ImageIO.write(img, "png", file)
} else if(filename.toLowerCase.endsWith("bmp")) {
// Who, in the world, is still using BMP ???
val img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
render(img.createGraphics, 0, 0, width, height)
val file = new File(filename)
ImageIO.write(img, "bmp", file)
} else if(filename.toLowerCase.endsWith("jpg") || filename.toLowerCase.endsWith("jpeg")) {
val img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
render(img.createGraphics, 0, 0, width, height)
val file = new File(filename)
ImageIO.write(img, "jpg", file)
} else if(filename.toLowerCase.endsWith("svg")) {
try {
val plugin = "org.graphstream.ui.batik.BatikGraphics2D"
val c = Class.forName(plugin)
val o = c.newInstance.asInstanceOf[Object]
if(o.isInstanceOf[Graphics2DOutput]) {
val out = o.asInstanceOf[Graphics2DOutput]
val g2 = out.getGraphics();
render(g2, 0, 0, width, height)
out.outputTo(filename)
} else {
Logger.getLogger(this.getClass.getSimpleName).warning("Plugin %s is not an instance of Graphics2DOutput (%s).".format(plugin, o.getClass.getName))
}
} catch {
case e:Exception => e.printStackTrace
}
} else {
Logger.getLogger(this.getClass.getSimpleName).warning("Unknown screenshot filename extension %s, saving to jpeg.".format(filename))
val img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
render(img.createGraphics, 0, 0, width, height)
val file = new File(filename+".jpg")
ImageIO.write(img, "jpg", file)
}
}
def setBackLayerRenderer(renderer:LayerRenderer) { backRenderer = renderer }
def setForeLayoutRenderer(renderer:LayerRenderer) { foreRenderer = renderer }
// Commands -- Style group listener
def elementStyleChanged(element:Element, oldStyle:StyleGroup, style:StyleGroup) {
// XXX The element renderer should be the listener, not this. ... XXX
if(oldStyle ne null) {
} else if(oldStyle ne null) {
val renderer = oldStyle.getRenderer(J2DGraphRenderer.DEFAULT_RENDERER)
if((renderer ne null ) && renderer.isInstanceOf[JComponentRenderer])
renderer.asInstanceOf[JComponentRenderer].unequipElement(element.asInstanceOf[GraphicElement])
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy