]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.trend/src/org/simantics/trend/impl/VertRuler.java
Fixed history data collection minmax stream updates and plot rendering
[simantics/platform.git] / bundles / org.simantics.trend / src / org / simantics / trend / impl / VertRuler.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.trend.impl;
13
14 import java.awt.Color;
15 import java.awt.Font;
16 import java.awt.FontMetrics;
17 import java.awt.Graphics2D;
18 import java.awt.geom.AffineTransform;
19 import java.awt.geom.Path2D;
20 import java.text.Format;
21
22 import org.simantics.g2d.utils.GridSpacing;
23 import org.simantics.g2d.utils.GridUtil;
24 import org.simantics.trend.configuration.ItemPlacement;
25 import org.simantics.trend.configuration.TrendItem.Renderer;
26 import org.simantics.utils.format.ValueFormat;
27
28 public class VertRuler extends TrendGraphicalNode {
29
30         private static final long serialVersionUID = 3773787909384380074L;
31
32         GridSpacing spacing = GridSpacing.SOME_SPACING;
33         double min = -1, max = 1;
34         double iMin = Double.MAX_VALUE, iMax = -Double.MAX_VALUE;
35         String label = "";
36         Color color = Color.GRAY;
37         boolean autoscroll = true;  // Autoscroll on/off
38         boolean manualscale = false; // Autoscale / manual scale
39         double labelWidth = 7;
40
41         static final double TRIANGLE_SIZE = 7;
42     static final Path2D TRIANGLE;
43                         
44         public void layout()
45         {
46                 TrendNode trend = getTrend();
47                 ValueFormat vf = trend.valueFormat;
48                 spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);
49                 labelWidth = Math.max(7, GridUtil.calcLabelWidth(min, max, vf.format, spacing));
50                 double w = 30 + labelWidth;
51                 // Snap w -> next 20 pixels
52                 double quantization = 10; 
53                 int x = (int) Math.ceil( w / quantization );
54                 if (x<4) x = 4;
55                 w = x * quantization;
56                 w += 5;
57                 bounds.setFrame(0, 0, w, getHeight());          
58                 trend.shapedirty = true;
59         }
60
61         public void setHeight(double height) {
62                 if (height==bounds.getHeight()) return;
63                 bounds.setFrame(0, 0, bounds.getWidth(), height);               
64                 getTrend().shapedirty = true;
65         }
66         
67         public boolean setMinMax(double min, double max) {
68                 if (min==this.min && max==this.max) return false;
69                 spacing = GridSpacing.makeGridSpacing(max-min, getHeight(), 15);
70                 this.min = min;
71                 this.max = max;
72                 getTrend().shapedirty = true;
73                 return true;
74         }       
75         
76         @Override
77         protected void doRender(Graphics2D g) {
78                 TrendNode trend = (TrendNode) getParent();
79                 
80                 // Draw little "Frozen"
81                 if ( !trend.printing )
82                 {
83                         g.setColor( Color.LIGHT_GRAY );
84                         g.setFont( RULER_FONT );
85                         String txt = !autoscroll ? (manualscale ? "*" : "Auto off") : (manualscale ? "" : "Auto on");
86                         // Draw at bottom
87                         //g.drawString(txt, 2.f, (float)getHeight() + 14.f );
88                         // Draw at top
89                         g.drawString(txt, 5.f, -9.f );
90                 }
91                 
92                 g.setPaint( color );
93                 g.setStroke( GridUtil.RULER_LINE_STROKE );              
94                                 
95                 ValueFormat vf = trend.valueFormat;
96                 VertRuler master = trend.vertRuler;
97                 VertRuler slave = this;
98                 if ( master != slave )
99                 {       
100                         // Paint "slave" ruler - a ruler with ticks from master and labels from this
101                         int tickCount = GridUtil.getTickCount(master.spacing, master.min, master.getHeight());
102                         int noOfDecimals = calcNoOfDecimals(tickCount, slave.max-slave.min);
103                         Format format = vf.toFormat(noOfDecimals);
104                         
105                         GridUtil.paintVerticalSlaveRuler(
106                                         master.spacing,
107                                         spacing, 
108                                         g,
109                                         master.min,
110                                         slave.min,
111                                         getHeight(),
112                                         format);
113                 } else {
114                         Format format = vf.format;
115                         
116                         // Paint normal ruler
117                         GridUtil.paintVerticalRuler(
118                                 spacing, 
119                                 g,
120                                 min,
121                                 getHeight(),
122                                 format);
123                 }
124                 
125                 // Draw label
126                 {
127 //                      Shape oldClip = g2d.getClip();
128 //                      Rectangle2D.Double newClip = new Rectangle2D.Double(0,-20, getWidth(), 30);
129 //                      g2d.setClip(newClip);
130                         boolean selected = trend.singleAxis ? false : trend.vertRuler==this;
131                         selected &= !trend.printing;
132                         
133                         Font font = selected ? RULER_FONT_BOLD : RULER_FONT;
134                         FontMetrics fm = g.getFontMetrics( font );
135                         //LineMetrics lm = fm.getLineMetrics(label, g);
136                         double wid = fm.stringWidth(label);
137                         
138                         AffineTransform at = g.getTransform();
139                         g.translate( getWidth()-15, (getHeight()-wid)/2);
140 //                      g2d.translate( 18+labelWidth, (getHeight()-wid)/2);
141                         g.transform( AffineTransform.getQuadrantRotateInstance(1) );
142                         g.setColor( color );
143                         g.setFont( font );
144                         g.drawString( label, (float) 0, (float) 0);
145                         g.setTransform( at );                   
146 //                      g2d.setClip(oldClip);
147                         
148                         // Triangle
149                         if (selected) {
150                                 at = g.getTransform();
151                                 g.translate( getWidth() - TRIANGLE_SIZE - 5, 0 );
152                                 g.setColor( color );
153                                 g.fill( TRIANGLE );                             
154                                 g.setTransform( at );                   
155                         }
156                 }
157         }
158
159         public void setKnownMinMax() {
160                 TrendNode trend = (TrendNode) getParent();
161                 iMax = -Double.MAX_VALUE;
162                 iMin = Double.MAX_VALUE;
163                 for (ItemNode item : trend.analogItems) {
164                         if (item.item.renderer != Renderer.Analog || item.ruler!=this) continue;
165                         if ( !Double.isNaN(item.min ) ) iMin  = Math.min(iMin, item.min ); 
166                         if ( !Double.isNaN(item.max ) ) iMax  = Math.max(iMax, item.max );
167                 }
168                 
169                 if (iMin == Double.MAX_VALUE && iMax == -Double.MAX_VALUE) {
170                         iMin = 0.;
171                         iMax = 1.;
172                 }
173         }
174         
175         public boolean autoscale() {
176                 if (!autoscroll) return false;
177                 setKnownMinMax();
178                 double nMin = iMin;
179                 double nMax = iMax;
180                 double diff = nMax - nMin;
181                 if (diff==0.0) {
182                         nMin -= 0.5;
183                         nMax += 0.5;
184                         diff = nMax - nMin;
185                 }
186                 double margin = diff*0.02;
187                 
188                 TrendNode trend = getTrend();
189                 if (trend.itemPlacement == ItemPlacement.Stacked) {
190                         int c = trend.vertRulers.size();
191                         int i = c-trend.vertRulers.indexOf(this)-1;
192                         nMin = nMin - (diff)*i - margin;
193                         nMax = nMax + (diff)*(c-i-1) + margin;
194                         
195                 } else {
196                         nMin = iMin - margin;
197                         nMax = iMax + margin;
198                 }               
199
200                 return setMinMax(nMin, nMax);
201         }
202         
203         public void translate(double dy) {
204                 min += dy;
205                 max += dy;
206                 autoscroll = false;
207         }
208         
209         public void zoomIn(double y, double height) {
210                 autoscroll = false;
211                 
212                 double diff = max-min;
213                 double sy = diff / getHeight();
214                 if ( Math.abs(diff)<GridSpacing.GRID_MIN_USER_SIZE && height<getHeight()) {
215 //                      System.out.println(y/getHeight()*4+", "+getHeight());
216 //                      diff = GridSpacing.GRID_MIN_USER_SIZE;
217 //                      sy = diff / getHeight();
218 //                      double ry = y/getHeight()*4;
219 //                      double vy = (max+min)/2-y*sy; 
220 //                      setMinMax(vy-GridSpacing.GRID_MIN_USER_SIZE/2, vy+GridSpacing.GRID_MIN_USER_SIZE/2);
221                         return;
222                 } else {
223                         double newMin  = min + (getHeight() - y-height)*sy;
224                         double newMax  = max - (y)*sy;
225                         setMinMax(newMin, newMax);
226                 }
227         }
228         
229         public void zoomOut() {
230                 autoscroll = true;
231                 autoscale();
232         }       
233         
234         public void zoomTo(double min, double max) {
235                 setMinMax(min, max);
236                 autoscroll = false;
237         }
238         
239         public double unitsPerPixel() {
240                 return (max-min) / getHeight();
241         }
242         
243         static int calcNoOfDecimals(int tickCount, double diff)
244         {
245                 int interestingNumbers;
246                 if ( tickCount<=2 ) interestingNumbers = 1; else
247                 if ( tickCount>=3 && tickCount<=9 ) interestingNumbers = 2; else
248                 if ( tickCount>=10 && tickCount<=99 ) interestingNumbers = 3; else
249                 if ( tickCount>=100 && tickCount<=999 ) interestingNumbers = 4; else
250                         interestingNumbers = 5;
251                 
252                 int decimals = interestingNumbers - ((int)Math.ceil( Math.log10(diff) ));
253                 if (decimals<0) decimals = 0;
254                 
255                 return decimals;
256         }
257         
258         public static void main(String[] args) {
259                 double diff = 12.4567890;
260                 for ( int tickCount=0; tickCount<15; tickCount++) {
261                         int noOfDecimals = calcNoOfDecimals(tickCount, diff);
262                         Format format = ValueFormat.Currency.toFormat(noOfDecimals);
263                         System.out.println("diff="+diff+", tickcount="+tickCount+", #ofDecimals="+noOfDecimals+", formatted diff="+format.format(diff));
264                 }
265         }
266         static {
267                 
268                 TRIANGLE = new Path2D.Double();
269                 TRIANGLE.moveTo(-TRIANGLE_SIZE/2, 0);
270                 TRIANGLE.lineTo(TRIANGLE_SIZE/2, 0);
271                 TRIANGLE.lineTo(0, TRIANGLE_SIZE);
272
273         }
274
275 }