--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.scenegraph.swing;
+
+import java.awt.Graphics2D;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.swing.JPanel;\r
+\r
+import org.jfree.chart.ChartFactory;\r
+import org.jfree.chart.ChartPanel;\r
+import org.jfree.chart.JFreeChart;\r
+import org.jfree.chart.axis.ValueAxis;\r
+import org.jfree.chart.plot.PlotOrientation;\r
+import org.jfree.chart.plot.XYPlot;\r
+import org.jfree.data.xy.XYSeries;\r
+import org.jfree.data.xy.XYSeriesCollection;\r
+import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget;\r
+import org.simantics.scenegraph.g2d.IdentityAffineTransform;\r
+import org.simantics.scenegraph.g2d.nodes.Trend2DNode.TrendPoint;\r
+\r
+@RasterOutputWidget
+public class JFreeTrendNode extends ComponentNode<JPanel> {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8508750881358776559L;
+
+ protected String title = null;
+ protected String yTitle = null;
+ protected String xTitle = null;
+ protected transient List<TrendPoint> points = null;
+
+ protected transient XYSeries series = null;\r
+
+ @Override\r
+ public void init() {\r
+ series = new XYSeries("Trend");\r
+ final XYSeriesCollection dataset = new XYSeriesCollection(series);\r
+ if(title == null) title = "Trend";\r
+ if(xTitle == null) xTitle = "Value";\r
+ if(yTitle == null) yTitle = "Time";\r
+ scale = true;\r
+\r
+\r
+ final JFreeChart chart = ChartFactory.createXYLineChart(\r
+ title,\r
+ xTitle,\r
+ yTitle,\r
+ dataset,\r
+ PlotOrientation.VERTICAL,\r
+ false,\r
+ true,\r
+ false\r
+ );\r
+ final XYPlot plot = chart.getXYPlot();\r
+ ValueAxis axis = plot.getDomainAxis();\r
+ axis.setAutoRange(true);\r
+// axis.setFixedAutoRange(60000.0); // 60 seconds\r
+\r
+ component = new ChartPanel(chart, false);\r
+ ((ChartPanel)component).setRefreshBuffer(false);\r
+ component.setIgnoreRepaint(true); \r
+ component.setDoubleBuffered(false);\r
+ if(bounds != null) {\r
+ component.setBounds(0, 0, 0, 0);\r
+ }\r
+\r
+ if(points != null) {\r
+ for(TrendPoint p : points) {\r
+ try {\r
+ series.add(p.getX(), p.getY());\r
+ } catch(org.jfree.data.general.SeriesException e) {\r
+\r
+ }\r
+ }\r
+ }\r
+ super.init();\r
+ }\r
+
+ @Override
+ public void render(Graphics2D g2d) {
+ if (component != null) {
+ AffineTransform ot = g2d.getTransform();\r
+\r
+ double scaleX = ot.getScaleX();
+ double scaleY = ot.getScaleY();
+\r
+ if (transform == IdentityAffineTransform.INSTANCE)\r
+ transform = new AffineTransform();
+ synchronized(transform) {
+ transform.setToTranslation(bounds.getMinX(), bounds.getMinY());
+ transform.scale(1/scaleX, 1/scaleY);
+ }
+ g2d.transform(transform);
+ int width = (int)(bounds.getWidth() * scaleX);
+ int height = (int)(bounds.getHeight() * scaleY);
+
+ component.setLocation((int)g2d.getTransform().getTranslateX(), (int)g2d.getTransform().getTranslateY());
+ if(component.getSize().getWidth() != width || component.getSize().getHeight() != height) {
+ component.setSize(width, height);\r
+ }
+ component.paint(g2d);\r
+ \r
+ g2d.setTransform(ot);
+ }
+ }\r
+
+ @SyncField("title")
+ public void setTitle(String title) {
+ this.title = title;
+ if(component != null)
+ ((ChartPanel)component).getChart().setTitle(title);
+ }
+
+ @SyncField("xTitle")
+ public void setXTitle(String xTitle) {
+ this.xTitle = xTitle;
+ if(component != null)\r
+ ((ChartPanel)component).getChart().getXYPlot().getDomainAxis().setLabel(xTitle);\r
+ }
+
+ @SyncField("yTitle")
+ public void setYTitle(String yTitle) {
+ this.yTitle = yTitle;
+ if(component != null)\r
+ ((ChartPanel)component).getChart().getXYPlot().getRangeAxis().setLabel(yTitle);\r
+ }
+
+ @SyncField("bounds")
+ public void setBounds(Rectangle2D bounds) {
+ this.bounds = bounds;\r
+// width = (int)bounds.getWidth();\r
+// height = (int)bounds.getHeight();
+ }
+
+ @SyncField("points")
+ protected void setPoints(List<TrendPoint> points) {
+ this.points = points;
+ if(series != null) {
+ series.clear();
+ for(TrendPoint p : points) {
+ try {
+ series.add(p.getX(), p.getY());
+ } catch(org.jfree.data.general.SeriesException e) {
+
+ }
+ }
+ }
+ }
+
+ @ClientSide
+ protected void appendPoints(List<TrendPoint> points) {
+ if(this.points == null) this.points = new ArrayList<TrendPoint>();
+ /**
+ * 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.addAll(points);
+ }
+
+ for(TrendPoint p : points) {
+ try {
+ series.add(p.getX(), p.getY());
+ } catch(org.jfree.data.general.SeriesException e) {
+
+ }
+ }
+ }
+
+ /**
+ * Update trend points. If
+ *
+ * @param newpoints
+ */
+ public void updatePoints(List<TrendPoint> newpoints) {
+ if(points == null) points = new ArrayList<TrendPoint>();
+ for(int n = newpoints.size()-1; n >= 0; n--) {
+ int t = 0;
+ for(int o = points.size()-1; o >= 0; o--) {
+ if(!newpoints.get(n-t).equals(points.get(o))) {
+ break;
+ }
+ if(o == 0 || o < points.size()-10) {
+ // Now we have 10 matching values, so n tells where the old points ends
+ ArrayList<TrendPoint> appendedPoints = new ArrayList<TrendPoint>();
+ for(int i = n; i < newpoints.size()-1; i++) {
+ appendedPoints.add(newpoints.get(i));
+ }
+ points = new ArrayList<TrendPoint>(newpoints);
+ if(appendedPoints != null && appendedPoints.size() > 0) {
+ appendPoints(appendedPoints);
+ }
+ return;
+ }
+ if((n-t) == 0) {
+ setPoints(newpoints);
+ return;
+ }
+ t++;
+ }
+ }
+ setPoints(newpoints);
+ }
+}