This is the object I'm using to create a donut with segments that can be animated. There is a method to pass in an array of values to update the segments which then "tweens" to the new values by recreating the widget a bunch of times.
UPDATE 12/21
This method is causing a memory leak/garbage collection issues. Is there a more performant/efficient method to accomplishing this?
The memory leak was a seperate issue that was resolved. This post is primarily about finding a more efficient way to generate and animate the geometry for this mesh.
donut = function(values, inner_radius, outer_radius) {
var _inner_radius = inner_radius;
var _outer_radius = outer_radius;
var _cur_angle = 0.0;
var _sector_spacing = (Math.PI * 2) / 150.0;
var _container = 0;
var _cur_values = values.slice(0);
var _animation_speed = 0.85;
createWidget(_cur_values);
function createWidget(values) {
if ( _container != 0 ) {
var geometry_for_deletion = [];
_container.traverse(function (node) {
if (node instanceof THREE.Mesh) {
geometry_for_deletion.push(node);
}
});
for (var each = 0; each < geometry_for_deletion.length; ++each) {
geometry_for_deletion[each].parent.remove(geometry_for_deletion[each]);
}
geometry_for_deletion = null;
}
else {
_container = new THREE.Object3D();
_container.name = 'wedge_container';
}
var total_value = 0;
for (var i = 0; i < values.length; ++i) {
total_value += values[i];
};
for (var i = 0; i < values.length; ++i) {
var angle_1 = _cur_angle;
var angle_2 = _cur_angle + (values[i] / total_value) *
( Math.PI * 2 - ( values.length ) * _sector_spacing );
var mesh = createSegment(i,angle_1, angle_2, _inner_radius, outer_radius);
_container.add(mesh);
_cur_angle = angle_2 + _sector_spacing;
}
scene.add(_container);
}
function createSegment(i,begin_angle, end_angle, _inner_radius, outer_radius) {
var sector_pts = [];
var num_verts_per_arc = 16;
for (var j = 0; j < num_verts_per_arc; ++j) {
var a = begin_angle + (j / (num_verts_per_arc - 1)) * (end_angle - begin_angle);
var x = outer_radius * Math.cos(a);
var y = outer_radius * Math.sin(a);
sector_pts.push(new THREE.Vector2(x, y));
}
for (var j = 0; j < num_verts_per_arc; ++j) {
var a = end_angle - (j / (num_verts_per_arc - 1)) * (end_angle - begin_angle);
var x = _inner_radius * Math.cos(a);
var y = _inner_radius * Math.sin(a);
sector_pts.push(new THREE.Vector2(x, y));
}
var sector_shape = new THREE.Shape(sector_pts);
var geometry = new THREE.ShapeGeometry(sector_shape); //, { material: i });
geometry.name = 'wedge';
var material = new THREE.MeshBasicMaterial({
color: color,
overdraw: true
});
var segment_mesh = new THREE.Mesh(geometry, material );
return segment_mesh;
}
this.getParent = function() {
return _container;
}
this.updateValues = function(new_values) {
if ( new_values.length != values.length ) {
console.error("Different number of values in update not allowed");
return;
}
var tween_values = _cur_values.slice(0);
TweenMax.to(
{ val: 0 },
_animation_speed,
{
val: 1,
ease: Power3.easeOut,
onUpdate: function(that,tween_values,_cur_values,new_values) {
for(var i=0; i < tween_values.length;++i) {
tween_values[i] = _cur_values[i] + ( new_values[i] - _cur_values[i] ) * that.target.val;
}
createWidget(tween_values);
},
onUpdateParams: ["{self}",tween_values,_cur_values,new_values],
onComplete: function(tween_values,_cur_values) {
_cur_values = tween_values.slice(0);
},
onCompleteParams: [tween_values,_cur_values]
}
);
}
};
Usage is as follows:
var mydonut1 = new donut( [20,20,20,20,20], 75, 100 );
mydonut1.updateValues( [30,10,40,10,10] );
var mydonut2 = new donut( [20,20,20,20,20], 75, 100 );
mydonut2.updateValues( [30,10,40,10,10] );