Skip to content

Instantly share code, notes, and snippets.

@jgermade
Created January 15, 2018 16:10
Show Gist options
  • Save jgermade/66fcc78af0ca50ecb2ff5b02e604eaa5 to your computer and use it in GitHub Desktop.
Save jgermade/66fcc78af0ca50ecb2ff5b02e604eaa5 to your computer and use it in GitHub Desktop.
var path_setters = {
radio: function (path, radio) {
path.el.setAttribute('r', radio );
},
stroke_color: function (path, stroke_color) {
path.stroke_color = stroke_color || 'transparent';
path.el.style.stroke = stroke_color;
},
stroke_width: function (path, stroke_width) {
path.stroke_width = stroke_width || 0;
path.el.style.strokeWidth = path.stroke_width;
},
fill_color: function (path, fill_color) {
path.fill_color = fill_color || 'transparent';
path.el.style.fill = path.fill_color;
},
}, animation_duration = 500,
_find = function (list, iteratee, this_arg) {
for( var i = 0, n = list.length ; i < n ; i++ ) {
if( iteratee.call(this_arg, list[i], i) ) return list[i];
}
},
_remove = function (list, iteratee, this_arg) {
for( var i = list.length - 1 ; i >= 0 ; i-- ) {
if( iteratee.call(this_arg, list[i], i) ) list.splice(i, 1);
}
};
_remove.item = function (list, item) {
for( var i = list.length - 1 ; i >= 0 ; i-- ) {
if( item === list[i] ) list.splice(i, 1);
}
};
var setTransform = new Function ('style', 'transition', (function () {
var style = document.body.style,
src = '';
['webkitTransition', 'mozTransition', 'msTransition', 'transition'].forEach(function (key) {
if( key in style ) src += 'style.' + key + ' = transition;\n';
});
['webkitTransform', 'mozTransform', 'msTransform', 'transform'].forEach(function (key) {
if( key in style ) src += 'style.' + key + ' = \'translateZ(0) rotate(-90deg)\';\n';
});
['webkitTransformOrigin', 'mozTransformOrigin', 'msTransformOrigin', 'transformOrigin'].forEach(function (key) {
if( key in style ) src += 'style.' + key + ' = \'50% 50%\';\n';
});
return src;
})() );
function _initPath (path, view_box, stroke_color, stroke_width, radio, fill_color) {
path.el = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
setTransform( path.el.style, 'all ' + animation_duration + 'ms ease' );
path.el.setAttribute('cx', view_box/2 );
path.el.setAttribute('cy', view_box/2 );
path_setters.radio(path, radio);
path_setters.stroke_color(path, stroke_color);
path_setters.stroke_width(path, stroke_width);
path_setters.fill_color(path, fill_color);
path.len = 2*Math.PI*radio;
}
function Path (view_box, stroke_color, stroke_width, radio, fill_color) {
view_box = view_box || 200;
stroke_width = stroke_width || view_box/2;
_initPath(this, view_box, stroke_color, stroke_width, radio || (view_box - (stroke_width || 0))/2, fill_color );
}
Path.prototype.morph = function (stroke_color, stroke_width, radio, fill_color) {
var path = this;
setTimeout(function () {
if( radio !== null ) path_setters.radio(path, radio);
if( stroke_color !== null ) path_setters.stroke_color(path, stroke_color);
if( stroke_width !== null ) path_setters.stroke_width(path, stroke_width);
if( fill_color !== null ) path_setters.fill_color(path, fill_color);
}, 0);
};
Path.prototype.draw = function (portion, offset) {
offset = offset || 0;
this.el.setAttribute('stroke-dashoffset', pieOffset(offset, this.len) );
this.el.setAttribute('stroke-dasharray', pieArray(portion, this.len) );
return offset + portion;
};
function createSVG (options) {
this.options = options;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('version', '1.1');
svg.setAttribute('viewBox', '0 0 ' + options.view_box + ' ' + options.view_box);
if( options.width ) svg.setAttribute('width', options.width );
if( options.height ) svg.setAttribute('height', options.height );
return svg;
}
function pieOffset (offset, pie_len) {
return -(offset*pie_len);
}
function pieArray (len, pie_len) {
return (len*pie_len) + ' ' + pie_len;
}
function PieChart (options) {
options = Object.create(options || {});
this.options = options;
options.view_box = options.view_box || options.size || 200;
if( options.size ) {
options.width = options.width || options.view_box;
options.height = options.height || options.view_box;
}
this.el = createSVG(options);
}
function _insert (list, index, item) {
return list.splice(0, index).concat(item).concat( list.splice(0) );
}
function _updatePaths (pie, inbound_paths, current_paths, offset, inbound_path, current_path) {
var path;
inbound_path = inbound_path || inbound_paths.shift();
current_path = current_path || current_paths.shift();
if( !inbound_path ) {
if( current_path ) {
_updatePaths(pie, inbound_paths, current_paths );
current_path.value = null;
return;
} else return;
}
if( !current_path ) {
path = Object.create(inbound_path);
path.dom = new Path(pie.options.view_box, inbound_path.color, pie.options.stroke_width );
path.dom.draw(0, offset);
pie.el.appendChild(path.dom.el);
pie.paths.push(path);
_updatePaths(pie, inbound_paths, current_paths, offset );
return;
}
if( inbound_path.color === current_path.color ) {
offset += current_path.value/pie.total;
current_path.value = inbound_path.value;
_updatePaths(pie, inbound_paths, current_paths, offset );
} else if( _find(current_paths, function (path) {
return path.color === inbound_path.color;
}) ) {
offset += current_path.value/pie.total;
current_path.value = null;
_updatePaths(pie, inbound_paths, current_paths, offset, inbound_path );
} else {
path = Object.create(inbound_path);
path.dom = new Path(pie.options.view_box, inbound_path.color, pie.options.stroke_width );
path.dom.draw(0, offset );
pie.el.insertBefore(path.dom.el, current_path.dom.el);
pie.paths = _insert( pie.paths, pie.paths.indexOf(current_path), path );
_updatePaths(pie, inbound_paths, current_paths, offset, null, current_path );
}
}
PieChart.prototype.updatePaths = function (paths) {
var pie = this, total, offset = 0;
// console.log('updatePaths', paths, total);
if( pie.paths ) {
total = pie.paths.reduce(function (total, path) { return total + path.value || 0; }, 0),
pie.total = total;
_updatePaths(pie, paths.slice(), pie.paths.slice(), 0 );
total = pie.paths.reduce(function (total, path) { return total + (path.value || 0); }, 0);
setTimeout(function () {
pie.paths.forEach(function (path) {
if( path.value === null ) {
path.dom.draw(0, offset);
setTimeout(function () {
pie.el.removeChild(path.dom.el);
_remove.item( pie.paths, path );
}, animation_duration);
} else {
offset = path.dom.draw(path.value/total, offset);
}
});
}, 0);
} else {
total = paths.reduce(function (total, path) { return total + path.value || 0; }, 0),
pie.paths = [];
paths.forEach(function (path) {
path = Object.create(path);
path.dom = new Path(pie.options.view_box, path.color, pie.options.stroke_width );
// var path = new Path(pie.options.view_box, _path.color, pie.options.stroke_width );
offset = path.dom.draw(path.value/total, offset);
pie.paths.push(path);
pie.el.appendChild(path.dom.el);
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment