pmux-logview 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ //