Created
May 21, 2014 21:28
-
-
Save mrsweaters/023a5bd9ba1aed5fc54a to your computer and use it in GitHub Desktop.
Custom Pizza Line Labels
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$.extend(Pizza, { | |
line : function (legend) { | |
var settings = legend.data('settings'), | |
svg = this.svg(legend, settings), | |
container = $(this.identifier(legend)), | |
width = container.outerWidth(), | |
height = container.outerHeight(), | |
data = legend.data('graph-data'), | |
max_x = max_y = min_x = min_y = total_x = total_y = 0, | |
i = data.length, | |
points = ''; | |
for (var i = 0; i < data.length; i++) { | |
if (data[i].x > max_x) max_x = data[i].x; | |
if (data[i].y > max_y) max_y = data[i].y; | |
if (min_x > data[i].x) min_x = data[i].x; | |
if (min_y > data[i].y) min_y = data[i].y; | |
total_x += data[i].x; | |
total_y += data[i].y; | |
} | |
var existing_group = $('g[data-id=line]', svg); | |
if (existing_group.length > 0) { | |
var line_g = $('g[data-id=line]', svg)[0], | |
circle_g = $('g[data-id=points]', svg)[0], | |
polyline = $('path[data-id=path]', line_g)[0]; | |
} else { | |
var polyline = this.svg_obj('path'), | |
line_g = this.svg_obj('g'), | |
circle_g = this.svg_obj('g'); | |
line_g.setAttribute('data-id', 'line'); | |
circle_g.setAttribute('data-id', 'points'); | |
polyline.setAttribute('data-id', 'path'); | |
} | |
for (var i = 0; i < data.length; i++) { | |
if (existing_group.length > 0) { | |
var circle = $('circle[data-id=c' + i + ']', circle_g)[0]; | |
} else { | |
var circle = this.svg_obj('circle'); | |
circle.setAttribute('data-id', 'c' + i); | |
} | |
var x = (data[i].x / max_x) * width, | |
y = (data[i].y / max_y) * height; | |
points += x + ',' + y + ' '; | |
this.set_attr(circle, {cx: x, cy: y,r: 0,fill: data[i.color], | |
'data-value': data[i].x + ', ' + data[i].y, | |
'data-tooltip': '', | |
'title': data[i].x + ', ' + data[i].y, | |
'class': 'has-tip tip-top'}); | |
Snap(circle).animate({ | |
r: 4 | |
}, 1500, mina[settings.animation_type]); | |
this.animate(Snap(circle), x, y, settings, 2); | |
if (existing_group.length < 1) { | |
circle_g.appendChild(circle); | |
} | |
} | |
this.flip(circle_g, height); | |
this.flip(line_g, height); | |
if (settings.show_grid) { | |
if (settings.line_no_x_labels) { | |
this.assemble_grid_x(svg, min_x, max_x, width, height, settings, data.labelX); | |
} | |
if (settings.line_no_y_labels) { | |
this.assemble_grid_y(svg, min_y, max_y, width, height, settings, data.labelY); | |
} | |
} | |
var v = this.points_to_path(points); | |
this.set_attr(polyline, {d:v, fill: 'none', stroke: 'black', 'stroke-width': 2}); | |
if (existing_group.length < 1) { | |
line_g.appendChild(polyline); | |
svg.appendChild(line_g); | |
} | |
if (existing_group.length < 1) { | |
svg.appendChild(circle_g); | |
} | |
return [legend, svg]; | |
}, | |
assemble_grid_x : function (svg, min, max, width, height, settings, labelX) { | |
var existing_group = $('g[data-id=gridx]', svg); | |
if (existing_group.length > 0) { | |
var line_g = existing_group[0], | |
text_g = $('g[data-id=labelx]', svg)[0]; | |
} else { | |
var line_g = this.svg_obj('g'), | |
text_g = this.svg_obj('g'); | |
line_g.setAttribute('data-id', 'gridx'); | |
text_g.setAttribute('data-id', 'labelx'); | |
} | |
var ticks = this.ticks(min, max, settings.bar_intervals).reverse(), | |
ticks_length = i = ticks.length, | |
total_tick_width = 0, | |
interval = width/(ticks_length-1); | |
while (i--) { | |
if (existing_group.length > 0) { | |
var line = $('line[data-id=l' + i + ']', line_g)[0], | |
text = $('text[data-id=t' + i + ']', text_g)[0]; | |
} else { | |
var line = this.svg_obj('line'), | |
text = this.svg_obj('text'); | |
line.setAttribute('data-id', 'l' + i); | |
text.setAttribute('data-id', 't' + i); | |
} | |
var line_width = total_tick_width + interval; | |
this.set_attr(line, { | |
x1 : line_width, | |
x2 : line_width, | |
y1 : 0, | |
y2 : height, | |
stroke : 'gray', | |
'stroke-width' : 1, | |
'stroke-dasharray' : '5,5' | |
}) | |
.set_attr(text, { | |
y: height + 20, | |
x: line_width - interval, | |
'text-anchor': 'middle' | |
}); | |
if (existing_group.length < 1) { | |
text.innerHTML = labelX || ticks[i]; | |
text_g.appendChild(text); | |
line_g.appendChild(line); | |
} | |
total_tick_width = line_width; | |
} | |
line_g.setAttribute('transform', 'translate(-' + interval + ', 0)'); | |
if (existing_group.length < 1) { | |
svg.appendChild(line_g); | |
svg.appendChild(text_g); | |
} | |
}, | |
assemble_grid_y : function (svg, min, max, width, height, settings, labelY) { | |
var existing_group = $('g[data-id=gridy]', svg); | |
if (existing_group.length > 0) { | |
var line_g = existing_group[0], | |
text_g = $('g[data-id=labely]', svg)[0]; | |
} else { | |
var line_g = this.svg_obj('g'), | |
text_g = this.svg_obj('g'); | |
line_g.setAttribute('data-id', 'gridy'); | |
text_g.setAttribute('data-id', 'labely'); | |
} | |
var ticks = this.ticks(min, max, settings.bar_intervals), | |
ticks_length = i = ticks.length, | |
total_tick_height = 0; | |
while (i--) { | |
if (existing_group.length > 0) { | |
var line = $('line[data-id=l' + i + ']', line_g)[0], | |
text = $('text[data-id=t' + i + ']', text_g)[0]; | |
} else { | |
var line = this.svg_obj('line'), | |
text = this.svg_obj('text'); | |
line.setAttribute('data-id', 'l' + i); | |
text.setAttribute('data-id', 't' + i); | |
} | |
var line_height = total_tick_height + (height/(ticks_length-1)); | |
this.set_attr(line, { | |
x1 : 0, | |
x2 : width, | |
y1 : line_height, | |
y2 : line_height, | |
stroke : 'gray', | |
'stroke-width' : 1, | |
'stroke-dasharray' : '5,5' | |
}) | |
.set_attr(text, { | |
x : -8, | |
y : line_height + 5, | |
'text-anchor': 'end' | |
}); | |
if (existing_group.length < 1) { | |
text_g.appendChild(text); | |
line_g.appendChild(line); | |
text.innerHTML = labelY || ticks[i]; | |
} | |
total_tick_height = line_height; | |
} | |
line_g.setAttribute('transform', 'translate(0, -' + total_tick_height / ticks_length + ')'); | |
text_g.setAttribute('transform', 'translate(0, -' + total_tick_height / ticks_length + ')'); | |
if (existing_group.length < 1) { | |
svg.appendChild(line_g); | |
svg.appendChild(text_g); | |
} | |
}, | |
points_to_path : function (points) { | |
var points = points.split(/\s+|,/); | |
var x0=points.shift(), y0=points.shift(); | |
var pathdata = 'M'+x0+','+y0+'L'+points.join(' '); | |
return ['M'+x0+','+y0+'L'].concat(points).join(' '); | |
}, | |
line_events : function () { | |
$(this.scope).on('mouseenter.pizza mouseleave.pizza touchstart.pizza', '[data-line-id] li', function (e) { | |
var parent = $(this).parent(), | |
path = $('#' + parent.data('line-id') + ' circle[data-id="c' + $(this).index() + '"]')[0], | |
settings = $(this).parent().data('settings'); | |
if (/start/i.test(e.type)) { | |
$(path).siblings('circle').each(function () { | |
if (this.nodeName) { | |
Snap(path).animate({ | |
transform: 's1 1 ' + path.getAttribute('cx') + ' ' + path.getAttribute('cy') | |
}, settings.animation_speed, mina[settings.animation_type]); | |
} | |
}); | |
} | |
if (/enter|start/i.test(e.type)) { | |
Snap(path).animate({ | |
transform: 's2 2 ' + path.getAttribute('cx') + ' ' + path.getAttribute('cy') | |
}, settings.animation_speed, mina[settings.animation_type]); | |
$(path).trigger('mouseenter') | |
} else { | |
Snap(path).animate({ | |
transform: 's1 1 ' + path.getAttribute('cx') + ' ' + path.getAttribute('cy') | |
}, settings.animation_speed, mina[settings.animation_type]); | |
$(path).trigger('mouseout') | |
} | |
}); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Pizza = { | |
version : '0.2.2', | |
settings : { | |
donut: false, | |
donut_inner_ratio: 0.4, // between 0 and 1 | |
percent_offset: 35, // relative to radius | |
show_text: true, // show or hide the percentage on the chart. | |
animation_speed: 500, | |
always_show_text: false, | |
show_grid: true, | |
bar_spacer: 100, | |
bar_intervals: 6, | |
line_no_y_labels: true, | |
line_no_x_labels: false, | |
animation_type: 'elastic' // options: backin, backout, bounce, easein, | |
// easeinout, easeout, linear | |
}, | |
NS : 'http://www.w3.org/2000/svg', | |
init : function (scope, options) { | |
var self = this; | |
this.scope = scope || document.body; | |
var charts = $('[data-pie-id], [data-line-id], [data-bar-id]', this.scope); | |
$.extend(true, this.settings, options); | |
if (charts.length > 0) { | |
charts.each(function () { | |
return self.build($(this), options); | |
}); | |
} else if ($(this.scope).is('[data-pie-id]') | |
|| $(this.scope).is('[data-line-id]') | |
|| $(this.scope).is('[data-bar-id]')) { | |
this.build($(this.scope), options); | |
} | |
this.events(); | |
}, | |
events : function () { | |
var self = this; | |
$(window).off('.pizza').on('resize.pizza', self.throttle(function () { | |
self.init(); | |
}, 500)); | |
$(this.scope).off('.pizza'); | |
this.pie_events(); | |
this.line_events(); | |
this.bar_events(); | |
}, | |
build : function(legend, options) { | |
legend.data('settings', $.extend({}, this.settings, options, legend.data('options'))); | |
this.data(legend, options || {}); | |
if (legend.data('pie-id')) { | |
this.update_DOM(this.pie(legend)); | |
} else if (legend.data('line-id')) { | |
this.update_DOM(this.line(legend)); | |
} else if (legend.data('bar-id')) { | |
this.update_DOM(this.bar(legend)); | |
} | |
}, | |
data : function (legend, options) { | |
var data = [], | |
count = 0; | |
$('li', legend).each(function () { | |
var segment = $(this); | |
if (options.data) { | |
data.push({ | |
value: options.data[segment.index()], | |
text: segment.data('text'), | |
color: segment.css('color'), | |
segment: segment | |
}); | |
} else { | |
data.push({ | |
x : segment.data('x'), | |
y : segment.data('y'), | |
labelX: segment.data('label-x'), | |
labelY: segment.data('label-y'), | |
value: segment.data('value'), | |
text: segment.data('text'), | |
color: segment.css('color'), | |
segment: segment | |
}); | |
} | |
}); | |
return legend.data('graph-data', data); | |
}, | |
update_DOM : function (parts) { | |
var legend = parts[0], | |
graph = parts[1]; | |
return $(this.identifier(legend)).html(graph); | |
}, | |
animate : function (el, cx, cy, settings, scale) { | |
var self = this, | |
scale = scale || 1.05; | |
el.hover(function (e) { | |
var path = Snap(e.target), | |
text = Snap(path.node.nextSibling); | |
path.animate({ | |
transform: 's' + scale + ' ' + scale + ' ' + cx + ' ' + cy | |
}, settings.animation_speed, mina[settings.animation_type]); | |
if (!/text/.test(text.node.nodeName)) return; | |
text.touchend(function () { | |
Snap(path).animate({ | |
transform: 's' + scale + ' ' + scale + ' ' + cx + ' ' + cy | |
}, settings.animation_speed, mina[settings.animation_type]); | |
}); | |
if (settings.show_text) { | |
text.animate({ | |
opacity: 1 | |
}, settings.animation_speed); | |
text.touchend(function () { | |
text.animate({ | |
opacity: 1 | |
}, settings.animation_speed); | |
}); | |
} | |
}, function (e) { | |
var path = Snap(e.target), | |
text = Snap(path.node.nextSibling); | |
path.animate({ | |
transform: 's1 1 ' + cx + ' ' + cy | |
}, settings.animation_speed, mina[settings.animation_type]); | |
if (!/text/.test(text.node.nodeName)) return; | |
text.animate({ | |
opacity: 0 | |
}, settings.animation_speed); | |
}); | |
}, | |
parse_options : function (string, percent, value) { | |
var percentStr = Math.ceil(percent) + '%', | |
output = string.replace(/{{ *percent *}}/ig, percentStr) | |
.replace(/{{ *value *}}/ig, value); | |
return output; | |
}, | |
svg : function (legend, settings) { | |
var container = $(this.identifier(legend)), | |
svg = $('svg', container), | |
width = container.width(), | |
pie = legend.attr('data-pie-id'), | |
height = container.height(); | |
if (svg.length > 0) { | |
svg = svg[0]; | |
} else { | |
var svg = this.svg_obj('svg'); | |
svg.width = width; | |
svg.height = height; | |
} | |
if (pie) { | |
var view_box = '-' + settings.percent_offset + ' -' + settings.percent_offset + ' ' + | |
(width + (settings.percent_offset * 1.5)) + ' ' + | |
(width + (settings.percent_offset * 1.5)); | |
} else { | |
var view_box = '-' + settings.percent_offset + ' -' + settings.percent_offset + ' ' + | |
(width + (settings.percent_offset * 1.6)) + ' ' + | |
(height + (settings.percent_offset * 1.6)); | |
} | |
this.set_attr(svg, {width: '100%', height: '100%', viewBox: view_box}); | |
return svg; | |
}, | |
identifier : function (legend) { | |
id = legend.data('pie-id') || legend.data('bar-id') || legend.data('line-id'); | |
return '#' + id; | |
}, | |
throttle : function(fun, delay) { | |
var timer = null; | |
return function () { | |
var context = this, args = arguments; | |
clearTimeout(timer); | |
timer = setTimeout(function () { | |
fun.apply(context, args); | |
}, delay); | |
}; | |
}, | |
svg_obj : function (type) { | |
return document.createElementNS(this.NS, type); | |
}, | |
ticks: function (min, max, count) { | |
var span = max - min, | |
step = Math.pow(10, Math.floor(Math.log(span / count) / Math.LN10)), | |
err = count / span * step; | |
// Filter ticks to get closer to the desired count. | |
if (err <= .15) step *= 10; | |
else if (err <= .35) step *= 5; | |
else if (err <= .75) step *= 2; | |
// Round start and stop values to step interval. | |
var tstart = Math.ceil(min / step) * step, | |
tstop = Math.floor(max / step) * step + step * .5, | |
ticks = [], | |
x; | |
// now generate ticks | |
for (i=tstart; i < tstop; i += step) { | |
ticks.push(i); | |
} | |
return ticks; | |
}, | |
set_attr : function (node, attrs) { | |
for (attr in attrs) { | |
node.setAttribute(attr, attrs[attr]); | |
} | |
return this; | |
}, | |
flip : function (node, h) { | |
node.setAttribute('transform', 'translate(0, ' + h +') scale(1, -1)'); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment