normalize-svg-path
Advanced tools
Comparing version 0.1.0 to 1.0.0
288
index.js
@@ -0,200 +1,122 @@ | ||
'use strict' | ||
var π = Math.PI | ||
var _120 = radians(120) | ||
module.exports = normalize | ||
/** | ||
* describe `path` in terms of cubic bézier | ||
* curves and move commands | ||
* | ||
* @param {Array} path | ||
* @return {Array} | ||
*/ | ||
var arcToCurve = require('svg-arc-to-cubic-bezier').default | ||
function normalize(path){ | ||
// init state | ||
var prev | ||
var result = [] | ||
var bezierX = 0 | ||
var bezierY = 0 | ||
var startX = 0 | ||
var startY = 0 | ||
var quadX = null | ||
var quadY = null | ||
var x = 0 | ||
var y = 0 | ||
// init state | ||
var prev | ||
var result = [] | ||
var bezierX = 0 | ||
var bezierY = 0 | ||
var startX = 0 | ||
var startY = 0 | ||
var quadX = null | ||
var quadY = null | ||
var x = 0 | ||
var y = 0 | ||
for (var i = 0, len = path.length; i < len; i++) { | ||
var seg = path[i] | ||
var command = seg[0] | ||
switch (command) { | ||
case 'M': | ||
startX = seg[1] | ||
startY = seg[2] | ||
break | ||
case 'A': | ||
seg = arc(x, y,seg[1],seg[2],radians(seg[3]),seg[4],seg[5],seg[6],seg[7]) | ||
// split multi part | ||
seg.unshift('C') | ||
if (seg.length > 7) { | ||
result.push(seg.splice(0, 7)) | ||
seg.unshift('C') | ||
} | ||
break | ||
case 'S': | ||
// default control point | ||
var cx = x | ||
var cy = y | ||
if (prev == 'C' || prev == 'S') { | ||
cx += cx - bezierX // reflect the previous command's control | ||
cy += cy - bezierY // point relative to the current point | ||
} | ||
seg = ['C', cx, cy, seg[1], seg[2], seg[3], seg[4]] | ||
break | ||
case 'T': | ||
if (prev == 'Q' || prev == 'T') { | ||
quadX = x * 2 - quadX // as with 'S' reflect previous control point | ||
quadY = y * 2 - quadY | ||
} else { | ||
quadX = x | ||
quadY = y | ||
} | ||
seg = quadratic(x, y, quadX, quadY, seg[1], seg[2]) | ||
break | ||
case 'Q': | ||
quadX = seg[1] | ||
quadY = seg[2] | ||
seg = quadratic(x, y, seg[1], seg[2], seg[3], seg[4]) | ||
break | ||
case 'L': | ||
seg = line(x, y, seg[1], seg[2]) | ||
break | ||
case 'H': | ||
seg = line(x, y, seg[1], y) | ||
break | ||
case 'V': | ||
seg = line(x, y, x, seg[1]) | ||
break | ||
case 'Z': | ||
seg = line(x, y, startX, startY) | ||
break | ||
} | ||
for (var i = 0, len = path.length; i < len; i++) { | ||
var seg = path[i] | ||
var command = seg[0] | ||
// update state | ||
prev = command | ||
x = seg[seg.length - 2] | ||
y = seg[seg.length - 1] | ||
if (seg.length > 4) { | ||
bezierX = seg[seg.length - 4] | ||
bezierY = seg[seg.length - 3] | ||
} else { | ||
bezierX = x | ||
bezierY = y | ||
} | ||
result.push(seg) | ||
} | ||
switch (command) { | ||
case 'M': | ||
startX = seg[1] | ||
startY = seg[2] | ||
break | ||
case 'A': | ||
var curves = arcToCurve({ | ||
px: x, | ||
py: y, | ||
cx: seg[6], | ||
cy: seg[7], | ||
rx: seg[1], | ||
ry: seg[2], | ||
xAxisRotation: seg[3], | ||
largeArcFlag: seg[4], | ||
sweepFlag: seg[5] | ||
}) | ||
return result | ||
} | ||
// null-curves | ||
if (!curves.length) continue | ||
function line(x1, y1, x2, y2){ | ||
return ['C', x1, y1, x2, y2, x2, y2] | ||
} | ||
for (var j = 0, c; j < curves.length; j++) { | ||
c = curves[j] | ||
seg = ['C', c.x1, c.y1, c.x2, c.y2, c.x, c.y] | ||
if (j < curves.length - 1) result.push(seg) | ||
} | ||
function quadratic(x1, y1, cx, cy, x2, y2){ | ||
return [ | ||
'C', | ||
x1/3 + (2/3) * cx, | ||
y1/3 + (2/3) * cy, | ||
x2/3 + (2/3) * cx, | ||
y2/3 + (2/3) * cy, | ||
x2, | ||
y2 | ||
] | ||
} | ||
break | ||
case 'S': | ||
// default control point | ||
var cx = x | ||
var cy = y | ||
if (prev == 'C' || prev == 'S') { | ||
cx += cx - bezierX // reflect the previous command's control | ||
cy += cy - bezierY // point relative to the current point | ||
} | ||
seg = ['C', cx, cy, seg[1], seg[2], seg[3], seg[4]] | ||
break | ||
case 'T': | ||
if (prev == 'Q' || prev == 'T') { | ||
quadX = x * 2 - quadX // as with 'S' reflect previous control point | ||
quadY = y * 2 - quadY | ||
} else { | ||
quadX = x | ||
quadY = y | ||
} | ||
seg = quadratic(x, y, quadX, quadY, seg[1], seg[2]) | ||
break | ||
case 'Q': | ||
quadX = seg[1] | ||
quadY = seg[2] | ||
seg = quadratic(x, y, seg[1], seg[2], seg[3], seg[4]) | ||
break | ||
case 'L': | ||
seg = line(x, y, seg[1], seg[2]) | ||
break | ||
case 'H': | ||
seg = line(x, y, seg[1], y) | ||
break | ||
case 'V': | ||
seg = line(x, y, x, seg[1]) | ||
break | ||
case 'Z': | ||
seg = line(x, y, startX, startY) | ||
break | ||
} | ||
// This function is ripped from | ||
// github.com/DmitryBaranovskiy/raphael/blob/4d97d4/raphael.js#L2216-L2304 | ||
// which references w3.org/TR/SVG11/implnote.html#ArcImplementationNotes | ||
// TODO: make it human readable | ||
// update state | ||
prev = command | ||
x = seg[seg.length - 2] | ||
y = seg[seg.length - 1] | ||
if (seg.length > 4) { | ||
bezierX = seg[seg.length - 4] | ||
bezierY = seg[seg.length - 3] | ||
} else { | ||
bezierX = x | ||
bezierY = y | ||
} | ||
result.push(seg) | ||
} | ||
function arc(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { | ||
if (!recursive) { | ||
var xy = rotate(x1, y1, -angle) | ||
x1 = xy.x | ||
y1 = xy.y | ||
xy = rotate(x2, y2, -angle) | ||
x2 = xy.x | ||
y2 = xy.y | ||
var x = (x1 - x2) / 2 | ||
var y = (y1 - y2) / 2 | ||
var h = (x * x) / (rx * rx) + (y * y) / (ry * ry) | ||
if (h > 1) { | ||
h = Math.sqrt(h) | ||
rx = h * rx | ||
ry = h * ry | ||
} | ||
var rx2 = rx * rx | ||
var ry2 = ry * ry | ||
var k = (large_arc_flag == sweep_flag ? -1 : 1) | ||
* Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))) | ||
if (k == Infinity) k = 1 // neutralize | ||
var cx = k * rx * y / ry + (x1 + x2) / 2 | ||
var cy = k * -ry * x / rx + (y1 + y2) / 2 | ||
var f1 = Math.asin(((y1 - cy) / ry).toFixed(9)) | ||
var f2 = Math.asin(((y2 - cy) / ry).toFixed(9)) | ||
f1 = x1 < cx ? π - f1 : f1 | ||
f2 = x2 < cx ? π - f2 : f2 | ||
if (f1 < 0) f1 = π * 2 + f1 | ||
if (f2 < 0) f2 = π * 2 + f2 | ||
if (sweep_flag && f1 > f2) f1 = f1 - π * 2 | ||
if (!sweep_flag && f2 > f1) f2 = f2 - π * 2 | ||
} else { | ||
f1 = recursive[0] | ||
f2 = recursive[1] | ||
cx = recursive[2] | ||
cy = recursive[3] | ||
} | ||
// greater than 120 degrees requires multiple segments | ||
if (Math.abs(f2 - f1) > _120) { | ||
var f2old = f2 | ||
var x2old = x2 | ||
var y2old = y2 | ||
f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1) | ||
x2 = cx + rx * Math.cos(f2) | ||
y2 = cy + ry * Math.sin(f2) | ||
var res = arc(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]) | ||
} | ||
var t = Math.tan((f2 - f1) / 4) | ||
var hx = 4 / 3 * rx * t | ||
var hy = 4 / 3 * ry * t | ||
var curve = [ | ||
2 * x1 - (x1 + hx * Math.sin(f1)), | ||
2 * y1 - (y1 - hy * Math.cos(f1)), | ||
x2 + hx * Math.sin(f2), | ||
y2 - hy * Math.cos(f2), | ||
x2, | ||
y2 | ||
] | ||
if (recursive) return curve | ||
if (res) curve = curve.concat(res) | ||
for (var i = 0; i < curve.length;) { | ||
var rot = rotate(curve[i], curve[i+1], angle) | ||
curve[i++] = rot.x | ||
curve[i++] = rot.y | ||
} | ||
return curve | ||
return result | ||
} | ||
function rotate(x, y, rad){ | ||
return { | ||
x: x * Math.cos(rad) - y * Math.sin(rad), | ||
y: x * Math.sin(rad) + y * Math.cos(rad) | ||
} | ||
function line(x1, y1, x2, y2){ | ||
return ['C', x1, y1, x2, y2, x2, y2] | ||
} | ||
function radians(degress){ | ||
return degress * (π / 180) | ||
function quadratic(x1, y1, cx, cy, x2, y2){ | ||
return [ | ||
'C', | ||
x1/3 + (2/3) * cx, | ||
y1/3 + (2/3) * cy, | ||
x2/3 + (2/3) * cx, | ||
y2/3 + (2/3) * cy, | ||
x2, | ||
y2 | ||
] | ||
} |
{ | ||
"name": "normalize-svg-path", | ||
"version": "0.1.0", | ||
"description": "convert all segments in a path to curves", | ||
"keywords": ["svg","path","normalize"], | ||
"dependencies": {}, | ||
"version": "1.0.0", | ||
"description": "Convert all segments in a path to curves", | ||
"keywords": [ | ||
"svg", | ||
"path", | ||
"normalize" | ||
], | ||
"dependencies": { | ||
"svg-arc-to-cubic-bezier": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"serve": "jkroso/serve", | ||
"dom": "component/dom", | ||
"parse-svg-path": "*", | ||
"equals": "*", | ||
"mocha": "*", | ||
"jsmd": "*" | ||
"parse-svg-path": "^0.1.2", | ||
"tape": "^4.7.0" | ||
}, | ||
@@ -18,4 +20,3 @@ "repository": "git://github.com/jkroso/normalize-svg-path.git", | ||
"author": "Jake Rosoman", | ||
"files": ["index.js"], | ||
"license": "MIT" | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
10525
2
8
252
1
1
27
2
+ Addedsvg-arc-to-cubic-bezier@2.0.0(transitive)