Skip to content

Commit

Permalink
Refactored .toString() to improve speed
Browse files Browse the repository at this point in the history
  • Loading branch information
Vitaly Puzrin committed Jan 11, 2022
1 parent 7b25737 commit eea1834
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [2.5.0] - WIP
### Changed
- Refactored `.toString()` to improve speed.


## [2.4.1] - 2022-01-03
### Fixed
- Fixed TS definition (regression in 2.4.0), #57.
Expand Down Expand Up @@ -155,6 +160,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- First release.


[2.5.0]: https://github.com/fontello/svgpath/compare/2.4.1...2.5.0
[2.4.1]: https://github.com/fontello/svgpath/compare/2.4.0...2.4.1
[2.4.0]: https://github.com/fontello/svgpath/compare/2.3.1...2.4.0
[2.3.1]: https://github.com/fontello/svgpath/compare/2.3.0...2.3.1
Expand Down
14 changes: 8 additions & 6 deletions benchmark/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ fs.readdirSync(IMPLS_DIRECTORY).sort().forEach(name => {
IMPLS.push({ name, code });
});


const SAMPLES = {
big: fs.readFileSync(path.join(__dirname, 'samples/big.txt'), 'utf8'),
one_path: fs.readFileSync(path.join(__dirname, 'samples/one_path.txt'), 'utf8')
};

let suite;

function run(suite) {
Expand All @@ -36,6 +30,13 @@ function run(suite) {
.run();
}


const SAMPLES = {
big: fs.readFileSync(path.join(__dirname, 'samples/big.txt'), 'utf8'),
one_path: fs.readFileSync(path.join(__dirname, 'samples/one_path.txt'), 'utf8')
};


suite = new Benchmark.Suite('.from("big.txt")');

IMPLS.forEach(impl => {
Expand All @@ -53,6 +54,7 @@ IMPLS.forEach(impl => {

run(suite);


const long = 'M 4.8173765432098765 -9.12666320366964 Z'.repeat(5000);

suite = new Benchmark.Suite('.from(long).toString()');
Expand Down
46 changes: 31 additions & 15 deletions lib/svgpath.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,26 +187,42 @@ SvgPath.prototype.__evaluateStack = function () {
// Convert processed SVG Path back to string
//
SvgPath.prototype.toString = function () {
var elements = [], skipCmd, cmd;
var result = '', prevCmd = '', cmdSkipped = false;

this.__evaluateStack();

for (var i = 0; i < this.segments.length; i++) {
// remove repeating commands names
cmd = this.segments[i][0];
skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0];
elements = elements.concat(skipCmd ? this.segments[i].slice(1) : this.segments[i]);
for (var i = 0, len = this.segments.length; i < len; i++) {
var segment = this.segments[i];
var cmd = segment[0];

// Command not repeating => store
if (cmd !== prevCmd || cmd === 'm' || cmd === 'M') {
// workaround for FontForge SVG importing bug, keep space between "z m".
if (cmd === 'm' && prevCmd === 'z') result += ' ';
result += cmd;

cmdSkipped = false;
} else {
cmdSkipped = true;
}

// Store segment params
for (var pos = 1; pos < segment.length; pos++) {
var val = segment[pos];
// Space can be skipped
// 1. After command (always)
// 2. For negative value (with '-' at start)
if (pos === 1) {
if (cmdSkipped && val >= 0) result += ' ';
} else if (val >= 0) result += ' ';

result += val;
}

prevCmd = cmd;
}

return elements.join(' ')
// Optimizations: remove spaces around commands & before `-`
//
// We could also remove leading zeros for `0.5`-like values,
// but their count is too small to spend time for.
.replace(/ ?([achlmqrstvz]) ?/gi, '$1')
.replace(/ \-/g, '-')
// workaround for FontForge SVG importing bug
.replace(/zm/g, 'z m');
return result;
};


Expand Down

0 comments on commit eea1834

Please sign in to comment.