pmux-logview 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Gemfile +4 -0
  2. data/LICENSE.txt +22 -0
  3. data/Makefile +18 -0
  4. data/README.md +113 -0
  5. data/Rakefile +4 -0
  6. data/bin/pmux-logview +4 -0
  7. data/conf/config.ru +15 -0
  8. data/conf/password +5 -0
  9. data/conf/pmux-logview.conf +12 -0
  10. data/lib/pmux-logview.rb +11 -0
  11. data/lib/pmux-logview/application.rb +69 -0
  12. data/lib/pmux-logview/auth_helper.rb +60 -0
  13. data/lib/pmux-logview/controller.rb +141 -0
  14. data/lib/pmux-logview/log_parser.rb +368 -0
  15. data/lib/pmux-logview/logger_wrapper.rb +129 -0
  16. data/lib/pmux-logview/model.rb +21 -0
  17. data/lib/pmux-logview/static/css/images/animated-overlay.gif +0 -0
  18. data/lib/pmux-logview/static/css/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png +0 -0
  19. data/lib/pmux-logview/static/css/images/ui-bg_flat_15_cd0a0a_40x100.png +0 -0
  20. data/lib/pmux-logview/static/css/images/ui-bg_glass_100_e4f1fb_1x400.png +0 -0
  21. data/lib/pmux-logview/static/css/images/ui-bg_glass_50_3baae3_1x400.png +0 -0
  22. data/lib/pmux-logview/static/css/images/ui-bg_glass_80_d7ebf9_1x400.png +0 -0
  23. data/lib/pmux-logview/static/css/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png +0 -0
  24. data/lib/pmux-logview/static/css/images/ui-bg_highlight-hard_70_000000_1x100.png +0 -0
  25. data/lib/pmux-logview/static/css/images/ui-bg_highlight-soft_100_deedf7_1x100.png +0 -0
  26. data/lib/pmux-logview/static/css/images/ui-bg_highlight-soft_25_ffef8f_1x100.png +0 -0
  27. data/lib/pmux-logview/static/css/images/ui-icons_2694e8_256x240.png +0 -0
  28. data/lib/pmux-logview/static/css/images/ui-icons_2e83ff_256x240.png +0 -0
  29. data/lib/pmux-logview/static/css/images/ui-icons_3d80b3_256x240.png +0 -0
  30. data/lib/pmux-logview/static/css/images/ui-icons_72a7cf_256x240.png +0 -0
  31. data/lib/pmux-logview/static/css/images/ui-icons_ffffff_256x240.png +0 -0
  32. data/lib/pmux-logview/static/css/jquery-ui-1.10.0.css +1186 -0
  33. data/lib/pmux-logview/static/css/jquery.dataTables.css +221 -0
  34. data/lib/pmux-logview/static/css/normalize.css +396 -0
  35. data/lib/pmux-logview/static/css/pmux-logview.css +161 -0
  36. data/lib/pmux-logview/static/css/tchart.css +124 -0
  37. data/lib/pmux-logview/static/font/7TssRTXcaLr8beqDiv5lkQ.woff +0 -0
  38. data/lib/pmux-logview/static/images/back_disabled.png +0 -0
  39. data/lib/pmux-logview/static/images/back_enabled.png +0 -0
  40. data/lib/pmux-logview/static/images/back_enabled_hover.png +0 -0
  41. data/lib/pmux-logview/static/images/forward_disabled.png +0 -0
  42. data/lib/pmux-logview/static/images/forward_enabled.png +0 -0
  43. data/lib/pmux-logview/static/images/forward_enabled_hover.png +0 -0
  44. data/lib/pmux-logview/static/images/sort_asc.png +0 -0
  45. data/lib/pmux-logview/static/images/sort_asc_disabled.png +0 -0
  46. data/lib/pmux-logview/static/images/sort_both.png +0 -0
  47. data/lib/pmux-logview/static/images/sort_desc.png +0 -0
  48. data/lib/pmux-logview/static/images/sort_desc_disabled.png +0 -0
  49. data/lib/pmux-logview/static/js/d3.v3.min.js +4 -0
  50. data/lib/pmux-logview/static/js/jquery-1.9.1.js +9597 -0
  51. data/lib/pmux-logview/static/js/jquery-ui-1.10.0.js +14883 -0
  52. data/lib/pmux-logview/static/js/jquery.activity-indicator-1.0.0.min.js +10 -0
  53. data/lib/pmux-logview/static/js/jquery.dataTables.min.js +157 -0
  54. data/lib/pmux-logview/static/js/pmux-logview-base.js +102 -0
  55. data/lib/pmux-logview/static/js/pmux-logview-detail.js +181 -0
  56. data/lib/pmux-logview/static/js/pmux-logview-index.js +324 -0
  57. data/lib/pmux-logview/static/js/tchart.js +2125 -0
  58. data/lib/pmux-logview/version.rb +5 -0
  59. data/lib/pmux-logview/views/detail.erb +58 -0
  60. data/lib/pmux-logview/views/index.erb +97 -0
  61. data/pmux-logview.gemspec +27 -0
  62. data/rpm/Makefile +20 -0
  63. data/rpm/pmux-logview +111 -0
  64. data/rpm/pmux-logview.spec +65 -0
  65. metadata +224 -0
@@ -0,0 +1,324 @@
1
+ pmux_logview.index = {
2
+ parent: pmux_logview,
3
+ job_log_sort_keys: [ "job_id", "mapper", "start_time", "end_time", "elapsed_time" ],
4
+ job_log_sort_key: "start_time",
5
+ job_log_sort_order: "desc",
6
+ job_log_nitems: 20,
7
+ job_log_page: 0,
8
+ job_log_jobs: {},
9
+ job_log_jobs_cookie: 0,
10
+ reload_job_log_type: "archive",
11
+ reload_job_log_initialized: false,
12
+ reload_dispatcher_log_initialized: false,
13
+ job_log_ajax_requested: false,
14
+ dispatcher_log_ajax_requested: false,
15
+ need_reload_job_log: true,
16
+ need_reload_dispatcher_log: false,
17
+ reload_job_log_timer_id: null,
18
+ reload_dispatcher_log_timer_id: null,
19
+ draw_invoke_timer_id: null,
20
+ tab_active_index: 0,
21
+ selected_job_id: null,
22
+ $main_tab: null,
23
+ $job_log_table: null,
24
+ $dispatcher_log_table: null,
25
+ $more_button: null,
26
+ $job_chart_tchart: null,
27
+ max_mapper_length: 60
28
+ };
29
+
30
+ pmux_logview.index.draw_job_chart = function() {
31
+ // convert tchart format
32
+ var source = {
33
+ settings: {
34
+ drawActorsSwimlaneChart: false,
35
+ width: $(window).innerWidth() - 80,
36
+ tasksGanttChart : {
37
+ label: "jobs gantt chart"
38
+ },
39
+ tasksBarChart : {
40
+ label: "jobs bar chart"
41
+ }
42
+ },
43
+ actors : null,
44
+ tasks : {}
45
+ };
46
+ var job_count = 0;
47
+ for (job_id in this.job_log_jobs) {
48
+ var from = Number(this.job_log_jobs[job_id].start_time_msec);
49
+ var to;
50
+ if ("end_time_msec" in this.job_log_jobs[job_id]) {
51
+ to = Number(this.job_log_jobs[job_id].end_time_msec);
52
+ } else {
53
+ continue;
54
+ }
55
+ source.tasks[job_id] = {
56
+ name: "id " + job_id,
57
+ from: from,
58
+ to: to,
59
+ clickEventArg: this.job_log_jobs[job_id],
60
+ nextTasks: null
61
+ }
62
+ job_count += 1;
63
+ }
64
+ if (job_count != 0) {
65
+ this.$job_chart_tchart.tchart('update', source);
66
+ }
67
+ }
68
+
69
+ pmux_logview.index.open_detail = function(job_id) {
70
+ window.open("/detail?job_id=" + job_id, "_blank");
71
+ };
72
+
73
+ pmux_logview.index.update_progress_bar = function() {
74
+ $(".progress-bar").each(function() {
75
+ var $target = $(this);
76
+ var data_value = $target.attr("data-value");
77
+ $target.progressbar({value: Number(data_value)});
78
+ });
79
+ };
80
+
81
+ pmux_logview.index.reload_job_log = function(force) {
82
+ if (!this.parent.can_reload) {
83
+ return;
84
+ }
85
+ if (!force && this.job_log_ajax_requested) {
86
+ return;
87
+ }
88
+ var self = this;
89
+ var param = { sort_key: this.job_log_sort_key,
90
+ sort_order: this.job_log_sort_order,
91
+ type: this.reload_job_log_type,
92
+ nitems: this.job_log_nitems,
93
+ page: this.job_log_page,
94
+ jobs_cookie: this.job_log_jobs_cookie };
95
+ this.parent.ajax_base("/log/job", "GET", param).done(function(data, textStatus, XMLHttpRequest) {
96
+ if (!("jobs_cookie" in data && "jobs" in data)) {
97
+ self.$job_log_table.fnClearTable();
98
+ self.$job_log_table.fnAddData(["invalid response", "", "", "", ""]);
99
+ self.parent.activityOff(function(){ self.$main_tab.tabs("option", "disabled", false) });
100
+ return;
101
+ }
102
+ $.extend(true, self.job_log_jobs, data.jobs);
103
+ self.job_log_jobs_cookie = data.jobs_cookie;
104
+ self.$job_log_table.fnClearTable();
105
+ var sorted_jobs = [];
106
+ for (var job_id in self.job_log_jobs) {
107
+ if (self.$job_log_table.fnSettings().aaSorting.length == 0) {
108
+ var inserted = false;
109
+ for (var i = 0; i < sorted_jobs.length; i++) {
110
+ if (Number(self.job_log_jobs[job_id]["start_time_msec"]) > Number(sorted_jobs[i]["start_time_msec"])) {
111
+ sorted_jobs.splice(i, 0, self.job_log_jobs[job_id]);
112
+ inserted = true;
113
+ break;
114
+ }
115
+ }
116
+ if (!inserted) {
117
+ sorted_jobs.push(self.job_log_jobs[job_id]);
118
+ }
119
+ } else {
120
+ sorted_jobs.push(self.job_log_jobs[job_id]);
121
+ }
122
+ }
123
+ var body_array = [];
124
+ for (i = 0; i < sorted_jobs.length; i++) {
125
+ var row_array = []
126
+ var job_id_html = '';
127
+ job_id_html += '<button class="container button-color button-normalize ui-corner-all" onClick="pmux_logview.index.open_detail(\'' + sorted_jobs[i]["job_id"] + '\')">';
128
+ job_id_html += ' <span class="icon-space">' + sorted_jobs[i].job_id + '</span>';
129
+ job_id_html += ' </span><span class="button-icon-adjust ui-icon ui-icon-info"></span>';
130
+ job_id_html += '</button>';
131
+ row_array.push(job_id_html)
132
+ if (sorted_jobs[i].mapper.length > self.max_mapper_length) {
133
+ row_array.push('<span class="text-ellipsis">'+ sorted_jobs[i].mapper.substring(0, self.max_mapper_length) + '...</span>');
134
+ } else {
135
+ row_array.push('<span class="text-ellipsis">'+ sorted_jobs[i].mapper + '</span>');
136
+ }
137
+ row_array.push('<span class="cell-nowrap">' + sorted_jobs[i].start_time + '</span>');
138
+ if (sorted_jobs[i].end_time.match(/^\d+%$/)) {
139
+ var percent = sorted_jobs[i].end_time.replace("%","");
140
+ row_array.push('<span class="cell-nowrap"><div class="progress-bar" data-value="' + percent + '" ></div></span>');
141
+ } else {
142
+ row_array.push('<span class="cell-nowrap">' + sorted_jobs[i].end_time + '</span>');
143
+ }
144
+ row_array.push(sorted_jobs[i].elapsed_time);
145
+ body_array.push(row_array);
146
+ }
147
+ self.$job_log_table.fnAddData(body_array);
148
+ self.update_progress_bar();
149
+ self.parent.activityOff(function(){ self.$main_tab.tabs("option", "disabled", false) });
150
+ self.valid_last_job_id = true;
151
+ self.reload_job_log_type = "update";
152
+ self.job_log_ajax_requested = false;
153
+ }).fail(function(XMLHttpRequest, textStatus, errorThrown) {
154
+ self.parent.open_dialog("job log の読み込みに失敗しました。");
155
+ self.parent.activityOff(function(){ self.$main_tab.tabs("option", "disabled", false) });
156
+ self.job_log_ajax_requested = false;
157
+ });
158
+ self.job_log_ajax_requested = true;
159
+ };
160
+
161
+ pmux_logview.index.reload_dispatcher_log = function() {
162
+ if (!this.parent.can_reload) {
163
+ return;
164
+ }
165
+ if (this.dispatcher_log_ajax_requested) {
166
+ return;
167
+ }
168
+ var self = this;
169
+ this.parent.ajax_base("/log/dispatcher", "GET", {}).done(function(data, textStatus, XMLHttpRequest) {
170
+ self.$dispatcher_log_table.fnClearTable();
171
+ var body_array = [];
172
+ for (var i = data.length - 1; i >= 0; i--) {
173
+ body_array.push([data[i]]);
174
+ }
175
+ self.$dispatcher_log_table.fnAddData(body_array);
176
+ self.parent.activityOff(function(){ self.$main_tab.tabs("option", "disabled", false) });
177
+ self.dispatcher_log_ajax_requested = false;
178
+ }).fail(function(XMLHttpRequest, textStatus, errorThrown) {
179
+ self.parent.open_dialog("dispatcher log の読み込みに失敗しました。");
180
+ self.parent.activityOff(function(){ self.$main_tab.tabs("option", "disabled", false) });
181
+ self.dispatcher_log_ajax_requested = false;
182
+ });
183
+ this.dispatcher_log_ajax_requested = true;
184
+ };
185
+
186
+ pmux_logview.index.reload = function() {
187
+ var self = this;
188
+ if (this.need_reload_job_log) {
189
+ if (this.reload_job_log_timer_id == null) {
190
+ this.reload_job_log_timer_id = setInterval(function(){
191
+ self.reload_job_log(false);
192
+ }, 3000);
193
+ }
194
+ if (!this.reload_job_log_initialized) {
195
+ this.parent.activityOn(function(){ self.$main_tab.tabs("option", "disabled", true) });
196
+ this.reload_job_log_type = "archive";
197
+ this.reload_job_log(true);
198
+ this.reload_job_log_initialized = true;
199
+ }
200
+ } else {
201
+ if (this.reload_job_log_timer_id != null) {
202
+ clearInterval(this.reload_job_log_timer_id);
203
+ this.reload_job_log_timer_id = null;
204
+ }
205
+ }
206
+ if (this.need_reload_dispatcher_log) {
207
+ if (this.reload_dispatcher_log_timer_id == null) {
208
+ this.reload_dispatcher_log_timer_id = setInterval(function(){
209
+ self.reload_dispatcher_log();
210
+ }, 3000);
211
+ }
212
+ if (!this.reload_dispatcher_log_initialized) {
213
+ this.parent.activityOn(function(){ self.$main_tab.tabs("option", "disabled", true) });
214
+ this.reload_dispatcher_log();
215
+ this.reload_dispatcher_log_initialized = true;
216
+ }
217
+ } else {
218
+ if (this.reload_dispatcher_log_timer_id != null) {
219
+ clearInterval(this.reload_dispatcher_log_timer_id);
220
+ this.reload_dispatcher_log_timer_id = null;
221
+ }
222
+ }
223
+ };
224
+
225
+ pmux_logview.index.draw_invoke = function() {
226
+ if (this.tab_active_index == 2) {
227
+ this.draw_job_chart();
228
+ }
229
+ if (this.draw_invoke_timer_id != null) {
230
+ clearInterval(this.draw_invoke_timer_id);
231
+ this.draw_invoke_timer_id = null;
232
+ }
233
+ }
234
+
235
+ pmux_logview.index.initialize = function() {
236
+ var self = this;
237
+ this.parent.initialize();
238
+ this.$main_tab = $("#main-tabs").tabs({
239
+ active: this.tab_active_index,
240
+ activate: function(event, ui) {
241
+ self.tab_active_index = self.$main_tab.tabs("option", "active");
242
+ if (self.tab_active_index == 0) {
243
+ self.need_reload_job_log = true;
244
+ self.need_reload_dispatcher_log = false;
245
+ } else if (self.tab_active_index == 1) {
246
+ self.need_reload_job_log = false;
247
+ self.need_reload_dispatcher_log = true;
248
+ } else if (self.tab_active_index == 2) {
249
+ self.draw_job_chart();
250
+ }
251
+ self.reload();
252
+ }
253
+ });
254
+ this.$job_log_table = $("#job-log-table").dataTable({
255
+ aaSorting: [],
256
+ bPaginate: false,
257
+ bScrollCollapse: true,
258
+ bSort: true,
259
+ bFilter: true,
260
+ bJQueryUI: true,
261
+ bAutoWidth: true,
262
+ sPaginationType: "full_numbers",
263
+ fnDrawCallback: function() {
264
+ self.update_progress_bar();
265
+ var $this = (this)
266
+ if ($this.fnSettings().aaSorting.length != 0) {
267
+ var sort_key = self.job_log_sort_keys[$this.fnSettings().aaSorting[0][0]];
268
+ var sort_order = $this.fnSettings().aaSorting[0][1];
269
+ if (self.job_log_sort_key != sort_key || self.job_log_sort_order != sort_order) {
270
+ self.job_log_sort_key = sort_key;
271
+ self.job_log_sort_order = sort_order;
272
+ self.job_log_page = 0;
273
+ self.reload_job_log_type = "archive";
274
+ self.reload_job_log(true);
275
+ }
276
+ }
277
+ }
278
+ });
279
+ this.$dispatcher_log_table = $("#dispatcher-log-table").dataTable({
280
+ aaSorting: [],
281
+ bPaginate: false,
282
+ bScrollCollapse: true,
283
+ bSort: false,
284
+ bFilter: true,
285
+ bJQueryUI: true,
286
+ bAutoWidth: true
287
+ });
288
+ this.$more_button = $("#more-button").click(function() {
289
+ self.job_log_page += 1;
290
+ self.reload_job_log_type = "archive";
291
+ self.parent.activityOn(function(){ self.$main_tab.tabs("option", "disabled", true) });
292
+ self.reload_job_log(true);
293
+ });
294
+ this.$job_chart_tchart = $("#job-chart-tchart").tchart({
295
+ onTaskClick: function(task, target, event) {
296
+ var html = '<table class="border task-tooltip"><thead class="task-tooltip"></thead>';
297
+ html += '<tbody class="task-tooltip"><tr class="task-tooltip">';
298
+ for (key in task) {
299
+ html += '<td class="task-tooltip">' + key +'</td>';
300
+ if (key == "job_id") {
301
+ html += '<td><button class="container button-color button-normalize ui-corner-all" onClick="pmux_logview.index.open_detail(\'' + task[key] + '\')">';
302
+ html += ' <span class="icon-space">' + task[key] + '</span>';
303
+ html += ' </span><span class="button-icon-adjust ui-icon ui-icon-info"></span>';
304
+ html += '</button></td></tr><tr class="task-tooltip">';
305
+ } else {
306
+ html += '<td class="task-tooltip">' + task[key] +'</td></tr><tr class="task-tooltip">';
307
+ }
308
+ }
309
+ html += '</tr></tbody></table>';
310
+ self.parent.open_tooltip(html, target, event);
311
+ }
312
+ });
313
+ $(window).resize(function() {
314
+ if (self.draw_invoke_timer_id == null) {
315
+ self.draw_invoke_timer_id = setInterval(function() { self.draw_invoke() }, 1000);
316
+ }
317
+ });
318
+ this.reload();
319
+ };
320
+
321
+ $(document).ready(function(){
322
+ pmux_logview.index.initialize();
323
+ });
324
+
@@ -0,0 +1,2125 @@
1
+ (function($) {
2
+ var _tcColorPattern = ['#990033','#ff0066','#cc00cc','#6600cc','#3333ff','#003366','#009999','#00ff99',
3
+ '#009933','#00cc00','#ccff00','#ffcc00','#996633','#cc9966','#ff3366','#ff3399',
4
+ '#cc00ff','#9966ff','#3333cc','#6699cc','#669999','#339966','#33ff66','#33ff00',
5
+ '#999900','#ffcc66','#330000','#ffcc99','#cc0033','#ff0099','#9900cc','#330066',
6
+ '#0066ff','#006699','#99cccc','#006633','#00ff66','#66ff00','#cccc00','#ffcc33',
7
+ '#663333','#ffffff','#ff0033','#ff33cc','#990099','#6600ff','#0033ff','#3399cc',
8
+ '#ccffff','#336633','#ccffcc','#99ff00','#cccc33','#cc9933','#996666','#cccccc',
9
+ '#ff9999','#ff00cc','#cc99cc','#6633ff','#3366ff','#0099cc','#33cccc','#669966',
10
+ '#ccff99','#66cc00','#333300','#996600','#cc9999','#999999','#cc3366','#ff66ff',
11
+ '#996699','#ccccff','#3366cc','#66ccff','#66cccc','#66cc66','#99ff66','#00ff00',
12
+ '#666600','#cc9900','#993333','#666666','#ffccff','#ff33ff','#663366','#9999ff',
13
+ '#000066','#3399ff','#339999','#99ff99','#99ff33','#33cc00','#999933','#ff9900',
14
+ '#cc6666','#333333','#cc6699','#ff00ff','#660099','#9999cc','#000033','#003399',
15
+ '#336666','#66ff66','#00ff33','#339900','#cccc66','#cc6600','#ffcccc','#993366',
16
+ '#cc0099','#9933cc','#6666cc','#0000ff','#0099ff','#006666','#339933','#33ff33',
17
+ '#99cc66','#666633','#993300','#ff3333','#660033','#990066','#660066','#6666ff',
18
+ '#000099','#33ccff','#003333','#99cc99','#00cc33','#669933','#999966','#cc6633',
19
+ '#cc3333','#cc3399','#cc66cc','#9900ff','#666699','#0033cc','#00ccff','#00ffcc',
20
+ '#66ff99','#33cc33','#99cc33','#cccc99','#663300','#ff6666','#ff99cc','#cc33cc',
21
+ '#9933ff','#333366','#0000cc','#99ffff','#33ffcc','#33ff99','#66ff33','#336600',
22
+ '#ffffcc','#ff9966','#660000','#ff66cc','#cc99ff','#9966cc','#333399','#336699',
23
+ '#66ffff','#33cc99','#33cc66','#009900','#669900','#ffff99','#ff6633','#990000',
24
+ '#ff99ff','#cc66ff','#330033','#330099','#0066cc','#33ffff','#00cc99','#00cc66',
25
+ '#66cc33','#99cc00','#ffff66','#ff9933','#cc0000','#ff6699','#cc33ff','#663399',
26
+ '#3300cc','#99ccff','#00ffff','#66ffcc','#66cc99','#006600','#ccff66','#ffff33',
27
+ '#ff6600','#ff0000','#cc0066','#993399','#6633cc','#3300ff','#6699ff','#00cccc',
28
+ '#99ffcc','#009966','#003300','#ccff33','#ffff00','#cc3300','#ff3300','#000000'];
29
+
30
+ var _tcGetColor = function(pos) {
31
+ var idx = pos % _tcColorPattern.length;
32
+ return _tcColorPattern[idx];
33
+ }
34
+
35
+ var _tcGetStringLength = function(str) {
36
+ len = 0;
37
+ for (var i = 0; i < str.length; i++) {
38
+ if (str.charCodeAt(i) < 256) {
39
+ len += 1;
40
+ } else {
41
+ len += 2;
42
+ }
43
+ }
44
+ return len;
45
+ }
46
+
47
+ var _tcTFPad = function(v, len) {
48
+ return ("000" + v).substr(-len);
49
+ }
50
+
51
+ var _tcTimestampFormat = function(value, BrushFromTo) {
52
+ var differ = BrushFromTo[1] - BrushFromTo[0];
53
+ var msec = value % 1000;
54
+ var dt = new Date(value);
55
+ if (differ < 1000) {
56
+ // 1sec
57
+ return "" + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2) + "." + _tcTFPad(msec, 3);
58
+ } else if (differ < 60 * 1000) {
59
+ // 1min
60
+ return "" + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2) + "." + _tcTFPad(msec, 3);
61
+ } else if (differ < 60 * 60 * 1000) {
62
+ // 1hour
63
+ return "" + _tcTFPad((dt.getMonth() + 1), 2) + "-" + _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2);
64
+ } else if (differ < 24 * 60 * 60 * 1000) {
65
+ // 1day
66
+ return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" + _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2);
67
+ } else if (differ < 7 * 24 * 60 * 60 * 1000) {
68
+ // 1week
69
+ return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" + _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2);
70
+ } else if (differ < 30 * 24 * 60 * 60 * 1000) {
71
+ // 1month
72
+ return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" + _tcTFPad(dt.getDate(), 2);
73
+ } else {
74
+ return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" + _tcTFPad(dt.getDate(), 2);
75
+ }
76
+ }
77
+
78
+ var _tcElapsedTimeFormat = function(value, BrushFromTo) {
79
+ var differ = BrushFromTo[1] - BrushFromTo[0];
80
+ var dt = new Date(value);
81
+ var week = Math.floor(value / (7 * 24 * 60 * 60 * 1000));
82
+ value -= week * (7 * 24 * 60 * 60 * 1000);
83
+ var day = Math.floor(value / (24 * 60 * 60 * 1000));
84
+ value -= day * (24 * 60 * 60 * 1000);
85
+ var hour = Math.floor(value / (60 * 60 * 1000));
86
+ value -= hour * (60 * 60 * 1000);
87
+ var min = Math.floor(value / (60 * 1000));
88
+ value -= min * (60 * 1000);
89
+ var sec = Math.floor(value / (1000));
90
+ value -= sec * (1000);
91
+ var msec = value;
92
+ if (differ < 1000) {
93
+ // < 1sec
94
+ return "" + msec + "ms";
95
+ } else if (differ < 60 * 1000) {
96
+ // < 1min
97
+ return "" + sec + "s " + msec + "ms";
98
+ } else if (differ < 60 * 60 * 1000) {
99
+ // < 1hour
100
+ return "" + min + "m " + sec + "s ";
101
+ } else if (differ < 24 * 60 * 60 * 1000) {
102
+ // < 1day
103
+ return "" + hour + "h " + min + "m ";
104
+ } else if (differ < 7 * 24 * 60 * 60 * 1000) {
105
+ // < 1week
106
+ return "" + day + "d " + hour + "h " + min + "m ";
107
+ } else {
108
+ // other
109
+ return "" + week + "w " + day + "d " + hour + "h ";
110
+ }
111
+ }
112
+
113
+ var _tcAdjustBlushValue = function(brushFrom, brushTo, start, end) {
114
+ if (brushFrom == null ||
115
+ brushTo == null) {
116
+ brushFrom = start;
117
+ brushTo = end;
118
+ }
119
+ if (brushFrom < start) {
120
+ brushFrom = start;
121
+ }
122
+ if (brushTo > end) {
123
+ brushTo = end;
124
+ }
125
+ if (brushTo == brushFrom) {
126
+ brushFrom = start;
127
+ brushTo = end;
128
+ }
129
+ return [brushFrom, brushTo];
130
+ }
131
+
132
+ var _tcGetBrushExtent = function(viewRange, start, end) {
133
+ if (viewRange.from == null ||
134
+ viewRange.to == null) {
135
+ return [0, 0];
136
+ } else {
137
+ if (viewRange.from < start) {
138
+ viewRange.from = start;
139
+ }
140
+ if (viewRange.to > end) {
141
+ viewRange.to = end;
142
+ }
143
+ return [viewRange.from, viewRange.to];
144
+ }
145
+ }
146
+ var _tcGetCommonData = function(source) {
147
+ var startDateMin = null;
148
+ var endDateMax = null;
149
+ var commonData = {}
150
+ commonData.scrolls = [];
151
+ commonData.tasks = [];
152
+ commonData.containers = [ {cls: "scrollButtonsContainer"},
153
+ {cls: "optionsContainer" } ];
154
+ commonData.datePickerContainersData = [ {cls: "datePickerContainer startDatePickerContainer", label: "start :"},
155
+ {cls: "datePickerContainer endDatePickerContainer", label: "end :"} ]
156
+ commonData.datePickersData = [ {span: "span.startDatePickerContainer", data: [{ cls: "startDatePicker" }] },
157
+ {span: "span.endDatePickerContainer", data: [{ cls: "endDatePicker" }] } ]
158
+ if (source.actors != null) {
159
+ if (source.settings.drawActorsSummaryBarChart) {
160
+ commonData.scrolls.push({target: "div.actorsSummaryBarChart", label: source.settings.actorsSummaryBarChart.label , cls: "tchartButton ui-corner-all"});
161
+ } else if (source.settings.drawActorsSwimlaneChart) {
162
+ commonData.scrolls.push({target: "div.actorsSwimlaneChart", label: source.settings.actorsSwimlaneChart.label , cls: "tchartButton ui-corner-all"});
163
+ }
164
+ }
165
+ if (source.tasks != null) {
166
+ commonData.scrolls.push({target: "div.tasksGanttChart", label: source.settings.tasksGanttChart.label, cls: "tchartButton ui-corner-all"});
167
+ commonData.scrolls.push({target: "div.tasksBarChart", label: source.settings.tasksBarChart.label, cls: "tchartButton ui-corner-all"});
168
+ var count = 0;
169
+ for (var taskId in source.tasks) {
170
+ if (startDateMin == null) {
171
+ startDateMin = source.tasks[taskId].from;
172
+ } else {
173
+ if (source.tasks[taskId].from < startDateMin) {
174
+ startDateMin = source.tasks[taskId].from;
175
+ }
176
+ }
177
+ if (endDateMax == null) {
178
+ endDateMax = source.tasks[taskId].to;
179
+ } else {
180
+ if (source.tasks[taskId].to > endDateMax) {
181
+ endDateMax = source.tasks[taskId].to;
182
+ }
183
+ }
184
+ if (source.settings.startDate != null && source.settings.startDate > source.tasks[taskId].from) {
185
+ continue;
186
+ }
187
+ if (source.settings.endDate != null && (source.settings.endDate + 86400000) < source.tasks[taskId].to) {
188
+ continue;
189
+ }
190
+ var color = _tcGetColor(count);
191
+ source.tasks[taskId].color = color;
192
+ var task = {
193
+ taskId: taskId,
194
+ name: source.tasks[taskId].name,
195
+ from: source.tasks[taskId].from,
196
+ to: source.tasks[taskId].to,
197
+ elapse: source.tasks[taskId].to - source.tasks[taskId].from,
198
+ clickEventArg: source.tasks[taskId].clickEventArg,
199
+ color: source.tasks[taskId].color
200
+ };
201
+ commonData.tasks.push(task);
202
+ count += 1;
203
+ }
204
+ }
205
+ if (source.settings.startDate == null) {
206
+ source.settings.startDate = startDateMin;
207
+ }
208
+ if (source.settings.endDate == null) {
209
+ source.settings.endDate = endDateMax;
210
+ }
211
+ commonData.tickWidth = source.settings.fontSize * 25 / 2;
212
+ commonData.fromMin = d3.min(commonData.tasks, function(d){ return d.from });
213
+ commonData.toMax = d3.max(commonData.tasks, function(d){ return d.to });
214
+ commonData.elapseMax = d3.max(commonData.tasks, function(d){ return d.elapse });
215
+ commonData.startDateMin = startDateMin;
216
+ commonData.endDateMax = endDateMax;
217
+ return commonData;
218
+ }
219
+
220
+ var _tcDrawCreateContainers = function(self, divSel, containerData) {
221
+ var containers = d3.selectAll(self)
222
+ .selectAll(divSel)
223
+ .selectAll("div")
224
+ .data(containerData);
225
+ containers.attr("class", function(d) { return d.cls })
226
+ containers.enter()
227
+ .append("div")
228
+ .attr("class", function(d) { return d.cls })
229
+ containers.exit().remove();
230
+ }
231
+
232
+ var _tcDrawCreateScrollButtons = function(self, divSel, scrollButtonsData) {
233
+ var scrollButtons = d3.selectAll(self)
234
+ .selectAll(divSel)
235
+ .selectAll("div.scrollButtonsContainer")
236
+ .selectAll("button")
237
+ .data(scrollButtonsData);
238
+ scrollButtons.attr("class", function(d) { return d.cls })
239
+ .text(function(d) { return d.label })
240
+ scrollButtons.enter()
241
+ .append("button")
242
+ .attr("class", function(d) { return d.cls })
243
+ .text(function(d) { return d.label })
244
+ .on("click", function(d) {
245
+ $('html,body').animate(
246
+ { scrollTop: $(d.target).offset().top},
247
+ { duration: 100, easing: "swing" }
248
+ );
249
+ });
250
+ scrollButtons.exit().remove();
251
+ return scrollButtons;
252
+ }
253
+
254
+ var _tcDrawCreateSummaryButton = function(self, divSel, summaryButtonData, callback) {
255
+ var summaryButton = d3.selectAll(self)
256
+ .selectAll(divSel)
257
+ .selectAll("div.optionsContainer")
258
+ .selectAll("button")
259
+ .data(summaryButtonData);
260
+ summaryButton.attr("class", "tchartButton ui-corner-all")
261
+ .text(function(d) { return d.label })
262
+ .on("click", function(d) {
263
+ callback();
264
+ });
265
+ summaryButton.enter()
266
+ .append("button")
267
+ .attr("class", "tchartButton ui-corner-all")
268
+ .text(function(d) { return d.label })
269
+ .on("click", function(d) {
270
+ callback();
271
+ });
272
+ summaryButton.exit().remove();
273
+ return summaryButton;
274
+ }
275
+
276
+ var _tcDrawCreatePrevNextInputs = function(self, divSel, startValue, stepValue, callbackAll, callbackPrev, callbackStart, callbackStep, callbackNext) {
277
+ var prevNextContainers = d3.selectAll(self)
278
+ .selectAll(divSel)
279
+ .selectAll("div.optionsContainer")
280
+ .selectAll("span")
281
+ .data([{cls: "allContainer", label: ""},
282
+ {cls: "prevContainer", label: ""},
283
+ {cls: "startContainer", label: "start"},
284
+ {cls: "stepContainer", label: "step"},
285
+ {cls: "nextContainer", label: ""}]);
286
+ prevNextContainers.enter()
287
+ .append("span")
288
+ .attr("class", function(d) { return d.cls })
289
+ .text(function(d) { return d.label })
290
+ prevNextContainers.exit().remove();
291
+
292
+ var allButton = d3.selectAll(self)
293
+ .selectAll(divSel)
294
+ .selectAll("div.optionsContainer")
295
+ .selectAll("span.allContainer")
296
+ .selectAll("button")
297
+ .data([{label: "all" }]);
298
+ allButton.enter()
299
+ .append("button")
300
+ .attr("class", "tchartButton ui-corner-all")
301
+ .text(function(d) { return d.label })
302
+ .on("click", function(d) {
303
+ callbackAll();
304
+ });
305
+ allButton.exit().remove();
306
+
307
+ var prevButton = d3.selectAll(self)
308
+ .selectAll(divSel)
309
+ .selectAll("div.optionsContainer")
310
+ .selectAll("span.prevContainer")
311
+ .selectAll("button")
312
+ .data([{ label: "prev" }]);
313
+ prevButton.enter()
314
+ .append("button")
315
+ .attr("class", "tchartButton ui-corner-all")
316
+ .text(function(d) { return d.label })
317
+ .on("click", function(d) {
318
+ callbackPrev();
319
+ });
320
+ prevButton.exit().remove();
321
+
322
+ var startInput = d3.selectAll(self)
323
+ .selectAll(divSel)
324
+ .selectAll("div.optionsContainer")
325
+ .selectAll("span.startContainer")
326
+ .selectAll("input")
327
+ .data([{cls: "startInput", type : "number"}]);
328
+ startInput.enter()
329
+ .append("input")
330
+ .attr("class", function(d) { return d.cls })
331
+ .attr("type", function(d) { return d.type })
332
+ .on("change", function(d) {
333
+ callbackStart(this, d3.event);
334
+ });
335
+ startInput.exit().remove();
336
+ self.find("div.optionsContainer > span.startContainer > input.startInput").val(startValue + 1);
337
+
338
+ var stepInput = d3.selectAll(self)
339
+ .selectAll(divSel)
340
+ .selectAll("div.optionsContainer")
341
+ .selectAll("span.stepContainer")
342
+ .selectAll("input")
343
+ .data([{cls: "stepInput", type : "number"}]);
344
+ stepInput.enter()
345
+ .append("input")
346
+ .attr("class", function(d) { return d.cls })
347
+ .attr("type", function(d) { return d.type })
348
+ .on("change", function(d) {
349
+ callbackStep(this, d3.event);
350
+ });
351
+ stepInput.exit().remove();
352
+ self.find("div.optionsContainer > span.stepContainer > input.stepInput").val(stepValue);
353
+
354
+ var nextButton = d3.selectAll(self)
355
+ .selectAll(divSel)
356
+ .selectAll("div.optionsContainer")
357
+ .selectAll("span.nextContainer")
358
+ .selectAll("button")
359
+ .data([{ label: "next" }]);
360
+ nextButton.enter()
361
+ .append("button")
362
+ .attr("class", "tchartButton ui-corner-all")
363
+ .text(function(d) { return d.label })
364
+ .on("click", function(d) {
365
+ callbackNext();
366
+ });
367
+ nextButton.exit().remove();
368
+
369
+ return prevNextContainers;
370
+ }
371
+
372
+ var _tcDrawCreateHeadTailInputs = function(self, divSel, headValue, tailValue, callbackAll, callbackHead, callbackTail) {
373
+ var headTailContainers = d3.selectAll(self)
374
+ .selectAll(divSel)
375
+ .selectAll("div.optionsContainer")
376
+ .selectAll("span")
377
+ .data([{cls: "allContainer", label: ""},
378
+ {cls: "headContainer", label: "head"},
379
+ {cls: "tailContainer", label: "tail"}]);
380
+ headTailContainers.enter()
381
+ .append("span")
382
+ .attr("class", function(d) { return d.cls })
383
+ .text(function(d) { return d.label })
384
+ headTailContainers.exit().remove();
385
+
386
+ var allButton = d3.selectAll(self)
387
+ .selectAll(divSel)
388
+ .selectAll("div.optionsContainer")
389
+ .selectAll("span.allContainer")
390
+ .selectAll("button")
391
+ .data([{ label: "all" }]);
392
+ allButton.enter()
393
+ .append("button")
394
+ .attr("class", "tchartButton ui-corner-all")
395
+ .text(function(d) { return d.label })
396
+ .on("click", function(d) {
397
+ callbackAll();
398
+ });
399
+ allButton.exit().remove();
400
+
401
+ var headInput = d3.selectAll(self)
402
+ .selectAll(divSel)
403
+ .selectAll("div.optionsContainer")
404
+ .selectAll("span.headContainer")
405
+ .selectAll("input")
406
+ .data([{cls: "headInput", type : "number"}]);
407
+ headInput.enter()
408
+ .append("input")
409
+ .attr("class", function(d) { return d.cls })
410
+ .attr("type", function(d) { return d.type })
411
+ .on("change", function(d) {
412
+ callbackHead(this, d3.event);
413
+ });
414
+ headInput.exit().remove();
415
+ self.find("div.optionsContainer > span.headContainer > input.headInput").val(headValue);
416
+
417
+ var tailInput = d3.selectAll(self)
418
+ .selectAll(divSel)
419
+ .selectAll("div.optionsContainer")
420
+ .selectAll("span.tailContainer")
421
+ .selectAll("input")
422
+ .data([{cls: "tailInput", type : "number"}]);
423
+ tailInput.enter()
424
+ .append("input")
425
+ .attr("class", function(d) { return d.cls })
426
+ .attr("type", function(d) { return d.type })
427
+ .on("change", function(d) {
428
+ callbackTail(this, d3.event);
429
+ });
430
+ tailInput.exit().remove();
431
+ self.find("div.optionsContainer > span.tailContainer > input.tailInput").val(tailValue);
432
+
433
+ return headTailContainers;
434
+ }
435
+
436
+ var _tcDrawCreateTopSvg = function(self, divSel, topSvgData) {
437
+ var topSvg = d3.selectAll(self)
438
+ .selectAll(divSel)
439
+ .selectAll("svg")
440
+ .data(topSvgData);
441
+ topSvg.attr("class", function(d) { return d.cls })
442
+ .attr("width", function(d) { return d.width })
443
+ .attr("height", function(d) { return d.height })
444
+ .attr("viewBox", function(d) { return d.viewBox });
445
+ topSvg.enter()
446
+ .append("svg")
447
+ .attr("class", function(d) { return d.cls })
448
+ .attr("width", function(d) { return d.width })
449
+ .attr("height", function(d) { return d.height })
450
+ .attr("viewBox", function(d) { return d.viewBox });
451
+ topSvg.exit().remove();
452
+ return topSvg;
453
+ }
454
+
455
+ var _tcDrawCreateSubSvgs = function(topSvg, svgSel, subSvgsData) {
456
+ var subSvgs = topSvg.selectAll(svgSel)
457
+ .data(subSvgsData)
458
+ subSvgs.attr("x", function(d) { return d.x })
459
+ .attr("y", function(d) { return d.y })
460
+ .attr("width", function(d) { return d.width })
461
+ .attr("height", function(d) { return d.height })
462
+ .attr("viewBox", function(d) { return d.viewBox });
463
+ subSvgs.enter()
464
+ .append("svg")
465
+ .attr("class", function(d) { return d.cls })
466
+ .attr("preserveAspectRatio", function(d) { return d.preserveAspectRatio})
467
+ .attr("x", function(d) { return d.x })
468
+ .attr("y", function(d) { return d.y })
469
+ .attr("width", function(d) { return d.width })
470
+ .attr("height", function(d) { return d.height })
471
+ .attr("viewBox", function(d) { return d.viewBox});
472
+ subSvgs.exit().remove();
473
+ return subSvgs;
474
+ }
475
+
476
+ var _tcDrawCreateTasksRects = function(topSvg, subSvg, rectSel, tasksRectsData, source, onTaskClick) {
477
+ var tasksRects = topSvg.selectAll(subSvg)
478
+ .selectAll(rectSel)
479
+ .data(tasksRectsData);
480
+ tasksRects.attr("x", function(d) { return d.x; })
481
+ .attr("y", function(d) { return d.y; })
482
+ .attr("width", function(d) { return d.width; })
483
+ .attr("height", function(d) { return d.height; })
484
+ .attr("fill", function(d) { return d.color; });
485
+ tasksRects.enter()
486
+ .append("rect")
487
+ .attr("x", function(d) { return d.x; })
488
+ .attr("y", function(d) { return d.y; })
489
+ .attr("rx", function(d) { return d.rx; })
490
+ .attr("ry", function(d) { return d.ry; })
491
+ .attr("width", function(d) { return d.width; })
492
+ .attr("height", function(d) { return d.height; })
493
+ .attr("class", function(d) { return d.cls; })
494
+ .attr("fill", function(d) { return d.color; })
495
+ .on("click", function(d) {
496
+ if (onTaskClick && d.taskId) {
497
+ onTaskClick(source.tasks[d.taskId].clickEventArg, this, d3.event);
498
+ }
499
+ });
500
+ tasksRects.exit().remove();
501
+ return tasksRects;
502
+ }
503
+
504
+ var _tcDrawCreateLines = function(topSvg, subSvg, lineSel, linesData) {
505
+ var lines = topSvg.selectAll(subSvg)
506
+ .selectAll(lineSel)
507
+ .data(linesData);
508
+ lines.attr("x1", function(d) { return d.x1 })
509
+ .attr("y1", function(d) { return d.y1 })
510
+ .attr("x2", function(d) { return d.x2 })
511
+ .attr("y2", function(d) { return d.y2 });
512
+ lines.enter()
513
+ .append("line")
514
+ .attr("x1", function(d) { return d.x1 })
515
+ .attr("y1", function(d) { return d.y1 })
516
+ .attr("x2", function(d) { return d.x2 })
517
+ .attr("y2", function(d) { return d.y2 })
518
+ .attr("class", function(d) { return d.cls })
519
+ lines.exit().remove();
520
+ return lines;
521
+ }
522
+
523
+ var _tcDrawCreateLabels = function(topSvg, subSvg, textSel, labelsData, fontSize) {
524
+ var labels = topSvg.selectAll(subSvg)
525
+ .selectAll(textSel)
526
+ .data(labelsData);
527
+ labels.text(function(d) {return d.label})
528
+ .attr("x", function(d) { return d.x; })
529
+ .attr("y", function(d) { return d.y; })
530
+ .style("font-size", fontSize + "px");
531
+ labels.enter()
532
+ .append("text")
533
+ .text(function(d) {return d.label})
534
+ .attr("x", function(d) { return d.x; })
535
+ .attr("y", function(d) { return d.y; })
536
+ .attr("class", function(d){ return d.cls; })
537
+ .style("font-size", fontSize + "px");
538
+ labels.exit().remove();
539
+ return labels;
540
+ }
541
+
542
+ var _tcDrawCreateAxis = function(topSvg, subSvg, axisSel, axisData, axisScales, fontSize) {
543
+ var axis = topSvg.selectAll(subSvg)
544
+ .selectAll(axisSel)
545
+ .data(axisData);
546
+ axis.attr("class", function(d){ return d.cls; })
547
+ .attr("transform", function(d) { return d.trans; });
548
+ axis.enter()
549
+ .append("g")
550
+ .attr("transform", function(d) { return d.trans; })
551
+ .attr("class", function(d){ return d.cls; });
552
+ axis.exit().remove();
553
+ for (var i = 0; i < axisScales.length; i++) {
554
+ topSvg.selectAll(subSvg)
555
+ .selectAll(axisScales[i].group)
556
+ .call(axisScales[i].scale)
557
+ .selectAll("text")
558
+ .style("font-size", fontSize + "px")
559
+ .style("text-anchor", "start");
560
+ }
561
+ return axis;
562
+ }
563
+
564
+ var _tcDrawCreateBrushRects = function(topSvg, subSvg, rectSel, brushRectsData) {
565
+ var brushRects = topSvg.selectAll(subSvg)
566
+ .selectAll(rectSel)
567
+ .data(brushRectsData);
568
+ brushRects.attr("x", function(d) { return d.x; })
569
+ .attr("y", function(d) { return d.y; })
570
+ .attr("width", function(d) { return d.width; })
571
+ .attr("height", function(d) { return d.height; })
572
+ .attr("fill", function(d) { return d.color; });
573
+ brushRects.enter()
574
+ .append("rect")
575
+ .attr("x", function(d) { return d.x; })
576
+ .attr("y", function(d) { return d.y; })
577
+ .attr("rx", function(d) { return d.rx; })
578
+ .attr("ry", function(d) { return d.ry; })
579
+ .attr("width", function(d) { return d.width; })
580
+ .attr("height", function(d) { return d.height; })
581
+ .attr("class", function(d) { return d.cls; })
582
+ .attr("fill", function(d) { return d.color; });
583
+ brushRects.exit().remove();
584
+ return brushRects;
585
+ }
586
+
587
+ var _tcDrawCreateBrush = function(topSvg, subSvg, brushSel, brushData, brushScales) {
588
+ var brush = topSvg.selectAll(subSvg)
589
+ .selectAll(brushSel)
590
+ .data(brushData)
591
+ brush.attr("class", function(d){ return d.cls; })
592
+ brush.enter()
593
+ .append("g")
594
+ .attr("class", function(d){ return d.cls; })
595
+ brush.exit().remove();
596
+ for (var i = 0; i < brushScales.length; i++) {
597
+ if (brushScales[i].type == "x") {
598
+ topSvg.selectAll(subSvg)
599
+ .selectAll(brushScales[i].group)
600
+ .call(brushScales[i].scale)
601
+ .selectAll("rect")
602
+ .attr("height", brushScales[i].height)
603
+ }
604
+ }
605
+ return brush;
606
+ }
607
+
608
+ var _tcDrawActorsSummaryBarChart = function(self, source, onTaskClick, commonData) {
609
+ if (source.actors == null || !source.settings.drawActorsSummaryBarChart) {
610
+ return;
611
+ }
612
+ // get need param
613
+ if (commonData == null) {
614
+ commonData = _tcGetCommonData(source);
615
+ }
616
+ var maxNameLen = 0;
617
+ for (actorId in source.actors) {
618
+ var len = _tcGetStringLength(source.actors[actorId].name);
619
+ if (maxNameLen < len) {
620
+ maxNameLen = len;
621
+ }
622
+ }
623
+ // create summary data
624
+ var actors = [];
625
+ var count = 0;
626
+ var tasksMax = 0;
627
+ for (actorId in source.actors) {
628
+ var actor = {
629
+ name: actorId,
630
+ color: _tcGetColor(count),
631
+ taskSize: source.actors[actorId].tasks.length,
632
+ taskId: null,
633
+ clickEventArg: null
634
+ }
635
+ if (tasksMax < source.actors[actorId].tasks.length) {
636
+ tasksMax = source.actors[actorId].tasks.length;
637
+ }
638
+ actors.push(actor);
639
+ count += 1;
640
+ }
641
+ // sort
642
+ var sortedActors = d3.values(actors).sort(function(a, b){ return d3.descending(a.taskSize, b.taskSize); });
643
+ // defines
644
+ var brushEndCb = function() {
645
+ var extent = d3.event.target.extent();
646
+ source.settings.actorsSummaryBarChart.viewRange.from = extent[0];
647
+ source.settings.actorsSummaryBarChart.viewRange.to = extent[1];
648
+ _tcDrawActorsSummaryBarChart(self, source, onTaskClick, null);
649
+ }
650
+ var fontSize = source.settings.fontSize;
651
+ var yPadding = 8;
652
+ var xOffset = ((maxNameLen * fontSize)/1.8) + fontSize + yPadding;
653
+ var axisHeight = 8 + fontSize + yPadding + fontSize + yPadding;
654
+ var yOffset = axisHeight;
655
+ var brushHeight = source.settings.brushHeight + yPadding;
656
+ var barMaxHeight = source.settings.actorsSummaryBarChart.barMaxHeight;
657
+ var canvasHeight = barMaxHeight * sortedActors.length;
658
+ var canvasWidth = source.settings.width - xOffset;
659
+ var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
660
+ var svgWidth = xOffset + canvasWidth;
661
+ var xmax = tasksMax;
662
+ var brushFromTo = _tcAdjustBlushValue(source.settings.actorsSummaryBarChart.viewRange.from,
663
+ source.settings.actorsSummaryBarChart.viewRange.to,
664
+ 0,
665
+ xmax);
666
+ var zoom = xmax / (brushFromTo[1] - brushFromTo[0]);
667
+ if ((brushFromTo[1] - brushFromTo[0]) == 0) {
668
+ zoom = 1;
669
+ }
670
+
671
+ var x = d3.scale.linear()
672
+ .domain([0, xmax])
673
+ .range([0, canvasWidth]);
674
+ var axisX = d3.scale.linear()
675
+ .domain([0, xmax])
676
+ .range([0, canvasWidth * zoom]);
677
+ var y = d3.scale.linear()
678
+ .domain([0, 1])
679
+ .range([0, barMaxHeight]);
680
+ var brushY = d3.scale.linear()
681
+ .domain([0, sortedActors.length])
682
+ .range([0, brushHeight - yPadding]);
683
+ var xAxisTop = d3.svg.axis()
684
+ .scale(axisX)
685
+ .orient("top")
686
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
687
+ .tickSize(8, 4, 2)
688
+ var xAxisBottom = d3.svg.axis()
689
+ .scale(axisX)
690
+ .orient("bottom")
691
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
692
+ .tickSize(8, 4, 2)
693
+ var xBrushScale = d3.svg.brush().x(x)
694
+ .on("brushend", brushEndCb)
695
+ .extent(_tcGetBrushExtent(source.settings.actorsSummaryBarChart.viewRange, 0, xmax));
696
+ // convert data
697
+ var topSvgData = [{cls: "actorsSummaryBarChartSvg",
698
+ width: svgWidth,
699
+ height: svgHeight,
700
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
701
+ var subSvgsData = [{cls: "actorsSummaryBarChartRectsSvg actorsSummaryBarChartSubSvg",
702
+ x: xOffset,
703
+ y: yOffset,
704
+ width: canvasWidth,
705
+ height: canvasHeight,
706
+ preserveAspectRatio: "none",
707
+ viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
708
+ {cls: "actorsSummaryBarChartAxisSvg actorsSummaryBarChartSubSvg",
709
+ x: xOffset,
710
+ y: 0,
711
+ preserveAspectRatio: "xMidYMid",
712
+ width: canvasWidth,
713
+ height: yOffset + canvasHeight + axisHeight,
714
+ viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset +canvasHeight + axisHeight) },
715
+ {cls: "actorsSummaryBarChartLinesSvg actorsSummaryBarChartSubSvg",
716
+ x: 0,
717
+ y: 0,
718
+ width: svgWidth,
719
+ height: yOffset + canvasHeight + axisHeight,
720
+ preserveAspectRatio: "xMidYMid",
721
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
722
+ {cls: "actorsSummaryBarChartLabelsSvg actorsSummaryBarChartSubSvg",
723
+ x: 0,
724
+ y: 0,
725
+ width: svgWidth,
726
+ height: yOffset + canvasHeight + axisHeight,
727
+ preserveAspectRatio: "xMidYMid",
728
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
729
+ {cls: "actorsSummaryBarChartBrushSvg actorsSummaryBarChartSubSvg",
730
+ x: xOffset,
731
+ y: yOffset + canvasHeight + axisHeight,
732
+ width: canvasWidth,
733
+ height: brushHeight,
734
+ preserveAspectRatio: "xMidYMid",
735
+ viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
736
+ var axisData = [{trans: "translate(0, " + yOffset + ")" ,
737
+ cls: "actorsSummaryBarChartXAxisTop actorsSummaryBarChartAxis",
738
+ scale: "x"},
739
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
740
+ cls: "actorsSummaryBarChartXAxisBottom actorsSummaryBarChartAxis",
741
+ scale: "x"}];
742
+ var axisScales = [{group: "g.actorsSummaryBarChartXAxisTop",
743
+ scale: xAxisTop},
744
+ {group: "g.actorsSummaryBarChartXAxisBottom",
745
+ scale: xAxisBottom}];
746
+ var brushData = [{cls:"actorsSummaryBarChartXBrush actorsSummaryBarChartBrush"}];
747
+ var brushScales = [{group: "g.actorsSummaryBarChartXBrush",
748
+ scale: xBrushScale,
749
+ type: "x",
750
+ height: brushHeight - yPadding}];
751
+ var tasksRectsData = [];
752
+ var linesData = [];
753
+ var labelsData = [];
754
+ var brushRectsData = [];
755
+ brushRectsData.push({cls:"actorsSummaryBarChartBrushBackgroundRect actorsSummaryBarChartBrushRect",
756
+ x: 0,
757
+ y: 0,
758
+ ry: 0,
759
+ ry: 0,
760
+ width: canvasWidth,
761
+ height: brushHeight - yPadding,
762
+ fill: "" });
763
+ for (var i = 0; i < sortedActors.length; i++) {
764
+ linesData.push({ x1: xOffset,
765
+ y1: y(i) + yOffset,
766
+ x2: canvasWidth + xOffset,
767
+ y2: y(i) + yOffset,
768
+ cls: "actorsSummaryBarChartLaneLine actorsSummaryBarChartLine" });
769
+ labelsData.push({ x: 0,
770
+ y: yOffset + y(i) + (barMaxHeight / 2) + (fontSize / 2),
771
+ label: sortedActors[i].name,
772
+ cls: "actorsSummaryBarChartLabel" });
773
+ tasksRectsData.push({ x: x(0),
774
+ y: y(i) + (barMaxHeight/16),
775
+ rx: 6,
776
+ ry: 6,
777
+ width: x(sortedActors[i].taskSize) - x(0),
778
+ height: barMaxHeight - ((barMaxHeight/16) * 2),
779
+ taskId: null,
780
+ color: sortedActors[i].color,
781
+ cls: "actorsSummaryBarChartTaskRect" });
782
+ brushRectsData.push({ x: x(0),
783
+ y: brushY(i),
784
+ rx: 3,
785
+ ry: 3,
786
+ width: x(sortedActors[i].taskSize) - x(0),
787
+ height: (brushHeight - yPadding) / sortedActors.length,
788
+ color: sortedActors[i].color,
789
+ cls: "actorsSummaryBarChartBrushTaskRect actorsSummaryBarChartBrushRect" });
790
+ }
791
+ linesData.push({ x1: xOffset,
792
+ y1: yOffset,
793
+ x2: xOffset,
794
+ y2: canvasHeight + yOffset,
795
+ cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
796
+ linesData.push({ x1: canvasWidth + xOffset,
797
+ y1: yOffset,
798
+ x2: canvasWidth + xOffset,
799
+ y2: canvasHeight + yOffset,
800
+ cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
801
+ linesData.push({ x1: xOffset,
802
+ y1: yOffset,
803
+ x2: canvasWidth + xOffset,
804
+ y2: yOffset,
805
+ cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
806
+ linesData.push({ x1: xOffset,
807
+ y1: canvasHeight + yOffset,
808
+ x2: canvasWidth + xOffset,
809
+ y2: canvasHeight + yOffset,
810
+ cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
811
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
812
+ y: yPadding + fontSize,
813
+ label: "(tasks)",
814
+ cls: "actorsSummaryBarChartLabel"});
815
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
816
+ y: yOffset + canvasHeight + axisHeight - yPadding,
817
+ label: "(tasks)",
818
+ cls: "actorsSummaryBarChartLabel"});
819
+ labelsData.push({ x: 0,
820
+ y: yOffset - yPadding,
821
+ label: "(actors)",
822
+ cls: "actorsSummaryBarChartLabel" });
823
+
824
+ var containers = _tcDrawCreateContainers(self,
825
+ "div.actorsSummaryBarChart",
826
+ commonData.containers);
827
+ var scrollButtons = _tcDrawCreateScrollButtons(self,
828
+ "div.actorsSummaryBarChart",
829
+ commonData.scrolls);
830
+ var summaryButtonData = [{ label: "detail" }];
831
+ var summaryButton = _tcDrawCreateSummaryButton(self,
832
+ "div.actorsSummaryBarChart",
833
+ summaryButtonData,
834
+ function() {
835
+ source.settings.drawActorsSummaryBarChart = false;
836
+ _tcDraw(self, source, onTaskClick);
837
+ });
838
+ var topSvg = _tcDrawCreateTopSvg(self,
839
+ "div.actorsSummaryBarChart",
840
+ topSvgData);
841
+ var subSvgs = _tcDrawCreateSubSvgs(topSvg,
842
+ "svg.actorsSummaryBarChartSubSvg",
843
+ subSvgsData);
844
+ var tasksRects = _tcDrawCreateTasksRects(topSvg,
845
+ "svg.actorsSummaryBarChartRectsSvg",
846
+ "actorsSummaryBarChartTaskRect",
847
+ tasksRectsData,
848
+ source,
849
+ null);
850
+ var lines = _tcDrawCreateLines(topSvg,
851
+ "svg.actorsSummaryBarChartLinesSvg",
852
+ "line.actorsSummaryBarChartLine",
853
+ linesData);
854
+ var labels = _tcDrawCreateLabels(topSvg,
855
+ "svg.actorsSummaryBarChartLabelsSvg",
856
+ "text.actorsSummaryBarChartLabel",
857
+ labelsData,
858
+ fontSize);
859
+ var axis = _tcDrawCreateAxis(topSvg,
860
+ "svg.actorsSummaryBarChartAxisSvg",
861
+ "g.actorsSummaryBarChartAxis",
862
+ axisData,
863
+ axisScales,
864
+ fontSize);
865
+ var brushRects = _tcDrawCreateBrushRects(topSvg,
866
+ "svg.actorsSummaryBarChartBrushSvg",
867
+ "rect.actorsSummaryBarChartBrushRect",
868
+ brushRectsData);
869
+ var brush = _tcDrawCreateBrush(topSvg,
870
+ "svg.actorsSummaryBarChartBrushSvg",
871
+ "g.actorsSummaryBarChartBrush",
872
+ brushData,
873
+ brushScales);
874
+ }
875
+
876
+ var _tcDrawActorsSwimlaneChart = function(self, source, onTaskClick, commonData) {
877
+ if (source.actors == null || !source.settings.drawActorsSwimlaneChart) {
878
+ return;
879
+ }
880
+ // get need param
881
+ if (commonData == null) {
882
+ commonData = _tcGetCommonData(source);
883
+ }
884
+ var maxNameLen = 0;
885
+ for (actorId in source.actors) {
886
+ var len = _tcGetStringLength(source.actors[actorId].name);
887
+ if (maxNameLen < len) {
888
+ maxNameLen = len;
889
+ }
890
+ }
891
+ // defines
892
+ var brushEndCb = function() {
893
+ var extent = d3.event.target.extent();
894
+ source.settings.actorsSwimlaneChart.viewRange.from = extent[0];
895
+ source.settings.actorsSwimlaneChart.viewRange.to = extent[1];
896
+ _tcDrawActorsSwimlaneChart(self, source, onTaskClick, null);
897
+ }
898
+ var fontSize = source.settings.fontSize;
899
+ var yPadding = 8;
900
+ var xOffset = ((maxNameLen * fontSize) / 1.8) + fontSize + yPadding;
901
+ var axisHeight = 8 + ((fontSize + yPadding) * 2) + fontSize;
902
+ var yOffset = axisHeight;
903
+ var brushHeight = source.settings.brushHeight + yPadding;
904
+ var barMaxHeight = source.settings.actorsSwimlaneChart.barMaxHeight;
905
+ var canvasHeight = barMaxHeight * commonData.tasks.length;
906
+ var canvasWidth = source.settings.width - xOffset;
907
+ var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
908
+ var svgWidth = xOffset + canvasWidth;
909
+ var xmax = commonData.toMax;
910
+ var startTime = source.settings.startTime;
911
+ if (startTime == null) {
912
+ startTime = commonData.fromMin;
913
+ }
914
+ var brushFromTo = _tcAdjustBlushValue(source.settings.actorsSwimlaneChart.viewRange.from,
915
+ source.settings.actorsSwimlaneChart.viewRange.to,
916
+ startTime,
917
+ xmax);
918
+ var zoom = (xmax - startTime) / (brushFromTo[1] - brushFromTo[0]);
919
+ if ((brushFromTo[1] - brushFromTo[0]) == 0) {
920
+ zoom = 1;
921
+ }
922
+ var x = d3.scale.linear()
923
+ .domain([startTime, xmax])
924
+ .range([0, canvasWidth]);
925
+ var axisX = d3.scale.linear()
926
+ .domain([startTime, xmax])
927
+ .range([0, canvasWidth * zoom]);
928
+ var axisXRel = d3.scale.linear()
929
+ .domain([0, xmax - startTime])
930
+ .range([0, canvasWidth * zoom]);
931
+ var y = d3.scale.linear()
932
+ .domain([0, 1])
933
+ .range([0, barMaxHeight]);
934
+ var brushY = d3.scale.linear()
935
+ .domain([0, commonData.tasks.length])
936
+ .range([0, brushHeight - yPadding]);
937
+ var xAxisTop = d3.svg.axis()
938
+ .scale(axisX)
939
+ .orient("top")
940
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
941
+ .tickSize(8, 4, 2)
942
+ .tickPadding(fontSize + 3)
943
+ .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
944
+ var xRelAxisTop = d3.svg.axis()
945
+ .scale(axisXRel)
946
+ .orient("top")
947
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
948
+ .tickSize(8, 4, 2)
949
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
950
+ var xAxisBottom = d3.svg.axis()
951
+ .scale(axisX)
952
+ .orient("bottom")
953
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
954
+ .tickSize(8, 4, 2)
955
+ .tickPadding(fontSize + 3)
956
+ .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
957
+ var xRelAxisBottom = d3.svg.axis()
958
+ .scale(axisXRel)
959
+ .orient("bottom")
960
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
961
+ .tickSize(8, 4, 2)
962
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
963
+ var xBrushScale = d3.svg.brush().x(x)
964
+ .on("brushend", brushEndCb)
965
+ .extent(_tcGetBrushExtent(source.settings.actorsSwimlaneChart.viewRange, startTime, xmax));
966
+ // convert data
967
+ var topSvgData = [{cls: "actorsSwimlaneChartSvg",
968
+ width: svgWidth,
969
+ height: svgHeight,
970
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
971
+ var subSvgsData = [{cls: "actorsSwimlaneChartRectsSvg actorsSwimlaneChartSubSvg",
972
+ x: xOffset,
973
+ y: yOffset,
974
+ width: canvasWidth,
975
+ height: canvasHeight,
976
+ preserveAspectRatio: "none",
977
+ viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
978
+ {cls: "actorsSwimlaneChartAxisSvg actorsSwimlaneChartSubSvg",
979
+ x: xOffset,
980
+ y: 0,
981
+ preserveAspectRatio: "xMidYMid",
982
+ width: canvasWidth,
983
+ height: yOffset + canvasHeight + axisHeight,
984
+ viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset + canvasHeight + axisHeight) },
985
+ {cls: "actorsSwimlaneChartLinesSvg actorsSwimlaneChartSubSvg",
986
+ x: 0,
987
+ y: 0,
988
+ width: svgWidth,
989
+ height: yOffset + canvasHeight + axisHeight,
990
+ preserveAspectRatio: "xMidYMid",
991
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
992
+ {cls: "actorsSwimlaneChartLabelsSvg actorsSwimlaneChartSubSvg",
993
+ x: 0,
994
+ y: 0,
995
+ width: svgWidth,
996
+ height: yOffset + canvasHeight + axisHeight,
997
+ preserveAspectRatio: "xMidYMid",
998
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
999
+ {cls: "actorsSwimlaneChartBrushSvg actorsSwimlaneChartSubSvg",
1000
+ x: xOffset,
1001
+ y: yOffset + canvasHeight + axisHeight,
1002
+ width: canvasWidth,
1003
+ height: brushHeight,
1004
+ preserveAspectRatio: "xMidYMid",
1005
+ viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
1006
+ var axisData = [{trans: "translate(0, " + yOffset + ")" ,
1007
+ cls: "actorsSwimlaneChartXAxisTop actorsSwimlaneChartAxis",
1008
+ scale: "x"},
1009
+ {trans: "translate(0, " + yOffset + ")" ,
1010
+ cls: "actorsSwimlaneChartXRelAxisTop actorsSwimlaneChartRelAxis",
1011
+ scale: "x"},
1012
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
1013
+ cls: "actorsSwimlaneChartXAxisBottom actorsSwimlaneChartAxis",
1014
+ scale: "x"},
1015
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
1016
+ cls: "actorsSwimlaneChartXRelAxisBottom actorsSwimlaneChartRelAxis",
1017
+ scale: "x"}];
1018
+ var axisScales = [{group: "g.actorsSwimlaneChartXAxisTop",
1019
+ scale: xAxisTop},
1020
+ {group: "g.actorsSwimlaneChartXRelAxisTop",
1021
+ scale: xRelAxisTop},
1022
+ {group: "g.actorsSwimlaneChartXAxisBottom",
1023
+ scale: xAxisBottom},
1024
+ {group: "g.actorsSwimlaneChartXRelAxisBottom",
1025
+ scale: xRelAxisBottom}];
1026
+ var brushData = [{cls:"actorsSwimlaneChartXBrush actorsSwimlaneChartBrush"}];
1027
+ var brushScales = [{group: "g.actorsSwimlaneChartXBrush",
1028
+ scale: xBrushScale,
1029
+ type: "x",
1030
+ height: brushHeight - yPadding}];
1031
+ var tasksRectsData = [];
1032
+ var linesData = [];
1033
+ var labelsData = [];
1034
+ var brushRectsData = [];
1035
+ var totalTaskCount = 0;
1036
+ brushRectsData.push({cls:"actorsSwimlaneChartBrushBackgroundRect actorsSwimlaneChartBrushRect",
1037
+ x: 0,
1038
+ y: 0,
1039
+ ry: 0,
1040
+ ry: 0,
1041
+ width: canvasWidth,
1042
+ height: brushHeight - yPadding,
1043
+ fill: "" });
1044
+ for (actorId in source.actors) {
1045
+ var laneMaxHeight = barMaxHeight * source.actors[actorId].tasks.length;
1046
+ linesData.push({ x1: xOffset,
1047
+ y1: y(totalTaskCount) + yOffset,
1048
+ x2: canvasWidth + xOffset,
1049
+ y2: y(totalTaskCount) + yOffset,
1050
+ cls: "actorsSwimlaneChartLaneLine actorsSwimlaneChartLine" });
1051
+ labelsData.push({ x: 0,
1052
+ y: yOffset + y(totalTaskCount) + (laneMaxHeight / 2) + (fontSize / 2),
1053
+ label: source.actors[actorId].name,
1054
+ cls: "actorsSwimlaneChartLabel" });
1055
+ for (var j = 0; j < source.actors[actorId].tasks.length; j++) {
1056
+ var task = source.tasks[source.actors[actorId].tasks[j]];
1057
+ tasksRectsData.push({ x: x(task.from),
1058
+ y: y(totalTaskCount) + (barMaxHeight/16),
1059
+ rx: 6,
1060
+ ry: 6,
1061
+ width: x(task.to) - x(task.from),
1062
+ height: barMaxHeight - ((barMaxHeight/16) * 2),
1063
+ taskId: source.actors[actorId].tasks[j],
1064
+ color: task.color,
1065
+ cls: "actorsSwimlaneChartTaskRect" });
1066
+ brushRectsData.push({ x: x(task.from),
1067
+ y: brushY(totalTaskCount),
1068
+ rx: 3,
1069
+ ry: 3,
1070
+ width: x(task.to) - x(task.from),
1071
+ height: (brushHeight - yPadding) / commonData.tasks.length,
1072
+ color: task.color,
1073
+ cls: "actorsSwimlaneChartBrushTaskRect actorsSwimlaneChartBrushRect" });
1074
+ totalTaskCount += 1;
1075
+ }
1076
+ }
1077
+ linesData.push({ x1: xOffset,
1078
+ y1: yOffset,
1079
+ x2: xOffset,
1080
+ y2: canvasHeight + yOffset,
1081
+ cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
1082
+ linesData.push({ x1: canvasWidth + xOffset,
1083
+ y1: yOffset,
1084
+ x2: canvasWidth + xOffset,
1085
+ y2: canvasHeight + yOffset,
1086
+ cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
1087
+ linesData.push({ x1: xOffset,
1088
+ y1: yOffset,
1089
+ x2: canvasWidth + xOffset,
1090
+ y2: yOffset,
1091
+ cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
1092
+ linesData.push({ x1: xOffset,
1093
+ y1: canvasHeight + yOffset,
1094
+ x2: canvasWidth + xOffset,
1095
+ y2: canvasHeight + yOffset,
1096
+ cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
1097
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1098
+ y: yPadding + fontSize,
1099
+ label: "(time)",
1100
+ cls: "actorsSwimlaneChartLabel"});
1101
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1102
+ y: yOffset + canvasHeight + axisHeight - yPadding,
1103
+ label: "(time)",
1104
+ cls: "actorsSwimlaneChartLabel"});
1105
+ labelsData.push({ x: 0,
1106
+ y: yOffset - yPadding,
1107
+ label: "(actors)",
1108
+ cls: "actorsSwimlaneChartLabel" });
1109
+
1110
+ var containers = _tcDrawCreateContainers(self,
1111
+ "div.actorsSwimlaneChart",
1112
+ commonData.containers);
1113
+ var scrollButtons = _tcDrawCreateScrollButtons(self,
1114
+ "div.actorsSwimlaneChart",
1115
+ commonData.scrolls);
1116
+ var summaryButtonData = [{ label: "summary",
1117
+ cls: "tchartSummaryButton ui-corner-all"}];
1118
+ var summaryButton = _tcDrawCreateSummaryButton(self,
1119
+ "div.actorsSwimlaneChart",
1120
+ summaryButtonData,
1121
+ function() {
1122
+ source.settings.drawActorsSummaryBarChart = true;
1123
+ _tcDraw(self, source, onTaskClick);
1124
+ });
1125
+ var topSvg = _tcDrawCreateTopSvg(self,
1126
+ "div.actorsSwimlaneChart",
1127
+ topSvgData);
1128
+ var subSvgs = _tcDrawCreateSubSvgs(topSvg,
1129
+ "svg.actorsSwimlaneChartSubSvg",
1130
+ subSvgsData);
1131
+ var tasksRects = _tcDrawCreateTasksRects(topSvg,
1132
+ "svg.actorsSwimlaneChartRectsSvg",
1133
+ "actorsSwimlaneChartTaskRect",
1134
+ tasksRectsData,
1135
+ source,
1136
+ onTaskClick);
1137
+ var lines = _tcDrawCreateLines(topSvg,
1138
+ "svg.actorsSwimlaneChartLinesSvg",
1139
+ "line.actorsSwimlaneChartLine",
1140
+ linesData);
1141
+ var labels = _tcDrawCreateLabels(topSvg,
1142
+ "svg.actorsSwimlaneChartLabelsSvg",
1143
+ "text.actorsSwimlaneChartLabel",
1144
+ labelsData,
1145
+ fontSize);
1146
+ var axis = _tcDrawCreateAxis(topSvg,
1147
+ "svg.actorsSwimlaneChartAxisSvg",
1148
+ "g.actorsSwimlaneChartAxis",
1149
+ axisData,
1150
+ axisScales,
1151
+ fontSize);
1152
+ var brushRects = _tcDrawCreateBrushRects(topSvg,
1153
+ "svg.actorsSwimlaneChartBrushSvg",
1154
+ "rect.actorsSwimlaneChartBrushRect",
1155
+ brushRectsData);
1156
+ var brush = _tcDrawCreateBrush(topSvg,
1157
+ "svg.actorsSwimlaneChartBrushSvg",
1158
+ "g.actorsSwimlaneChartBrush",
1159
+ brushData,
1160
+ brushScales);
1161
+ }
1162
+
1163
+ var _tcDrawTasksGanttChart = function(self, source, onTaskClick, commonData) {
1164
+ if (!source.settings.drawTasksGanttChart) {
1165
+ return;
1166
+ }
1167
+ // get need param
1168
+ if (commonData == null) {
1169
+ commonData = _tcGetCommonData(source);
1170
+ }
1171
+ var maxNameLen = 0;
1172
+ for (var i = 0; i < commonData.tasks.length; i++) {
1173
+ var len = _tcGetStringLength(commonData.tasks[i].name);
1174
+ if (maxNameLen < len) {
1175
+ maxNameLen = len;
1176
+ }
1177
+ }
1178
+ // sort
1179
+ var sortedTasks = d3.values(commonData.tasks).sort(function(a, b){ return d3.ascending(a.from, b.from); });
1180
+ var start = source.settings.tasksGanttChart.start;
1181
+ var end = start + source.settings.tasksGanttChart.step;
1182
+ if (start > sortedTasks.length - 1) {
1183
+ start = 0;
1184
+ }
1185
+ if (end > sortedTasks.length) {
1186
+ end = sortedTasks.length;
1187
+ }
1188
+ sortedTasks = sortedTasks.slice(start, end);
1189
+ // defines
1190
+ var brushEndCb = function() {
1191
+ var extent = d3.event.target.extent();
1192
+ source.settings.tasksGanttChart.viewRange.from = extent[0];
1193
+ source.settings.tasksGanttChart.viewRange.to = extent[1];
1194
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1195
+ }
1196
+
1197
+ var fontSize = source.settings.fontSize;
1198
+ var yPadding = 8;
1199
+ var xOffset = ((maxNameLen * fontSize) / 1.8) + fontSize + yPadding;
1200
+ var axisHeight = 8 + ((fontSize + yPadding) * 2) + fontSize;
1201
+ var yOffset = axisHeight
1202
+ var brushHeight = source.settings.brushHeight + yPadding;
1203
+ var barMaxHeight = source.settings.tasksGanttChart.barMaxHeight;
1204
+ var laneMaxHeight = source.settings.tasksGanttChart.laneMaxHeight;
1205
+ var canvasHeight = laneMaxHeight * sortedTasks.length;
1206
+ var canvasWidth = source.settings.width - xOffset;
1207
+ var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
1208
+ var svgWidth = xOffset + canvasWidth;
1209
+ var xmax = commonData.toMax;
1210
+ var startTime = source.settings.startTime;
1211
+ if (startTime == null) {
1212
+ startTime = commonData.fromMin;
1213
+ }
1214
+ var brushFromTo = _tcAdjustBlushValue(source.settings.tasksGanttChart.viewRange.from,
1215
+ source.settings.tasksGanttChart.viewRange.to,
1216
+ startTime,
1217
+ xmax);
1218
+ var zoom = (xmax - startTime) / (brushFromTo[1] - brushFromTo[0]);
1219
+ if ((brushFromTo[1] - brushFromTo[0]) == 0) {
1220
+ zoom = 1;
1221
+ }
1222
+ var x = d3.scale.linear()
1223
+ .domain([startTime, xmax])
1224
+ .range([0, canvasWidth]);
1225
+ var axisX = d3.scale.linear()
1226
+ .domain([startTime, xmax])
1227
+ .range([0, canvasWidth * zoom]);
1228
+ var axisXRel = d3.scale.linear()
1229
+ .domain([0, xmax - startTime])
1230
+ .range([0, canvasWidth * zoom]);
1231
+ var y = d3.scale.linear()
1232
+ .domain([0, 1])
1233
+ .range([0, laneMaxHeight]);
1234
+ var brushY = d3.scale.linear()
1235
+ .domain([0, sortedTasks.length])
1236
+ .range([0, brushHeight - yPadding]);
1237
+ var xAxisTop = d3.svg.axis()
1238
+ .scale(axisX)
1239
+ .orient("top")
1240
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1241
+ .tickSize(8, 4, 2)
1242
+ .tickPadding(fontSize + 3)
1243
+ .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
1244
+ var xRelAxisTop = d3.svg.axis()
1245
+ .scale(axisXRel)
1246
+ .orient("top")
1247
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1248
+ .tickSize(8, 4, 2)
1249
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
1250
+ var xAxisBottom = d3.svg.axis()
1251
+ .scale(axisX)
1252
+ .orient("bottom")
1253
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1254
+ .tickSize(8, 4, 2)
1255
+ .tickPadding(fontSize + 3)
1256
+ .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
1257
+ var xRelAxisBottom = d3.svg.axis()
1258
+ .scale(axisXRel)
1259
+ .orient("bottom")
1260
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1261
+ .tickSize(8, 4, 2)
1262
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
1263
+ var xBrushScale = d3.svg.brush().x(x)
1264
+ .on("brushend", brushEndCb)
1265
+ .extent(_tcGetBrushExtent(source.settings.tasksGanttChart.viewRange, startTime, xmax));
1266
+ // convert data
1267
+ var topSvgData = [{cls: "tasksGanttChartSvg",
1268
+ width: svgWidth,
1269
+ height: svgHeight,
1270
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
1271
+ var subSvgsData = [{cls: "tasksGanttChartRectsSvg tasksGanttChartSubSvg",
1272
+ x: xOffset,
1273
+ y: yOffset,
1274
+ width: canvasWidth,
1275
+ height: canvasHeight,
1276
+ preserveAspectRatio: "none",
1277
+ viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
1278
+ {cls: "tasksGanttChartAxisSvg tasksGanttChartSubSvg",
1279
+ x: xOffset,
1280
+ y: 0,
1281
+ preserveAspectRatio: "xMidYMid",
1282
+ width: canvasWidth,
1283
+ height: yOffset + canvasHeight + axisHeight,
1284
+ viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset + canvasHeight + axisHeight) },
1285
+ {cls: "tasksGanttChartLinesSvg tasksGanttChartSubSvg",
1286
+ x: 0,
1287
+ y: 0,
1288
+ width: svgWidth,
1289
+ height: yOffset + canvasHeight + axisHeight,
1290
+ preserveAspectRatio: "xMidYMid",
1291
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
1292
+ {cls: "tasksGanttChartLabelsSvg tasksGanttChartSubSvg",
1293
+ x: 0,
1294
+ y: 0,
1295
+ width: svgWidth,
1296
+ height: yOffset + canvasHeight + axisHeight,
1297
+ preserveAspectRatio: "xMidYMid",
1298
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
1299
+ {cls: "tasksGanttChartBrushSvg tasksGanttChartSubSvg",
1300
+ x: xOffset,
1301
+ y: yOffset + canvasHeight + axisHeight,
1302
+ width: canvasWidth,
1303
+ height: brushHeight,
1304
+ preserveAspectRatio: "xMidYMid",
1305
+ viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
1306
+ var axisData = [{trans: "translate(0, " + (yOffset) + ")" ,
1307
+ cls: "tasksGanttChartXAxisTop tasksGanttChartAxis",
1308
+ scale: "x"},
1309
+ {trans: "translate(0, " + (yOffset) + ")" ,
1310
+ cls: "tasksGanttChartXRelAxisTop tasksGanttChartRelAxis",
1311
+ scale: "x"},
1312
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
1313
+ cls: "tasksGanttChartXAxisBottom tasksGanttChartAxis",
1314
+ scale: "x"},
1315
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
1316
+ cls: "tasksGanttChartXRelAxisBottom tasksGanttChartRelAxis",
1317
+ scale: "x"}];
1318
+ var axisScales = [{group: "g.tasksGanttChartXAxisTop",
1319
+ scale: xAxisTop},
1320
+ {group: "g.tasksGanttChartXRelAxisTop",
1321
+ scale: xRelAxisTop},
1322
+ {group: "g.tasksGanttChartXAxisBottom",
1323
+ scale: xAxisBottom},
1324
+ {group: "g.tasksGanttChartXRelAxisBottom",
1325
+ scale: xRelAxisBottom}];
1326
+ var brushData = [{cls:"tasksGanttChartXBrush tasksGanttChartBrush"}];
1327
+ var brushScales = [{group: "g.tasksGanttChartXBrush",
1328
+ scale: xBrushScale,
1329
+ type: "x",
1330
+ height: brushHeight - yPadding}];
1331
+ var tasksRectsData = [];
1332
+ var linesData = [];
1333
+ var labelsData = [];
1334
+ var brushRectsData = [];
1335
+ brushRectsData.push({cls:"tasksGanttChartBrushBackgroundRect tasksGanttChartBrushRect",
1336
+ x: 0,
1337
+ y: 0,
1338
+ ry: 0,
1339
+ ry: 0,
1340
+ width: canvasWidth,
1341
+ height: brushHeight - yPadding,
1342
+ fill: "" });
1343
+ for (var i = 0; i < sortedTasks.length; i++) {
1344
+ linesData.push({ x1: xOffset,
1345
+ y1: y(i) + yOffset,
1346
+ x2: canvasWidth + xOffset,
1347
+ y2: y(i) + yOffset,
1348
+ cls: "tasksGanttChartLaneLine tasksGanttChartLine" });
1349
+ labelsData.push({ x: 0,
1350
+ y: yOffset + y(i) + (laneMaxHeight / 2) + (fontSize / 2),
1351
+ label: sortedTasks[i].name,
1352
+ cls: "tasksGanttChartLabel" });
1353
+ tasksRectsData.push({ x: x(sortedTasks[i].from),
1354
+ y: y(i) + ((laneMaxHeight - barMaxHeight) / 2),
1355
+ rx: 6,
1356
+ ry: 6,
1357
+ width: x(sortedTasks[i].to) - x(sortedTasks[i].from),
1358
+ height: barMaxHeight - ((barMaxHeight/16) * 2),
1359
+ taskId: sortedTasks[i].taskId,
1360
+ color: sortedTasks[i].color,
1361
+ cls: "tasksGanttChartTaskRect" });
1362
+ brushRectsData.push({ x: x(sortedTasks[i].from),
1363
+ y: brushY(i),
1364
+ rx: 3,
1365
+ ry: 3,
1366
+ width: x(sortedTasks[i].to) - x(sortedTasks[i].from),
1367
+ height: (brushHeight - yPadding) / sortedTasks.length,
1368
+ color: sortedTasks[i].color,
1369
+ cls: "tasksGanttChartBrushTaskRect tasksGanttChartBrushRect" });
1370
+ }
1371
+ linesData.push({ x1: xOffset,
1372
+ y1: yOffset,
1373
+ x2: xOffset,
1374
+ y2: canvasHeight + yOffset,
1375
+ cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
1376
+ linesData.push({ x1: canvasWidth + xOffset,
1377
+ y1: yOffset,
1378
+ x2: canvasWidth + xOffset,
1379
+ y2: canvasHeight + yOffset,
1380
+ cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
1381
+ linesData.push({ x1: xOffset,
1382
+ y1: yOffset,
1383
+ x2: canvasWidth + xOffset,
1384
+ y2: yOffset,
1385
+ cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
1386
+ linesData.push({ x1: xOffset,
1387
+ y1: canvasHeight + yOffset,
1388
+ x2: canvasWidth + xOffset,
1389
+ y2: canvasHeight + yOffset,
1390
+ cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
1391
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1392
+ y: yPadding + fontSize,
1393
+ label: "(time)",
1394
+ cls: "tasksGanttChartLabel"});
1395
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1396
+ y: yOffset + canvasHeight + axisHeight - yPadding,
1397
+ label: "(time)",
1398
+ cls: "tasksGanttChartLabel"});
1399
+ labelsData.push({ x: 0,
1400
+ y: yOffset - yPadding,
1401
+ label: "(tasks)",
1402
+ cls: "tasksGanttChartLabel" });
1403
+
1404
+ var containers = _tcDrawCreateContainers(self,
1405
+ "div.tasksGanttChart",
1406
+ commonData.containers);
1407
+ var scrollButtons = _tcDrawCreateScrollButtons(self,
1408
+ "div.tasksGanttChart",
1409
+ commonData.scrolls);
1410
+ var prevNextInputs = _tcDrawCreatePrevNextInputs(self,
1411
+ "div.tasksGanttChart",
1412
+ source.settings.tasksGanttChart.start,
1413
+ source.settings.tasksGanttChart.step,
1414
+ function() {
1415
+ source.settings.tasksGanttChart.start = 0;
1416
+ source.settings.tasksGanttChart.step = commonData.tasks.length;
1417
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1418
+ },
1419
+ function() {
1420
+ source.settings.tasksGanttChart.start -= source.settings.tasksGanttChart.step;
1421
+ if (source.settings.tasksGanttChart.start < 0) {
1422
+ source.settings.tasksGanttChart.start = 0;
1423
+ }
1424
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1425
+ },
1426
+ function(target, event) {
1427
+ var start = parseInt(event.target.value) - 1;
1428
+ if (typeof start === "number" && !isNaN(start) && start >= 0) {
1429
+ source.settings.tasksGanttChart.start = start;
1430
+ }
1431
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1432
+ },
1433
+ function(target, event) {
1434
+ var step = parseInt(event.target.value);
1435
+ if (typeof step === "number" && !isNaN(step) && step >= 0) {
1436
+ source.settings.tasksGanttChart.step = step;
1437
+ }
1438
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1439
+ },
1440
+ function() {
1441
+ if (source.settings.tasksGanttChart.start + source.settings.tasksGanttChart.step <= commonData.tasks.length - 1) {
1442
+ source.settings.tasksGanttChart.start += source.settings.tasksGanttChart.step;
1443
+ }
1444
+ _tcDrawTasksGanttChart(self, source, onTaskClick, null);
1445
+ });
1446
+ var topSvg = _tcDrawCreateTopSvg(self,
1447
+ "div.tasksGanttChart",
1448
+ topSvgData);
1449
+ var subSvgs = _tcDrawCreateSubSvgs(topSvg,
1450
+ "svg.tasksGanttChartSubSvg",
1451
+ subSvgsData);
1452
+ var tasksRects = _tcDrawCreateTasksRects(topSvg,
1453
+ "svg.tasksGanttChartRectsSvg",
1454
+ "tasksGanttChartTaskRect",
1455
+ tasksRectsData,
1456
+ source,
1457
+ onTaskClick);
1458
+ var lines = _tcDrawCreateLines(topSvg,
1459
+ "svg.tasksGanttChartLinesSvg",
1460
+ "line.tasksGanttChartLine",
1461
+ linesData);
1462
+ var labels = _tcDrawCreateLabels(topSvg,
1463
+ "svg.tasksGanttChartLabelsSvg",
1464
+ "text.tasksGanttChartLabel",
1465
+ labelsData,
1466
+ fontSize);
1467
+ var axis = _tcDrawCreateAxis(topSvg,
1468
+ "svg.tasksGanttChartAxisSvg",
1469
+ "g.tasksGanttChartAxis",
1470
+ axisData,
1471
+ axisScales,
1472
+ fontSize);
1473
+ var brushRects = _tcDrawCreateBrushRects(topSvg,
1474
+ "svg.tasksGanttChartBrushSvg",
1475
+ "rect.tasksGanttChartBrushRect",
1476
+ brushRectsData);
1477
+ var brush = _tcDrawCreateBrush(topSvg,
1478
+ "svg.tasksGanttChartBrushSvg",
1479
+ "g.tasksGanttChartBrush",
1480
+ brushData,
1481
+ brushScales);
1482
+ }
1483
+
1484
+ var _tcDrawTasksBarChart = function(self, source, onTaskClick, commonData) {
1485
+ if (!source.settings.drawTasksBarChart) {
1486
+ return;
1487
+ }
1488
+ // get need param
1489
+ if (commonData == null) {
1490
+ commonData = _tcGetCommonData(source);
1491
+ }
1492
+ var maxNameLen = 0;
1493
+ for (var i = 0; i < commonData.tasks.length; i++) {
1494
+ var len = _tcGetStringLength(commonData.tasks[i].name);
1495
+ if (maxNameLen < len) {
1496
+ maxNameLen = len;
1497
+ }
1498
+ }
1499
+ // sort
1500
+ var sortedTasks = d3.values(commonData.tasks).sort(function(a, b){ return d3.descending(a.elapse, b.elapse); });
1501
+ var head = source.settings.tasksBarChart.head;
1502
+ var tail = source.settings.tasksBarChart.tail;
1503
+ var snipdot = {
1504
+ taskId: null,
1505
+ name: " .",
1506
+ elapse: 0,
1507
+ taskId: null,
1508
+ clickEventArg: null,
1509
+ color: "#000000"
1510
+ };
1511
+ var snip = {
1512
+ taskId: null,
1513
+ name: "(snip)",
1514
+ elapse: 0,
1515
+ taskId: null,
1516
+ clickEventArg: null,
1517
+ color: "#000000"
1518
+ };
1519
+ if (sortedTasks.length > head + tail) {
1520
+ sortedTasks.splice(head, sortedTasks.length - (head + tail), snipdot, snipdot, snipdot, snip, snipdot, snipdot, snipdot);
1521
+ }
1522
+ // defines
1523
+ var brushEndCb = function() {
1524
+ var extent = d3.event.target.extent();
1525
+ source.settings.tasksBarChart.viewRange.from = extent[0];
1526
+ source.settings.tasksBarChart.viewRange.to = extent[1];
1527
+ _tcDrawTasksBarChart(self, source, onTaskClick, null);
1528
+ }
1529
+ var fontSize = source.settings.fontSize;
1530
+ var yPadding = 8;
1531
+ var xOffset = ((maxNameLen * fontSize)/1.8) + fontSize + yPadding;
1532
+ var axisHeight = 8 + fontSize + yPadding + fontSize + yPadding;
1533
+ var yOffset = axisHeight;
1534
+ var brushHeight = source.settings.brushHeight + yPadding;
1535
+ var barMaxHeight = source.settings.tasksBarChart.barMaxHeight;
1536
+ var canvasHeight = barMaxHeight * sortedTasks.length;
1537
+ var canvasWidth = source.settings.width - xOffset;
1538
+ var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
1539
+ var svgWidth = xOffset + canvasWidth;
1540
+ var xmax = commonData.elapseMax
1541
+ var brushFromTo = _tcAdjustBlushValue(source.settings.tasksBarChart.viewRange.from,
1542
+ source.settings.tasksBarChart.viewRange.to,
1543
+ 0,
1544
+ xmax);
1545
+ var zoom = xmax / (brushFromTo[1] - brushFromTo[0]);
1546
+ if ((brushFromTo[1] - brushFromTo[0]) == 0) {
1547
+ zoom = 1;
1548
+ }
1549
+
1550
+ var x = d3.scale.linear()
1551
+ .domain([0, xmax])
1552
+ .range([0, canvasWidth]);
1553
+ var axisX = d3.scale.linear()
1554
+ .domain([0, xmax])
1555
+ .range([0, canvasWidth * zoom]);
1556
+ var y = d3.scale.linear()
1557
+ .domain([0, 1])
1558
+ .range([0, barMaxHeight]);
1559
+ var brushY = d3.scale.linear()
1560
+ .domain([0, sortedTasks.length])
1561
+ .range([0, brushHeight - yPadding]);
1562
+ var xAxisTop = d3.svg.axis()
1563
+ .scale(axisX)
1564
+ .orient("top")
1565
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1566
+ .tickSize(8, 4, 2)
1567
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
1568
+ var xAxisBottom = d3.svg.axis()
1569
+ .scale(axisX)
1570
+ .orient("bottom")
1571
+ .ticks((canvasWidth / commonData.tickWidth) * zoom)
1572
+ .tickSize(8, 4, 2)
1573
+ .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
1574
+ var xBrushScale = d3.svg.brush().x(x)
1575
+ .on("brushend", brushEndCb)
1576
+ .extent(_tcGetBrushExtent(source.settings.tasksBarChart.viewRange, 0, xmax));
1577
+ // convert data
1578
+ var topSvgData = [{cls: "tasksBarChartSvg",
1579
+ width: svgWidth,
1580
+ height: svgHeight,
1581
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
1582
+ var subSvgsData = [{cls: "tasksBarChartRectsSvg tasksBarChartSubSvg",
1583
+ x: xOffset,
1584
+ y: yOffset,
1585
+ width: canvasWidth,
1586
+ height: canvasHeight,
1587
+ preserveAspectRatio: "none",
1588
+ viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
1589
+ {cls: "tasksBarChartAxisSvg tasksBarChartSubSvg",
1590
+ x: xOffset,
1591
+ y: 0,
1592
+ preserveAspectRatio: "xMidYMid",
1593
+ width: canvasWidth,
1594
+ height: yOffset + canvasHeight + axisHeight,
1595
+ viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset +canvasHeight + axisHeight) },
1596
+ {cls: "tasksBarChartLinesSvg tasksBarChartSubSvg",
1597
+ x: 0,
1598
+ y: 0,
1599
+ width: svgWidth,
1600
+ height: yOffset + canvasHeight + axisHeight,
1601
+ preserveAspectRatio: "xMidYMid",
1602
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
1603
+ {cls: "tasksBarChartLabelsSvg tasksBarChartSubSvg",
1604
+ x: 0,
1605
+ y: 0,
1606
+ width: svgWidth,
1607
+ height: yOffset + canvasHeight + axisHeight,
1608
+ preserveAspectRatio: "xMidYMid",
1609
+ viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
1610
+ {cls: "tasksBarChartBrushSvg tasksBarChartSubSvg",
1611
+ x: xOffset,
1612
+ y: yOffset + canvasHeight + axisHeight,
1613
+ width: canvasWidth,
1614
+ height: brushHeight,
1615
+ preserveAspectRatio: "xMidYMid",
1616
+ viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
1617
+ var axisData = [{trans: "translate(0, " + yOffset + ")" ,
1618
+ cls: "tasksBarChartXAxisTop tasksBarChartAxis",
1619
+ scale: "x"},
1620
+ {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
1621
+ cls: "tasksBarChartXAxisBottom tasksBarChartAxis",
1622
+ scale: "x"}];
1623
+ var axisScales = [{group: "g.tasksBarChartXAxisTop",
1624
+ scale: xAxisTop},
1625
+ {group: "g.tasksBarChartXAxisBottom",
1626
+ scale: xAxisBottom}];
1627
+ var brushData = [{cls:"tasksBarChartXBrush tasksBarChartBrush"}];
1628
+ var brushScales = [{group: "g.tasksBarChartXBrush",
1629
+ scale: xBrushScale,
1630
+ type: "x",
1631
+ height: brushHeight - yPadding}];
1632
+ var tasksRectsData = [];
1633
+ var linesData = [];
1634
+ var labelsData = [];
1635
+ var brushRectsData = [];
1636
+ brushRectsData.push({cls:"tasksBarChartBrushBackgroundRect tasksBarChartBrushRect",
1637
+ x: 0,
1638
+ y: 0,
1639
+ ry: 0,
1640
+ ry: 0,
1641
+ width: canvasWidth,
1642
+ height: brushHeight - yPadding,
1643
+ fill: "" });
1644
+ for (var i = 0; i < sortedTasks.length; i++) {
1645
+ linesData.push({ x1: xOffset,
1646
+ y1: y(i) + yOffset,
1647
+ x2: canvasWidth + xOffset,
1648
+ y2: y(i) + yOffset,
1649
+ cls: "tasksBarChartLaneLine tasksBarChartLine" });
1650
+ labelsData.push({ x: 0,
1651
+ y: yOffset + y(i) + (barMaxHeight / 2) + (fontSize / 2),
1652
+ label: sortedTasks[i].name,
1653
+ cls: "tasksBarChartLabel" });
1654
+ tasksRectsData.push({ x: x(0),
1655
+ y: y(i) + (barMaxHeight/16),
1656
+ rx: 6,
1657
+ ry: 6,
1658
+ width: x(sortedTasks[i].elapse) - x(0),
1659
+ height: barMaxHeight - ((barMaxHeight/16) * 2),
1660
+ taskId: sortedTasks[i].taskId,
1661
+ color: sortedTasks[i].color,
1662
+ cls: "tasksBarChartTaskRect" });
1663
+ brushRectsData.push({ x: x(0),
1664
+ y: brushY(i),
1665
+ rx: 3,
1666
+ ry: 3,
1667
+ width: x(sortedTasks[i].elapse) - x(0),
1668
+ height: (brushHeight - yPadding) / sortedTasks.length,
1669
+ color: sortedTasks[i].color,
1670
+ cls: "tasksBarChartBrushTaskRect tasksBarChartBrushRect" });
1671
+ }
1672
+ linesData.push({ x1: xOffset,
1673
+ y1: yOffset,
1674
+ x2: xOffset,
1675
+ y2: canvasHeight + yOffset,
1676
+ cls: "tasksBarChartCanvasLine tasksBarChartLine" });
1677
+ linesData.push({ x1: canvasWidth + xOffset,
1678
+ y1: yOffset,
1679
+ x2: canvasWidth + xOffset,
1680
+ y2: canvasHeight + yOffset,
1681
+ cls: "tasksBarChartCanvasLine tasksBarChartLine" });
1682
+ linesData.push({ x1: xOffset,
1683
+ y1: yOffset,
1684
+ x2: canvasWidth + xOffset,
1685
+ y2: yOffset,
1686
+ cls: "tasksBarChartCanvasLine tasksBarChartLine" });
1687
+ linesData.push({ x1: xOffset,
1688
+ y1: canvasHeight + yOffset,
1689
+ x2: canvasWidth + xOffset,
1690
+ y2: canvasHeight + yOffset,
1691
+ cls: "tasksBarChartCanvasLine tasksBarChartLine" });
1692
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1693
+ y: yPadding + fontSize,
1694
+ label: "(time)",
1695
+ cls: "tasksBarChartLabel"});
1696
+ labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
1697
+ y: yOffset + canvasHeight + axisHeight - yPadding,
1698
+ label: "(time)",
1699
+ cls: "tasksBarChartLabel"});
1700
+ labelsData.push({ x: 0,
1701
+ y: yOffset - yPadding,
1702
+ label: "(tasks)",
1703
+ cls: "tasksBarChartLabel" });
1704
+
1705
+ var containers = _tcDrawCreateContainers(self,
1706
+ "div.tasksBarChart",
1707
+ commonData.containers);
1708
+ var scrollButtons = _tcDrawCreateScrollButtons(self,
1709
+ "div.tasksBarChart",
1710
+ commonData.scrolls);
1711
+ var headTailInputs = _tcDrawCreateHeadTailInputs(self,
1712
+ "div.tasksBarChart",
1713
+ source.settings.tasksBarChart.head,
1714
+ source.settings.tasksBarChart.tail,
1715
+ function() {
1716
+ source.settings.tasksBarChart.head = commonData.tasks.length;
1717
+ source.settings.tasksBarChart.tail = 0;
1718
+ _tcDrawTasksBarChart(self, source, onTaskClick, null);
1719
+ },
1720
+ function(target, event) {
1721
+ var head = parseInt(event.target.value);
1722
+ if (typeof head === "number" && !isNaN(head) && head >= 0) {
1723
+ source.settings.tasksBarChart.head = head;
1724
+ }
1725
+ _tcDrawTasksBarChart(self, source, onTaskClick, null);
1726
+ },
1727
+ function(target, event) {
1728
+ var tail = parseInt(event.target.value);
1729
+ if (typeof tail === "number" && !isNaN(tail) && tail >= 0) {
1730
+ source.settings.tasksBarChart.tail = tail;
1731
+ }
1732
+ _tcDrawTasksBarChart(self, source, onTaskClick, null);
1733
+ });
1734
+ var topSvg = _tcDrawCreateTopSvg(self,
1735
+ "div.tasksBarChart",
1736
+ topSvgData);
1737
+ var subSvgs = _tcDrawCreateSubSvgs(topSvg,
1738
+ "svg.tasksBarChartSubSvg",
1739
+ subSvgsData);
1740
+ var tasksRects = _tcDrawCreateTasksRects(topSvg,
1741
+ "svg.tasksBarChartRectsSvg",
1742
+ "tasksBarChartTaskRect",
1743
+ tasksRectsData,
1744
+ source,
1745
+ onTaskClick);
1746
+ var lines = _tcDrawCreateLines(topSvg,
1747
+ "svg.tasksBarChartLinesSvg",
1748
+ "line.tasksBarChartLine",
1749
+ linesData);
1750
+ var labels = _tcDrawCreateLabels(topSvg,
1751
+ "svg.tasksBarChartLabelsSvg",
1752
+ "text.tasksBarChartLabel",
1753
+ labelsData,
1754
+ fontSize);
1755
+ var axis = _tcDrawCreateAxis(topSvg,
1756
+ "svg.tasksBarChartAxisSvg",
1757
+ "g.tasksBarChartAxis",
1758
+ axisData,
1759
+ axisScales,
1760
+ fontSize);
1761
+ var brushRects = _tcDrawCreateBrushRects(topSvg,
1762
+ "svg.tasksBarChartBrushSvg",
1763
+ "rect.tasksBarChartBrushRect",
1764
+ brushRectsData);
1765
+ var brush = _tcDrawCreateBrush(topSvg,
1766
+ "svg.tasksBarChartBrushSvg",
1767
+ "g.tasksBarChartBrush",
1768
+ brushData,
1769
+ brushScales);
1770
+ }
1771
+
1772
+ var _tcDraw = function(self, source, onTaskClick) {
1773
+ if (source.tasks == null) {
1774
+ return;
1775
+ }
1776
+
1777
+ // getCommonData
1778
+ var commonData = _tcGetCommonData(source);
1779
+
1780
+ // check tasks
1781
+ if (commonData.tasks.length == 0) {
1782
+ return;
1783
+ }
1784
+
1785
+ // datepicket Containers
1786
+ var datePickerContainers = d3.selectAll(self)
1787
+ .selectAll("span.datePickerContainer")
1788
+ .data(commonData.datePickerContainersData);
1789
+ datePickerContainers.enter()
1790
+ .append("span")
1791
+ .text(function (d) { return d.label})
1792
+ .attr("class", function(d) { return d.cls })
1793
+ datePickerContainers.exit().remove();
1794
+
1795
+ // datePickers
1796
+ for (var i = 0; i < commonData.datePickersData.length; i++) {
1797
+ var datePicker = d3.selectAll(self)
1798
+ .selectAll(commonData.datePickersData[i].span)
1799
+ .selectAll("input")
1800
+ .data(commonData.datePickersData[i].data)
1801
+ datePicker.enter()
1802
+ .append("input")
1803
+ .attr("type", "text")
1804
+ .attr("class", function(d) { return d.cls });
1805
+ datePicker.exit().remove()
1806
+ }
1807
+ var startDatePicker = $(".startDatePicker").datepicker({ onSelect: function() {
1808
+ source.settings.startDate = Date.parse($(this).val());
1809
+ _tcDraw(self, source, onTaskClick);
1810
+ }});
1811
+ var startDate = new Date(source.settings.startDate);
1812
+ startDatePicker.datepicker("option", "dateFormat", "yy-mm-dd")
1813
+ startDatePicker.datepicker("option", "minDate", new Date(commonData.startDateMin))
1814
+ startDatePicker.datepicker("option", "maxDate", new Date(commonData.endDateMax))
1815
+ startDatePicker.val(startDate.getFullYear() + "-" + _tcTFPad((startDate.getMonth() + 1), 2) + "-" + _tcTFPad(startDate.getDate(), 2))
1816
+
1817
+ var endDatePicker = $(".endDatePicker").datepicker({ onSelect: function() {
1818
+ source.settings.endDate = Date.parse($(this).val());
1819
+ _tcDraw(self, source, onTaskClick);
1820
+ }});
1821
+ var endDate = new Date(source.settings.endDate);
1822
+ endDatePicker.datepicker("option", "dateFormat", "yy-mm-dd")
1823
+ endDatePicker.datepicker("option", "minDate", new Date(commonData.startDateMin))
1824
+ endDatePicker.datepicker("option", "maxDate", new Date(commonData.endDateMax))
1825
+ endDatePicker.val(endDate.getFullYear() + "-" + _tcTFPad((endDate.getMonth() + 1), 2) + "-" + _tcTFPad(endDate.getDate(), 2))
1826
+
1827
+ // create svg divs
1828
+ var containers = []
1829
+ if (source.actors != null) {
1830
+ if (source.settings.drawActorsSummaryBarChart) {
1831
+ containers.push("actorsSummaryBarChart chartContainer");
1832
+ } else if (source.settings.drawActorsSwimlaneChart){
1833
+ containers.push("actorsSwimlaneChart chartContainer");
1834
+ }
1835
+ }
1836
+ containers.push("tasksGanttChart chartContainer");
1837
+ containers.push("tasksBarChart chartContainer");
1838
+
1839
+ var topDivs = d3.selectAll(self)
1840
+ .selectAll("div.chartContainer")
1841
+ .data(containers)
1842
+ topDivs.attr("class", function(d) { return d });
1843
+ topDivs.enter()
1844
+ .append("div")
1845
+ .attr("class", function(d) { return d });
1846
+ topDivs.exit().remove();
1847
+
1848
+ // draw charts
1849
+ if (source.actors != null) {
1850
+ if (source.settings.drawActorsSummaryBarChart) {
1851
+ _tcDrawActorsSummaryBarChart(self, source, onTaskClick, commonData);
1852
+ } else if (source.settings.drawActorsSwimlaneChart) {
1853
+ _tcDrawActorsSwimlaneChart(self, source, onTaskClick, commonData);
1854
+ }
1855
+ }
1856
+ _tcDrawTasksGanttChart(self, source, onTaskClick, commonData);
1857
+ _tcDrawTasksBarChart(self, source, onTaskClick, commonData);
1858
+ };
1859
+
1860
+ var _tcRemove = function(self, data) {
1861
+ d3.selectAll(self).selectAll("div")
1862
+ .data([])
1863
+ .exit()
1864
+ .remove();
1865
+ };
1866
+
1867
+ var _tcDataUpdate = function(data, source) {
1868
+ source.settings.startDate = null;
1869
+ if ("settings" in source) {
1870
+ $.extend(true, data.source.settings, source.settings);
1871
+ }
1872
+ if ("actors" in source) {
1873
+ data.source.actors = source.actors;
1874
+ }
1875
+ if ("tasks" in source) {
1876
+ data.source.tasks = source.tasks;
1877
+ }
1878
+ }
1879
+
1880
+ var _tcAjax = function(self, data) {
1881
+ $.ajax(data.ajaxParams).done(function(source) {
1882
+ _tcDataUpdate(data, source);
1883
+ _tcDraw(self, data.source, data.onTaskClick);
1884
+ })
1885
+ }
1886
+
1887
+ var _tcAjaxTimer = function(self, data) {
1888
+ if (data.ajaxPending) {
1889
+ if (data.ajaxTimerId != null) {
1890
+ clearInterval(data.ajaxTimerId);
1891
+ data.ajaxTimerId = null;
1892
+ }
1893
+ } else {
1894
+ if (data.ajaxTimerId == null) {
1895
+ data.ajaxTimerId = setInterval(function(){_tcAjax(self, data)();}, data.ajaxInterval);
1896
+ }
1897
+ _tcAjax(self, data);
1898
+ }
1899
+ }
1900
+
1901
+ var _tcDrawPrepare = function(self, data) {
1902
+ if (data.source.actors || data.source.tasks) {
1903
+ _tcDraw(self, data.source, data.onTaskClick);
1904
+ } else if (data.ajax != null && typeof data.ajax == "object" && typeof data.ajaxInterval == "number") {
1905
+ _tcAjaxTimer(self, data)
1906
+ } else if (data.ajax != null && typeof data.ajax == "object") {
1907
+ _tcAjax(self, data);
1908
+ }
1909
+ }
1910
+
1911
+ var _tcRemovePrepare = function(self, data) {
1912
+ if (data.ajaxTimerId != null) {
1913
+ clearInterval(data.ajaxTimerId);
1914
+ data.ajaxTimerId = null;
1915
+ }
1916
+ _tcRemove(self, data.source);
1917
+ }
1918
+
1919
+ var tchart = {
1920
+ init: function(options) {
1921
+ var data = this.data('tchart');
1922
+ if (!data) {
1923
+ this.data('tchart',
1924
+ $.extend(true, {
1925
+ ajaxTimerId: null,
1926
+ ajaxParams: null,
1927
+ ajaxInterval: null,
1928
+ ajaxPending: false,
1929
+ onTaskClick: null,
1930
+ source: {
1931
+ settings : {
1932
+ drawActorsSummaryBarChart: true,
1933
+ drawActorsSwimlaneChart: true,
1934
+ drawTasksGanttChart: true,
1935
+ drawTasksBarChart: true,
1936
+ fontSize: 12,
1937
+ width: 500,
1938
+ actorsSummaryBarChart : {
1939
+ label: "actors summary bar chart",
1940
+ barMaxHeight: 16,
1941
+ viewRange: {
1942
+ from: null,
1943
+ to: null
1944
+ }
1945
+ },
1946
+ actorsSwimlaneChart : {
1947
+ label: "actors swimlane chart",
1948
+ barMaxHeight:14,
1949
+ viewRange: {
1950
+ from: null,
1951
+ to: null
1952
+ }
1953
+ },
1954
+ tasksGanttChart : {
1955
+ start: 0,
1956
+ step: 50,
1957
+ label: "tasks gantt chart",
1958
+ barMaxHeight: 14,
1959
+ laneMaxHeight:16,
1960
+ viewRange: {
1961
+ from: null,
1962
+ to: null
1963
+ }
1964
+ },
1965
+ tasksBarChart : {
1966
+ head: 20,
1967
+ tail: 20,
1968
+ label: "tasks bar chart",
1969
+ barMaxHeight: 16,
1970
+ viewRange: {
1971
+ from: null,
1972
+ to: null
1973
+ }
1974
+ },
1975
+ startTime: null,
1976
+ brushHeight: 30,
1977
+ startDate: null,
1978
+ endDate: null
1979
+ },
1980
+ actors: null,
1981
+ tasks: null
1982
+ },
1983
+ }, options));
1984
+ data = this.data('tchart');
1985
+ }
1986
+ _tcDrawPrepare(this, data);
1987
+ return this;
1988
+ },
1989
+ update: function(source) {
1990
+ var data = this.data('tchart');
1991
+ if (!data) {
1992
+ return this;
1993
+ }
1994
+ _tcDataUpdate(data, source);
1995
+ _tcDraw(this, data.source, data.onTaskClick);
1996
+ return this;
1997
+ },
1998
+ remove: function() {
1999
+ var data = this.data('tchart');
2000
+ if (!data) {
2001
+ return this;
2002
+ }
2003
+ _tcRemovePrepare(this, data.source);
2004
+ return this;
2005
+ },
2006
+ pendingAjax: function(source) {
2007
+ var data = this.data('tchart');
2008
+ if (!data) {
2009
+ return this;
2010
+ }
2011
+ data.ajaxPending = true;
2012
+ _tcAjaxTimer(this, data);
2013
+ return this;
2014
+ },
2015
+ resumeAjax: function(source) {
2016
+ var data = this.data('tchart');
2017
+ if (!data) {
2018
+ return this;
2019
+ }
2020
+ data.ajaxResume = true;
2021
+ _tcAjaxTimer(this, data);
2022
+ return this;
2023
+ }
2024
+ }
2025
+
2026
+ $.fn.tchart = function(method) {
2027
+ if (tchart[method]) {
2028
+ return tchart[method].apply(this, Array.prototype.slice.call(arguments, 1));
2029
+ } else if (typeof method === 'object' || !method) {
2030
+ return tchart.init.apply(this, arguments);
2031
+ } else {
2032
+ $.error('Method ' + method + ' does not exist on jQuery.tchart');
2033
+ }
2034
+ return this;
2035
+ }
2036
+ })(jQuery);
2037
+
2038
+ //////////////////////////////////////////////////////////////////////////
2039
+ //
2040
+ // * initizlize
2041
+ //
2042
+ // usage:
2043
+ // $(target).tchart([options])
2044
+ //
2045
+ // option:
2046
+ // ajaxParams: jquery ajax param
2047
+ // ajaxInterval: ajax polling interval [ Number (milliseconds) ]
2048
+ // onTaskClick: task click event callback [ function ]
2049
+ //
2050
+ // * remove chart
2051
+ //
2052
+ // usage:
2053
+ // $(target).tchart("remove")
2054
+ //
2055
+ // * update chart
2056
+ //
2057
+ // usage:
2058
+ // $(target).tchart("update", source)
2059
+ //
2060
+ // source:
2061
+ // {
2062
+ // settings: {
2063
+ // drawActorsSummaryBarChart: boolean,
2064
+ // drawActorsSwimlaneChart: boolane,
2065
+ // drawTasksGanttChart: boolane,
2066
+ // drawTasksBarChart: boolane,
2067
+ // fontSize: Number,
2068
+ // width: Number,
2069
+ // actorsSwimlaneChart : {
2070
+ // barMaxHeight: Number
2071
+ // },
2072
+ // tasksGanttChart : {
2073
+ // barMaxHeight: Number,
2074
+ // laneMaxHeight: Number
2075
+ // },
2076
+ // tasksBarChart : {
2077
+ // barMaxHeight: Number,
2078
+ // },
2079
+ // startTime: Number (millisecond) or null,
2080
+ // brushHeight: Number
2081
+ // },
2082
+ // actors : {
2083
+ // actorId1 : {
2084
+ // name: string,
2085
+ // tasks : [
2086
+ // taskId1
2087
+ // ]
2088
+ // },
2089
+ // actorId2 : {
2090
+ // name: string,
2091
+ // tasks : [
2092
+ // taskId2
2093
+ // ]
2094
+ // }
2095
+ // },
2096
+ // tasks : {
2097
+ // task_Id1: {
2098
+ // name: string,
2099
+ // from: number (millisec time),
2100
+ // to: number (millisec time),
2101
+ // clickEventArg: object,
2102
+ // nextTasks : [
2103
+ // taskId2
2104
+ // ]
2105
+ // },
2106
+ // task_Id2: {
2107
+ // name: string,
2108
+ // from: number (millisec time),
2109
+ // to: number (millisec time),
2110
+ // clickEventArg: object,
2111
+ // nextTasks : null
2112
+ // }
2113
+ // }
2114
+ // }
2115
+ //
2116
+ // * pending ajax polling
2117
+ //
2118
+ // usage:
2119
+ // $(target).tchart("pendingAjax")
2120
+ //
2121
+ // * resume ajax polling
2122
+ //
2123
+ // usage:
2124
+ // $(target).tchart("resumeAjax")
2125
+ //