Changes:
* replaced some path processing with SVGPathCommander * minor improvements
This commit is contained in:
parent
b152aa8fa6
commit
b0a6495748
|
@ -240,6 +240,19 @@
|
|||
return {name:ComponentName}
|
||||
};
|
||||
|
||||
function queueStart(){
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
}
|
||||
|
||||
var TweenBase = function TweenBase(targetElement, startObject, endObject, options){
|
||||
this.element = targetElement;
|
||||
this.playing = false;
|
||||
|
@ -273,16 +286,7 @@
|
|||
if (this._onStart) {
|
||||
this._onStart.call(this);
|
||||
}
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
queueStart.call(this);
|
||||
this._startFired = true;
|
||||
}
|
||||
!Tick && Ticker();
|
||||
|
|
2
demo/src/kute-base.min.js
vendored
2
demo/src/kute-base.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -21,7 +21,7 @@
|
|||
|
||||
var Interpolate = {};
|
||||
|
||||
var onStart$1 = {};
|
||||
var onStart = {};
|
||||
|
||||
var Time = {};
|
||||
Time.now = self.performance.now.bind(self.performance);
|
||||
|
@ -42,11 +42,11 @@
|
|||
if (!Tweens.length && Tick) {
|
||||
cancelAnimationFrame(Tick);
|
||||
Tick = null;
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
KUTE[obj] && (delete KUTE[obj]);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
for (var prop in onStart[obj]) {
|
||||
KUTE[prop] && (delete KUTE[prop]);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@
|
|||
prepareProperty: prepareProperty,
|
||||
prepareStart: prepareStart,
|
||||
crossCheck: crossCheck,
|
||||
onStart: onStart$1,
|
||||
onStart: onStart,
|
||||
onComplete: onComplete,
|
||||
linkProperty: linkProperty
|
||||
};
|
||||
|
@ -112,7 +112,7 @@
|
|||
|
||||
function removeAll () { Tweens.length = 0; }
|
||||
|
||||
function linkInterpolation$1() {
|
||||
function linkInterpolation() {
|
||||
var this$1 = this;
|
||||
var loop = function ( component ) {
|
||||
var componentLink = linkProperty[component];
|
||||
|
@ -149,7 +149,7 @@
|
|||
getAll: getAll,
|
||||
removeAll: removeAll,
|
||||
stop: stop,
|
||||
linkInterpolation: linkInterpolation$1
|
||||
linkInterpolation: linkInterpolation
|
||||
};
|
||||
|
||||
function getInlineStyle(el) {
|
||||
|
@ -352,6 +352,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
function queueStart(){
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
}
|
||||
|
||||
var TweenBase = function TweenBase(targetElement, startObject, endObject, options){
|
||||
this.element = targetElement;
|
||||
this.playing = false;
|
||||
|
@ -369,8 +382,8 @@
|
|||
if( !(internalOption in this ) ) { this[internalOption] = options[op]; }
|
||||
}
|
||||
var easingFnName = this._easing.name;
|
||||
if (!onStart$1[easingFnName]) {
|
||||
onStart$1[easingFnName] = function(prop){
|
||||
if (!onStart[easingFnName]) {
|
||||
onStart[easingFnName] = function(prop){
|
||||
!KUTE[prop] && prop === this._easing.name && (KUTE[prop] = this._easing);
|
||||
};
|
||||
}
|
||||
|
@ -385,16 +398,7 @@
|
|||
if (this._onStart) {
|
||||
this._onStart.call(this);
|
||||
}
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
onStart$1[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
onStart$1[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation$1.call(this);
|
||||
queueStart.call(this);
|
||||
this._startFired = true;
|
||||
}
|
||||
!Tick && Ticker();
|
||||
|
@ -540,16 +544,7 @@
|
|||
if (this._onResume !== undefined) {
|
||||
this._onResume.call(this);
|
||||
}
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
queueStart.call(this);
|
||||
this._startTime += KUTE.Time() - this._pauseTime;
|
||||
add(this);
|
||||
!Tick && Ticker();
|
||||
|
@ -799,7 +794,7 @@
|
|||
Animation.prototype.setComponent = function setComponent (Component){
|
||||
var propertyInfo = this;
|
||||
var ComponentName = Component.component;
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart$1, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Category = Component.category;
|
||||
var Property = Component.property;
|
||||
var Length = Component.properties && Component.properties.length || Component.subProperties && Component.subProperties.length;
|
||||
|
@ -868,7 +863,7 @@
|
|||
AnimationDevelopment.prototype.setComponent = function setComponent (Component){
|
||||
Animation.prototype.setComponent.call(this, Component);
|
||||
var propertyInfo = this;
|
||||
var Functions = { prepareProperty: prepareProperty,prepareStart: prepareStart,onStart: onStart$1,onComplete: onComplete,crossCheck: crossCheck };
|
||||
var Functions = { prepareProperty: prepareProperty,prepareStart: prepareStart,onStart: onStart,onComplete: onComplete,crossCheck: crossCheck };
|
||||
var Category = Component.category;
|
||||
var Property = Component.property;
|
||||
var Length = Component.properties && Component.properties.length || Component.subProperties && Component.subProperties.length;
|
||||
|
@ -1232,7 +1227,7 @@
|
|||
if ( currentValue !== null && regex.test(currentValue) ) {
|
||||
var unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u;
|
||||
var suffix = /%/.test(unit) ? '_percent' : ("_" + unit);
|
||||
onStart$1[ComponentName][prop+suffix] = function(tp) {
|
||||
onStart[ComponentName][prop+suffix] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, p, a, b, v) {
|
||||
var _p = p.replace(suffix,'');
|
||||
|
@ -1242,7 +1237,7 @@
|
|||
};
|
||||
attributesObject[prop+suffix] = trueDimension(attrObj[p]);
|
||||
} else if ( !regex.test(attrObj[p]) || currentValue === null || currentValue !== null && !regex.test(currentValue) ) {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, (numbers(a,b,v) * 1000 >> 0) / 1000 );
|
||||
|
@ -1252,7 +1247,7 @@
|
|||
attributesObject[prop] = parseFloat(attrObj[p]);
|
||||
}
|
||||
} else {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, colors(a,b,v));
|
||||
|
@ -1560,17 +1555,16 @@
|
|||
};
|
||||
Components.SVGDraw = svgDraw;
|
||||
|
||||
function toPathString(pathArray) {
|
||||
var newPath = pathArray.map( function (c) {
|
||||
if (typeof(c) === 'string') {
|
||||
function pathToString(pathArray) {
|
||||
return pathArray.map( function (c) {
|
||||
if (typeof c === 'string') {
|
||||
return c
|
||||
} else {
|
||||
var c0 = c.shift();
|
||||
return c0 + c.join(',')
|
||||
return c.shift() + c.join(',')
|
||||
}
|
||||
});
|
||||
return newPath.join('');
|
||||
}).join(' ')
|
||||
}
|
||||
|
||||
function onStartCubicMorph(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = function(elem,a,b,v){
|
||||
|
@ -1581,12 +1575,256 @@
|
|||
curve[i].push( (numbers(path1[i][j], path2[i][j], v) * 1000 >>0)/1000 );
|
||||
}
|
||||
}
|
||||
elem.setAttribute("d", v === 1 ? b.original : toPathString(curve) );
|
||||
elem.setAttribute("d", v === 1 ? b.original : pathToString(curve) );
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var INVALID_INPUT = 'Invalid path value';
|
||||
function clonePath(pathArray){
|
||||
return pathArray.map(function (x) { return Array.isArray(x) ? clonePath(x) : !isNaN(+x) ? +x : x; } )
|
||||
}
|
||||
|
||||
var SVGPCOps = {
|
||||
decimals:3,
|
||||
round:1
|
||||
};
|
||||
|
||||
function roundPath(pathArray) {
|
||||
return pathArray.map( function (seg) { return seg.map(function (c,i) {
|
||||
var nr = +c, dc = Math.pow(10,SVGPCOps.decimals);
|
||||
return i ? (nr % 1 === 0 ? nr : (nr*dc>>0)/dc) : c
|
||||
}
|
||||
); })
|
||||
}
|
||||
|
||||
function SVGPathArray(pathString){
|
||||
this.segments = [];
|
||||
this.isClosed = 0;
|
||||
this.isAbsolute = 0;
|
||||
this.pathValue = pathString;
|
||||
this.max = pathString.length;
|
||||
this.index = 0;
|
||||
this.param = 0.0;
|
||||
this.segmentStart = 0;
|
||||
this.data = [];
|
||||
this.err = '';
|
||||
return this
|
||||
}
|
||||
|
||||
var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
|
||||
function isSpace(ch) {
|
||||
var specialSpaces = [
|
||||
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
|
||||
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF ];
|
||||
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) ||
|
||||
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
|
||||
(ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0);
|
||||
}
|
||||
function isCommand(code) {
|
||||
switch (code | 0x20) {
|
||||
case 0x6D:
|
||||
case 0x7A:
|
||||
case 0x6C:
|
||||
case 0x68:
|
||||
case 0x76:
|
||||
case 0x63:
|
||||
case 0x73:
|
||||
case 0x71:
|
||||
case 0x74:
|
||||
case 0x61:
|
||||
case 0x72:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function isArc(code) {
|
||||
return (code | 0x20) === 0x61;
|
||||
}
|
||||
function isDigit(code) {
|
||||
return (code >= 48 && code <= 57);
|
||||
}
|
||||
function isDigitStart(code) {
|
||||
return (code >= 48 && code <= 57) ||
|
||||
code === 0x2B ||
|
||||
code === 0x2D ||
|
||||
code === 0x2E;
|
||||
}
|
||||
function skipSpaces(state) {
|
||||
while (state.index < state.max && isSpace(state.pathValue.charCodeAt(state.index))) {
|
||||
state.index++;
|
||||
}
|
||||
}
|
||||
function scanFlag(state) {
|
||||
var ch = state.pathValue.charCodeAt(state.index);
|
||||
if (ch === 0x30) {
|
||||
state.param = 0;
|
||||
state.index++;
|
||||
return;
|
||||
}
|
||||
if (ch === 0x31) {
|
||||
state.param = 1;
|
||||
state.index++;
|
||||
return;
|
||||
}
|
||||
state.err = 'SvgPath: arc flag can be 0 or 1 only (at pos ' + 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.pathValue.charCodeAt(index);
|
||||
if (ch === 0x2B || ch === 0x2D) {
|
||||
index++;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
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);
|
||||
index++;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
if (zeroFirst && index < max) {
|
||||
if (ch && isDigit(ch)) {
|
||||
state.err = 'SvgPath: numbers started with `0` such as `09` are illegal (at pos ' + start + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasCeiling = true;
|
||||
}
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x2E) {
|
||||
hasDot = true;
|
||||
index++;
|
||||
while (isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasDecimal = true;
|
||||
}
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x65 || ch === 0x45) {
|
||||
if (hasDot && !hasCeiling && !hasDecimal) {
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
if (ch === 0x2B || ch === 0x2D) {
|
||||
index++;
|
||||
}
|
||||
if (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
state.index = index;
|
||||
state.param = parseFloat(state.pathValue.slice(start, index)) + 0.0;
|
||||
}
|
||||
function finalizeSegment(state) {
|
||||
var cmd = state.pathValue[state.segmentStart], cmdLC = cmd.toLowerCase(), params = state.data;
|
||||
if (cmdLC === 'm' && params.length > 2) {
|
||||
state.segments.push([ cmd, params[0], params[1] ]);
|
||||
params = params.slice(2);
|
||||
cmdLC = 'l';
|
||||
cmd = (cmd === 'm') ? 'l' : 'L';
|
||||
}
|
||||
if (cmdLC === 'r') {
|
||||
state.segments.push([ cmd ].concat(params));
|
||||
} else {
|
||||
while (params.length >= paramCounts[cmdLC]) {
|
||||
state.segments.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
||||
if (!paramCounts[cmdLC]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function scanSegment(state) {
|
||||
var max = state.max, cmdCode, is_arc, comma_found, need_params, i;
|
||||
state.segmentStart = state.index;
|
||||
cmdCode = state.pathValue.charCodeAt(state.index);
|
||||
is_arc = isArc(cmdCode);
|
||||
if (!isCommand(cmdCode)) {
|
||||
state.err = 'SvgPath: bad command ' + state.pathValue[state.index] + ' (at pos ' + state.index + ')';
|
||||
return;
|
||||
}
|
||||
need_params = paramCounts[state.pathValue[state.index].toLowerCase()];
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
state.data = [];
|
||||
if (!need_params) {
|
||||
state.isClosed = 1;
|
||||
finalizeSegment(state);
|
||||
return;
|
||||
}
|
||||
comma_found = false;
|
||||
for (;;) {
|
||||
for (i = need_params; i > 0; i--) {
|
||||
if (is_arc && (i === 3 || i === 4)) { scanFlag(state); }
|
||||
else { scanParam(state); }
|
||||
if (state.err.length) {
|
||||
return;
|
||||
}
|
||||
state.data.push(state.param);
|
||||
skipSpaces(state);
|
||||
comma_found = false;
|
||||
if (state.index < max && state.pathValue.charCodeAt(state.index) === 0x2C) {
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
comma_found = true;
|
||||
}
|
||||
}
|
||||
if (comma_found) {
|
||||
continue;
|
||||
}
|
||||
if (state.index >= state.max) {
|
||||
break;
|
||||
}
|
||||
if (!isDigitStart(state.pathValue.charCodeAt(state.index))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
finalizeSegment(state);
|
||||
}
|
||||
function parsePathString(pathString) {
|
||||
if ( Array.isArray(pathString) ) {
|
||||
return clonePath(pathString)
|
||||
}
|
||||
var state = new SVGPathArray(pathString), max = state.max;
|
||||
skipSpaces(state);
|
||||
while (state.index < max && !state.err.length) {
|
||||
scanSegment(state);
|
||||
}
|
||||
if (state.err.length) {
|
||||
state.segments = [];
|
||||
} else if (state.segments.length) {
|
||||
if ('mM'.indexOf(state.segments[0][0]) < 0) {
|
||||
state.err = 'SvgPath: string should start with `M` or `m`';
|
||||
state.segments = [];
|
||||
} else {
|
||||
state.segments[0][0] = 'M';
|
||||
}
|
||||
}
|
||||
return roundPath(state.segments)
|
||||
}
|
||||
|
||||
function catmullRom2bezier(crp, z) {
|
||||
var d = [];
|
||||
for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
|
||||
|
@ -1612,17 +1850,19 @@
|
|||
p[0] = {x: +crp[i], y: +crp[i + 1]};
|
||||
}
|
||||
}
|
||||
d.push(["C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
d.push([
|
||||
"C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
]);
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
function ellipsePath(x, y, rx, ry, a) {
|
||||
if (a == null && ry == null) {
|
||||
ry = rx;
|
||||
|
@ -1634,10 +1874,10 @@
|
|||
var res;
|
||||
if (a != null) {
|
||||
var rad = Math.PI / 180,
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad);
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad);
|
||||
res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
|
||||
} else {
|
||||
res = [
|
||||
|
@ -1650,49 +1890,18 @@
|
|||
}
|
||||
return res;
|
||||
}
|
||||
function parsePathString(pathString) {
|
||||
if (!pathString) {
|
||||
return null;
|
||||
}
|
||||
if( pathString instanceof Array ) {
|
||||
return pathString;
|
||||
} else {
|
||||
var spaces = "\\" + (("x09|x0a|x0b|x0c|x0d|x20|xa0|u1680|u180e|u2000|u2001|u2002|u2003|u2004|u2005|u2006|u2007|u2008|u2009|u200a|u202f|u205f|u3000|u2028|u2029").split('|').join('\\')),
|
||||
pathCommand = new RegExp(("([a-z])[" + spaces + ",]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[" + spaces + "]*,?[" + spaces + "]*)+)"), "ig"),
|
||||
pathValues = new RegExp(("(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[" + spaces + "]*,?[" + spaces + "]*"), "ig"),
|
||||
paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
|
||||
data = [];
|
||||
pathString.replace(pathCommand, function (a, b, c) {
|
||||
var params = [], name = b.toLowerCase();
|
||||
c.replace(pathValues, function (a, b) {
|
||||
b && params.push(+b);
|
||||
});
|
||||
if (name == "m" && params.length > 2) {
|
||||
data.push([b].concat(params.splice(0, 2)));
|
||||
name = "l";
|
||||
b = b == "m" ? "l" : "L";
|
||||
}
|
||||
if (name == "o" && params.length == 1) {
|
||||
data.push([b, params[0]]);
|
||||
}
|
||||
if (name == "r") {
|
||||
data.push([b].concat(params));
|
||||
} else { while (params.length >= paramCounts[name]) {
|
||||
data.push([b].concat(params.splice(0, paramCounts[name])));
|
||||
if (!paramCounts[name]) {
|
||||
break;
|
||||
}
|
||||
} }
|
||||
});
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
function pathToAbsolute(pathArray) {
|
||||
pathArray = parsePathString(pathArray);
|
||||
if (!pathArray || !pathArray.length) {
|
||||
return [["M", 0, 0]];
|
||||
}
|
||||
var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0, pa0;
|
||||
var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0,
|
||||
ii = pathArray.length,
|
||||
crz = pathArray.length === 3 &&
|
||||
pathArray[0][0] === "M" &&
|
||||
pathArray[1][0].toUpperCase() === "R" &&
|
||||
pathArray[2][0].toUpperCase() === "Z";
|
||||
if (pathArray[0][0] === "M") {
|
||||
x = +pathArray[0][1];
|
||||
y = +pathArray[0][2];
|
||||
|
@ -1701,14 +1910,9 @@
|
|||
start++;
|
||||
res[0] = ["M", x, y];
|
||||
}
|
||||
var crz = pathArray.length === 3 &&
|
||||
pathArray[0][0] === "M" &&
|
||||
pathArray[1][0].toUpperCase() === "R" &&
|
||||
pathArray[2][0].toUpperCase() === "Z";
|
||||
for (var r = (void 0), pa = (void 0), i = start, ii = pathArray.length; i < ii; i++) {
|
||||
var loop = function ( i ) {
|
||||
var r = (void 0), pa = pathArray[i], pa0 = pa[0];
|
||||
res.push(r = []);
|
||||
pa = pathArray[i];
|
||||
pa0 = pa[0];
|
||||
if (pa0 !== pa0.toUpperCase()) {
|
||||
r[0] = pa0.toUpperCase();
|
||||
switch (r[0]) {
|
||||
|
@ -1728,19 +1932,19 @@
|
|||
r[1] = +pa[1] + x;
|
||||
break;
|
||||
case "R":
|
||||
var dots = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots.length; j < jj; j++) {
|
||||
dots[j] = +dots[j] + x;
|
||||
dots[++j] = +dots[j] + y;
|
||||
var dots$1 = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots$1.length; j < jj; j++) {
|
||||
dots$1[j] = +dots$1[j] + x;
|
||||
dots$1[++j] = +dots$1[j] + y;
|
||||
}
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
res = res.concat(catmullRom2bezier(dots$1, crz));
|
||||
break;
|
||||
case "O":
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
dots$1 = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots$1.push(dots$1[0]);
|
||||
res = res.concat(dots$1);
|
||||
break;
|
||||
case "U":
|
||||
res.pop();
|
||||
|
@ -1751,84 +1955,71 @@
|
|||
mx = +pa[1] + x;
|
||||
my = +pa[2] + y;
|
||||
default:
|
||||
for (j = 1, jj = pa.length; j < jj; j++) {
|
||||
r[j] = +pa[j] + ((j % 2) ? x : y);
|
||||
for (var j$1 = 1, jj$1 = pa.length; j$1 < jj$1; j$1++) {
|
||||
r[j$1] = +pa[j$1] + ((j$1 % 2) ? x : y);
|
||||
}
|
||||
}
|
||||
} else if (pa0 == "R") {
|
||||
} else if (pa0 === "R") {
|
||||
dots = [x, y].concat(pa.slice(1));
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
r = ["R"].concat(pa.slice(-2));
|
||||
} else if (pa0 == "O") {
|
||||
} else if (pa0 === "O") {
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
} else if (pa0 == "U") {
|
||||
} else if (pa0 === "U") {
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
res = res.concat(ellipsePath(x, y, +pa[1], +pa[2], +pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
} else {
|
||||
for (var k = 0, kk = pa.length; k < kk; k++) {
|
||||
r[k] = pa[k];
|
||||
}
|
||||
pa.map(function (k){ return r.push(k); });
|
||||
}
|
||||
pa0 = pa0.toUpperCase();
|
||||
if (pa0 != "O") {
|
||||
if (pa0 !== "O") {
|
||||
switch (r[0]) {
|
||||
case "Z":
|
||||
x = +mx;
|
||||
y = +my;
|
||||
x = mx;
|
||||
y = my;
|
||||
break;
|
||||
case "H":
|
||||
x = r[1];
|
||||
x = +r[1];
|
||||
break;
|
||||
case "V":
|
||||
y = r[1];
|
||||
y = +r[1];
|
||||
break;
|
||||
case "M":
|
||||
mx = r[r.length - 2];
|
||||
my = r[r.length - 1];
|
||||
mx = +r[r.length - 2];
|
||||
my = +r[r.length - 1];
|
||||
default:
|
||||
x = r[r.length - 2];
|
||||
y = r[r.length - 1];
|
||||
x = +r[r.length - 2];
|
||||
y = +r[r.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
};
|
||||
for (var i = start; i < ii; i++) loop( i );
|
||||
return roundPath(res)
|
||||
}
|
||||
function l2c(x1, y1, x2, y2) {
|
||||
return [x1, y1, x2, y2, x2, y2];
|
||||
}
|
||||
function q2c(x1, y1, ax, ay, x2, y2) {
|
||||
var _13 = 1 / 3;
|
||||
var _23 = 2 / 3;
|
||||
return [
|
||||
_13 * x1 + _23 * ax,
|
||||
_13 * y1 + _23 * ay,
|
||||
_13 * x2 + _23 * ax,
|
||||
_13 * y2 + _23 * ay,
|
||||
x2,
|
||||
y2
|
||||
]
|
||||
|
||||
function rotateVector(x, y, rad) {
|
||||
var X = x * Math.cos(rad) - y * Math.sin(rad),
|
||||
Y = x * Math.sin(rad) + y * Math.cos(rad);
|
||||
return {x: X, y: Y}
|
||||
}
|
||||
|
||||
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
|
||||
var _120 = Math.PI * 120 / 180, rad = Math.PI / 180 * (+angle || 0);
|
||||
var res = [], xy, f1, f2, cx, cy;
|
||||
function rotateVector(x, y, rad) {
|
||||
var X = x * Math.cos(rad) - y * Math.sin(rad),
|
||||
Y = x * Math.sin(rad) + y * Math.cos(rad);
|
||||
return {x: X, y: Y};
|
||||
}
|
||||
var _120 = Math.PI * 120 / 180,
|
||||
rad = Math.PI / 180 * (angle || 0),
|
||||
res = [], xy, f1, f2, cx, cy;
|
||||
if (!recursive) {
|
||||
xy = rotateVector(x1, y1, -rad);
|
||||
x1 = xy.x;
|
||||
y1 = xy.y;
|
||||
x1 = xy.x; y1 = xy.y;
|
||||
xy = rotateVector(x2, y2, -rad);
|
||||
x2 = xy.x;
|
||||
y2 = xy.y;
|
||||
var x = (x1 - x2) / 2, y = (y1 - y2) / 2, h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
|
||||
x2 = xy.x; y2 = xy.y;
|
||||
var x = (x1 - x2) / 2,
|
||||
y = (y1 - y2) / 2,
|
||||
h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
|
||||
if (h > 1) {
|
||||
h = Math.sqrt(h);
|
||||
rx = h * rx;
|
||||
|
@ -1841,8 +2032,8 @@
|
|||
/ (rx2 * y * y + ry2 * x * x)));
|
||||
cx = k * rx * y / ry + (x1 + x2) / 2,
|
||||
cy = k * -ry * x / rx + (y1 + y2) / 2;
|
||||
f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
|
||||
f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
|
||||
f1 = Math.asin(((y1 - cy) / ry)),
|
||||
f2 = Math.asin(((y2 - cy) / ry));
|
||||
f1 = x1 < cx ? Math.PI - f1 : f1;
|
||||
f2 = x2 < cx ? Math.PI - f2 : f2;
|
||||
f1 < 0 && (f1 = Math.PI * 2 + f1);
|
||||
|
@ -1869,30 +2060,43 @@
|
|||
}
|
||||
df = f2 - f1;
|
||||
var c1 = Math.cos(f1),
|
||||
s1 = Math.sin(f1),
|
||||
c2 = Math.cos(f2),
|
||||
s2 = Math.sin(f2),
|
||||
t = Math.tan(df / 4),
|
||||
hx = 4 / 3 * rx * t,
|
||||
hy = 4 / 3 * ry * t,
|
||||
m1 = [x1, y1],
|
||||
m2 = [x1 + hx * s1, y1 - hy * c1],
|
||||
m3 = [x2 + hx * s2, y2 - hy * c2],
|
||||
m4 = [x2, y2];
|
||||
s1 = Math.sin(f1),
|
||||
c2 = Math.cos(f2),
|
||||
s2 = Math.sin(f2),
|
||||
t = Math.tan(df / 4),
|
||||
hx = 4 / 3 * rx * t,
|
||||
hy = 4 / 3 * ry * t,
|
||||
m1 = [x1, y1],
|
||||
m2 = [x1 + hx * s1, y1 - hy * c1],
|
||||
m3 = [x2 + hx * s2, y2 - hy * c2],
|
||||
m4 = [x2, y2];
|
||||
m2[0] = 2 * m1[0] - m2[0];
|
||||
m2[1] = 2 * m1[1] - m2[1];
|
||||
if (recursive) {
|
||||
return [m2, m3, m4].concat(res);
|
||||
} else {
|
||||
res = [m2, m3, m4].concat(res).join().split(",");
|
||||
var newres = [];
|
||||
for (var i = 0, ii = res.length; i < ii; i++) {
|
||||
newres[i] = i % 2 ? rotateVector(res[i - 1], res[i], rad).y : rotateVector(res[i], res[i + 1], rad).x;
|
||||
}
|
||||
return newres;
|
||||
return res.map(function (rz,i){ return i % 2 ? rotateVector(res[i - 1], rz, rad).y : rotateVector(rz, res[i + 1], rad).x; });
|
||||
}
|
||||
}
|
||||
function processPath (path, d, pcom) {
|
||||
|
||||
function q2c (x1, y1, ax, ay, x2, y2) {
|
||||
var _13 = 1 / 3, _23 = 2 / 3;
|
||||
return [
|
||||
_13 * x1 + _23 * ax,
|
||||
_13 * y1 + _23 * ay,
|
||||
_13 * x2 + _23 * ax,
|
||||
_13 * y2 + _23 * ay,
|
||||
x2,
|
||||
y2
|
||||
]
|
||||
}
|
||||
|
||||
function l2c(x1, y1, x2, y2) {
|
||||
return [x1, y1, x2, y2, x2, y2];
|
||||
}
|
||||
|
||||
function processPath(path, d, pcom) {
|
||||
var nx, ny;
|
||||
if (!path) {
|
||||
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
|
||||
|
@ -1946,10 +2150,10 @@
|
|||
path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
|
||||
break;
|
||||
}
|
||||
path.map(function (x,i){ return i?x.toFixed(3):x; });
|
||||
return path;
|
||||
}
|
||||
function fixM (path1, path2, a1, a2, i) {
|
||||
|
||||
function fixM(path1, path2, a1, a2, i) {
|
||||
if (path1 && path2 && path1[i][0] === "M" && path2[i][0] !== "M") {
|
||||
path2.splice(i, 0, ["M", a2.x, a2.y]);
|
||||
a1.bx = 0;
|
||||
|
@ -1958,25 +2162,29 @@
|
|||
a1.y = path1[i][2];
|
||||
}
|
||||
}
|
||||
function fixArc (p, p2, pcoms1, pcoms2, i) {
|
||||
|
||||
function fixArc(p, p2, pc1, pc2, i) {
|
||||
if (p[i].length > 7) {
|
||||
p[i].shift();
|
||||
var pi = p[i];
|
||||
while (pi.length) {
|
||||
pcoms1[i] = "A";
|
||||
p2 && (pcoms2[i] = "A");
|
||||
pc1[i] = "A";
|
||||
p2 && (pc2[i] = "A");
|
||||
p.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
|
||||
}
|
||||
p.splice(i, 1);
|
||||
}
|
||||
}
|
||||
function path2curve(path, path2) {
|
||||
|
||||
function pathToCurve(path, path2) {
|
||||
var p = pathToAbsolute(path),
|
||||
p2 = path2 && pathToAbsolute(path2),
|
||||
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
|
||||
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null};
|
||||
var pcoms1 = [], pcoms2 = [], pfirst = "", pcom = "";
|
||||
for (var i = 0, ii = Math.max(p.length, p2 && p2.length || 0); i < ii; i++) {
|
||||
var pcoms1 = [], pcoms2 = [],
|
||||
pfirst = "", pcom = "",
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
for (var i = 0; i < ii; i++) {
|
||||
p[i] && (pfirst = p[i][0]);
|
||||
if (pfirst !== "C") {
|
||||
pcoms1[i] = pfirst;
|
||||
|
@ -2015,73 +2223,68 @@
|
|||
attrs2.x = p2 && seg2[seg2len - 2];
|
||||
attrs2.y = p2 && seg2[seg2len - 1];
|
||||
}
|
||||
return p2 ? [p, p2] : p;
|
||||
return p2 ? [roundPath(p), roundPath(p2)] : roundPath(p);
|
||||
}
|
||||
|
||||
function reverseCurve(pathCurveArray){
|
||||
var curveSegments = clonePath(pathCurveArray),
|
||||
curveCount = curveSegments.length - 2,
|
||||
ci = 0, ni = 0,
|
||||
currentSeg = [],
|
||||
nextSeg = [],
|
||||
x1, y1, x2, y2, x, y,
|
||||
curveOnly = curveSegments.slice(1),
|
||||
rotatedCurve = curveOnly.map(function (p,i){
|
||||
ci = curveCount - i;
|
||||
ni = ci - 1 < 0 ? curveCount : ci - 1;
|
||||
currentSeg = curveOnly[ci];
|
||||
nextSeg = curveOnly[ni];
|
||||
x = nextSeg[nextSeg.length - 2];
|
||||
y = nextSeg[nextSeg.length - 1];
|
||||
x1 = currentSeg[3]; y1 = currentSeg[4];
|
||||
x2 = currentSeg[1]; y2 = currentSeg[2];
|
||||
return [p[0],x1,y1,x2,y2,x,y]
|
||||
});
|
||||
return [['M',rotatedCurve[curveCount][5],rotatedCurve[curveCount][6]]].concat(rotatedCurve)
|
||||
}
|
||||
|
||||
function createPath (path) {
|
||||
var np = document.createElementNS('http://www.w3.org/2000/svg','path'),
|
||||
d = path instanceof SVGElement ? path.getAttribute('d') : path;
|
||||
np.setAttribute('d',d);
|
||||
return np
|
||||
}
|
||||
function getSegments(curveArray) {
|
||||
return curveArray.map(function (seg) {
|
||||
return {
|
||||
x: seg[seg[0] === 'M' ? 1 : 5],
|
||||
y: seg[seg[0] === 'M' ? 2 : 6],
|
||||
seg: seg
|
||||
function getRotationSegments(s,idx) {
|
||||
var segsCount = s.length, pointCount = segsCount - 1;
|
||||
return s.map(function (p,i){
|
||||
var oldSegIdx = idx + i, seg;
|
||||
if (i===0 || s[oldSegIdx] && s[oldSegIdx][0] === 'M') {
|
||||
seg = s[oldSegIdx];
|
||||
return ['M',seg[seg.length-2],seg[seg.length-1]]
|
||||
} else {
|
||||
if (oldSegIdx >= segsCount) { oldSegIdx -= pointCount; }
|
||||
return s[oldSegIdx]
|
||||
}
|
||||
})
|
||||
}
|
||||
function reverseCurve(path){
|
||||
var newSegments = [],
|
||||
oldSegments = getSegments(path),
|
||||
segsCount = oldSegments.length,
|
||||
pointCount = segsCount - 1,
|
||||
oldSegIdx = pointCount,
|
||||
oldSegs = [];
|
||||
oldSegments.map(function (p,i){
|
||||
if (i === 0||oldSegments[oldSegIdx].seg[0] === 'M') {
|
||||
newSegments[i] = ['M',oldSegments[oldSegIdx].x,oldSegments[oldSegIdx].y];
|
||||
} else {
|
||||
oldSegIdx = pointCount - i > 0 ? pointCount - i : pointCount;
|
||||
oldSegs = oldSegments[oldSegIdx].seg;
|
||||
newSegments[i] = [oldSegs[0], oldSegs[5],oldSegs[6],oldSegs[3],oldSegs[4], oldSegs[1], oldSegs[2]];
|
||||
}
|
||||
});
|
||||
return newSegments
|
||||
}
|
||||
function getRotationSegments(s,idx) {
|
||||
var newSegments = [], segsCount = s.length, pointCount = segsCount - 1;
|
||||
s.map(function (p,i){
|
||||
var oldSegIdx = idx + i;
|
||||
if (i===0 || s[oldSegIdx] && s[oldSegIdx].seg[0] === 'M') {
|
||||
newSegments[i] = ['M',s[oldSegIdx].x,s[oldSegIdx].y];
|
||||
} else {
|
||||
if (oldSegIdx >= segsCount) { oldSegIdx -= pointCount; }
|
||||
newSegments[i] = s[oldSegIdx].seg;
|
||||
}
|
||||
});
|
||||
return newSegments
|
||||
}
|
||||
function getRotations(a) {
|
||||
var startSegments = getSegments(a), rotations = [];
|
||||
startSegments.map(function (s,i){rotations[i] = getRotationSegments(startSegments,i);});
|
||||
return rotations
|
||||
return a.map(function (s,i) { return getRotationSegments(a,i); })
|
||||
}
|
||||
function getRotatedCurve(a,b) {
|
||||
var startSegments = getSegments(a),
|
||||
endSegments = getSegments(b),
|
||||
segsCount = startSegments.length,
|
||||
pointCount = segsCount - 1,
|
||||
var segCount = a.length - 1,
|
||||
linePaths = [],
|
||||
lineLengths = [],
|
||||
rotations = getRotations(a);
|
||||
rotations.map(function (r,i){
|
||||
var sumLensSqrd = 0, linePath = createPath('M0,0L0,0');
|
||||
for (var j = 0; j < pointCount; j++) {
|
||||
var linePt1 = startSegments[(i + j) % pointCount];
|
||||
var linePt2 = endSegments[ j % pointCount];
|
||||
var linePathStr = "M" + (linePt1.x) + "," + (linePt1.y) + "L" + (linePt2.x) + "," + (linePt2.y);
|
||||
var sumLensSqrd = 0,
|
||||
linePath = createPath('M0,0L0,0'),
|
||||
linePt1, ll1,
|
||||
linePt2, ll2,
|
||||
linePathStr;
|
||||
for (var j = 0; j < segCount; j++) {
|
||||
linePt1 = a[(i + j) % segCount]; ll1 = linePt1.length;
|
||||
linePt2 = b[ j % segCount]; ll2 = linePt2.length;
|
||||
linePathStr = "M" + (linePt1[ll1-2]) + "," + (linePt1[ll1-1]) + "L" + (linePt2[ll2-2]) + "," + (linePt2[ll2-1]);
|
||||
linePath.setAttribute('d',linePathStr);
|
||||
sumLensSqrd += Math.pow(linePath.getTotalLength(),2);
|
||||
linePaths[j] = linePath;
|
||||
|
@ -2089,9 +2292,8 @@
|
|||
lineLengths[i] = sumLensSqrd;
|
||||
sumLensSqrd = 0;
|
||||
});
|
||||
var computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths)),
|
||||
newPath = rotations[computedIndex];
|
||||
return newPath
|
||||
var computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths));
|
||||
return rotations[computedIndex]
|
||||
}
|
||||
function getCubicMorph(tweenProp){
|
||||
return this.element.getAttribute('d');
|
||||
|
@ -2121,9 +2323,9 @@
|
|||
if ( !pathCurve1 || !pathCurve2 || ( pathCurve1 && pathCurve2 && pathCurve1[0][0] === 'M' && pathCurve1.length !== pathCurve2.length) ) {
|
||||
var path1 = this.valuesStart[tweenProp].original,
|
||||
path2 = this.valuesEnd[tweenProp].original,
|
||||
curves = path2curve(path1,path2);
|
||||
var curve0 = this._reverseFirstPath ? reverseCurve.call(this,curves[0]) : curves[0],
|
||||
curve1 = this._reverseSecondPath ? reverseCurve.call(this,curves[1]) : curves[1];
|
||||
curves = pathToCurve(path1,path2);
|
||||
var curve0 = this._reverseFirstPath ? reverseCurve(curves[0]) : curves[0],
|
||||
curve1 = this._reverseSecondPath ? reverseCurve(curves[1]) : curves[1];
|
||||
curve0 = getRotatedCurve.call(this,curve0,curve1);
|
||||
this.valuesStart[tweenProp].curve = curve0;
|
||||
this.valuesEnd[tweenProp].curve = curve1;
|
||||
|
@ -2140,13 +2342,12 @@
|
|||
component: 'svgCubicMorph',
|
||||
property: 'path',
|
||||
defaultValue: [],
|
||||
Interpolate: {numbers: numbers,toPathString: toPathString},
|
||||
Interpolate: {numbers: numbers,pathToString: pathToString},
|
||||
functions: svgCubicMorphFunctions,
|
||||
Util: {
|
||||
l2c: l2c, q2c: q2c, a2c: a2c, catmullRom2bezier: catmullRom2bezier, ellipsePath: ellipsePath,
|
||||
path2curve: path2curve, pathToAbsolute: pathToAbsolute, toPathString: toPathString, parsePathString: parsePathString,
|
||||
pathToCurve: pathToCurve, pathToAbsolute: pathToAbsolute, pathToString: pathToString, parsePathString: parsePathString,
|
||||
getRotatedCurve: getRotatedCurve, getRotations: getRotations,
|
||||
getRotationSegments: getRotationSegments, reverseCurve: reverseCurve, getSegments: getSegments, createPath: createPath
|
||||
getRotationSegments: getRotationSegments, reverseCurve: reverseCurve, createPath: createPath
|
||||
}
|
||||
};
|
||||
Components.SVGCubicMorph = svgCubicMorph;
|
||||
|
|
2
demo/src/kute-extra.min.js
vendored
2
demo/src/kute-extra.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/src/kute.min.js
vendored
2
demo/src/kute.min.js
vendored
File diff suppressed because one or more lines are too long
533
dist/kute.esm.js
vendored
533
dist/kute.esm.js
vendored
|
@ -15,7 +15,7 @@ var globalObject = typeof (global) !== 'undefined' ? global
|
|||
|
||||
var Interpolate = {};
|
||||
|
||||
var onStart$1 = {};
|
||||
var onStart = {};
|
||||
|
||||
var Time = {};
|
||||
Time.now = self.performance.now.bind(self.performance);
|
||||
|
@ -36,11 +36,11 @@ function stop() {
|
|||
if (!Tweens.length && Tick) {
|
||||
cancelAnimationFrame(Tick);
|
||||
Tick = null;
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
KUTE[obj] && (delete KUTE[obj]);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
for (var prop in onStart[obj]) {
|
||||
KUTE[prop] && (delete KUTE[prop]);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ var Objects = {
|
|||
prepareProperty: prepareProperty,
|
||||
prepareStart: prepareStart,
|
||||
crossCheck: crossCheck,
|
||||
onStart: onStart$1,
|
||||
onStart: onStart,
|
||||
onComplete: onComplete,
|
||||
linkProperty: linkProperty
|
||||
};
|
||||
|
@ -106,7 +106,7 @@ function getAll () { return Tweens; }
|
|||
|
||||
function removeAll () { Tweens.length = 0; }
|
||||
|
||||
function linkInterpolation$1() {
|
||||
function linkInterpolation() {
|
||||
var this$1 = this;
|
||||
var loop = function ( component ) {
|
||||
var componentLink = linkProperty[component];
|
||||
|
@ -143,7 +143,7 @@ var Internals = {
|
|||
getAll: getAll,
|
||||
removeAll: removeAll,
|
||||
stop: stop,
|
||||
linkInterpolation: linkInterpolation$1
|
||||
linkInterpolation: linkInterpolation
|
||||
};
|
||||
|
||||
function getInlineStyle(el) {
|
||||
|
@ -346,6 +346,19 @@ function selector(el, multi) {
|
|||
}
|
||||
}
|
||||
|
||||
function queueStart(){
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
}
|
||||
|
||||
var TweenBase = function TweenBase(targetElement, startObject, endObject, options){
|
||||
this.element = targetElement;
|
||||
this.playing = false;
|
||||
|
@ -363,8 +376,8 @@ var TweenBase = function TweenBase(targetElement, startObject, endObject, option
|
|||
if( !(internalOption in this ) ) { this[internalOption] = options[op]; }
|
||||
}
|
||||
var easingFnName = this._easing.name;
|
||||
if (!onStart$1[easingFnName]) {
|
||||
onStart$1[easingFnName] = function(prop){
|
||||
if (!onStart[easingFnName]) {
|
||||
onStart[easingFnName] = function(prop){
|
||||
!KUTE[prop] && prop === this._easing.name && (KUTE[prop] = this._easing);
|
||||
};
|
||||
}
|
||||
|
@ -379,16 +392,7 @@ TweenBase.prototype.start = function start (time) {
|
|||
if (this._onStart) {
|
||||
this._onStart.call(this);
|
||||
}
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
onStart$1[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
onStart$1[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation$1.call(this);
|
||||
queueStart.call(this);
|
||||
this._startFired = true;
|
||||
}
|
||||
!Tick && Ticker();
|
||||
|
@ -534,16 +538,7 @@ var Tween = (function (TweenBase) {
|
|||
if (this._onResume !== undefined) {
|
||||
this._onResume.call(this);
|
||||
}
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
queueStart.call(this);
|
||||
this._startTime += KUTE.Time() - this._pauseTime;
|
||||
add(this);
|
||||
!Tick && Ticker();
|
||||
|
@ -708,7 +703,7 @@ var Animation = function Animation(Component){
|
|||
Animation.prototype.setComponent = function setComponent (Component){
|
||||
var propertyInfo = this;
|
||||
var ComponentName = Component.component;
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart$1, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Category = Component.category;
|
||||
var Property = Component.property;
|
||||
var Length = Component.properties && Component.properties.length || Component.subProperties && Component.subProperties.length;
|
||||
|
@ -936,7 +931,7 @@ function prepareAttr(tweenProp,attrObj){
|
|||
if ( currentValue !== null && regex.test(currentValue) ) {
|
||||
var unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u;
|
||||
var suffix = /%/.test(unit) ? '_percent' : ("_" + unit);
|
||||
onStart$1[ComponentName][prop+suffix] = function(tp) {
|
||||
onStart[ComponentName][prop+suffix] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, p, a, b, v) {
|
||||
var _p = p.replace(suffix,'');
|
||||
|
@ -946,7 +941,7 @@ function prepareAttr(tweenProp,attrObj){
|
|||
};
|
||||
attributesObject[prop+suffix] = trueDimension(attrObj[p]);
|
||||
} else if ( !regex.test(attrObj[p]) || currentValue === null || currentValue !== null && !regex.test(currentValue) ) {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, (numbers(a,b,v) * 1000 >> 0) / 1000 );
|
||||
|
@ -956,7 +951,7 @@ function prepareAttr(tweenProp,attrObj){
|
|||
attributesObject[prop] = parseFloat(attrObj[p]);
|
||||
}
|
||||
} else {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, colors(a,b,v));
|
||||
|
@ -1462,30 +1457,45 @@ function onStartSVGMorph(tweenProp){
|
|||
}
|
||||
}
|
||||
|
||||
var INVALID_INPUT = 'Invalid path value';
|
||||
function isFiniteNumber(number) {
|
||||
return typeof number === "number" && isFinite(number);
|
||||
function clonePath(pathArray){
|
||||
return pathArray.map(function (x) { return Array.isArray(x) ? clonePath(x) : !isNaN(+x) ? +x : x; } )
|
||||
}
|
||||
function distance(a, b) {
|
||||
return Math.sqrt(
|
||||
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
|
||||
);
|
||||
|
||||
var SVGPCOps = {
|
||||
decimals:3,
|
||||
round:1
|
||||
};
|
||||
|
||||
function roundPath(pathArray) {
|
||||
return pathArray.map( function (seg) { return seg.map(function (c,i) {
|
||||
var nr = +c, dc = Math.pow(10,SVGPCOps.decimals);
|
||||
return i ? (nr % 1 === 0 ? nr : (nr*dc>>0)/dc) : c
|
||||
}
|
||||
); })
|
||||
}
|
||||
function pointAlong(a, b, pct) {
|
||||
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
|
||||
}
|
||||
function samePoint(a, b) {
|
||||
return distance(a, b) < 1e-9;
|
||||
|
||||
function SVGPathArray(pathString){
|
||||
this.segments = [];
|
||||
this.isClosed = 0;
|
||||
this.isAbsolute = 0;
|
||||
this.pathValue = pathString;
|
||||
this.max = pathString.length;
|
||||
this.index = 0;
|
||||
this.param = 0.0;
|
||||
this.segmentStart = 0;
|
||||
this.data = [];
|
||||
this.err = '';
|
||||
return this
|
||||
}
|
||||
|
||||
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) {
|
||||
var specialSpaces = [
|
||||
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
|
||||
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF ];
|
||||
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) ||
|
||||
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
|
||||
(ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
|
||||
(ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0);
|
||||
}
|
||||
function isCommand(code) {
|
||||
switch (code | 0x20) {
|
||||
|
@ -1516,23 +1526,13 @@ function isDigitStart(code) {
|
|||
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))) {
|
||||
while (state.index < state.max && isSpace(state.pathValue.charCodeAt(state.index))) {
|
||||
state.index++;
|
||||
}
|
||||
}
|
||||
function scanFlag(state) {
|
||||
var ch = state.path.charCodeAt(state.index);
|
||||
var ch = state.pathValue.charCodeAt(state.index);
|
||||
if (ch === 0x30) {
|
||||
state.param = 0;
|
||||
state.index++;
|
||||
|
@ -1543,7 +1543,7 @@ function scanFlag(state) {
|
|||
state.index++;
|
||||
return;
|
||||
}
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: arc flag can be 0 or 1 only (at pos ' + state.index + ')';
|
||||
}
|
||||
function scanParam(state) {
|
||||
var start = state.index,
|
||||
|
@ -1555,81 +1555,78 @@ function scanParam(state) {
|
|||
hasDot = false,
|
||||
ch;
|
||||
if (index >= max) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: missed param (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
ch = state.path.charCodeAt(index);
|
||||
ch = state.pathValue.charCodeAt(index);
|
||||
if (ch === 0x2B || ch === 0x2D) {
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (!isDigit(ch) && ch !== 0x2E) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
if (ch !== 0x2E) {
|
||||
zeroFirst = (ch === 0x30);
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
if (zeroFirst && index < max) {
|
||||
if (ch && isDigit(ch)) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: numbers started with `0` such as `09` are illegal (at pos ' + start + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (index < max && isDigit(state.path.charCodeAt(index))) {
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasCeiling = true;
|
||||
}
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x2E) {
|
||||
hasDot = true;
|
||||
index++;
|
||||
while (isDigit(state.path.charCodeAt(index))) {
|
||||
while (isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasDecimal = true;
|
||||
}
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x65 || ch === 0x45) {
|
||||
if (hasDot && !hasCeiling && !hasDecimal) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.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))) {
|
||||
if (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
state.index = index;
|
||||
state.param = parseFloat(state.path.slice(start, index)) + 0.0;
|
||||
state.param = parseFloat(state.pathValue.slice(start, index)) + 0.0;
|
||||
}
|
||||
function finalizeSegment(state) {
|
||||
var cmd, cmdLC;
|
||||
cmd = state.path[state.segmentStart];
|
||||
cmdLC = cmd.toLowerCase();
|
||||
var params = state.data;
|
||||
var cmd = state.pathValue[state.segmentStart], cmdLC = cmd.toLowerCase(), params = state.data;
|
||||
if (cmdLC === 'm' && params.length > 2) {
|
||||
state.result.push([ cmd, params[0], params[1] ]);
|
||||
state.segments.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));
|
||||
state.segments.push([ cmd ].concat(params));
|
||||
} else {
|
||||
while (params.length >= paramCounts[cmdLC]) {
|
||||
state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
||||
state.segments.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
||||
if (!paramCounts[cmdLC]) {
|
||||
break;
|
||||
}
|
||||
|
@ -1639,17 +1636,18 @@ function finalizeSegment(state) {
|
|||
function scanSegment(state) {
|
||||
var max = state.max, cmdCode, is_arc, comma_found, need_params, i;
|
||||
state.segmentStart = state.index;
|
||||
cmdCode = state.path.charCodeAt(state.index);
|
||||
cmdCode = state.pathValue.charCodeAt(state.index);
|
||||
is_arc = isArc(cmdCode);
|
||||
if (!isCommand(cmdCode)) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: bad command ' + state.pathValue[state.index] + ' (at pos ' + state.index + ')';
|
||||
return;
|
||||
}
|
||||
need_params = paramCounts[state.path[state.index].toLowerCase()];
|
||||
need_params = paramCounts[state.pathValue[state.index].toLowerCase()];
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
state.data = [];
|
||||
if (!need_params) {
|
||||
state.isClosed = 1;
|
||||
finalizeSegment(state);
|
||||
return;
|
||||
}
|
||||
|
@ -1664,7 +1662,7 @@ function scanSegment(state) {
|
|||
state.data.push(state.param);
|
||||
skipSpaces(state);
|
||||
comma_found = false;
|
||||
if (state.index < max && state.path.charCodeAt(state.index) === 0x2C) {
|
||||
if (state.index < max && state.pathValue.charCodeAt(state.index) === 0x2C) {
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
comma_found = true;
|
||||
|
@ -1676,148 +1674,250 @@ function scanSegment(state) {
|
|||
if (state.index >= state.max) {
|
||||
break;
|
||||
}
|
||||
if (!isDigitStart(state.path.charCodeAt(state.index))) {
|
||||
if (!isDigitStart(state.pathValue.charCodeAt(state.index))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
finalizeSegment(state);
|
||||
}
|
||||
function pathParse(svgPath) {
|
||||
var state = new State(svgPath), max = state.max;
|
||||
function parsePathString(pathString) {
|
||||
if ( Array.isArray(pathString) ) {
|
||||
return clonePath(pathString)
|
||||
}
|
||||
var state = new SVGPathArray(pathString), 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 = "KUTE.js - " + INVALID_INPUT;
|
||||
state.result = [];
|
||||
state.segments = [];
|
||||
} else if (state.segments.length) {
|
||||
if ('mM'.indexOf(state.segments[0][0]) < 0) {
|
||||
state.err = 'SvgPath: string should start with `M` or `m`';
|
||||
state.segments = [];
|
||||
} else {
|
||||
state.result[0][0] = 'M';
|
||||
state.segments[0][0] = 'M';
|
||||
}
|
||||
}
|
||||
return {
|
||||
err: state.err,
|
||||
segments: state.result
|
||||
};
|
||||
return roundPath(state.segments)
|
||||
}
|
||||
var SvgPath = function SvgPath(path){
|
||||
if (!(this instanceof SvgPath)) { return new SvgPath(path); }
|
||||
var pstate = pathParse(path);
|
||||
this.segments = pstate.segments;
|
||||
this.err = pstate.err;
|
||||
};
|
||||
SvgPath.prototype.iterate = function iterate (iterator) {
|
||||
var segments = this.segments,
|
||||
replacements = {},
|
||||
needReplace = false,
|
||||
lastX = 0,
|
||||
lastY = 0,
|
||||
countourStartX = 0,
|
||||
countourStartY = 0,
|
||||
newSegments;
|
||||
segments.map( 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());
|
||||
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':
|
||||
lastX = countourStartX;
|
||||
lastY = countourStartY;
|
||||
return;
|
||||
default:
|
||||
lastX = s[s.length - 2] + (isRelative ? lastX : 0);
|
||||
lastY = s[s.length - 1] + (isRelative ? lastY : 0);
|
||||
}
|
||||
});
|
||||
if (!needReplace) { return this; }
|
||||
newSegments = [];
|
||||
segments.map(function (s,i){
|
||||
if (typeof replacements[i] !== 'undefined') {
|
||||
replacements[i].map(function (r){
|
||||
newSegments.push(r);
|
||||
});
|
||||
|
||||
function catmullRom2bezier(crp, z) {
|
||||
var d = [];
|
||||
for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
|
||||
var p = [
|
||||
{x: +crp[i - 2], y: +crp[i - 1]},
|
||||
{x: +crp[i], y: +crp[i + 1]},
|
||||
{x: +crp[i + 2], y: +crp[i + 3]},
|
||||
{x: +crp[i + 4], y: +crp[i + 5]}
|
||||
];
|
||||
if (z) {
|
||||
if (!i) {
|
||||
p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
|
||||
} else if (iLen - 4 == i) {
|
||||
p[3] = {x: +crp[0], y: +crp[1]};
|
||||
} else if (iLen - 2 == i) {
|
||||
p[2] = {x: +crp[0], y: +crp[1]};
|
||||
p[3] = {x: +crp[2], y: +crp[3]};
|
||||
}
|
||||
} else {
|
||||
newSegments.push(s);
|
||||
if (iLen - 4 == i) {
|
||||
p[3] = p[2];
|
||||
} else if (!i) {
|
||||
p[0] = {x: +crp[i], y: +crp[i + 1]};
|
||||
}
|
||||
}
|
||||
});
|
||||
this.segments = newSegments;
|
||||
return this;
|
||||
};
|
||||
SvgPath.prototype.abs = function abs () {
|
||||
this.iterate(function (s, index, x, y) {
|
||||
var name = s[0],
|
||||
nameUC = name.toUpperCase(),
|
||||
i;
|
||||
if (name === nameUC) { return; }
|
||||
s[0] = nameUC;
|
||||
switch (name) {
|
||||
case 'v':
|
||||
s[1] += y;
|
||||
return;
|
||||
case 'a':
|
||||
s[6] += x;
|
||||
s[7] += y;
|
||||
return;
|
||||
default:
|
||||
for (i = 1; i < s.length; i++) {
|
||||
s[i] += i % 2 ? x : y;
|
||||
}
|
||||
d.push([
|
||||
"C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
]);
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
function ellipsePath(x, y, rx, ry, a) {
|
||||
if (a == null && ry == null) {
|
||||
ry = rx;
|
||||
}
|
||||
x = +x;
|
||||
y = +y;
|
||||
rx = +rx;
|
||||
ry = +ry;
|
||||
var res;
|
||||
if (a != null) {
|
||||
var rad = Math.PI / 180,
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad);
|
||||
res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
|
||||
} else {
|
||||
res = [
|
||||
["M", x, y],
|
||||
["m", 0, -ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, 2 * ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, -2 * ry],
|
||||
["z"]
|
||||
];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function pathToAbsolute(pathArray) {
|
||||
pathArray = parsePathString(pathArray);
|
||||
if (!pathArray || !pathArray.length) {
|
||||
return [["M", 0, 0]];
|
||||
}
|
||||
var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0,
|
||||
ii = pathArray.length,
|
||||
crz = pathArray.length === 3 &&
|
||||
pathArray[0][0] === "M" &&
|
||||
pathArray[1][0].toUpperCase() === "R" &&
|
||||
pathArray[2][0].toUpperCase() === "Z";
|
||||
if (pathArray[0][0] === "M") {
|
||||
x = +pathArray[0][1];
|
||||
y = +pathArray[0][2];
|
||||
mx = x;
|
||||
my = y;
|
||||
start++;
|
||||
res[0] = ["M", x, y];
|
||||
}
|
||||
var loop = function ( i ) {
|
||||
var r = (void 0), pa = pathArray[i], pa0 = pa[0];
|
||||
res.push(r = []);
|
||||
if (pa0 !== pa0.toUpperCase()) {
|
||||
r[0] = pa0.toUpperCase();
|
||||
switch (r[0]) {
|
||||
case "A":
|
||||
r[1] = pa[1];
|
||||
r[2] = pa[2];
|
||||
r[3] = pa[3];
|
||||
r[4] = pa[4];
|
||||
r[5] = pa[5];
|
||||
r[6] = +pa[6] + x;
|
||||
r[7] = +pa[7] + y;
|
||||
break;
|
||||
case "V":
|
||||
r[1] = +pa[1] + y;
|
||||
break;
|
||||
case "H":
|
||||
r[1] = +pa[1] + x;
|
||||
break;
|
||||
case "R":
|
||||
var dots$1 = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots$1.length; j < jj; j++) {
|
||||
dots$1[j] = +dots$1[j] + x;
|
||||
dots$1[++j] = +dots$1[j] + y;
|
||||
}
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots$1, crz));
|
||||
break;
|
||||
case "O":
|
||||
res.pop();
|
||||
dots$1 = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots$1.push(dots$1[0]);
|
||||
res = res.concat(dots$1);
|
||||
break;
|
||||
case "U":
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
break;
|
||||
case "M":
|
||||
mx = +pa[1] + x;
|
||||
my = +pa[2] + y;
|
||||
default:
|
||||
for (var j$1 = 1, jj$1 = pa.length; j$1 < jj$1; j$1++) {
|
||||
r[j$1] = +pa[j$1] + ((j$1 % 2) ? x : y);
|
||||
}
|
||||
}
|
||||
} else if (pa0 === "R") {
|
||||
dots = [x, y].concat(pa.slice(1));
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
r = ["R"].concat(pa.slice(-2));
|
||||
} else if (pa0 === "O") {
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
} else if (pa0 === "U") {
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, +pa[1], +pa[2], +pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
} else {
|
||||
pa.map(function (k){ return r.push(k); });
|
||||
}
|
||||
}, true);
|
||||
return this;
|
||||
};
|
||||
SvgPath.prototype.toString = function toString () {
|
||||
var this$1 = this;
|
||||
var elements = [], skipCmd, cmd;
|
||||
this.segments.map( function (s,i) {
|
||||
cmd = s[0];
|
||||
skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this$1.segments[i - 1][0];
|
||||
elements = elements.concat(skipCmd ? s.slice(1) : s);
|
||||
});
|
||||
return elements.join(' ')
|
||||
.replace(/ ?([achlmqrstvz]) ?/gi, '$1')
|
||||
.replace(/ \-/g, '-')
|
||||
.replace(/zm/g, 'z m');
|
||||
};
|
||||
function split(parsed) {
|
||||
return parsed
|
||||
.toString()
|
||||
.split("M")
|
||||
.map(function (d, i) {
|
||||
d = d.trim();
|
||||
return i && d ? "M" + d : d;
|
||||
})
|
||||
.filter(function (d) { return d; });
|
||||
pa0 = pa0.toUpperCase();
|
||||
if (pa0 !== "O") {
|
||||
switch (r[0]) {
|
||||
case "Z":
|
||||
x = mx;
|
||||
y = my;
|
||||
break;
|
||||
case "H":
|
||||
x = +r[1];
|
||||
break;
|
||||
case "V":
|
||||
y = +r[1];
|
||||
break;
|
||||
case "M":
|
||||
mx = +r[r.length - 2];
|
||||
my = +r[r.length - 1];
|
||||
default:
|
||||
x = +r[r.length - 2];
|
||||
y = +r[r.length - 1];
|
||||
}
|
||||
}
|
||||
};
|
||||
for (var i = start; i < ii; i++) loop( i );
|
||||
return roundPath(res)
|
||||
}
|
||||
|
||||
function pathToString(pathArray) {
|
||||
return pathArray.map( function (c) {
|
||||
if (typeof c === 'string') {
|
||||
return c
|
||||
} else {
|
||||
return c.shift() + c.join(',')
|
||||
}
|
||||
}).join(' ')
|
||||
}
|
||||
|
||||
function splitPath(pathString) {
|
||||
return pathString
|
||||
.replace( /(m|M)/g, "|$1")
|
||||
.split('|')
|
||||
.map(function (s){ return s.trim(); })
|
||||
.filter(function (s){ return s; })
|
||||
}
|
||||
|
||||
var INVALID_INPUT = 'Invalid path value';
|
||||
function isFiniteNumber(number) {
|
||||
return typeof number === "number" && isFinite(number);
|
||||
}
|
||||
function distance(a, b) {
|
||||
return Math.sqrt(
|
||||
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
|
||||
);
|
||||
}
|
||||
function pointAlong(a, b, pct) {
|
||||
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
|
||||
}
|
||||
function samePoint(a, b) {
|
||||
return distance(a, b) < 1e-9;
|
||||
}
|
||||
function pathStringToRing(str, maxSegmentLength) {
|
||||
var parsed = new SvgPath(str).abs();
|
||||
var parsed = pathToAbsolute(str);
|
||||
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
|
||||
}
|
||||
function exactRing(parsed) {
|
||||
var segments = parsed.segments || [],
|
||||
ring = [];
|
||||
function exactRing(segments) {
|
||||
var ring = [];
|
||||
if (!segments.length || segments[0][0] !== "M") {
|
||||
return false;
|
||||
}
|
||||
|
@ -1841,7 +1941,8 @@ function exactRing(parsed) {
|
|||
return ring.length ? { ring: ring } : false;
|
||||
}
|
||||
function approximateRing(parsed, maxSegmentLength) {
|
||||
var ringPath = split(parsed)[0], ring = [], len, testPath, numPoints = 3;
|
||||
var ringPath = splitPath(pathToString(parsed))[0],
|
||||
ring = [], len, testPath, numPoints = 3;
|
||||
if (!ringPath) {
|
||||
throw new TypeError(INVALID_INPUT);
|
||||
}
|
||||
|
@ -2032,9 +2133,11 @@ var svgMorph = {
|
|||
defaultOptions: {morphPrecision : 10, morphIndex:0},
|
||||
functions: svgMorphFunctions,
|
||||
Util: {
|
||||
INVALID_INPUT: INVALID_INPUT,isFiniteNumber: isFiniteNumber,distance: distance,pointAlong: pointAlong,samePoint: samePoint,paramCounts: paramCounts,SPECIAL_SPACES: SPECIAL_SPACES,isSpace: isSpace,isCommand: isCommand,isArc: isArc,isDigit: isDigit,
|
||||
isDigitStart: isDigitStart,State: State,skipSpaces: skipSpaces,scanFlag: scanFlag,scanParam: scanParam,finalizeSegment: finalizeSegment,scanSegment: scanSegment,pathParse: pathParse,SvgPath: SvgPath,split: split,pathStringToRing: pathStringToRing,
|
||||
exactRing: exactRing,approximateRing: approximateRing,measure: measure,rotateRing: rotateRing,polygonLength: polygonLength,polygonArea: polygonArea,addPoints: addPoints,bisect: bisect,normalizeRing: normalizeRing,validRing: validRing,getInterpolationPoints: getInterpolationPoints}
|
||||
INVALID_INPUT: INVALID_INPUT,isFiniteNumber: isFiniteNumber,distance: distance,pointAlong: pointAlong,samePoint: samePoint,
|
||||
pathToAbsolute: pathToAbsolute,pathToString: pathToString,pathStringToRing: pathStringToRing,
|
||||
exactRing: exactRing,approximateRing: approximateRing,measure: measure,rotateRing: rotateRing,polygonLength: polygonLength,polygonArea: polygonArea,
|
||||
addPoints: addPoints,bisect: bisect,normalizeRing: normalizeRing,validRing: validRing,getInterpolationPoints: getInterpolationPoints
|
||||
}
|
||||
};
|
||||
Components.SVGMorph = svgMorph;
|
||||
|
||||
|
|
2
dist/kute.esm.min.js
vendored
2
dist/kute.esm.min.js
vendored
File diff suppressed because one or more lines are too long
533
dist/kute.js
vendored
533
dist/kute.js
vendored
|
@ -21,7 +21,7 @@
|
|||
|
||||
var Interpolate = {};
|
||||
|
||||
var onStart$1 = {};
|
||||
var onStart = {};
|
||||
|
||||
var Time = {};
|
||||
Time.now = self.performance.now.bind(self.performance);
|
||||
|
@ -42,11 +42,11 @@
|
|||
if (!Tweens.length && Tick) {
|
||||
cancelAnimationFrame(Tick);
|
||||
Tick = null;
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
KUTE[obj] && (delete KUTE[obj]);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
for (var prop in onStart[obj]) {
|
||||
KUTE[prop] && (delete KUTE[prop]);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@
|
|||
prepareProperty: prepareProperty,
|
||||
prepareStart: prepareStart,
|
||||
crossCheck: crossCheck,
|
||||
onStart: onStart$1,
|
||||
onStart: onStart,
|
||||
onComplete: onComplete,
|
||||
linkProperty: linkProperty
|
||||
};
|
||||
|
@ -112,7 +112,7 @@
|
|||
|
||||
function removeAll () { Tweens.length = 0; }
|
||||
|
||||
function linkInterpolation$1() {
|
||||
function linkInterpolation() {
|
||||
var this$1 = this;
|
||||
var loop = function ( component ) {
|
||||
var componentLink = linkProperty[component];
|
||||
|
@ -149,7 +149,7 @@
|
|||
getAll: getAll,
|
||||
removeAll: removeAll,
|
||||
stop: stop,
|
||||
linkInterpolation: linkInterpolation$1
|
||||
linkInterpolation: linkInterpolation
|
||||
};
|
||||
|
||||
function getInlineStyle(el) {
|
||||
|
@ -352,6 +352,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
function queueStart(){
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
}
|
||||
|
||||
var TweenBase = function TweenBase(targetElement, startObject, endObject, options){
|
||||
this.element = targetElement;
|
||||
this.playing = false;
|
||||
|
@ -369,8 +382,8 @@
|
|||
if( !(internalOption in this ) ) { this[internalOption] = options[op]; }
|
||||
}
|
||||
var easingFnName = this._easing.name;
|
||||
if (!onStart$1[easingFnName]) {
|
||||
onStart$1[easingFnName] = function(prop){
|
||||
if (!onStart[easingFnName]) {
|
||||
onStart[easingFnName] = function(prop){
|
||||
!KUTE[prop] && prop === this._easing.name && (KUTE[prop] = this._easing);
|
||||
};
|
||||
}
|
||||
|
@ -385,16 +398,7 @@
|
|||
if (this._onStart) {
|
||||
this._onStart.call(this);
|
||||
}
|
||||
for (var obj in onStart$1) {
|
||||
if (typeof (onStart$1[obj]) === 'function') {
|
||||
onStart$1[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart$1[obj]) {
|
||||
onStart$1[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation$1.call(this);
|
||||
queueStart.call(this);
|
||||
this._startFired = true;
|
||||
}
|
||||
!Tick && Ticker();
|
||||
|
@ -540,16 +544,7 @@
|
|||
if (this._onResume !== undefined) {
|
||||
this._onResume.call(this);
|
||||
}
|
||||
for (var obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (var prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
queueStart.call(this);
|
||||
this._startTime += KUTE.Time() - this._pauseTime;
|
||||
add(this);
|
||||
!Tick && Ticker();
|
||||
|
@ -714,7 +709,7 @@
|
|||
Animation.prototype.setComponent = function setComponent (Component){
|
||||
var propertyInfo = this;
|
||||
var ComponentName = Component.component;
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart$1, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Functions = { prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart, onComplete: onComplete, crossCheck: crossCheck };
|
||||
var Category = Component.category;
|
||||
var Property = Component.property;
|
||||
var Length = Component.properties && Component.properties.length || Component.subProperties && Component.subProperties.length;
|
||||
|
@ -942,7 +937,7 @@
|
|||
if ( currentValue !== null && regex.test(currentValue) ) {
|
||||
var unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u;
|
||||
var suffix = /%/.test(unit) ? '_percent' : ("_" + unit);
|
||||
onStart$1[ComponentName][prop+suffix] = function(tp) {
|
||||
onStart[ComponentName][prop+suffix] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, p, a, b, v) {
|
||||
var _p = p.replace(suffix,'');
|
||||
|
@ -952,7 +947,7 @@
|
|||
};
|
||||
attributesObject[prop+suffix] = trueDimension(attrObj[p]);
|
||||
} else if ( !regex.test(attrObj[p]) || currentValue === null || currentValue !== null && !regex.test(currentValue) ) {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, (numbers(a,b,v) * 1000 >> 0) / 1000 );
|
||||
|
@ -962,7 +957,7 @@
|
|||
attributesObject[prop] = parseFloat(attrObj[p]);
|
||||
}
|
||||
} else {
|
||||
onStart$1[ComponentName][prop] = function(tp) {
|
||||
onStart[ComponentName][prop] = function(tp) {
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = function (elem, oneAttr, a, b, v) {
|
||||
elem.setAttribute(oneAttr, colors(a,b,v));
|
||||
|
@ -1468,30 +1463,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
var INVALID_INPUT = 'Invalid path value';
|
||||
function isFiniteNumber(number) {
|
||||
return typeof number === "number" && isFinite(number);
|
||||
function clonePath(pathArray){
|
||||
return pathArray.map(function (x) { return Array.isArray(x) ? clonePath(x) : !isNaN(+x) ? +x : x; } )
|
||||
}
|
||||
function distance(a, b) {
|
||||
return Math.sqrt(
|
||||
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
|
||||
);
|
||||
|
||||
var SVGPCOps = {
|
||||
decimals:3,
|
||||
round:1
|
||||
};
|
||||
|
||||
function roundPath(pathArray) {
|
||||
return pathArray.map( function (seg) { return seg.map(function (c,i) {
|
||||
var nr = +c, dc = Math.pow(10,SVGPCOps.decimals);
|
||||
return i ? (nr % 1 === 0 ? nr : (nr*dc>>0)/dc) : c
|
||||
}
|
||||
); })
|
||||
}
|
||||
function pointAlong(a, b, pct) {
|
||||
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
|
||||
}
|
||||
function samePoint(a, b) {
|
||||
return distance(a, b) < 1e-9;
|
||||
|
||||
function SVGPathArray(pathString){
|
||||
this.segments = [];
|
||||
this.isClosed = 0;
|
||||
this.isAbsolute = 0;
|
||||
this.pathValue = pathString;
|
||||
this.max = pathString.length;
|
||||
this.index = 0;
|
||||
this.param = 0.0;
|
||||
this.segmentStart = 0;
|
||||
this.data = [];
|
||||
this.err = '';
|
||||
return this
|
||||
}
|
||||
|
||||
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) {
|
||||
var specialSpaces = [
|
||||
0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
|
||||
0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF ];
|
||||
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) ||
|
||||
(ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
|
||||
(ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0);
|
||||
(ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0);
|
||||
}
|
||||
function isCommand(code) {
|
||||
switch (code | 0x20) {
|
||||
|
@ -1522,23 +1532,13 @@
|
|||
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))) {
|
||||
while (state.index < state.max && isSpace(state.pathValue.charCodeAt(state.index))) {
|
||||
state.index++;
|
||||
}
|
||||
}
|
||||
function scanFlag(state) {
|
||||
var ch = state.path.charCodeAt(state.index);
|
||||
var ch = state.pathValue.charCodeAt(state.index);
|
||||
if (ch === 0x30) {
|
||||
state.param = 0;
|
||||
state.index++;
|
||||
|
@ -1549,7 +1549,7 @@
|
|||
state.index++;
|
||||
return;
|
||||
}
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: arc flag can be 0 or 1 only (at pos ' + state.index + ')';
|
||||
}
|
||||
function scanParam(state) {
|
||||
var start = state.index,
|
||||
|
@ -1561,81 +1561,78 @@
|
|||
hasDot = false,
|
||||
ch;
|
||||
if (index >= max) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: missed param (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
ch = state.path.charCodeAt(index);
|
||||
ch = state.pathValue.charCodeAt(index);
|
||||
if (ch === 0x2B || ch === 0x2D) {
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (!isDigit(ch) && ch !== 0x2E) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
if (ch !== 0x2E) {
|
||||
zeroFirst = (ch === 0x30);
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
if (zeroFirst && index < max) {
|
||||
if (ch && isDigit(ch)) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: numbers started with `0` such as `09` are illegal (at pos ' + start + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (index < max && isDigit(state.path.charCodeAt(index))) {
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasCeiling = true;
|
||||
}
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x2E) {
|
||||
hasDot = true;
|
||||
index++;
|
||||
while (isDigit(state.path.charCodeAt(index))) {
|
||||
while (isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
hasDecimal = true;
|
||||
}
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.charCodeAt(index) : 0;
|
||||
}
|
||||
if (ch === 0x65 || ch === 0x45) {
|
||||
if (hasDot && !hasCeiling && !hasDecimal) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
ch = (index < max) ? state.path.charCodeAt(index) : 0;
|
||||
ch = (index < max) ? state.pathValue.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))) {
|
||||
if (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
while (index < max && isDigit(state.pathValue.charCodeAt(index))) {
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
|
||||
return;
|
||||
}
|
||||
}
|
||||
state.index = index;
|
||||
state.param = parseFloat(state.path.slice(start, index)) + 0.0;
|
||||
state.param = parseFloat(state.pathValue.slice(start, index)) + 0.0;
|
||||
}
|
||||
function finalizeSegment(state) {
|
||||
var cmd, cmdLC;
|
||||
cmd = state.path[state.segmentStart];
|
||||
cmdLC = cmd.toLowerCase();
|
||||
var params = state.data;
|
||||
var cmd = state.pathValue[state.segmentStart], cmdLC = cmd.toLowerCase(), params = state.data;
|
||||
if (cmdLC === 'm' && params.length > 2) {
|
||||
state.result.push([ cmd, params[0], params[1] ]);
|
||||
state.segments.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));
|
||||
state.segments.push([ cmd ].concat(params));
|
||||
} else {
|
||||
while (params.length >= paramCounts[cmdLC]) {
|
||||
state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
||||
state.segments.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC])));
|
||||
if (!paramCounts[cmdLC]) {
|
||||
break;
|
||||
}
|
||||
|
@ -1645,17 +1642,18 @@
|
|||
function scanSegment(state) {
|
||||
var max = state.max, cmdCode, is_arc, comma_found, need_params, i;
|
||||
state.segmentStart = state.index;
|
||||
cmdCode = state.path.charCodeAt(state.index);
|
||||
cmdCode = state.pathValue.charCodeAt(state.index);
|
||||
is_arc = isArc(cmdCode);
|
||||
if (!isCommand(cmdCode)) {
|
||||
state.err = "KUTE.js - " + INVALID_INPUT;
|
||||
state.err = 'SvgPath: bad command ' + state.pathValue[state.index] + ' (at pos ' + state.index + ')';
|
||||
return;
|
||||
}
|
||||
need_params = paramCounts[state.path[state.index].toLowerCase()];
|
||||
need_params = paramCounts[state.pathValue[state.index].toLowerCase()];
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
state.data = [];
|
||||
if (!need_params) {
|
||||
state.isClosed = 1;
|
||||
finalizeSegment(state);
|
||||
return;
|
||||
}
|
||||
|
@ -1670,7 +1668,7 @@
|
|||
state.data.push(state.param);
|
||||
skipSpaces(state);
|
||||
comma_found = false;
|
||||
if (state.index < max && state.path.charCodeAt(state.index) === 0x2C) {
|
||||
if (state.index < max && state.pathValue.charCodeAt(state.index) === 0x2C) {
|
||||
state.index++;
|
||||
skipSpaces(state);
|
||||
comma_found = true;
|
||||
|
@ -1682,148 +1680,250 @@
|
|||
if (state.index >= state.max) {
|
||||
break;
|
||||
}
|
||||
if (!isDigitStart(state.path.charCodeAt(state.index))) {
|
||||
if (!isDigitStart(state.pathValue.charCodeAt(state.index))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
finalizeSegment(state);
|
||||
}
|
||||
function pathParse(svgPath) {
|
||||
var state = new State(svgPath), max = state.max;
|
||||
function parsePathString(pathString) {
|
||||
if ( Array.isArray(pathString) ) {
|
||||
return clonePath(pathString)
|
||||
}
|
||||
var state = new SVGPathArray(pathString), 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 = "KUTE.js - " + INVALID_INPUT;
|
||||
state.result = [];
|
||||
state.segments = [];
|
||||
} else if (state.segments.length) {
|
||||
if ('mM'.indexOf(state.segments[0][0]) < 0) {
|
||||
state.err = 'SvgPath: string should start with `M` or `m`';
|
||||
state.segments = [];
|
||||
} else {
|
||||
state.result[0][0] = 'M';
|
||||
state.segments[0][0] = 'M';
|
||||
}
|
||||
}
|
||||
return {
|
||||
err: state.err,
|
||||
segments: state.result
|
||||
};
|
||||
return roundPath(state.segments)
|
||||
}
|
||||
var SvgPath = function SvgPath(path){
|
||||
if (!(this instanceof SvgPath)) { return new SvgPath(path); }
|
||||
var pstate = pathParse(path);
|
||||
this.segments = pstate.segments;
|
||||
this.err = pstate.err;
|
||||
};
|
||||
SvgPath.prototype.iterate = function iterate (iterator) {
|
||||
var segments = this.segments,
|
||||
replacements = {},
|
||||
needReplace = false,
|
||||
lastX = 0,
|
||||
lastY = 0,
|
||||
countourStartX = 0,
|
||||
countourStartY = 0,
|
||||
newSegments;
|
||||
segments.map( 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());
|
||||
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':
|
||||
lastX = countourStartX;
|
||||
lastY = countourStartY;
|
||||
return;
|
||||
default:
|
||||
lastX = s[s.length - 2] + (isRelative ? lastX : 0);
|
||||
lastY = s[s.length - 1] + (isRelative ? lastY : 0);
|
||||
}
|
||||
});
|
||||
if (!needReplace) { return this; }
|
||||
newSegments = [];
|
||||
segments.map(function (s,i){
|
||||
if (typeof replacements[i] !== 'undefined') {
|
||||
replacements[i].map(function (r){
|
||||
newSegments.push(r);
|
||||
});
|
||||
|
||||
function catmullRom2bezier(crp, z) {
|
||||
var d = [];
|
||||
for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
|
||||
var p = [
|
||||
{x: +crp[i - 2], y: +crp[i - 1]},
|
||||
{x: +crp[i], y: +crp[i + 1]},
|
||||
{x: +crp[i + 2], y: +crp[i + 3]},
|
||||
{x: +crp[i + 4], y: +crp[i + 5]}
|
||||
];
|
||||
if (z) {
|
||||
if (!i) {
|
||||
p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
|
||||
} else if (iLen - 4 == i) {
|
||||
p[3] = {x: +crp[0], y: +crp[1]};
|
||||
} else if (iLen - 2 == i) {
|
||||
p[2] = {x: +crp[0], y: +crp[1]};
|
||||
p[3] = {x: +crp[2], y: +crp[3]};
|
||||
}
|
||||
} else {
|
||||
newSegments.push(s);
|
||||
if (iLen - 4 == i) {
|
||||
p[3] = p[2];
|
||||
} else if (!i) {
|
||||
p[0] = {x: +crp[i], y: +crp[i + 1]};
|
||||
}
|
||||
}
|
||||
});
|
||||
this.segments = newSegments;
|
||||
return this;
|
||||
};
|
||||
SvgPath.prototype.abs = function abs () {
|
||||
this.iterate(function (s, index, x, y) {
|
||||
var name = s[0],
|
||||
nameUC = name.toUpperCase(),
|
||||
i;
|
||||
if (name === nameUC) { return; }
|
||||
s[0] = nameUC;
|
||||
switch (name) {
|
||||
case 'v':
|
||||
s[1] += y;
|
||||
return;
|
||||
case 'a':
|
||||
s[6] += x;
|
||||
s[7] += y;
|
||||
return;
|
||||
default:
|
||||
for (i = 1; i < s.length; i++) {
|
||||
s[i] += i % 2 ? x : y;
|
||||
}
|
||||
d.push([
|
||||
"C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
]);
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
function ellipsePath(x, y, rx, ry, a) {
|
||||
if (a == null && ry == null) {
|
||||
ry = rx;
|
||||
}
|
||||
x = +x;
|
||||
y = +y;
|
||||
rx = +rx;
|
||||
ry = +ry;
|
||||
var res;
|
||||
if (a != null) {
|
||||
var rad = Math.PI / 180,
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad);
|
||||
res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
|
||||
} else {
|
||||
res = [
|
||||
["M", x, y],
|
||||
["m", 0, -ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, 2 * ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, -2 * ry],
|
||||
["z"]
|
||||
];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function pathToAbsolute(pathArray) {
|
||||
pathArray = parsePathString(pathArray);
|
||||
if (!pathArray || !pathArray.length) {
|
||||
return [["M", 0, 0]];
|
||||
}
|
||||
var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0,
|
||||
ii = pathArray.length,
|
||||
crz = pathArray.length === 3 &&
|
||||
pathArray[0][0] === "M" &&
|
||||
pathArray[1][0].toUpperCase() === "R" &&
|
||||
pathArray[2][0].toUpperCase() === "Z";
|
||||
if (pathArray[0][0] === "M") {
|
||||
x = +pathArray[0][1];
|
||||
y = +pathArray[0][2];
|
||||
mx = x;
|
||||
my = y;
|
||||
start++;
|
||||
res[0] = ["M", x, y];
|
||||
}
|
||||
var loop = function ( i ) {
|
||||
var r = (void 0), pa = pathArray[i], pa0 = pa[0];
|
||||
res.push(r = []);
|
||||
if (pa0 !== pa0.toUpperCase()) {
|
||||
r[0] = pa0.toUpperCase();
|
||||
switch (r[0]) {
|
||||
case "A":
|
||||
r[1] = pa[1];
|
||||
r[2] = pa[2];
|
||||
r[3] = pa[3];
|
||||
r[4] = pa[4];
|
||||
r[5] = pa[5];
|
||||
r[6] = +pa[6] + x;
|
||||
r[7] = +pa[7] + y;
|
||||
break;
|
||||
case "V":
|
||||
r[1] = +pa[1] + y;
|
||||
break;
|
||||
case "H":
|
||||
r[1] = +pa[1] + x;
|
||||
break;
|
||||
case "R":
|
||||
var dots$1 = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots$1.length; j < jj; j++) {
|
||||
dots$1[j] = +dots$1[j] + x;
|
||||
dots$1[++j] = +dots$1[j] + y;
|
||||
}
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots$1, crz));
|
||||
break;
|
||||
case "O":
|
||||
res.pop();
|
||||
dots$1 = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots$1.push(dots$1[0]);
|
||||
res = res.concat(dots$1);
|
||||
break;
|
||||
case "U":
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
break;
|
||||
case "M":
|
||||
mx = +pa[1] + x;
|
||||
my = +pa[2] + y;
|
||||
default:
|
||||
for (var j$1 = 1, jj$1 = pa.length; j$1 < jj$1; j$1++) {
|
||||
r[j$1] = +pa[j$1] + ((j$1 % 2) ? x : y);
|
||||
}
|
||||
}
|
||||
} else if (pa0 === "R") {
|
||||
dots = [x, y].concat(pa.slice(1));
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
r = ["R"].concat(pa.slice(-2));
|
||||
} else if (pa0 === "O") {
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, +pa[1], +pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
} else if (pa0 === "U") {
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, +pa[1], +pa[2], +pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
} else {
|
||||
pa.map(function (k){ return r.push(k); });
|
||||
}
|
||||
}, true);
|
||||
return this;
|
||||
};
|
||||
SvgPath.prototype.toString = function toString () {
|
||||
var this$1 = this;
|
||||
var elements = [], skipCmd, cmd;
|
||||
this.segments.map( function (s,i) {
|
||||
cmd = s[0];
|
||||
skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this$1.segments[i - 1][0];
|
||||
elements = elements.concat(skipCmd ? s.slice(1) : s);
|
||||
});
|
||||
return elements.join(' ')
|
||||
.replace(/ ?([achlmqrstvz]) ?/gi, '$1')
|
||||
.replace(/ \-/g, '-')
|
||||
.replace(/zm/g, 'z m');
|
||||
};
|
||||
function split(parsed) {
|
||||
return parsed
|
||||
.toString()
|
||||
.split("M")
|
||||
.map(function (d, i) {
|
||||
d = d.trim();
|
||||
return i && d ? "M" + d : d;
|
||||
})
|
||||
.filter(function (d) { return d; });
|
||||
pa0 = pa0.toUpperCase();
|
||||
if (pa0 !== "O") {
|
||||
switch (r[0]) {
|
||||
case "Z":
|
||||
x = mx;
|
||||
y = my;
|
||||
break;
|
||||
case "H":
|
||||
x = +r[1];
|
||||
break;
|
||||
case "V":
|
||||
y = +r[1];
|
||||
break;
|
||||
case "M":
|
||||
mx = +r[r.length - 2];
|
||||
my = +r[r.length - 1];
|
||||
default:
|
||||
x = +r[r.length - 2];
|
||||
y = +r[r.length - 1];
|
||||
}
|
||||
}
|
||||
};
|
||||
for (var i = start; i < ii; i++) loop( i );
|
||||
return roundPath(res)
|
||||
}
|
||||
|
||||
function pathToString(pathArray) {
|
||||
return pathArray.map( function (c) {
|
||||
if (typeof c === 'string') {
|
||||
return c
|
||||
} else {
|
||||
return c.shift() + c.join(',')
|
||||
}
|
||||
}).join(' ')
|
||||
}
|
||||
|
||||
function splitPath(pathString) {
|
||||
return pathString
|
||||
.replace( /(m|M)/g, "|$1")
|
||||
.split('|')
|
||||
.map(function (s){ return s.trim(); })
|
||||
.filter(function (s){ return s; })
|
||||
}
|
||||
|
||||
var INVALID_INPUT = 'Invalid path value';
|
||||
function isFiniteNumber(number) {
|
||||
return typeof number === "number" && isFinite(number);
|
||||
}
|
||||
function distance(a, b) {
|
||||
return Math.sqrt(
|
||||
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
|
||||
);
|
||||
}
|
||||
function pointAlong(a, b, pct) {
|
||||
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
|
||||
}
|
||||
function samePoint(a, b) {
|
||||
return distance(a, b) < 1e-9;
|
||||
}
|
||||
function pathStringToRing(str, maxSegmentLength) {
|
||||
var parsed = new SvgPath(str).abs();
|
||||
var parsed = pathToAbsolute(str);
|
||||
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
|
||||
}
|
||||
function exactRing(parsed) {
|
||||
var segments = parsed.segments || [],
|
||||
ring = [];
|
||||
function exactRing(segments) {
|
||||
var ring = [];
|
||||
if (!segments.length || segments[0][0] !== "M") {
|
||||
return false;
|
||||
}
|
||||
|
@ -1847,7 +1947,8 @@
|
|||
return ring.length ? { ring: ring } : false;
|
||||
}
|
||||
function approximateRing(parsed, maxSegmentLength) {
|
||||
var ringPath = split(parsed)[0], ring = [], len, testPath, numPoints = 3;
|
||||
var ringPath = splitPath(pathToString(parsed))[0],
|
||||
ring = [], len, testPath, numPoints = 3;
|
||||
if (!ringPath) {
|
||||
throw new TypeError(INVALID_INPUT);
|
||||
}
|
||||
|
@ -2038,9 +2139,11 @@
|
|||
defaultOptions: {morphPrecision : 10, morphIndex:0},
|
||||
functions: svgMorphFunctions,
|
||||
Util: {
|
||||
INVALID_INPUT: INVALID_INPUT,isFiniteNumber: isFiniteNumber,distance: distance,pointAlong: pointAlong,samePoint: samePoint,paramCounts: paramCounts,SPECIAL_SPACES: SPECIAL_SPACES,isSpace: isSpace,isCommand: isCommand,isArc: isArc,isDigit: isDigit,
|
||||
isDigitStart: isDigitStart,State: State,skipSpaces: skipSpaces,scanFlag: scanFlag,scanParam: scanParam,finalizeSegment: finalizeSegment,scanSegment: scanSegment,pathParse: pathParse,SvgPath: SvgPath,split: split,pathStringToRing: pathStringToRing,
|
||||
exactRing: exactRing,approximateRing: approximateRing,measure: measure,rotateRing: rotateRing,polygonLength: polygonLength,polygonArea: polygonArea,addPoints: addPoints,bisect: bisect,normalizeRing: normalizeRing,validRing: validRing,getInterpolationPoints: getInterpolationPoints}
|
||||
INVALID_INPUT: INVALID_INPUT,isFiniteNumber: isFiniteNumber,distance: distance,pointAlong: pointAlong,samePoint: samePoint,
|
||||
pathToAbsolute: pathToAbsolute,pathToString: pathToString,pathStringToRing: pathStringToRing,
|
||||
exactRing: exactRing,approximateRing: approximateRing,measure: measure,rotateRing: rotateRing,polygonLength: polygonLength,polygonArea: polygonArea,
|
||||
addPoints: addPoints,bisect: bisect,normalizeRing: normalizeRing,validRing: validRing,getInterpolationPoints: getInterpolationPoints
|
||||
}
|
||||
};
|
||||
Components.SVGMorph = svgMorph;
|
||||
|
||||
|
|
2
dist/kute.min.js
vendored
2
dist/kute.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -54,6 +54,7 @@
|
|||
},
|
||||
"homepage": "http://thednp.github.io/kute.js",
|
||||
"dependencies": {
|
||||
"svg-path-commander": "^0.0.1-c",
|
||||
"cubic-bezier-easing": "^1.0.2",
|
||||
"minifill": "^0.0.13",
|
||||
"shorter-js": "^0.1.4"
|
||||
|
|
|
@ -2,504 +2,17 @@ import Components from '../objects/components.js'
|
|||
import selector from '../util/selector.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import {toPathString,onStartCubicMorph} from './svgCubicMorphBase.js'
|
||||
import {onStartCubicMorph} from './svgCubicMorphBase.js'
|
||||
|
||||
import parsePathString from 'svg-path-commander/src/process/parsePathString.js'
|
||||
import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute.js'
|
||||
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve.js'
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
import reverseCurve from 'svg-path-commander/src/process/reverseCurve.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Util
|
||||
const INVALID_INPUT = 'Invalid path value'
|
||||
|
||||
/* Raphael.js - path (https://github.com/DmitryBaranovskiy/raphael)
|
||||
* Copyright © 2008-2013 Dmitry Baranovskiy (http://dmitrybaranovskiy.github.io/raphael/)
|
||||
* Copyright © 2008-2013 Sencha Labs (http://sencha.com)
|
||||
* Licensed under the MIT (http://dmitrybaranovskiy.github.io/raphael/license.html) license.
|
||||
* KUTE.js modifications
|
||||
* - parsePathString is now moved outside of main functions
|
||||
* - processPath moved outside pathToAbsolute function body
|
||||
* - fixArc moved outside path2curve function body
|
||||
* - fixM moved outside path2curve function body
|
||||
* - minor fixes like "a != b" => "a !== b", various undefined/unused variables
|
||||
*/
|
||||
|
||||
// http://schepers.cc/getting-to-the-point
|
||||
function catmullRom2bezier(crp, z) {
|
||||
const d = [];
|
||||
for (let i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
|
||||
const p = [
|
||||
{x: +crp[i - 2], y: +crp[i - 1]},
|
||||
{x: +crp[i], y: +crp[i + 1]},
|
||||
{x: +crp[i + 2], y: +crp[i + 3]},
|
||||
{x: +crp[i + 4], y: +crp[i + 5]}
|
||||
];
|
||||
if (z) {
|
||||
if (!i) {
|
||||
p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
|
||||
} else if (iLen - 4 == i) {
|
||||
p[3] = {x: +crp[0], y: +crp[1]};
|
||||
} else if (iLen - 2 == i) {
|
||||
p[2] = {x: +crp[0], y: +crp[1]};
|
||||
p[3] = {x: +crp[2], y: +crp[3]};
|
||||
}
|
||||
} else {
|
||||
if (iLen - 4 == i) {
|
||||
p[3] = p[2];
|
||||
} else if (!i) {
|
||||
p[0] = {x: +crp[i], y: +crp[i + 1]};
|
||||
}
|
||||
}
|
||||
d.push(["C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
])
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
function ellipsePath(x, y, rx, ry, a) {
|
||||
if (a == null && ry == null) {
|
||||
ry = rx;
|
||||
}
|
||||
x = +x;
|
||||
y = +y;
|
||||
rx = +rx;
|
||||
ry = +ry;
|
||||
let res;
|
||||
if (a != null) {
|
||||
const rad = Math.PI / 180,
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad);
|
||||
res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
|
||||
} else {
|
||||
res = [
|
||||
["M", x, y],
|
||||
["m", 0, -ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, 2 * ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, -2 * ry],
|
||||
["z"]
|
||||
];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Parses given path string into an array of arrays of path segments
|
||||
function parsePathString(pathString) {
|
||||
if (!pathString) {
|
||||
return null;
|
||||
}
|
||||
if( pathString instanceof Array ) {
|
||||
return pathString;
|
||||
} else {
|
||||
// tracer minifier cannot compute this string for some reason
|
||||
// let spaces = "\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029";
|
||||
let spaces = `\\${("x09|x0a|x0b|x0c|x0d|x20|xa0|u1680|u180e|u2000|u2001|u2002|u2003|u2004|u2005|u2006|u2007|u2008|u2009|u200a|u202f|u205f|u3000|u2028|u2029").split('|').join('\\')}`,
|
||||
pathCommand = new RegExp(`([a-z])[${spaces},]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[${spaces}]*,?[${spaces}]*)+)`, `ig`),
|
||||
pathValues = new RegExp(`(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[${spaces}]*,?[${spaces}]*`, `ig`),
|
||||
paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
|
||||
data = [];
|
||||
|
||||
pathString.replace(pathCommand, (a, b, c) => {
|
||||
let params = [], name = b.toLowerCase();
|
||||
|
||||
c.replace(pathValues, (a, b) => {
|
||||
b && params.push(+b);
|
||||
});
|
||||
if (name == "m" && params.length > 2) {
|
||||
data.push([b].concat(params.splice(0, 2)));
|
||||
name = "l";
|
||||
b = b == "m" ? "l" : "L";
|
||||
}
|
||||
if (name == "o" && params.length == 1) {
|
||||
data.push([b, params[0]]);
|
||||
}
|
||||
if (name == "r") {
|
||||
data.push([b].concat(params));
|
||||
} else while (params.length >= paramCounts[name]) {
|
||||
data.push([b].concat(params.splice(0, paramCounts[name])));
|
||||
if (!paramCounts[name]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
function pathToAbsolute(pathArray) {
|
||||
pathArray = parsePathString(pathArray);
|
||||
|
||||
if (!pathArray || !pathArray.length) {
|
||||
return [["M", 0, 0]];
|
||||
}
|
||||
let res = [], x = 0, y = 0, mx = 0, my = 0, start = 0, pa0;
|
||||
if (pathArray[0][0] === "M") {
|
||||
x = +pathArray[0][1];
|
||||
y = +pathArray[0][2];
|
||||
mx = x;
|
||||
my = y;
|
||||
start++;
|
||||
res[0] = ["M", x, y];
|
||||
}
|
||||
const crz = pathArray.length === 3 &&
|
||||
pathArray[0][0] === "M" &&
|
||||
pathArray[1][0].toUpperCase() === "R" &&
|
||||
pathArray[2][0].toUpperCase() === "Z";
|
||||
for (let r, pa, i = start, ii = pathArray.length; i < ii; i++) {
|
||||
res.push(r = []);
|
||||
pa = pathArray[i];
|
||||
pa0 = pa[0];
|
||||
if (pa0 !== pa0.toUpperCase()) {
|
||||
r[0] = pa0.toUpperCase();
|
||||
switch (r[0]) {
|
||||
case "A":
|
||||
r[1] = pa[1];
|
||||
r[2] = pa[2];
|
||||
r[3] = pa[3];
|
||||
r[4] = pa[4];
|
||||
r[5] = pa[5];
|
||||
r[6] = +pa[6] + x;
|
||||
r[7] = +pa[7] + y;
|
||||
break;
|
||||
case "V":
|
||||
r[1] = +pa[1] + y;
|
||||
break;
|
||||
case "H":
|
||||
r[1] = +pa[1] + x;
|
||||
break;
|
||||
case "R":
|
||||
var dots = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots.length; j < jj; j++) {
|
||||
dots[j] = +dots[j] + x;
|
||||
dots[++j] = +dots[j] + y;
|
||||
}
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
break;
|
||||
case "O":
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
break;
|
||||
case "U":
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
break;
|
||||
case "M":
|
||||
mx = +pa[1] + x;
|
||||
my = +pa[2] + y;
|
||||
default:
|
||||
for (j = 1, jj = pa.length; j < jj; j++) {
|
||||
r[j] = +pa[j] + ((j % 2) ? x : y);
|
||||
}
|
||||
}
|
||||
} else if (pa0 == "R") {
|
||||
dots = [x, y].concat(pa.slice(1));
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
r = ["R"].concat(pa.slice(-2));
|
||||
} else if (pa0 == "O") {
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
} else if (pa0 == "U") {
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
} else {
|
||||
for (let k = 0, kk = pa.length; k < kk; k++) {
|
||||
r[k] = pa[k];
|
||||
}
|
||||
}
|
||||
pa0 = pa0.toUpperCase();
|
||||
if (pa0 != "O") {
|
||||
switch (r[0]) {
|
||||
case "Z":
|
||||
x = +mx;
|
||||
y = +my;
|
||||
break;
|
||||
case "H":
|
||||
x = r[1];
|
||||
break;
|
||||
case "V":
|
||||
y = r[1];
|
||||
break;
|
||||
case "M":
|
||||
mx = r[r.length - 2];
|
||||
my = r[r.length - 1];
|
||||
default:
|
||||
x = r[r.length - 2];
|
||||
y = r[r.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function l2c(x1, y1, x2, y2) {
|
||||
return [x1, y1, x2, y2, x2, y2];
|
||||
}
|
||||
function q2c(x1, y1, ax, ay, x2, y2) {
|
||||
const _13 = 1 / 3;
|
||||
const _23 = 2 / 3;
|
||||
return [
|
||||
_13 * x1 + _23 * ax,
|
||||
_13 * y1 + _23 * ay,
|
||||
_13 * x2 + _23 * ax,
|
||||
_13 * y2 + _23 * ay,
|
||||
x2,
|
||||
y2
|
||||
]
|
||||
}
|
||||
|
||||
// for more information of where this math came from visit:
|
||||
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
||||
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
|
||||
const _120 = Math.PI * 120 / 180, rad = Math.PI / 180 * (+angle || 0);
|
||||
let res = [], xy, f1, f2, cx, cy;
|
||||
|
||||
function rotateVector(x, y, rad) {
|
||||
const X = x * Math.cos(rad) - y * Math.sin(rad),
|
||||
Y = x * Math.sin(rad) + y * Math.cos(rad);
|
||||
return {x: X, y: Y};
|
||||
}
|
||||
|
||||
if (!recursive) {
|
||||
xy = rotateVector(x1, y1, -rad);
|
||||
x1 = xy.x;
|
||||
y1 = xy.y;
|
||||
xy = rotateVector(x2, y2, -rad);
|
||||
x2 = xy.x;
|
||||
y2 = xy.y;
|
||||
// const cos = Math.cos(Math.PI / 180 * angle);
|
||||
// const sin = Math.sin(Math.PI / 180 * angle);
|
||||
let x = (x1 - x2) / 2, y = (y1 - y2) / 2, h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
|
||||
if (h > 1) {
|
||||
h = Math.sqrt(h);
|
||||
rx = h * rx;
|
||||
ry = h * ry;
|
||||
}
|
||||
let rx2 = rx * rx,
|
||||
ry2 = ry * ry,
|
||||
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)));
|
||||
|
||||
cx = k * rx * y / ry + (x1 + x2) / 2,
|
||||
cy = k * -ry * x / rx + (y1 + y2) / 2;
|
||||
|
||||
f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
|
||||
f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
|
||||
|
||||
f1 = x1 < cx ? Math.PI - f1 : f1;
|
||||
f2 = x2 < cx ? Math.PI - f2 : f2;
|
||||
f1 < 0 && (f1 = Math.PI * 2 + f1);
|
||||
f2 < 0 && (f2 = Math.PI * 2 + f2);
|
||||
if (sweep_flag && f1 > f2) {
|
||||
f1 = f1 - Math.PI * 2;
|
||||
}
|
||||
if (!sweep_flag && f2 > f1) {
|
||||
f2 = f2 - Math.PI * 2;
|
||||
}
|
||||
} else {
|
||||
f1 = recursive[0];
|
||||
f2 = recursive[1];
|
||||
cx = recursive[2];
|
||||
cy = recursive[3];
|
||||
}
|
||||
let df = f2 - f1;
|
||||
if (Math.abs(df) > _120) {
|
||||
const f2old = f2, x2old = x2, y2old = y2;
|
||||
|
||||
f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
|
||||
x2 = cx + rx * Math.cos(f2);
|
||||
y2 = cy + ry * Math.sin(f2);
|
||||
res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
|
||||
}
|
||||
df = f2 - f1;
|
||||
const c1 = Math.cos(f1),
|
||||
s1 = Math.sin(f1),
|
||||
c2 = Math.cos(f2),
|
||||
s2 = Math.sin(f2),
|
||||
t = Math.tan(df / 4),
|
||||
hx = 4 / 3 * rx * t,
|
||||
hy = 4 / 3 * ry * t,
|
||||
m1 = [x1, y1],
|
||||
m2 = [x1 + hx * s1, y1 - hy * c1],
|
||||
m3 = [x2 + hx * s2, y2 - hy * c2],
|
||||
m4 = [x2, y2];
|
||||
m2[0] = 2 * m1[0] - m2[0];
|
||||
m2[1] = 2 * m1[1] - m2[1];
|
||||
if (recursive) {
|
||||
return [m2, m3, m4].concat(res);
|
||||
} else {
|
||||
res = [m2, m3, m4].concat(res).join().split(",");
|
||||
const newres = [];
|
||||
for (let i = 0, ii = res.length; i < ii; i++) {
|
||||
newres[i] = i % 2 ? rotateVector(res[i - 1], res[i], rad).y : rotateVector(res[i], res[i + 1], rad).x;
|
||||
}
|
||||
return newres;
|
||||
}
|
||||
}
|
||||
|
||||
function processPath (path, d, pcom) {
|
||||
let nx, ny;
|
||||
if (!path) {
|
||||
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
|
||||
}
|
||||
!(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
|
||||
switch (path[0]) {
|
||||
case "M":
|
||||
d.X = path[1];
|
||||
d.Y = path[2];
|
||||
break;
|
||||
case "A":
|
||||
path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
|
||||
break;
|
||||
case "S":
|
||||
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
|
||||
nx = d.x * 2 - d.bx; // And reflect the previous
|
||||
ny = d.y * 2 - d.by; // command's control point relative to the current point.
|
||||
}
|
||||
else { // or some else or nothing
|
||||
nx = d.x;
|
||||
ny = d.y;
|
||||
}
|
||||
path = ["C", nx, ny].concat(path.slice(1));
|
||||
break;
|
||||
case "T":
|
||||
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
|
||||
d.qx = d.x * 2 - d.qx; // And make a reflection similar
|
||||
d.qy = d.y * 2 - d.qy; // to case "S".
|
||||
}
|
||||
else { // or something else or nothing
|
||||
d.qx = d.x;
|
||||
d.qy = d.y;
|
||||
}
|
||||
path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
|
||||
break;
|
||||
case "Q":
|
||||
d.qx = path[1];
|
||||
d.qy = path[2];
|
||||
path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
|
||||
break;
|
||||
case "L":
|
||||
path = ["C"].concat(l2c(d.x, d.y, path[1], path[2]));
|
||||
break;
|
||||
case "H":
|
||||
path = ["C"].concat(l2c(d.x, d.y, path[1], d.y));
|
||||
break;
|
||||
case "V":
|
||||
path = ["C"].concat(l2c(d.x, d.y, d.x, path[1]));
|
||||
break;
|
||||
case "Z":
|
||||
path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
|
||||
break;
|
||||
}
|
||||
path.map((x,i)=>i?x.toFixed(3):x)
|
||||
return path;
|
||||
}
|
||||
|
||||
function fixM (path1, path2, a1, a2, i) {
|
||||
if (path1 && path2 && path1[i][0] === "M" && path2[i][0] !== "M") {
|
||||
path2.splice(i, 0, ["M", a2.x, a2.y]);
|
||||
a1.bx = 0;
|
||||
a1.by = 0;
|
||||
a1.x = path1[i][1];
|
||||
a1.y = path1[i][2];
|
||||
// ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
}
|
||||
}
|
||||
|
||||
function fixArc (p, p2, pcoms1, pcoms2, i) {
|
||||
if (p[i].length > 7) {
|
||||
p[i].shift();
|
||||
const pi = p[i];
|
||||
while (pi.length) {
|
||||
pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
|
||||
p2 && (pcoms2[i] = "A"); // the same as above
|
||||
p.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
|
||||
}
|
||||
p.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function path2curve(path, path2) {
|
||||
let p = pathToAbsolute(path), // holder for previous path command of original path
|
||||
p2 = path2 && pathToAbsolute(path2),
|
||||
// p2 = path2 ? pathToAbsolute(path2) : pathToAbsolute('M0,0L0,0'),
|
||||
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
|
||||
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null};
|
||||
|
||||
// path commands of original path p
|
||||
// path commands of original path p2
|
||||
// temporary holder for original path command
|
||||
let pcoms1 = [], pcoms2 = [], pfirst = "", pcom = "";
|
||||
|
||||
for (let i = 0, ii = Math.max(p.length, p2 && p2.length || 0); i < ii; i++) {
|
||||
p[i] && (pfirst = p[i][0]); // save current path command
|
||||
|
||||
if (pfirst !== "C") { // C is not saved yet, because it may be result of conversion
|
||||
pcoms1[i] = pfirst; // Save current path command
|
||||
i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
|
||||
}
|
||||
p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
|
||||
|
||||
// A is the only command
|
||||
// which may produce multiple C:s
|
||||
// so we have to make sure that C is also C in original path
|
||||
if (pcoms1[i] !== "A" && pfirst === "C") pcoms1[i] = "C";
|
||||
|
||||
// fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
|
||||
fixArc(p, p2, pcoms1, pcoms2, i); // fixArc adds also the right amount of A:s to pcoms1 fixArc (p, p2, pcoms1, pcoms2, i) {
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
|
||||
if (p2) { // the same procedures is done to p2
|
||||
p2[i] && (pfirst = p2[i][0]);
|
||||
if (pfirst !== "C") {
|
||||
pcoms2[i] = pfirst;
|
||||
i && (pcom = pcoms2[i - 1]);
|
||||
}
|
||||
p2[i] = processPath(p2[i], attrs2, pcom);
|
||||
|
||||
if (pcoms2[i] !== "A" && pfirst === "C") {
|
||||
pcoms2[i] = "C";
|
||||
}
|
||||
|
||||
// fixArc(p2, i);
|
||||
fixArc(p2, p, pcoms2, pcoms1, i); // fixArc (p, p2, pcoms1, pcoms2, i) {
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
}
|
||||
fixM(p, p2, attrs, attrs2, i);
|
||||
p2 && fixM(p2, p, attrs2, attrs, i);
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
|
||||
let seg = p[i],
|
||||
seg2 = p2 && p2[i],
|
||||
seglen = seg.length,
|
||||
seg2len = p2 && seg2.length;
|
||||
attrs.x = seg[seglen - 2];
|
||||
attrs.y = seg[seglen - 1];
|
||||
attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
|
||||
attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
|
||||
attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x);
|
||||
attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y);
|
||||
attrs2.x = p2 && seg2[seg2len - 2];
|
||||
attrs2.y = p2 && seg2[seg2len - 1];
|
||||
}
|
||||
|
||||
return p2 ? [p, p2] : p;
|
||||
}
|
||||
|
||||
function createPath (path) { // create a <path> when glyph
|
||||
const np = document.createElementNS('http://www.w3.org/2000/svg','path'),
|
||||
d = path instanceof SVGElement ? path.getAttribute('d') : path
|
||||
|
@ -507,82 +20,42 @@ function createPath (path) { // create a <path> when glyph
|
|||
return np
|
||||
}
|
||||
|
||||
function getSegments(curveArray) {
|
||||
// let result = []
|
||||
// curveArray.map((seg, i) => {
|
||||
// result[i] = {
|
||||
// x: seg[seg[0] === 'M' ? 1 : 5],
|
||||
// y: seg[seg[0] === 'M' ? 2 : 6],
|
||||
// seg: seg
|
||||
// }
|
||||
// })
|
||||
// return result
|
||||
|
||||
return curveArray.map(seg => {
|
||||
return {
|
||||
x: seg[seg[0] === 'M' ? 1 : 5],
|
||||
y: seg[seg[0] === 'M' ? 2 : 6],
|
||||
seg: seg
|
||||
}
|
||||
})
|
||||
}
|
||||
function reverseCurve(path){
|
||||
let newSegments = [],
|
||||
oldSegments = getSegments(path),
|
||||
segsCount = oldSegments.length,
|
||||
pointCount = segsCount - 1,
|
||||
oldSegIdx = pointCount,
|
||||
oldSegs = []
|
||||
|
||||
oldSegments.map((p,i)=>{
|
||||
if (i === 0||oldSegments[oldSegIdx].seg[0] === 'M') {
|
||||
newSegments[i] = ['M',oldSegments[oldSegIdx].x,oldSegments[oldSegIdx].y]
|
||||
} else {
|
||||
oldSegIdx = pointCount - i > 0 ? pointCount - i : pointCount;
|
||||
oldSegs = oldSegments[oldSegIdx].seg
|
||||
newSegments[i] = [oldSegs[0], oldSegs[5],oldSegs[6],oldSegs[3],oldSegs[4], oldSegs[1], oldSegs[2]]
|
||||
}
|
||||
})
|
||||
|
||||
return newSegments
|
||||
}
|
||||
|
||||
function getRotationSegments(s,idx) {
|
||||
let newSegments = [], segsCount = s.length, pointCount = segsCount - 1
|
||||
let segsCount = s.length, pointCount = segsCount - 1
|
||||
|
||||
s.map((p,i)=>{
|
||||
let oldSegIdx = idx + i;
|
||||
if (i===0 || s[oldSegIdx] && s[oldSegIdx].seg[0] === 'M') {
|
||||
newSegments[i] = ['M',s[oldSegIdx].x,s[oldSegIdx].y]
|
||||
return s.map((p,i)=>{
|
||||
let oldSegIdx = idx + i, seg;
|
||||
if (i===0 || s[oldSegIdx] && s[oldSegIdx][0] === 'M') {
|
||||
seg = s[oldSegIdx]
|
||||
return ['M',seg[seg.length-2],seg[seg.length-1]]
|
||||
} else {
|
||||
if (oldSegIdx >= segsCount) oldSegIdx -= pointCount;
|
||||
newSegments[i] = s[oldSegIdx].seg
|
||||
return s[oldSegIdx]
|
||||
}
|
||||
})
|
||||
return newSegments
|
||||
}
|
||||
|
||||
function getRotations(a) {
|
||||
let startSegments = getSegments(a), rotations = [];
|
||||
startSegments.map((s,i)=>{rotations[i] = getRotationSegments(startSegments,i)})
|
||||
return rotations
|
||||
return a.map((s,i) => getRotationSegments(a,i))
|
||||
}
|
||||
|
||||
function getRotatedCurve(a,b) {
|
||||
let startSegments = getSegments(a),
|
||||
endSegments = getSegments(b),
|
||||
segsCount = startSegments.length,
|
||||
pointCount = segsCount - 1,
|
||||
let segCount = a.length - 1,
|
||||
linePaths = [],
|
||||
lineLengths = [],
|
||||
rotations = getRotations(a);
|
||||
|
||||
rotations.map((r,i)=>{
|
||||
let sumLensSqrd = 0, linePath = createPath('M0,0L0,0');
|
||||
for (let j = 0; j < pointCount; j++) {
|
||||
let linePt1 = startSegments[(i + j) % pointCount];
|
||||
let linePt2 = endSegments[ j % pointCount];
|
||||
let linePathStr = `M${linePt1.x},${linePt1.y}L${linePt2.x},${linePt2.y}`;
|
||||
let sumLensSqrd = 0,
|
||||
linePath = createPath('M0,0L0,0'),
|
||||
linePt1, ll1,
|
||||
linePt2, ll2,
|
||||
linePathStr
|
||||
|
||||
for (let j = 0; j < segCount; j++) {
|
||||
linePt1 = a[(i + j) % segCount]; ll1 = linePt1.length
|
||||
linePt2 = b[ j % segCount]; ll2 = linePt2.length
|
||||
linePathStr = `M${linePt1[ll1-2]},${linePt1[ll1-1]}L${linePt2[ll2-2]},${linePt2[ll2-1]}`
|
||||
linePath.setAttribute('d',linePathStr);
|
||||
sumLensSqrd += Math.pow(linePath.getTotalLength(),2);
|
||||
linePaths[j] = linePath;
|
||||
|
@ -591,9 +64,9 @@ function getRotatedCurve(a,b) {
|
|||
sumLensSqrd = 0
|
||||
})
|
||||
|
||||
let computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths)),
|
||||
newPath = rotations[computedIndex];
|
||||
return newPath
|
||||
let computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths))
|
||||
|
||||
return rotations[computedIndex]
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
|
@ -630,10 +103,10 @@ function crossCheckCubicMorph(tweenProp){
|
|||
if ( !pathCurve1 || !pathCurve2 || ( pathCurve1 && pathCurve2 && pathCurve1[0][0] === 'M' && pathCurve1.length !== pathCurve2.length) ) {
|
||||
let path1 = this.valuesStart[tweenProp].original,
|
||||
path2 = this.valuesEnd[tweenProp].original,
|
||||
curves = path2curve(path1,path2)
|
||||
curves = pathToCurve(path1,path2)
|
||||
|
||||
let curve0 = this._reverseFirstPath ? reverseCurve.call(this,curves[0]) : curves[0],
|
||||
curve1 = this._reverseSecondPath ? reverseCurve.call(this,curves[1]) : curves[1]
|
||||
let curve0 = this._reverseFirstPath ? reverseCurve(curves[0]) : curves[0],
|
||||
curve1 = this._reverseSecondPath ? reverseCurve(curves[1]) : curves[1]
|
||||
|
||||
curve0 = getRotatedCurve.call(this,curve0,curve1)
|
||||
this.valuesStart[tweenProp].curve = curve0;
|
||||
|
@ -655,14 +128,13 @@ const svgCubicMorph = {
|
|||
component: 'svgCubicMorph',
|
||||
property: 'path',
|
||||
defaultValue: [],
|
||||
Interpolate: {numbers,toPathString},
|
||||
Interpolate: {numbers,pathToString},
|
||||
functions: svgCubicMorphFunctions,
|
||||
// export utils to global for faster execution
|
||||
Util: {
|
||||
l2c, q2c, a2c, catmullRom2bezier, ellipsePath,
|
||||
path2curve, pathToAbsolute, toPathString, parsePathString,
|
||||
pathToCurve, pathToAbsolute, pathToString, parsePathString,
|
||||
getRotatedCurve, getRotations,
|
||||
getRotationSegments, reverseCurve, getSegments, createPath
|
||||
getRotationSegments, reverseCurve, createPath
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Interpolation
|
||||
export function toPathString(pathArray) {
|
||||
let newPath = pathArray.map( (c) => {
|
||||
if (typeof(c) === 'string') {
|
||||
return c
|
||||
} else {
|
||||
let c0 = c.shift();
|
||||
return c0 + c.join(',')
|
||||
}
|
||||
})
|
||||
return newPath.join('');
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
export function onStartCubicMorph(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = function(elem,a,b,v){
|
||||
// v === 1 && console.log(a.curve,b.curve)
|
||||
|
||||
let curve = [], path1 = a.curve, path2 = b.curve;
|
||||
for(let i=0, l=path2.length; i<l; i++) { // each path command
|
||||
curve.push([path1[i][0]]);
|
||||
|
@ -27,7 +19,7 @@ export function onStartCubicMorph(tweenProp){
|
|||
curve[i].push( (numbers(path1[i][j], path2[i][j], v) * 1000 >>0)/1000 );
|
||||
}
|
||||
}
|
||||
elem.setAttribute("d", v === 1 ? b.original : toPathString(curve) );
|
||||
elem.setAttribute("d", v === 1 ? b.original : pathToString(curve) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +29,7 @@ const baseSvgCubicMorph = {
|
|||
component: 'baseSVGCubicMorph',
|
||||
property: 'path',
|
||||
// defaultValue: [],
|
||||
Interpolate: {numbers,toPathString},
|
||||
Interpolate: {numbers,pathToString},
|
||||
functions: {onStart:onStartCubicMorph}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,16 @@ import defaultOptions from '../objects/defaultOptions.js'
|
|||
import Components from '../objects/components.js'
|
||||
import coords from '../interpolation/coords.js'
|
||||
import {onStartSVGMorph} from './svgMorphBase.js'
|
||||
|
||||
import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute.js'
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
import splitPath from 'svg-path-commander/src/util/splitPath.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers,coords} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Interpolation
|
||||
// function function(array1, array2, length, progress)
|
||||
|
||||
|
||||
// Component Util
|
||||
const INVALID_INPUT = 'Invalid path value'
|
||||
|
||||
|
@ -30,487 +33,15 @@ function samePoint(a, b) {
|
|||
return distance(a, b) < 1e-9;
|
||||
}
|
||||
|
||||
// SVGPATH
|
||||
// https://github.com/fontello/svgpath/
|
||||
const paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 };
|
||||
|
||||
const 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 isArc(code) {
|
||||
return (code | 0x20) === 0x61;
|
||||
}
|
||||
|
||||
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 scanFlag(state) {
|
||||
let ch = state.path.charCodeAt(state.index);
|
||||
|
||||
if (ch === 0x30/* 0 */) {
|
||||
state.param = 0;
|
||||
state.index++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch === 0x31/* 1 */) {
|
||||
state.param = 1;
|
||||
state.index++;
|
||||
return;
|
||||
}
|
||||
|
||||
// state.err = 'SvgPath: arc flag can be 0 or 1 only (at pos ' + state.index + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
}
|
||||
function scanParam(state) {
|
||||
let 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 + ')';.
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
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 + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
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 illegal (at pos ' + start + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
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 + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
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 + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
state.index = index;
|
||||
state.param = parseFloat(state.path.slice(start, index)) + 0.0;
|
||||
}
|
||||
function finalizeSegment(state) {
|
||||
let 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();
|
||||
|
||||
let 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) {
|
||||
let max = state.max, cmdCode, is_arc, comma_found, need_params, i;
|
||||
|
||||
state.segmentStart = state.index;
|
||||
cmdCode = state.path.charCodeAt(state.index);
|
||||
is_arc = isArc(cmdCode);
|
||||
|
||||
if (!isCommand(cmdCode)) {
|
||||
// state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')';
|
||||
state.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
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--) {
|
||||
if (is_arc && (i === 3 || i === 4)) scanFlag(state);
|
||||
else 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
|
||||
function pathParse(svgPath) {
|
||||
let state = new State(svgPath), 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.err = `KUTE.js - ${INVALID_INPUT}`;
|
||||
|
||||
state.result = [];
|
||||
} else {
|
||||
state.result[0][0] = 'M';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
err: state.err,
|
||||
segments: state.result
|
||||
};
|
||||
}
|
||||
|
||||
class SvgPath {
|
||||
constructor(path){
|
||||
if (!(this instanceof SvgPath)) { return new SvgPath(path); }
|
||||
|
||||
let 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;
|
||||
}
|
||||
// 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.
|
||||
//
|
||||
iterate(iterator) {
|
||||
let segments = this.segments,
|
||||
replacements = {},
|
||||
needReplace = false,
|
||||
lastX = 0,
|
||||
lastY = 0,
|
||||
countourStartX = 0,
|
||||
countourStartY = 0,
|
||||
newSegments;
|
||||
|
||||
segments.map( (s,index) => {
|
||||
|
||||
let res = iterator(s, index, lastX, lastY);
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
replacements[index] = res;
|
||||
needReplace = true;
|
||||
}
|
||||
|
||||
let 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 = [];
|
||||
|
||||
segments.map((s,i)=>{
|
||||
if (typeof replacements[i] !== 'undefined') {
|
||||
replacements[i].map((r)=>{
|
||||
newSegments.push(r);
|
||||
})
|
||||
} else {
|
||||
newSegments.push(s);
|
||||
}
|
||||
})
|
||||
|
||||
this.segments = newSegments;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Converts segments from relative to absolute
|
||||
abs() {
|
||||
this.iterate(function (s, index, x, y) {
|
||||
let 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;
|
||||
}
|
||||
// Convert processed SVG Path back to string
|
||||
//
|
||||
toString () {
|
||||
let elements = [], skipCmd, cmd;
|
||||
|
||||
this.segments.map( (s,i) => {
|
||||
// remove repeating commands names
|
||||
cmd = s[0];
|
||||
skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0];
|
||||
elements = elements.concat(skipCmd ? s.slice(1) : s);
|
||||
})
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
// flubber
|
||||
// https://github.com/veltman/flubber
|
||||
function split(parsed) {
|
||||
return parsed
|
||||
.toString()
|
||||
.split("M")
|
||||
.map((d, i) => {
|
||||
d = d.trim();
|
||||
return i && d ? "M" + d : d;
|
||||
})
|
||||
.filter(d => d);
|
||||
}
|
||||
|
||||
function pathStringToRing(str, maxSegmentLength) {
|
||||
let parsed = new SvgPath(str).abs();
|
||||
|
||||
let parsed = pathToAbsolute(str);
|
||||
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
|
||||
}
|
||||
|
||||
function exactRing(parsed) {
|
||||
let segments = parsed.segments || [],
|
||||
ring = [];
|
||||
function exactRing(segments) {
|
||||
let ring = [];
|
||||
|
||||
if (!segments.length || segments[0][0] !== "M") {
|
||||
return false;
|
||||
|
@ -535,7 +66,8 @@ function exactRing(parsed) {
|
|||
}
|
||||
|
||||
function approximateRing(parsed, maxSegmentLength) {
|
||||
let ringPath = split(parsed)[0], ring = [], len, testPath, numPoints = 3;
|
||||
let ringPath = splitPath(pathToString(parsed))[0],
|
||||
ring = [], len, testPath, numPoints = 3;
|
||||
|
||||
if (!ringPath) {
|
||||
throw new TypeError(INVALID_INPUT);
|
||||
|
@ -774,9 +306,11 @@ const svgMorph = {
|
|||
functions: svgMorphFunctions,
|
||||
// Export utils to global for faster execution
|
||||
Util: {
|
||||
INVALID_INPUT,isFiniteNumber,distance,pointAlong,samePoint,paramCounts,SPECIAL_SPACES,isSpace,isCommand,isArc,isDigit,
|
||||
isDigitStart,State,skipSpaces,scanFlag,scanParam,finalizeSegment,scanSegment,pathParse,SvgPath,split,pathStringToRing,
|
||||
exactRing,approximateRing,measure,rotateRing,polygonLength,polygonArea,addPoints,bisect,normalizeRing,validRing,getInterpolationPoints}
|
||||
INVALID_INPUT,isFiniteNumber,distance,pointAlong,samePoint,
|
||||
pathToAbsolute,pathToString,pathStringToRing,
|
||||
exactRing,approximateRing,measure,rotateRing,polygonLength,polygonArea,
|
||||
addPoints,bisect,normalizeRing,validRing,getInterpolationPoints
|
||||
}
|
||||
}
|
||||
|
||||
export default svgMorph
|
||||
|
|
17
src/core/queueStart.js
Normal file
17
src/core/queueStart.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import onStart from '../objects/onStart.js'
|
||||
import linkInterpolation from './linkInterpolation.js'
|
||||
|
||||
export default function(){
|
||||
// fire onStart actions
|
||||
for (let obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj) // easing functions
|
||||
} else {
|
||||
for (let prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
// add interpolations
|
||||
linkInterpolation.call(this)
|
||||
}
|
|
@ -9,6 +9,7 @@ import crossCheck from '../objects/crossCheck.js'
|
|||
import prepareObject from '../process/prepareObject.js'
|
||||
import getStartValues from '../process/getStartValues.js'
|
||||
import {Tick,Ticker} from '../core/render.js'
|
||||
import queueStart from '../core/queueStart.js'
|
||||
|
||||
defaultOptions.repeat = 0
|
||||
defaultOptions.repeatDelay = 0
|
||||
|
@ -83,8 +84,8 @@ export default class Tween extends TweenBase {
|
|||
getStartValues.call(this);
|
||||
|
||||
// this is where we do the valuesStart and valuesEnd check for fromTo() method
|
||||
for ( const component in crossCheck ) {
|
||||
for ( const prop in crossCheck[component] ) {
|
||||
for ( let component in crossCheck ) {
|
||||
for ( let prop in crossCheck[component] ) {
|
||||
crossCheck[component][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
|
@ -94,14 +95,13 @@ export default class Tween extends TweenBase {
|
|||
|
||||
// set yoyo values
|
||||
if (this._yoyo) {
|
||||
for ( const endProp in this.valuesEnd ) {
|
||||
for ( let endProp in this.valuesEnd ) {
|
||||
this.valuesRepeat[endProp] = this.valuesStart[endProp]
|
||||
}
|
||||
}
|
||||
|
||||
super.start(time);
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
// updates to super methods
|
||||
|
@ -135,16 +135,7 @@ export default class Tween extends TweenBase {
|
|||
this._onResume.call(this);
|
||||
}
|
||||
// re-queue execution context
|
||||
for (let obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj);
|
||||
} else {
|
||||
for (let prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
linkInterpolation.call(this);
|
||||
queueStart.call(this)
|
||||
// update time and let it roll
|
||||
this._startTime += KUTE.Time() - this._pauseTime;
|
||||
add(this);
|
||||
|
|
|
@ -8,7 +8,7 @@ import {Tick,Ticker,stop} from '../core/render.js'
|
|||
|
||||
import add from '../core/add.js'
|
||||
import remove from '../core/remove.js'
|
||||
import linkInterpolation from '../core/linkInterpolation.js'
|
||||
import queueStart from '../core/queueStart.js'
|
||||
|
||||
// single Tween object construct
|
||||
// TweenBase is meant to be use for pre-processed values
|
||||
|
@ -74,18 +74,7 @@ export default class TweenBase {
|
|||
this._onStart.call(this);
|
||||
}
|
||||
|
||||
// fire onStart actions
|
||||
for (let obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj) // easing functions
|
||||
} else {
|
||||
for (let prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
// add interpolations
|
||||
linkInterpolation.call(this)
|
||||
queueStart.call(this)
|
||||
|
||||
this._startFired = true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue