From 1e2d2f2495e8409b4be31ff947864167a67fd6bb Mon Sep 17 00:00:00 2001 From: tryan Date: Mon, 7 Apr 2014 16:04:45 +1000 Subject: Switch to self-hosted flotr2 graphs from Google Charts --- .../java/com/gitblit/wicket/charting/Chart.java | 145 +++++ .../java/com/gitblit/wicket/charting/Charts.java | 48 ++ .../gitblit/wicket/charting/Flotr2BarChart.java | 167 ++++++ .../com/gitblit/wicket/charting/Flotr2Charts.java | 76 +++ .../gitblit/wicket/charting/Flotr2LineChart.java | 150 +++++ .../gitblit/wicket/charting/Flotr2PieChart.java | 112 ++++ .../com/gitblit/wicket/charting/GoogleChart.java | 107 ---- .../com/gitblit/wicket/charting/GoogleCharts.java | 67 --- .../gitblit/wicket/charting/GoogleLineChart.java | 60 -- .../gitblit/wicket/charting/GooglePieChart.java | 86 --- .../com/gitblit/wicket/charting/SecureChart.java | 633 --------------------- .../wicket/charting/SecureChartDataEncoding.java | 102 ---- .../com/gitblit/wicket/pages/ActivityPage.java | 27 +- .../com/gitblit/wicket/pages/DashboardPage.java | 14 +- .../java/com/gitblit/wicket/pages/MetricsPage.html | 12 +- .../java/com/gitblit/wicket/pages/MetricsPage.java | 123 ++-- .../com/gitblit/wicket/pages/MyDashboardPage.html | 4 +- .../com/gitblit/wicket/pages/OverviewPage.java | 11 +- .../java/com/gitblit/wicket/pages/SummaryPage.html | 2 +- .../java/com/gitblit/wicket/pages/SummaryPage.java | 82 +-- src/main/resources/flotr2/flotr2.custom.css | 21 + src/main/resources/flotr2/flotr2.min.js | 10 + 22 files changed, 869 insertions(+), 1190 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/charting/Chart.java create mode 100644 src/main/java/com/gitblit/wicket/charting/Charts.java create mode 100644 src/main/java/com/gitblit/wicket/charting/Flotr2BarChart.java create mode 100644 src/main/java/com/gitblit/wicket/charting/Flotr2Charts.java create mode 100644 src/main/java/com/gitblit/wicket/charting/Flotr2LineChart.java create mode 100644 src/main/java/com/gitblit/wicket/charting/Flotr2PieChart.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/GoogleChart.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/GoogleCharts.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/GooglePieChart.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/SecureChart.java delete mode 100644 src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java create mode 100644 src/main/resources/flotr2/flotr2.custom.css create mode 100644 src/main/resources/flotr2/flotr2.min.js (limited to 'src') diff --git a/src/main/java/com/gitblit/wicket/charting/Chart.java b/src/main/java/com/gitblit/wicket/charting/Chart.java new file mode 100644 index 00000000..331b386a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Chart.java @@ -0,0 +1,145 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import com.gitblit.Keys; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebApp; +import com.gitblit.wicket.GitBlitWebSession; + +/** + * Abstract parent class for different type of chart: bar, pie & line + * + * @author James Moger + * + */ +public abstract class Chart implements Serializable { + + private static final long serialVersionUID = 1L; + final String tagId; + final String dataName; + final String title; + final String keyName; + final String valueName; + final List values; + final List highlights; + int width; + int height; + boolean showLegend; + String dateFormat = "MMM dd"; + String clickUrl = null; + + public Chart(String tagId, String title, String keyName, String valueName) { + this.tagId = tagId; + this.dataName = StringUtils.getSHA1(tagId).substring(0, 8); + this.title = title; + this.keyName = keyName; + this.valueName = valueName; + values = new ArrayList(); + highlights = new ArrayList(); + showLegend = true; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setShowLegend(boolean val) { + this.showLegend = val; + } + + public void addValue(String name, int value) { + values.add(new ChartValue(name, value)); + } + + public void addValue(String name, float value) { + values.add(new ChartValue(name, value)); + } + + public void addValue(String name, double value) { + values.add(new ChartValue(name, (float) value)); + } + + public void addValue(Date date, int value) { + values.add(new ChartValue(String.valueOf(date.getTime()), value)); + } + + public void addHighlight(Date date, int value) { + highlights.add(new ChartValue(String.valueOf(date.getTime()), value)); + } + + protected abstract void appendChart(StringBuilder sb); + + protected void line(StringBuilder sb, String line) { + sb.append(line); + sb.append('\n'); + } + + protected TimeZone getTimeZone() { + return GitBlitWebApp.get().settings().getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get() + .getTimezone() : GitBlitWebApp.get().getTimezone(); + } + + protected class ChartValue implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + final String name; + final float value; + + ChartValue(String name, float value) { + this.name = name; + this.value = value; + } + + @Override + public int compareTo(ChartValue o) { + // sorts the dataset by largest value first + if (value > o.value) { + return -1; + } else if (value < o.value) { + return 1; + } + return 0; + } + } + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + public String getClickUrl() { + return clickUrl; + } + + public void setClickUrl(String clickUrl) { + this.clickUrl = clickUrl; + } +} diff --git a/src/main/java/com/gitblit/wicket/charting/Charts.java b/src/main/java/com/gitblit/wicket/charting/Charts.java new file mode 100644 index 00000000..54a7689b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Charts.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.markup.html.IHeaderContributor; + +/** + * Abstract parent class for Flotr2 Charts + * + * @author Tim Ryan + * + */ +public abstract class Charts implements IHeaderContributor { + + private static final long serialVersionUID = 1L; + + public final List charts = new ArrayList(); + + public void addChart(Chart chart) { + charts.add(chart); + } + + protected void line(StringBuilder sb, String line) { + sb.append(line); + sb.append('\n'); + } + + public abstract Chart createPieChart(String tagId, String title, String keyName, String valueName); + public abstract Chart createLineChart(String tagId, String title, String keyName, String valueName); + public abstract Chart createBarChart(String tagId, String title, String keyName, String valueName); + +} diff --git a/src/main/java/com/gitblit/wicket/charting/Flotr2BarChart.java b/src/main/java/com/gitblit/wicket/charting/Flotr2BarChart.java new file mode 100644 index 00000000..4f07555e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Flotr2BarChart.java @@ -0,0 +1,167 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; + +/** + * Implementation of a Bar chart using the flotr2 library + * + * @author Tim Ryan + * + */ +public class Flotr2BarChart extends Chart { + + private static final long serialVersionUID = 1L; + boolean xAxisIsDate = false; + + public Flotr2BarChart(String tagId, String title, String keyName, + String valueName) { + super(tagId, title, keyName, valueName); + + } + + @Override + protected void appendChart(StringBuilder sb) { + + String dName = "data_" + dataName; + sb.append("var labels_" + dataName + " = ["); + if(xAxisIsDate){ + + // Generate labels for the dates + SimpleDateFormat df = new SimpleDateFormat(dateFormat); + df.setTimeZone(getTimeZone()); + + // Sort the values first + Collections.sort(values, new Comparator() { + + public int compare(ChartValue o1, ChartValue o2) { + long long1 = Long.parseLong(o1.name); + long long2 = Long.parseLong(o2.name); + return (int) (long2 - long1); + } + + }); + + + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + Date date = new Date(Long.parseLong(value.name)); + String label = df.format(date); + if(i > 0){ + sb.append(","); + } + sb.append("[\"" + label + "\", " + value.name + "]"); + } + + } + else { + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + if(i > 0){ + sb.append(","); + } + sb.append("\"" + value.name + "\""); + } + } + line(sb, "];"); + + line(sb, MessageFormat.format("var {0} = Flotr.draw(document.getElementById(''{1}''),", dName, tagId)); + + // Add the data + line(sb, "["); + line(sb, "{ data : [ "); + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + if(i > 0){ + sb.append(","); + } + if(xAxisIsDate){ + line(sb, MessageFormat.format("[{0}, {1}] ", value.name, Float.toString(value.value))); + } + else { + line(sb, MessageFormat.format("[{0}, {1}] ", Integer.toString(i), Float.toString(value.value))); + } + + } + line(sb, MessageFormat.format(" ], label : ''{0}'', color: ''#FF9900'' '}'", valueName)); + line(sb, "]"); + + // Add the options + line(sb, ", {"); + if(title != null && title.isEmpty() == false){ + line(sb, MessageFormat.format("title : ''{0}'',", title)); + } + line(sb, "bars : {"); + line(sb, " show : true,"); + line(sb, " horizontal : false,"); + line(sb, " barWidth : 1"); + line(sb, "},"); + line(sb, "points: { show: false },"); + line(sb, "mouse: {"); + line(sb, " track: true,"); + line(sb, " lineColor: '#002060',"); + line(sb, " position: 'ne',"); + line(sb, " trackFormatter: function (obj) {"); + line(sb, " return labels_" + dataName + "[obj.index] + ': ' + parseInt(obj.y) + ' ' + obj.series.label;"); + line(sb, " }"); + line(sb, "},"); + line(sb, "xaxis: {"); + line(sb, " showLabels: true,"); + line(sb, " showMinorLabels: false,"); + line(sb, " tickFormatter: function (x) {"); + line(sb, " var index = parseInt(x);"); + line(sb, " if(x % 1 == 0 && labels_" + dataName + "[index])"); + line(sb, " return labels_" + dataName + "[index];"); + line(sb, " return \"\";"); + line(sb, " },"); + line(sb, " margin: 10"); + line(sb, "},"); + line(sb, "yaxis: {"); + line(sb, " showLabels: false,"); + line(sb, " showMinorLabels: false,"); + line(sb, " tickDecimals: 0,"); + line(sb, " margin: 10"); + line(sb, "},"); + line(sb, "grid: {"); + line(sb, " verticalLines: false,"); + line(sb, " minorVerticalLines: null,"); + line(sb, " horizontalLines: true,"); + line(sb, " minorHorizontalLines: null,"); + line(sb, " outlineWidth: 1,"); + line(sb, " outline: 's'"); + line(sb, "},"); + line(sb, "legend: {"); + line(sb, " show: false"); + line(sb, "}"); + line(sb, "});"); + + } + + @Override + public void addValue(Date date, int value) { + xAxisIsDate = true; + String name = String.valueOf(date.getTime()); + super.addValue(name, value); + } + + + +} diff --git a/src/main/java/com/gitblit/wicket/charting/Flotr2Charts.java b/src/main/java/com/gitblit/wicket/charting/Flotr2Charts.java new file mode 100644 index 00000000..dd723622 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Flotr2Charts.java @@ -0,0 +1,76 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import javax.servlet.ServletContext; + +import org.apache.wicket.markup.html.IHeaderResponse; +import org.apache.wicket.protocol.http.WebApplication; + +/** + * Concrete class for Flotr2 charts + * + * @author Tim Ryan + * + */ +public class Flotr2Charts extends Charts { + + private static final long serialVersionUID = 1L; + + @Override + public void renderHead(IHeaderResponse response) { + + // add Google Chart JS API reference + ServletContext servletContext = WebApplication.get().getServletContext(); + String contextPath = servletContext.getContextPath(); + + response.renderJavascriptReference(contextPath + "/bootstrap/js/jquery.js"); + response.renderJavascriptReference(contextPath + "/flotr2/flotr2.min.js"); + response.renderCSSReference(contextPath + "/flotr2/flotr2.custom.css"); + + // prepare draw chart function + StringBuilder sb = new StringBuilder(); + + line(sb, "$( document ).ready(function() {"); + // add charts to header + for (Chart chart : charts) { + chart.appendChart(sb); + } + + // end draw chart function + line(sb, "});"); + response.renderJavascript(sb.toString(), null); + } + + @Override + public Chart createPieChart(String tagId, String title, String keyName, + String valueName) { + return new Flotr2PieChart(tagId, title, keyName, valueName); + } + + @Override + public Chart createLineChart(String tagId, String title, String keyName, + String valueName) { + return new Flotr2LineChart(tagId, title, keyName, valueName); + } + + @Override + public Chart createBarChart(String tagId, String title, String keyName, + String valueName) { + return new Flotr2BarChart(tagId, title, keyName, valueName); + } + +} diff --git a/src/main/java/com/gitblit/wicket/charting/Flotr2LineChart.java b/src/main/java/com/gitblit/wicket/charting/Flotr2LineChart.java new file mode 100644 index 00000000..f795999c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Flotr2LineChart.java @@ -0,0 +1,150 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Implementation of a Line chart using the flotr2 library + * + * @author Tim Ryan + * + */ +public class Flotr2LineChart extends Chart { + + private static final long serialVersionUID = 1L; + boolean xAxisIsDate = false; + + public Flotr2LineChart(String tagId, String title, String keyName, + String valueName) { + super(tagId, title, keyName, valueName); + + } + + @Override + protected void appendChart(StringBuilder sb) { + + String dName = "data_" + dataName; + sb.append("var labels_" + dataName + " = ["); + if(xAxisIsDate){ + // Generate labels for the dates + SimpleDateFormat df = new SimpleDateFormat(dateFormat); + df.setTimeZone(getTimeZone()); + + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + Date date = new Date(Long.parseLong(value.name)); + String label = df.format(date); + if(i > 0){ + sb.append(","); + } + sb.append("\"" + label + "\""); + } + + } + else { + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + if(i > 0){ + sb.append(","); + } + sb.append("\"" + value.name + "\""); + } + } + line(sb, "];"); + + line(sb, MessageFormat.format("var {0} = Flotr.draw(document.getElementById(''{1}''),", dName, tagId)); + + // Add the data + line(sb, "["); + line(sb, "{ data : [ "); + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + if(i > 0){ + sb.append(","); + } + line(sb, MessageFormat.format("[{0}, {1}] ", value.name, Float.toString(value.value))); + } + line(sb, MessageFormat.format(" ], label : ''{0}'', lines : '{' show : true '}', color: ''#ff9900'' '}'", valueName)); + + if(highlights.size() > 0){ + // get the highlights + line(sb, ", { data : [ "); + for (int i = 0; i < highlights.size(); i++) { + ChartValue value = highlights.get(i); + if(i > 0){ + sb.append(","); + } + line(sb, MessageFormat.format("[{0}, {1}] ", value.name, Float.toString(value.value))); + } + line(sb, MessageFormat.format(" ], label : ''{0}'', points : '{' show : true, fill: true, fillColor:''#002060'' '}', color: ''#ff9900'' '}'", valueName)); + } + line(sb, "]"); + + // Add the options + line(sb, ", {"); + if(title != null && title.isEmpty() == false){ + line(sb, MessageFormat.format("title : ''{0}'',", title)); + } + line(sb, "mouse: {"); + line(sb, " track: true,"); + line(sb, " lineColor: '#002060',"); + line(sb, " position: 'ne',"); + line(sb, " trackFormatter: function (obj) {"); + line(sb, " return labels_" + dataName + "[obj.index] + ': ' + parseInt(obj.y) + ' ' + obj.series.label;"); + line(sb, " }"); + line(sb, "},"); + line(sb, "xaxis: {"); + line(sb, " showLabels: false,"); + line(sb, " showMinorLabels: false,"); + line(sb, " autoscale: true,"); + line(sb, " autoscaleMargin: 0,"); + line(sb, " margin: 10"); + line(sb, "},"); + line(sb, "yaxis: {"); + line(sb, " showLabels: false,"); + line(sb, " showMinorLabels: false,"); + line(sb, " tickDecimals: 0,"); + line(sb, " autoscale: true,"); + line(sb, " autoscaleMargin: 1,"); + line(sb, " margin: 10"); + line(sb, "},"); + line(sb, "grid: {"); + line(sb, " verticalLines: false,"); + line(sb, " minorVerticalLines: null,"); + line(sb, " horizontalLines: true,"); + line(sb, " minorHorizontalLines: null,"); + line(sb, " outlineWidth: 1,"); + line(sb, " outline: 's'"); + line(sb, "},"); + line(sb, "legend: {"); + line(sb, " show: false"); + line(sb, "}"); + line(sb, "});"); + + } + + @Override + public void addValue(Date date, int value) { + xAxisIsDate = true; + super.addValue(date, value); + } + + + +} diff --git a/src/main/java/com/gitblit/wicket/charting/Flotr2PieChart.java b/src/main/java/com/gitblit/wicket/charting/Flotr2PieChart.java new file mode 100644 index 00000000..ea04db94 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/Flotr2PieChart.java @@ -0,0 +1,112 @@ +/* + * Copyright 2011 gitblit.com. + * + * Licensed 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 com.gitblit.wicket.charting; + +import java.text.MessageFormat; + +import com.gitblit.utils.StringUtils; + +/** + * Implementation of a Pie chart using the flotr2 library + * + * @author Tim Ryan + * + */ +public class Flotr2PieChart extends Chart { + + private static final long serialVersionUID = 1L; + + public Flotr2PieChart(String tagId, String title, String keyName, String valueName) { + super(tagId, title, keyName, valueName); + } + + @Override + protected void appendChart(StringBuilder sb) { + + String dName = "data_" + dataName; + line(sb, "var selected_" + dataName + " = null;"); + line(sb, MessageFormat.format("var {0} = Flotr.draw(document.getElementById(''{1}''),", dName, tagId)); + + // Add the data + line(sb, "["); + for (int i = 0; i < values.size(); i++) { + ChartValue value = values.get(i); + if(i > 0){ + sb.append(","); + } + line(sb, MessageFormat.format("'{'data : [ [0, {0}] ], label : ''{1}'', color: ''{2}'' '}'", Float.toString(value.value), value.name, StringUtils.getColor(value.name))); + } + line(sb, "]"); + + // Add the options + line(sb, ", {"); + line(sb, MessageFormat.format("title : ''{0}'',", title)); + line(sb, "fontSize : 2,"); + line(sb, "pie : {"); + line(sb, " show : true,"); + line(sb, " labelFormatter : function (pie, slice) {"); + line(sb, " if(slice / pie > .05)"); + line(sb, " return Math.round(slice / pie * 100).toString() + \"%\";"); + line(sb, " }"); + line(sb, "}"); + line(sb, ", mouse: {"); + line(sb, " track: true,"); + line(sb, " lineColor: '#002060',"); + line(sb, " trackFormatter: function (obj)"); + line(sb, " {"); + line(sb, " selected_" + dataName + " = obj.series.label;"); + line(sb, " return obj.series.label + \": \" + parseInt(obj.y) + \" (\" + Math.round(obj.fraction * 100) + \"%)\";" ); + line(sb, " }"); + line(sb, "}"); + line(sb, ", xaxis: {"); + line(sb, " margin: false,"); + line(sb, " showLabels: false,"); + line(sb, " showMinorLabels: false"); + line(sb, "}"); + line(sb, ", yaxis: {"); + line(sb, " margin: false,"); + line(sb, " min: 20,"); + line(sb, " showLabels: false,"); + line(sb, " showMinorLabels: false"); + line(sb, "}"); + line(sb, ", grid: {"); + line(sb, " verticalLines: false,"); + line(sb, " minorVerticalLines: null,"); + line(sb, " horizontalLines: false,"); + line(sb, " minorHorizontalLines: null,"); + line(sb, " outlineWidth: 0"); + line(sb, "}"); + line(sb, ", legend: {"); + if(showLegend){ + line(sb, " show: true"); + } + else { + line(sb, " show: false"); + } + line(sb, "}"); + line(sb, "});"); + + if(clickUrl != null && clickUrl.isEmpty() == false){ + line(sb, MessageFormat.format("Flotr.EventAdapter.observe(document.getElementById(''{0}''), ''flotr:click'', function (mouse, a, b, c) '{'", tagId)); + line(sb, " window.location.href = \"" + clickUrl + "\" + selected_" + dataName + ";"); + line(sb, "});"); + } + + + + } + +} diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleChart.java b/src/main/java/com/gitblit/wicket/charting/GoogleChart.java deleted file mode 100644 index a7188352..00000000 --- a/src/main/java/com/gitblit/wicket/charting/GoogleChart.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2011 gitblit.com. - * - * Licensed 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 com.gitblit.wicket.charting; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import com.gitblit.utils.StringUtils; - -/** - * Abstract parent class for Google Charts built with the Visualization API. - * - * @author James Moger - * - */ -public abstract class GoogleChart implements Serializable { - - private static final long serialVersionUID = 1L; - final String tagId; - final String dataName; - final String title; - final String keyName; - final String valueName; - final List values; - int width; - int height; - boolean showLegend; - - public GoogleChart(String tagId, String title, String keyName, String valueName) { - this.tagId = tagId; - this.dataName = StringUtils.getSHA1(title).substring(0, 8); - this.title = title; - this.keyName = keyName; - this.valueName = valueName; - values = new ArrayList(); - showLegend = true; - } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } - - public void setShowLegend(boolean val) { - this.showLegend = val; - } - - public void addValue(String name, int value) { - values.add(new ChartValue(name, value)); - } - - public void addValue(String name, float value) { - values.add(new ChartValue(name, value)); - } - - public void addValue(String name, double value) { - values.add(new ChartValue(name, (float) value)); - } - - protected abstract void appendChart(StringBuilder sb); - - protected void line(StringBuilder sb, String line) { - sb.append(line); - sb.append('\n'); - } - - protected class ChartValue implements Serializable, Comparable { - - private static final long serialVersionUID = 1L; - - final String name; - final float value; - - ChartValue(String name, float value) { - this.name = name; - this.value = value; - } - - @Override - public int compareTo(ChartValue o) { - // sorts the dataset by largest value first - if (value > o.value) { - return -1; - } else if (value < o.value) { - return 1; - } - return 0; - } - } -} diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java b/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java deleted file mode 100644 index 8b727936..00000000 --- a/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright 2011 gitblit.com. - - Licensed 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 com.gitblit.wicket.charting; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.wicket.markup.html.IHeaderContributor; -import org.apache.wicket.markup.html.IHeaderResponse; - -/** - * The Google Visualization API provides interactive JavaScript based charts and - * graphs. This class implements the JavaScript header necessary to display - * complete graphs and charts. - * - * @author James Moger - * - */ -public class GoogleCharts implements IHeaderContributor { - - private static final long serialVersionUID = 1L; - - public final List charts = new ArrayList(); - - public void addChart(GoogleChart chart) { - charts.add(chart); - } - - @Override - public void renderHead(IHeaderResponse response) { - // add Google Chart JS API reference - response.renderJavascriptReference("https://www.google.com/jsapi"); - - // prepare draw chart function - StringBuilder sb = new StringBuilder(); - line(sb, "google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});"); - line(sb, "google.setOnLoadCallback(drawChart);"); - line(sb, "function drawChart() {"); - - // add charts to header - for (GoogleChart chart : charts) { - chart.appendChart(sb); - } - - // end draw chart function - line(sb, "}"); - response.renderJavascript(sb.toString(), null); - } - - private void line(StringBuilder sb, String line) { - sb.append(line); - sb.append('\n'); - } -} \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java b/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java deleted file mode 100644 index 44da20ab..00000000 --- a/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011 gitblit.com. - * - * Licensed 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 com.gitblit.wicket.charting; - -import java.text.MessageFormat; - -/** - * Builds an interactive line chart using the Visualization API. - * - * @author James Moger - * - */ -public class GoogleLineChart extends GoogleChart { - - private static final long serialVersionUID = 1L; - - public GoogleLineChart(String tagId, String title, String keyName, String valueName) { - super(tagId, title, keyName, valueName); - } - - @Override - protected void appendChart(StringBuilder sb) { - String dName = "data_" + dataName; - line(sb, MessageFormat.format("var {0} = new google.visualization.DataTable();", dName)); - line(sb, MessageFormat.format("{0}.addColumn(''string'', ''{1}'');", dName, keyName)); - line(sb, MessageFormat.format("{0}.addColumn(''number'', ''{1}'');", dName, valueName)); - line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size())); - - for (int i = 0; i < values.size(); i++) { - ChartValue value = values.get(i); - line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 0, \"{2}\");", dName, i, - value.name)); - line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 1, {2,number,0.0});", dName, - i, value.value)); - } - - String cName = "chart_" + dataName; - line(sb, MessageFormat.format( - "var {0} = new google.visualization.LineChart(document.getElementById(''{1}''));", - cName, tagId)); - line(sb, - MessageFormat - .format("{0}.draw({1}, '{'width: {2,number,0}, height: {3,number,0}, pointSize: 4, chartArea:'{'left:20,top:20'}', vAxis: '{' textPosition: ''none'' '}', legend: ''none'', title: ''{4}'' '}');", - cName, dName, width, height, title)); - line(sb, ""); - } -} \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java deleted file mode 100644 index 71191664..00000000 --- a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2011 gitblit.com. - * - * Licensed 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 com.gitblit.wicket.charting; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.gitblit.utils.StringUtils; - -/** - * Builds an interactive pie chart using the Visualization API. - * - * @author James Moger - * - */ -public class GooglePieChart extends GoogleChart { - - private static final long serialVersionUID = 1L; - - public GooglePieChart(String tagId, String title, String keyName, String valueName) { - super(tagId, title, keyName, valueName); - } - - @Override - protected void appendChart(StringBuilder sb) { - // create dataset - String dName = "data_" + dataName; - line(sb, MessageFormat.format("var {0} = new google.visualization.DataTable();", dName)); - line(sb, MessageFormat.format("{0}.addColumn(''string'', ''{1}'');", dName, keyName)); - line(sb, MessageFormat.format("{0}.addColumn(''number'', ''{1}'');", dName, valueName)); - line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size())); - - Collections.sort(values); - List list = new ArrayList(); - - int maxSlices = 10; - - if (values.size() > maxSlices) { - list.addAll(values.subList(0, maxSlices)); - } else { - list.addAll(values); - } - - StringBuilder colors = new StringBuilder("colors:["); - for (int i = 0; i < list.size(); i++) { - ChartValue value = list.get(i); - colors.append('\''); - colors.append(StringUtils.getColor(value.name)); - colors.append('\''); - if (i < values.size() - 1) { - colors.append(','); - } - line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 0, \"{2}\");", dName, i, - value.name)); - line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 1, {2,number,0.0});", dName, - i, value.value)); - } - colors.append(']'); - - // instantiate chart - String cName = "chart_" + dataName; - line(sb, MessageFormat.format( - "var {0} = new google.visualization.PieChart(document.getElementById(''{1}''));", - cName, tagId)); - line(sb, - MessageFormat - .format("{0}.draw({1}, '{' title: ''{4}'', {5}, legend: '{' position:''{6}'' '}' '}');", - cName, dName, width, height, title, colors.toString(), showLegend ? "right" : "none")); - line(sb, ""); - } -} \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/charting/SecureChart.java b/src/main/java/com/gitblit/wicket/charting/SecureChart.java deleted file mode 100644 index aba25c40..00000000 --- a/src/main/java/com/gitblit/wicket/charting/SecureChart.java +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright 2007 Daniel Spiewak. - * Copyright 2013 gitblit.com. - * - * Licensed 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 com.gitblit.wicket.charting; - -import java.awt.Color; -import java.awt.Dimension; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.wicket.markup.ComponentTag; -import org.apache.wicket.markup.html.WebComponent; -import org.wicketstuff.googlecharts.ChartDataEncoding; -import org.wicketstuff.googlecharts.IChartAxis; -import org.wicketstuff.googlecharts.IChartData; -import org.wicketstuff.googlecharts.IChartFill; -import org.wicketstuff.googlecharts.IChartGrid; -import org.wicketstuff.googlecharts.IChartProvider; -import org.wicketstuff.googlecharts.IFillArea; -import org.wicketstuff.googlecharts.ILineStyle; -import org.wicketstuff.googlecharts.ILinearGradientFill; -import org.wicketstuff.googlecharts.ILinearStripesFill; -import org.wicketstuff.googlecharts.IRangeMarker; -import org.wicketstuff.googlecharts.IShapeMarker; -import org.wicketstuff.googlecharts.ISolidFill; -import org.wicketstuff.googlecharts.Range; - -/** - * This is a fork of org.wicketstuff.googlecharts.Chart whose only purpose - * is to build https urls instead of http urls. - * - * @author Daniel Spiewak - * @author James Moger - */ -public class SecureChart extends WebComponent implements Serializable { - - private static final long serialVersionUID = 6286305912682861488L; - private IChartProvider provider; - private StringBuilder url; - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - - public SecureChart(String id, IChartProvider provider) { - super(id); - - this.provider = provider; - } - - public void invalidate() { - lock.writeLock().lock(); - try { - url = null; - } finally { - lock.writeLock().unlock(); - } - } - - public CharSequence constructURL() { - lock.writeLock().lock(); - try { - if (url != null) { - return url; - } - - url = new StringBuilder("https://chart.googleapis.com/chart?"); - - addParameter(url, "chs", render(provider.getSize())); - addParameter(url, "chd", render(provider.getData())); - addParameter(url, "cht", render(provider.getType())); - addParameter(url, "chbh", render(provider.getBarWidth(), provider.getBarGroupSpacing())); - addParameter(url, "chtt", render(provider.getTitle())); - addParameter(url, "chdl", render(provider.getLegend())); - addParameter(url, "chco", render(provider.getColors())); - - IChartFill bgFill = provider.getBackgroundFill(); - IChartFill fgFill = provider.getChartFill(); - - StringBuilder fillParam = new StringBuilder(); - - if (bgFill != null) { - fillParam.append("bg,").append(render(bgFill)); - } - - if (fgFill != null) { - if (fillParam.length() > 0) { - fillParam.append('|'); - } - - fillParam.append("c,").append(render(fgFill)); - } - - if (fillParam.toString().trim().equals("")) { - fillParam = null; - } - - addParameter(url, "chf", fillParam); - - IChartAxis[] axes = provider.getAxes(); - addParameter(url, "chxt", renderTypes(axes)); - addParameter(url, "chxl", renderLabels(axes)); - addParameter(url, "chxp", renderPositions(axes)); - addParameter(url, "chxr", renderRanges(axes)); - addParameter(url, "chxs", renderStyles(axes)); - - addParameter(url, "chg", render(provider.getGrid())); - addParameter(url, "chm", render(provider.getShapeMarkers())); - addParameter(url, "chm", render(provider.getRangeMarkers())); - addParameter(url, "chls", render(provider.getLineStyles())); - addParameter(url, "chm", render(provider.getFillAreas())); - addParameter(url, "chl", render(provider.getPieLabels())); - - return url; - } finally { - lock.writeLock().unlock(); - } - } - - private void addParameter(StringBuilder url, CharSequence param, CharSequence value) { - if (value == null || value.length() == 0) { - return; - } - - if (url.charAt(url.length() - 1) != '?') { - url.append('&'); - } - - url.append(param).append('=').append(value); - } - - private CharSequence convert(ChartDataEncoding encoding, double value, double max) { - switch (encoding) { - case TEXT: - return SecureChartDataEncoding.TEXT.convert(value, max); - case EXTENDED: - return SecureChartDataEncoding.EXTENDED.convert(value, max); - case SIMPLE: - default: - return SecureChartDataEncoding.SIMPLE.convert(value, max); - } - } - - private CharSequence render(Dimension dim) { - if (dim == null) { - return null; - } - - return new StringBuilder().append(dim.width).append('x').append(dim.height); - } - - private CharSequence render(IChartData data) { - if (data == null) { - return null; - } - - ChartDataEncoding encoding = data.getEncoding(); - - StringBuilder back = new StringBuilder(); - back.append(render(encoding)).append(':'); - - for (double[] set : data.getData()) { - if (set == null || set.length == 0) { - back.append(convert(encoding, -1, data.getMax())); - } else { - for (double value : set) { - back.append(convert(encoding, value, data.getMax())).append(encoding.getValueSeparator()); - } - - if (back.substring(back.length() - encoding.getValueSeparator().length(), - back.length()).equals(encoding.getValueSeparator())) { - back.setLength(back.length() - encoding.getValueSeparator().length()); - } - } - - back.append(encoding.getSetSeparator()); - } - - if (back.substring(back.length() - encoding.getSetSeparator().length(), - back.length()).equals(encoding.getSetSeparator())) { - back.setLength(back.length() - encoding.getSetSeparator().length()); - } - - return back; - } - - private CharSequence render(Enum value) { - if (value == null) { - return null; - } - - try { - Object back = value.getClass().getMethod("getRendering").invoke(value); - - if (back != null) { - return back.toString(); - } - } catch (IllegalArgumentException e) { - } catch (SecurityException e) { - } catch (IllegalAccessException e) { - } catch (InvocationTargetException e) { - } catch (NoSuchMethodException e) { - } - - return null; - } - - private CharSequence render(int barWidth, int groupSpacing) { - if (barWidth == -1) { - return null; - } - - StringBuilder back = new StringBuilder(barWidth); - - if (groupSpacing >= 0) { - back.append(',').append(groupSpacing); - } - - return back; - } - - private CharSequence render(String[] values) { - if (values == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (String value : values) { - CharSequence toRender = render(value); - if (toRender == null) { - toRender = ""; - } - - back.append(toRender).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(String value) { - if (value == null) { - return value; - } - - StringBuilder back = new StringBuilder(); - - for (char c : value.toCharArray()) { - if (c == ' ') { - back.append('+'); - } else { - back.append(c); - } - } - - return back; - } - - private CharSequence render(Color[] values) { - if (values == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (Color value : values) { - CharSequence toRender = render(value); - if (toRender == null) { - toRender = ""; - } - - back.append(toRender).append(','); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(Color value) { - if (value == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - { - String toPad = Integer.toHexString(value.getRed()); - - if (toPad.length() == 1) { - back.append(0); - } - back.append(toPad); - } - - { - String toPad = Integer.toHexString(value.getGreen()); - - if (toPad.length() == 1) { - back.append(0); - } - back.append(toPad); - } - - { - String toPad = Integer.toHexString(value.getBlue()); - - if (toPad.length() == 1) { - back.append(0); - } - back.append(toPad); - } - - { - String toPad = Integer.toHexString(value.getAlpha()); - - if (toPad.length() == 1) { - back.append(0); - } - back.append(toPad); - } - - return back; - } - - private CharSequence render(IChartFill fill) { - if (fill == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - if (fill instanceof ISolidFill) { - ISolidFill solidFill = (ISolidFill) fill; - - back.append("s,"); - back.append(render(solidFill.getColor())); - } else if (fill instanceof ILinearGradientFill) { - ILinearGradientFill gradientFill = (ILinearGradientFill) fill; - - back.append("lg,").append(gradientFill.getAngle()).append(','); - - Color[] colors = gradientFill.getColors(); - double[] offsets = gradientFill.getOffsets(); - for (int i = 0; i < colors.length; i++) { - back.append(render(colors[i])).append(',').append(offsets[i]).append(','); - } - - back.setLength(back.length() - 1); - } else if (fill instanceof ILinearStripesFill) { - ILinearStripesFill stripesFill = (ILinearStripesFill) fill; - - back.append("ls,").append(stripesFill.getAngle()).append(','); - - Color[] colors = stripesFill.getColors(); - double[] widths = stripesFill.getWidths(); - for (int i = 0; i < colors.length; i++) { - back.append(render(colors[i])).append(',').append(widths[i]).append(','); - } - - back.setLength(back.length() - 1); - } else { - return null; - } - - return back; - } - - private CharSequence renderTypes(IChartAxis[] axes) { - if (axes == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (IChartAxis axis : axes) { - back.append(render(axis.getType())).append(','); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence renderLabels(IChartAxis[] axes) { - if (axes == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (int i = 0; i < axes.length; i++) { - if (axes[i] == null || axes[i].getLabels() == null) { - continue; - } - - back.append(i).append(":|"); - - for (String label : axes[i].getLabels()) { - if (label == null) { - back.append('|'); - continue; - } - - back.append(render(label)).append('|'); - } - - if (i == axes.length - 1) { - back.setLength(back.length() - 1); - } - } - - return back; - } - - private CharSequence renderPositions(IChartAxis[] axes) { - if (axes == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (int i = 0; i < axes.length; i++) { - if (axes[i] == null || axes[i].getPositions() == null) { - continue; - } - - back.append(i).append(','); - - for (double position : axes[i].getPositions()) { - back.append(position).append(','); - } - - back.setLength(back.length() - 1); - - back.append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence renderRanges(IChartAxis[] axes) { - if (axes == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (int i = 0; i < axes.length; i++) { - if (axes[i] == null || axes[i].getRange() == null) { - continue; - } - - back.append(i).append(','); - - Range range = axes[i].getRange(); - back.append(range.getStart()).append(',').append(range.getEnd()).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence renderStyles(IChartAxis[] axes) { - if (axes == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (int i = 0; i < axes.length; i++) { - if (axes[i] == null || axes[i].getColor() == null - || axes[i].getFontSize() < 0 || axes[i].getAlignment() == null) { - continue; - } - - back.append(i).append(','); - back.append(render(axes[i].getColor())).append(','); - back.append(axes[i].getFontSize()).append(','); - back.append(render(axes[i].getAlignment())).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(IChartGrid grid) { - if (grid == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - back.append(grid.getXStepSize()).append(','); - back.append(grid.getYStepSize()); - - if (grid.getSegmentLength() >= 0) { - back.append(',').append(grid.getSegmentLength()); - back.append(',').append(grid.getBlankLength()); - } - - return back; - } - - private CharSequence render(IShapeMarker[] markers) { - if (markers == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (IShapeMarker marker : markers) { - back.append(render(marker.getType())).append(','); - back.append(render(marker.getColor())).append(','); - back.append(marker.getIndex()).append(','); - back.append(marker.getPoint()).append(','); - back.append(marker.getSize()).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(IRangeMarker[] markers) { - if (markers == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (IRangeMarker marker : markers) { - back.append(render(marker.getType())).append(','); - back.append(render(marker.getColor())).append(','); - back.append(0).append(','); - back.append(marker.getStart()).append(','); - back.append(marker.getEnd()).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(IFillArea[] areas) { - if (areas == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (IFillArea area : areas) { - back.append(render(area.getType())).append(','); - back.append(render(area.getColor())).append(','); - back.append(area.getStartIndex()).append(','); - back.append(area.getEndIndex()).append(','); - back.append(0).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - private CharSequence render(ILineStyle[] styles) { - if (styles == null) { - return null; - } - - StringBuilder back = new StringBuilder(); - - for (ILineStyle style : styles) { - if (style == null) { - back.append('|'); - continue; - } - - back.append(style.getThickness()).append(','); - back.append(style.getSegmentLength()).append(','); - back.append(style.getBlankLength()).append('|'); - } - - if (back.length() > 0) { - back.setLength(back.length() - 1); - } - - return back; - } - - @Override - protected void onComponentTag(ComponentTag tag) { - checkComponentTag(tag, "img"); - super.onComponentTag(tag); - - tag.put("src", constructURL()); - } -} diff --git a/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java b/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java deleted file mode 100644 index c5ac4608..00000000 --- a/src/main/java/com/gitblit/wicket/charting/SecureChartDataEncoding.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2007 Daniel Spiewak. - * Copyright 2013 gitblit.com. - * - * Licensed 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 com.gitblit.wicket.charting; - -/** - * This class is a pristine fork of org.wicketstuff.googlecharts.ChartDataEncoding - * to bring the package-protected convert methods to SecureChart. - * - * @author Daniel Spiewak - */ -public enum SecureChartDataEncoding { - - SIMPLE("s", "", ",") { - - @Override - CharSequence convert(double value, double max) { - if (value < 0) { - return "_"; - } - - value = Math.round((CHARS.length() - 1) * value / max); - - if (value > CHARS.length() - 1) { - throw new IllegalArgumentException(value + " is out of range for SIMPLE encoding"); - } - - return Character.toString(CHARS.charAt((int) value)); - } - }, - TEXT("t", ",", "|") { - - @Override - CharSequence convert(double value, double max) { - if (value < 0) { - value = -1; - } - - if (value > 100) { - throw new IllegalArgumentException(value + " is out of range for TEXT encoding"); - } - - return Double.toString(value); - } - }, - EXTENDED("e", "", ",") { - - @Override - CharSequence convert(double value, double max) { - if (value < 0) { - return "__"; - } - - value = Math.round(value); - - if (value > (EXT_CHARS.length() - 1) * (EXT_CHARS.length() - 1)) { - throw new IllegalArgumentException(value + " is out of range for EXTENDED encoding"); - } - - int rem = (int) (value % EXT_CHARS.length()); - int exp = (int) (value / EXT_CHARS.length()); - - return new StringBuilder().append(EXT_CHARS.charAt(exp)).append(EXT_CHARS.charAt(rem)); - } - }; - private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - private static final String EXT_CHARS = CHARS + "-_."; - private final String rendering, valueSeparator, setSeparator; - - private SecureChartDataEncoding(String rendering, String valueSeparator, String setSeparator) { - this.rendering = rendering; - this.valueSeparator = valueSeparator; - this.setSeparator = setSeparator; - } - - public String getRendering() { - return rendering; - } - - public String getValueSeparator() { - return valueSeparator; - } - - public String getSetSeparator() { - return setSeparator; - } - - abstract CharSequence convert(double value, double max); -} diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java index 070caf32..f0e390dc 100644 --- a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java +++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java @@ -41,10 +41,9 @@ import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.charting.GoogleChart; -import com.gitblit.wicket.charting.GoogleCharts; -import com.gitblit.wicket.charting.GoogleLineChart; -import com.gitblit.wicket.charting.GooglePieChart; +import com.gitblit.wicket.charting.Chart; +import com.gitblit.wicket.charting.Charts; +import com.gitblit.wicket.charting.Flotr2Charts; import com.gitblit.wicket.panels.ActivityPanel; /** @@ -118,7 +117,7 @@ public class ActivityPage extends RootPage { // create the activity charts if (app().settings().getBoolean(Keys.web.generateActivityGraph, true)) { - GoogleCharts charts = createCharts(recentActivity); + Charts charts = createCharts(recentActivity); add(new HeaderContributor(charts)); add(new Fragment("chartsPanel", "chartsFragment", this)); } else { @@ -166,7 +165,7 @@ public class ActivityPage extends RootPage { * @param recentActivity * @return */ - private GoogleCharts createCharts(List recentActivity) { + private Charts createCharts(List recentActivity) { // activity metrics Map repositoryMetrics = new HashMap(); Map authorMetrics = new HashMap(); @@ -193,34 +192,36 @@ public class ActivityPage extends RootPage { } } - // build google charts - GoogleCharts charts = new GoogleCharts(); + // build charts + Charts charts = new Flotr2Charts(); // sort in reverse-chronological order and then reverse that Collections.sort(recentActivity); Collections.reverse(recentActivity); // daily line chart - GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day", + Chart chart = charts.createLineChart("chartDaily", getString("gb.dailyActivity"), "day", getString("gb.commits")); SimpleDateFormat df = new SimpleDateFormat("MMM dd"); df.setTimeZone(getTimeZone()); for (Activity metric : recentActivity) { - chart.addValue(df.format(metric.startDate), metric.getCommitCount()); + chart.addValue(metric.startDate, metric.getCommitCount()); } charts.addChart(chart); - // active repositories pie chart - chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"), + // active repositories pie chart + chart = charts.createPieChart("chartRepositories", getString("gb.activeRepositories"), getString("gb.repository"), getString("gb.commits")); for (Metric metric : repositoryMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setShowLegend(false); + String url = urlFor(SummaryPage.class, null).toString() + "?r="; + chart.setClickUrl(url); charts.addChart(chart); // active authors pie chart - chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"), + chart = charts.createPieChart("chartAuthors", getString("gb.activeAuthors"), getString("gb.author"), getString("gb.commits")); for (Metric metric : authorMetrics.values()) { chart.addValue(metric.name, metric.count); diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java index 959a3d31..9853449e 100644 --- a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java +++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java @@ -48,9 +48,9 @@ import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.PageRegistration; import com.gitblit.wicket.PageRegistration.DropDownMenuItem; import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration; -import com.gitblit.wicket.charting.GoogleChart; -import com.gitblit.wicket.charting.GoogleCharts; -import com.gitblit.wicket.charting.GooglePieChart; +import com.gitblit.wicket.charting.Chart; +import com.gitblit.wicket.charting.Charts; +import com.gitblit.wicket.charting.Flotr2Charts; import com.gitblit.wicket.panels.DigestsPanel; import com.gitblit.wicket.panels.LinkPanel; @@ -218,19 +218,21 @@ public abstract class DashboardPage extends RootPage { if (app().settings().getBoolean(Keys.web.generateActivityGraph, true)) { // build google charts - GoogleCharts charts = new GoogleCharts(); + Charts charts = new Flotr2Charts(); // active repositories pie chart - GoogleChart chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"), + Chart chart = charts.createPieChart("chartRepositories", getString("gb.activeRepositories"), getString("gb.repository"), getString("gb.commits")); for (Metric metric : repositoryMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setShowLegend(false); + String url = urlFor(SummaryPage.class, null).toString() + "?r="; + chart.setClickUrl(url); charts.addChart(chart); // active authors pie chart - chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"), + chart = charts.createPieChart("chartAuthors", getString("gb.activeAuthors"), getString("gb.author"), getString("gb.commits")); for (Metric metric : authorMetrics.values()) { chart.addValue(metric.name, metric.count); diff --git a/src/main/java/com/gitblit/wicket/pages/MetricsPage.html b/src/main/java/com/gitblit/wicket/pages/MetricsPage.html index 4aefc798..302d020d 100644 --- a/src/main/java/com/gitblit/wicket/pages/MetricsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MetricsPage.html @@ -13,7 +13,7 @@ - @@ -22,19 +22,19 @@ -
+

-
+

-
+
-

-
+
+

+
diff --git a/src/main/java/com/gitblit/wicket/pages/MetricsPage.java b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java index d4cfc8e9..7ae4e4ed 100644 --- a/src/main/java/com/gitblit/wicket/pages/MetricsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java @@ -15,27 +15,20 @@ */ package com.gitblit.wicket.pages; -import java.awt.Color; -import java.awt.Dimension; import java.text.MessageFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.List; import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.eclipse.jgit.lib.Repository; -import org.wicketstuff.googlecharts.ChartAxis; -import org.wicketstuff.googlecharts.ChartAxisType; -import org.wicketstuff.googlecharts.ChartProvider; -import org.wicketstuff.googlecharts.ChartType; -import org.wicketstuff.googlecharts.IChartData; -import org.wicketstuff.googlecharts.LineStyle; -import org.wicketstuff.googlecharts.MarkerType; -import org.wicketstuff.googlecharts.ShapeMarker; import com.gitblit.models.Metric; import com.gitblit.utils.MetricUtils; @@ -43,7 +36,9 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.CacheControl; import com.gitblit.wicket.CacheControl.LastModified; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.charting.SecureChart; +import com.gitblit.wicket.charting.Chart; +import com.gitblit.wicket.charting.Charts; +import com.gitblit.wicket.charting.Flotr2Charts; @CacheControl(LastModified.REPOSITORY) public class MetricsPage extends RepositoryPage { @@ -66,73 +61,71 @@ public class MetricsPage extends RepositoryPage { MessageFormat.format(getString("gb.branchStats"), metricsTotal.count, metricsTotal.tag, getTimeUtils().duration(metricsTotal.duration)))); } - insertLinePlot("commitsChart", metrics); - insertBarPlot("dayOfWeekChart", getDayOfWeekMetrics(r, objectId)); - insertPieChart("authorsChart", getAuthorMetrics(r, objectId)); + + Charts charts = new Flotr2Charts(); + + add(WicketUtils.newBlankImage("commitsChart")); + add(WicketUtils.newBlankImage("dayOfWeekChart")); + add(WicketUtils.newBlankImage("authorsChart")); + + createLineChart(charts, "commitsChart", metrics); + createBarChart(charts, "dayOfWeekChart", getDayOfWeekMetrics(r, objectId)); + createPieChart(charts, "authorsChart", getAuthorMetrics(r, objectId)); + + add(new HeaderContributor(charts)); + } - private void insertLinePlot(String wicketId, List metrics) { + private void createLineChart(Charts charts, String id, List metrics) { if ((metrics != null) && (metrics.size() > 0)) { - IChartData data = WicketUtils.getChartData(metrics); - - ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE, - data); - ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM); - dateAxis.setLabels(new String[] { metrics.get(0).name, - metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name }); - provider.addAxis(dateAxis); - - ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT); - commitAxis.setLabels(new String[] { "", - String.valueOf((int) WicketUtils.maxValue(metrics)) }); - provider.addAxis(commitAxis); - - provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) }); - provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.decode("#002060"), 1, -1, 5)); - - add(new SecureChart(wicketId, provider)); - } else { - add(WicketUtils.newBlankImage(wicketId)); + + Chart chart = charts.createLineChart(id, "", "day", + getString("gb.commits")); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + String displayFormat = "MMM dd"; + if(metrics.size() > 0 && metrics.get(0).name.length() == 7){ + df = new SimpleDateFormat("yyyy-MM"); + displayFormat = "yyyy MMM"; + } + df.setTimeZone(getTimeZone()); + chart.setDateFormat(displayFormat); + for (Metric metric : metrics) { + Date date; + try { + date = df.parse(metric.name); + } catch (ParseException e) { + logger.error("Unable to parse date: " + metric.name); + return; + } + chart.addValue(date, (int)metric.count); + if(metric.tag > 0 ){ + chart.addHighlight(date, (int)metric.count); + } + } + charts.addChart(chart); } } - - private void insertBarPlot(String wicketId, List metrics) { + + private void createPieChart(Charts charts, String id, List metrics) { if ((metrics != null) && (metrics.size() > 0)) { - IChartData data = WicketUtils.getChartData(metrics); - - ChartProvider provider = new ChartProvider(new Dimension(400, 100), - ChartType.BAR_VERTICAL_SET, data); - ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM); - List labels = new ArrayList(); + + Chart chart = charts.createPieChart(id, "", "day", + getString("gb.commits")); for (Metric metric : metrics) { - labels.add(metric.name); + chart.addValue(metric.name, (int)metric.count); } - dateAxis.setLabels(labels.toArray(new String[labels.size()])); - provider.addAxis(dateAxis); - - ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT); - commitAxis.setLabels(new String[] { "", - String.valueOf((int) WicketUtils.maxValue(metrics)) }); - provider.addAxis(commitAxis); - - add(new SecureChart(wicketId, provider)); - } else { - add(WicketUtils.newBlankImage(wicketId)); + charts.addChart(chart); } } - - private void insertPieChart(String wicketId, List metrics) { + + private void createBarChart(Charts charts, String id, List metrics) { if ((metrics != null) && (metrics.size() > 0)) { - IChartData data = WicketUtils.getChartData(metrics); - List labels = new ArrayList(); + Chart chart = charts.createBarChart(id, "", "day", + getString("gb.commits")); for (Metric metric : metrics) { - labels.add(metric.name); + chart.addValue(metric.name, (int)metric.count); } - ChartProvider provider = new ChartProvider(new Dimension(800, 200), ChartType.PIE, data); - provider.setPieLabels(labels.toArray(new String[labels.size()])); - add(new SecureChart(wicketId, provider)); - } else { - add(WicketUtils.newBlankImage(wicketId)); + charts.addChart(chart); } } diff --git a/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html index b55688cc..ed3754e0 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyDashboardPage.html @@ -68,8 +68,8 @@ - - + +
diff --git a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java index efb7f4cf..1979f97f 100644 --- a/src/main/java/com/gitblit/wicket/pages/OverviewPage.java +++ b/src/main/java/com/gitblit/wicket/pages/OverviewPage.java @@ -37,9 +37,9 @@ import com.gitblit.wicket.CacheControl; import com.gitblit.wicket.CacheControl.LastModified; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.charting.GoogleChart; -import com.gitblit.wicket.charting.GoogleCharts; -import com.gitblit.wicket.charting.GoogleLineChart; +import com.gitblit.wicket.charting.Chart; +import com.gitblit.wicket.charting.Charts; +import com.gitblit.wicket.charting.Flotr2Charts; import com.gitblit.wicket.panels.BranchesPanel; import com.gitblit.wicket.panels.LinkPanel; import com.gitblit.wicket.panels.ReflogPanel; @@ -135,8 +135,10 @@ public class OverviewPage extends RepositoryPage { if ((metrics != null) && (metrics.size() > 0) && app().settings().getBoolean(Keys.web.generateActivityGraph, true)) { + Charts charts = new Flotr2Charts(); + // daily line chart - GoogleChart chart = new GoogleLineChart("chartDaily", "", "unit", + Chart chart = charts.createLineChart("chartDaily", "", "unit", getString("gb.commits")); for (Metric metric : metrics) { chart.addValue(metric.name, metric.count); @@ -144,7 +146,6 @@ public class OverviewPage extends RepositoryPage { chart.setWidth(375); chart.setHeight(150); - GoogleCharts charts = new GoogleCharts(); charts.addChart(chart); add(new HeaderContributor(charts)); } diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html index 42c59c48..2d1b6a56 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html @@ -9,7 +9,7 @@
- +
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java index fdc5d01d..eb6eb07a 100644 --- a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java @@ -15,14 +15,17 @@ */ package com.gitblit.wicket.pages; -import java.awt.Color; -import java.awt.Dimension; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + import org.apache.wicket.Component; import org.apache.wicket.PageParameters; +import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.panel.Fragment; @@ -31,14 +34,6 @@ import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; -import org.wicketstuff.googlecharts.ChartAxis; -import org.wicketstuff.googlecharts.ChartAxisType; -import org.wicketstuff.googlecharts.ChartProvider; -import org.wicketstuff.googlecharts.ChartType; -import org.wicketstuff.googlecharts.IChartData; -import org.wicketstuff.googlecharts.LineStyle; -import org.wicketstuff.googlecharts.MarkerType; -import org.wicketstuff.googlecharts.ShapeMarker; import com.gitblit.Keys; import com.gitblit.models.Metric; @@ -53,7 +48,9 @@ import com.gitblit.wicket.MarkupProcessor; import com.gitblit.wicket.MarkupProcessor.MarkupDocument; import com.gitblit.wicket.MarkupProcessor.MarkupSyntax; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.charting.SecureChart; +import com.gitblit.wicket.charting.Chart; +import com.gitblit.wicket.charting.Charts; +import com.gitblit.wicket.charting.Flotr2Charts; import com.gitblit.wicket.panels.BranchesPanel; import com.gitblit.wicket.panels.LinkPanel; import com.gitblit.wicket.panels.LogPanel; @@ -159,38 +156,49 @@ public class SummaryPage extends RepositoryPage { // global, no readme on summary page add(new Label("readme").setVisible(false)); } - - // Display an activity line graph - insertActivityGraph(metrics); + + Charts charts = createCharts(metrics); + add(new HeaderContributor(charts)); + } @Override protected String getPageName() { return getString("gb.summary"); } - - private void insertActivityGraph(List metrics) { - if ((metrics != null) && (metrics.size() > 0) - && app().settings().getBoolean(Keys.web.generateActivityGraph, true)) { - IChartData data = WicketUtils.getChartData(metrics); - - ChartProvider provider = new ChartProvider(new Dimension(290, 100), ChartType.LINE, - data); - ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM); - dateAxis.setLabels(new String[] { metrics.get(0).name, - metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name }); - provider.addAxis(dateAxis); - - ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT); - commitAxis.setLabels(new String[] { "", - String.valueOf((int) WicketUtils.maxValue(metrics)) }); - provider.addAxis(commitAxis); - provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) }); - provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.decode("#002060"), 1, -1, 5)); - - add(new SecureChart("commitsChart", provider)); - } else { - add(WicketUtils.newBlankImage("commitsChart")); + + private Charts createCharts(List metrics) { + + Charts charts = new Flotr2Charts(); + + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); + String displayFormat = "MMM dd"; + if(metrics.size() > 0 && metrics.get(0).name.length() == 7){ + df = new SimpleDateFormat("yyyy-MM"); + displayFormat = "yyyy MMM"; } + df.setTimeZone(getTimeZone()); + + // build google charts + Chart chart = charts.createLineChart("commitsChart", getString("gb.activity"), "day", getString("gb.commits")); + chart.setDateFormat(displayFormat); + + for (Metric metric : metrics) { + Date date; + try { + date = df.parse(metric.name); + } catch (ParseException e) { + logger.error("Unable to parse date: " + metric.name); + return charts; + } + chart.addValue(date, (int)metric.count); + if(metric.tag > 0 ){ + chart.addHighlight(date, (int)metric.count); + } + } + charts.addChart(chart); + + return charts; } + } diff --git a/src/main/resources/flotr2/flotr2.custom.css b/src/main/resources/flotr2/flotr2.custom.css new file mode 100644 index 00000000..d3f92707 --- /dev/null +++ b/src/main/resources/flotr2/flotr2.custom.css @@ -0,0 +1,21 @@ +.flotr-mouse-value { + opacity: 1 !important; + background-color: #FFFFFF !important; + color: #666 !important; + font-size: 10px; + border: 1px solid #ddd; +} + +.flotr-legend-label{ + opacity: 1 !important; + background-color: #FFFFFF !important; + color: #666 !important; + font-size: 10px; + padding: 2px; + border-style: none !important; +} + +.flotr-title { + text-align: left !important; + font-size: 10px !important; +} \ No newline at end of file diff --git a/src/main/resources/flotr2/flotr2.min.js b/src/main/resources/flotr2/flotr2.min.js new file mode 100644 index 00000000..c348a695 --- /dev/null +++ b/src/main/resources/flotr2/flotr2.min.js @@ -0,0 +1,10 @@ +/*! + * bean.js - copyright Jacob Thornton 2011 + * https://github.com/fat/bean + * MIT License + * special thanks to: + * dean edwards: http://dean.edwards.name/ + * dperini: https://github.com/dperini/nwevents + * the entire mootools team: github.com/mootools/mootools-core + */ +!function(a,c,b){if(typeof module!=="undefined"){module.exports=b(a,c)}else{if(typeof define==="function"&&typeof define.amd==="object"){define(b)}else{c[a]=b(a,c)}}}("bean",this,function(p,R){var J=window,L=R[p],I=/over|out/,z=/[^\.]*(?=\..*)\.|.*/,H=/\..*/,o="addEventListener",h="attachEvent",a="removeEventListener",r="detachEvent",k=document||{},A=k.documentElement||{},u=A[o],B=u?o:h,s=Array.prototype.slice,c=/click|mouse|menu|drag|drop/i,K=/^touch|^gesture/i,F={one:1},P=(function(U,T,S){for(S=0;S0){Z=Z.split(" ");for(X=Z.length;X--;){C(W,Z[X],ab)}return W}aa=S&&Z.replace(H,"");if(aa&&E[aa]){aa=E[aa].type}if(!Z||S){if(T=S&&Z.replace(z,"")){T=T.split(".")}Y(W,aa,ab,T)}else{if(typeof Z==="function"){Y(W,null,Z)}else{for(V in Z){if(Z.hasOwnProperty(V)){C(W,V,Z[V])}}}}return W},g=function(U,ac,aa,S,T){var Y,W,V,X,Z=aa,ab=aa&&typeof aa==="string";if(ac&&!aa&&typeof ac==="object"){for(Y in ac){if(ac.hasOwnProperty(Y)){g.apply(this,[U,Y,ac[Y]])}}}else{X=arguments.length>3?s.call(arguments,3):[];W=(ab?aa:ac).split(" ");ab&&(aa=q(ac,(Z=S),T))&&(X=s.call(X,1));this===F&&(aa=w(C,U,ac,aa,Z));for(V=W.length;V--;){j(U,W[V],aa,Z,X)}}return U},l=function(){return g.apply(F,arguments)},N=u?function(T,V,U){var S=k.createEvent(T?"HTMLEvents":"UIEvents");S[T?"initEvent":"initUIEvent"](V,true,true,J,1);U.dispatchEvent(S)}:function(S,U,T){T=d(T,S);S?T.fireEvent("on"+U,k.createEventObject()):T["_on"+U]++},v=function(V,aa,Y){var W,U,T,Z,S,X=aa.split(" ");for(W=X.length;W--;){aa=X[W].replace(H,"");if(Z=X[W].replace(z,"")){Z=Z.split(".")}if(!Z&&!Y&&V[B]){N(P[aa],aa,V)}else{S=O.get(V,aa);Y=[false].concat(Y);for(U=0,T=S.length;U=I.computed&&(I={value:P,computed:N})});return I.value};G.min=function(L,K,J){if(!K&&G.isArray(L)){return Math.min.apply(Math,L)}var I={computed:Infinity};d(L,function(P,M,O){var N=K?K.call(J,P,M,O):P;NL?1:0}),"value")};G.groupBy=function(K,J){var I={};d(K,function(N,L){var M=J(N,L);(I[M]||(I[M]=[])).push(N)});return I};G.sortedIndex=function(N,M,K){K||(K=G.identity);var I=0,L=N.length;while(I>1;K(N[J])=0})})};G.difference=function(J,I){return G.filter(J,function(K){return !G.include(I,K)})};G.zip=function(){var I=u.call(arguments);var L=G.max(G.pluck(I,"length"));var K=new Array(L);for(var J=0;J=0;K--){J=[I[K].apply(this,J)]}return J[0]}};G.after=function(J,I){return function(){if(--J<1){return I.apply(this,arguments)}}};G.keys=E||function(K){if(K!==Object(K)){throw new TypeError("Invalid object")}var J=[];for(var I in K){if(q.call(K,I)){J[J.length]=I}}return J};G.values=function(I){return G.map(I,G.identity)};G.functions=G.methods=function(K){var J=[];for(var I in K){if(G.isFunction(K[I])){J.push(I)}}return J.sort()};G.extend=function(I){d(u.call(arguments,1),function(J){for(var K in J){if(J[K]!==void 0){I[K]=J[K]}}});return I};G.defaults=function(I){d(u.call(arguments,1),function(J){for(var K in J){if(I[K]==null){I[K]=J[K]}}});return I};G.clone=function(I){return G.isArray(I)?I.slice():G.extend({},I)};G.tap=function(J,I){I(J);return J};G.isEqual=function(J,I){if(J===I){return true}var M=typeof(J),O=typeof(I);if(M!=O){return false}if(J==I){return true}if((!J&&I)||(J&&!I)){return false}if(J._chain){J=J._wrapped}if(I._chain){I=I._wrapped}if(J.isEqual){return J.isEqual(I)}if(I.isEqual){return I.isEqual(J)}if(G.isDate(J)&&G.isDate(I)){return J.getTime()===I.getTime()}if(G.isNaN(J)&&G.isNaN(I)){return false}if(G.isRegExp(J)&&G.isRegExp(I)){return J.source===I.source&&J.global===I.global&&J.ignoreCase===I.ignoreCase&&J.multiline===I.multiline}if(M!=="object"){return false}if(J.length&&(J.length!==I.length)){return false}var K=G.keys(J),N=G.keys(I);if(K.length!=N.length){return false}for(var L in J){if(!(L in I)||!G.isEqual(J[L],I[L])){return false}}return true};G.isEmpty=function(J){if(G.isArray(J)||G.isString(J)){return J.length===0}for(var I in J){if(q.call(J,I)){return false}}return true};G.isElement=function(I){return !!(I&&I.nodeType==1)};G.isArray=c||function(I){return z.call(I)==="[object Array]"};G.isObject=function(I){return I===Object(I)};G.isArguments=function(I){return !!(I&&q.call(I,"callee"))};G.isFunction=function(I){return !!(I&&I.constructor&&I.call&&I.apply)};G.isString=function(I){return !!(I===""||(I&&I.charCodeAt&&I.substr))};G.isNumber=function(I){return !!(I===0||(I&&I.toExponential&&I.toFixed))};G.isNaN=function(I){return I!==I};G.isBoolean=function(I){return I===true||I===false};G.isDate=function(I){return !!(I&&I.getTimezoneOffset&&I.setUTCFullYear)};G.isRegExp=function(I){return !!(I&&I.test&&I.exec&&(I.ignoreCase||I.ignoreCase===false))};G.isNull=function(I){return I===null};G.isUndefined=function(I){return I===void 0};G.noConflict=function(){w._=t;return this};G.identity=function(I){return I};G.times=function(L,K,J){for(var I=0;I/g,interpolate:/<%=([\s\S]+?)%>/g};G.template=function(L,K){var M=G.templateSettings;var I="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+L.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(M.interpolate,function(N,O){return"',"+O.replace(/\\'/g,"'")+",'"}).replace(M.evaluate||null,function(N,O){return"');"+O.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";var J=new Function("obj",I);return K?J(K):J};var g=function(I){this._wrapped=I};G.prototype=g.prototype;var p=function(J,I){return I?G(J).chain():J};var s=function(I,J){g.prototype[I]=function(){var K=u.call(arguments);A.call(K,this._wrapped);return p(J.apply(G,K),this._chain)}};G.mixin(G);d(["pop","push","reverse","shift","sort","splice","unshift"],function(I){var J=j[I];g.prototype[I]=function(){J.apply(this._wrapped,arguments);return p(this._wrapped,this._chain)}});d(["concat","join","slice"],function(I){var J=j[I];g.prototype[I]=function(){return p(J.apply(this._wrapped,arguments),this._chain)}});g.prototype.chain=function(){this._chain=true;return this};g.prototype.value=function(){return this._wrapped}})();(function(){var b=this,c=this.Flotr,a;a={_:_,bean:bean,isIphone:/iphone/i.test(navigator.userAgent),isIE:(navigator.appVersion.indexOf("MSIE")!=-1?parseFloat(navigator.appVersion.split("MSIE")[1]):false),graphTypes:{},plugins:{},addType:function(d,e){a.graphTypes[d]=e;a.defaultOptions[d]=e.options||{};a.defaultOptions.defaultType=a.defaultOptions.defaultType||d},addPlugin:function(d,e){a.plugins[d]=e;a.defaultOptions[d]=e.options||{}},draw:function(e,f,d,g){g=g||a.Graph;return new g(e,f,d)},merge:function(h,f){var g,e,d=f||{};for(g in h){e=h[g];if(e&&typeof(e)==="object"){if(e.constructor===Array){d[g]=this._.clone(e)}else{if(e.constructor!==RegExp&&!this._.isElement(e)){d[g]=a.merge(e,(f?f[g]:undefined))}else{d[g]=e}}}else{d[g]=e}}return d},clone:function(d){return a.merge(d,{})},getTickSize:function(h,g,d,e){var l=(d-g)/h,k=a.getMagnitude(l),j=10,f=l/k;if(f<1.5){j=1}else{if(f<2.25){j=2}else{if(f<3){j=((e===0)?2:2.5)}else{if(f<7.5){j=5}}}}return j*k},defaultTickFormatter:function(e,d){return e+""},defaultTrackFormatter:function(d){return"("+d.x+", "+d.y+")"},engineeringNotation:function(h,d,g){var f=["Y","Z","E","P","T","G","M","k",""],j=["y","z","a","f","p","n","µ","m",""],e=f.length;g=g||1000;d=Math.pow(10,d||2);if(h===0){return 0}if(h>1){while(e--&&(h>=g)){h/=g}}else{f=j;e=f.length;while(e--&&(h<1)){h*=g}}return(Math.round(h*d)/d)+f[e]},getMagnitude:function(d){return Math.pow(10,Math.floor(Math.log(d)/Math.LN10))},toPixel:function(d){return Math.floor(d)+0.5},toRad:function(d){return -d*(Math.PI/180)},floorInBase:function(e,d){return d*Math.floor(e/d)},drawText:function(e,g,d,h,f){if(!e.fillText){e.drawText(g,d,h,f);return}f=this._.extend({size:a.defaultOptions.fontSize,color:"#000000",textAlign:"left",textBaseline:"bottom",weight:1,angle:0},f);e.save();e.translate(d,h);e.rotate(f.angle);e.fillStyle=f.color;e.font=(f.weight>1?"bold ":"")+(f.size*1.3)+"px sans-serif";e.textAlign=f.textAlign;e.textBaseline=f.textBaseline;e.fillText(g,0,0);e.restore()},getBestTextAlign:function(e,d){d=d||{textAlign:"center",textBaseline:"middle"};e+=a.getTextAngleFromAlign(d);if(Math.abs(Math.cos(e))>0.01){d.textAlign=(Math.cos(e)>0?"right":"left")}if(Math.abs(Math.sin(e))>0.01){d.textBaseline=(Math.sin(e)>0?"top":"bottom")}return d},alignTable:{"right middle":0,"right top":Math.PI/4,"center top":Math.PI/2,"left top":3*(Math.PI/4),"left middle":Math.PI,"left bottom":-3*(Math.PI/4),"center bottom":-Math.PI/2,"right bottom":-Math.PI/4,"center middle":0},getTextAngleFromAlign:function(d){return a.alignTable[d.textAlign+" "+d.textBaseline]||0},noConflict:function(){b.Flotr=c;return this}};b.Flotr=a})();Flotr.defaultOptions={colors:["#00A8F0","#C0D800","#CB4B4B","#4DA74D","#9440ED"],ieBackgroundColor:"#FFFFFF",title:null,subtitle:null,shadowSize:4,defaultType:null,HtmlText:true,fontColor:"#545454",fontSize:7.5,resolution:1,parseFloat:true,xaxis:{ticks:null,minorTicks:null,showLabels:true,showMinorLabels:false,labelsAngle:0,title:null,titleAngle:0,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscale:false,autoscaleMargin:0,color:null,mode:"normal",timeFormat:null,timeMode:"UTC",timeUnit:"millisecond",scaling:"linear",base:Math.E,titleAlign:"center",margin:true},x2axis:{},yaxis:{ticks:null,minorTicks:null,showLabels:true,showMinorLabels:false,labelsAngle:0,title:null,titleAngle:90,noTicks:5,minorTickFreq:null,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscale:false,autoscaleMargin:0,color:null,scaling:"linear",base:Math.E,titleAlign:"center",margin:true},y2axis:{titleAngle:270},grid:{color:"#545454",backgroundColor:null,backgroundImage:null,watermarkAlpha:0.4,tickColor:"#DDDDDD",labelMargin:3,verticalLines:true,minorVerticalLines:null,horizontalLines:true,minorHorizontalLines:null,outlineWidth:1,outline:"nsew",circular:false},mouse:{track:false,trackAll:false,position:"se",relative:false,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:"#FF3F19",trackDecimals:1,sensibility:2,trackY:true,radius:3,fillColor:null,fillOpacity:0.4}};(function(){var b=Flotr._;function c(j,h,e,f){this.rgba=["r","g","b","a"];var d=4;while(-1<--d){this[this.rgba[d]]=arguments[d]||((d==3)?1:0)}this.normalize()}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};c.prototype={scale:function(g,f,h,e){var d=4;while(-1<--d){if(!b.isUndefined(arguments[d])){this[this.rgba[d]]*=arguments[d]}}return this.normalize()},alpha:function(d){if(!b.isUndefined(d)&&!b.isNull(d)){this.a=d}return this.normalize()},clone:function(){return new c(this.r,this.b,this.g,this.a)},limit:function(e,d,f){return Math.max(Math.min(e,f),d)},normalize:function(){var d=this.limit;this.r=d(parseInt(this.r,10),0,255);this.g=d(parseInt(this.g,10),0,255);this.b=d(parseInt(this.b,10),0,255);this.a=d(this.a,0,1);return this},distance:function(e){if(!e){return}e=new c.parse(e);var f=0,d=3;while(-1<--d){f+=Math.abs(this[this.rgba[d]]-e[this.rgba[d]])}return f},toString:function(){return(this.a>=1)?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"},contrast:function(){var d=1-(0.299*this.r+0.587*this.g+0.114*this.b)/255;return(d<0.5?"#000000":"#ffffff")}};b.extend(c,{parse:function(e){if(e instanceof c){return e}var d;if((d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(e))){return new c(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if((d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(e))){return new c(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if((d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(e))){return new c(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}if((d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(e))){return new c(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if((d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(e))){return new c(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if((d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(e))){return new c(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}var f=(e+"").replace(/^\s*([\S\s]*?)\s*$/,"$1").toLowerCase();if(f=="transparent"){return new c(255,255,255,0)}return(d=a[f])?new c(d[0],d[1],d[2]):new c(0,0,0,0)},processColor:function(d,f){var e=f.opacity;if(!d){return"rgba(0, 0, 0, 0)"}if(d instanceof c){return d.alpha(e).toString()}if(b.isString(d)){return c.parse(d).alpha(e).toString()}var l=d.colors?d:{colors:d};if(!f.ctx){if(!b.isArray(l.colors)){return"rgba(0, 0, 0, 0)"}return c.parse(b.isArray(l.colors[0])?l.colors[0][1]:l.colors[0]).alpha(e).toString()}l=b.extend({start:"top",end:"bottom"},l);if(/top/i.test(l.start)){f.x1=0}if(/left/i.test(l.start)){f.y1=0}if(/bottom/i.test(l.end)){f.x2=0}if(/right/i.test(l.end)){f.y2=0}var h,k,g,j=f.ctx.createLinearGradient(f.x1,f.y1,f.x2,f.y2);for(h=0;h=q){break}}q=h[u][0];o=h[u][1];if(o=="year"){q=Flotr.getTickSize(e.noTicks*j.year,r,t,0);if(q==0.5){o="month";q=6}}b.tickUnit=o;b.tickSize=q;var z=new Date(r);var g=q*j[o];function a(d){l(z,d,m,Flotr.floorInBase(A(z,d,m),q))}switch(o){case"millisecond":a("Milliseconds");break;case"second":a("Seconds");break;case"minute":a("Minutes");break;case"hour":a("Hours");break;case"month":a("Month");break;case"year":a("FullYear");break}if(g>=j.second){l(z,"Milliseconds",m,0)}if(g>=j.minute){l(z,"Seconds",m,0)}if(g>=j.hour){l(z,"Minutes",m,0)}if(g>=j.day){l(z,"Hours",m,0)}if(g>=j.day*4){l(z,"Date",m,1)}if(g>=j.year){l(z,"Month",m,0)}var w=0,k=NaN,p;do{p=k;k=z.getTime();C.push({v:k/D,label:s(k/D,b)});if(o=="month"){if(q<1){l(z,"Date",m,1);var f=z.getTime();l(z,"Month",m,A(z,"Month",m)+1);var c=z.getTime();z.setTime(k+w*j.hour+(c-f)*q);w=A(z,"Hours",m);l(z,"Hours",m,0)}else{l(z,"Month",m,A(z,"Month",m)+q)}}else{if(o=="year"){l(z,"FullYear",m,A(z,"FullYear",m)+q)}else{z.setTime(k+g)}}}while(k0){return{x:f.touches[0].pageX,y:f.touches[0].pageY}}else{if(!b._.isUndefined(f.changedTouches)&&f.changedTouches.length>0){return{x:f.changedTouches[0].pageX,y:f.changedTouches[0].pageY}}else{if(f.pageX||f.pageY){return{x:f.pageX,y:f.pageY}}else{if(f.clientX||f.clientY){var g=document,c=g.body,h=g.documentElement;return{x:f.clientX+c.scrollLeft+h.scrollLeft,y:f.clientY+c.scrollTop+h.scrollTop}}}}}}}})();(function(){var c=Flotr,d=c.DOM,a=c._,b=function(e){this.o=e};b.prototype={dimensions:function(h,f,e,g){if(!h){return{width:0,height:0}}return(this.o.html)?this.html(h,this.o.element,e,g):this.canvas(h,f)},canvas:function(o,f){if(!this.o.textEnabled){return}f=f||{};var k=this.measureText(o,f),g=k.width,p=f.size||c.defaultOptions.fontSize,j=f.angle||0,l=Math.cos(j),h=Math.sin(j),q=2,m=6,e;e={width:Math.abs(l*g)+Math.abs(h*p)+q,height:Math.abs(h*g)+Math.abs(l*p)+m};return e},html:function(h,e,g,f){var j=d.create("div");d.setStyles(j,{position:"absolute",top:"-10000px"});d.insert(j,'
'+h+"
");d.insert(this.o.element,j);return d.size(j)},measureText:function(h,g){var e=this.o.ctx,f;if(!e.fillText||(c.isIphone&&e.measure)){return{width:e.measure(h,g)}}g=a.extend({size:c.defaultOptions.fontSize,weight:1,angle:0},g);e.save();e.font=(g.weight>1?"bold ":"")+(g.size*1.3)+"px sans-serif";f=e.measureText(h);e.restore();return f}};Flotr.Text=b})();(function(){var e=Flotr.DOM,c=Flotr.EventAdapter,a=Flotr._,b=Flotr;Graph=function(g,h,f){this._setEl(g);this._initMembers();this._initPlugins();c.fire(this.el,"flotr:beforeinit",[this]);this.data=h;this.series=b.Series.getSeries(h);this._initOptions(f);this._initGraphTypes();this._initCanvas();this._text=new b.Text({element:this.el,ctx:this.ctx,html:this.options.HtmlText,textEnabled:this.textEnabled});c.fire(this.el,"flotr:afterconstruct",[this]);this._initEvents();this.findDataRanges();this.calculateSpacing();this.draw(a.bind(function(){c.fire(this.el,"flotr:afterinit",[this])},this))};function d(g,f,h){c.observe.apply(this,arguments);this._handles.push(arguments);return this}Graph.prototype={destroy:function(){c.fire(this.el,"flotr:destroy");a.each(this._handles,function(f){c.stopObserving.apply(this,f)});this._handles=[];this.el.graph=null},observe:d,_observe:d,processColor:function(f,g){var h={x1:0,y1:0,x2:this.plotWidth,y2:this.plotHeight,opacity:1,ctx:this.ctx};a.extend(h,g);return b.Color.processColor(f,h)},findDataRanges:function(){var f=this.axes,l,j,g;a.each(this.series,function(m){g=m.getRange();if(g){l=m.xaxis;j=m.yaxis;l.datamin=Math.min(g.xmin,l.datamin);l.datamax=Math.max(g.xmax,l.datamax);j.datamin=Math.min(g.ymin,j.datamin);j.datamax=Math.max(g.ymax,j.datamax);l.used=(l.used||g.xused);j.used=(j.used||g.yused)}},this);if(!f.x.used&&!f.x2.used){f.x.used=true}if(!f.y.used&&!f.y2.used){f.y.used=true}a.each(f,function(m){m.calculateRange()});var h=a.keys(b.graphTypes),k=false;a.each(this.series,function(m){if(m.hide){return}a.each(h,function(o){if(m[o]&&m[o].show){this.extendRange(o,m);k=true}},this);if(!k){this.extendRange(this.options.defaultType,m)}},this)},extendRange:function(g,f){if(this[g].extendRange){this[g].extendRange(f,f.data,f[g],this[g])}if(this[g].extendYRange){this[g].extendYRange(f.yaxis,f.data,f[g],this[g])}if(this[g].extendXRange){this[g].extendXRange(f.xaxis,f.data,f[g],this[g])}},calculateSpacing:function(){var w=this.axes,A=this.options,s=this.series,k=A.grid.labelMargin,m=this._text,z=w.x,f=w.x2,v=w.y,u=w.y2,q=A.grid.outlineWidth,r,o,h,t;a.each(w,function(j){j.calculateTicks();j.calculateTextDimensions(m,A)});t=m.dimensions(A.title,{size:A.fontSize*1.5},"font-size:1em;font-weight:bold;","flotr-title");this.titleHeight=t.height;t=m.dimensions(A.subtitle,{size:A.fontSize},"font-size:smaller;","flotr-subtitle");this.subtitleHeight=t.height;for(o=0;o1){this.multitouches=k.touches}c.fire(g,"flotr:mousedown",[event,this]);this.observe(document,"touchend",j)},this));this.observe(this.overlay,"touchmove",a.bind(function(k){var l=this.getEventPosition(k);k.preventDefault();f=true;if(this.multitouches||(k.touches&&k.touches.length>1)){this.multitouches=k.touches}else{if(!h){c.fire(g,"flotr:mousemove",[event,l,this])}}this.lastMousePos=l},this))}else{this.observe(this.overlay,"mousedown",a.bind(this.mouseDownHandler,this)).observe(g,"mousemove",a.bind(this.mouseMoveHandler,this)).observe(this.overlay,"click",a.bind(this.clickHandler,this)).observe(g,"mouseout",function(){c.fire(g,"flotr:mouseout")})}},_initCanvas:function(){var j=this.el,h=this.options,k=j.children,q=[],g,l,r,f;for(l=k.length;l--;){g=k[l];if(!this.canvas&&g.className==="flotr-canvas"){this.canvas=g}else{if(!this.overlay&&g.className==="flotr-overlay"){this.overlay=g}else{q.push(g)}}}for(l=q.length;l--;){j.removeChild(q[l])}e.setStyles(j,{position:"relative"});r={};r.width=j.clientWidth;r.height=j.clientHeight;if(r.width<=0||r.height<=0||h.resolution<=0){throw"Invalid dimensions for plot, width = "+r.width+", height = "+r.height+", resolution = "+h.resolution}this.canvas=m(this.canvas,"canvas");this.overlay=m(this.overlay,"overlay");this.ctx=p(this.canvas);this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);this.octx=p(this.overlay);this.octx.clearRect(0,0,this.overlay.width,this.overlay.height);this.canvasHeight=r.height;this.canvasWidth=r.width;this.textEnabled=!!this.ctx.drawText||!!this.ctx.fillText;function m(s,o){if(!s){s=e.create("canvas");if(typeof FlashCanvas!="undefined"&&typeof s.getContext==="function"){FlashCanvas.initElement(s)}s.className="flotr-"+o;s.style.cssText="position:absolute;left:0px;top:0px;";e.insert(j,s)}a.each(r,function(t,u){e.show(s);if(o=="canvas"&&s.getAttribute(u)===t){return}s.setAttribute(u,t*h.resolution);s.style[u]=t+"px"});s.context_=null;return s}function p(o){if(window.G_vmlCanvasManager){window.G_vmlCanvasManager.initElement(o)}var s=o.getContext("2d");if(!window.G_vmlCanvasManager){s.scale(h.resolution,h.resolution)}return s}},_initPlugins:function(){a.each(b.plugins,function(g,f){a.each(g.callbacks,function(h,j){this.observe(this.el,j,a.bind(h,this))},this);this[f]=b.clone(g);a.each(this[f],function(h,j){if(a.isFunction(h)){this[f][j]=a.bind(h,this)}},this)},this)},_initOptions:function(g){var B=b.clone(b.defaultOptions);B.x2axis=a.extend(a.clone(B.xaxis),B.x2axis);B.y2axis=a.extend(a.clone(B.yaxis),B.y2axis);this.options=b.merge(g||{},B);if(this.options.grid.minorVerticalLines===null&&this.options.xaxis.scaling==="logarithmic"){this.options.grid.minorVerticalLines=true}if(this.options.grid.minorHorizontalLines===null&&this.options.yaxis.scaling==="logarithmic"){this.options.grid.minorHorizontalLines=true}c.fire(this.el,"flotr:afterinitoptions",[this]);this.axes=b.Axis.getAxes(this.options);var o=[],h=[],r=this.series.length,w=this.series.length,k=this.options.colors,f=[],m=0,v,q,p,A;for(q=w-1;q>-1;--q){v=this.series[q].color;if(v){--w;if(a.isNumber(v)){o.push(v)}else{f.push(b.Color.parse(v))}}}for(q=o.length-1;q>-1;--q){w=Math.max(w,o[q]+1)}for(q=0;h.length=k.length){q=0;++m}}for(q=0,p=0;q10){t.minorTickFreq=0}else{if(m-p>5){t.minorTickFreq=2}else{t.minorTickFreq=5}}}}else{r.tickSize=Flotr.getTickSize(t.noTicks,q,k,t.tickDecimals)}r.min=q;r.max=k;if(t.min===null&&t.autoscale){r.min-=r.tickSize*s;if(r.min<0&&r.datamin>=0){r.min=0}r.min=r.tickSize*Math.floor(r.min/r.tickSize)}if(t.max===null&&t.autoscale){r.max+=r.tickSize*s;if(r.max>0&&r.datamax<=0&&r.datamax!=r.datamin){r.max=0}r.max=r.tickSize*Math.ceil(r.max/r.tickSize)}if(r.min==r.max){r.max=r.min+1}},calculateTextDimensions:function(l,k){var o="",p,m;if(this.options.showLabels){for(m=0;mo.length){o=this.ticks[m].label}}}this.maxLabel=l.dimensions(o,{size:k.fontSize,angle:Flotr.toRad(this.options.labelsAngle)},"font-size:smaller;","flotr-grid-label");this.titleSize=l.dimensions(this.options.title,{size:k.fontSize*1.2,angle:Flotr.toRad(this.options.titleAngle)},"font-weight:bold;","flotr-axis-title")},_cleanUserTicks:function(r,s){var q=this,m=this.options,k,p,l,o;if(h.isFunction(r)){r=r({min:q.min,max:q.max})}for(p=0;p1)?o[1]:m.tickFormatter(k,{min:q.min,max:q.max})}else{k=o;l=m.tickFormatter(k,{min:this.min,max:this.max})}s[p]={v:k,label:l}}},_calculateTimeTicks:function(){this.ticks=Flotr.Date.generator(this)},_calculateLogTicks:function(){var r=this,s=r.options,m,q;var l=Math.log(r.max);if(s.base!=Math.E){l/=Math.log(s.base)}l=Math.ceil(l);var p=Math.log(r.min);if(s.base!=Math.E){p/=Math.log(s.base)}p=Math.ceil(p);for(i=p;ih){h=m;k=true}if(le){e=l;j=true}}return{xmin:c,xmax:h,ymin:o,ymax:e,xused:k,yused:j}}};b.extend(a,{getSeries:function(c){return b.map(c,function(e){var d;if(e.data){d=new a();b.extend(d,e)}else{d=new a({data:e})}return d})}});Flotr.Series=a})();Flotr.addType("lines",{options:{show:false,lineWidth:2,fill:false,fillBorder:false,fillColor:null,fillOpacity:0.4,steps:false,stacked:false},stack:{values:[]},draw:function(b){var c=b.context,a=b.lineWidth,d=b.shadowSize,e;c.save();c.lineJoin="round";if(d){c.lineWidth=d/2;e=a/2+c.lineWidth/2;c.strokeStyle="rgba(0,0,0,0.1)";this.plot(b,e+d/2,false);c.strokeStyle="rgba(0,0,0,0.2)";this.plot(b,e,false)}c.lineWidth=a;c.strokeStyle=b.color;this.plot(b,0,true);c.restore()},plot:function(e,l,w){var c=e.context,r=e.width,q=e.height,A=e.xScale,b=e.yScale,z=e.data,k=e.stacked?this.stack:false,f=z.length-1,p=null,o=null,m=b(0),g=null,v,u,d,a,j,h,t;if(f<1){return}c.beginPath();for(t=0;t0&&z[t][1]){c.stroke();s();g=null;c.closePath();c.beginPath()}}continue}v=A(z[t][0]);u=A(z[t+1][0]);if(g===null){g=z[t]}if(k){j=k.values[z[t][0]]||0;h=k.values[z[t+1][0]]||k.values[z[t][0]]||0;d=b(z[t][1]+j);a=b(z[t+1][1]+h);if(w){k.values[z[t][0]]=z[t][1]+j;if(t==f-1){k.values[z[t+1][0]]=z[t+1][1]+h}}}else{d=b(z[t][1]);a=b(z[t+1][1])}if((d>q&&a>q)||(d<0&&a<0)||(v<0&&u<0)||(v>r&&u>r)){continue}if((p!=v)||(o!=d+l)){c.moveTo(v,d+l)}p=u;o=a+l;if(e.steps){c.lineTo(p+l/2,d+l);c.lineTo(p+l/2,o)}else{c.lineTo(p,o)}}if(!e.fill||e.fill&&!e.fillBorder){c.stroke()}s();function s(){if(!l&&e.fill&&g){v=A(g[0]);c.fillStyle=e.fillStyle;c.lineTo(u,m);c.lineTo(v,m);c.lineTo(v,b(g[1]));c.fill();if(e.fillBorder){c.stroke()}}}c.closePath()},extendYRange:function(b,f,l,m){var a=b.options;if(l.stacked&&((!a.max&&a.max!==0)||(!a.min&&a.min!==0))){var g=b.max,d=b.min,c=m.positiveSums||{},h=m.negativeSums||{},k,e;for(e=0;e0){c[k]=(c[k]||0)+f[e][1];g=Math.max(g,c[k])}else{h[k]=(h[k]||0)+f[e][1];d=Math.min(d,h[k])}}m.negativeSums=h;m.positiveSums=c;b.max=g;b.min=d}if(l.steps){this.hit=function(w){var r=w.data,t=w.args,j=w.yScale,s=t[0],o=r.length,p=t[1],v=s.x,u=s.relY,q;for(q=0;q=r[q][0]&&v<=r[q+1][0]){if(Math.abs(j(r[q][1])-u)<8){p.x=r[q][0];p.y=r[q][1];p.index=q;p.seriesIndex=w.index}break}}};this.drawHit=function(v){var o=v.context,r=v.args,p=v.data,u=v.xScale,q=r.index,t=u(r.x),s=v.yScale(r.y),j;if(p.length-1>q){j=v.xScale(p[q+1][0]);o.save();o.strokeStyle=v.color;o.lineWidth=v.lineWidth;o.beginPath();o.moveTo(t,s);o.lineTo(j,s);o.stroke();o.closePath();o.restore()}};this.clearHit=function(w){var p=w.context,s=w.args,q=w.data,v=w.xScale,o=w.lineWidth,r=s.index,u=v(s.x),t=w.yScale(s.y),j;if(q.length-1>r){j=w.xScale(q[r+1][0]);p.clearRect(u-o,t-o,j-u+2*o,2*o)}}}}});Flotr.addType("bars",{options:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,horizontal:false,stacked:false,centered:true,topPadding:0.1,grouped:false},stack:{positive:[],negative:[],_positive:[],_negative:[]},draw:function(a){var b=a.context;this.current+=1;b.save();b.lineJoin="miter";b.lineWidth=a.lineWidth;b.strokeStyle=a.color;if(a.fill){b.fillStyle=a.fillStyle}this.plot(a);b.restore()},plot:function(k){var e=k.data,c=k.context,b=k.shadowSize,f,g,d,h,a,j;if(e.length<1){return}this.translate(c,k.horizontal);for(f=0;f0?e.positive:e.negative;g=t[m]||g;t[m]=g+o}d=u(m-s);r=u(m+l-s);k=b(o+g);f=b(g);if(f<0){f=0}return(j===null||h===null)?null:{x:m,y:o,xScale:u,yScale:b,top:k,left:Math.min(d,r)-a/2,width:Math.abs(r-d)-a,height:f-k}},hit:function(m){var e=m.data,g=m.args,f=g[0],b=g[1],l=f.x,k=f.y,h=this.getBarGeometry(l,k,m),a=h.width/2,c=h.left,j,d;for(d=e.length;d--;){j=this.getBarGeometry(e[d][0],e[d][1],m);if(j.y>h.y&&Math.abs(c-j.left)0){d[p]=(d[p]||0)+o;k=Math.max(k,d[p])}else{l[p]=(l[p]||0)+o;e=Math.min(e,l[p])}}}if((b==1&&a)||(b==-1&&!a)){if(r.topPadding&&(c.max===c.datamax||(r.stacked&&this.stackMax!==k))){k+=r.topPadding*(k-e)}}this.stackMin=e;this.stackMax=k;this.negativeSums=l;this.positiveSums=d;c.max=k;c.min=e}});Flotr.addType("bubbles",{options:{show:false,lineWidth:2,fill:true,fillOpacity:0.4,baseRadius:2},draw:function(a){var b=a.context,c=a.shadowSize;b.save();b.lineWidth=a.lineWidth;b.fillStyle="rgba(0,0,0,0.05)";b.strokeStyle="rgba(0,0,0,0.05)";this.plot(a,c/2);b.strokeStyle="rgba(0,0,0,0.1)";this.plot(a,c/4);b.strokeStyle=a.color;b.fillStyle=a.fillStyle;this.plot(a);b.restore()},plot:function(j,b){var c=j.data,a=j.context,g,d,h,f,e;b=b||0;for(d=0;dq?"downFillColor":"upFillColor"];if(e.fill&&!e.barcharts){d.fillStyle="rgba(0,0,0,0.05)";d.fillRect(f+l,u+l,z-f,b-u);d.save();d.globalAlpha=e.fillOpacity;d.fillStyle=t;d.fillRect(f,u+a,z-f,b-u);d.restore()}if(a||s){m=Math.floor((f+z)/2)+g;d.strokeStyle=t;d.beginPath();if(e.barcharts){d.moveTo(m,Math.floor(p+r));d.lineTo(m,Math.floor(h+r));j=Math.floor(o+r)+0.5;d.moveTo(Math.floor(f)+g,j);d.lineTo(m,j);j=Math.floor(q+r)+0.5;d.moveTo(Math.floor(z)+g,j);d.lineTo(m,j)}else{d.strokeRect(f,u+a,z-f,b-u);d.moveTo(m,Math.floor(u+a));d.lineTo(m,Math.floor(p+a));d.moveTo(m,Math.floor(b+a));d.lineTo(m,Math.floor(h+a))}d.closePath();d.stroke()}}},extendXRange:function(b,c,a){if(b.options.max===null){b.max=Math.max(b.datamax+0.5,b.max);b.min=Math.min(b.datamin-0.5,b.min)}}});Flotr.addType("gantt",{options:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,centered:true},draw:function(c){var a=this.ctx,e=c.gantt.barWidth,d=Math.min(c.gantt.lineWidth,e);a.save();a.translate(this.plotOffset.left,this.plotOffset.top);a.lineJoin="miter";a.lineWidth=d;a.strokeStyle=c.color;a.save();this.gantt.plotShadows(c,e,0,c.gantt.fill);a.restore();if(c.gantt.fill){var b=c.gantt.fillColor||c.color;a.fillStyle=this.processColor(b,{opacity:c.gantt.fillOpacity})}this.gantt.plot(c,e,0,c.gantt.fill);a.restore()},plot:function(j,o,e,q){var w=j.data;if(w.length<1){return}var t=j.xaxis,b=j.yaxis,p=this.ctx,r;for(r=0;rt.max||mb.max){continue}if(ct.max){v=t.max;if(t.lastSerie!=j){k=false}}if(gb.max){m=b.max;if(b.lastSerie!=j){k=false}}if(q){p.beginPath();p.moveTo(t.d2p(c),b.d2p(g)+e);p.lineTo(t.d2p(c),b.d2p(m)+e);p.lineTo(t.d2p(v),b.d2p(m)+e);p.lineTo(t.d2p(v),b.d2p(g)+e);p.fill();p.closePath()}if(j.gantt.lineWidth&&(f||a||k)){p.beginPath();p.moveTo(t.d2p(c),b.d2p(g)+e);p[f?"lineTo":"moveTo"](t.d2p(c),b.d2p(m)+e);p[k?"lineTo":"moveTo"](t.d2p(v),b.d2p(m)+e);p[a?"lineTo":"moveTo"](t.d2p(v),b.d2p(g)+e);p.stroke();p.closePath()}}},plotShadows:function(g,j,c){var v=g.data;if(v.length<1){return}var q,f,h,t,r=g.xaxis,a=g.yaxis,p=this.ctx,m=this.options.shadowSize;for(q=0;qr.max||ka.max){continue}if(br.max){u=r.max}if(ea.max){k=a.max}var o=r.d2p(u)-r.d2p(b)-((r.d2p(u)+m<=this.plotWidth)?0:m);var l=a.d2p(e)-a.d2p(k)-((a.d2p(e)+m<=this.plotHeight)?0:m);p.fillStyle="rgba(0,0,0,0.05)";p.fillRect(Math.min(r.d2p(b)+m,this.plotWidth),Math.min(a.d2p(k)+m,this.plotHeight),o,l)}},extendXRange:function(b){if(b.options.max===null){var c=b.min,k=b.max,e,d,m,o,h,a={},l={},f=null;for(e=0;el){l=b.max+k.barWidth}}}b.lastSerie=h;b.max=l;b.min=d;b.tickSize=Flotr.getTickSize(b.options.noTicks,d,l,b.options.tickDecimals)}}});(function(){Flotr.defaultMarkerFormatter=function(b){return(Math.round(b.y*100)/100)+""};Flotr.addType("markers",{options:{show:false,lineWidth:1,color:"#000000",fill:false,fillColor:"#FFFFFF",fillOpacity:0.4,stroke:false,position:"ct",verticalMargin:0,labelFormatter:Flotr.defaultMarkerFormatter,fontSize:Flotr.defaultOptions.fontSize,stacked:false,stackingType:"b",horizontal:false},stack:{positive:[],negative:[],values:[]},draw:function(p){var f=p.data,c=p.context,l=p.stacked?p.stack:false,j=p.stackingType,b,h,g,e,o,k,m;c.save();c.lineJoin="round";c.lineWidth=p.lineWidth;c.strokeStyle="rgba(0,0,0,0.5)";c.fillStyle=p.fillStyle;function d(r,q){h=l.negative[r]||0;b=l.positive[r]||0;if(q>0){l.positive[r]=h+q;return h+q}else{l.negative[r]=b+q;return b+q}}for(e=0;e0?"top":"bottom",G,p,m,t,s;c.save();c.translate(w/2,u/2);c.scale(1,F);p=Math.cos(I)*B;m=Math.sin(I)*B;if(o>0){this.plotSlice(p+o,m+o,g,D,v,c);if(E){c.fillStyle="rgba(0,0,0,0.1)";c.fill()}}this.plotSlice(p,m,g,D,v,c);if(E){c.fillStyle=j;c.fill()}c.lineWidth=b;c.strokeStyle=C;c.stroke();G={size:f.fontSize*1.2,color:f.fontColor,weight:1.5};if(l){if(f.htmlText||!f.textEnabled){divStyle="position:absolute;"+H+":"+(u/2+(H==="top"?s:-s))+"px;";divStyle+=h+":"+(w/2+(h==="right"?-t:t))+"px;";q.push('
',l,"
")}else{G.textAlign=h;G.textBaseline=H;Flotr.drawText(c,l,t,s,G)}}if(f.htmlText||!f.textEnabled){var r=Flotr.DOM.node('
');Flotr.DOM.insert(r,q.join(""));Flotr.DOM.insert(f.element,r)}c.restore();this.startAngle=v;this.slices=this.slices||[];this.slices.push({radius:Math.min(e.width,e.height)*k/2,x:p,y:m,explode:B,start:D,end:v})},plotSlice:function(c,g,b,f,d,e){e.beginPath();e.moveTo(c,g);e.arc(c,g,b,f,d,false);e.lineTo(c,g);e.closePath()},hit:function(s){var h=s.data[0],l=s.args,j=s.index,k=l[0],f=l[1],q=this.slices[j],p=k.relX-s.width/2,o=k.relY-s.height/2,b=Math.sqrt(p*p+o*o),e=Math.atan(o/p),c=Math.PI*2,m=q.explode||s.explode,d=q.start%c,g=q.end%c;if(p<0){e+=Math.PI}else{if(p>0&&o<0){e+=c}}if(bm){if((d>=g&&(ed))||(e>d&&e0){c.lineWidth=d/2;c.strokeStyle="rgba(0,0,0,0.1)";this.plot(b,d/2+c.lineWidth/2);c.strokeStyle="rgba(0,0,0,0.2)";this.plot(b,c.lineWidth/2)}c.lineWidth=b.lineWidth;c.strokeStyle=b.color;c.fillStyle=b.fillColor||b.color;this.plot(b);c.restore()},plot:function(j,c){var d=j.data,a=j.context,h=j.xScale,b=j.yScale,e,g,f;for(e=d.length-1;e>-1;--e){f=d[e][1];if(f===null){continue}g=h(d[e][0]);f=b(f);if(g<0||g>j.width||f<0||f>j.height){continue}a.beginPath();if(c){a.arc(g,f+c,j.radius,0,Math.PI,false)}else{a.arc(g,f,j.radius,0,2*Math.PI,true);if(j.fill){a.fill()}}a.stroke();a.closePath()}}});Flotr.addType("radar",{options:{show:false,lineWidth:2,fill:true,fillOpacity:0.4,radiusRatio:0.9},draw:function(a){var b=a.context,c=a.shadowSize;b.save();b.translate(a.width/2,a.height/2);b.lineWidth=a.lineWidth;b.fillStyle="rgba(0,0,0,0.05)";b.strokeStyle="rgba(0,0,0,0.05)";this.plot(a,c/2);b.strokeStyle="rgba(0,0,0,0.1)";this.plot(a,c/4);b.strokeStyle=a.color;b.fillStyle=a.fillStyle;this.plot(a);b.restore()},plot:function(j,d){var e=j.data,a=j.context,g=Math.min(j.height,j.width)*j.radiusRatio/2,b=2*Math.PI/e.length,c=-Math.PI/2,f,h;d=d||0;a.beginPath();for(f=0;fthis.plotWidth||g.relY>this.plotHeight){this.el.style.cursor=null;a.removeClass(this.el,"flotr-crosshair");return}if(d.hideCursor){this.el.style.cursor="none";a.addClass(this.el,"flotr-crosshair")}e.save();e.strokeStyle=d.color;e.lineWidth=1;e.beginPath();if(d.mode.indexOf("x")!=-1){e.moveTo(b,c.top);e.lineTo(b,c.top+this.plotHeight)}if(d.mode.indexOf("y")!=-1){e.moveTo(c.left,f);e.lineTo(c.left+this.plotWidth,f)}e.stroke();e.restore()},clearCrosshair:function(){var c=this.plotOffset,b=this.lastMousePos,d=this.octx;if(b){d.clearRect(b.relX+c.left,c.top,1,this.plotHeight+1);d.clearRect(c.left,b.relY+c.top,this.plotWidth+1,1)}}})})();(function(){var c=Flotr.DOM,b=Flotr._;function a(g,e,f,d){var j="image/"+g,h=e.toDataURL(j),k=new Image();k.src=h;return k}Flotr.addPlugin("download",{saveImage:function(g,f,d,e){var h=null;if(Flotr.isIE&&Flotr.isIE<9){h=""+this.canvas.firstChild.innerHTML+"";return window.open().document.write(h)}if(g!=="jpeg"&&g!=="png"){return}h=a(g,this.canvas,f,d);if(b.isElement(h)&&e){this.download.restoreCanvas();c.hide(this.canvas);c.hide(this.overlay);c.setStyles({position:"absolute"});c.insert(this.el,h);this.saveImageElement=h}else{return window.open(h.src)}},restoreCanvas:function(){c.show(this.canvas);c.show(this.overlay);if(this.saveImageElement){this.el.removeChild(this.saveImageElement)}this.saveImageElement=null}})})();(function(){var b=Flotr.EventAdapter,a=Flotr._;Flotr.addPlugin("graphGrid",{callbacks:{"flotr:beforedraw":function(){this.graphGrid.drawGrid()},"flotr:afterdraw":function(){this.graphGrid.drawOutline()}},drawGrid:function(){var q=this.ctx,e=this.options,c=e.grid,h=c.verticalLines,A=c.horizontalLines,p=c.minorVerticalLines,z=c.minorHorizontalLines,s=this.plotHeight,g=this.plotWidth,B,k,t,r;if(h||p||A||z){b.fire(this.el,"flotr:beforegrid",[this.axes.x,this.axes.y,e,this])}q.save();q.lineWidth=1;q.strokeStyle=c.tickColor;function o(v){for(t=0;t=B.max)||(D==B.min||D==B.max)&&c.outlineWidth){return}v(Math.floor(B.d2p(D))+q.lineWidth/2)})}function m(j){q.moveTo(j,0);q.lineTo(j,s)}function C(j){q.moveTo(0,j);q.lineTo(g,j)}if(c.circular){q.translate(this.plotOffset.left+g/2,this.plotOffset.top+s/2);var f=Math.min(s,g)*e.radar.radiusRatio/2,w=this.axes.x.ticks.length,d=2*(Math.PI/w),u=-Math.PI/2;q.beginPath();B=this.axes.y;if(A){o(B.ticks)}if(z){o(B.minorTicks)}if(h){a.times(w,function(j){q.moveTo(0,0);q.lineTo(Math.cos(j*d+u)*f,Math.sin(j*d+u)*f)})}q.stroke()}else{q.translate(this.plotOffset.left,this.plotOffset.top);if(c.backgroundColor){q.fillStyle=this.processColor(c.backgroundColor,{x1:0,y1:0,x2:g,y2:s});q.fillRect(0,0,g,s)}q.beginPath();B=this.axes.x;if(h){l(B.ticks,m)}if(p){l(B.minorTicks,m)}B=this.axes.y;if(A){l(B.ticks,C)}if(z){l(B.minorTicks,C)}q.stroke()}q.restore();if(h||p||A||z){b.fire(this.el,"flotr:aftergrid",[this.axes.x,this.axes.y,e,this])}},drawOutline:function(){var p=this,g=p.options,c=g.grid,l=c.outline,z=p.ctx,e=c.backgroundImage,q=p.plotOffset,r=q.left,A=q.top,m=p.plotWidth,B=p.plotHeight,s,F,o,j,w,C;if(!c.outlineWidth){return}z.save();if(c.circular){z.translate(r+m/2,A+B/2);var h=Math.min(B,m)*g.radar.radiusRatio/2,E=this.axes.x.ticks.length,d=2*(Math.PI/E),D=-Math.PI/2;z.beginPath();z.lineWidth=c.outlineWidth;z.strokeStyle=c.color;z.lineJoin="round";for(i=0;i<=E;++i){z[i===0?"moveTo":"lineTo"](Math.cos(i*d+D)*h,Math.sin(i*d+D)*h)}z.stroke()}else{z.translate(r,A);var k=c.outlineWidth,f=0.5-k+((k+1)%2/2),t="lineTo",u="moveTo";z.lineWidth=k;z.strokeStyle=c.color;z.lineJoin="miter";z.beginPath();z.moveTo(f,f);m=m-(k/2)%1;B=B+k/2;z[l.indexOf("n")!==-1?t:u](m,f);z[l.indexOf("e")!==-1?t:u](m,B);z[l.indexOf("s")!==-1?t:u](f,B);z[l.indexOf("w")!==-1?t:u](f,f);z.stroke();z.closePath()}z.restore();if(e){o=e.src||e;j=(parseInt(e.left,10)||0)+q.left;w=(parseInt(e.top,10)||0)+q.top;F=new Image();F.onload=function(){z.save();if(e.alpha){z.globalAlpha=e.alpha}z.globalCompositeOperation="destination-over";z.drawImage(F,0,0,F.width,F.height,j,w,m,B);z.restore()};F.src=o}}})})();(function(){var d=Flotr.DOM,b=Flotr._,c=Flotr,a="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;";Flotr.addPlugin("hit",{callbacks:{"flotr:mousemove":function(f,g){this.hit.track(g)},"flotr:click":function(e){this.hit.track(e)},"flotr:mouseout":function(){this.hit.clearHit()}},track:function(e){if(this.options.mouse.track||b.any(this.series,function(f){return f.mouse&&f.mouse.track})){this.hit.hit(e)}},executeOnType:function(h,l,g){var k=false,f;if(!b.isArray(h)){h=[h]}function j(m,e){b.each(b.keys(c.graphTypes),function(o){if(m[o]&&m[o].show&&this[o][l]){f=this.getOptions(m,o);f.fill=!!m.mouse.fillColor;f.fillStyle=this.processColor(m.mouse.fillColor||"#ffffff",{opacity:m.mouse.fillOpacity});f.color=m.mouse.lineColor;f.context=this.octx;f.index=e;if(g){f.args=g}this[o][l].call(this[o],f);k=true}},this)}b.each(h,j,this);return k},drawHit:function(j){var g=this.octx,f=j.series;if(f.mouse.lineColor){g.save();g.lineWidth=(f.points?f.points.lineWidth:1);g.strokeStyle=f.mouse.lineColor;g.fillStyle=this.processColor(f.mouse.fillColor||"#ffffff",{opacity:f.mouse.fillOpacity});g.translate(this.plotOffset.left,this.plotOffset.top);if(!this.hit.executeOnType(f,"drawHit",j)){var h=j.xaxis,e=j.yaxis;g.beginPath();g.arc(h.d2p(j.x),e.d2p(j.y),f.points.radius||f.mouse.radius,0,2*Math.PI,true);g.fill();g.stroke();g.closePath()}g.restore();this.clip(g)}this.prevHit=j},clearHit:function(){var g=this.prevHit,j=this.octx,e=this.plotOffset;j.save();j.translate(e.left,e.top);if(g){if(!this.hit.executeOnType(g.series,"clearHit",this.prevHit)){var f=g.series,h=(f.points?f.points.lineWidth:1);offset=(f.points.radius||f.mouse.radius)+h;j.clearRect(g.xaxis.d2p(g.x)-offset,g.yaxis.d2p(g.y)-offset,offset*2,offset*2)}d.hide(this.mouseTrack);this.prevHit=null}j.restore()},hit:function(k){var q=this.options,f=this.prevHit,e,g,m,h,j,p,o,l;if(this.series.length===0){return}n={relX:k.relX,relY:k.relY,absX:k.absX,absY:k.absY};if(q.mouse.trackY&&!q.mouse.trackAll&&this.hit.executeOnType(this.series,"hit",[k,n])){if(!b.isUndefined(n.seriesIndex)){j=this.series[n.seriesIndex];n.series=j;n.mouse=j.mouse;n.xaxis=j.xaxis;n.yaxis=j.yaxis}}else{e=this.hit.closest(k);if(e){e=q.mouse.trackY?e.point:e.x;h=e.seriesIndex;j=this.series[h];o=j.xaxis;l=j.yaxis;g=2*j.mouse.sensibility;if(q.mouse.trackAll||(e.distanceXt.xaxis.max){continue}B=Math.abs(p-m);A=Math.abs(o-l);g=B*B+A*A;if(g
');this.mouseTrack=h;d.insert(this.el,h)}if(!l.mouse.relative){if(g.charAt(0)=="n"){v+="top:"+(q+u)+"px;bottom:auto;"}else{if(g.charAt(0)=="s"){v+="bottom:"+(q+f)+"px;top:auto;"}}if(g.charAt(1)=="e"){v+="right:"+(q+w)+"px;left:auto;"}else{if(g.charAt(1)=="w"){v+="left:"+(q+o)+"px;right:auto;"}}}else{if(B.bars.show){v+="bottom:"+(q-u-l.yaxis.d2p(l.y/2)+this.canvasHeight)+"px;top:auto;";v+="left:"+(q+o+l.xaxis.d2p(l.x-A.bars.barWidth/2))+"px;right:auto;"}else{if(B.pie.show){var e={x:(this.plotWidth)/2,y:(this.plotHeight)/2},t=(Math.min(this.canvasWidth,this.canvasHeight)*B.pie.sizeRatio)/2,r=l.sAngle=5||Math.abs(g.second.y-g.first.y)>=5}})})();(function(){var a=Flotr.DOM;Flotr.addPlugin("labels",{callbacks:{"flotr:afterdraw":function(){this.labels.draw()}},draw:function(){var d,s,g,m,p,f,v,b,u,k,r,j="",c=0,e=this.options,q=this.ctx,w=this.axes,t={size:e.fontSize};for(r=0;r(J?I.plotWidth:I.plotHeight)){continue}Flotr.drawText(q,s.label,A(I,J,F,E),G(I,J,F,E),z);if(!J&&!F){q.save();q.strokeStyle=z.color;q.beginPath();q.moveTo(I.plotOffset.left+I.plotWidth-8,I.plotOffset.top+D.d2p(s.v));q.lineTo(I.plotOffset.left+I.plotWidth,I.plotOffset.top+D.d2p(s.v));q.stroke();q.restore()}}function H(K){return K.options.showLabels&&K.used}function A(M,L,K,N){return M.plotOffset.left+(L?N:(K?-e.grid.labelMargin:e.grid.labelMargin+M.plotWidth))}function G(M,L,K,N){return M.plotOffset.top+(L?e.grid.labelMargin:N)+((L&&K)?M.plotHeight:0)}}function l(G,C){var H=C.orientation===1,E=C.n===1,A="",B,z,F,D=G.plotOffset;if(!H&&!E){q.save();q.strokeStyle=C.options.color||e.grid.color;q.beginPath()}if(C.options.showLabels&&(E?true:C.used)){for(r=0;r(H?G.canvasWidth:G.canvasHeight))){continue}F=D.top+(H?((E?1:-1)*(G.plotHeight+e.grid.labelMargin)):C.d2p(s.v)-C.maxLabel.height/2);B=H?(D.left+C.d2p(s.v)-p/2):0;A="";if(r===0){A=" first"}else{if(r===C.ticks.length-1){A=" last"}}A+=H?" flotr-grid-label-x":" flotr-grid-label-y";j+=['
'+s.label+"
"].join(" ");if(!H&&!E){q.moveTo(D.left+G.plotWidth-8,D.top+C.d2p(s.v));q.lineTo(D.left+G.plotWidth,D.top+C.d2p(s.v))}}}}}})})();(function(){var b=Flotr.DOM,a=Flotr._;Flotr.addPlugin("legend",{options:{show:true,noColumns:1,labelFormatter:function(c){return c},labelBoxBorderColor:"#CCCCCC",labelBoxWidth:14,labelBoxHeight:10,labelBoxMargin:5,labelBoxOpacity:0.4,container:null,position:"nw",margin:5,backgroundColor:null,backgroundOpacity:0.85},callbacks:{"flotr:afterinit":function(){this.legend.insertLegend()}},insertLegend:function(){if(!this.options.legend.show){return}var u=this.series,v=this.plotOffset,h=this.options,e=h.legend,R=[],f=false,F=this.ctx,N=a.filter(u,function(c){return(c.label&&!c.hide)}).length,D=e.position,E=e.margin,H,l,G;if(N){if(!h.HtmlText&&this.textEnabled&&!e.container){var J={size:h.fontSize*1.1,color:h.grid.color};var B=e.labelBoxWidth,Q=e.labelBoxHeight,I=e.labelBoxMargin,M=v.left+E,K=v.top+E;var P=0;for(H=u.length-1;H>-1;--H){if(!u[H].label||u[H].hide){continue}l=e.labelFormatter(u[H].label);P=Math.max(P,this._text.measureText(l,J).width)}var A=Math.round(B+I*3+P),j=Math.round(N*(I+Q)+I);if(D.charAt(0)=="s"){K=v.top+this.plotHeight-(E+j)}if(D.charAt(1)=="e"){M=v.left+this.plotWidth-(E+A)}G=this.processColor(e.backgroundColor||"rgb(240,240,240)",{opacity:e.backgroundOpacity||0.1});F.fillStyle=G;F.fillRect(M,K,A,j);F.strokeStyle=e.labelBoxBorderColor;F.strokeRect(Flotr.toPixel(M),Flotr.toPixel(K),A,j);var t=M+I;var r=K+I;for(H=0;H":"");f=true}var z=u[H],q=e.labelBoxWidth,k=e.labelBoxHeight,d=(z.bars?z.bars.fillOpacity:e.labelBoxOpacity),g="opacity:"+d+";filter:alpha(opacity="+d*100+");";l=e.labelFormatter(z.label);G="background-color:"+((z.bars&&z.bars.show&&z.bars.fillColor&&z.bars.fill)?z.bars.fillColor:z.color)+";";R.push('','
','
','
',"
","
","",'',l,"")}if(f){R.push("")}if(R.length>0){var L=''+R.join("")+"
";if(e.container){b.insert(e.container,L)}else{var o={position:"absolute","z-index":2};if(D.charAt(0)=="n"){o.top=(E+v.top)+"px";o.bottom="auto"}else{if(D.charAt(0)=="s"){o.bottom=(E+v.bottom)+"px";o.top="auto"}}if(D.charAt(1)=="e"){o.right=(E+v.right)+"px";o.left="auto"}else{if(D.charAt(1)=="w"){o.left=(E+v.left)+"px";o.right="auto"}}var w=b.create("div"),C;w.className="flotr-legend";b.setStyles(w,o);b.insert(w,L);b.insert(this.el,w);if(!e.backgroundOpacity){return}var O=e.backgroundColor||h.grid.backgroundColor||"#ffffff";a.extend(o,b.size(w),{backgroundColor:O,"z-index":1});o.width+="px";o.height+="px";w=b.create("div");w.className="flotr-legend-bg";b.setStyles(w,o);b.opacity(w,e.backgroundOpacity);b.insert(w," ");b.insert(this.el,w)}}}}}})})();(function(){function b(e){if(this.options.spreadsheet.tickFormatter){return this.options.spreadsheet.tickFormatter(e)}else{var d=a.find(this.axes.x.ticks,function(f){return f.v==e});if(d){return d.label}return e}}var c=Flotr.DOM,a=Flotr._;Flotr.addPlugin("spreadsheet",{options:{show:false,tabGraphLabel:"Graph",tabDataLabel:"Data",toolbarDownload:"Download CSV",toolbarSelectAll:"Select all",csvFileSeparator:",",decimalSeparator:".",tickFormatter:null,initialTab:"graph"},callbacks:{"flotr:afterconstruct":function(){if(!this.options.spreadsheet.show){return}var e=this.spreadsheet,d=c.node('
'),g=c.node('
'+this.options.spreadsheet.tabGraphLabel+"
"),f=c.node('
'+this.options.spreadsheet.tabDataLabel+"
"),h;e.tabsContainer=d;e.tabs={graph:g,data:f};c.insert(d,g);c.insert(d,f);c.insert(this.el,d);h=c.size(f).height+2;this.plotOffset.bottom+=h;c.setStyles(d,{top:this.canvasHeight-h+"px"});this.observe(g,"click",function(){e.showTab("graph")}).observe(f,"click",function(){e.showTab("data")});if(this.options.spreadsheet.initialTab!=="graph"){e.showTab(this.options.spreadsheet.initialTab)}}},loadDataGrid:function(){if(this.seriesData){return this.seriesData}var d=this.series,e={};a.each(d,function(g,f){a.each(g.data,function(j){var h=j[0],m=j[1],l=e[h];if(l){l[f+1]=m}else{var k=[];k[0]=h;k[f+1]=m;e[h]=k}})});this.seriesData=a.sortBy(e,function(g,f){return parseInt(f,10)});return this.seriesData},constructDataGrid:function(){if(this.spreadsheet.datagrid){return this.spreadsheet.datagrid}var o=this.series,k=this.spreadsheet.loadDataGrid(),e=[""],h,g,l;var f=[''];f.push("");a.each(o,function(q,p){f.push('");e.push("")});f.push("");a.each(k,function(p){f.push("");a.times(o.length+1,function(s){var q="td",u=p[s],t=(!a.isUndefined(u)?Math.round(u*100000)/100000:"");if(s===0){q="th";var r=b.call(this,t);if(r){t=r}}f.push("<"+q+(q=="th"?' scope="row"':"")+">"+t+"")},this);f.push("")},this);e.push("");l=c.node(f.join(""));h=c.node('");g=c.node('");this.observe(h,"click",a.bind(this.spreadsheet.downloadCSV,this)).observe(g,"click",a.bind(this.spreadsheet.selectAllData,this));var j=c.node('
');c.insert(j,h);c.insert(j,g);var m=this.canvasHeight-c.size(this.spreadsheet.tabsContainer).height-2,d=c.node('
');c.insert(d,j);c.insert(d,l);c.insert(this.el,d);this.spreadsheet.datagrid=l;this.spreadsheet.container=d;return l},showTab:function(d){if(this.spreadsheet.activeTab===d){return}switch(d){case"graph":c.hide(this.spreadsheet.container);c.removeClass(this.spreadsheet.tabs.data,"selected");c.addClass(this.spreadsheet.tabs.graph,"selected");break;case"data":if(!this.spreadsheet.datagrid){this.spreadsheet.constructDataGrid()}c.show(this.spreadsheet.container);c.addClass(this.spreadsheet.tabs.data,"selected");c.removeClass(this.spreadsheet.tabs.graph,"selected");break;default:throw"Illegal tab name: "+d}this.spreadsheet.activeTab=d},selectAllData:function(){if(this.spreadsheet.tabs){var e,d,h,g,f=this.spreadsheet.constructDataGrid();this.spreadsheet.showTab("data");setTimeout(function(){if((h=f.ownerDocument)&&(g=h.defaultView)&&g.getSelection&&h.createRange&&(e=window.getSelection())&&e.removeAllRanges){d=h.createRange();d.selectNode(f);e.removeAllRanges();e.addRange(d)}else{if(document.body&&document.body.createTextRange&&(d=document.body.createTextRange())){d.moveToElementText(f);d.select()}}},0);return true}else{return false}},downloadCSV:function(){var d="",f=this.series,e=this.options,h=this.spreadsheet.loadDataGrid(),g=encodeURIComponent(e.spreadsheet.csvFileSeparator);if(e.spreadsheet.decimalSeparator===e.spreadsheet.csvFileSeparator){throw"The decimal separator is the same as the column separator ("+e.spreadsheet.decimalSeparator+")"}a.each(f,function(k,j){d+=g+'"'+(k.label||String.fromCharCode(65+j)).replace(/\"/g,'\\"')+'"'});d+="%0D%0A";d+=a.reduce(h,function(k,l){var m=b.call(this,l[0])||"";m='"'+(m+"").replace(/\"/g,'\\"')+'"';var j=l.slice(1).join(g);if(e.spreadsheet.decimalSeparator!=="."){j=j.replace(/\./g,e.spreadsheet.decimalSeparator)}return k+m+g+j+"%0D%0A"},"",this);if(Flotr.isIE&&Flotr.isIE<9){d=d.replace(new RegExp(g,"g"),decodeURIComponent(g)).replace(/%0A/g,"\n").replace(/%0D/g,"\r");window.open().document.write(d)}else{window.open("data:text/csv,"+d)}}})})();(function(){var a=Flotr.DOM;Flotr.addPlugin("titles",{callbacks:{"flotr:afterdraw":function(){this.titles.drawTitles()}},drawTitles:function(){var e,d=this.options,g=d.grid.labelMargin,c=this.ctx,b=this.axes;if(!d.HtmlText&&this.textEnabled){var f={size:d.fontSize,color:d.grid.color,textAlign:"center"};if(d.subtitle){Flotr.drawText(c,d.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,f)}f.weight=1.5;f.size*=1.5;if(d.title){Flotr.drawText(c,d.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,f)}f.weight=1.8;f.size*=0.8;if(b.x.options.title&&b.x.used){f.textAlign=b.x.options.titleAlign||"center";f.textBaseline="top";f.angle=Flotr.toRad(b.x.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+b.x.maxLabel.height+this.plotHeight+2*g,f)}if(b.x2.options.title&&b.x2.used){f.textAlign=b.x2.options.titleAlign||"center";f.textBaseline="bottom";f.angle=Flotr.toRad(b.x2.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-b.x2.maxLabel.height-2*g,f)}if(b.y.options.title&&b.y.used){f.textAlign=b.y.options.titleAlign||"right";f.textBaseline="middle";f.angle=Flotr.toRad(b.y.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.y.options.title,this.plotOffset.left-b.y.maxLabel.width-2*g,this.plotOffset.top+this.plotHeight/2,f)}if(b.y2.options.title&&b.y2.used){f.textAlign=b.y2.options.titleAlign||"left";f.textBaseline="middle";f.angle=Flotr.toRad(b.y2.options.titleAngle);f=Flotr.getBestTextAlign(f.angle,f);Flotr.drawText(c,b.y2.options.title,this.plotOffset.left+this.plotWidth+b.y2.maxLabel.width+2*g,this.plotOffset.top+this.plotHeight/2,f)}}else{e=[];if(d.title){e.push('
',d.title,"
")}if(d.subtitle){e.push('
',d.subtitle,"
")}e.push("");e.push('
');if(b.x.options.title&&b.x.used){e.push('
',b.x.options.title,"
")}if(b.x2.options.title&&b.x2.used){e.push('
',b.x2.options.title,"
")}if(b.y.options.title&&b.y.used){e.push('
',b.y.options.title,"
")}if(b.y2.options.title&&b.y2.used){e.push('
',b.y2.options.title,"
")}e=e.join("");var h=a.create("div");a.setStyles({color:d.grid.color});h.className="flotr-titles";a.insert(this.el,h);a.insert(h,e)}}})})(); \ No newline at end of file -- cgit v1.2.3
 '+(q.label||String.fromCharCode(65+p))+"