Skip to content

Instantly share code, notes, and snippets.

@dylang
Created September 10, 2012 21:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dylang/3694235 to your computer and use it in GitHub Desktop.
Save dylang/3694235 to your computer and use it in GitHub Desktop.
piehole
function testPie(element) {
// constants
var FONT = 'ProximaNova';
var WIDTH = 390,
HEIGHT = 390,
CENTER_X = 200,
CENTER_Y = 200,
CX_CY = CENTER_X+','+CENTER_Y;
// TODO - move this MP to JSP
var MESSAGE_PROPERTIES_TYPES = {
COOLING: 'Cooling',
HEATING: 'Heating',
WATER_HEATING: 'Hot Water',
APPLIANCES: 'Appliances',
LIGHTING: 'Lighting',
OTHER: 'Other'
};
// Order of the questions
var PIE_ORDER = ['COOLING', 'HEATING', 'WATER_HEATING', 'APPLIANCES', 'LIGHTING', 'OTHER'],
PIE_COLORS = { COOLING: '#1087C9', HEATING: '#AB3E2C', WATER_HEATING: '#663366', APPLIANCES: '#C2B59B', LIGHTING: '#65D9C5', OTHER: '#8FC740'};
// set arrays of the slice fill colors and sizes
var sliceColors = ['1087C9','AB3E2C','663366','C2B59B','65D9C5','8FC740'],
sliceData = [30, 30, 20, 10, 70, 38];
// pie vars
var paper = Raphael(element, WIDTH, HEIGHT),
slicePercents = [],
SLICE_COUNT = sliceData.length,
rDeg = -90,
s1 = 's1,1,',
s2 = 's1.05,1.05,',
paths = paper.set(),
total = 0,
start;
var
i = 0;
for (i = 0; i < SLICE_COUNT; i++) {
total += sliceData[i];
}
Raphael.el.rHide = function () {
this.attr({opacity:0});
};
Raphael.el.rShow = function () {
this.attr({opacity:1});
};
function hideHole() {
holes.attr({opacity:0});
}
paper.customAttributes.segment = function (x, y, r, a1, a2) {
var flag = (a2 - a1) > 180,
a1 = (a1 % 360) * Math.PI / 180;
a2 = (a2 % 360) * Math.PI / 180;
return {
path: [["M", x, y], ["l", r * Math.cos(a1), r * Math.sin(a1)], ["A", r, r, 0, +flag, 1, x + r * Math.cos(a2), y + r * Math.sin(a2)], ["z"]]
};
};
/**
* animate
* @param ms miliseconds
* @param ind pie slice number. null for gray, number for how many to show in color
*/
function pieAnimate(ms,ind) {
var start = 0, end, val,
rDeg = -90,
indj = parseInt(ind)+SLICE_COUNT,
j, newPercent;
// loop through pie slices
for (i = 0; i < SLICE_COUNT; i++) {
j = i+SLICE_COUNT;
val = 360 / total * sliceData[i];
end = start+val;
newPercent = Math.round((sliceData[i] / total) * 100);
slicePercents.push(newPercent);
percent[i].attr('text',newPercent);
//$('.tip-container section:eq('+i+') .percentage').html(newPercent);
// set a complete class, figure out colors
var hexColor = 'dddddd';
paths[j].attr({cursor:'default'});
if ( i<=ind ) {
paths[j].data('class','finished');
hexColor = sliceColors[i];
} else if (ind==SLICE_COUNT-1) {
hexColor = sliceColors[SLICE_COUNT-1];
} else if (ind==SLICE_COUNT) {
paths[j].data('class','finished').attr({cursor:'pointer'});
}
// calculate the new slice sizes, animate them
paths[i].animate({
segment: [CENTER_X, CENTER_Y, 165, start, end, i, ind],
fill: '#'+hexColor,
transform:['paper'+rDeg+','+CX_CY]
},
ms || 700,
'backOut');
paths[j].attr({
segment: [CENTER_X, CENTER_Y, 165, start, start+=val, i, ind],
transform:['paper'+rDeg+','+CX_CY]
});
}
// make the selected slice larger, show the corresponding donuteHole
if (ind<SLICE_COUNT) {
// show the stuff in the hole
hideHole();
circle.rShow();
headers[ind].rShow();
inProg.rShow();
// active class for the active audit section
paths[indj].data('class','active');
// bump the active slice out
paths[ind].animate({transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY], fill: '#888888'}, 700, "backOut");
paths[indj].animate({transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY]},0);
}
// rotate the pie, so that the first slice starts at 12:00
paths.transform('paper'+rDeg+','+CX_CY);
}
// okay this is tricky. we create TWO pies, one that sits over the other, invisible, so that hovering over the hole
// doesn't hover out of the slice. All the click and hover functions happen on the invisible pie on top. Ya dig?
// first we build the colorful "underpie":
start = 0;
for (i = 0; i < SLICE_COUNT; i++) {
val = 360 / total * sliceData[i];
(function (i, val) {
paths.push(paper.path().attr({segment: [CENTER_X, CENTER_Y, 1, start, start + val], stroke: "#ffffff", "stroke-width": 3, opacity:1}));
})(i, val);
start += val;
}
// cut out a hole next, so it is layered between the overpie and underpie. add the text.
var holes = paper.set(),
headers = paper.set(),
headers2= paper.set(),
percent = paper.set(),
perc2 = paper.set(),
circle = paper.circle(CENTER_X, CENTER_Y, 95).attr({fill: '#F5F5F5', stroke: '#FFFFFF', "stroke-width":3}),
instr = paper.text(CENTER_X, CENTER_Y, 'Answer the questions on\nthe right to see your\n energy use breakdown.').attr({'font-size':12,'font-family':'proxima'}),
inProg = paper.text(CENTER_X, CENTER_Y+25, 'In progress').attr({'font-size':16,'font-family':FONT,'fill':'#000000'}),
notStrt = paper.text(CENTER_X, CENTER_Y+25, 'Not started').attr({'font-size':16,'font-family':FONT,'fill':'#000000'}),
average = paper.set();
for (i = 0; i < SLICE_COUNT; i++) {
(function (i) {
var t1 = paper.text(CENTER_X-20 , CENTER_Y-15, sliceData[i]).attr({'font-size':55,'font-family':FONT,'font-weight':'bold','fill':'#000000'}),
t1W = (t1.getBBox().width)/2,
t2 = paper.text(CENTER_X+t1W, CENTER_Y-15, '%').attr({'font-size':55,'font-family':FONT,'font-weight':'normal','fill':'#000000'}),
perc1 = paper.set();
percent.push(t1);
headers.push(paper.text(CENTER_X, CENTER_Y-15, MESSAGE_PROPERTIES_TYPES[PIE_ORDER[i]]).attr({'font-size':25,'font-family':FONT,'font-weight':'bold','fill':'#'+sliceColors[i]}));
headers2.push(paper.text(CENTER_X, CENTER_Y+25, MESSAGE_PROPERTIES_TYPES[PIE_ORDER[i]]).attr({'font-size':25,'font-family':FONT,'font-weight':'bold','fill':'#'+sliceColors[i]}));
perc1.push(t1,t2);
perc2.push(perc1);
average.push(paper.text(CENTER_X, CENTER_Y+20, Math.round((sliceData[i] / total) * 100)+'% is the average used\nby utility customers').attr({'font-size':12,'font-family':FONT,'font-weight':'normal','fill':'#000000'}));
})(i);
}
holes.push(circle,headers,headers2,perc2,instr,inProg,notStrt,average);
hideHole();
// then we build an invisible pie, layered on top of everything else
start = 0;
for (i = 0; i < SLICE_COUNT; i++) {
var val = 360 / total * sliceData[i],
j = i+SLICE_COUNT;
(function (i, j, val) {
paths
.push(paper.path()
.attr({
segment: [ CENTER_X, CENTER_Y, 1, start, start + val],
stroke: "#000",
fill:"#fff",
"stroke-width": 3,
opacity:0
})
.click(function () { // the hidden over-pie.
// click the slice
var getClass = paths[j].data('class');
if (getClass=='finished') {
// set a class, so that the hover effects don't work when the pie is spinning
paths.data('class','animating');
// reset the scale, don't want the bounce effect when the pie spins
paths.stop().transform(s1+CX_CY+'paper'+rDeg+','+CX_CY);
// get the right rotation of the pie, based on what was clicked
var z = paths[i].attr('segment');
var t = z[4]-((z[4]-z[3])/2); // should give the center line of a slice
rDeg = -t; // new rotation degree is the center of the selected slice (set this as global)
// hide the hole
hideHole();
// rotate the pie so that active slice faces the audit
paths.animate({transform: [s1+CX_CY+'paper'+rDeg+','+CX_CY]}, 700, "backOut", function(){
// remove that animating class, so hover animation works again
setTimeout(function(){
paths.data('class','finished');
paths[i].data('class','selected');
},500);
// pop the clicked slice back out
for (vi = 0; vi < SLICE_COUNT; vi++) {
paths[vi].animate({opacity:0.5}, 700, "backOut");
};
paths[i].animate({opacity:1, transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY]}, 700, "backOut");
paths[j].attr({transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY]});
// show the slice-specific tip modal
//$('.tip-container section').hide();
//$('.tip-container').show().children('section').eq(i).show();
});
}
})
.hover(
// hover over
function() {
var getClass = paths[j].data('class');
if (getClass !== 'animating') {
hideHole();
circle.rShow();
paths[i].animate({transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY]}, 200, "backOut");
paths[j].attr({transform: [s2+CX_CY+'paper'+rDeg+','+CX_CY]});
}
if (getClass == 'started') {
headers[i].rShow();
notStrt.rShow();
}
if (getClass == 'active') {
headers[i].rShow();
inProg.rShow();
}
if (getClass == 'finished' || getClass == 'selected') {
headers2[i].rShow();
perc2[i].attr({opacity:1});
}
if (getClass == undefined) {
headers[i].attr({'fill': '#888888'}).rShow();
average[i].rShow();
paths[i].animate({fill: '#888888'}, 200, "backOut");
}
},
// hover out
function() {
var getClass = paths[j].data('class');
if (getClass == 'started' || getClass == 'finished' || getClass == undefined) {
var transform = paths[j].attr('transform'); // redundant, but necessary, otherwise the rotation value is from before the slice was clicked
hideHole();
paths[i].animate({transform: [s1+CX_CY+'paper'+rDeg+','+CX_CY]}, 400, "backOut");
paths[j].attr({transform: [s1+CX_CY+'paper'+rDeg+','+CX_CY]});
}
if (getClass == 'selected') {
hideHole();
}
if (getClass == 'active') {
circle.rShow();
headers[i].rShow();
inProg.rShow();
}
if (getClass == undefined) {
paths.animate({fill: '#dddddd'}, 200, "backOut");
}
for (var vi = SLICE_COUNT; vi < (SLICE_COUNT*2); vi++) {
getClass = paths[vi].data('class');
// set the right hole back
if (getClass == 'active' ) {
circle.rShow();
headers[vi-SLICE_COUNT].rShow();
inProg.rShow();
}
}
}
));
})(i, j, val);
start += val;
}
// make-a da pie on page load
//pieAnimate(700);
pieAnimate(700,SLICE_COUNT-1);
//pieAnimate(700,auditNext);
//pieAnimate(700,auditPrev);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment