Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
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('&lt;')
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('&gt;')
87
					.click( function () {
88
						navigatePage(1);
89
					}))
90
				.append(jQuery('<a href="javascript:///" class="nav-link nav-begin"/>')
91
					.html('&#124;&lt;')
92
					.click( function () {
93
						navigateTo('begin');
94
					}))
95
				.append(jQuery('<a href="javascript:///" class="nav-link nav-prev-week"/>')
96
					.html('&lt;&lt;')
97
					.click( function () {
98
						navigateTo(tools.getCellSize()*7);
99
					}))
100
				.append(jQuery('<a href="javascript:///" class="nav-link nav-prev-day"/>')
101
					.html('&lt;')
102
					.click( function () {
103
						navigateTo(tools.getCellSize());
104
					}))
105
				.append(jQuery('<a href="javascript:///" class="nav-link nav-next-day"/>')
106
					.html('&gt;')
107
					.click( function () {
108
						navigateTo(tools.getCellSize() * -1);
109
					}))
110
				.append(jQuery('<a href="javascript:///" class="nav-link nav-next-week"/>')
111
					.html('&gt;&gt;')
112
					.click( function () {
113
						navigateTo(tools.getCellSize() * -7);
114
					}))
115
				.append(jQuery('<a href="javascript:///" class="nav-link nav-end"/>')
116
					.html('&gt;&#124;')
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
};