/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph.swing; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget; import org.simantics.scenegraph.g2d.nodes.Trend2DNode.TrendPoint; @RasterOutputWidget public class MultiVariableTrendNode extends ComponentNode { /** * */ private static final long serialVersionUID = 8508750881358776559L; protected transient JFreeChart chart = null; protected transient List> points = new ArrayList>(); protected transient XYSeriesCollection dataset = null; @Override public void init() { XYSeries serie = new XYSeries("Trend"); dataset = new XYSeriesCollection(serie); scale = false; chart = ChartFactory.createXYLineChart( "Trend", // Title "Value", // X-title "Time", // Y-title dataset, PlotOrientation.VERTICAL, false, true, false ); final XYPlot plot = chart.getXYPlot(); ValueAxis axis = plot.getDomainAxis(); axis.setAutoRange(true); // axis.setFixedAutoRange(60000.0); // 60 seconds component = new ChartPanel(chart, false); ((ChartPanel)component).setRefreshBuffer(false); component.setIgnoreRepaint(true); component.setDoubleBuffered(false); if(bounds != null) { component.setBounds(0, 0, 0, 0); } for(int i = 0; i < points.size(); i++) { if(dataset.getSeriesCount() < i) { XYSeries s = new XYSeries("Serie "+(i+1)); dataset.addSeries(s); dataset.addSeries(s); } for(TrendPoint p : points.get(i)) { try { dataset.getSeries(i).add(p.getX(), p.getY()); } catch(org.jfree.data.general.SeriesException e) { } } } super.init(); } @Override public void render(Graphics2D g2d) { if (component != null) { AffineTransform ot = g2d.getTransform(); g2d.transform(transform); double scaleX = g2d.getTransform().getScaleX(); double scaleY = g2d.getTransform().getScaleY(); AffineTransform at = new AffineTransform(); at.setToTranslation(bounds.getMinX(), bounds.getMinY()); at.scale(1/scaleX, 1/scaleY); g2d.transform(at); int width = (int)(bounds.getWidth() * scaleX); int height = (int)(bounds.getHeight() * scaleY); synchronized(component) { component.setLocation((int)g2d.getTransform().getTranslateX(), (int)g2d.getTransform().getTranslateY()); if(component.getSize().getWidth() != width || component.getSize().getHeight() != height) { component.setSize(width, height); } component.paint(g2d); } g2d.setTransform(ot); } } @PropertySetter("Title") @ClientSide public void setTitle(String title) { if(component != null) { synchronized(component) { ((ChartPanel)component).getChart().setTitle(title); } } } @PropertySetter("X-Axis Label") @ClientSide public void setXTitle(String xTitle) { if(component != null) { synchronized(component) { ((ChartPanel)component).getChart().getXYPlot().getDomainAxis().setLabel(xTitle); } } } @PropertySetter("Y-Axis Label") @ClientSide public void setYTitle(String yTitle) { if(component != null) { synchronized(component) { ((ChartPanel)component).getChart().getXYPlot().getRangeAxis().setLabel(yTitle); } } } @ClientSide public void setPoints(List points, Integer serie) { while(dataset.getSeriesCount() <= serie) { this.points.add(new ArrayList()); dataset.addSeries(new XYSeries("Trend "+(dataset.getSeriesCount()+1))); } this.points.add(serie, points); synchronized(component) { dataset.getSeries(serie.intValue()).clear(); for(TrendPoint p : points) { try { dataset.getSeries(serie.intValue()).add(p.getX(), p.getY()); } catch(org.jfree.data.general.SeriesException e) { } } } } @ClientSide protected void appendPoints(List points, Integer serie) { while(dataset.getSeriesCount() <= serie) { this.points.add(new ArrayList()); dataset.addSeries(new XYSeries("Trend "+(dataset.getSeriesCount()+1))); } /** * We need to have the same set of points on the both sides, so locally the points are just updated, * but on remote side we send only the new points. * In case we are running on local workbench, the point list is updated and in addition these points * would be added to the list without this check. * FIXME: find out some way to implement this without this check */ if(location.equals(Location.REMOTE)) { this.points.get(serie).addAll(points); } for(TrendPoint p : points) { try { dataset.getSeries(serie).add(p.getX(), p.getY()); } catch(org.jfree.data.general.SeriesException e) { } } } }