This project has retired. For details please refer to its Attic page.
Chart xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.chukwa.hicc;
20  
21  
22  import java.util.ArrayList;
23  import java.util.Map;
24  import java.util.TreeMap;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map.Entry;
28  import java.text.SimpleDateFormat;
29  import javax.servlet.http.HttpServletRequest;
30  import javax.swing.text.html.HTMLDocument.Iterator;
31  
32  import org.apache.hadoop.chukwa.util.XssFilter;
33  import org.json.JSONArray;
34  
35  @SuppressWarnings("unused")
36  public class Chart {
37    private String id;
38    private String title;
39    private String graphType;
40    private ArrayList<TreeMap<String, TreeMap<String, Double>>> dataset;
41    private ArrayList<String> chartType;
42    private ArrayList<String> restData;
43    private boolean xLabelOn;
44    private boolean yLabelOn;
45    private boolean yRightLabelOn;
46    private int width;
47    private int height;
48    private List<String> xLabelRange;
49    private HashMap<String, Long> xLabelRangeHash;
50    private HttpServletRequest request = null;
51    private boolean legend;
52    private String xLabel = "";
53    private String yLabel = "";
54    private String yRightLabel = "";
55    private int datasetCounter = 0;
56    private double max = 0;
57    private double min = 0;
58    private int seriesCounter = 0;
59    private List<String> rightList;
60    private boolean userDefinedMax = false;
61    private boolean userDefinedMin = false;
62    private boolean displayPercentage = false;
63    private String[] seriesOrder = null;
64    private XssFilter xf = null;
65    
66    public Chart(HttpServletRequest request) {
67      xf = new XssFilter(request);
68      if (request != null && xf.getParameter("boxId") != null) {
69        this.id = xf.getParameter("boxId");
70      } else {
71        this.id = "0";
72      }
73      this.title = "Untitled Chart";
74      this.graphType = "image";
75      this.xLabelOn = true;
76      this.yLabelOn = true;
77      this.width = 400;
78      this.height = 200;
79      this.request = request;
80      this.legend = true;
81      this.max = 0;
82      this.datasetCounter = 0;
83      this.seriesCounter = 0;
84      this.rightList = new ArrayList<String>();
85      this.userDefinedMax = false;
86      this.userDefinedMin = false;
87      this.displayPercentage = false;
88      this.seriesOrder = null;
89    }
90  
91    public void setYMax(double max) {
92      this.max = max;
93      this.userDefinedMax = true;
94    }
95  
96    public void setYMin(double min) {
97      this.min = min;
98      this.userDefinedMin = true;
99    }
100 
101   public void setDisplayPercentage(boolean percentage) {
102     this.displayPercentage = percentage;
103   }
104 
105   public void setSize(int width, int height) {
106     this.width = width;
107     this.height = height;
108   }
109 
110   public void setGraphType(String graphType) {
111     if (graphType != null) {
112       this.graphType = graphType;
113     }
114   }
115 
116   public void setTitle(String title) {
117     this.title = title;
118   }
119 
120   public void setId(String id) {
121     this.id = id;
122   }
123 
124   public void setDataSet(String chartType,
125     TreeMap<String, TreeMap<String, Double>> data) {
126     if (this.dataset == null) {
127       this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>();
128       this.chartType = new ArrayList<String>();
129     }
130     this.dataset.add(data);
131     this.chartType.add(chartType);
132   }
133 
134   public void setDataSet(String chartType, String series, String data) {
135     if (this.dataset == null) {
136       this.restData = new ArrayList<String>();
137       this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>();
138       this.chartType = new ArrayList<String>();
139     }
140     this.chartType.add(chartType);
141     this.restData.add(data);
142     TreeMap<String, TreeMap<String, Double>> tree = new TreeMap<String, TreeMap<String, Double>>();
143     tree.put(series, new TreeMap<String, Double>()); 
144     this.dataset.add(tree);
145   }
146 
147   public void setSeriesOrder(String[] metrics) {
148     this.seriesOrder = (String[]) metrics.clone();
149   }
150 
151   public void setXAxisLabels(boolean toggle) {
152     xLabelOn = toggle;
153   }
154 
155   public void setYAxisLabels(boolean toggle) {
156     yLabelOn = toggle;
157   }
158 
159   public void setYAxisRightLabels(boolean toggle) {
160     yRightLabelOn = toggle;
161   }
162 
163   public void setXAxisLabel(String label) {
164     xLabel = label;
165   }
166 
167   public void setYAxisLabel(String label) {
168     yLabel = label;
169   }
170 
171   public void setYAxisRightLabel(String label) {
172     yRightLabel = label;
173   }
174 
175   public void setXLabelsRange(List<String> range) {
176     xLabelRange = range;
177     xLabelRangeHash = new HashMap<String, Long>();
178     long value = 0;
179     for (String label : range) {
180       xLabelRangeHash.put(label, value);
181       value++;
182     }
183   }
184 
185   public void setLegend(boolean toggle) {
186     legend = toggle;
187   }
188 
189   public String plot() {
190     StringBuilder output = new StringBuilder();
191     if (dataset == null && restData == null) {
192       output.append("No Data available.");
193       return output.toString();
194     }
195     String dateFormat = "%H:%M";
196     if (xLabel.intern() == "Time".intern()) {
197 //      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
198 //      try {
199 //        long xMin = 0;
200 //        long xMax = 0;
201 //        if(xLabelRange!=null && xLabelRange.size()>0) {
202 //          xMin = Long.parseLong(xLabelRange.get(0));
203 //          xMax = Long.parseLong(xLabelRange.get(xLabelRange.size() - 1));
204 //        }
205 //        if (xMax - xMin > 31536000000L) {
206 //          dateFormat = "%y";
207 //        } else if (xMax - xMin > 2592000000L) {
208 //          dateFormat = "%y-%m";
209 //        } else if (xMax - xMin > 604800000L) {
210 //          dateFormat = "%m-%d";
211 //        } else if (xMax - xMin > 86400000L) {
212 //          dateFormat = "%m-%d %H:%M";
213 //        }
214 //      } catch (NumberFormatException e) {
215 //        dateFormat = "%y-%m-%d %H:%M";
216 //      }
217     }
218     StringBuilder xAxisOptions = new StringBuilder();
219     if (xLabel.intern() == "Time".intern()) {
220 //      if(this.restData==null) {
221 //        xAxisOptions.append("timeformat: \"");
222 //        xAxisOptions.append(dateFormat);
223 //        xAxisOptions.append("\",");
224 //      }
225       xAxisOptions.append("mode: \"time\"");
226     } else {
227       xAxisOptions
228           .append("tickFormatter: function (val, axis) { if(val!=0) { return xLabels[Math.round(val)]; } else { return \" \"; }; }, ticks: 5");
229     }
230     if (request != null && xf.getParameter("format") == null) {
231       output
232           .append("<html><link href=\"/hicc/css/default.css\" rel=\"stylesheet\" type=\"text/css\">\n");
233       output
234           .append("<html><link href=\"/hicc/css/iframe.css\" rel=\"stylesheet\" type=\"text/css\">\n");
235       output
236           .append("<html><link href=\"/hicc/css/flexigrid/flexigrid.css\" rel=\"stylesheet\" type=\"text/css\">\n");
237       output
238           .append("<body><script type=\"text/javascript\" src=\"/hicc/js/jquery-1.2.6.min.js\"></script>\n");
239       output
240           .append("<script type=\"text/javascript\" src=\"/hicc/js/jquery.flot.pack.js\"></script>\n");
241       output
242           .append("<script type=\"text/javascript\" src=\"/hicc/js/flexigrid.pack.js\"></script>\n");
243       output
244           .append("<script type=\"text/javascript\" src=\"/hicc/js/excanvas.pack.js\"></script>\n");
245       output
246           .append("<script type=\"text/javascript\" src=\"/hicc/js/base64.js\"></script>\n");
247       output
248           .append("<script type=\"text/javascript\" src=\"/hicc/js/canvas2image.js\"></script>\n");
249       output.append("<div id=\"placeholderTitle\"><center>" + title
250           + "</center></div>\n");
251       output.append("<div id=\"placeholder\" style=\"width:" + this.width
252           + "px;height:" + this.height + "px;\"></div>\n");
253       output.append("<center><div id=\"placeholderLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
254       output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
255       output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n");
256       output.append("<input type=\"hidden\" id=\"boxId\" value=\"iframe"
257           + this.id + "\">\n");
258       output
259           .append("<script type=\"text/javascript\" src=\"/hicc/js/flot.extend.js\">\n");
260       output.append("</script>\n");
261       output.append("<script type=\"text/javascript\">\n");
262       output.append("var chartTitle=\"<center>" + title + "</center>\";\n");
263       output.append("var height=" + this.height + ";\n");
264       output.append("var xLabels=new Array();\n");
265       output.append("var cw = document.body.clientWidth-70;\n");
266       output.append("var ch = document.body.clientHeight-50;\n");
267       output
268           .append("document.getElementById('placeholder').style.width=cw+'px';\n");
269       output
270           .append("document.getElementById('placeholder').style.height=ch+'px';\n");
271     }
272     output.append("_options={\n");
273     output.append("        points: { show: false },\n");
274     output.append("        xaxis: { " + xAxisOptions + " },\n");
275     output.append("	  selection: { mode: \"xy\" },\n");
276     output.append("	  grid: {\n");
277     output.append("	           clickable: true,\n");
278     output.append("	           hoverable: true,\n");
279     output.append("	           tickColor: \"#C0C0C0\",\n");
280     output.append("            borderWidth: 0,\n");
281     output.append("	           backgroundColor:\"#F9F9F9\"\n");
282     output.append("	  },\n");
283     output.append("	  legend: { show: " + this.legend
284         + ", noColumns: 3, container: $(\"#placeholderLegend\") },\n");
285     output.append("        yaxis: { ");
286     boolean stack = false;
287     for (String type : this.chartType) {
288       if (type.startsWith("stack")) {
289         stack = true;
290       }
291     }
292     if (stack) {
293       output.append("mode: \"stack\", ");
294     }
295     if (displayPercentage) {
296       output
297           .append("tickFormatter: function(val, axis) { return val.toFixed(axis.tickDecimals) + \" %\"; }");
298     } else {
299       output.append("tickFormatter: function(val, axis) { ");
300       output
301           .append("if (val >= 1000000000000000) return (val / 1000000000000000).toFixed(2) + \"x10<sup>15</sup>\";");
302       output
303           .append("else if (val >= 100000000000000) return (val / 100000000000000).toFixed(2) + \"x10<sup>14</sup>\";");
304       output
305           .append("else if (val >= 10000000000000) return (val / 10000000000000).toFixed(2) + \"x10<sup>13</sup>\";");
306       output
307           .append("else if (val >= 1000000000000) return (val / 1000000000000).toFixed(2) + \"x10<sup>12</sup>\";");
308       output
309           .append("else if (val >= 100000000000) return (val / 100000000000).toFixed(2) + \"x10<sup>11</sup>\";");
310       output
311           .append("else if (val >= 10000000000) return (val / 10000000000).toFixed(2) + \"x10<sup>10</sup>\";");
312       output
313           .append("else if (val >= 1000000000) return (val / 1000000000).toFixed(2) + \"x10<sup>9</sup>\";");
314       output
315           .append("else if (val >= 100000000) return (val / 100000000).toFixed(2) + \"x10<sup>8</sup>\";");
316       output
317           .append("else if (val >= 10000000) return (val / 10000000).toFixed(2) + \"x10<sup>7</sup>\";");
318       output
319           .append("else if (val >= 1000000) return (val / 1000000).toFixed(2) + \"x10<sup>6</sup>\";");
320       output
321           .append("else if (val >= 100000) return (val / 100000).toFixed(2) + \"x10<sup>5</sup>\";");
322       output
323           .append("else if (val >= 10000) return (val / 10000).toFixed(2) + \"x10<sup>4</sup>\";");
324       output
325           .append("else if (val >= 2000) return (val / 1000).toFixed(2) + \"x10<sup>3</sup>\";");
326       output.append("else return val.toFixed(2) + \"\"; }");
327     }
328     if (userDefinedMin) {
329       output.append(", min:");
330       output.append(this.min);
331     }
332     if (userDefinedMax) {
333       output.append(", max:");
334       output.append(this.max);
335     }
336     output.append("}\n");
337     output.append("	};\n");
338     if (!xLabel.equals("Time")) {
339       output.append("xLabels = [\"");
340       for (int i = 0; i < xLabelRange.size(); i++) {
341         if (i > 0) {
342           output.append("\",\"");
343         }
344         output.append(xLabelRange.get(i));
345       }
346       output.append("\"];\n");
347     }
348     output.append("_series=[\n");
349     ColorPicker cp = new ColorPicker();
350     int i = 0;
351     if(this.dataset!=null) {
352       for (TreeMap<String, TreeMap<String, Double>> dataMap : this.dataset) {
353         String[] keyNames;
354         if (this.seriesOrder != null) {
355           keyNames = this.seriesOrder;
356         } else {
357           keyNames = dataMap.keySet().toArray(
358               new String[dataMap.size()]);
359         }
360         int counter = 0;
361         if (i != 0 && !this.userDefinedMax) {
362             this.max = 0;
363         }
364         for (String seriesName : keyNames) {
365           int counter2 = 0;
366           if ((counter != 0) || (i != 0)) {
367             output.append(",");
368           }
369           String param = "fill: false, lineWidth: 1";
370           String type = "lines";
371           if (this.chartType.get(i).intern() == "stack-area".intern()
372               || this.chartType.get(i).intern() == "area".intern()) {
373             param = "fill: true, lineWidth: 0";
374           }
375           if (this.chartType.get(i).intern() == "bar".intern()) {
376             type = "bars";
377             param = "stepByStep: true, lineWidth: 0";
378           }
379           if (this.chartType.get(i).intern() == "point".intern()) {
380             type = "points";
381             param = "fill: false";
382           }
383           output.append("  {");
384           output.append(type);
385           output.append(": { show: true, ");
386           output.append(param);
387           output.append(" }, color: \"");
388           output.append(cp.getNext());
389           output.append("\", label: \"");
390           output.append(seriesName);
391           output.append("\", ");
392           String showYAxis = "false";
393           String shortRow = "false";
394           if (counter == 0 || i > 0) {
395             showYAxis = "true";
396             shortRow = "false";
397           }
398           output.append(" row: { show: ");
399           output.append(showYAxis);
400           output.append(",shortRow:");
401           output.append(shortRow);
402           output.append(", showYAxis:");
403           output.append(showYAxis);
404           output.append("}, data:[");
405           TreeMap<String, Double> data = dataMap.get(seriesName);
406           if(data!=null) {
407             java.util.Iterator<Entry<String, Double>> iter = data.entrySet().iterator();
408             while (iter.hasNext()) {
409               Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iter.next();
410               int rangeLabel = 0;
411               if (counter2 != 0) {
412                 output.append(",");
413               }
414               if (xLabel.equals("Time")) {
415                 if (Double.isNaN(entry.getValue())) {
416                   output.append("[");
417                   output.append(entry.getKey());
418                   output.append(",NULL]");
419                 } else {
420                   output.append("[");
421                   output.append(entry.getKey());
422                   output.append(",");
423                   output.append(entry.getValue());
424                   output.append("]");
425                 }
426               } else {
427                 long value = xLabelRangeHash.get(entry.getKey());
428                 if (Double.isNaN(entry.getValue())) {
429                   output.append("[");
430                   output.append(value);
431                   output.append(",NULL]");
432                 } else {
433                   output.append("[");
434                   output.append(value);
435                   output.append(",");
436                   output.append(entry.getValue());
437                   output.append("]");
438                 }
439                 rangeLabel++;
440               }
441               counter2++;
442             }
443           }
444           output.append("], min:0");
445           if (this.userDefinedMax) {
446             output.append(", max:");
447             output.append(this.max);
448           }
449           output.append("}");
450           counter++;
451         }
452         i++;
453       }
454       }
455     output.append(" ];\n");
456     if(this.restData!=null) {
457       JSONArray arr = new JSONArray();
458       for(String url : restData) {
459         arr.put(url);
460       }
461       output.append("var _rest = ");
462       output.append(arr.toString());
463       output.append(";");
464     }
465     if (request != null && xf.getParameter("format") == null) {
466       output.append("$(document).ready(function() { \n");
467       if(this.restData!=null) {
468         output.append("   loadData();\n");
469       } else {
470         output.append("   wholePeriod();\n");
471       }
472       output.append("   $(window).resize(function() { wholePeriod(); });\n");
473       output.append("});\n");
474       output.append("</script>\n");
475       output.append("<input type=\"button\" value=\"Export\" onclick=\"javascript:saveReport();\">\n");
476       output.append("</body></html>\n");
477     } else {
478       output.append("chartTitle=\"<center>" + this.title + "</center>\";");
479       output.append("height=" + this.height + ";");
480     }
481     return output.toString();
482   }
483 }