Skip to content

Commit

Permalink
segment -> s & loops unroll
Browse files Browse the repository at this point in the history
  • Loading branch information
Vitaly Puzrin committed Apr 14, 2015
1 parent 3e1ba3b commit 1185808
Showing 1 changed file with 76 additions and 78 deletions.
154 changes: 76 additions & 78 deletions lib/svgpath.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,29 @@ SvgPath.prototype.__matrix = function (m) {
// Quick leave for empty matrix
if (!m.queue.length) { return; }

this.iterate(function (segment, index, x, y) {
this.iterate(function (s, index, x, y) {
var p, result, name, isRelative;

switch (segment[0]) {
switch (s[0]) {

// Process 'assymetric' commands separately
case 'v':
p = m.calc(0, segment[1], true);
p = m.calc(0, s[1], true);
result = (p[0] === 0) ? [ 'v', p[1] ] : [ 'l', p[0], p[1] ];
break;

case 'V':
p = m.calc(x, segment[1], false);
p = m.calc(x, s[1], false);
result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ];
break;

case 'h':
p = m.calc(segment[1], 0, true);
p = m.calc(s[1], 0, true);
result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ];
break;

case 'H':
p = m.calc(segment[1], y, false);
p = m.calc(s[1], y, false);
result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ];
break;

Expand Down Expand Up @@ -98,37 +98,37 @@ SvgPath.prototype.__matrix = function (m) {

// If scaleX or scaleY === 0 - replace arc with line
if (arc2line) {
result = [ (segment[0] === 'a') ? 'l' : 'L', segment[6], segment[7] ];
result = [ (s[0] === 'a') ? 'l' : 'L', s[6], s[7] ];
break;
}

result = segment.slice();
result = s.slice();

// Apply scale to rx & ry only
result[1] = segment[1] * sx;
result[2] = segment[2] * sy;
result[1] = s[1] * sx;
result[2] = s[2] * sy;

// Apply rotation angle to x-axis-rotation
a = segment[3] + angle;
a = s[3] + angle;
// Normalize value to be in -179.999...180
// http://stackoverflow.com/a/28316366/1031804
a += Math.ceil((-a - 180) / 360) * 360;
result[3] = (a === -180) ? 180 : a;

// Transform end point as usual (without translation for relative notation)
p = m.calc(segment[6], segment[7], segment[0] === 'a');
p = m.calc(s[6], s[7], s[0] === 'a');
result[6] = p[0];
result[7] = p[1];
break;

default:
name = segment[0];
name = s[0];
result = [ name ];
isRelative = (name.toLowerCase() === name);

// Apply transformations to the segment
for (var i = 1; i < segment.length; i += 2) {
p = m.calc(segment[i], segment[i + 1], isRelative);
for (var i = 1; i < s.length; i += 2) {
p = m.calc(s[i], s[i + 1], isRelative);
result.push(p[0], p[1]);
}
}
Expand Down Expand Up @@ -170,13 +170,13 @@ SvgPath.prototype.toString = function () {

this.__evaluateStack();

for (var s = 0; s < this.segments.length; s++) {
for (var i = 0; i < this.segments.length; i++) {
// remove repeating commands names
if (s > 0 && (this.segments[s][0] === this.segments[s - 1][0])) {
elements.push(this.segments[s].slice(1));
if (i > 0 && (this.segments[i][0] === this.segments[i - 1][0])) {
elements.push(this.segments[i].slice(1));
continue;
}
elements.push(this.segments[s]);
elements.push(this.segments[i]);
}

return [].concat.apply([], elements).join(' ')
Expand Down Expand Up @@ -244,21 +244,21 @@ SvgPath.prototype.round = function (d) {

this.__evaluateStack();

this.segments.forEach(function (segment) {
this.segments.forEach(function (s) {
// Special processing for ARC:
// [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
if (segment[0].toLowerCase() === 'a') {
segment[1] = +segment[1].toFixed(d);
segment[2] = +segment[2].toFixed(d);
segment[3] = +segment[3].toFixed(d + 2); // better precision for rotation
segment[6] = +segment[6].toFixed(d);
segment[7] = +segment[7].toFixed(d);
if (s[0].toLowerCase() === 'a') {
s[1] = +s[1].toFixed(d);
s[2] = +s[2].toFixed(d);
s[3] = +s[3].toFixed(d + 2); // better precision for rotation
s[6] = +s[6].toFixed(d);
s[7] = +s[7].toFixed(d);
return;
}

segment.forEach(function (val, i) {
s.forEach(function (val, i) {
if (!i) { return; }
segment[i] = +segment[i].toFixed(d);
s[i] = +s[i].toFixed(d);
});
});

Expand All @@ -284,35 +284,35 @@ SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
this.__evaluateStack();
}

segments.forEach(function (segment, index) {
segments.forEach(function (s, index) {

var res = iterator(segment, index, lastX, lastY);
var res = iterator(s, index, lastX, lastY);

if (Array.isArray(res)) {
replacements[index] = res;
needReplace = true;
}

// all relative commands except Z
isRelative = 'achlmqrstv'.indexOf(segment[0]) >= 0;
var nameLC = segment[0].toLowerCase();
isRelative = 'achlmqrstv'.indexOf(s[0]) >= 0;
var nameLC = s[0].toLowerCase();

// calculate absolute X and Y
if (nameLC === 'm') {
lastX = segment[1] + (isRelative ? lastX : 0);
lastY = segment[2] + (isRelative ? lastY : 0);
lastX = s[1] + (isRelative ? lastX : 0);
lastY = s[2] + (isRelative ? lastY : 0);
countourStartX = lastX;
countourStartY = lastY;
return;
}

if (nameLC === 'h') {
lastX = segment[1] + (isRelative ? lastX : 0);
lastX = s[1] + (isRelative ? lastX : 0);
return;
}

if (nameLC === 'v') {
lastY = segment[1] + (isRelative ? lastY : 0);
lastY = s[1] + (isRelative ? lastY : 0);
return;
}

Expand All @@ -322,8 +322,8 @@ SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
return;
}

lastX = segment[segment.length - 2] + (isRelative ? lastX : 0);
lastY = segment[segment.length - 1] + (isRelative ? lastY : 0);
lastX = s[s.length - 2] + (isRelative ? lastX : 0);
lastY = s[s.length - 1] + (isRelative ? lastY : 0);
});

// Replace segments if iterator return results
Expand Down Expand Up @@ -352,35 +352,34 @@ SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
//
SvgPath.prototype.abs = function () {

this.iterate(function (segment, index, x, y) {
var name = segment[0],
nameUC = name.toUpperCase();
this.iterate(function (s, index, x, y) {
var name = s[0],
nameUC = name.toUpperCase(),
i;

// Skip absolute commands
if (name === nameUC) { return; }

segment[0] = nameUC;
s[0] = nameUC;

// V is the only command, with shifted coords parity
if (name === 'v') {
segment[1] += y;
s[1] += y;
return;
}

// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// touch x, y only
if (name === 'a') {
segment[6] += x;
segment[7] += y;
s[6] += x;
s[7] += y;
return;
}

segment.forEach(function (val, i) {
if (!i) { return; } // skip command
segment[i] = i % 2 ? val + x : val + y; // odd values are X, even - Y
}, true);

});
for (i = 1; i < s.length; i++) {
s[i] += i % 2 ? x : y; // odd values are X, even - Y
}
}, true);

return this;
};
Expand All @@ -390,34 +389,33 @@ SvgPath.prototype.abs = function () {
//
SvgPath.prototype.rel = function () {

this.iterate(function (segment, index, x, y) {
var name = segment[0],
nameLC = name.toLowerCase();
this.iterate(function (s, index, x, y) {
var name = s[0],
nameLC = name.toLowerCase(),
i;

// Skip relative commands
if (name === nameLC) { return; }

segment[0] = name.toLowerCase();
s[0] = name.toLowerCase();

// V is the only command, with shifted coords parity
if (name === 'V') {
segment[1] -= y;
s[1] -= y;
return;
}

// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// touch x, y only
if (name === 'A') {
segment[6] -= x;
segment[7] -= y;
s[6] -= x;
s[7] -= y;
return;
}

segment.forEach(function (val, i) {
if (!i) { return; } // skip command
segment[i] = i % 2 ? val - x : val - y; // odd values are X, even - Y
});

for (i = 1; i < s.length; i++) {
s[i] -= i % 2 ? x : y; // odd values are X, even - Y
}
}, true);

return this;
Expand All @@ -427,37 +425,37 @@ SvgPath.prototype.rel = function () {
// Converts smooth curves (with missed control point) to generic curves
//
SvgPath.prototype.unshort = function () {
var self = this;
var segments = this.segments;
var prevControlX, prevControlY;
var curControlX, curControlY;

// TODO: add lazy evaluation flag when relative commands supported

this.iterate(function (segment, index, x, y) {
var name = segment[0];
this.iterate(function (s, idx, x, y) {
var name = s[0];

if (name === 'T') { // qubic curve
segment[0] = 'Q';
prevControlX = self.segments[index - 1][0] === 'Q' ? self.segments[index - 1][1] : x;
s[0] = 'Q';
prevControlX = segments[idx - 1][0] === 'Q' ? segments[idx - 1][1] : x;
curControlX = 2 * (x || 0) - (prevControlX || 0);
prevControlY = self.segments[index - 1][0] === 'Q' ? self.segments[index - 1][2] : y;
prevControlY = segments[idx - 1][0] === 'Q' ? segments[idx - 1][2] : y;
curControlY = 2 * (y || 0) - (prevControlY || 0);
self.segments[index] = [
segment[0],
segments[idx] = [
s[0],
curControlX, curControlY,
segment[1], segment[2]
s[1], s[2]
];
} else if (name === 'S') { // quadratic curve

segment[0] = 'C';
prevControlX = self.segments[index - 1][0] === 'C' ? self.segments[index - 1][3] : x;
s[0] = 'C';
prevControlX = segments[idx - 1][0] === 'C' ? segments[idx - 1][3] : x;
curControlX = 2 * (x || 0) - (prevControlX || 0);
prevControlY = self.segments[index - 1][0] === 'C' ? self.segments[index - 1][4] : y;
prevControlY = segments[idx - 1][0] === 'C' ? segments[idx - 1][4] : y;
curControlY = 2 * (y || 0) - (prevControlY || 0);
self.segments[index] = [
segment[0],
segments[idx] = [
s[0],
curControlX, curControlY,
segment[1], segment[2], segment[3], segment[4]
s[1], s[2], s[3], s[4]
];
}
});
Expand Down

0 comments on commit 1185808

Please sign in to comment.