pmux-logview 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/Makefile +18 -0
- data/README.md +113 -0
- data/Rakefile +4 -0
- data/bin/pmux-logview +4 -0
- data/conf/config.ru +15 -0
- data/conf/password +5 -0
- data/conf/pmux-logview.conf +12 -0
- data/lib/pmux-logview.rb +11 -0
- data/lib/pmux-logview/application.rb +69 -0
- data/lib/pmux-logview/auth_helper.rb +60 -0
- data/lib/pmux-logview/controller.rb +141 -0
- data/lib/pmux-logview/log_parser.rb +368 -0
- data/lib/pmux-logview/logger_wrapper.rb +129 -0
- data/lib/pmux-logview/model.rb +21 -0
- data/lib/pmux-logview/static/css/images/animated-overlay.gif +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_diagonals-thick_90_eeeeee_40x40.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_flat_15_cd0a0a_40x100.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_glass_100_e4f1fb_1x400.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_glass_50_3baae3_1x400.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_glass_80_d7ebf9_1x400.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_highlight-hard_100_f2f5f7_1x100.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_highlight-hard_70_000000_1x100.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_highlight-soft_100_deedf7_1x100.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-bg_highlight-soft_25_ffef8f_1x100.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-icons_2694e8_256x240.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-icons_3d80b3_256x240.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-icons_72a7cf_256x240.png +0 -0
- data/lib/pmux-logview/static/css/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/pmux-logview/static/css/jquery-ui-1.10.0.css +1186 -0
- data/lib/pmux-logview/static/css/jquery.dataTables.css +221 -0
- data/lib/pmux-logview/static/css/normalize.css +396 -0
- data/lib/pmux-logview/static/css/pmux-logview.css +161 -0
- data/lib/pmux-logview/static/css/tchart.css +124 -0
- data/lib/pmux-logview/static/font/7TssRTXcaLr8beqDiv5lkQ.woff +0 -0
- data/lib/pmux-logview/static/images/back_disabled.png +0 -0
- data/lib/pmux-logview/static/images/back_enabled.png +0 -0
- data/lib/pmux-logview/static/images/back_enabled_hover.png +0 -0
- data/lib/pmux-logview/static/images/forward_disabled.png +0 -0
- data/lib/pmux-logview/static/images/forward_enabled.png +0 -0
- data/lib/pmux-logview/static/images/forward_enabled_hover.png +0 -0
- data/lib/pmux-logview/static/images/sort_asc.png +0 -0
- data/lib/pmux-logview/static/images/sort_asc_disabled.png +0 -0
- data/lib/pmux-logview/static/images/sort_both.png +0 -0
- data/lib/pmux-logview/static/images/sort_desc.png +0 -0
- data/lib/pmux-logview/static/images/sort_desc_disabled.png +0 -0
- data/lib/pmux-logview/static/js/d3.v3.min.js +4 -0
- data/lib/pmux-logview/static/js/jquery-1.9.1.js +9597 -0
- data/lib/pmux-logview/static/js/jquery-ui-1.10.0.js +14883 -0
- data/lib/pmux-logview/static/js/jquery.activity-indicator-1.0.0.min.js +10 -0
- data/lib/pmux-logview/static/js/jquery.dataTables.min.js +157 -0
- data/lib/pmux-logview/static/js/pmux-logview-base.js +102 -0
- data/lib/pmux-logview/static/js/pmux-logview-detail.js +181 -0
- data/lib/pmux-logview/static/js/pmux-logview-index.js +324 -0
- data/lib/pmux-logview/static/js/tchart.js +2125 -0
- data/lib/pmux-logview/version.rb +5 -0
- data/lib/pmux-logview/views/detail.erb +58 -0
- data/lib/pmux-logview/views/index.erb +97 -0
- data/pmux-logview.gemspec +27 -0
- data/rpm/Makefile +20 -0
- data/rpm/pmux-logview +111 -0
- data/rpm/pmux-logview.spec +65 -0
- 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
|
+
//
|