| 5 |
lars |
1 |
/**
|
|
|
2 |
*
|
|
|
3 |
* JQuery fn.gantt gantt chart plugin v0.2
|
|
|
4 |
* Copyright 2011 by Marek Bielańczuk
|
|
|
5 |
* http://mbielanczuk.com/
|
|
|
6 |
* Released under the MIT and GPL Licenses.
|
|
|
7 |
*
|
|
|
8 |
* Date: Tue Jun 21 00:18:16 +0200 2011
|
|
|
9 |
*/
|
|
|
10 |
|
|
|
11 |
jQuery.fn.gantt = function (options) {
|
|
|
12 |
var defaults = {
|
|
|
13 |
source: null,
|
|
|
14 |
itemsPerPage: 7,
|
|
|
15 |
months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"],
|
|
|
16 |
dow: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
|
|
|
17 |
startPos: new Date()
|
|
|
18 |
};
|
|
|
19 |
var options = jQuery.extend(defaults, options);
|
|
|
20 |
var data = null; // Recived data
|
|
|
21 |
var pageNum = 0; // Current page number
|
|
|
22 |
var pageCount = 0; // Aviable pages count
|
|
|
23 |
var rowsOnLastPage = 0; // How many rows on last page
|
|
|
24 |
var rowsNum = 0; //
|
|
|
25 |
var hPosition = 0; // Current position on diagram (Horizontal)
|
|
|
26 |
var dateStart = null;
|
|
|
27 |
var dateEnd = null;
|
|
|
28 |
|
|
|
29 |
var create = function(jQuerythis) {
|
|
|
30 |
if (!options.source)
|
|
|
31 |
return;
|
|
|
32 |
|
|
|
33 |
jQuery.getJSON(options.source, function(rData) {
|
|
|
34 |
data = rData;
|
|
|
35 |
rowsNum = data.length;
|
|
|
36 |
pageCount = Math.ceil(rowsNum/options.itemsPerPage);
|
|
|
37 |
rowsOnLastPage = rowsNum - (Math.floor(rowsNum/options.itemsPerPage) * options.itemsPerPage);
|
|
|
38 |
|
|
|
39 |
dateStart = tools.getMinDate();
|
|
|
40 |
dateEnd = tools.getMaxDate();
|
|
|
41 |
|
|
|
42 |
var contTable = createContainer();
|
|
|
43 |
jQuerythis.append(contTable);
|
|
|
44 |
fillHollydays();
|
|
|
45 |
fillData();
|
|
|
46 |
jQuerythis.css({
|
|
|
47 |
height: jQuery(".fn-gantt").height() + "px"
|
|
|
48 |
});
|
|
|
49 |
jQuery('.fn-gantt .dataPanel').css({'margin-left': hPosition+'px'});
|
|
|
50 |
|
|
|
51 |
var d = Math.round((options.startPos/1000 - dateStart/1000) / 86400 )-2;
|
|
|
52 |
if (d > 0)
|
|
|
53 |
{
|
|
|
54 |
navigateTo(-1*d * tools.getCellSize());
|
|
|
55 |
} else {
|
|
|
56 |
repositionLabel();
|
|
|
57 |
}
|
|
|
58 |
});
|
|
|
59 |
|
|
|
60 |
var createContainer = function() {
|
|
|
61 |
/* Left panel */
|
|
|
62 |
var ganttLeftPanel = jQuery('<div class="leftPanel"/>')
|
|
|
63 |
.append(jQuery('<div class="row spacer"/>')
|
|
|
64 |
.css("height", tools.getCellSize()*4+"px")
|
|
|
65 |
.css("width", "100%"));
|
|
|
66 |
jQuery.each(data, function(i, entry) {
|
|
|
67 |
if (i >= pageNum*options.itemsPerPage && i < (pageNum*options.itemsPerPage+options.itemsPerPage))
|
|
|
68 |
{
|
|
|
69 |
ganttLeftPanel
|
|
|
70 |
.append(jQuery('<div class="row name"/>').append(jQuery('<span class="label"/>').html(entry.name)))
|
|
|
71 |
.append(jQuery('<div class="row desc"/>').append(jQuery('<span class="label"/>').html(entry.desc)));
|
|
|
72 |
}
|
|
|
73 |
});
|
|
|
74 |
|
|
|
75 |
/* Navigation panel */
|
|
|
76 |
var ganttNavigate = jQuery('<div class="navigate" />')
|
|
|
77 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-page-back"/>')
|
|
|
78 |
.html('<')
|
|
|
79 |
.click( function () {
|
|
|
80 |
navigatePage(-1);
|
|
|
81 |
}))
|
|
|
82 |
.append(jQuery('<div class="page-number"/>')
|
|
|
83 |
.append(jQuery('<span/>')
|
|
|
84 |
.html(pageNum+1 + ' of ' + pageCount)))
|
|
|
85 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-page-next"/>')
|
|
|
86 |
.html('>')
|
|
|
87 |
.click( function () {
|
|
|
88 |
navigatePage(1);
|
|
|
89 |
}))
|
|
|
90 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-begin"/>')
|
|
|
91 |
.html('|<')
|
|
|
92 |
.click( function () {
|
|
|
93 |
navigateTo('begin');
|
|
|
94 |
}))
|
|
|
95 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-prev-week"/>')
|
|
|
96 |
.html('<<')
|
|
|
97 |
.click( function () {
|
|
|
98 |
navigateTo(tools.getCellSize()*7);
|
|
|
99 |
}))
|
|
|
100 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-prev-day"/>')
|
|
|
101 |
.html('<')
|
|
|
102 |
.click( function () {
|
|
|
103 |
navigateTo(tools.getCellSize());
|
|
|
104 |
}))
|
|
|
105 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-next-day"/>')
|
|
|
106 |
.html('>')
|
|
|
107 |
.click( function () {
|
|
|
108 |
navigateTo(tools.getCellSize() * -1);
|
|
|
109 |
}))
|
|
|
110 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-next-week"/>')
|
|
|
111 |
.html('>>')
|
|
|
112 |
.click( function () {
|
|
|
113 |
navigateTo(tools.getCellSize() * -7);
|
|
|
114 |
}))
|
|
|
115 |
.append(jQuery('<a href="javascript:///" class="nav-link nav-end"/>')
|
|
|
116 |
.html('>|')
|
|
|
117 |
.click( function () {
|
|
|
118 |
navigateTo('end');
|
|
|
119 |
}));
|
|
|
120 |
|
|
|
121 |
/* Container */
|
|
|
122 |
var gantt = jQuery('<div class="fn-gantt" />');
|
|
|
123 |
gantt
|
|
|
124 |
.append(
|
|
|
125 |
jQuery('<div class="fn-content"/>')
|
|
|
126 |
.append(ganttLeftPanel)
|
|
|
127 |
.append(
|
|
|
128 |
jQuery('<div class="rightPanel"/>')
|
|
|
129 |
.append(createDataContainer())
|
|
|
130 |
))
|
|
|
131 |
.append(jQuery('<div class="bottom"/>')
|
|
|
132 |
.append(ganttNavigate));
|
|
|
133 |
|
|
|
134 |
return gantt;
|
|
|
135 |
};
|
|
|
136 |
|
|
|
137 |
// Creates Data container with header
|
|
|
138 |
var createDataContainer = function() {
|
|
|
139 |
var range = tools.parseDateRange(dateStart, dateEnd);
|
|
|
140 |
|
|
|
141 |
var years = jQuery("<div class='row'/>");
|
|
|
142 |
var year = range[0].getFullYear();
|
|
|
143 |
var daysInYear = 0;
|
|
|
144 |
|
|
|
145 |
var months = jQuery("<div class='row'/>");
|
|
|
146 |
var month = range[0].getMonth();
|
|
|
147 |
var daysInMonth = 0;
|
|
|
148 |
|
|
|
149 |
var days = jQuery('<div class="row"/>');
|
|
|
150 |
var dow = jQuery('<div class="row"/>');
|
|
|
151 |
|
|
|
152 |
var today = new Date();
|
|
|
153 |
today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
|
154 |
|
|
|
155 |
jQuery.each(range, function(i, rday) {
|
|
|
156 |
if (rday.getFullYear() != year) {
|
|
|
157 |
years.append(jQuery('<div class="row header year"/>')
|
|
|
158 |
.css("width", tools.getCellSize()*daysInYear + "px")
|
|
|
159 |
.append(jQuery("<div class='label'/>").html(year)));
|
|
|
160 |
year = rday.getFullYear();
|
|
|
161 |
daysInYear = 0;
|
|
|
162 |
}
|
|
|
163 |
daysInYear++;
|
|
|
164 |
|
|
|
165 |
if (rday.getMonth() != month) {
|
|
|
166 |
months.append(jQuery('<div class="row header month"/>')
|
|
|
167 |
.css("width", tools.getCellSize()*daysInMonth + "px")
|
|
|
168 |
.append(jQuery("<div class='label'/>").html(options.months[month])));
|
|
|
169 |
month = rday.getMonth();
|
|
|
170 |
daysInMonth = 0;
|
|
|
171 |
}
|
|
|
172 |
daysInMonth++;
|
|
|
173 |
var day_class = (today - rday == 0) ? ' today' : (options.hollydays && options.hollydays.join().indexOf(rday.getTime())>-1) ? "hollyday" : rday.getDay() == 6 ? "sa" : (rday.getDay() == 0 ? "sn" : "wd");
|
|
|
174 |
days.append(jQuery('<div class="row day '+day_class+'" />').html(rday.getDate()));
|
|
|
175 |
dow.append(jQuery('<div class="row day '+day_class+'" />').html( options.dow[rday.getDay()] ));
|
|
|
176 |
|
|
|
177 |
});
|
|
|
178 |
|
|
|
179 |
years.append(jQuery('<div class="row header year"/>')
|
|
|
180 |
.css("width", tools.getCellSize()*daysInYear + "px")
|
|
|
181 |
.append(jQuery("<div class='label'/>").html(year)));
|
|
|
182 |
|
|
|
183 |
months.append(jQuery('<div class="row header month"/>')
|
|
|
184 |
.css("width", tools.getCellSize()*daysInMonth + "px")
|
|
|
185 |
.append(jQuery("<div class='label'/>").html(options.months[month])));
|
|
|
186 |
|
|
|
187 |
var dataPanel = jQuery("<div class='dataPanel'/>").css("width", range.length*tools.getCellSize()+"px");
|
|
|
188 |
dataPanel.append(years);
|
|
|
189 |
dataPanel.append(months);
|
|
|
190 |
dataPanel.append(days);
|
|
|
191 |
dataPanel.append(dow);
|
|
|
192 |
|
|
|
193 |
jQuery.each(data, function(i, entry) {
|
|
|
194 |
if (i >= pageNum*options.itemsPerPage && i < (pageNum*options.itemsPerPage+options.itemsPerPage))
|
|
|
195 |
{
|
|
|
196 |
var dRow = jQuery('<div class="row">');
|
|
|
197 |
jQuery.each(range, function(j, day) {
|
|
|
198 |
var todayCls = (today - day == 0) ? ' today' : day.getDay() == 6 ? ' sa' : (day.getDay() == 0 ? ' sn' : '');
|
|
|
199 |
dRow.append(jQuery('<div class="row day' + todayCls + '" id="d'+i+'-'+ tools.genId(day.getTime())+'" />')
|
|
|
200 |
.html(day));
|
|
|
201 |
});
|
|
|
202 |
dataPanel.append(dRow);
|
|
|
203 |
}
|
|
|
204 |
});
|
|
|
205 |
|
|
|
206 |
return dataPanel;
|
|
|
207 |
};
|
|
|
208 |
|
|
|
209 |
createProgressBar = function(days, cls, desc) {
|
|
|
210 |
var cellWidth = tools.getCellSize();
|
|
|
211 |
var barMarg = tools.getProgressBarMargin() || 0;
|
|
|
212 |
var bar = jQuery("<div class='bar' />")
|
|
|
213 |
.addClass( cls )
|
|
|
214 |
.css({
|
|
|
215 |
width: ((cellWidth * ++days) - barMarg)
|
|
|
216 |
});
|
|
|
217 |
if (desc)
|
|
|
218 |
{
|
|
|
219 |
bar
|
|
|
220 |
.mouseover(function(e){
|
|
|
221 |
var hint = jQuery("<div class='fn-gantt-hint' />").html(desc);
|
|
|
222 |
jQuery("body").append(hint);
|
|
|
223 |
hint.css('left', e.pageX);
|
|
|
224 |
hint.css('top', e.pageY);
|
|
|
225 |
hint.show();
|
|
|
226 |
})
|
|
|
227 |
.mouseout(function(){
|
|
|
228 |
jQuery(".fn-gantt-hint").remove();
|
|
|
229 |
})
|
|
|
230 |
.mousemove(function(e){
|
|
|
231 |
jQuery('.fn-gantt-hint').css('left', e.pageX);
|
|
|
232 |
jQuery('.fn-gantt-hint').css('top', e.pageY+15);
|
|
|
233 |
});
|
|
|
234 |
}
|
|
|
235 |
return bar;
|
|
|
236 |
};
|
|
|
237 |
|
|
|
238 |
var fillHollydays = function() {
|
|
|
239 |
if (options.hollydays)
|
|
|
240 |
{
|
|
|
241 |
jQuery.each(data, function(i, entry) {
|
|
|
242 |
jQuery.each(options.hollydays, function(j, hollyday) {
|
|
|
243 |
jQuery('#d'+i+'-'+ tools.genId(tools.dateDeserialize(hollyday).getTime()))
|
|
|
244 |
.addClass("hollyday");
|
|
|
245 |
});
|
|
|
246 |
});
|
|
|
247 |
}
|
|
|
248 |
};
|
|
|
249 |
|
|
|
250 |
var fillData = function() {
|
|
|
251 |
jQuery.each(data, function(i, entry) {
|
|
|
252 |
if (i >= pageNum * options.itemsPerPage && i < (pageNum*options.itemsPerPage+options.itemsPerPage))
|
|
|
253 |
{
|
|
|
254 |
jQuery.each(entry.values, function(j, day) {
|
|
|
255 |
var _bar = createProgressBar(
|
|
|
256 |
Math.floor(((Date.parse(tools.dateDeserialize(day.to)) / 1000)
|
|
|
257 |
- (Date.parse(tools.dateDeserialize(day.from)) / 1000)) / 86400),
|
|
|
258 |
day.customClass ? day.customClass : '',
|
|
|
259 |
day.desc ? day.desc : ''
|
|
|
260 |
);
|
|
|
261 |
jQuery('#d'+i+'-'+ tools.genId(tools.dateDeserialize(day.from).getTime()))
|
|
|
262 |
.append(_bar
|
|
|
263 |
);
|
|
|
264 |
});
|
|
|
265 |
}
|
|
|
266 |
});
|
|
|
267 |
};
|
|
|
268 |
|
|
|
269 |
navigateTo = function(val) {
|
|
|
270 |
switch (val) {
|
|
|
271 |
case 'begin':
|
|
|
272 |
jQuery('.fn-gantt .dataPanel').animate({
|
|
|
273 |
'margin-left': '0px'
|
|
|
274 |
}, 'fast', function() {repositionLabel();});
|
|
|
275 |
break;
|
|
|
276 |
case 'end':
|
|
|
277 |
var mLeft = jQuery('.fn-gantt .dataPanel').width() - jQuery('.fn-gantt .rightPanel').width();
|
|
|
278 |
jQuery('.fn-gantt .dataPanel').animate({
|
|
|
279 |
'margin-left': '-' + mLeft + 'px'
|
|
|
280 |
}, 'fast', function() {repositionLabel();});
|
|
|
281 |
break;
|
|
|
282 |
default:
|
|
|
283 |
var max_left = (jQuery('.fn-gantt .dataPanel').width() - jQuery('.fn-gantt .rightPanel').width()) * -1;
|
|
|
284 |
var cur_marg = jQuery('.fn-gantt .dataPanel').css('margin-left').replace('px','');
|
|
|
285 |
var val = parseInt(cur_marg) + val;
|
|
|
286 |
if (val <= 0 && val >= max_left)
|
|
|
287 |
jQuery('.fn-gantt .dataPanel').animate({
|
|
|
288 |
'margin-left': val + 'px'
|
|
|
289 |
}, 'fast', repositionLabel);
|
|
|
290 |
break;
|
|
|
291 |
}
|
|
|
292 |
};
|
|
|
293 |
|
|
|
294 |
navigatePage = function(val) {
|
|
|
295 |
if ((pageNum+val) >= 0 && (pageNum+val) < Math.ceil(rowsNum/options.itemsPerPage))
|
|
|
296 |
{
|
|
|
297 |
pageNum += val;
|
|
|
298 |
hPosition = jQuery('.fn-gantt .dataPanel').css('margin-left').replace('px','');
|
|
|
299 |
jQuerythis.empty();
|
|
|
300 |
create(jQuerythis);
|
|
|
301 |
}
|
|
|
302 |
};
|
|
|
303 |
|
|
|
304 |
repositionLabel = function() {
|
|
|
305 |
jQuery('.fn-gantt .dataPanel').stop();
|
|
|
306 |
|
|
|
307 |
var wrapper = { offset: jQuery('.fn-gantt .rightPanel').offset(),
|
|
|
308 |
width: jQuery('.fn-gantt .rightPanel').width(),
|
|
|
309 |
height: jQuery('.fn-gantt .rightPanel').height()};
|
|
|
310 |
|
|
|
311 |
jQuery(".fn-gantt .rightPanel .year, .fn-gantt .rightPanel .month").each(function(i, obj) {
|
|
|
312 |
var objDim = { offset: jQuery(obj).offset(),
|
|
|
313 |
width: jQuery(obj).width(),
|
|
|
314 |
height: jQuery(obj).height()};
|
|
|
315 |
|
|
|
316 |
if (objDim.offset.left + objDim.width > wrapper.offset.left
|
|
|
317 |
&& objDim.offset.left < wrapper.offset.left+wrapper.width)
|
|
|
318 |
{
|
|
|
319 |
var viewArea = {
|
|
|
320 |
left: objDim.offset.left > wrapper.offset.left ? objDim.offset.left : wrapper.offset.left,
|
|
|
321 |
right: objDim.offset.left+objDim.width < wrapper.offset.left + wrapper.width ? objDim.offset.left+objDim.width : wrapper.offset.left + wrapper.width
|
|
|
322 |
};
|
|
|
323 |
jQuery(obj).children(".label").css("float", "left");
|
|
|
324 |
var labelWidth = jQuery(obj).children(".label").width();
|
|
|
325 |
|
|
|
326 |
var objMarg = objDim.offset.left < wrapper.offset.left ? wrapper.offset.left-objDim.offset.left : 0;
|
|
|
327 |
if (viewArea.right-viewArea.left > labelWidth)
|
|
|
328 |
jQuery(obj).children(".label")
|
|
|
329 |
.css("margin-left", objMarg + (viewArea.right - viewArea.left)/2 - labelWidth/2 + "px");
|
|
|
330 |
}
|
|
|
331 |
});
|
|
|
332 |
};
|
|
|
333 |
};
|
|
|
334 |
|
|
|
335 |
var tools = new function() {
|
|
|
336 |
this.getMaxDate = function() {
|
|
|
337 |
var maxDate = null;
|
|
|
338 |
jQuery.each(data, function(i, entry) {
|
|
|
339 |
jQuery.each(entry.values, function(i, date) {
|
|
|
340 |
maxDate = maxDate < tools.dateDeserialize(date.to) ? tools.dateDeserialize(date.to) : maxDate;
|
|
|
341 |
});
|
|
|
342 |
});
|
|
|
343 |
maxDate.setDate(maxDate.getDate() + 2);
|
|
|
344 |
if (maxDate.getDate() <= 4)
|
|
|
345 |
maxDate.setDate(maxDate.getDate() + 4);
|
|
|
346 |
return maxDate;
|
|
|
347 |
};
|
|
|
348 |
this.getMinDate = function() {
|
|
|
349 |
var minDate = null;
|
|
|
350 |
jQuery.each(data, function(i, entry) {
|
|
|
351 |
jQuery.each(entry.values, function(i, date) {
|
|
|
352 |
minDate = minDate > tools.dateDeserialize(date.from) || minDate == null ? tools.dateDeserialize(date.from) : minDate;
|
|
|
353 |
});
|
|
|
354 |
});
|
|
|
355 |
minDate.setDate(minDate.getDate() - 2);
|
|
|
356 |
if (minDate.getDate() >= 27)
|
|
|
357 |
minDate.setDate(minDate.getDate() - 4);
|
|
|
358 |
return minDate;
|
|
|
359 |
};
|
|
|
360 |
this.parseDateRange = function(from, to) {
|
|
|
361 |
var current = new Date(from.getTime());
|
|
|
362 |
var end = new Date(to.getTime());;
|
|
|
363 |
var ret = new Array();
|
|
|
364 |
var i = 0;
|
|
|
365 |
do {
|
|
|
366 |
ret[i++] = new Date(current.getTime());
|
|
|
367 |
current.setDate(current.getDate()+1);
|
|
|
368 |
} while (current <= to);
|
|
|
369 |
return ret;
|
|
|
370 |
};
|
|
|
371 |
this.dateDeserialize = function (dateStr) {
|
|
|
372 |
return eval('new' + dateStr.replace(/\//g, ' '));
|
|
|
373 |
};
|
|
|
374 |
this.genId = function (ticks) {
|
|
|
375 |
var t = Math.floor(ticks / 86400000);
|
|
|
376 |
return t * 86400000;
|
|
|
377 |
};
|
|
|
378 |
var _getCellSize = null;
|
|
|
379 |
this.getCellSize = function() {
|
|
|
380 |
if (!_getCellSize)
|
|
|
381 |
{
|
|
|
382 |
jQuery("body").append(
|
|
|
383 |
jQuery("<div style='display: none; position: absolute;' class='fn-gantt' id='measureCellWidth'><div class='row'></div></div>")
|
|
|
384 |
);
|
|
|
385 |
_getCellSize = jQuery('#measureCellWidth .row').height();
|
|
|
386 |
jQuery('#measureCellWidth').empty().remove();
|
|
|
387 |
}
|
|
|
388 |
return _getCellSize;
|
|
|
389 |
};
|
|
|
390 |
this.getPageHeight = function() {
|
|
|
391 |
return pageNum+1 == pageCount ? rowsOnLastPage*tools.getCellSize() : options.itemsPerPage*tools.getCellSize();
|
|
|
392 |
};
|
|
|
393 |
var _getProgressBarMargin = null;
|
|
|
394 |
this.getProgressBarMargin = function() {
|
|
|
395 |
if (!_getProgressBarMargin)
|
|
|
396 |
{
|
|
|
397 |
jQuery("body").append(
|
|
|
398 |
jQuery("<div style='display: none; position: absolute;' id='measureBarWidth' ><div class='fn-gantt'><div class='rightPanel'><div class='dataPanel'><div class='row day'><div class='bar' /></div></div></div></div></div>")
|
|
|
399 |
);
|
|
|
400 |
_getProgressBarMargin = parseInt(jQuery('#measureBarWidth .fn-gantt .rightPanel .day .bar').css("margin-left").replace("px",""));
|
|
|
401 |
_getProgressBarMargin += parseInt(jQuery('#measureBarWidth .fn-gantt .rightPanel .day .bar').css("margin-right").replace("px",""));
|
|
|
402 |
jQuery('#measureBarWidth').empty().remove();
|
|
|
403 |
}
|
|
|
404 |
return _getProgressBarMargin;
|
|
|
405 |
};
|
|
|
406 |
};
|
|
|
407 |
jQuery(this).empty();
|
|
|
408 |
create(jQuery(this));
|
|
|
409 |
};
|