• R/O
  • SSH
  • HTTPS

shibuya-trac: Commit


Commit MetaInfo

Revision796 (tree)
Zeit2011-05-29 17:11:36
Autorwadahiro

Log Message

ver 0.5-SNAPSHOT

  • Pieチャート対応
  • グラフ生成を書き直し

Ändern Zusammenfassung

Diff

--- plugins/reportincludeplugin/trunk/0.11/reportinclude/tests/__init__.py (nonexistent)
+++ plugins/reportincludeplugin/trunk/0.11/reportinclude/tests/__init__.py (revision 796)
@@ -0,0 +1,9 @@
1+import unittest
2+
3+def suite():
4+ suite = unittest.TestSuite()
5+ suite.addTest(dateutils_test.suite())
6+ return suite
7+
8+if __name__ == '__main__':
9+ unittest.main(defaultTest="suite")
\ No newline at end of file
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- plugins/reportincludeplugin/trunk/0.11/reportinclude/tests/renderer_test.py (nonexistent)
+++ plugins/reportincludeplugin/trunk/0.11/reportinclude/tests/renderer_test.py (revision 796)
@@ -0,0 +1,136 @@
1+# -*- coding: utf-8 -*-
2+
3+import sys
4+import os
5+import re
6+import unittest
7+
8+script_dir = os.path.dirname(os.path.abspath(__file__))
9+base_dir = script_dir + os.sep + '../'
10+if not base_dir in sys.path:
11+ sys.path.insert(0, base_dir)
12+
13+from renderer import ReportRenderer
14+
15+class ComponentManagerStub(object):
16+ components = {}
17+
18+ def component_activated(self, dummy):
19+ pass
20+
21+ def get_db_cnx(self):
22+ return DBStub()
23+
24+class RequestStub(object):
25+ def __init__(self):
26+ self.href = HrefStub()
27+ self.tz = None
28+
29+class HrefStub(object):
30+ def worktime(self, id):
31+ return 'worktime/%s' % id
32+
33+class ConfigStub(object):
34+ def get(self, tag, key):
35+ pass
36+
37+class DBStub(object):
38+ def __init__(self, row=None):
39+ self.row = row
40+
41+ def cursor(self):
42+ print "cursor"
43+ return self
44+
45+ def execute(self, sql , args):
46+ print "excecute"
47+ return self
48+
49+ def fetchone(self):
50+ print "fetchone"
51+ return self.row
52+
53+ def commit(self):
54+ print "commit"
55+
56+class RendererTest(unittest.TestCase):
57+
58+ def setUp(self):
59+ self.env = ComponentManagerStub()
60+ self.req = RequestStub()
61+ self.db = DBStub()
62+
63+ def test_getXAxisType(self):
64+ renderer = ReportRenderer(self.env)
65+
66+ type = renderer._getXAxisType(self.req, ['2011-04-31'], [])
67+ self.assertEqual("string", type)
68+
69+ type = renderer._getXAxisType(self.req, ['2011-04-30'], [])
70+ self.assertEqual("date", type)
71+
72+ type = renderer._getXAxisType(self.req, [100, 110], [])
73+ self.assertEqual("number", type)
74+
75+ type = renderer._getXAxisType(self.req, ["100", "110"], [])
76+ self.assertEqual("number", type)
77+
78+ def test_to_js_array(self):
79+ renderer = ReportRenderer(self.env)
80+
81+ result = renderer._to_js_array([1, 2, 3])
82+ self.assertEqual("[1,2,3]", result)
83+
84+ result = renderer._to_js_array([1, 'a', 3])
85+ self.assertEqual("['1','a','3']", result)
86+
87+ result = renderer._to_js_array([])
88+ self.assertEqual("[]", result)
89+
90+ result = renderer._to_js_array(None)
91+ self.assertEqual("null", result)
92+
93+ def test_convert_col(self):
94+ renderer = ReportRenderer(self.env)
95+
96+ col = renderer._convert_col(self.req, 'test', '1')
97+ self.assertEqual('1', col)
98+
99+ col = renderer._convert_col(self.req, '時刻', '100000')
100+ self.assertEqual('12:46:40', col)
101+
102+ col = renderer._convert_col(self.req, '日付', '100000')
103+ self.assertEqual('1970/01/02', col)
104+
105+ col = renderer._convert_col(self.req, '日時', '100000')
106+ self.assertEqual('1970/01/02 12:46:40', col)
107+
108+ col = renderer._convert_col(self.req, 'time', '100000')
109+ self.assertEqual('12:46:40', col)
110+
111+ col = renderer._convert_col(self.req, 'date', '100000')
112+ self.assertEqual('1970/01/02', col)
113+
114+ col = renderer._convert_col(self.req, 'datetime', '100000')
115+ self.assertEqual('1970/01/02 12:46:40', col)
116+
117+ def ticket(id):
118+ return '/ticket/%s' % id
119+ self.req.href.ticket = ticket
120+
121+ col = renderer._convert_col(self.req, 'ticket', '100')
122+ self.assertEqual('<a class="ticket" href="/ticket/100" title="View Ticket">#100</a>',
123+ str(col))
124+
125+ col = renderer._convert_col(self.req, 'id', '100')
126+ self.assertEqual('<a class="ticket" href="/ticket/100" title="View Ticket">#100</a>',
127+ str(col))
128+
129+ col = renderer._convert_col(self.req, 'チケット', '100')
130+ self.assertEqual('<a class="ticket" href="/ticket/100" title="View Ticket">#100</a>',
131+ str(col))
132+
133+
134+if __name__ == '__main__':
135+ unittest.main()
136+
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- plugins/reportincludeplugin/trunk/0.11/reportinclude/htdocs/js/jqplot/reportgraph.js (revision 795)
+++ plugins/reportincludeplugin/trunk/0.11/reportinclude/htdocs/js/jqplot/reportgraph.js (revision 796)
@@ -1,277 +1,249 @@
1-//reportgraph.js
1+(function(jQuery) {
2+ jQuery.fn.reportGraph = function(options) {
3+ var defaults = {
4+ 'graph': 'lines',
5+ 'stack' : false,
6+ 'legendLoc' : 'ne',
7+ 'legendXOffset' : 0,
8+ 'legendYOffset' : 0,
9+ 'xaxisType' : 'string',
10+ 'xaxisMin' : null,
11+ 'xaxisMax' : null,
12+ 'yaxisMin' : null,
13+ 'yaxisMax' : null,
14+ 'xaxisFormatString' : null,
15+ 'yaxisFormatString' : null
16+ };
217
18+ var setting = jQuery.extend(defaults, options);
19+ var id = this.attr('id');
20+
21+ var graph = _getGraph(setting);
22+ graph.draw(id);
23+
24+ return this;
25+ };
326
4-$( function() {
5- /*
6- $(".reportgraph").each(
7- function() {
8- renderGraph(this);
9- });
10- */
11-});
12-
13-function renderGraph(id) {
27+ // Factory
28+ function _getGraph(setting) {
29+ if (setting.graph == 'lines') {
30+ return new LineGraph(setting);
31+ }
32+ if (setting.graph == 'bars') {
33+ return new BarGraph(setting);
34+ }
35+ if (setting.graph == 'pie') {
36+ return new PieGraph(setting);
37+ }
38+ }
1439
15- var idstr = jQuery(id).attr('id').split("_")[1];
16- // console.log(idstr);
17-
18- // option handling
19- var title = $("#reportgraphopt_" + idstr + " .title").text();
20-
21- var opt_per = $("#reportgraphopt_" + idstr + " .per").text()
22- .toLowerCase();
23- var x_minTickSize = opt_per == "week" ? [ 7, "day" ] : [ 1, "day" ];
24-
25- var graphtype = $("#reportgraphopt_" + idstr + " .graph").text()
26- .toLowerCase();
27- var dateFormatPattern = $("#reportgraphopt_" + idstr + " .dateFormat")
28- .text();
29- var dateFormat = new DateFormat(dateFormatPattern);
30-
31- var cols = $("#reportgraphopt_" + idstr + " .cols").text().split(',');
32-
33- var isStackSeries = false;
34- if($("#reportgraphopt_" + idstr + " .stack").text().toLowerCase() == 'true') {
35- isStackSeries = true;
36- }
37-
38- var legendLoc = $("#reportgraphopt_" + idstr + " .legendLoc").text();
39- var legendXOffset = $("#reportgraphopt_" + idstr + " .legendXOffset").text();
40- var legendYOffset = $("#reportgraphopt_" + idstr + " .legendYOffset").text();
41-
42- var xaxisMin = $("#reportgraphopt_" + idstr + " .xaxisMin").text();
43- var xaxisMax = $("#reportgraphopt_" + idstr + " .xaxisMax").text();
44- var yaxisMin = $("#reportgraphopt_" + idstr + " .yaxisMin").text();
45- var yaxisMax = $("#reportgraphopt_" + idstr + " .yaxisMax").text();
46-
47- if(xaxisMin == 'null') {xaxisMin = null;}
48- if(xaxisMax == 'null') {xaxisMax = null;}
49- if(yaxisMin == 'null') {yaxisMin = null;}
50- if(yaxisMax == 'null') {yaxisMax = null;}
51-
52- var xaxisFormatString = $("#reportgraphopt_" + idstr + " .xaxisFormatString").text();
53- var yaxisFormatString = $("#reportgraphopt_" + idstr + " .yaxisFormatString").text();
54-
55- // collect label
56- var table_headers = [];
57- $("#reportgraphtable_" + idstr + " thead tr th").each( function(col_index) {
58- table_headers.push($(this).text());
59- });
60-
61- var labels = []
62- if (cols[0] == '') {
63- $.each(table_headers, function(table_headers_index, table_header) {
64- if (table_headers_index == 0) {
65- return true;
66- }
67- labels.push(table_header);
68- });
69- } else {
70- // for selected column
71- $.each(table_headers, function(table_headers_index, table_header) {
72- $.each(cols, function(col_index, col) {
73- if (col == table_header) {
74- labels.push(table_header);
75- }
76- });
77- });
78- }
79-
80- var xaxis_values = getXaxisValues(idstr, 0, dateFormat);
81-
82- var isDateAxis = false;
83- var isNumAxis = false;
84- switch (xaxis_values['type']) {
85- case 'date':
86- isDateAxis = true;
87- case 'number':
88- isNumAxis = true;
89- }
90- var datas = getTableValues(idstr, xaxis_values, table_headers, dateFormat);
91-
92- switch (graphtype) {
93- case 'bars':
94- graph_opt = {
95- type : $.jqplot.BarRenderer,
96- opts : {
97- }
98- };
99- break;
100- case 'lines':
101- default:
102- graph_opt = {
103- type : $.jqplot.LineRenderer,
104- opts : {
105- }
106- };
107- }
108-
109- var xaxis_opts = {}
110- if (isDateAxis) {
111- xaxis_opts = {
112- renderer: $.jqplot.DateAxisRenderer,
113- min: xaxisMin,
114- max: xaxisMax
115- };
116- } else if (isNumAxis) {
117- xaxis_opts = {
118- min: toNum(xaxisMin, null),
119- max: toNum(xaxisMax, null)
120- };
121- } else {
122- xaxis_opts = {
123- renderer: $.jqplot.CategoryAxisRenderer,
124- min: xaxisMin,
125- max: xaxisMax,
126- ticks: xaxis_values['values']
127- };
128- }
129- xaxis_opts.tickOptions = {formatString: xaxisFormatString};
130-
131- var yaxis_opts = {
132- tickOptions: {formatString: yaxisFormatString},
133- min: toNum(yaxisMin, null),
134- max: toNum(yaxisMax, null)
135- };
136-
137- var series = [];
138- $.each(labels, function(index, label) {
139- series.push({
140- label: label,
141- renderer: graph_opt['type']
142- })
143- });
144-
145- isFill = false;
146- if (isStackSeries && graphtype == 'lines') {
147- isFill = true;
148- }
149- plot1 = $.jqplot('placeholder_' + idstr, datas, {
150- legend: {
151- show: true,
152- location: legendLoc,
153- xoffset: Number(legendXOffset, 10),
154- yoffset: Number(legendYOffset, 10)
155- },
156- title: title,
157- stackSeries: isStackSeries,
158- series: series,
159- seriesDefaults: {
160- fill: isFill
161- },
162- axes: {
163- xaxis: xaxis_opts,
164- yaxis: yaxis_opts
165- },
166- highlighter: {
167- sizeAdjust: 10
168- },
169- cursor: {show: true}
170- });
171-}
172-
173-function toNum(str, defaultValue) {
174- if (str == null) {
175- return defaultValue;
176- }
177- num = Number(str, 10);
178- if (!isNaN(num)) {
179- return num;
180- } else {
181- return defaultValue;
40+ /**
41+ * Class: Graph
42+ */
43+ function Graph(setting) {
44+ this.setting = setting;
45+
46+ this.data = this.getData();
47+ this.title = setting.title;
48+ this.stack = setting.stack;
49+ this.seriesDefaults = this.getSeriesDefaults(setting);
50+ this.series = this.getSeries(setting);
51+ this.legendOption = {
52+ show: true,
53+ location: setting.legendLoc,
54+ xoffset: setting.legendXOffset,
55+ yoffset: setting.legendYOffset
56+ };
57+ this.xaxisOption = {
58+ renderer: this.getXAxisRenderer(setting),
59+ min: this.getXAxisMin(setting),
60+ max: this.getXAxisMax(setting),
61+ ticks: this.getTicks(setting),
62+ numberTicks: this.getNumberTicks(setting),
63+ tickOptions: {formatString: setting.xaxisFormatString}
64+ };
65+ this.yaxisOption = {
66+ min: setting.yaxisMin,
67+ max: setting.yaxisMax,
68+ tickOptions: {formatString: setting.yaxisFormatString}
69+ };
18270 }
183-}
71+
72+ Graph.prototype.draw = function(id) {
73+ jQuery.jqplot(id, this.data, {
74+ legend: this.legendOption,
75+ title: this.title,
76+ stackSeries: this.stack,
77+ seriesDefaults: this.seriesDefaults,
78+ series: this.series,
79+ axes: {
80+ xaxis: this.xaxisOption,
81+ yaxis: this.yaxisOption
82+ },
83+ highlighter: {
84+ sizeAdjust: 10
85+ },
86+ cursor: {show: true}
87+ });
88+ };
89+
90+ Graph.prototype.getSeriesDefaults = function() {
91+ var seriesDefaults = {};
92+ seriesDefaults = {
93+ renderer: this.getRenderer(this.setting),
94+ rendererOptions:{
95+ barWidth: 10
96+ },
97+ fill: this.setting.stack && this.setting.graph == 'lines'
98+ }
99+ return seriesDefaults;
100+ };
101+
102+ Graph.prototype.getRenderer = function() {
103+ return jQuery.jqplot.LineRenderer;
104+ };
105+
106+ Graph.prototype.getData = function() {
107+ if (this.setting.xaxisType == 'date' || this.setting.xaxisType == 'number') {
108+ return _getData(this.setting);
109+ }
110+ return this.setting.data;
111+ };
112+
113+ Graph.prototype.getTicks = function() {
114+ if (this.setting.xaxisType == 'date' || this.setting.xaxisType == 'number') {
115+ return []
116+ }
117+ return this.setting.ticks;
118+ };
119+
120+ Graph.prototype.getNumberTicks = function() {
121+ var number = this.setting.ticks.length;
122+ return number;
123+ };
124+
125+ Graph.prototype.getXAxisRenderer = function() {
126+ if (this.setting.xaxisType == 'number') {
127+ return jQuery.jqplot.LinerAxisRenderer;
128+ }
129+ if (this.setting.xaxisType == 'date') {
130+ return jQuery.jqplot.DateAxisRenderer;
131+ }
132+ // string
133+ return jQuery.jqplot.CategoryAxisRenderer;
134+ };
135+
136+ Graph.prototype.getXAxisMin = function() {
137+ if (this.setting.xaxisMin == null) {
138+ return this.setting.ticks[0];
139+ }
140+ return this.setting.xaxisMin;
141+ };
142+
143+ Graph.prototype.getXAxisMax = function() {
144+ if (this.setting.xaxisMax == null) {
145+ return this.setting.ticks[this.setting.ticks.length-1];
146+ }
147+ return this.setting.xaxisMax;
148+ };
149+
150+ Graph.prototype.getSeries = function() {
151+ var series = [];
152+ jQuery.each(this.setting.seriesLabel, function(index, value){
153+ // use default renderer.
154+ series.push({label: value})
155+ });
156+ return series;
157+ };
158+
159+ /**
160+ * Class: BarGraph
161+ */
162+ function BarGraph(setting) {
163+ Graph.apply(this, arguments);
164+ }
165+
166+ // extend Graph
167+ jQuery.extend(BarGraph.prototype, Graph.prototype);
168+
169+ BarGraph.prototype.getRenderer = function() {
170+ return jQuery.jqplot.BarRenderer;
171+ };
184172
185-function convertData(str, dateFormat) {
186- // try convert to date
187- date = dateFormat.parse(str);
188- if (date != null) {
189- var strDate = new DateFormat("yyyy-MM-dd").format(date);
190- return ['date', strDate];
173+ BarGraph.prototype.getSeriesDefaults = function() {
174+ var seriesDefaults = Graph.prototype.getSeriesDefaults.apply(this);
175+ seriesDefaults.rendererOptions = {
176+ barWidth: this.setting.barWidth
177+ };
178+ return seriesDefaults;
179+ };
180+
181+ /**
182+ * Class: LineGraph
183+ */
184+ function LineGraph(setting) {
185+ Graph.apply(this, arguments);
191186 }
187+
188+ // extend Graph
189+ jQuery.extend(LineGraph.prototype, Graph.prototype);
192190
193- // try convert to int
194- num = Number(str, 10);
195- if (!isNaN(num)) {
196- return ['number', num];
191+ LineGraph.prototype.getRenderer = function() {
192+ return jQuery.jqplot.LineRenderer;
193+ };
194+
195+ /**
196+ * Class: PieGraph
197+ */
198+ function PieGraph(setting) {
199+ Graph.apply(this, arguments);
197200 }
201+
202+ // extend Graph
203+ jQuery.extend(PieGraph.prototype, Graph.prototype);
198204
199- // for string. create ticks.
200- return ['str', str];
201-}
202-
203-function getTableValues(tableId, xaxis_values, table_headers, dateFormat) {
205+ PieGraph.prototype.getRenderer = function() {
206+ return jQuery.jqplot.PieRenderer;
207+ };
204208
205- var tmp = {};
209+ PieGraph.prototype.getData = function() {
210+ return _getData(this.setting);
211+ };
206212
207- $.each(table_headers, function(index, table_header) {
208- tmp[table_header] = [];
209- }
210- );
213+ PieGraph.prototype.getTicks = function() {
214+ return []
215+ };
216+
217+ PieGraph.prototype.getXAxisRenderer = function() {
218+ return jQuery.jqplot.LinerAxisRenderer;
219+ };
220+
221+ // Utility
222+ function _getData(setting) {
223+ var rtn = [];
224+ jQuery.each(setting.data, function(seriesIndex, seriesValue) {
225+ var newSeries = [];
226+
227+ // caluculate sum for pie.
228+ var sum = 0;
229+ if (setting.graph == 'pie') {
230+ jQuery.each(seriesValue, function(dataIndex, dataValue) {
231+ sum += dataValue;
232+ });
233+ }
211234
212- $("#reportgraphtable_" + tableId + " tbody tr").each(
213- function(row_index) {
214- $(this).children().each(function(col_index) {
215-
216- // for xaxis column
217- if(col_index == xaxis_values['colIndex']) {
218- return true;
235+ // create series.
236+ jQuery.each(seriesValue, function(dataIndex, dataValue) {
237+ var newTick = setting.ticks[dataIndex];
238+ if (setting.graph == 'pie') {
239+ newTick += ': ' + dataValue + ' (' + Math.round((dataValue/sum)*100*100)/100 + '%)';
219240 }
220-
221- table_header = table_headers[col_index];
222-
223- value = $(this).text();
224- if (value == '') {
225- return true;
226- }
227- value = Number(value, 10);
228-
229- if (xaxis_values['type'] == 'str') {
230- tmp[table_header].push(value);
231- } else {
232- tmp[table_header].push([xaxis_values['values'][row_index], value]);
233- }
241+ newSeries.push([newTick, dataValue])
234242 });
243+ rtn.push(newSeries);
235244 });
236-
237- var datas = [];
238- $.each(table_headers, function(index, table_header) {
239- // for xaxis column
240- if(index == xaxis_values['colIndex']) {
241- return true;
242- }
243- datas.push(tmp[table_header]);
244- }
245- );
245+ return rtn;
246+ }
246247
247- return datas;
248-}
248+})(jQuery);
249249
250-function getXaxisValues(tableId, index, dateFormat) {
251- var values = []
252- var type = 'str';
253-
254- $("#reportgraphtable_" + tableId + " tbody tr").each(
255- function(row_index) {
256- $(this).children().each( function(col_index) {
257- if (col_index == index) {
258-
259- str = $(this).text();
260- xaxis_value = convertData(str, dateFormat);
261-
262- type = xaxis_value[0];
263- values.push(xaxis_value[1]);
264- }
265- });
266- }
267- );
268-
269- var xaxis_values = {
270- colIndex: index,
271- type: type,
272- values: values
273- };
274-
275- // console.log("xaxis_values=" + xaxis_values['values'])
276- return xaxis_values;
277-}
--- plugins/reportincludeplugin/trunk/0.11/reportinclude/macro.py (revision 795)
+++ plugins/reportincludeplugin/trunk/0.11/reportinclude/macro.py (revision 796)
@@ -86,10 +86,11 @@
8686 * yaxisMax: Y軸の最大値を指定します。指定しない場合は、グラフデータより自動的に計算されます。
8787
8888 表からグラフの生成は、以下のルールに従って行われます。
89- * 一番左の列が、X軸の値になります。
89+ * グラフの種類がlines,barsの場合は、1列目がX軸の値になります。
9090 * デフォルトではyyyy-MM-dd形式の場合は日付と見なして、時系列データとして扱います。
9191 * 2列目以降がグラフのデータとなります。
9292 * ヘッダ行の値がラベルになります。
93+ * グラフの種類がpieの場合は、1列目が表示項目のラベル、2列目がその値として描画します。
9394
9495 例:
9596 * report:1 を表示する。
@@ -130,7 +131,6 @@
130131
131132 def _add_script(self, req):
132133 if not hasattr(req, '_reportinclude'):
133- add_script(req, 'reportinclude/js/dateformat.js')
134134 #add_stylesheet(req, 'reportinclude/css/reportinclude.css')
135135
136136 # add script and css for jqplot
@@ -138,6 +138,7 @@
138138 add_script(req, 'reportinclude/js/jqplot/jquery.jqplot.min.js')
139139 add_script(req, 'reportinclude/js/jqplot/jqplot.pointLabels.min.js')
140140 add_script(req, 'reportinclude/js/jqplot/jqplot.barRenderer.min.js')
141+ add_script(req, 'reportinclude/js/jqplot/jqplot.pieRenderer.min.js')
141142 add_script(req, 'reportinclude/js/jqplot/jqplot.categoryAxisRenderer.min.js')
142143 add_script(req, 'reportinclude/js/jqplot/jqplot.dateAxisRenderer.min.js')
143144 add_script(req, 'reportinclude/js/jqplot/jqplot.cursor.min.js')
--- plugins/reportincludeplugin/trunk/0.11/reportinclude/renderer.py (revision 795)
+++ plugins/reportincludeplugin/trunk/0.11/reportinclude/renderer.py (revision 796)
@@ -3,8 +3,10 @@
33 from genshi.builder import tag
44 from genshi.filters import Transformer
55
6+from trac.core import TracError
7+from trac.resource import ResourceNotFound
68 from trac.ticket.report import ReportModule
7-from trac.util.datefmt import format_datetime, format_date, format_time
9+from trac.util.datefmt import format_datetime, format_date, format_time, parse_date
810
911 class ReportRenderer(object):
1012
@@ -25,15 +27,15 @@
2527 if opts['title'] == '':
2628 opts['title'] = title
2729
28- table = self._render_table(req, id, vars, opts, title, sql, desc)
29- return self._render_graph(req, opts, table, title, desc)
30+ table, columns, table_data = self._render_table(req, id, vars, opts, title, sql, desc)
31+ table = self._render_graph(req, opts, table, columns, table_data, title, desc)
32+ return table
3033 else:
3134 raise ResourceNotFound(
3235 _('Report [%(num)] does not exist.', num=id),
3336 _('Invalid Report Number'))
34-
37+
3538 def _render_table(self, req, id, vars, opts, title, sql, desc):
36-
3739 db = self.env.get_db_cnx()
3840
3941 sql, vars = self._sql_sub_vars(sql, vars, db)
@@ -69,6 +71,10 @@
6971 tbody = tag.tbody()
7072 table.append(tbody)
7173
74+ table_data = {}
75+ for col in columns:
76+ table_data[col] = []
77+
7278 for idx, row in enumerate(cursor):
7379
7480 odd_or_even = (idx % 2 == 0) and 'odd' or 'even'
@@ -77,6 +83,7 @@
7783
7884 for col_idx, col in enumerate(row):
7985 column = columns[col_idx]
86+
8087 if column == '__color__' and css_class is '':
8188 css_class = 'color%s-' % col
8289 continue
@@ -83,18 +90,10 @@
8390 if column.startswith('_'):
8491 continue
8592
86- if column == 'time':
87- col = col != None and format_time(int(col)) or '--'
88- if column in ('date', 'created', 'modified'):
89- col = col != None and format_date(int(col)) or '--'
90- if column == 'datetime':
91- col = col != None and format_datetime(int(col)) or '--'
92-
93- if column.lower() in ('ticket', 'id', u'チケット'):
94- col = tag.a('#' + str(col), title='View Ticket', class_='ticket',
95- href=req.href.ticket(str(col)))
93+ converted_col = self._convert_col(req, column, col)
9694
97- tr = tr(tag.td(col))
95+ tr = tr(tag.td(converted_col))
96+ table_data[column].append(col)
9897
9998 css_class = css_class + odd_or_even
10099 tr = tr(class_ = css_class)
@@ -101,36 +100,67 @@
101100 tbody.append(tr)
102101
103102 #add_stylesheet(req, 'wikitable/css/wikitable.css')
104- return table
103+ return table, columns, table_data
105104
106- def _render_graph(self, req, opts, table, title, desc):
107-
108- if opts['graph'] != 'lines' and opts['graph'] != 'bars':
105+ def _render_graph(self, req, opts, table, columns, table_data, title, desc):
106+ u"""TracReportsの結果をグラフで表示する。
107+ """
108+ if opts['graph'] not in ('lines', 'bars', 'pie'):
109109 return table
110+
111+ ticks = table_data[columns[0]]
112+
113+ data = '['
114+ for column in columns[1:]:
115+ #print table_data[column]
116+ values = self._to_js_array(table_data[column])
117+ data = data + values + ','
118+ data = data[:-1] + ']'
119+
120+ xaxisType = self._getXAxisType(req, ticks, opts)
110121
111- opttag = tag.div(id="reportgraphopt_%d" % (self.index),
112- style="display:none")
113-
114- for opt in opts:
115- opttag.append(tag.span(opts[opt], class_=opt))
116-
117122 script = """
118123 jQuery(document).ready(function($) {
119- renderGraph("#reportgraph_%d");
124+ $('#reportgraph_%d').reportGraph({
125+ graph: '%s',
126+ seriesLabel: %s,
127+ data: %s,
128+ ticks: %s,
129+ title: '%s',
130+ stack: %s,
131+ legendLoc: '%s',
132+ legendXOffset: %s,
133+ legendYOffset: %s,
134+ xaxisType: '%s',
135+ xaxisMin: %s,
136+ xaxisMax: %s,
137+ yaxisMin: %s,
138+ yaxisMax: %s,
139+ xaxisFormatString: '%s',
140+ yaxisFormatString: '%s',
141+ barWidth: '%s'
142+ });
120143 });
121- """ % (self.index)
144+ """ % (self.index, opts['graph'], self._to_js_array(columns[1:]),
145+ data, self._to_js_array(ticks),
146+ opts['title'], opts['stack'].lower(), opts['legendLoc'],
147+ opts['legendXOffset'], opts['legendYOffset'],
148+ xaxisType, opts['xaxisMin'], opts['xaxisMax'],
149+ opts['yaxisMin'], opts['yaxisMax'],
150+ opts['xaxisFormatString'], opts['yaxisFormatString'], opts['barWidth'])
151+
152+ print script
122153
123154 div = tag.div(
124155 tag.div(' ',
125- id="placeholder_%d" % (self.index),
156+ id="reportgraph_%d" % (self.index),
126157 style="width:%spx;height:%spx;" %
127158 (opts["width"],opts["height"])),
128- opttag,
129159 tag.br(),
130160 table,
131161 tag.script(script, type="text/javascript"),
132162 class_="reportgraph",
133- id="reportgraph_%d" % (self.index)
163+ id="reporinclude_%d" % (self.index)
134164 )
135165 return div
136166
@@ -146,7 +176,7 @@
146176 'graph':'',
147177 'table':'inline',
148178 'dateFormat':'yyyy-MM-dd',
149- 'stack':False,
179+ 'stack':'false',
150180 'legendLoc':'ne',
151181 'legendXOffset':'12',
152182 'legendYOffset':'12',
@@ -155,7 +185,8 @@
155185 'yaxisMin':'null',
156186 'yaxisMax':'null',
157187 'xaxisFormatString':'',
158- 'yaxisFormatString':''
188+ 'yaxisFormatString':'',
189+ 'barWidth':'50'
159190 }
160191
161192 vars = {}
@@ -214,3 +245,52 @@
214245 rm = ReportModule(self.env)
215246 sql, vars = rm.sql_sub_vars(sql, vars, db)
216247 return sql, vars
248+
249+ def _getXAxisType(self, req, ticks, opts):
250+ if ticks and len(ticks) > 0:
251+ try:
252+ int(ticks[0])
253+ return 'number'
254+ except ValueError:
255+ pass
256+
257+ try:
258+ parse_date(ticks[0], req.tz)
259+ return 'date'
260+ except TracError:
261+ pass
262+
263+ return 'string'
264+
265+ def _to_js_array(self, array):
266+ if array is None:
267+ return 'null'
268+ if len(array) == 0:
269+ return '[]'
270+
271+ is_number = True
272+ for value in array:
273+ try:
274+ int(value)
275+ except ValueError:
276+ is_number = False
277+ pass
278+
279+ if is_number:
280+ return "[" + ",".join(map(str, array)) + "]"
281+ else:
282+ return "['" + "','".join(map(str, array)) + "']"
283+
284+ def _convert_col(self, req, column, col):
285+ if column == 'time' or column.endswith(u'時刻'):
286+ col = col != None and format_time(int(col)) or '--'
287+ if column in ('date', 'created', 'modified') or column.endswith(u'日付'):
288+ print col
289+ col = col != None and format_date(int(col)) or '--'
290+ if column == 'datetime' or column.endswith(u'日時'):
291+ col = col != None and format_datetime(int(col)) or '--'
292+
293+ if column.lower() in ('ticket', 'id', u'チケット'):
294+ col = tag.a('#' + str(col), title='View Ticket', class_='ticket',
295+ href=req.href.ticket(str(col)))
296+ return col
--- plugins/reportincludeplugin/trunk/0.11/setup.py (revision 795)
+++ plugins/reportincludeplugin/trunk/0.11/setup.py (revision 796)
@@ -8,12 +8,12 @@
88 author_email='wadahiro@gmail.com',
99 url = "http://sourceforge.jp/projects/shibuya-trac/wiki/plugins%2FReportIncludePlugin",
1010 description='Trac plugin for include a report (with graph) in a wiki page',
11- version='0.4.3',
11+ version='0.5-SNAPSHOT',
1212 license='New BSD',
1313 packages=find_packages(exclude=['*.tests*']),
1414 package_data={'reportinclude': ['htdocs/css/*.css', 'htdocs/css/jqplot/*.css', 'htdocs/js/*.js',
1515 'htdocs/js/flot/*.js', 'htdocs/js/jqplot/*.js', 'htdocs/image/*.gif',
16- 'templates/*.html']},
16+ 'templates/*.html', 'htdocs/*.html']},
1717 entry_points={
1818 'trac.plugins': [
1919 'reportinclude = reportinclude'
Show on old repository browser