| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.chukwa.hicc; |
| |
| |
| import java.util.ArrayList; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map.Entry; |
| import java.text.SimpleDateFormat; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.swing.text.html.HTMLDocument.Iterator; |
| |
| import org.apache.hadoop.chukwa.util.XssFilter; |
| import org.json.JSONArray; |
| |
| @SuppressWarnings("unused") |
| public class Chart { |
| private String id; |
| private String title; |
| private String graphType; |
| private ArrayList<TreeMap<String, TreeMap<String, Double>>> dataset; |
| private ArrayList<String> chartType; |
| private ArrayList<String> restData; |
| private boolean xLabelOn; |
| private boolean yLabelOn; |
| private boolean yRightLabelOn; |
| private int width; |
| private int height; |
| private List<String> xLabelRange; |
| private HashMap<String, Long> xLabelRangeHash; |
| private HttpServletRequest request = null; |
| private boolean legend; |
| private String xLabel = ""; |
| private String yLabel = ""; |
| private String yRightLabel = ""; |
| private int datasetCounter = 0; |
| private double max = 0; |
| private double min = 0; |
| private int seriesCounter = 0; |
| private List<String> rightList; |
| private boolean userDefinedMax = false; |
| private boolean userDefinedMin = false; |
| private boolean displayPercentage = false; |
| private String[] seriesOrder = null; |
| private XssFilter xf = null; |
| |
| public Chart(HttpServletRequest request) { |
| xf = new XssFilter(request); |
| if (request != null && xf.getParameter("boxId") != null) { |
| this.id = xf.getParameter("boxId"); |
| } else { |
| this.id = "0"; |
| } |
| this.title = "Untitled Chart"; |
| this.graphType = "image"; |
| this.xLabelOn = true; |
| this.yLabelOn = true; |
| this.width = 400; |
| this.height = 200; |
| this.request = request; |
| this.legend = true; |
| this.max = 0; |
| this.datasetCounter = 0; |
| this.seriesCounter = 0; |
| this.rightList = new ArrayList<String>(); |
| this.userDefinedMax = false; |
| this.userDefinedMin = false; |
| this.displayPercentage = false; |
| this.seriesOrder = null; |
| } |
| |
| public void setYMax(double max) { |
| this.max = max; |
| this.userDefinedMax = true; |
| } |
| |
| public void setYMin(double min) { |
| this.min = min; |
| this.userDefinedMin = true; |
| } |
| |
| public void setDisplayPercentage(boolean percentage) { |
| this.displayPercentage = percentage; |
| } |
| |
| public void setSize(int width, int height) { |
| this.width = width; |
| this.height = height; |
| } |
| |
| public void setGraphType(String graphType) { |
| if (graphType != null) { |
| this.graphType = graphType; |
| } |
| } |
| |
| public void setTitle(String title) { |
| this.title = title; |
| } |
| |
| public void setId(String id) { |
| this.id = id; |
| } |
| |
| public void setDataSet(String chartType, |
| TreeMap<String, TreeMap<String, Double>> data) { |
| if (this.dataset == null) { |
| this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>(); |
| this.chartType = new ArrayList<String>(); |
| } |
| this.dataset.add(data); |
| this.chartType.add(chartType); |
| } |
| |
| public void setDataSet(String chartType, String series, String data) { |
| if (this.dataset == null) { |
| this.restData = new ArrayList<String>(); |
| this.dataset = new ArrayList<TreeMap<String, TreeMap<String, Double>>>(); |
| this.chartType = new ArrayList<String>(); |
| } |
| this.chartType.add(chartType); |
| this.restData.add(data); |
| TreeMap<String, TreeMap<String, Double>> tree = new TreeMap<String, TreeMap<String, Double>>(); |
| tree.put(series, new TreeMap<String, Double>()); |
| this.dataset.add(tree); |
| } |
| |
| public void setSeriesOrder(String[] metrics) { |
| this.seriesOrder = (String[]) metrics.clone(); |
| } |
| |
| public void setXAxisLabels(boolean toggle) { |
| xLabelOn = toggle; |
| } |
| |
| public void setYAxisLabels(boolean toggle) { |
| yLabelOn = toggle; |
| } |
| |
| public void setYAxisRightLabels(boolean toggle) { |
| yRightLabelOn = toggle; |
| } |
| |
| public void setXAxisLabel(String label) { |
| xLabel = label; |
| } |
| |
| public void setYAxisLabel(String label) { |
| yLabel = label; |
| } |
| |
| public void setYAxisRightLabel(String label) { |
| yRightLabel = label; |
| } |
| |
| public void setXLabelsRange(List<String> range) { |
| xLabelRange = range; |
| xLabelRangeHash = new HashMap<String, Long>(); |
| long value = 0; |
| for (String label : range) { |
| xLabelRangeHash.put(label, value); |
| value++; |
| } |
| } |
| |
| public void setLegend(boolean toggle) { |
| legend = toggle; |
| } |
| |
| public String plot() { |
| StringBuilder output = new StringBuilder(); |
| if (dataset == null && restData == null) { |
| output.append("No Data available."); |
| return output.toString(); |
| } |
| String dateFormat = "%H:%M"; |
| if (xLabel.intern() == "Time".intern()) { |
| // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| // try { |
| // long xMin = 0; |
| // long xMax = 0; |
| // if(xLabelRange!=null && xLabelRange.size()>0) { |
| // xMin = Long.parseLong(xLabelRange.get(0)); |
| // xMax = Long.parseLong(xLabelRange.get(xLabelRange.size() - 1)); |
| // } |
| // if (xMax - xMin > 31536000000L) { |
| // dateFormat = "%y"; |
| // } else if (xMax - xMin > 2592000000L) { |
| // dateFormat = "%y-%m"; |
| // } else if (xMax - xMin > 604800000L) { |
| // dateFormat = "%m-%d"; |
| // } else if (xMax - xMin > 86400000L) { |
| // dateFormat = "%m-%d %H:%M"; |
| // } |
| // } catch (NumberFormatException e) { |
| // dateFormat = "%y-%m-%d %H:%M"; |
| // } |
| } |
| StringBuilder xAxisOptions = new StringBuilder(); |
| if (xLabel.intern() == "Time".intern()) { |
| // if(this.restData==null) { |
| // xAxisOptions.append("timeformat: \""); |
| // xAxisOptions.append(dateFormat); |
| // xAxisOptions.append("\","); |
| // } |
| xAxisOptions.append("mode: \"time\""); |
| } else { |
| xAxisOptions |
| .append("tickFormatter: function (val, axis) { if(val!=0) { return xLabels[Math.round(val)]; } else { return \" \"; }; }, ticks: 5"); |
| } |
| if (request != null && xf.getParameter("format") == null) { |
| output |
| .append("<html><link href=\"/hicc/css/default.css\" rel=\"stylesheet\" type=\"text/css\">\n"); |
| output |
| .append("<html><link href=\"/hicc/css/iframe.css\" rel=\"stylesheet\" type=\"text/css\">\n"); |
| output |
| .append("<html><link href=\"/hicc/css/flexigrid/flexigrid.css\" rel=\"stylesheet\" type=\"text/css\">\n"); |
| output |
| .append("<body><script type=\"text/javascript\" src=\"/hicc/js/jquery-1.2.6.min.js\"></script>\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/jquery.flot.pack.js\"></script>\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/flexigrid.pack.js\"></script>\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/excanvas.pack.js\"></script>\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/base64.js\"></script>\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/canvas2image.js\"></script>\n"); |
| output.append("<div id=\"placeholderTitle\"><center>" + title |
| + "</center></div>\n"); |
| output.append("<div id=\"placeholder\" style=\"width:" + this.width |
| + "px;height:" + this.height + "px;\"></div>\n"); |
| output.append("<center><div id=\"placeholderLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); |
| output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); |
| output.append("<center><div id=\"statisLegend\" style=\"display:"+(legend?"block":"none")+";\"></div></center>\n"); |
| output.append("<input type=\"hidden\" id=\"boxId\" value=\"iframe" |
| + this.id + "\">\n"); |
| output |
| .append("<script type=\"text/javascript\" src=\"/hicc/js/flot.extend.js\">\n"); |
| output.append("</script>\n"); |
| output.append("<script type=\"text/javascript\">\n"); |
| output.append("var chartTitle=\"<center>" + title + "</center>\";\n"); |
| output.append("var height=" + this.height + ";\n"); |
| output.append("var xLabels=new Array();\n"); |
| output.append("var cw = document.body.clientWidth-70;\n"); |
| output.append("var ch = document.body.clientHeight-50;\n"); |
| output |
| .append("document.getElementById('placeholder').style.width=cw+'px';\n"); |
| output |
| .append("document.getElementById('placeholder').style.height=ch+'px';\n"); |
| } |
| output.append("_options={\n"); |
| output.append(" points: { show: false },\n"); |
| output.append(" xaxis: { " + xAxisOptions + " },\n"); |
| output.append(" selection: { mode: \"xy\" },\n"); |
| output.append(" grid: {\n"); |
| output.append(" clickable: true,\n"); |
| output.append(" hoverable: true,\n"); |
| output.append(" tickColor: \"#C0C0C0\",\n"); |
| output.append(" borderWidth: 0,\n"); |
| output.append(" backgroundColor:\"#F9F9F9\"\n"); |
| output.append(" },\n"); |
| output.append(" legend: { show: " + this.legend |
| + ", noColumns: 3, container: $(\"#placeholderLegend\") },\n"); |
| output.append(" yaxis: { "); |
| boolean stack = false; |
| for (String type : this.chartType) { |
| if (type.startsWith("stack")) { |
| stack = true; |
| } |
| } |
| if (stack) { |
| output.append("mode: \"stack\", "); |
| } |
| if (displayPercentage) { |
| output |
| .append("tickFormatter: function(val, axis) { return val.toFixed(axis.tickDecimals) + \" %\"; }"); |
| } else { |
| output.append("tickFormatter: function(val, axis) { "); |
| output |
| .append("if (val >= 1000000000000000) return (val / 1000000000000000).toFixed(2) + \"x10<sup>15</sup>\";"); |
| output |
| .append("else if (val >= 100000000000000) return (val / 100000000000000).toFixed(2) + \"x10<sup>14</sup>\";"); |
| output |
| .append("else if (val >= 10000000000000) return (val / 10000000000000).toFixed(2) + \"x10<sup>13</sup>\";"); |
| output |
| .append("else if (val >= 1000000000000) return (val / 1000000000000).toFixed(2) + \"x10<sup>12</sup>\";"); |
| output |
| .append("else if (val >= 100000000000) return (val / 100000000000).toFixed(2) + \"x10<sup>11</sup>\";"); |
| output |
| .append("else if (val >= 10000000000) return (val / 10000000000).toFixed(2) + \"x10<sup>10</sup>\";"); |
| output |
| .append("else if (val >= 1000000000) return (val / 1000000000).toFixed(2) + \"x10<sup>9</sup>\";"); |
| output |
| .append("else if (val >= 100000000) return (val / 100000000).toFixed(2) + \"x10<sup>8</sup>\";"); |
| output |
| .append("else if (val >= 10000000) return (val / 10000000).toFixed(2) + \"x10<sup>7</sup>\";"); |
| output |
| .append("else if (val >= 1000000) return (val / 1000000).toFixed(2) + \"x10<sup>6</sup>\";"); |
| output |
| .append("else if (val >= 100000) return (val / 100000).toFixed(2) + \"x10<sup>5</sup>\";"); |
| output |
| .append("else if (val >= 10000) return (val / 10000).toFixed(2) + \"x10<sup>4</sup>\";"); |
| output |
| .append("else if (val >= 2000) return (val / 1000).toFixed(2) + \"x10<sup>3</sup>\";"); |
| output.append("else return val.toFixed(2) + \"\"; }"); |
| } |
| if (userDefinedMin) { |
| output.append(", min:"); |
| output.append(this.min); |
| } |
| if (userDefinedMax) { |
| output.append(", max:"); |
| output.append(this.max); |
| } |
| output.append("}\n"); |
| output.append(" };\n"); |
| if (!xLabel.equals("Time")) { |
| output.append("xLabels = [\""); |
| for (int i = 0; i < xLabelRange.size(); i++) { |
| if (i > 0) { |
| output.append("\",\""); |
| } |
| output.append(xLabelRange.get(i)); |
| } |
| output.append("\"];\n"); |
| } |
| output.append("_series=[\n"); |
| ColorPicker cp = new ColorPicker(); |
| int i = 0; |
| if(this.dataset!=null) { |
| for (TreeMap<String, TreeMap<String, Double>> dataMap : this.dataset) { |
| String[] keyNames; |
| if (this.seriesOrder != null) { |
| keyNames = this.seriesOrder; |
| } else { |
| keyNames = dataMap.keySet().toArray( |
| new String[dataMap.size()]); |
| } |
| int counter = 0; |
| if (i != 0 && !this.userDefinedMax) { |
| this.max = 0; |
| } |
| for (String seriesName : keyNames) { |
| int counter2 = 0; |
| if ((counter != 0) || (i != 0)) { |
| output.append(","); |
| } |
| String param = "fill: false, lineWidth: 1"; |
| String type = "lines"; |
| if (this.chartType.get(i).intern() == "stack-area".intern() |
| || this.chartType.get(i).intern() == "area".intern()) { |
| param = "fill: true, lineWidth: 0"; |
| } |
| if (this.chartType.get(i).intern() == "bar".intern()) { |
| type = "bars"; |
| param = "stepByStep: true, lineWidth: 0"; |
| } |
| if (this.chartType.get(i).intern() == "point".intern()) { |
| type = "points"; |
| param = "fill: false"; |
| } |
| output.append(" {"); |
| output.append(type); |
| output.append(": { show: true, "); |
| output.append(param); |
| output.append(" }, color: \""); |
| output.append(cp.getNext()); |
| output.append("\", label: \""); |
| output.append(seriesName); |
| output.append("\", "); |
| String showYAxis = "false"; |
| String shortRow = "false"; |
| if (counter == 0 || i > 0) { |
| showYAxis = "true"; |
| shortRow = "false"; |
| } |
| output.append(" row: { show: "); |
| output.append(showYAxis); |
| output.append(",shortRow:"); |
| output.append(shortRow); |
| output.append(", showYAxis:"); |
| output.append(showYAxis); |
| output.append("}, data:["); |
| TreeMap<String, Double> data = dataMap.get(seriesName); |
| if(data!=null) { |
| java.util.Iterator<Entry<String, Double>> iter = data.entrySet().iterator(); |
| while (iter.hasNext()) { |
| Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iter.next(); |
| int rangeLabel = 0; |
| if (counter2 != 0) { |
| output.append(","); |
| } |
| if (xLabel.equals("Time")) { |
| if (Double.isNaN(entry.getValue())) { |
| output.append("["); |
| output.append(entry.getKey()); |
| output.append(",NULL]"); |
| } else { |
| output.append("["); |
| output.append(entry.getKey()); |
| output.append(","); |
| output.append(entry.getValue()); |
| output.append("]"); |
| } |
| } else { |
| long value = xLabelRangeHash.get(entry.getKey()); |
| if (Double.isNaN(entry.getValue())) { |
| output.append("["); |
| output.append(value); |
| output.append(",NULL]"); |
| } else { |
| output.append("["); |
| output.append(value); |
| output.append(","); |
| output.append(entry.getValue()); |
| output.append("]"); |
| } |
| rangeLabel++; |
| } |
| counter2++; |
| } |
| } |
| output.append("], min:0"); |
| if (this.userDefinedMax) { |
| output.append(", max:"); |
| output.append(this.max); |
| } |
| output.append("}"); |
| counter++; |
| } |
| i++; |
| } |
| } |
| output.append(" ];\n"); |
| if(this.restData!=null) { |
| JSONArray arr = new JSONArray(); |
| for(String url : restData) { |
| arr.put(url); |
| } |
| output.append("var _rest = "); |
| output.append(arr.toString()); |
| output.append(";"); |
| } |
| if (request != null && xf.getParameter("format") == null) { |
| output.append("$(document).ready(function() { \n"); |
| if(this.restData!=null) { |
| output.append(" loadData();\n"); |
| } else { |
| output.append(" wholePeriod();\n"); |
| } |
| output.append(" $(window).resize(function() { wholePeriod(); });\n"); |
| output.append("});\n"); |
| output.append("</script>\n"); |
| output.append("<input type=\"button\" value=\"Export\" onclick=\"javascript:saveReport();\">\n"); |
| output.append("</body></html>\n"); |
| } else { |
| output.append("chartTitle=\"<center>" + this.title + "</center>\";"); |
| output.append("height=" + this.height + ";"); |
| } |
| return output.toString(); |
| } |
| } |