diff --git a/README.md b/README.md index 8a3365c..dbc2b73 100644 --- a/README.md +++ b/README.md @@ -137,17 +137,35 @@ const b = [ const interpolator = interpolatePathCommands(a, b); -let result = interpolator(0); -/* => [ +> interpolator(0); +[ { type: 'M', x: 0, y: 0 }, { type: 'L', x: 5, y: 5 }, { type: 'L', x: 10, y: 10 }, -] */ +] -result = interpolator(0.5); -/* => [ +> interpolator(0.5); +[ { type: 'M', x: 5, y: 5 }, { type: 'L', x: 12.5, y: 12.5 }, { type: 'L', x: 105, y: 105 }, -] */ +] +``` + + + +# pathCommandsFromString(*pathDString*) + +Converts a path `d` string into an array of path command objects to work with [**interpolatePathCommands**](#interpolatePathCommands). + +Example usage: + +```js +const a = 'M0,0L10,10'; + +> pathCommandsFromString(a) +[ + { type: 'M', x: 0, y: 0 }, + { type: 'L', x: 10, y: 10 }, +] ``` diff --git a/docs/d3-interpolate-path.js b/docs/d3-interpolate-path.js index 2722878..c96be2a 100644 --- a/docs/d3-interpolate-path.js +++ b/docs/d3-interpolate-path.js @@ -294,7 +294,7 @@ function splitCurve(commandStart, commandEnd, segmentCount) { return splitCurveAsPoints(points, segmentCount).map(pointsToCommand); } -var commandTokenRegex = /[MLCSTQAHVmlcstqahv]|-?[\d.e+-]+/g; +var commandTokenRegex = /[MLCSTQAHVZmlcstqahv]|-?[\d.e+-]+/g; /** * List of params for each command type in a path `d` attribute */ @@ -308,7 +308,8 @@ var typeMap = { S: ['x2', 'y2', 'x', 'y'], Q: ['x1', 'y1', 'x', 'y'], T: ['x', 'y'], - A: ['rx', 'ry', 'xAxisRotation', 'largeArcFlag', 'sweepFlag', 'x', 'y'] + A: ['rx', 'ry', 'xAxisRotation', 'largeArcFlag', 'sweepFlag', 'x', 'y'], + Z: [] }; // Add lower case entries too matching uppercase (e.g. 'm' == 'M') Object.keys(typeMap).forEach(function (key) { @@ -522,7 +523,7 @@ function extend(commandsToExtend, referenceCommands, excludeSegment) { */ -function makeCommands(d) { +function pathCommandsFromString(d) { // split into valid tokens var tokens = (d || '').match(commandTokenRegex) || []; var commands = []; @@ -568,7 +569,6 @@ function makeCommands(d) { * @returns {Function} Interpolation function that maps t ([0, 1]) to an array of path commands. */ - function interpolatePathCommands(aCommandsInput, bCommandsInput, excludeSegment) { // make a copy so we don't mess with the input arrays var aCommands = aCommandsInput == null ? [] : aCommandsInput.slice(); @@ -578,7 +578,7 @@ function interpolatePathCommands(aCommandsInput, bCommandsInput, excludeSegment) return function nullInterpolator() { return []; }; - } // do we add Z during interpolation? yes if either one has it. (we'd expect both to have it or not) + } // do we add Z during interpolation? yes if both have it. (we'd expect both to have it or not) var addZ = (aCommands.length === 0 || aCommands[aCommands.length - 1].type === 'Z') && (bCommands.length === 0 || bCommands[bCommands.length - 1].type === 'Z'); // we temporarily remove Z @@ -638,7 +638,7 @@ function interpolatePathCommands(aCommandsInput, bCommandsInput, excludeSegment) if (t > 0) { for (var i = 0; i < interpolatedCommands.length; ++i) { - if (interpolatedCommands[i].type === 'Z') continue; + // if (interpolatedCommands[i].type === 'Z') continue; var aCommand = aCommands[i]; var bCommand = bCommands[i]; var interpolatedCommand = interpolatedCommands[i]; @@ -681,9 +681,8 @@ function interpolatePathCommands(aCommandsInput, bCommandsInput, excludeSegment) */ function interpolatePath(a, b, excludeSegment) { - // note this removes Z - var aCommands = makeCommands(a); - var bCommands = makeCommands(b); + var aCommands = pathCommandsFromString(a); + var bCommands = pathCommandsFromString(b); if (!aCommands.length && !bCommands.length) { return function nullInterpolator() { @@ -691,7 +690,6 @@ function interpolatePath(a, b, excludeSegment) { }; } - var addZ = (a == null || a[a.length - 1] === 'Z') && (b == null || b[b.length - 1] === 'Z'); var commandInterpolator = interpolatePathCommands(aCommands, bCommands, excludeSegment); return function pathStringInterpolator(t) { // at 1 return the final value without the extensions used during interpolation @@ -717,16 +715,13 @@ function interpolatePath(a, b, excludeSegment) { _iterator2.f(); } - if (addZ) { - interpolatedString += 'Z'; - } - return interpolatedString; }; } exports.interpolatePath = interpolatePath; exports.interpolatePathCommands = interpolatePathCommands; +exports.pathCommandsFromString = pathCommandsFromString; Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/index.js b/index.js index 0e9c5c5..a99f00f 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ export { default as interpolatePath, interpolatePathCommands, + pathCommandsFromString, } from './src/interpolatePath'; diff --git a/src/interpolatePath.js b/src/interpolatePath.js index 3125baf..78a0101 100644 --- a/src/interpolatePath.js +++ b/src/interpolatePath.js @@ -1,6 +1,6 @@ import splitCurve from './split'; -const commandTokenRegex = /[MLCSTQAHVmlcstqahv]|-?[\d.e+-]+/g; +const commandTokenRegex = /[MLCSTQAHVZmlcstqahv]|-?[\d.e+-]+/g; /** * List of params for each command type in a path `d` attribute */ @@ -14,6 +14,7 @@ const typeMap = { Q: ['x1', 'y1', 'x', 'y'], T: ['x', 'y'], A: ['rx', 'ry', 'xAxisRotation', 'largeArcFlag', 'sweepFlag', 'x', 'y'], + Z: [], }; // Add lower case entries too matching uppercase (e.g. 'm' == 'M') @@ -264,7 +265,7 @@ function extend(commandsToExtend, referenceCommands, excludeSegment) { * * @param {String|null} d A path `d` string */ -function makeCommands(d) { +export function pathCommandsFromString(d) { // split into valid tokens const tokens = (d || '').match(commandTokenRegex) || []; const commands = []; @@ -329,7 +330,7 @@ export function interpolatePathCommands( }; } - // do we add Z during interpolation? yes if either one has it. (we'd expect both to have it or not) + // do we add Z during interpolation? yes if both have it. (we'd expect both to have it or not) const addZ = (aCommands.length === 0 || aCommands[aCommands.length - 1].type === 'Z') && (bCommands.length === 0 || bCommands[bCommands.length - 1].type === 'Z'); @@ -390,7 +391,7 @@ export function interpolatePathCommands( // we can skip at t=0 since we copied aCommands to begin if (t > 0) { for (let i = 0; i < interpolatedCommands.length; ++i) { - if (interpolatedCommands[i].type === 'Z') continue; + // if (interpolatedCommands[i].type === 'Z') continue; const aCommand = aCommands[i]; const bCommand = bCommands[i]; @@ -425,9 +426,8 @@ export function interpolatePathCommands( * @returns {Function} Interpolation function that maps t ([0, 1]) to a path `d` string. */ export default function interpolatePath(a, b, excludeSegment) { - // note this removes Z - let aCommands = makeCommands(a); - let bCommands = makeCommands(b); + let aCommands = pathCommandsFromString(a); + let bCommands = pathCommandsFromString(b); if (!aCommands.length && !bCommands.length) { return function nullInterpolator() { @@ -435,10 +435,6 @@ export default function interpolatePath(a, b, excludeSegment) { }; } - const addZ = - (a == null || a[a.length - 1] === 'Z') && - (b == null || b[b.length - 1] === 'Z'); - const commandInterpolator = interpolatePathCommands( aCommands, bCommands, @@ -458,9 +454,6 @@ export default function interpolatePath(a, b, excludeSegment) { for (const interpolatedCommand of interpolatedCommands) { interpolatedString += commandToString(interpolatedCommand); } - if (addZ) { - interpolatedString += 'Z'; - } return interpolatedString; }; diff --git a/test/interpolatePathCommands-test.js b/test/interpolatePathCommands-test.js index 3c3f63c..f896cc5 100644 --- a/test/interpolatePathCommands-test.js +++ b/test/interpolatePathCommands-test.js @@ -78,8 +78,6 @@ tape( { type: 'L', x: 20, y: 20 }, ]; - ('M10,10L20,20'); - const interpolator = interpolatePathCommands(aCommands, bCommands); t.same(interpolator(0), aCommands);