001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.web.client.chart;
017
018import com.google.gwt.widgetideas.graphics.client.Color;
019import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
020import com.smartgwt.client.types.Alignment;
021import com.smartgwt.client.types.VerticalAlignment;
022import com.smartgwt.client.util.Format;
023import com.smartgwt.client.widgets.Canvas;
024import com.smartgwt.client.widgets.Label;
025import com.smartgwt.client.widgets.layout.HLayout;
026import com.smartgwt.client.widgets.layout.VLayout;
027
028/**
029 *
030 * @author kulikov
031 */
032public class Chart extends VLayout {
033
034    private final static int LABEL_SIZE = 30;
035    private final static int Y_SCALE = 10;
036    
037    private YAxis yAxis = new YAxis();
038    private XAxis xAxis = new XAxis();
039    
040    private int X, Y;
041    
042    private ViewPort viewPort = new ViewPort();
043    private GWTCanvas canvas;
044
045    /**
046     * Creates chart with given title.
047     * 
048     * @param title chart's title.
049     */
050    public Chart(String title) {
051        setWidth100();
052        setHeight100();
053        
054        init();
055    }
056
057    public final void init() {
058        Title title = new Title("");
059        title.setWidth100();
060        title.setHeight(30);
061        addMember(title);
062
063        HLayout layout = new HLayout();
064        layout.setWidth100();
065        layout.setHeight100();
066
067        layout.addMember(yAxis);
068        layout.addMember(viewPort);
069
070        addMember(layout);
071        addMember(xAxis);        
072        addMember(new Footer());
073    }
074
075    public void drawChart(String[] xl, double[] x, double[] y1, double[] y2, double[] y3) {
076        viewPort.drawChart(xl, x, y1, y2, y3);
077    }
078    
079    
080    private class Title extends VLayout {
081        public Title(String title) {
082            setContents(title);
083        }
084    }
085
086    private class Footer extends VLayout {
087        public Footer() {
088            HLayout layout = new HLayout();
089            addMember(layout);
090            
091            Label strut = new Label();
092            strut.setWidth(LABEL_SIZE);
093            
094            Label min = new Label("<span style=\"color:red\">Min</span>");
095            Label max = new Label("<span style=\"color:blue\">Max</span>");
096            Label avg = new Label("<span style=\"color:green\">Average</span>");
097            
098            layout.addMember(strut);
099            layout.addMember(min);
100            layout.addMember(max);
101            layout.addMember(avg);
102        }
103    }
104    
105    
106    /**
107     * YAxis.
108     */
109    private class YAxis extends VLayout {
110
111        public YAxis() {
112            setWidth(LABEL_SIZE);
113            setHeight100();
114        }
115        
116        private void clean() {
117            Canvas[] members = this.getMembers();
118            for (int i = 0; i < members.length; i++) {
119                this.removeMember(members[i]);
120            }
121        }
122        
123        public void drawLabels(String[] x) {
124            clean();
125            int j = x.length - 1;
126            for (int i = 0; i < x.length; i++) {
127                addMember(new YLabel(x[j--]));
128            }
129        }
130    }
131
132    /**
133     * Label for Y axis.
134     * 
135     */
136    private class YLabel extends Label {
137        
138        public YLabel(String v) {
139            setWidth100();
140            setHeight100();
141            setContents(v);
142            setAlign(Alignment.CENTER);
143            setLayoutAlign(Alignment.CENTER);
144            setLayoutAlign(VerticalAlignment.BOTTOM);
145            setValign(VerticalAlignment.BOTTOM);
146        }
147    }
148    
149    private class XAxis extends HLayout {
150
151        public XAxis() {
152            setHeight(LABEL_SIZE);
153            setWidth100();
154        }
155
156        private void clean() {
157            Canvas[] members = this.getMembers();
158            for (int i = 0; i < members.length; i++) {
159                this.removeMember(members[i]);
160            }
161        }
162        
163        public void drawLabels(String[] x) {
164            clean();
165            
166            Label strut = new Label();
167            strut.setWidth(LABEL_SIZE);
168            strut.setHeight(LABEL_SIZE);
169            
170            addMember(strut);
171            
172            for (int i = 0; i < x.length; i++) {
173                addMember(new XLabel(x[i]));
174            }
175        }
176    }
177
178    private class XLabel extends Label {
179        public XLabel(String v) {
180            setWidth100();
181            setHeight100();
182            setContents(v);
183            setAlign(Alignment.LEFT);
184            setLayoutAlign(Alignment.LEFT);
185        }
186    }
187    
188    private class ViewPort extends HLayout {
189        
190        private final Color COLOR[] = new Color[]{Color.RED, Color.BLUE, Color.GREEN};
191                
192        public ViewPort() {
193            setWidth100();
194            setHeight100();
195            setBorder("2px solid black");
196        }
197
198        private void drawGrid(int N, int M) {
199            if (canvas == null) {
200                canvas = new GWTCanvas(getWidth(), getHeight());
201                addMember(canvas);
202            } else {
203                canvas.clear();
204            }
205            
206            //draw horizontal lines
207            
208            X = canvas.getCoordWidth();
209            Y = canvas.getCoordHeight();
210            
211            double dx = X / N;
212            double dy = Y / M;
213            
214            canvas.beginPath();
215
216            canvas.setLineWidth(1); 
217            canvas.setStrokeStyle(Color.BLACK);
218              
219            for (int i = 0; i < N; i++) {
220                double x = dx * (i + 1);
221                
222                canvas.moveTo(x, 0);
223                canvas.lineTo(x, Y);
224            }
225
226            //draw vertical lines
227            int j = M -1;
228            for (int i = 0; i < M; i++) {
229                double y = Y - dy * (j--);
230                
231                canvas.moveTo(0, y);
232                canvas.lineTo(X, y);
233            }
234            
235            canvas.stroke();
236            
237        }
238        
239        private void drawLine(double[] y, double min, double max, Color color) {
240            canvas.beginPath();
241
242            canvas.setLineWidth(2); 
243            canvas.setStrokeStyle(color);
244                       
245            double xScale = X / y.length;
246            double yScale = Y / (max - min);
247            
248            
249            for (int i = 0; i < y.length -1; i++) {
250                canvas.moveTo(i * xScale, Y - (y[i] - min) * yScale);
251                canvas.lineTo((i + 1)* xScale, Y - (y[i + 1] - min) * yScale);
252            }
253            
254            canvas.stroke();
255        }
256        
257        private String[] yLabels(double[]... y) {
258            String[] labels = new String[Y_SCALE];
259            
260            double min = min(y);
261            double max = max(y);
262            
263            double s = (max - min)/Y_SCALE;
264            for (int i = 0; i < Y_SCALE; i++) {
265                labels[i] = Format.toUSString((min + i * s), 2);
266            }
267            
268            return labels;
269        }
270        
271        public void drawChart(String[] xLabels, double[] x, double[]... y) {
272            String[] yLabels = yLabels(y);
273            
274            yAxis.drawLabels(yLabels);
275            xAxis.drawLabels(xLabels);
276            
277            double min = min(y);
278            double max = max(y);
279            
280            drawGrid(xLabels.length, yLabels.length);
281                        
282            for (int i = 0; i < y.length; i++) {
283                drawLine(y[i], min, max, COLOR[i]);
284            }
285        }
286        
287        private double min(double[]... x) {
288            double min = x[0][0];
289            for (int j = 0; j < x.length; j++ ) {
290                for (int i = 0; i < x[j].length; i++) {
291                    if (x[j][i] < min) min = x[j][i];
292                }
293            }
294            return min;
295        }
296
297        private double max(double[]... x) {
298            double max = x[0][0];
299            for (int j = 0; j < x.length; j++) {
300                for (int i = 0; i < x[j].length; i++) {
301                    if (x[j][i] > max) max = x[j][i];
302                }
303            }
304            return max;
305        }
306        
307    }
308
309}