1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.scenegraph.swing;
14 import java.awt.Graphics2D;
\r
15 import java.awt.geom.AffineTransform;
\r
16 import java.awt.geom.Rectangle2D;
\r
17 import java.util.ArrayList;
\r
18 import java.util.List;
\r
20 import javax.swing.JPanel;
\r
22 import org.jfree.chart.ChartFactory;
\r
23 import org.jfree.chart.ChartPanel;
\r
24 import org.jfree.chart.JFreeChart;
\r
25 import org.jfree.chart.axis.ValueAxis;
\r
26 import org.jfree.chart.plot.PlotOrientation;
\r
27 import org.jfree.chart.plot.XYPlot;
\r
28 import org.jfree.data.xy.XYSeries;
\r
29 import org.jfree.data.xy.XYSeriesCollection;
\r
30 import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget;
\r
31 import org.simantics.scenegraph.g2d.IdentityAffineTransform;
\r
32 import org.simantics.scenegraph.g2d.nodes.Trend2DNode.TrendPoint;
\r
35 public class JFreeTrendNode extends ComponentNode<JPanel> {
40 private static final long serialVersionUID = 8508750881358776559L;
42 protected String title = null;
43 protected String yTitle = null;
44 protected String xTitle = null;
45 protected transient List<TrendPoint> points = null;
47 protected transient XYSeries series = null;
\r
50 public void init() {
\r
51 series = new XYSeries("Trend");
\r
52 final XYSeriesCollection dataset = new XYSeriesCollection(series);
\r
53 if(title == null) title = "Trend";
\r
54 if(xTitle == null) xTitle = "Value";
\r
55 if(yTitle == null) yTitle = "Time";
\r
59 final JFreeChart chart = ChartFactory.createXYLineChart(
\r
64 PlotOrientation.VERTICAL,
\r
69 final XYPlot plot = chart.getXYPlot();
\r
70 ValueAxis axis = plot.getDomainAxis();
\r
71 axis.setAutoRange(true);
\r
72 // axis.setFixedAutoRange(60000.0); // 60 seconds
\r
74 component = new ChartPanel(chart, false);
\r
75 ((ChartPanel)component).setRefreshBuffer(false);
\r
76 component.setIgnoreRepaint(true);
\r
77 component.setDoubleBuffered(false);
\r
78 if(bounds != null) {
\r
79 component.setBounds(0, 0, 0, 0);
\r
82 if(points != null) {
\r
83 for(TrendPoint p : points) {
\r
85 series.add(p.getX(), p.getY());
\r
86 } catch(org.jfree.data.general.SeriesException e) {
\r
95 public void render(Graphics2D g2d) {
96 if (component != null) {
97 AffineTransform ot = g2d.getTransform();
\r
99 double scaleX = ot.getScaleX();
100 double scaleY = ot.getScaleY();
102 if (transform == IdentityAffineTransform.INSTANCE)
\r
103 transform = new AffineTransform();
104 synchronized(transform) {
105 transform.setToTranslation(bounds.getMinX(), bounds.getMinY());
106 transform.scale(1/scaleX, 1/scaleY);
108 g2d.transform(transform);
109 int width = (int)(bounds.getWidth() * scaleX);
110 int height = (int)(bounds.getHeight() * scaleY);
112 component.setLocation((int)g2d.getTransform().getTranslateX(), (int)g2d.getTransform().getTranslateY());
113 if(component.getSize().getWidth() != width || component.getSize().getHeight() != height) {
114 component.setSize(width, height);
\r
116 component.paint(g2d);
\r
118 g2d.setTransform(ot);
123 public void setTitle(String title) {
125 if(component != null)
126 ((ChartPanel)component).getChart().setTitle(title);
130 public void setXTitle(String xTitle) {
131 this.xTitle = xTitle;
132 if(component != null)
\r
133 ((ChartPanel)component).getChart().getXYPlot().getDomainAxis().setLabel(xTitle);
\r
137 public void setYTitle(String yTitle) {
138 this.yTitle = yTitle;
139 if(component != null)
\r
140 ((ChartPanel)component).getChart().getXYPlot().getRangeAxis().setLabel(yTitle);
\r
144 public void setBounds(Rectangle2D bounds) {
145 this.bounds = bounds;
\r
146 // width = (int)bounds.getWidth();
\r
147 // height = (int)bounds.getHeight();
151 protected void setPoints(List<TrendPoint> points) {
152 this.points = points;
155 for(TrendPoint p : points) {
157 series.add(p.getX(), p.getY());
158 } catch(org.jfree.data.general.SeriesException e) {
166 protected void appendPoints(List<TrendPoint> points) {
167 if(this.points == null) this.points = new ArrayList<TrendPoint>();
169 * We need to have the same set of points on the both sides, so locally the points are just updated,
170 * but on remote side we send only the new points.
171 * In case we are running on local workbench, the point list is updated and in addition these points
172 * would be added to the list without this check.
173 * FIXME: find out some way to implement this without this check
175 if(location.equals(Location.REMOTE)) {
176 this.points.addAll(points);
179 for(TrendPoint p : points) {
181 series.add(p.getX(), p.getY());
182 } catch(org.jfree.data.general.SeriesException e) {
189 * Update trend points. If
193 public void updatePoints(List<TrendPoint> newpoints) {
194 if(points == null) points = new ArrayList<TrendPoint>();
195 for(int n = newpoints.size()-1; n >= 0; n--) {
197 for(int o = points.size()-1; o >= 0; o--) {
198 if(!newpoints.get(n-t).equals(points.get(o))) {
201 if(o == 0 || o < points.size()-10) {
202 // Now we have 10 matching values, so n tells where the old points ends
203 ArrayList<TrendPoint> appendedPoints = new ArrayList<TrendPoint>();
204 for(int i = n; i < newpoints.size()-1; i++) {
205 appendedPoints.add(newpoints.get(i));
207 points = new ArrayList<TrendPoint>(newpoints);
208 if(appendedPoints != null && appendedPoints.size() > 0) {
209 appendPoints(appendedPoints);
214 setPoints(newpoints);
220 setPoints(newpoints);