This is a typical problem you'll run into with asynchronous JavaScript code such as event handlers. The for loop in your circleCreate() function uses a variable i which it increments for each wedge. This is fine where you use i to create the wedge:
angleDeg: vangle[i],
But it fails where you use it inside the click event handler:
alert(vtext[i]);
Why is that?
When you create the wedge using the new Kinetic.Wedge() call, this is done directly inside the loop. This code runs synchronously; it uses the value of i as it exists at the very moment that this particular iteration of the loop is run.
But the click event handler doesn't run at that time. It may not run at all, if you never click. When you do click a wedge, its event handler is called at that time, long after the original loop has finished running.
So, what is the value of i when the event handler does run? It's whatever value the code left in it when it ran originally. This for loop exits when i equals vangle.length—so in other words, i is past the end of the array, and therefore vangle[i] is undefined.
You can fix this easily with a closure, by simply calling a function for each loop iteration:
var layer = new Kinetic.Layer();
function circleCreate(vangle, vradius, vcolor, vtext) {
startAngle = 0;
endAngle = 0;
for (var i = 0; i < vangle.length; i++) {
addWedge( i );
}
stage.add(layer);
function addWedge( i ) {
startAngle = endAngle;
endAngle = startAngle + vangle[i];
var wedge = new Kinetic.Wedge({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: vradius,
angleDeg: vangle[i],
fill: vcolor,
stroke: 'black',
strokeWidth: 1,
rotationDeg: startAngle
});
wedge.on('click', function() {
alert(vtext[i]);
});
layer.add(wedge);
}
}
What happens now is that calling the addWedge() function captures the value of i individually for each loop iteration. As you know, every function can have its own local variables/parameters, and the i inside addWedge() is local to that function—and specifically, local to each individual invocation of that function. (Note that because addWedge() is a function of its own, the i inside that function is not the same as the i in the outer circleCreate() function. If this is confusing, it's fine to give it a different name.)
Updated fiddle
A better way
This said, I recommend a different approach to structuring your data. As I was reading your code, the angle and text arrays caught my eye:
var anglesParents = [120, 120, 120];
var parentTextArray = ['Parent1', 'Parent2', 'Parent3'];
There are similar but lengthier pairs of arrays for children and grandchildren.
You use the values from these arrays with the vtext[i] and vangle[i] references in circleCreate().
In general, unless there's a specific reason to use parallel arrays like this, your code will become cleaner if you combine them into a single array of objects:
[
{ angle: 120, text: 'Parent1' },
{ angle: 120, text: 'Parent2' },
{ angle: 120, text: 'Parent3' }
]
For your nested cirles, we can take this a step further and combine all three rings into a single large array of objects that describes the entire set of nested rings. Where you have these arrays:
var anglesParents = [120, 120, 120];
var anglesChildren = [120, 60, 60, 60, 60];
var anglesGrandchildren = [
33.33, 20, 23.33, 43.33, 22.10, 25.26,
12.63, 28, 32, 33, 27, 36, 14.4, 9.6
];
var grandchildrenTextArray = [
'GrandCHild1', 'GrandCHild2', 'GrandCHild3', 'GrandCHild4',
'GrandCHild5', 'GrandCHild6', 'GrandCHild7', 'GrandCHild8',
'GrandCHild9', 'GrandCHild10', 'GrandCHild11', 'GrandCHild12',
'GrandCHild13', 'GrandCHild14', 'GrandCHild15', 'GrandCHild16'
];
var childrenTextArray = [
'Child1', 'Child2', 'Child3', 'Child4', 'Child5'
];
var parentTextArray = ['Parent1', 'Parent2', 'Parent3'];
It would be:
var rings = [
{
radius: 200,
color: 'grey',
slices: [
{ angle: 33.33, text: 'GrandChild1' },
{ angle: 20, text: 'GrandChild2' },
{ angle: 23.33, text: 'GrandChild3' },
{ angle: 43.33, text: 'GrandChild4' },
{ angle: 22.10, text: 'GrandChild5' },
{ angle: 25.26, text: 'GrandChild6' },
{ angle: 12.63, text: 'GrandChild7' },
{ angle: 28, text: 'GrandChild8' },
{ angle: 32, text: 'GrandChild9' },
{ angle: 33, text: 'GrandChild10' },
{ angle: 27, text: 'GrandChild10' },
{ angle: 36, text: 'GrandChild12' },
{ angle: 14.4, text: 'GrandChild13' },
{ angle: 9.6, text: 'GrandChild14' }
]
},
{
radius: 150,
color: 'darkgrey',
slices: [
{ angle: 120, text: 'Child1' },
{ angle: 60, text: 'Child2' },
{ angle: 60, text: 'Child3' },
{ angle: 60, text: 'Child4' },
{ angle: 60, text: 'Child5' }
]
},
{
radius: 100,
color: 'lightgrey',
slices: [
{ angle: 120, text: 'Parent1' },
{ angle: 120, text: 'Parent2' },
{ angle: 120, text: 'Parent3' }
]
}
];
Now this is longer than the original, what with all the angle: and text: property names, but that stuff compresses out very nicely with the gzip compression that servers and browsers use.
More importantly, it helps simplify and clarify the code and avoid errors. Did you happen to notice that your anglesGrandchildren and grandchildrenTextArray are not the same length? :-)
Using a single array of objects instead of parallel arrays prevents an error like that.
To use this data, remove the circleCreate() function and these calls to it:
circleCreate(anglesGrandchildren, 200, "grey", grandchildrenTextArray);
circleCreate(anglesChildren, 150, "darkgrey", childrenTextArray);
circleCreate(anglesParents, 100, "lightgrey", parentTextArray);
and replace them with:
function createRings( rings ) {
var startAngle = 0, endAngle = 0,
x = stage.getWidth() / 2,
y = stage.getHeight() / 2;
rings.forEach( function( ring ) {
ring.slices.forEach( function( slice ) {
startAngle = endAngle;
endAngle = startAngle + slice.angle;
var wedge = new Kinetic.Wedge({
x: x,
y: y,
radius: ring.radius,
angleDeg: slice.angle,
fill: ring.color,
stroke: 'black',
strokeWidth: 1,
rotationDeg: startAngle
});
wedge.on('click', function() {
alert(slice.text);
});
layer.add(wedge);
});
});
stage.add(layer);
}
createRings( rings );
Now this code isn't really any shorter than the original, but some of the details are more clear: slice.angle and slice.text show clearly that the angle and text belong to the same slice object, where with the original vangle[i] and vtext[i] we're left hoping that the vangle and vtext arrays are the correct matching arrays and are properly lined up with each other.
I also used .forEach() instead of a for loop; since you're using Canvas we know you are on a modern browser. One nice thing is that forEach() uses a function call, so it automatically gives you a closure.
Also, I moved the calculations of x and y outside the loop since they are the same for every wedge.
Here's the latest fiddle with this updated code and data.