Added multi-point string handling to the path parser. Added support for 'm' and 'Z'.

This commit is contained in:
Jason Follas
2012-05-29 13:49:11 -04:00
parent 89370bfee7
commit d0acfb14e1
2 changed files with 130 additions and 39 deletions

View File

@@ -26,7 +26,11 @@ Kinetic.Path = function(config) {
break; break;
case 'M': case 'M':
context.moveTo(p[0], p[1]); context.moveTo(p[0], p[1]);
c = 'L'; // Subsequent points are treated as lineTo
break; break;
//case 'C':
// context.bezierCurveTo(p[0], p[1], p[2], p[3], path[i].p.x, path[i].p.y);
case 'z': case 'z':
context.closePath(); context.closePath();
break; break;
@@ -51,10 +55,29 @@ Kinetic.Path.prototype = {
* rendering * rendering
*/ */
getCommandsArray: function() { getCommandsArray: function() {
// Path Data Segment must begin with a moveTo
//m (x y)+ Relative moveTo (subsequent points are treated as lineTo)
//M (x y)+ Absolute moveTo (subsequent points are treated as lineTo)
//l (x y)+ Relative lineTo
//L (x y)+ Absolute LineTo
//h (x)+ Relative horizontal lineTo
//H (x)+ Absolute horizontal lineTo
//v (y)+ Relative vertical lineTo
//V (y)+ Absolute vertical lineTo
//z (closepath)
//Z (closepath)
//c (x1 y1 x2 y2 x y)+ Relative Bezier curve
//C (x1 y1 x2 y2 x y)+ Absolute Bezier curve
//q (x1 y1 x y)+ Relative Quadratic Bezier
//Q (x1 y1 x y)+ Absolute Quadratic Bezier
// Note: SVG s,S,t,T,a,A not implemented here
// command string // command string
var cs = this.attrs.commands; var cs = this.attrs.commands;
// command chars // command chars
var cc = ['M', 'l', 'L', 'v', 'V', 'h', 'H', 'z']; var cc = ['m', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z'];
// convert white spaces to commas // convert white spaces to commas
cs = cs.replace(new RegExp(' ', 'g'), ','); cs = cs.replace(new RegExp(' ', 'g'), ',');
// create pipes so that we can split the commands // create pipes so that we can split the commands
@@ -83,44 +106,68 @@ Kinetic.Path.prototype = {
for(var i = 0; i < p.length; i++) { for(var i = 0; i < p.length; i++) {
p[i] = parseFloat(p[i]); p[i] = parseFloat(p[i]);
} }
// convert l, H, h, V, and v to L
switch(c) { while (p.length > 0)
case 'M': {
cpx = p[0]; if (isNaN(p[0])) // case for a trailing comma before next command
cpy = p[1]; break;
break;
case 'l': var cmd = undefined;
cpx += p[0];
cpy += p[1]; // convert l, H, h, V, and v to L
break; switch(c) {
case 'L': case 'm':
cpx = p[0]; cmd = 'M';
cpy = p[1]; cpx += p.shift();
break; cpy += p.shift();
case 'h': c = 'l'; // subsequent points are treated as relative lineTo
cpx += p[0]; break;
break; case 'M':
case 'H': cmd = 'M';
cpx = p[0]; cpx = p.shift();
break; cpy = p.shift();
case 'v': c = 'L'; // subsequent points are treated as absolute lineTo
cpy += p[0]; break;
break; case 'l':
case 'V': cmd = 'L';
cpy = p[0]; cpx += p.shift();
break; cpy += p.shift();
} break;
// reassign command case 'L':
if(c == 'l' || c == 'V' || c == 'v' || c == 'H' || c == 'h') { cmd = 'L';
c = 'L'; cpx = p.shift();
p[0] = cpx; cpy = p.shift();
p[1] = cpy; break;
} case 'h':
ca.push({ cmd = 'L';
command: c, cpx += p.shift();
points: p break;
}); case 'H':
} cmd = 'L';
cpx = p.shift();
break;
case 'v':
cmd = 'L';
cpy += p.shift();
break;
case 'V':
cmd = 'L';
cpy = p.shift();
break;
}
ca.push({
command: cmd || c,
points: [cpx, cpy] // Need to add additional points if curves, etc.
});
}
if (c === 'z' || c === 'Z')
ca.push( {command: 'z', points: [] });
}
return ca; return ca;
}, },
/** /**

View File

@@ -1226,6 +1226,50 @@ Test.prototype.tests = {
path.setCommands('M200,100h100v50z'); path.setCommands('M200,100h100v50z');
},
'SHAPE - moveTo with implied lineTos and trailing comma': function(containerId) {
var stage = new Kinetic.Stage({
container: containerId,
width: 1024,
height: 480,
scale: 0.5,
x: 50,
y: 10
});
var layer = new Kinetic.Layer();
var path = new Kinetic.Path({
commands: 'm200,100,100,0,0,50,z',
fill: '#fcc',
stroke: '#333',
strokeWidth: 2,
shadow: {
color: 'maroon',
blur: 2,
offset: [10, 10],
alpha: 0.5
},
draggable: true
});
path.on('mouseover', function() {
this.setFill('red');
layer.draw();
});
path.on('mouseout', function() {
this.setFill('#ccc');
layer.draw();
});
layer.add(path);
stage.add(layer);
test(path.getCommands() === 'm200,100,100,0,0,50,z', 'commands are incorrect');
test(path.getCommandsArray().length === 4, 'commands array should have 4 elements');
test(path.getCommandsArray()[1].command === 'L', 'second command should be an implied lineTo');
}, },
'SHAPE - add map path': function(containerId) { 'SHAPE - add map path': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({