Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

123
static/js/ketcher2/node_modules/svgpath/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,123 @@
2.2.1 / 2016-12-24
------------------
- Update typescript definition for ts@2, #28.
- Replace unicode characters with ascii ones, #27.
2.2.0 / 2016-09-11
------------------
- Added `.skewX()` & `.skewY()` shortcuts.
- Added typescript definitions.
- Dropped `Makefile`, use npm instead.
- Deps bump & cleanup.
2.1.6 / 2016-03-09
------------------
- Fixed arc transforms for edge cases (precision + sweep flag), #23.
2.1.5 / 2016-01-03
------------------
- Improved parser error messages.
2.1.4 / 2016-01-03
------------------
- More strict params count and exponent parse.
- Properly correct round error on contour end.
- Never drop empty arcs. Replace with lines to avoid collisions on `S A S`.
2.1.3 / 2015-12-30
------------------
- Fixed `.unarc()` - expand zero-radius arcs to lines.
2.1.2 / 2015-12-22
------------------
- Fixed arc transforms, #13. Thanks to @kpym.
2.1.1 / 2015-12-07
------------------
- Don't collapse `M` & `m` commands on output.
2.1.0 / 2015-10-27
------------------
- First `m` in path should be processed as absolute (`M`).
- Don't force first `M` -> `m` on `.rel()`.
2.0.0 / 2015-04-16
------------------
- Unified transformations math.
- Added `.matrix` and `.rotate()`.
- Added `.unarc()` - convert arcs to curves.
- Evaluate curried transforms lazily.
- Fixed `.unshort()` - now relative commands processed too.
- Fixed `.round()` - no more precision loss on relative coordinated.
- 100% tests coverage.
- Minor optimisations & code refactoring.
1.0.7 / 2014-12-05
------------------
- Parser rewrite (1.5x speedup).
- Exposed `.err` property with text of error (empty on success).
1.0.6 / 2014-06-15
------------------
- Maintenance release - docs & build scripts update.
1.0.5 / 2014-04-09
------------------
- Fixed line terminators handle in parser.
1.0.4 / 2014-03-14
------------------
- Added .transform() support.
1.0.3 / 2014-02-23
------------------
- Parser rewrite (2x speed gain).
- toString(): skip command name on repeaded sequences.
- Added tests & benchmarks.
1.0.2 / 2013-12-03
------------------
- Fixed arcs roundung (missed type cast), by @kolya-ay.
1.0.1 / 2013-10-02
------------------
- Fixed params parse: 29.5.5 -> 29.5, 0.5.
1.0.0 / 2013-09-26
------------------
- First release.

22
static/js/ketcher2/node_modules/svgpath/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
(The MIT License)
Copyright (C) 2013-2015 by Vitaly Puzrin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

146
static/js/ketcher2/node_modules/svgpath/README.md generated vendored Normal file
View File

@ -0,0 +1,146 @@
svgpath
=======
[![Build Status](https://img.shields.io/travis/fontello/svgpath/master.svg?style=flat)](https://travis-ci.org/fontello/svgpath)
[![NPM version](https://img.shields.io/npm/v/svgpath.svg?style=flat)](https://www.npmjs.org/package/svgpath)
[![Coverage Status](https://img.shields.io/coveralls/fontello/svgpath/master.svg?style=flat)](https://coveralls.io/r/fontello/svgpath?branch=master)
> Low level toolkit for SVG paths transformations. Sometime you can't use
`transform` attributes and have to apply changes to svg paths directly.
Then this package is for you :) !
Note, this package works with `paths`, not with svg xml sources.
Install
-------
```bash
npm install svgpath
```
Example
-------
```js
var svgpath = require('svgpath');
var transformed = svgpath(__your_path__)
.scale(0.5)
.translate(100,200)
.rel()
.round(1)
.toString();
```
API
---
All methods are chainable (return self).
### new SvgPath(path) -> self
Constructor. Creates new `SvgPath` class instance with chainable methods.
`new` can be omited.
### .abs() -> self
Converts all path commands to absolute.
### .rel() -> self
Converts all path commands to relative. Useful to reduce output size.
### .scale(sx [, sy]) -> self
Rescale path (the same as SVG `scale` transformation). `sy` = `sx` by default.
### .translate(x [, y]) -> self
Rescale path (the same as SVG `translate` transformation). `y` = 0 by default.
### .rotate(angle [, rx, ry]) -> self
Rotate path to `angle` degrees around (rx, ry) point. If rotation center not set,
(0, 0) used. The same as SVG `rotate` transformation.
### .skewX(degrees) -> self
Skew path along the X axis by `degrees` angle.
### .skewY(degrees) -> self
Skew path along the Y axis by `degrees` angle.
### .matrix([ m1, m2, m3, m4, m5, m6 ]) -> self
Apply 2x3 affine transform matrix to path. Params - array. The same as SVG
`matrix` transformation.
### .transform(string) -> self
Any SVG transform or their combination. For example `rotate(90) scale(2,3)`.
The same format, as described in SVG standard for `transform` attribute.
### .unshort() -> self
Converts smooth curves `T`/`t`/`S`/`s` with "missed" control point to
generic curves (`Q`/`q`/`C`/`c`).
### .unarc() -> self
Replaces all arcs with bezier curves.
### .toString() -> string
Returns final path string.
### .round(precision) -> self
Round all coordinates to given decimal precision. By default round to integer.
Useful to reduce resulting output string size.
### .iterate(function(segment, index, x, y) [, keepLazyStack]) -> self
Apply iterator to all path segments.
- Each iterator receives `segment`, `index`, `x` and `y` params.
Where (x, y) - absolute coordinates of segment start point.
- Iterator can modify current segment directly (return nothing in this case).
- Iterator can return array of new segments to replace current one (`[]` means
that current segment should be delated).
If second param `keepLazyStack` set to `true`, then iterator will not evaluate
stacked transforms prior to run. That can be useful to optimize calculations.
Authors
-------
- Sergey Batishchev - [@snb2013](https://github.com/snb2013)
- Vitaly Puzrin - [@puzrin](https://github.com/puzrin)
- Alex Kocharin - [@rlidwka](https://github.com/rlidwka)
License
-------
[MIT](https://github.com/fontello/svgpath/blob/master/LICENSE)

22
static/js/ketcher2/node_modules/svgpath/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,22 @@
declare module "svgpath" {
interface SvgPath {
(path: string): SvgPath;
new (path: string): SvgPath;
abs(): SvgPath;
scale(sx: number, sy?: number): SvgPath;
translate(x: number, y?: number): SvgPath;
rotate(angle: number, rx?: number, ry?: number): SvgPath;
skewX(degrees: number): SvgPath;
skewY(degrees: number): SvgPath;
matrix(m1: number, m2: number, m3: number, m4: number, m5: number, m6: number): SvgPath;
transform(str: string): SvgPath;
unshort(): SvgPath;
unarc(): SvgPath;
toString(): String;
round(precision: number): SvgPath;
iterate(iterator: (segment: any[], index: number, x: number, y: number) => void, keepLazyStack?: boolean): SvgPath;
}
const svgPath: SvgPath;
export = svgPath;
}

3
static/js/ketcher2/node_modules/svgpath/index.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./lib/svgpath');

185
static/js/ketcher2/node_modules/svgpath/lib/a2c.js generated vendored Normal file
View File

@ -0,0 +1,185 @@
// Convert an arc to a sequence of cubic bézier curves
//
'use strict';
var TAU = Math.PI * 2;
/* eslint-disable space-infix-ops */
// Calculate an angle between two vectors
//
function vector_angle(ux, uy, vx, vy) {
var sign = (ux * vy - uy * vx < 0) ? -1 : 1;
var umag = Math.sqrt(ux * ux + uy * uy);
var vmag = Math.sqrt(ux * ux + uy * uy);
var dot = ux * vx + uy * vy;
var div = dot / (umag * vmag);
// rounding errors, e.g. -1.0000000000000002 can screw up this
if (div > 1.0) { div = 1.0; }
if (div < -1.0) { div = -1.0; }
return sign * Math.acos(div);
}
// Convert from endpoint to center parameterization,
// see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
//
// Return [cx, cy, theta1, delta_theta]
//
function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) {
// Step 1.
//
// Moving an ellipse so origin will be the middlepoint between our two
// points. After that, rotate it to line up ellipse axes with coordinate
// axes.
//
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
var rx_sq = rx * rx;
var ry_sq = ry * ry;
var x1p_sq = x1p * x1p;
var y1p_sq = y1p * y1p;
// Step 2.
//
// Compute coordinates of the centre of this ellipse (cx', cy')
// in the new coordinate system.
//
var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq);
if (radicant < 0) {
// due to rounding errors it might be e.g. -1.3877787807814457e-17
radicant = 0;
}
radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq);
radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1);
var cxp = radicant * rx/ry * y1p;
var cyp = radicant * -ry/rx * x1p;
// Step 3.
//
// Transform back to get centre coordinates (cx, cy) in the original
// coordinate system.
//
var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2;
var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2;
// Step 4.
//
// Compute angles (theta1, delta_theta).
//
var v1x = (x1p - cxp) / rx;
var v1y = (y1p - cyp) / ry;
var v2x = (-x1p - cxp) / rx;
var v2y = (-y1p - cyp) / ry;
var theta1 = vector_angle(1, 0, v1x, v1y);
var delta_theta = vector_angle(v1x, v1y, v2x, v2y);
if (fs === 0 && delta_theta > 0) {
delta_theta -= TAU;
}
if (fs === 1 && delta_theta < 0) {
delta_theta += TAU;
}
return [ cx, cy, theta1, delta_theta ];
}
//
// Approximate one unit arc segment with bézier curves,
// see http://math.stackexchange.com/questions/873224
//
function approximate_unit_arc(theta1, delta_theta) {
var alpha = 4/3 * Math.tan(delta_theta/4);
var x1 = Math.cos(theta1);
var y1 = Math.sin(theta1);
var x2 = Math.cos(theta1 + delta_theta);
var y2 = Math.sin(theta1 + delta_theta);
return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ];
}
module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) {
var sin_phi = Math.sin(phi * TAU / 360);
var cos_phi = Math.cos(phi * TAU / 360);
// Make sure radii are valid
//
var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2;
var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2;
if (x1p === 0 && y1p === 0) {
// we're asked to draw line to itself
return [];
}
if (rx === 0 || ry === 0) {
// one of the radii is zero
return [];
}
// Compensate out-of-range radii
//
rx = Math.abs(rx);
ry = Math.abs(ry);
var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
if (lambda > 1) {
rx *= Math.sqrt(lambda);
ry *= Math.sqrt(lambda);
}
// Get center parameters (cx, cy, theta1, delta_theta)
//
var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi);
var result = [];
var theta1 = cc[2];
var delta_theta = cc[3];
// Split an arc to multiple segments, so each segment
// will be less than τ/4 (= 90°)
//
var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1);
delta_theta /= segments;
for (var i = 0; i < segments; i++) {
result.push(approximate_unit_arc(theta1, delta_theta));
theta1 += delta_theta;
}
// We have a bezier approximation of a unit circle,
// now need to transform back to the original ellipse
//
return result.map(function (curve) {
for (var i = 0; i < curve.length; i += 2) {
var x = curve[i + 0];
var y = curve[i + 1];
// scale
x *= rx;
y *= ry;
// rotate
var xp = cos_phi*x - sin_phi*y;
var yp = sin_phi*x + cos_phi*y;
// translate
curve[i + 0] = xp + cc[0];
curve[i + 1] = yp + cc[1];
}
return curve;
});
};

102
static/js/ketcher2/node_modules/svgpath/lib/ellipse.js generated vendored Normal file
View File

@ -0,0 +1,102 @@
'use strict';
/* eslint-disable space-infix-ops */
// The precision used to consider an ellipse as a circle
//
var epsilon = 0.0000000001;
// To convert degree in radians
//
var torad = Math.PI / 180;
// Class constructor :
// an ellipse centred at 0 with radii rx,ry and x - axis - angle ax.
//
function Ellipse(rx, ry, ax) {
if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); }
this.rx = rx;
this.ry = ry;
this.ax = ax;
}
// Apply a linear transform m to the ellipse
// m is an array representing a matrix :
// - -
// | m[0] m[2] |
// | m[1] m[3] |
// - -
//
Ellipse.prototype.transform = function (m) {
// We consider the current ellipse as image of the unit circle
// by first scale(rx,ry) and then rotate(ax) ...
// So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle.
var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad);
var ma = [
this.rx * (m[0]*c + m[2]*s),
this.rx * (m[1]*c + m[3]*s),
this.ry * (-m[0]*s + m[2]*c),
this.ry * (-m[1]*s + m[3]*c)
];
// ma * transpose(ma) = [ J L ]
// [ L K ]
// L is calculated later (if the image is not a circle)
var J = ma[0]*ma[0] + ma[2]*ma[2],
K = ma[1]*ma[1] + ma[3]*ma[3];
// the discriminant of the characteristic polynomial of ma * transpose(ma)
var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) *
((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1]));
// the "mean eigenvalue"
var JK = (J + K) / 2;
// check if the image is (almost) a circle
if (D < epsilon * JK) {
// if it is
this.rx = this.ry = Math.sqrt(JK);
this.ax = 0;
return this;
}
// if it is not a circle
var L = ma[0]*ma[1] + ma[2]*ma[3];
D = Math.sqrt(D);
// {l1,l2} = the two eigen values of ma * transpose(ma)
var l1 = JK + D/2,
l2 = JK - D/2;
// the x - axis - rotation angle is the argument of the l1 - eigenvector
this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ?
90
:
Math.atan(Math.abs(L) > Math.abs(l1 - K) ?
(l1 - J) / L
:
L / (l1 - K)
) * 180 / Math.PI;
// if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90
if (this.ax >= 0) {
// if ax in [0,90]
this.rx = Math.sqrt(l1);
this.ry = Math.sqrt(l2);
} else {
// if ax in ]-90,0[ => exchange axes
this.ax += 90;
this.rx = Math.sqrt(l2);
this.ry = Math.sqrt(l1);
}
return this;
};
// Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0
//
Ellipse.prototype.isDegenerate = function () {
return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx);
};
module.exports = Ellipse;

144
static/js/ketcher2/node_modules/svgpath/lib/matrix.js generated vendored Normal file
View File

@ -0,0 +1,144 @@
'use strict';
// combine 2 matrixes
// m1, m2 - [a, b, c, d, e, g]
//
function combine(m1, m2) {
return [
m1[0] * m2[0] + m1[2] * m2[1],
m1[1] * m2[0] + m1[3] * m2[1],
m1[0] * m2[2] + m1[2] * m2[3],
m1[1] * m2[2] + m1[3] * m2[3],
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
];
}
function Matrix() {
if (!(this instanceof Matrix)) { return new Matrix(); }
this.queue = []; // list of matrixes to apply
this.cache = null; // combined matrix cache
}
Matrix.prototype.matrix = function (m) {
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) {
return this;
}
this.cache = null;
this.queue.push(m);
return this;
};
Matrix.prototype.translate = function (tx, ty) {
if (tx !== 0 || ty !== 0) {
this.cache = null;
this.queue.push([ 1, 0, 0, 1, tx, ty ]);
}
return this;
};
Matrix.prototype.scale = function (sx, sy) {
if (sx !== 1 || sy !== 1) {
this.cache = null;
this.queue.push([ sx, 0, 0, sy, 0, 0 ]);
}
return this;
};
Matrix.prototype.rotate = function (angle, rx, ry) {
var rad, cos, sin;
if (angle !== 0) {
this.translate(rx, ry);
rad = angle * Math.PI / 180;
cos = Math.cos(rad);
sin = Math.sin(rad);
this.queue.push([ cos, sin, -sin, cos, 0, 0 ]);
this.cache = null;
this.translate(-rx, -ry);
}
return this;
};
Matrix.prototype.skewX = function (angle) {
if (angle !== 0) {
this.cache = null;
this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]);
}
return this;
};
Matrix.prototype.skewY = function (angle) {
if (angle !== 0) {
this.cache = null;
this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]);
}
return this;
};
// Flatten queue
//
Matrix.prototype.toArray = function () {
if (this.cache) {
return this.cache;
}
if (!this.queue.length) {
this.cache = [ 1, 0, 0, 1, 0, 0 ];
return this.cache;
}
this.cache = this.queue[0];
if (this.queue.length === 1) {
return this.cache;
}
for (var i = 1; i < this.queue.length; i++) {
this.cache = combine(this.cache, this.queue[i]);
}
return this.cache;
};
// Apply list of matrixes to (x,y) point.
// If `isRelative` set, `translate` component of matrix will be skipped
//
Matrix.prototype.calc = function (x, y, isRelative) {
var m;
// Don't change point on empty transforms queue
if (!this.queue.length) { return [ x, y ]; }
// Calculate final matrix, if not exists
//
// NB. if you deside to apply transforms to point one-by-one,
// they should be taken in reverse order
if (!this.cache) {
this.cache = this.toArray();
}
m = this.cache;
// Apply matrix to point
return [
x * m[0] + y * m[2] + (isRelative ? 0 : m[4]),
x * m[1] + y * m[3] + (isRelative ? 0 : m[5])
];
};
module.exports = Matrix;

View File

@ -0,0 +1,285 @@
'use strict';
var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
var SPECIAL_SPACES = [
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF
];
function isSpace(ch) {
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators
// White spaces
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
(ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
}
function isCommand(code) {
/*eslint-disable no-bitwise*/
switch (code | 0x20) {
case 0x6D/* m */:
case 0x7A/* z */:
case 0x6C/* l */:
case 0x68/* h */:
case 0x76/* v */:
case 0x63/* c */:
case 0x73/* s */:
case 0x71/* q */:
case 0x74/* t */:
case 0x61/* a */:
case 0x72/* r */:
return true;
}
return false;
}
function isDigit(code) {
return (code >= 48 && code <= 57); // 0..9
}
function isDigitStart(code) {
return (code >= 48 && code <= 57) || /* 0..9 */
code === 0x2B || /* + */
code === 0x2D || /* - */
code === 0x2E; /* . */
}
function State(path) {
this.index = 0;
this.path = path;
this.max = path.length;
this.result = [];
this.param = 0.0;
this.err = '';
this.segmentStart = 0;
this.data = [];
}
function skipSpaces(state) {
while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) {
state.index++;
}
}
function scanParam(state) {
var start = state.index,
index = start,
max = state.max,
zeroFirst = false,
hasCeiling = false,
hasDecimal = false,
hasDot = false,
ch;
if (index >= max) {
state.err = 'SvgPath: missed param (at pos ' + index + ')';
return;
}
ch = state.path.charCodeAt(index);
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
index++;
ch = (index < max) ? state.path.charCodeAt(index) : 0;
}
// This logic is shamelessly borrowed from Esprima
// https://github.com/ariya/esprimas
//
if (!isDigit(ch) && ch !== 0x2E/* . */) {
state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
return;
}
if (ch !== 0x2E/* . */) {
zeroFirst = (ch === 0x30/* 0 */);
index++;
ch = (index < max) ? state.path.charCodeAt(index) : 0;
if (zeroFirst && index < max) {
// decimal number starts with '0' such as '09' is illegal.
if (ch && isDigit(ch)) {
state.err = 'SvgPath: numbers started with `0` such as `09` are ilegal (at pos ' + start + ')';
return;
}
}
while (index < max && isDigit(state.path.charCodeAt(index))) {
index++;
hasCeiling = true;
}
ch = (index < max) ? state.path.charCodeAt(index) : 0;
}
if (ch === 0x2E/* . */) {
hasDot = true;
index++;
while (isDigit(state.path.charCodeAt(index))) {
index++;
hasDecimal = true;
}
ch = (index < max) ? state.path.charCodeAt(index) : 0;
}
if (ch === 0x65/* e */ || ch === 0x45/* E */) {
if (hasDot && !hasCeiling && !hasDecimal) {
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
return;
}
index++;
ch = (index < max) ? state.path.charCodeAt(index) : 0;
if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
index++;
}
if (index < max && isDigit(state.path.charCodeAt(index))) {
while (index < max && isDigit(state.path.charCodeAt(index))) {
index++;
}
} else {
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
return;
}
}
state.index = index;
state.param = parseFloat(state.path.slice(start, index)) + 0.0;
}
function finalizeSegment(state) {
var cmd, cmdLC;
// Process duplicated commands (without comand name)
// This logic is shamelessly borrowed from Raphael
// https://github.com/DmitryBaranovskiy/raphael/
//
cmd = state.path[state.segmentStart];
cmdLC = cmd.toLowerCase();
var params = state.data;
if (cmdLC === 'm' && params.length > 2) {
state.result.push([ cmd, params[0], params[1] ]);
params = params.slice(2);
cmdLC = 'l';
cmd = (cmd === 'm') ? 'l' : 'L';
}
if (cmdLC === 'r') {
state.result.push([ cmd ].concat(params));
} else {
while (params.length >= paramCounts[cmdLC]) {
state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
if (!paramCounts[cmdLC]) {
break;
}
}
}
}
function scanSegment(state) {
var max = state.max,
cmdCode, comma_found, need_params, i;
state.segmentStart = state.index;
cmdCode = state.path.charCodeAt(state.index);
if (!isCommand(cmdCode)) {
state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')';
return;
}
need_params = paramCounts[state.path[state.index].toLowerCase()];
state.index++;
skipSpaces(state);
state.data = [];
if (!need_params) {
// Z
finalizeSegment(state);
return;
}
comma_found = false;
for (;;) {
for (i = need_params; i > 0; i--) {
scanParam(state);
if (state.err.length) {
return;
}
state.data.push(state.param);
skipSpaces(state);
comma_found = false;
if (state.index < max && state.path.charCodeAt(state.index) === 0x2C/* , */) {
state.index++;
skipSpaces(state);
comma_found = true;
}
}
// after ',' param is mandatory
if (comma_found) {
continue;
}
if (state.index >= state.max) {
break;
}
// Stop on next segment
if (!isDigitStart(state.path.charCodeAt(state.index))) {
break;
}
}
finalizeSegment(state);
}
/* Returns array of segments:
*
* [
* [ command, coord1, coord2, ... ]
* ]
*/
module.exports = function pathParse(svgPath) {
var state = new State(svgPath);
var max = state.max;
skipSpaces(state);
while (state.index < max && !state.err.length) {
scanSegment(state);
}
if (state.err.length) {
state.result = [];
} else if (state.result.length) {
if ('mM'.indexOf(state.result[0][0]) < 0) {
state.err = 'SvgPath: string should start with `M` or `m`';
state.result = [];
} else {
state.result[0][0] = 'M';
}
}
return {
err: state.err,
segments: state.result
};
};

629
static/js/ketcher2/node_modules/svgpath/lib/svgpath.js generated vendored Normal file
View File

@ -0,0 +1,629 @@
// SVG Path transformations library
//
// Usage:
//
// SvgPath('...')
// .translate(-150, -100)
// .scale(0.5)
// .translate(-150, -100)
// .toFixed(1)
// .toString()
//
'use strict';
var pathParse = require('./path_parse');
var transformParse = require('./transform_parse');
var matrix = require('./matrix');
var a2c = require('./a2c');
var ellipse = require('./ellipse');
// Class constructor
//
function SvgPath(path) {
if (!(this instanceof SvgPath)) { return new SvgPath(path); }
var pstate = pathParse(path);
// Array of path segments.
// Each segment is array [command, param1, param2, ...]
this.segments = pstate.segments;
// Error message on parse error.
this.err = pstate.err;
// Transforms stack for lazy evaluation
this.__stack = [];
}
SvgPath.prototype.__matrix = function (m) {
var self = this, i;
// Quick leave for empty matrix
if (!m.queue.length) { return; }
this.iterate(function (s, index, x, y) {
var p, result, name, isRelative;
switch (s[0]) {
// Process 'assymetric' commands separately
case 'v':
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, 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(s[1], 0, true);
result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ];
break;
case 'H':
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;
case 'a':
case 'A':
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// Drop segment if arc is empty (end point === start point)
/*if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
return [];
}*/
// Transform rx, ry and the x-axis-rotation
var ma = m.toArray();
var e = ellipse(s[1], s[2], s[3]).transform(ma);
// flip sweep-flag if matrix is not orientation-preserving
if (ma[0] * ma[3] - ma[1] * ma[2] < 0) {
s[5] = s[5] ? '0' : '1';
}
// Transform end point as usual (without translation for relative notation)
p = m.calc(s[6], s[7], s[0] === 'a');
// Empty arcs can be ignored by renderer, but should not be dropped
// to avoid collisions with `S A S` and so on. Replace with empty line.
if ((s[0] === 'A' && s[6] === x && s[7] === y) ||
(s[0] === 'a' && s[6] === 0 && s[7] === 0)) {
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
break;
}
// if the resulting ellipse is (almost) a segment ...
if (e.isDegenerate()) {
// replace the arc by a line
result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ];
} else {
// if it is a real ellipse
// s[0], s[4] and s[5] are not modified
result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ];
}
break;
case 'm':
// Edge case. The very first `m` should be processed as absolute, if happens.
// Make sense for coord shift transforms.
isRelative = index > 0;
p = m.calc(s[1], s[2], isRelative);
result = [ 'm', p[0], p[1] ];
break;
default:
name = s[0];
result = [ name ];
isRelative = (name.toLowerCase() === name);
// Apply transformations to the segment
for (i = 1; i < s.length; i += 2) {
p = m.calc(s[i], s[i + 1], isRelative);
result.push(p[0], p[1]);
}
}
self.segments[index] = result;
}, true);
};
// Apply stacked commands
//
SvgPath.prototype.__evaluateStack = function () {
var m, i;
if (!this.__stack.length) { return; }
if (this.__stack.length === 1) {
this.__matrix(this.__stack[0]);
this.__stack = [];
return;
}
m = matrix();
i = this.__stack.length;
while (--i >= 0) {
m.matrix(this.__stack[i].toArray());
}
this.__matrix(m);
this.__stack = [];
};
// Convert processed SVG Path back to string
//
SvgPath.prototype.toString = function () {
var elements = [], skipCmd, cmd;
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]);
}
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');
};
// Translate path to (x [, y])
//
SvgPath.prototype.translate = function (x, y) {
this.__stack.push(matrix().translate(x, y || 0));
return this;
};
// Scale path to (sx [, sy])
// sy = sx if not defined
//
SvgPath.prototype.scale = function (sx, sy) {
this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy));
return this;
};
// Rotate path around point (sx [, sy])
// sy = sx if not defined
//
SvgPath.prototype.rotate = function (angle, rx, ry) {
this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0));
return this;
};
// Skew path along the X axis by `degrees` angle
//
SvgPath.prototype.skewX = function (degrees) {
this.__stack.push(matrix().skewX(degrees));
return this;
};
// Skew path along the Y axis by `degrees` angle
//
SvgPath.prototype.skewY = function (degrees) {
this.__stack.push(matrix().skewY(degrees));
return this;
};
// Apply matrix transform (array of 6 elements)
//
SvgPath.prototype.matrix = function (m) {
this.__stack.push(matrix().matrix(m));
return this;
};
// Transform path according to "transform" attr of SVG spec
//
SvgPath.prototype.transform = function (transformString) {
if (!transformString.trim()) {
return this;
}
this.__stack.push(transformParse(transformString));
return this;
};
// Round coords with given decimal precition.
// 0 by default (to integers)
//
SvgPath.prototype.round = function (d) {
var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l;
d = d || 0;
this.__evaluateStack();
this.segments.forEach(function (s) {
var isRelative = (s[0].toLowerCase() === s[0]);
switch (s[0]) {
case 'H':
case 'h':
if (isRelative) { s[1] += deltaX; }
deltaX = s[1] - s[1].toFixed(d);
s[1] = +s[1].toFixed(d);
return;
case 'V':
case 'v':
if (isRelative) { s[1] += deltaY; }
deltaY = s[1] - s[1].toFixed(d);
s[1] = +s[1].toFixed(d);
return;
case 'Z':
case 'z':
deltaX = contourStartDeltaX;
deltaY = contourStartDeltaY;
return;
case 'M':
case 'm':
if (isRelative) {
s[1] += deltaX;
s[2] += deltaY;
}
deltaX = s[1] - s[1].toFixed(d);
deltaY = s[2] - s[2].toFixed(d);
contourStartDeltaX = deltaX;
contourStartDeltaY = deltaY;
s[1] = +s[1].toFixed(d);
s[2] = +s[2].toFixed(d);
return;
case 'A':
case 'a':
// [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
if (isRelative) {
s[6] += deltaX;
s[7] += deltaY;
}
deltaX = s[6] - s[6].toFixed(d);
deltaY = s[7] - s[7].toFixed(d);
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;
default:
// a c l q s t
l = s.length;
if (isRelative) {
s[l - 2] += deltaX;
s[l - 1] += deltaY;
}
deltaX = s[l - 2] - s[l - 2].toFixed(d);
deltaY = s[l - 1] - s[l - 1].toFixed(d);
s.forEach(function (val, i) {
if (!i) { return; }
s[i] = +s[i].toFixed(d);
});
return;
}
});
return this;
};
// Apply iterator function to all segments. If function returns result,
// current segment will be replaced to array of returned segments.
// If empty array is returned, current regment will be deleted.
//
SvgPath.prototype.iterate = function (iterator, keepLazyStack) {
var segments = this.segments,
replacements = {},
needReplace = false,
lastX = 0,
lastY = 0,
countourStartX = 0,
countourStartY = 0;
var i, j, newSegments;
if (!keepLazyStack) {
this.__evaluateStack();
}
segments.forEach(function (s, index) {
var res = iterator(s, index, lastX, lastY);
if (Array.isArray(res)) {
replacements[index] = res;
needReplace = true;
}
var isRelative = (s[0] === s[0].toLowerCase());
// calculate absolute X and Y
switch (s[0]) {
case 'm':
case 'M':
lastX = s[1] + (isRelative ? lastX : 0);
lastY = s[2] + (isRelative ? lastY : 0);
countourStartX = lastX;
countourStartY = lastY;
return;
case 'h':
case 'H':
lastX = s[1] + (isRelative ? lastX : 0);
return;
case 'v':
case 'V':
lastY = s[1] + (isRelative ? lastY : 0);
return;
case 'z':
case 'Z':
// That make sence for multiple contours
lastX = countourStartX;
lastY = countourStartY;
return;
default:
lastX = s[s.length - 2] + (isRelative ? lastX : 0);
lastY = s[s.length - 1] + (isRelative ? lastY : 0);
}
});
// Replace segments if iterator return results
if (!needReplace) { return this; }
newSegments = [];
for (i = 0; i < segments.length; i++) {
if (typeof replacements[i] !== 'undefined') {
for (j = 0; j < replacements[i].length; j++) {
newSegments.push(replacements[i][j]);
}
} else {
newSegments.push(segments[i]);
}
}
this.segments = newSegments;
return this;
};
// Converts segments from relative to absolute
//
SvgPath.prototype.abs = function () {
this.iterate(function (s, index, x, y) {
var name = s[0],
nameUC = name.toUpperCase(),
i;
// Skip absolute commands
if (name === nameUC) { return; }
s[0] = nameUC;
switch (name) {
case 'v':
// v has shifted coords parity
s[1] += y;
return;
case 'a':
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// touch x, y only
s[6] += x;
s[7] += y;
return;
default:
for (i = 1; i < s.length; i++) {
s[i] += i % 2 ? x : y; // odd values are X, even - Y
}
}
}, true);
return this;
};
// Converts segments from absolute to relative
//
SvgPath.prototype.rel = function () {
this.iterate(function (s, index, x, y) {
var name = s[0],
nameLC = name.toLowerCase(),
i;
// Skip relative commands
if (name === nameLC) { return; }
// Don't touch the first M to avoid potential confusions.
if (index === 0 && name === 'M') { return; }
s[0] = nameLC;
switch (name) {
case 'V':
// V has shifted coords parity
s[1] -= y;
return;
case 'A':
// ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// touch x, y only
s[6] -= x;
s[7] -= y;
return;
default:
for (i = 1; i < s.length; i++) {
s[i] -= i % 2 ? x : y; // odd values are X, even - Y
}
}
}, true);
return this;
};
// Converts arcs to cubic bézier curves
//
SvgPath.prototype.unarc = function () {
this.iterate(function (s, index, x, y) {
var new_segments, nextX, nextY, result = [], name = s[0];
// Skip anything except arcs
if (name !== 'A' && name !== 'a') { return null; }
if (name === 'a') {
// convert relative arc coordinates to absolute
nextX = x + s[6];
nextY = y + s[7];
} else {
nextX = s[6];
nextY = s[7];
}
new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]);
// Degenerated arcs can be ignored by renderer, but should not be dropped
// to avoid collisions with `S A S` and so on. Replace with empty line.
if (new_segments.length === 0) {
return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ];
}
new_segments.forEach(function (s) {
result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]);
});
return result;
});
return this;
};
// Converts smooth curves (with missed control point) to generic curves
//
SvgPath.prototype.unshort = function () {
var segments = this.segments;
var prevControlX, prevControlY, prevSegment;
var curControlX, curControlY;
// TODO: add lazy evaluation flag when relative commands supported
this.iterate(function (s, idx, x, y) {
var name = s[0], nameUC = name.toUpperCase(), isRelative;
// First command MUST be M|m, it's safe to skip.
// Protect from access to [-1] for sure.
if (!idx) { return; }
if (nameUC === 'T') { // quadratic curve
isRelative = (name === 't');
prevSegment = segments[idx - 1];
if (prevSegment[0] === 'Q') {
prevControlX = prevSegment[1] - x;
prevControlY = prevSegment[2] - y;
} else if (prevSegment[0] === 'q') {
prevControlX = prevSegment[1] - prevSegment[3];
prevControlY = prevSegment[2] - prevSegment[4];
} else {
prevControlX = 0;
prevControlY = 0;
}
curControlX = -prevControlX;
curControlY = -prevControlY;
if (!isRelative) {
curControlX += x;
curControlY += y;
}
segments[idx] = [
isRelative ? 'q' : 'Q',
curControlX, curControlY,
s[1], s[2]
];
} else if (nameUC === 'S') { // cubic curve
isRelative = (name === 's');
prevSegment = segments[idx - 1];
if (prevSegment[0] === 'C') {
prevControlX = prevSegment[3] - x;
prevControlY = prevSegment[4] - y;
} else if (prevSegment[0] === 'c') {
prevControlX = prevSegment[3] - prevSegment[5];
prevControlY = prevSegment[4] - prevSegment[6];
} else {
prevControlX = 0;
prevControlY = 0;
}
curControlX = -prevControlX;
curControlY = -prevControlY;
if (!isRelative) {
curControlX += x;
curControlY += y;
}
segments[idx] = [
isRelative ? 'c' : 'C',
curControlX, curControlY,
s[1], s[2], s[3], s[4]
];
}
});
return this;
};
module.exports = SvgPath;

View File

@ -0,0 +1,87 @@
'use strict';
var Matrix = require('./matrix');
var operations = {
matrix: true,
scale: true,
rotate: true,
translate: true,
skewX: true,
skewY: true
};
var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/;
var PARAMS_SPLIT_RE = /[\s,]+/;
module.exports = function transformParse(transformString) {
var matrix = new Matrix();
var cmd, params;
// Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
transformString.split(CMD_SPLIT_RE).forEach(function (item) {
// Skip empty elements
if (!item.length) { return; }
// remember operation
if (typeof operations[item] !== 'undefined') {
cmd = item;
return;
}
// extract params & att operation to matrix
params = item.split(PARAMS_SPLIT_RE).map(function (i) {
return +i || 0;
});
// If params count is not correct - ignore command
switch (cmd) {
case 'matrix':
if (params.length === 6) {
matrix.matrix(params);
}
return;
case 'scale':
if (params.length === 1) {
matrix.scale(params[0], params[0]);
} else if (params.length === 2) {
matrix.scale(params[0], params[1]);
}
return;
case 'rotate':
if (params.length === 1) {
matrix.rotate(params[0], 0, 0);
} else if (params.length === 3) {
matrix.rotate(params[0], params[1], params[2]);
}
return;
case 'translate':
if (params.length === 1) {
matrix.translate(params[0], 0);
} else if (params.length === 2) {
matrix.translate(params[0], params[1]);
}
return;
case 'skewX':
if (params.length === 1) {
matrix.skewX(params[0]);
}
return;
case 'skewY':
if (params.length === 1) {
matrix.skewY(params[0]);
}
return;
}
});
return matrix;
};

67
static/js/ketcher2/node_modules/svgpath/package.json generated vendored Normal file
View File

@ -0,0 +1,67 @@
{
"_from": "svgpath@^2.1.5",
"_id": "svgpath@2.2.1",
"_inBundle": false,
"_integrity": "sha1-CDS7Z8iadkcrK9BswQH6e1F7Iiw=",
"_location": "/svgpath",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "svgpath@^2.1.5",
"name": "svgpath",
"escapedName": "svgpath",
"rawSpec": "^2.1.5",
"saveSpec": null,
"fetchSpec": "^2.1.5"
},
"_requiredBy": [
"/svg2ttf"
],
"_resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.2.1.tgz",
"_shasum": "0834bb67c89a76472b2bd06cc101fa7b517b222c",
"_spec": "svgpath@^2.1.5",
"_where": "/home/manfred/enviPath/ketcher2/ketcher/node_modules/svg2ttf",
"bugs": {
"url": "https://github.com/fontello/svgpath/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Low level toolkit for SVG paths transformations.",
"devDependencies": {
"ansi": "^0.3.1",
"benchmark": "^2.1.1",
"coveralls": "^2.11.2",
"eslint": "^3.5.0",
"istanbul": "^0.4.5",
"mocha": "^3.0.2"
},
"files": [
"index.js",
"index.d.ts",
"lib/"
],
"homepage": "https://github.com/fontello/svgpath#readme",
"keywords": [
"svg",
"path",
"transform",
"scale",
"translate",
"rotate",
"matrix"
],
"license": "MIT",
"name": "svgpath",
"repository": {
"type": "git",
"url": "git+https://github.com/fontello/svgpath.git"
},
"scripts": {
"coverage": "rm -rf coverage && istanbul cover _mocha",
"lint": "eslint .",
"report-coveralls": "istanbul cover _mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage",
"test": "npm run lint && mocha"
},
"version": "2.2.1"
}