/**
* Copyright 2010-2013 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.swing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import org.jplot2d.element.Plot;
import org.jplot2d.env.RenderEnvironment;
import org.jplot2d.interaction.InteractionManager;
import org.jplot2d.interaction.MousePreference;
import org.jplot2d.interaction.PlotDefaultMousePreference;
import org.jplot2d.interaction.PlotInteractionManager;
import org.jplot2d.notice.DefaultNotifier;
import org.jplot2d.renderer.AsyncImageRenderer;
import org.jplot2d.renderer.GraphicsConfigurationCompatibleImageFactory;
import org.jplot2d.renderer.ImageRenderer;
import org.jplot2d.renderer.RenderingFinishedEvent;
import org.jplot2d.renderer.RenderingFinishedListener;
import org.jplot2d.swing.interaction.InteractionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A JComponent that display a plot in its center.
*
* @author Jingjing Li
*
*/
public class JPlot2DComponent extends JComponent implements HierarchyListener, RenderingFinishedListener {
public static class DefaultImageRendererFactory implements ImageRendererFactory {
private final JPlot2DComponent comp;
public DefaultImageRendererFactory(JPlot2DComponent comp) {
this.comp = comp;
}
@Override
public AsyncImageRenderer createImageRenderer() {
return new AsyncImageRenderer(new GraphicsConfigurationCompatibleImageFactory(
comp.getGraphicsConfiguration(), comp.getPlotBackground()));
}
}
private static final long serialVersionUID = 1L;
static Logger logger = LoggerFactory.getLogger("org.jplot2d.swing");
private final RenderEnvironment env;
private Color bgColor = Color.WHITE;
private ImageRendererFactory rendererFactory;
private ImageRenderer r;
private Object renderLock = new Object();
private long ifsn = -1;
private Object fsnLock = new Object();
private volatile BufferedImage image;
private int xoff, yoff;
private InteractionManager imanager;
private final InteractionListener ial;
private boolean iaEnabled;
/**
* Construct a JComponent to display the given plot in its center. The plot properties can be safely by multiple
* threads.
*
* @param plot
* the plot to be display
*/
public JPlot2DComponent(Plot plot) {
this(plot, true);
}
/**
* Construct a JComponent to display the given plot in its center.
*
* @param plot
* the plot to be display
* @param threadSafe
* if false, all plot properties can only be changed within a single thread. if
* true, all plot properties can be safely changed by multiple threads.
*/
public JPlot2DComponent(Plot plot, boolean threadSafe) {
this(createRenderEnvironment(threadSafe));
env.setPlot(plot, new DefaultNotifier(this));
}
/**
* create a RenderEnvironment with the given plot.
*
* @param plot
* @param threadSafe
* @return
*/
private static RenderEnvironment createRenderEnvironment(boolean threadSafe) {
RenderEnvironment env = new RenderEnvironment(threadSafe);
return env;
}
/**
* Construct a JComponent to display a plot in its center. The plot has been assigned to the given
* RenderEnvironment.
*
* @param env
* the RenderEnvironment
*/
public JPlot2DComponent(RenderEnvironment env) {
this.env = env;
rendererFactory = new DefaultImageRendererFactory(this);
setBackground(Color.GRAY);
setOpaque(true);
addHierarchyListener(this);
imanager = createInteractionManager();
ial = new InteractionListener(this, imanager, env);
setFocusable(true);
requestFocusInWindow();
setInteractionEnabled(true);
}
/**
* Return the RenderEnvironment of this JPlot2DComponent. The RenderEnvironment generate plot images and display
* them in this component.
*
* @return the RenderEnvironment of this JPlot2DComponen
*/
public RenderEnvironment getRenderEnvironment() {
return env;
}
/**
* Returns the background color of plot. The default color is Color.WHITE.
*
* @return the background color of plot
*/
public Color getPlotBackground() {
return bgColor;
}
/**
* Sets the background color of plot. The default color is Color.WHITE.
*
* @param bgcolor
* the new background color of plot
*/
public void setPlotBackground(Color bgColor) {
this.bgColor = bgColor;
replaceRenderer();
}
/**
* Returns the renderer factory used to create image renderers.
*
* @return the current renderer factory
*/
public ImageRendererFactory getImageRendererFactory() {
return rendererFactory;
}
/**
* Sets the renderer factory used to create image renderers.
*
* @param rendererFactory
* the new renderer factory
*/
public void setImageRendererFactory(ImageRendererFactory rendererFactory) {
this.rendererFactory = rendererFactory;
replaceRenderer();
}
/**
* Recreate a new renderer and re-render the plot. Only when a renderer already exist.
*/
private void replaceRenderer() {
synchronized (renderLock) {
if (r != null) {
env.removeRenderer(r);
r = createAndSetRenderer();
}
}
}
/**
* Create a new image renderer and add it to render environment.
*
* @return
*/
private ImageRenderer createAndSetRenderer() {
synchronized (fsnLock) {
ifsn = -1;
}
ImageRenderer ir = rendererFactory.createImageRenderer();
ir.addRenderingFinishedListener(this);
env.addRenderer(ir);
env.exportPlot(ir);
return ir;
}
public void hierarchyChanged(HierarchyEvent event) {
if ((event.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
synchronized (renderLock) {
if (this.isDisplayable()) {
r = createAndSetRenderer();
} else {
env.removeRenderer(r);
r = null;
}
}
}
}
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
env.getPlot().setContainerSize(new Dimension(width, height));
}
public void paintComponent(Graphics g) {
// clear background
((Graphics2D) g).setBackground(this.getBackground());
g.clearRect(0, 0, getWidth(), getHeight());
if (image != null) {
int width = image.getWidth();
int height = image.getHeight();
xoff = (getWidth() - width) / 2;
yoff = (getHeight() - height) / 2;
g.drawImage(image, xoff, yoff, this);
ial.draw((Graphics2D) g);
}
}
/**
* Returns the current image displayed in this component.
*
* @return the current image
*/
public BufferedImage getImage() {
return image;
}
/**
* Returns the x offset where the plot image draw.
*
* @return the x offset of the plot image
*/
public int getImageOffsetX() {
return xoff;
}
/**
* Returns the y offset where the plot image draw.
*
* @return the y offset of the plot image
*/
public int getImageOffsetY() {
return yoff;
}
public void renderingFinished(RenderingFinishedEvent event) {
long sn = event.getSN();
boolean ok;
synchronized (fsnLock) {
if (sn > ifsn) {
ok = true;
ifsn = sn;
} else {
ok = false;
}
}
if (!ok) {
logger.trace("[R] Rendering finished in wrong order, drop R." + sn + " Current result is " + ifsn);
return;
}
image = (BufferedImage) event.getResult();
repaint();
}
/**
* Subclass can return it's own InteractionManager, initiated with a MousePreference
*
* @return an InteractionManager
*/
protected InteractionManager createInteractionManager() {
InteractionManager result = PlotInteractionManager.getInstance();
result.setMousePreference(PlotDefaultMousePreference.getInstance());
return result;
}
public void setMousePreference(MousePreference prefs) {
imanager.setMousePreference(prefs);
}
public void setInteractionEnabled(boolean enabled) {
if (iaEnabled == enabled) {
return;
}
if (enabled) {
addKeyListener(ial);
addMouseListener(ial);
addMouseMotionListener(ial);
addMouseWheelListener((MouseWheelListener) ial);
} else {
removeKeyListener(ial);
removeMouseListener(ial);
removeMouseMotionListener(ial);
removeMouseWheelListener((MouseWheelListener) ial);
}
iaEnabled = enabled;
}
}
Ads help maintain this website.