Skip to content

Commit

Permalink
Solving #17
Browse files Browse the repository at this point in the history
  • Loading branch information
thednp committed Jun 21, 2022
1 parent 0e2e0c7 commit 2bca07c
Show file tree
Hide file tree
Showing 21 changed files with 297 additions and 361 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# SVGPathCommander
[![Coverage Status](https://coveralls.io/repos/github/thednp/svg-path-commander/badge.svg)](https://coveralls.io/github/thednp/svg-path-commander)
[![ci](https://github.com/thednp/svg-path-commander/actions/workflows/ci.yml/badge.svg)](https://github.com/thednp/svg-path-commander/actions/workflows/ci.yml)
[![NPM Version](https://img.shields.io/npm/v/svg-path-commander.svg)](https://www.npmjs.com/package/svg-path-commander)
[![NPM Downloads](https://img.shields.io/npm/dm/svg-path-commander.svg)](http://npm-stat.com/charts.html?svg-path-commander)
[![jsDeliver](https://img.shields.io/jsdelivr/npm/hw/svg-path-commander)](https://www.jsdelivr.com/package/npm/svg-path-commander)
![cypress version](https://img.shields.io/badge/cypress-9.6.1-brightgreen)
![typescript version](https://img.shields.io/badge/typescript-4.5.2-brightgreen)
[![ci](https://github.com/thednp/svg-path-commander/actions/workflows/ci.yml/badge.svg)](https://github.com/thednp/svg-path-commander/actions/workflows/ci.yml)

![image](./docs/assets/SVGPathCommander.svg)

A modern set of ES6+ JavaScript tools for manipulating the `d` (description) attribute for *SVGPathElement* items. The library is implementing modern JavaScript API to produce reusable path strings with lossless quality. In addition, you also have a powerful tool to convert other SVG shapes like `<circle>` or `<rect>` to `<path>`.

[![NPM Version](https://img.shields.io/npm/v/svg-path-commander.svg?style=flat-square)](https://www.npmjs.com/package/svg-path-commander)
[![NPM Downloads](https://img.shields.io/npm/dm/svg-path-commander.svg?style=flat-square)](http://npm-stat.com/charts.html?svg-path-commander)
[![jsDeliver](https://data.jsdelivr.com/v1/package/npm/svg-path-commander/badge)](https://www.jsdelivr.com/package/npm/svg-path-commander)

While you may find familiar tools inside, this library brings ***new additions***:
* the build in `getBBox`, `getPointAtLength` and `getTotalLength` are more reliable and much more accurate than the native methods, not to mention their world class performance ratings;
Expand Down
167 changes: 77 additions & 90 deletions dist/svg-path-commander.es5.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* SVGPathCommander v1.0.4 (http://thednp.github.io/svg-path-commander)
* SVGPathCommander v1.0.5 (http://thednp.github.io/svg-path-commander)
* Copyright 2022 © thednp
* Licensed under MIT (https://github.com/thednp/svg-path-commander/blob/master/LICENSE)
*/
Expand Down Expand Up @@ -357,7 +357,6 @@
*/
function PathParser(pathString) {
/** @type {SVGPath.pathArray} */
// @ts-ignore
this.segments = [];
/** @type {string} */
this.pathValue = pathString;
Expand Down Expand Up @@ -420,7 +419,7 @@
*/
function isAbsoluteArray(path) {
return isPathArray(path)
// @ts-ignore -- `isPathArray` also checks if it's `Array`
// `isPathArray` also checks if it's `Array`
&& path.every(function (ref) {
var x = ref[0];

Expand All @@ -438,22 +437,21 @@
function pathToAbsolute(pathInput) {
/* istanbul ignore else */
if (isAbsoluteArray(pathInput)) {
// @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray`
// `isAbsoluteArray` checks if it's `pathArray`
return clonePath(pathInput);
}

var path = parsePathString(pathInput);
var x = 0; var y = 0;
var mx = 0; var my = 0;

// @ts-ignore -- the `absoluteSegment[]` is for sure an `absolutePath`
// the `absoluteSegment[]` is for sure an `absolutePath`
return path.map(function (segment) {
var assign, assign$1, assign$2;

var values = segment.slice(1).map(Number);
var pathCommand = segment[0];
/** @type {SVGPath.absoluteCommand} */
// @ts-ignore
var absCommand = pathCommand.toUpperCase();

if (pathCommand === 'M') {
Expand All @@ -463,7 +461,6 @@
return ['M', x, y];
}
/** @type {SVGPath.absoluteSegment} */
// @ts-ignore
var absoluteSegment = [];

if (pathCommand !== absCommand) {
Expand All @@ -483,12 +480,11 @@
// use brakets for `eslint: no-case-declaration`
// https://stackoverflow.com/a/50753272/803358
var absValues = values.map(function (n, j) { return n + (j % 2 ? y : x); });
// @ts-ignore for n, l, c, s, q, t
// for n, l, c, s, q, t
absoluteSegment = [absCommand ].concat( absValues);
}
}
} else {
// @ts-ignore
absoluteSegment = [absCommand ].concat( values);
}

Expand All @@ -499,17 +495,13 @@
y = my;
break;
case 'H':
// @ts-ignore
(assign$1 = absoluteSegment, x = assign$1[1]);
break;
case 'V':
// @ts-ignore
(assign$2 = absoluteSegment, y = assign$2[1]);
break;
default:
// @ts-ignore
x = absoluteSegment[segLength - 2];
// @ts-ignore
y = absoluteSegment[segLength - 1];

if (absCommand === 'M') {
Expand All @@ -530,7 +522,7 @@
*/
function isRelativeArray(path) {
return isPathArray(path)
// @ts-ignore -- `isPathArray` checks if it's `Array`
// `isPathArray` checks if it's `Array`
&& path.slice(1).every(function (ref) {
var pc = ref[0];

Expand Down Expand Up @@ -637,13 +629,45 @@
while (segment.length) {
// if created multiple C:s, their original seg is saved
allPathCommands[i] = 'A';
// @ts-ignore
path.splice(ni += 1, 0, ['C' ].concat( segment.splice(0, 6)));
}
path.splice(i, 1);
}
}

/**
* Iterates an array to check if it's a `pathArray`
* with all segments are in non-shorthand notation
* with absolute values.
*
* @param {string | SVGPath.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isNormalizedArray(path) {
// `isAbsoluteArray` also checks if it's `Array`
return isAbsoluteArray(path) && path.every(function (ref) {
var pc = ref[0];

return 'ACLMQZ'.includes(pc);
});
}

/**
* Iterates an array to check if it's a `pathArray`
* with all C (cubic bezier) segments.
*
* @param {string | SVGPath.pathArray} path the `Array` to be checked
* @returns {boolean} iteration result
*/
function isCurveArray(path) {
// `isPathArray` also checks if it's `Array`
return isNormalizedArray(path) && path.every(function (ref) {
var pc = ref[0];

return 'MC'.includes(pc);
});
}

/**
* Normalizes a single segment of a `pathArray` object.
*
Expand Down Expand Up @@ -692,23 +716,6 @@
return result;
}

/**
* Iterates an array to check if it's a `pathArray`
* with all segments are in non-shorthand notation
* with absolute values.
*
* @param {string | SVGPath.pathArray} path the `pathArray` to be checked
* @returns {boolean} iteration result
*/
function isNormalizedArray(path) {
// @ts-ignore -- `isAbsoluteArray` also checks if it's `Array`
return isAbsoluteArray(path) && path.every(function (ref) {
var pc = ref[0];

return 'ACLMQZ'.includes(pc);
});
}

/**
* @type {SVGPath.parserParams}
*/
Expand Down Expand Up @@ -757,55 +764,6 @@
return path;
}

/**
* Checks a `pathArray` for an unnecessary `Z` segment
* and returns a new `pathArray` without it.
*
* The `pathInput` must be a single path, without
* sub-paths. For multi-path `<path>` elements,
* use `splitPath` first and apply this utility on each
* sub-path separately.
*
* @param {SVGPath.pathArray | string} pathInput the `pathArray` source
* @return {SVGPath.pathArray} a fixed `pathArray`
*/
function fixPath(pathInput) {
var pathArray = parsePathString(pathInput);
var normalArray = normalizePath(pathArray);
var length = pathArray.length;
var isClosed = normalArray.slice(-1)[0][0] === 'Z';
var segBeforeZ = isClosed ? length - 2 : length - 1;

var ref = normalArray[0].slice(1);
var mx = ref[0];
var my = ref[1];
var ref$1 = normalArray[segBeforeZ].slice(-2);
var x = ref$1[0];
var y = ref$1[1];

/* istanbul ignore else */
if (isClosed && mx === x && my === y) {
return pathArray.slice(0, -1);
}
return pathArray;
}

/**
* Iterates an array to check if it's a `pathArray`
* with all C (cubic bezier) segments.
*
* @param {string | SVGPath.pathArray} path the `Array` to be checked
* @returns {boolean} iteration result
*/
function isCurveArray(path) {
// @ts-ignore -- `isPathArray` also checks if it's `Array`
return isNormalizedArray(path) && path.every(function (ref) {
var pc = ref[0];

return 'MC'.includes(pc);
});
}

/**
* Returns an {x,y} vector rotated by a given
* angle in radian.
Expand Down Expand Up @@ -1006,7 +964,7 @@

/* istanbul ignore else */
if (typeof distance === 'number') {
if (distance === 0) {
if (distance <= 0) {
point = { x: x1, y: y1 };
} else if (distance >= length) {
point = { x: x2, y: y2 };
Expand Down Expand Up @@ -1053,13 +1011,10 @@
var p5 = midPoint(p3, p4, t);
var p6 = midPoint(p4, p5, t);
var seg1 = p0.concat( p2, p4, p6, [t]);
// @ts-ignore
var cp1 = segmentLineFactory.apply(void 0, seg1).point;
var seg2 = p6.concat( p5, p3, p1, [0]);
// @ts-ignore
var cp2 = segmentLineFactory.apply(void 0, seg2).point;

// @ts-ignore
return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
}

Expand Down Expand Up @@ -1122,11 +1077,12 @@

/* istanbul ignore else */
if (isCurveArray(pathInput)) {
// @ts-ignore -- `isCurveArray` checks if it's `pathArray`
// `isCurveArray` checks if it's `pathArray`
return clonePath(pathInput);
}

var path = fixPath(normalizePath(pathInput));
// const path = fixPath(normalizePath(pathInput));
var path = normalizePath(pathInput);
var params = Object.assign({}, paramsParser);
var allPathCommands = [];
var pathCommand = ''; // ts-lint
Expand All @@ -1149,7 +1105,6 @@
params.y2 = +(segment[seglen - 3]) || params.y1;
}

// @ts-ignore
return path;
}

Expand Down Expand Up @@ -3230,7 +3185,6 @@
var split = splitPath(segments);
var subPath = split.length > 1 ? split : 0;

// @ts-ignore
var absoluteMultiPath = subPath && clonePath(subPath).map(function (x, i) {
if (onlySubpath) {
return i ? reversePath(x) : parsePathString(x);
Expand Down Expand Up @@ -3829,6 +3783,39 @@
return [['M' ].concat( rotatedCurve[0].slice(0, 2)) ].concat( rotatedCurve.map(function (x) { return ['C' ].concat( x.slice(2)); }));
}

/**
* Checks a `pathArray` for an unnecessary `Z` segment
* and returns a new `pathArray` without it.
*
* The `pathInput` must be a single path, without
* sub-paths. For multi-path `<path>` elements,
* use `splitPath` first and apply this utility on each
* sub-path separately.
*
* @param {SVGPath.pathArray | string} pathInput the `pathArray` source
* @return {SVGPath.pathArray} a fixed `pathArray`
*/
function fixPath(pathInput) {
var pathArray = parsePathString(pathInput);
var normalArray = normalizePath(pathArray);
var length = pathArray.length;
var isClosed = normalArray.slice(-1)[0][0] === 'Z';
var segBeforeZ = isClosed ? length - 2 : length - 1;

var ref = normalArray[0].slice(1);
var mx = ref[0];
var my = ref[1];
var ref$1 = normalArray[segBeforeZ].slice(-2);
var x = ref$1[0];
var y = ref$1[1];

/* istanbul ignore else */
if (isClosed && mx === x && my === y) {
return pathArray.slice(0, -1);
}
return pathArray;
}

/**
* @interface
*/
Expand Down Expand Up @@ -3870,7 +3857,7 @@
options: defaultOptions,
};

var version = "1.0.4";
var version = "1.0.5";

/**
* A global namespace for library version.
Expand Down
4 changes: 2 additions & 2 deletions dist/svg-path-commander.es5.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit 2bca07c

Please sign in to comment.