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