2 * o------------------------------------------------------------------------------o
3 * | This file is part of the RGraph package - you can learn more at: |
5 * | http://www.rgraph.net |
7 * | This package is licensed under the RGraph license. For all kinds of business |
8 * | purposes there is a small one-time licensing fee to pay and for non |
9 * | commercial purposes it is free to use. You can read the full license here: |
11 * | http://www.rgraph.net/LICENSE.txt |
12 * o------------------------------------------------------------------------------o
15 if (typeof(RGraph) == 'undefined') RGraph = {};
18 * The gantt chart constructor
20 * @param object canvas The cxanvas object
21 * @param array data The chart data
23 RGraph.Gantt = function (id)
25 // Get the canvas and context objects
27 this.canvas = document.getElementById(id);
28 this.context = this.canvas.getContext("2d");
29 this.canvas.__object__ = this;
35 * Compatibility with older browsers
37 RGraph.OldBrowserCompat(this.context);
42 'chart.background.barcolor1': 'white',
43 'chart.background.barcolor2': 'white',
44 'chart.background.grid': true,
45 'chart.background.grid.width': 1,
46 'chart.background.grid.color': '#ddd',
47 'chart.background.grid.hsize': 20,
48 'chart.background.grid.vsize': 20,
49 'chart.background.grid.hlines': true,
50 'chart.background.grid.vlines': true,
51 'chart.background.grid.border': true,
52 'chart.background.grid.autofit':false,
53 'chart.background.grid.autofit.numhlines': 7,
54 'chart.background.grid.autofit.numvlines': 20,
55 'chart.background.vbars': [],
56 'chart.text.size': 10,
57 'chart.text.font': 'Verdana',
58 'chart.text.color': 'black',
63 'chart.title.background': null,
64 'chart.title.hpos': null,
65 'chart.title.vpos': null,
67 'chart.borders': true,
68 'chart.defaultcolor': 'white',
71 'chart.tooltips.effect': 'fade',
72 'chart.tooltips.css.class': 'RGraph_tooltip',
73 'chart.tooltips.highlight': true,
76 'chart.contextmenu': null,
77 'chart.annotatable': false,
78 'chart.annotate.color': 'black',
79 'chart.zoom.factor': 1.5,
80 'chart.zoom.fade.in': true,
81 'chart.zoom.fade.out': true,
82 'chart.zoom.hdir': 'right',
83 'chart.zoom.vdir': 'down',
84 'chart.zoom.frames': 10,
85 'chart.zoom.delay': 50,
86 'chart.zoom.shadow': true,
87 'chart.zoom.mode': 'canvas',
88 'chart.zoom.thumbnail.width': 75,
89 'chart.zoom.thumbnail.height': 75,
90 'chart.zoom.background': true,
91 'chart.zoom.action': 'zoom',
92 'chart.resizable': false
95 // Check the common library has been included
96 if (typeof(RGraph) == 'undefined') {
97 alert('[GANTT] Fatal error: The common library does not appear to have been included');
105 * @param name string The name of the property to set
106 * @param value mixed The value of the property
108 RGraph.Gantt.prototype.Set = function (name, value)
110 this.properties[name.toLowerCase()] = value;
117 * @param name string The name of the property to get
119 RGraph.Gantt.prototype.Get = function (name)
121 return this.properties[name.toLowerCase()];
128 RGraph.Gantt.prototype.Draw = function ()
131 * Fire the onbeforedraw event
133 RGraph.FireCustomEvent(this, 'onbeforedraw');
136 * Clear all of this canvases event handlers (the ones installed by RGraph)
138 RGraph.ClearEventListeners(this.id);
140 var gutter = this.Get('chart.gutter');
143 * Work out the graphArea
145 this.graphArea = this.canvas.width - (2 * gutter);
146 this.graphHeight = this.canvas.height - (2 * gutter);
147 this.numEvents = this.Get('chart.events').length
148 this.barHeight = this.graphHeight / this.numEvents;
149 this.halfBarHeight = this.barHeight / 2;
152 * Draw the background
154 RGraph.background.Draw(this);
157 * Draw a space for the left hand labels
159 this.context.beginPath();
160 this.context.lineWidth = 1;
161 this.context.strokeStyle = this.Get('chart.background.grid.color');
162 this.context.fillStyle = 'white';
163 this.context.fillRect(0,gutter - 5,gutter * 3, this.canvas.height - (2 * gutter) + 10);
164 this.context.moveTo(gutter * 3, gutter);
165 this.context.lineTo(gutter * 3, this.canvas.height - gutter);
167 this.context.stroke();
171 * Draw the labels at the top
182 * Setup the context menu if required
184 if (this.Get('chart.contextmenu')) {
185 RGraph.ShowContext(this);
189 * If the canvas is annotatable, do install the event handlers
191 if (this.Get('chart.annotatable')) {
192 RGraph.Annotate(this);
196 * This bit shows the mini zoom window if requested
198 if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
199 RGraph.ShowZoomWindow(this);
204 * This function enables resizing
206 if (this.Get('chart.resizable')) {
207 RGraph.AllowResizing(this);
211 * Fire the RGraph ondraw event
213 RGraph.FireCustomEvent(this, 'ondraw');
218 * Draws the labels at the top and the left of the chart
220 RGraph.Gantt.prototype.DrawLabels = function ()
222 var gutter = this.Get('chart.gutter');
224 this.context.beginPath();
225 this.context.fillStyle = this.Get('chart.text.color');
228 * Draw the X labels at the top of the chart.
230 var labelSpace = (this.graphArea - (2 * gutter)) / this.Get('chart.labels').length;
231 var xPos = (3 * gutter) + (labelSpace / 2);
232 this.context.strokeStyle = 'black'
234 for (i=0; i<this.Get('chart.labels').length; ++i) {
235 RGraph.Text(this.context, this.Get('chart.text.font'), this.Get('chart.text.size'), xPos + (i * labelSpace), gutter * (3/4), String(this.Get('chart.labels')[i]), 'center', 'center');
238 // Draw the vertical labels
239 for (i=0; i<this.Get('chart.events').length; ++i) {
240 var ev = this.Get('chart.events')[i];
241 var x = (3 * gutter);
242 var y = gutter + this.halfBarHeight + (i * this.barHeight);
244 RGraph.Text(this.context, this.Get('chart.text.font'), this.Get('chart.text.size'), x - 5, y, String(ev[3]), 'center', 'right');
249 * Draws the events to the canvas
251 RGraph.Gantt.prototype.DrawEvents = function ()
253 var canvas = this.canvas;
254 var context = this.context;
255 var gutter = this.Get('chart.gutter');
256 var events = this.Get('chart.events');
259 * Reset the coords array to prevent it growing
264 * First draw the vertical bars that have been added
266 if (this.Get('chart.vbars')) {
267 for (i=0; i<this.Get('chart.vbars').length; ++i) {
269 if (this.Get('chart.vbars')[i][0] + this.Get('chart.vbars')[i][1] > this.Get('chart.xmax')) {
270 this.Get('chart.vbars')[i][1] = 364 - this.Get('chart.vbars')[i][0];
273 var barX = (3 * gutter) + ( (this.Get('chart.vbars')[i][0] - this.Get('chart.xmin')) / (this.Get('chart.xmax') - this.Get('chart.xmin')) ) * (this.graphArea - (2 * gutter) );
275 var width = ( (this.graphArea - (2 * gutter)) / (this.Get('chart.xmax') - this.Get('chart.xmin')) ) * this.Get('chart.vbars')[i][1];
276 var height = canvas.height - (2 * gutter);
278 // Right hand bounds checking
279 if ( (barX + width) > (this.canvas.width - gutter) ) {
280 width = this.canvas.width - gutter - barX;
283 context.fillStyle = this.Get('chart.vbars')[i][2];
284 context.fillRect(barX, barY, width, height);
292 for (i=0; i<events.length; ++i) {
295 var min = this.Get('chart.xmin');
298 context.strokeStyle = 'black';
299 context.fillStyle = ev[4] ? ev[4] : this.Get('chart.defaultcolor');
301 var barStartX = (3 * gutter) + ( (ev[0] - min) / (this.Get('chart.xmax') - min)) * (this.graphArea - (2 * gutter) );
302 //barStartX += this.margin;
303 var barStartY = gutter + (i * this.barHeight);
304 var barWidth = (ev[1] / (this.Get('chart.xmax') - min) ) * (this.graphArea - (2 * gutter));
307 * If the width is greater than the graph atrea, curtail it
309 if ( (barStartX + barWidth) > (canvas.width - gutter) ) {
310 barWidth = canvas.width - gutter - barStartX;
313 // draw the border around the bar
314 if (this.Get('chart.borders')) {
315 context.strokeStyle = 'black';
317 context.strokeRect(barStartX, barStartY + this.Get('chart.margin'), barWidth, this.barHeight - (2 * this.Get('chart.margin')) );
321 * Draw the actual bar storing store the coordinates
323 this.coords.push([barStartX, barStartY + this.Get('chart.margin'), barWidth, this.barHeight - (2 * this.Get('chart.margin'))]);
324 context.fillRect(barStartX, barStartY + this.Get('chart.margin'), barWidth, this.barHeight - (2 * this.Get('chart.margin')) );
326 // Work out the completeage indicator
327 var complete = (ev[2] / 100) * barWidth;
329 // Draw the % complete indicator. If it's greater than 0
330 if (typeof(ev[2]) == 'number') {
332 context.fillStyle = ev[5] ? ev[5] : '#0c0';
333 context.fillRect(barStartX,
334 barStartY + this.Get('chart.margin'),
335 (ev[2] / 100) * barWidth,
336 this.barHeight - (2 * this.Get('chart.margin')) );
339 context.fillStyle = this.Get('chart.text.color');
340 RGraph.Text(context, this.Get('chart.text.font'), this.Get('chart.text.size'), barStartX + barWidth + 5, barStartY + this.halfBarHeight, String(ev[2]) + '%', 'center');
346 * If tooltips are defined, handle them
348 if (this.Get('chart.tooltips')) {
350 // Register the object for redrawing
351 RGraph.Register(this);
354 * If the cursor is over a hotspot, change the cursor to a hand
356 var canvas_onmousemove_func = function (eventObj)
358 eventObj = RGraph.FixEventObject(eventObj);
359 var canvas = eventObj.target;
360 var obj = canvas.__object__;
361 var len = obj.coords.length;
364 * Get the mouse X/Y coordinates
366 var mouseCoords = RGraph.getMouseXY(eventObj);
369 * Loop through the bars determining if the mouse is over a bar
371 for (var i=0; i<len; i++) {
373 var mouseX = mouseCoords[0]; // In relation to the canvas
374 var mouseY = mouseCoords[1]; // In relation to the canvas
375 var left = obj.coords[i][0];
376 var top = obj.coords[i][1];
377 var width = obj.coords[i][2];
378 var height = obj.coords[i][3];
381 && mouseX <= (left + width)
383 && mouseY <= (top + height)
384 && (typeof(obj.Get('chart.tooltips')) == 'function' || obj.Get('chart.tooltips')[i]) ) {
386 canvas.style.cursor = 'pointer';
391 canvas.style.cursor = 'default';
393 this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false);
394 RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func);
397 var canvas_onclick_func = function (eventObj)
399 eventObj = RGraph.FixEventObject(eventObj);
401 var canvas = eventObj.target;
402 var context = canvas.getContext('2d');
403 var obj = canvas.__object__;
405 var mouseCoords = RGraph.getMouseXY(eventObj);
406 var mouseX = mouseCoords[0];
407 var mouseY = mouseCoords[1];
410 for (i=0; i<obj.coords.length; ++i) {
413 var xCoord = obj.coords[i][0];
414 var yCoord = obj.coords[i][1];
415 var width = obj.coords[i][2];
416 var height = obj.coords[i][3];
420 && (mouseX <= xCoord + width)
422 && (mouseY <= yCoord + height)
423 && obj.Get('chart.tooltips')
430 * Get the tooltip text
432 if (typeof(obj.Get('chart.tooltips')) == 'function') {
433 var text = obj.Get('chart.tooltips')(idx);
435 } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[idx]) == 'function') {
436 var text = obj.Get('chart.tooltips')[idx](idx);
438 } else if (typeof(obj.Get('chart.tooltips')) == 'object') {
439 var text = obj.Get('chart.tooltips')[idx];
445 if (String(text).length && text != null) {
447 // SHOW THE CORRECT TOOLTIP
448 RGraph.Tooltip(canvas, text, eventObj.pageX, eventObj.pageY, idx);
451 * Draw a rectangle around the correct bar, in effect highlighting it
453 context.strokeStyle = 'black';
454 context.fillStyle = 'rgba(255,255,255,0.8)';
455 context.strokeRect(xCoord, yCoord, width, height);
456 context.fillRect(xCoord, yCoord, width, height);
458 eventObj.stopPropagation();
464 this.canvas.addEventListener('click', canvas_onclick_func, false);
465 RGraph.AddEventListener(this.id, 'click', canvas_onclick_func);