odoo/addons/web_graph/static/lib/flotr2/js/types/pie.js

211 lines
6.7 KiB
JavaScript

/** Pie **/
/**
* Formats the pies labels.
* @param {Object} slice - Slice object
* @return {String} Formatted pie label string
*/
(function () {
var
_ = Flotr._;
Flotr.defaultPieLabelFormatter = function (total, value) {
return (100 * value / total).toFixed(2)+'%';
};
Flotr.addType('pie', {
options: {
show: false, // => setting to true will show bars, false will hide
lineWidth: 1, // => in pixels
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.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
explode: 6, // => the number of pixels the splices will be far from the center
sizeRatio: 0.6, // => the size ratio of the pie relative to the plot
startAngle: Math.PI/4, // => the first slice start angle
labelFormatter: Flotr.defaultPieLabelFormatter,
pie3D: false, // => whether to draw the pie in 3 dimenstions or not (ineffective)
pie3DviewAngle: (Math.PI/2 * 0.8),
pie3DspliceThickness: 20
},
draw : function (options) {
// TODO 3D charts what?
var
data = options.data,
context = options.context,
canvas = context.canvas,
lineWidth = options.lineWidth,
shadowSize = options.shadowSize,
sizeRatio = options.sizeRatio,
height = options.height,
width = options.width,
explode = options.explode,
color = options.color,
fill = options.fill,
fillStyle = options.fillStyle,
radius = Math.min(canvas.width, canvas.height) * sizeRatio / 2,
value = data[0][1],
html = [],
vScale = 1,//Math.cos(series.pie.viewAngle);
measure = Math.PI * 2 * value / this.total,
startAngle = this.startAngle || (2 * Math.PI * options.startAngle), // TODO: this initial startAngle is already in radians (fixing will be test-unstable)
endAngle = startAngle + measure,
bisection = startAngle + measure / 2,
label = options.labelFormatter(this.total, value),
//plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;
explodeCoeff = explode + radius + 4,
distX = Math.cos(bisection) * explodeCoeff,
distY = Math.sin(bisection) * explodeCoeff,
textAlign = distX < 0 ? 'right' : 'left',
textBaseline = distY > 0 ? 'top' : 'bottom',
style,
x, y,
distX, distY;
context.save();
context.translate(width / 2, height / 2);
context.scale(1, vScale);
x = Math.cos(bisection) * explode;
y = Math.sin(bisection) * explode;
// Shadows
if (shadowSize > 0) {
this.plotSlice(x + shadowSize, y + shadowSize, radius, startAngle, endAngle, context);
if (fill) {
context.fillStyle = 'rgba(0,0,0,0.1)';
context.fill();
}
}
this.plotSlice(x, y, radius, startAngle, endAngle, context);
if (fill) {
context.fillStyle = fillStyle;
context.fill();
}
context.lineWidth = lineWidth;
context.strokeStyle = color;
context.stroke();
style = {
size : options.fontSize * 1.2,
color : options.fontColor,
weight : 1.5
};
if (label) {
if (options.htmlText || !options.textEnabled) {
divStyle = 'position:absolute;' + textBaseline + ':' + (height / 2 + (textBaseline === 'top' ? distY : -distY)) + 'px;';
divStyle += textAlign + ':' + (width / 2 + (textAlign === 'right' ? -distX : distX)) + 'px;';
html.push('<div style="', divStyle, '" class="flotr-grid-label">', label, '</div>');
}
else {
style.textAlign = textAlign;
style.textBaseline = textBaseline;
Flotr.drawText(context, label, distX, distY, style);
}
}
if (options.htmlText || !options.textEnabled) {
var div = Flotr.DOM.node('<div style="color:' + options.fontColor + '" class="flotr-labels"></div>');
Flotr.DOM.insert(div, html.join(''));
Flotr.DOM.insert(options.element, div);
}
context.restore();
// New start angle
this.startAngle = endAngle;
this.slices = this.slices || [];
this.slices.push({
radius : Math.min(canvas.width, canvas.height) * sizeRatio / 2,
x : x,
y : y,
explode : explode,
start : startAngle,
end : endAngle
});
},
plotSlice : function (x, y, radius, startAngle, endAngle, context) {
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, false);
context.lineTo(x, y);
context.closePath();
},
hit : function (options) {
var
data = options.data[0],
args = options.args,
index = options.index,
mouse = args[0],
n = args[1],
slice = this.slices[index],
x = mouse.relX - options.width / 2,
y = mouse.relY - options.height / 2,
r = Math.sqrt(x * x + y * y),
theta = Math.atan(y / x),
circle = Math.PI * 2,
explode = slice.explode || options.explode,
start = slice.start % circle,
end = slice.end % circle;
if (x < 0) {
theta += Math.PI;
} else if (x > 0 && y < 0) {
theta += circle;
}
if (r < slice.radius + explode && r > explode) {
if ((start > end && (theta < end || theta > start)) ||
(theta > start && theta < end)) {
// TODO Decouple this from hit plugin (chart shouldn't know what n means)
n.x = data[0];
n.y = data[1];
n.sAngle = start;
n.eAngle = end;
n.index = 0;
n.seriesIndex = index;
n.fraction = data[1] / this.total;
}
}
},
drawHit: function (options) {
var
context = options.context,
slice = this.slices[options.args.seriesIndex];
context.save();
context.translate(options.width / 2, options.height / 2);
this.plotSlice(slice.x, slice.y, slice.radius, slice.start, slice.end, context);
context.stroke();
context.restore();
},
clearHit : function (options) {
var
context = options.context,
slice = this.slices[options.args.seriesIndex],
padding = 2 * options.lineWidth,
radius = slice.radius + padding;
context.save();
context.translate(options.width / 2, options.height / 2);
context.clearRect(
slice.x - radius,
slice.y - radius,
2 * radius + padding,
2 * radius + padding
);
context.restore();
},
extendYRange : function (axis, data) {
this.total = (this.total || 0) + data[0][1];
}
});
})();