230 lines
6.9 KiB
JavaScript
230 lines
6.9 KiB
JavaScript
/** Gantt
|
|
* Base on data in form [s,y,d] where:
|
|
* y - executor or simply y value
|
|
* s - task start value
|
|
* d - task duration
|
|
* **/
|
|
Flotr.addType('gantt', {
|
|
options: {
|
|
show: false, // => setting to true will show gantt, false will hide
|
|
lineWidth: 2, // => in pixels
|
|
barWidth: 1, // => in units of the x axis
|
|
fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill
|
|
fillColor: null, // => fill color
|
|
fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
|
|
centered: true // => center the bars to their x axis value
|
|
},
|
|
/**
|
|
* Draws gantt series in the canvas element.
|
|
* @param {Object} series - Series with options.gantt.show = true.
|
|
*/
|
|
draw: function(series) {
|
|
var ctx = this.ctx,
|
|
bw = series.gantt.barWidth,
|
|
lw = Math.min(series.gantt.lineWidth, bw);
|
|
|
|
ctx.save();
|
|
ctx.translate(this.plotOffset.left, this.plotOffset.top);
|
|
ctx.lineJoin = 'miter';
|
|
|
|
/**
|
|
* @todo linewidth not interpreted the right way.
|
|
*/
|
|
ctx.lineWidth = lw;
|
|
ctx.strokeStyle = series.color;
|
|
|
|
ctx.save();
|
|
this.gantt.plotShadows(series, bw, 0, series.gantt.fill);
|
|
ctx.restore();
|
|
|
|
if(series.gantt.fill){
|
|
var color = series.gantt.fillColor || series.color;
|
|
ctx.fillStyle = this.processColor(color, {opacity: series.gantt.fillOpacity});
|
|
}
|
|
|
|
this.gantt.plot(series, bw, 0, series.gantt.fill);
|
|
ctx.restore();
|
|
},
|
|
plot: function(series, barWidth, offset, fill){
|
|
var data = series.data;
|
|
if(data.length < 1) return;
|
|
|
|
var xa = series.xaxis,
|
|
ya = series.yaxis,
|
|
ctx = this.ctx, i;
|
|
|
|
for(i = 0; i < data.length; i++){
|
|
var y = data[i][0],
|
|
s = data[i][1],
|
|
d = data[i][2],
|
|
drawLeft = true, drawTop = true, drawRight = true;
|
|
|
|
if (s === null || d === null) continue;
|
|
|
|
var left = s,
|
|
right = s + d,
|
|
bottom = y - (series.gantt.centered ? barWidth/2 : 0),
|
|
top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0);
|
|
|
|
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
|
|
continue;
|
|
|
|
if(left < xa.min){
|
|
left = xa.min;
|
|
drawLeft = false;
|
|
}
|
|
|
|
if(right > xa.max){
|
|
right = xa.max;
|
|
if (xa.lastSerie != series)
|
|
drawTop = false;
|
|
}
|
|
|
|
if(bottom < ya.min)
|
|
bottom = ya.min;
|
|
|
|
if(top > ya.max){
|
|
top = ya.max;
|
|
if (ya.lastSerie != series)
|
|
drawTop = false;
|
|
}
|
|
|
|
/**
|
|
* Fill the bar.
|
|
*/
|
|
if(fill){
|
|
ctx.beginPath();
|
|
ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset);
|
|
ctx.lineTo(xa.d2p(left), ya.d2p(top) + offset);
|
|
ctx.lineTo(xa.d2p(right), ya.d2p(top) + offset);
|
|
ctx.lineTo(xa.d2p(right), ya.d2p(bottom) + offset);
|
|
ctx.fill();
|
|
ctx.closePath();
|
|
}
|
|
|
|
/**
|
|
* Draw bar outline/border.
|
|
*/
|
|
if(series.gantt.lineWidth && (drawLeft || drawRight || drawTop)){
|
|
ctx.beginPath();
|
|
ctx.moveTo(xa.d2p(left), ya.d2p(bottom) + offset);
|
|
|
|
ctx[drawLeft ?'lineTo':'moveTo'](xa.d2p(left), ya.d2p(top) + offset);
|
|
ctx[drawTop ?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(top) + offset);
|
|
ctx[drawRight?'lineTo':'moveTo'](xa.d2p(right), ya.d2p(bottom) + offset);
|
|
|
|
ctx.stroke();
|
|
ctx.closePath();
|
|
}
|
|
}
|
|
},
|
|
plotShadows: function(series, barWidth, offset){
|
|
var data = series.data;
|
|
if(data.length < 1) return;
|
|
|
|
var i, y, s, d,
|
|
xa = series.xaxis,
|
|
ya = series.yaxis,
|
|
ctx = this.ctx,
|
|
sw = this.options.shadowSize;
|
|
|
|
for(i = 0; i < data.length; i++){
|
|
y = data[i][0];
|
|
s = data[i][1];
|
|
d = data[i][2];
|
|
|
|
if (s === null || d === null) continue;
|
|
|
|
var left = s,
|
|
right = s + d,
|
|
bottom = y - (series.gantt.centered ? barWidth/2 : 0),
|
|
top = y + barWidth - (series.gantt.centered ? barWidth/2 : 0);
|
|
|
|
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)
|
|
continue;
|
|
|
|
if(left < xa.min) left = xa.min;
|
|
if(right > xa.max) right = xa.max;
|
|
if(bottom < ya.min) bottom = ya.min;
|
|
if(top > ya.max) top = ya.max;
|
|
|
|
var width = xa.d2p(right)-xa.d2p(left)-((xa.d2p(right)+sw <= this.plotWidth) ? 0 : sw);
|
|
var height = ya.d2p(bottom)-ya.d2p(top)-((ya.d2p(bottom)+sw <= this.plotHeight) ? 0 : sw );
|
|
|
|
ctx.fillStyle = 'rgba(0,0,0,0.05)';
|
|
ctx.fillRect(Math.min(xa.d2p(left)+sw, this.plotWidth), Math.min(ya.d2p(top)+sw, this.plotHeight), width, height);
|
|
}
|
|
},
|
|
extendXRange: function(axis) {
|
|
if(axis.options.max === null){
|
|
var newmin = axis.min,
|
|
newmax = axis.max,
|
|
i, j, x, s, g,
|
|
stackedSumsPos = {},
|
|
stackedSumsNeg = {},
|
|
lastSerie = null;
|
|
|
|
for(i = 0; i < this.series.length; ++i){
|
|
s = this.series[i];
|
|
g = s.gantt;
|
|
|
|
if(g.show && s.xaxis == axis) {
|
|
for (j = 0; j < s.data.length; j++) {
|
|
if (g.show) {
|
|
y = s.data[j][0]+'';
|
|
stackedSumsPos[y] = Math.max((stackedSumsPos[y] || 0), s.data[j][1]+s.data[j][2]);
|
|
lastSerie = s;
|
|
}
|
|
}
|
|
for (j in stackedSumsPos) {
|
|
newmax = Math.max(stackedSumsPos[j], newmax);
|
|
}
|
|
}
|
|
}
|
|
axis.lastSerie = lastSerie;
|
|
axis.max = newmax;
|
|
axis.min = newmin;
|
|
}
|
|
},
|
|
extendYRange: function(axis){
|
|
if(axis.options.max === null){
|
|
var newmax = Number.MIN_VALUE,
|
|
newmin = Number.MAX_VALUE,
|
|
i, j, s, g,
|
|
stackedSumsPos = {},
|
|
stackedSumsNeg = {},
|
|
lastSerie = null;
|
|
|
|
for(i = 0; i < this.series.length; ++i){
|
|
s = this.series[i];
|
|
g = s.gantt;
|
|
|
|
if (g.show && !s.hide && s.yaxis == axis) {
|
|
var datamax = Number.MIN_VALUE, datamin = Number.MAX_VALUE;
|
|
for(j=0; j < s.data.length; j++){
|
|
datamax = Math.max(datamax,s.data[j][0]);
|
|
datamin = Math.min(datamin,s.data[j][0]);
|
|
}
|
|
|
|
if (g.centered) {
|
|
newmax = Math.max(datamax + 0.5, newmax);
|
|
newmin = Math.min(datamin - 0.5, newmin);
|
|
}
|
|
else {
|
|
newmax = Math.max(datamax + 1, newmax);
|
|
newmin = Math.min(datamin, newmin);
|
|
}
|
|
// For normal horizontal bars
|
|
if (g.barWidth + datamax > newmax){
|
|
newmax = axis.max + g.barWidth;
|
|
}
|
|
}
|
|
}
|
|
axis.lastSerie = lastSerie;
|
|
axis.max = newmax;
|
|
axis.min = newmin;
|
|
axis.tickSize = Flotr.getTickSize(axis.options.noTicks, newmin, newmax, axis.options.tickDecimals);
|
|
}
|
|
}
|
|
});
|