3d-pie-chart
Version:
Raphael plugin 3d pie chart
231 lines (214 loc) • 6.88 kB
JavaScript
export const pie = (config, instance) => {
const {title, data} = config;
const isDoughnut = true;
let values = [], colors = [], labels = [];
if (!data || !Array.isArray(data)) {
console.error("data is required, see doc for more details");
}
for (const {value, label, color} of data) {
if (!value) {
console.error("value is require in data");
}
if (!color) {
console.log("use default color");
}
values.push(value);
colors.push(color);
labels.push(label);
}
// var tooltips = args.tooltip;
var percentages = [], doughnutSize = 1.5; //doughnut hole
var sum = 0;
for (var i = 0; i < values.length; i += 1) {
sum += values[i];
}
for (var j = 0; j < values.length; j += 1) {
percentages.push(((values[j]/sum)*100).toFixed(2)+"%");
}
var paper = instance;
var r1, r2, cx, cy;
var pie_width = paper.width,
pie_height = paper.height,
pie_radius = (pie_width > pie_height) ? .4*pie_height : .4*pie_width;
r1 = pie_radius; r2 = .9*r1;
cx = paper.width/2; cy = paper.height/2;
var dsize = 15 * ( pie_width / 1000 ) ; //thickness
var nos = values.length;
var calculatedTitleYOffset = r2/3;
var titleFontSize = 20 * (pie_width / 400);
var titleBox = paper.text(10, 10, title).attr({
x: cx,
y: cy - calculatedTitleYOffset,
'font-size': titleFontSize,
'font-weight': 'bold',
opacity: 0.8
});
if (nos == 1) {
if (isDoughnut) {
var e_ = paper.ellipse(cx, cy+17, r1, r2).attr({
fill: colors[0],
stroke: "#999"
});
var e = paper.ellipse(cx, cy, r1, r2).attr({
fill: colors[0],
stroke: "#999",
opacity: .8
});
var c = paper.ellipse(cx, cy, r1/doughnutSize, r2/doughnutSize).attr({
stroke: "#999",
fill: "#fff"
});
var arcTop = paper.path("M"+(cx+r1/doughnutSize)+","+(cy+17)+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,1,0,"+
(cx-r1/doughnutSize)+","+(cy+17)+
"L"+(cx-r1/doughnutSize)+","+cy+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,0,1,"+
(cx+r1/doughnutSize)+","+cy+"z").attr({stroke: "#111", fill: colors[0],opacity: 1});
var arcBot = paper.path("M"+(cx+r1/doughnutSize)+","+(cy+17)+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,1,1,"+
(cx-r1/doughnutSize)+","+(cy+17)).attr({stroke: "#111", opacity:.2});
} else {
var e = paper.ellipse(cx, cy, r1, r2).attr({
fill: colors[0],
stroke: "#999",
opacity: .8
});
var e_ = paper.ellipse(cx, cy+17, r1, r2).attr({
fill: colors[0],
stroke: "#999"
}).toBack();
}
} else {
var x = cx + r1, y = cy, preAngle = 0;
var ix = cx + r1/doughnutSize, iy = cy;
var all_set = [];
var topSet = paper.set();
var angles = [], tset = [], ttset = [];
for (var i = 0; i < nos; i += 1) {
var slice = paper.set();
var startX = x, startY = y;
var iStartX = ix, iStartY = iy;
var ratio = values[i]/sum;
var angle = 2*ratio*Math.PI, largeArc = 0;
angles.push(angle);
if (angle > Math.PI) largeArc = 1;
x = cx + r1*Math.cos(angle+preAngle);
y = cy + r2*Math.sin(angle+preAngle);
ix = cx + r1/doughnutSize*Math.cos(angle+preAngle);
iy = cy + r2/doughnutSize*Math.sin(angle+preAngle);
var centerX = (startX+x)/2, centerY = (startY+y)/2;
var centerLine = paper.path("M"+cx+","+cy+"L"+centerX+","+centerY).attr({
stroke: "none"
});
var coord = centerLine.getPointAtLength(15);
tset.push(coord);
var ttx = cx + (r1+45)*Math.cos(angle/2+preAngle),
tty = cy + (r2+45)*Math.sin(angle/2+preAngle);
ttset.push({x: ttx, y: tty});
if (isDoughnut) {
var side4 = paper.path("M"+iStartX+","+iStartY),
side3 = paper.path("M"+startX+","+startY),
side2 = paper.path("M"+cx+","+cy),
side1 = paper.path("M"+cx+","+cy),
topside = paper.path("M"+x+","+y);
side4 = paper.path("M"+iStartX+","+iStartY+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,"+largeArc+",1,"+ix+","+iy+
"L"+ix+","+(iy+dsize)+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,"+largeArc+",0,"+iStartX+","+(iStartY+dsize)+"z");
side3 = paper.path("M"+startX+","+startY+
"A"+r1+","+r2+",0,"+largeArc+",1,"+x+","+y+
"L"+x+","+(y+dsize)+
"A"+r1+","+r2+",0,"+largeArc+",0,"+startX+","+(startY+dsize)+"z");
side2 = paper.path("M"+ix+","+iy+
"L"+ix+","+(iy+dsize)+
"L"+x+","+(y+dsize)+
"L"+x+","+y+"z");
side1 = paper.path("M"+iStartX+","+iStartY+
"L"+iStartX+","+(iStartY+dsize)+
"L"+startX+","+(startY+dsize)+
"L"+startX+","+startY+"z");
topside = paper.path("M"+x+","+y+
"A"+r1+","+r2+",0,"+largeArc+",0,"+startX+","+startY+
"L"+iStartX+","+iStartY+
"A"+r1/doughnutSize+","+r2/doughnutSize+",0,"+largeArc+",1,"+ix+","+iy+
"z");
slice.push(side1, side2, side3, side4, topside);
} else {
var side3 = paper.path("M"+startX+","+startY),
side2 = paper.path("M"+cx+","+cy),
side1 = paper.path("M"+cx+","+cy),
topside = paper.path("M"+x+","+y);
side3 = paper.path("M"+startX+","+startY+
"A"+r1+","+r2+",0,"+largeArc+",1,"+x+","+y+
"L"+x+","+(y+dsize)+
"A"+r1+","+r2+",0,"+largeArc+",0,"+startX+","+(startY+dsize)+"z");
side2 = paper.path("M"+cx+","+cy+
"L"+cx+","+(cy+dsize)+
"L"+x+","+(y+dsize)+
"L"+x+","+y+"z");
side1 = paper.path("M"+cx+","+cy+
"L"+cx+","+(cy+dsize)+
"L"+startX+","+(startY+dsize)+
"L"+startX+","+startY+"z");
topside = paper.path("M"+x+","+y+
"A"+r1+","+r2+",0,"+largeArc+",0,"+startX+","+startY+
"L"+cx+","+cy+"z");
slice.push(topside, side1, side2, side3);
}
topSet.push(topside);
topSet.toFront();
slice.attr({
fill: colors[i],
stroke: "#555",
opacity: .8
});
all_set.push(slice);
preAngle += angle;
}
var mlist = [];
for (var i = 0; i < values.length; i += 1) {
mlist[i] = false;
}
var labelBox = paper.text(0, 0, '').attr({
x: cx,
y: cy,
'font-size': titleFontSize * .8,
'font-weight': 'normal',
opacity: 0.8,
stroke: 'blue',
});
function showLabel(index) {
labelBox.attr({
text: labels[index],
fill: colors[index],
stroke: colors[index]
});
labelBox.show();
}
topSet.forEach(function(shape, i) {
shape.hover(function() {
shape.node.style.cursor = "pointer";
var smx = (angles[i]>=Math.PI)?-(tset[i].x-cx):(tset[i].x-cx),
smy = (angles[i]>=Math.PI)?-(tset[i].y-cy):(tset[i].y-cy);
smx *= shape.paper.width / 800;
smy *= shape.paper.height / 800;
showLabel(i);
all_set[i].animate({
transform: "t"+smx+","+smy
}, 300);
if (navigator.userAgent.match(/(iPhone|iPod|iPad)/i)) {
setTimeout(function() {
all_set[i].animate({
transform: "t0,0"
});
}, 2000);
}
}, function() {
labelBox.hide();
all_set[i].animate({
transform: "t0,0"
}, 300);
});
});
}
};