Compare commits
187 commits
Author | SHA1 | Date | |
---|---|---|---|
426a45596c | |||
1dfd1e6109 | |||
19f9df8a93 | |||
fd8d4ba7c8 | |||
62854fba05 | |||
af6f86f983 | |||
990f6aea93 | |||
f524f7ecaf | |||
dd664e9bc7 | |||
72b1847a0a | |||
df3505b3c3 | |||
ab686c7cdb | |||
541daab882 | |||
5ce011d41a | |||
441a9ecedb | |||
17ce738de3 | |||
60950ffd02 | |||
a62165820f | |||
eb72644cfe | |||
307f59a7a4 | |||
ffeb00d326 | |||
1b82c657a1 | |||
ca0b3c6a15 | |||
997972c35f | |||
48dc93e438 | |||
d6e9319dc3 | |||
732312431b | |||
918d566d1e | |||
18cfa78abb | |||
88a28c8d19 | |||
784e092960 | |||
a8c06c1dad | |||
dab615ea54 | |||
8c52e9f9e7 | |||
7c12028d46 | |||
97c795a972 | |||
ced91131a3 | |||
94fe92738c | |||
7e098ab567 | |||
96f7709012 | |||
2c756c90b7 | |||
acbeb00a48 | |||
1d8cf96422 | |||
b51196cb86 | |||
cb72a478c2 | |||
e313cb369f | |||
81a86026c5 | |||
bd73c423b6 | |||
96d7f8952a | |||
2f1fed31e3 | |||
52bfc84ef7 | |||
1e5deb1f1c | |||
850b1e5960 | |||
393d0a0a2b | |||
d33b3b313b | |||
7cd7fe226c | |||
c977185621 | |||
6192946161 | |||
9303db19f1 | |||
da327643c7 | |||
af9e57b1f7 | |||
e0274126d8 | |||
024fdd2322 | |||
449f5ed1e3 | |||
293098c0c6 | |||
b414705778 | |||
709e78ac3b | |||
7b5bb32c17 | |||
2f4810a0a1 | |||
3f4e0c4d47 | |||
d5d29d53d2 | |||
585de95907 | |||
ead5728dcd | |||
05c15ee98c | |||
a82263d4b4 | |||
4f7682cdca | |||
1cf5f87f82 | |||
f07f783731 | |||
3005967c32 | |||
6db0e4b92d | |||
8d70c4a6c7 | |||
5660465f20 | |||
93ab1779a8 | |||
d2141361a3 | |||
6ff8e274d1 | |||
90dee25c42 | |||
5b61b7a1fe | |||
112b35aa5f | |||
178cac445e | |||
b8e98b9764 | |||
2121a43c8a | |||
c8f46895a8 | |||
663e98d810 | |||
2a1b6aebcf | |||
19bd7f7000 | |||
61182d9b68 | |||
670d18894c | |||
352069e5c4 | |||
188bd1953b | |||
0348584c94 | |||
6a6b7cfad0 | |||
901edb1a8b | |||
56883c77a4 | |||
f93780061a | |||
7bcc0049d7 | |||
9bbcffb7b6 | |||
cafb243a36 | |||
94116ebe76 | |||
15a4d86a8f | |||
3449aa9a7e | |||
1c2650a154 | |||
4ff44da4f9 | |||
ee496ee8f6 | |||
4b3108c871 | |||
f05e454f3e | |||
f1b2399d05 | |||
d5724b01e4 | |||
1736cc9c9a | |||
aba3219412 | |||
695f77c9c4 | |||
44816ad61e | |||
9aef44f813 | |||
ab8ef18953 | |||
3c9683b002 | |||
eaf8f73b07 | |||
069a20430c | |||
fde91644b0 | |||
e29d08f6bf | |||
9ed385e4c2 | |||
04010b4cab | |||
5482d8383e | |||
7d44719816 | |||
dfa70cd629 | |||
d184fe310c | |||
f121972947 | |||
3d8fadde3e | |||
5f10bd711e | |||
1d153c363a | |||
ed59e23b77 | |||
b3b806279d | |||
95ecba3f67 | |||
2040b36e44 | |||
a666fda6e3 | |||
428b45f8e8 | |||
ef57b574f2 | |||
45901d20ab | |||
1423ab641e | |||
d972e26f59 | |||
b7b82afb6c | |||
c1e1d06a9f | |||
ac8f5ebe05 | |||
f909b46a7e | |||
ccd18a2855 | |||
ba36c3bf31 | |||
71929b7fc7 | |||
ddb8212e4c | |||
6b9b095118 | |||
a6534763af | |||
9fa0b5a328 | |||
6943b0c7e8 | |||
f00ef2dcd6 | |||
af58612491 | |||
74f35db07c | |||
7808f9760f | |||
26f03f6134 | |||
9e693955ed | |||
6860924799 | |||
2a15904963 | |||
eec0a2751a | |||
b2bfd94608 | |||
f0d5096572 | |||
05748003ea | |||
7ca29f28c9 | |||
147a8e9fc8 | |||
641281daf5 | |||
c2d8f0805e | |||
780e3a0793 | |||
1e1bb9306c | |||
a89203dfda | |||
f3353235c2 | |||
fad2ff91bc | |||
c4effded66 | |||
d5a18b8fd5 | |||
0a24580341 | |||
ae8d9d9472 | |||
7903fcd166 | |||
65c14a6cce |
41
.eslintrc
|
@ -1,41 +0,0 @@
|
|||
{
|
||||
"extends": [
|
||||
// Extend the airbnb eslint config
|
||||
"airbnb-base"
|
||||
// Vue
|
||||
// "plugin:vue/vue3-recommended"
|
||||
],
|
||||
// "parser": "vue-eslint-parser",
|
||||
// "parser": "eslint-plugin-vue",
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
// ESLint will not look in parent folders for eslint configs
|
||||
"root": false,
|
||||
// An environment defines global variables that are predefined.
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
// Rule overrides
|
||||
"rules": {
|
||||
// Disable no-restricted-globals for global objects
|
||||
"no-restricted-globals": 0,
|
||||
// Disable no-params-reassign for properties
|
||||
// "no-param-reassign": ["error", { "props": false }],
|
||||
// Allow strict mode (we are not dealing with modules)
|
||||
// "strict": [0],
|
||||
// Allow use of "private methods" - impossible to satisfy
|
||||
"no-underscore-dangle": 0
|
||||
// Disable alert rule till we have a CE in place
|
||||
// "no-alert": 0
|
||||
// Allow extensions on imports
|
||||
// "import/extensions": 0,
|
||||
// Allow exporting mutable 'let' binding
|
||||
// "import/no-mutable-exports": 0,
|
||||
// Allow no named as default / member
|
||||
// "import/no-named-as-default": 0,
|
||||
// "import/no-named-as-default-member": 0
|
||||
}
|
||||
}
|
8
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
node_modules/
|
||||
experiments/
|
||||
.npmignore
|
||||
package-lock.json
|
||||
|
||||
node_modules
|
||||
package-lock.json
|
||||
experiments
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
node_modules/
|
||||
demo/
|
||||
experiments/
|
||||
package-lock.json
|
||||
.gitignore
|
22
LICENSE
|
@ -1,22 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 thednp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
62
README.md
|
@ -1,62 +0,0 @@
|
|||
# KUTE.js
|
||||
|
||||
A modern JavaScript animation engine built on ES6+ standards with strong TypeScript definitions and most essential features for the web with easy to use methods to set up high performance, cross-browser animations. The focus is code quality, flexibility, performance and size.
|
||||
|
||||
[![NPM Version](https://img.shields.io/npm/v/kute.js.svg?style=flat-square)](https://www.npmjs.com/package/kute.js)
|
||||
[![NPM Downloads](https://img.shields.io/npm/dm/kute.js.svg?style=flat-square)](http://npm-stat.com/charts.html?package=kute.js)
|
||||
[![jsDeliver](https://data.jsdelivr.com/v1/package/npm/kute.js/badge)](https://www.jsdelivr.com/package/npm/kute.js)
|
||||
[![CDNJS](https://img.shields.io/cdnjs/v/kute.js.svg?style=flat-square)](https://cdnjs.com/libraries/kute.js)
|
||||
|
||||
KUTE.js packs a series of components for presentation attributes, SVG transform, draw SVG strokes and path morphing, text string write up or number countdowns, plus additional CSS properties like colors, border-radius or typographic properties.
|
||||
|
||||
For components documentation, examples and other cool tips, check the [demo](http://thednp.github.io/kute.js/).
|
||||
|
||||
|
||||
# Components
|
||||
KUTE.js includes 18 components, but not all of them are bundled with the default distribution package:
|
||||
|
||||
* [backgroundPosition](http://thednp.github.io/kute.js/backgroundPosition.html) - enables the animation for the `backgroundPosition` CSS property
|
||||
* [borderRadius](http://thednp.github.io/kute.js/borderRadius.html) - enables the animation for all the **borderRadius** properties
|
||||
* [boxModel](http://thednp.github.io/kute.js/boxModel.html) - enables the animation for the **boxModel** properties like `top` , `left`, `width`, etc
|
||||
* [clipProperty](http://thednp.github.io/kute.js/clipProperty.html) - enables the animation for the `clip` property
|
||||
* [colorProperties](http://thednp.github.io/kute.js/colorProperties.html) - enables the animation for the **color** properties like `color`, `backgroundColor`
|
||||
* [filterEffects](http://thednp.github.io/kute.js/filterEffects.html) - enables the animation for the `filter` property
|
||||
* [htmlAttributes](http://thednp.github.io/kute.js/htmlAttributes.html) - enables the animation for any numeric as well as some color based **HTML Attributes**
|
||||
* [opacityProperty](http://thednp.github.io/kute.js/opacityProperty.html) - enables the animation for the `opacity` property
|
||||
* [scrollProperty](http://thednp.github.io/kute.js/scrollProperty.html) - enables the animation for the window/Element `scrollTop` Object property
|
||||
* [shadowProperties](http://thednp.github.io/kute.js/shadowProperties.html) - enables the animation for the **shadowProperties** properties: `textShadow` & `boxShadow`
|
||||
* [svgCubicMorph](http://thednp.github.io/kute.js/svgCubicMorph.html) - enables the animation for the `d` Presentation Attribute of the `<path>` SVGElement targets; this implements some [Raphael.js](https://dmitrybaranovskiy.github.io/raphael/) functionality
|
||||
* [svgMorph](http://thednp.github.io/kute.js/svgMorph.html) - enables the animation for the `d` Presentation Attribute of the `<path>` SVGElement targets; this component implements some [D3.js](https://github.com/d3/d3) and [flubber](https://github.com/veltman/flubber) functionality
|
||||
* [svgDraw](http://thednp.github.io/kute.js/svgDraw.html) - enables the animation for the `strokeDasharray` and `strokeDashoffset` CSS properties specific to `<path>` SVGElement
|
||||
* [svgTransform](http://thednp.github.io/kute.js/svgTransform.html) - enables the animation for the `transform` presentation attribute
|
||||
* [textProperties](http://thednp.github.io/kute.js/textProperties.html) - enables the animation for numeric `HTMLTextElement` related CSS properties like `fontSize` or `letterSpacing`
|
||||
* [textWrite](http://thednp.github.io/kute.js/textWrite.html) - enables the animation for the content of various strings
|
||||
* [transformFunctions](http://thednp.github.io/kute.js/transformFunctions.html) - enables the animation for the `transform` CSS3 property, the default component bundled with the official build
|
||||
* transformLegacy - enables the animation for the `transform` CSS3 property on legacy browsers IE9+, not included with the official build, but can be used in your custom builds
|
||||
* [transformMatrix](http://thednp.github.io/kute.js/transformMatrix.html) - enables the animation for the `transform` CSS3 property; this component implements `DOMMatrix()` API and is super light
|
||||
|
||||
All above mentioned components have a BASE version which doesn't include value processing, and their purpose is to provide a way to ship your super light version of your application.
|
||||
|
||||
|
||||
# Wiki
|
||||
For a complete developer guide, usage and stuff like npm, visit [the wiki](https://github.com/thednp/kute.js/wiki).
|
||||
|
||||
|
||||
# Browser Support
|
||||
KUTE.js is redeveloped for maximum performance on modern browsers. Some legacy browsers might some help, so give them a small polyfill set with most essential features required by KUTE.js to work, powered by [minifill](https://github.com/thednp/minifill), try it. For broader projects you might want to consider <a href="https://cdn.polyfill.io/v2/docs/">polyfills</a>.
|
||||
|
||||
|
||||
# Special Thanks
|
||||
* [Mike Bostock](https://bost.ocks.org/mike/) for his awesome [D3.js](https://github.com/d3/d3), one of the sources for our reworked [SVGMorph](http://thednp.github.io/kute.js/svgMorph.html) component.
|
||||
* [Noah Veltman](https://github.com/veltman) for his awesome [flubber](https://github.com/veltman/flubber), another one of the sources for the SVGMorph component.
|
||||
* [Andrew Willems](https://stackoverflow.com/users/5218951/andrew-willems) for his awesome [Stackoverflow answer](https://stackoverflow.com/questions/35560989/javascript-how-to-determine-a-svg-path-draw-direction) resulting in the creation of our [SVGCubicMorph](http://thednp.github.io/kute.js/svgCubicMorph.html) component.
|
||||
* [Dmitry Baranovskiy](https://dmitry.baranovskiy.com/) for his awesome [Raphael.js](https://dmitrybaranovskiy.github.io/raphael/), another source for our SVGCubicMorph component.
|
||||
* [@dalisoft](https://github.com/dalisoft) contributed a great deal to the performance and functionality of previous versions of KUTE.js.
|
||||
|
||||
|
||||
# Contributions
|
||||
* [Contributors & Collaborators](https://github.com/thednp/kute.js/graphs/contributors)
|
||||
|
||||
|
||||
# License
|
||||
[MIT License](https://github.com/thednp/kute.js/blob/master/LICENSE)
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 997 B |
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 3 KiB |
2
demo/src/kute.min.js
vendored
4621
dist/kute.esm.js
vendored
2
dist/kute.esm.min.js
vendored
4675
dist/kute.js
vendored
140
dist/polyfill.js
vendored
|
@ -1,140 +0,0 @@
|
|||
/*!
|
||||
* KUTE.js Polyfill v2.1.1-alpha1 (http://thednp.github.io/kute.js)
|
||||
* Copyright 2015-2021 © thednp
|
||||
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
|
||||
*/
|
||||
"use strict";
|
||||
if (!Array.from) {
|
||||
Array.from = (function () {
|
||||
var toStr = Object.prototype.toString;
|
||||
var isCallable = function (fn) {
|
||||
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
|
||||
};
|
||||
var toInteger = function (value) {
|
||||
var number = Number(value);
|
||||
if (isNaN(number)) { return 0; }
|
||||
if (number === 0 || !isFinite(number)) { return number; }
|
||||
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
|
||||
};
|
||||
var maxSafeInteger = Math.pow(2, 53) - 1;
|
||||
var toLength = function (value) {
|
||||
var len = toInteger(value);
|
||||
return Math.min(Math.max(len, 0), maxSafeInteger);
|
||||
};
|
||||
|
||||
return function from(arrayLike/*, mapFn, thisArg */) {
|
||||
var C = this, items = Object(arrayLike);
|
||||
if (arrayLike == null) {
|
||||
throw new TypeError('Array.from requires an array-like object - not null or undefined');
|
||||
}
|
||||
var mapFn = arguments.length > 1 ? arguments[1] : void undefined, T;
|
||||
if (typeof mapFn !== 'undefined') {
|
||||
if (!isCallable(mapFn)) {
|
||||
throw new TypeError('Array.from: when provided, the second argument must be a function');
|
||||
}
|
||||
|
||||
if (arguments.length > 2) {
|
||||
T = arguments[2];
|
||||
}
|
||||
}
|
||||
var len = toLength(items.length);
|
||||
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
|
||||
|
||||
var k = 0;
|
||||
var kValue;
|
||||
while (k < len) {
|
||||
kValue = items[k];
|
||||
if (mapFn) {
|
||||
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
|
||||
} else {
|
||||
A[k] = kValue;
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
A.length = len;
|
||||
return A;
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
// https://github.com/jonathantneal/array-flat-polyfill/blob/master/src/polyfill-flat.js
|
||||
|
||||
if (!Array.prototype.flat) {
|
||||
Object.defineProperty(Array.prototype, 'flat', {
|
||||
configurable: true,
|
||||
value: function flat () {
|
||||
var depth = isNaN(arguments[0]) ? 1 : Number(arguments[0]);
|
||||
|
||||
return depth ? Array.prototype.reduce.call(this, function (acc, cur) {
|
||||
if (Array.isArray(cur)) {
|
||||
acc.push.apply(acc, flat.call(cur, depth - 1));
|
||||
} else {
|
||||
acc.push(cur);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []) : Array.prototype.slice.call(this);
|
||||
},
|
||||
writable: true
|
||||
});
|
||||
}
|
||||
|
||||
if (!Array.prototype.includes) {
|
||||
Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
|
||||
var O = Object(this);
|
||||
var len = parseInt(O.length) || 0;
|
||||
if (len === 0) {
|
||||
return false;
|
||||
}
|
||||
var n = parseInt(arguments[1]) || 0;
|
||||
var k;
|
||||
if (n >= 0) {
|
||||
k = n;
|
||||
} else {
|
||||
k = len + n;
|
||||
if (k < 0) {k = 0;}
|
||||
}
|
||||
var currentElement;
|
||||
while (k < len) {
|
||||
currentElement = O[k];
|
||||
if (searchElement === currentElement ||
|
||||
(searchElement !== searchElement && currentElement !== currentElement)) {
|
||||
return true;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function(search, start) {
|
||||
if (search instanceof RegExp) {
|
||||
throw TypeError('first argument must not be a RegExp');
|
||||
}
|
||||
if (start === undefined) { start = 0; }
|
||||
return this.indexOf(search, start) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
if (!Number.isFinite) {
|
||||
Number.isFinite = function(value) {
|
||||
return typeof value === 'number'
|
||||
&& isFinite(value);
|
||||
};
|
||||
}
|
||||
|
||||
if (!Number.isInteger) {
|
||||
Number.isInteger = function(value) {
|
||||
return typeof value === 'number'
|
||||
&& isFinite(value)
|
||||
&& Math.floor(value) === value;
|
||||
};
|
||||
}
|
||||
|
||||
if (!Number.isNaN) {
|
||||
Number.isNaN = function(value) {
|
||||
return typeof value === 'number'
|
||||
&& value !== value;
|
||||
};
|
||||
}
|
3
dist/polyfill.min.js
vendored
|
@ -1,3 +0,0 @@
|
|||
// KUTE.js Polyfill v2.1.1-alpha1 | 2021 © thednp | MIT-License
|
||||
"use strict";
|
||||
var r,t,e,n;Array.from||(Array.from=(r=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===r.call(t)},e=Math.pow(2,53)-1,n=function(r){var t=function(r){var t=Number(r);return isNaN(t)?0:0!==t&&isFinite(t)?(t>0?1:-1)*Math.floor(Math.abs(t)):t}(r);return Math.min(Math.max(t,0),e)},function(r){var e=this,i=Object(r);if(null==r)throw new TypeError("Array.from requires an array-like object - not null or undefined");var o,a=arguments.length>1?arguments[1]:void 0;if(void 0!==a){if(!t(a))throw new TypeError("Array.from: when provided, the second argument must be a function");arguments.length>2&&(o=arguments[2])}for(var u,f=n(i.length),p=t(e)?Object(new e(f)):new Array(f),c=0;c<f;)u=i[c],p[c]=a?void 0===o?a(u,c):a.call(o,u,c):u,c+=1;return p.length=f,p})),Array.prototype.flat||Object.defineProperty(Array.prototype,"flat",{configurable:!0,value:function r(){var t=isNaN(arguments[0])?1:Number(arguments[0]);return t?Array.prototype.reduce.call(this,(function(e,n){return Array.isArray(n)?e.push.apply(e,r.call(n,t-1)):e.push(n),e}),[]):Array.prototype.slice.call(this)},writable:!0}),Array.prototype.includes||(Array.prototype.includes=function(r){var t=Object(this),e=parseInt(t.length)||0;if(0===e)return!1;var n,i,o=parseInt(arguments[1])||0;for(o>=0?n=o:(n=e+o)<0&&(n=0);n<e;){if(r===(i=t[n])||r!=r&&i!=i)return!0;n++}return!1}),String.prototype.includes||(String.prototype.includes=function(r,t){if(r instanceof RegExp)throw TypeError("first argument must not be a RegExp");return void 0===t&&(t=0),-1!==this.indexOf(r,t)}),Number.isFinite||(Number.isFinite=function(r){return"number"==typeof r&&isFinite(r)}),Number.isInteger||(Number.isInteger=function(r){return"number"==typeof r&&isFinite(r)&&Math.floor(r)===r}),Number.isNaN||(Number.isNaN=function(r){return"number"==typeof r&&r!=r});
|
80
package.json
|
@ -1,80 +0,0 @@
|
|||
{
|
||||
"name": "kute.js",
|
||||
"version": "2.2.3",
|
||||
"description": "JavaScript animation engine",
|
||||
"main": "dist/kute.min.js",
|
||||
"module": "dist/kute.esm.js",
|
||||
"jsnext": "src/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"types",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"help": "rollup --help",
|
||||
"build1": "npm-run-all --parallel copy-build build-*",
|
||||
"build": "npm run lint:js && npm-run-all --parallel copy-build build-*",
|
||||
"custom": "rollup -c --environment",
|
||||
"fix:js": "eslint src/ --config .eslintrc --fix",
|
||||
"lint:js": "eslint src/ --config .eslintrc",
|
||||
"copy-build": "rollup --environment OUTPUTFILE:demo/src/kute.min.js,DIST:standard,MIN:true,FORMAT:umd -c",
|
||||
"build-standard": "rollup --environment DIST:standard,MIN:false,FORMAT:umd -c",
|
||||
"build:ts": "tsc -d",
|
||||
"build-standard-min": "rollup --environment DIST:standard,MIN:true,FORMAT:umd -c",
|
||||
"build-standard-esm": "rollup --environment DIST:standard,MIN:false,FORMAT:esm -c",
|
||||
"build-standard-esm-min": "rollup --environment DIST:standard,MIN:true,FORMAT:esm -c",
|
||||
"build-base": "rollup --environment OUTPUTFILE:demo/src/kute-base.js,DIST:base,MIN:false,FORMAT:umd -c",
|
||||
"build-base-min": "rollup --environment OUTPUTFILE:demo/src/kute-base.min.js,DIST:base,MIN:true,FORMAT:umd -c",
|
||||
"build-extra": "rollup --environment OUTPUTFILE:demo/src/kute-extra.js,DIST:extra,MIN:false,FORMAT:umd -c",
|
||||
"build-extra-min": "rollup --environment OUTPUTFILE:demo/src/kute-extra.min.js,DIST:extra,MIN:true,FORMAT:umd -c",
|
||||
"polyfill": "npm-run-all --parallel polyfill-unminified polyfill-minified copy-polyfill copy-polyfill-legacy",
|
||||
"copy-polyfill-legacy": "rollup --environment INPUTFILE:src/util/polyfill-legacy.js,OUTPUTFILE:demo/src/polyfill-legacy.min.js,MIN:true -c rollup.polyfill.js",
|
||||
"copy-polyfill": "rollup --environment OUTPUTFILE:demo/src/polyfill.min.js,MIN:true -c rollup.polyfill.js",
|
||||
"polyfill-unminified": "rollup --environment MIN:false -c rollup.polyfill.js",
|
||||
"polyfill-minified": "rollup --environment MIN:true -c rollup.polyfill.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/thednp/kute.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"kute.js",
|
||||
"svg morph",
|
||||
"svg transform",
|
||||
"css3 transform",
|
||||
"matrix transform",
|
||||
"tweening engine",
|
||||
"animation engine",
|
||||
"javascript animation engine",
|
||||
"javascript animation",
|
||||
"animation",
|
||||
"native javascript"
|
||||
],
|
||||
"author": "thednp",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/thednp/kute.js/issues"
|
||||
},
|
||||
"homepage": "http://thednp.github.io/kute.js",
|
||||
"dependencies": {
|
||||
"cubic-bezier-easing": "^1.0.18",
|
||||
"minifill": "^0.0.16",
|
||||
"shorter-js": "^0.2.6",
|
||||
"svg-path-commander": "0.1.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"eslint": "^7.22.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-vue": "^7.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rollup": "^2.38.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.5.2"
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
'use strict'
|
||||
import buble from '@rollup/plugin-buble'
|
||||
import {terser} from 'rollup-plugin-terser'
|
||||
import node from '@rollup/plugin-node-resolve'
|
||||
import json from '@rollup/plugin-json'
|
||||
import * as pkg from "./package.json"
|
||||
|
||||
|
||||
let INPUTFILE = process.env.INPUTFILE
|
||||
let OUTPUTFILE = process.env.OUTPUTFILE
|
||||
const DIST = process.env.DIST // base|standard|extra
|
||||
const NAME = DIST.charAt(0).toUpperCase() + DIST.slice(1); // Base|Standard|Extra
|
||||
const MIN = process.env.MIN === 'true' // true/false|unset
|
||||
const FORMAT = process.env.FORMAT // umd|iife|esm
|
||||
|
||||
const year = (new Date).getFullYear()
|
||||
const banner =
|
||||
`/*!
|
||||
* KUTE.js ${NAME} v${pkg.version} (${pkg.homepage})
|
||||
* Copyright 2015-${year} © ${pkg.author}
|
||||
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
|
||||
*/`
|
||||
const miniBanner = `// KUTE.js ${NAME} v${pkg.version} | ${pkg.author} © ${year} | ${pkg.license}-License`
|
||||
|
||||
INPUTFILE = INPUTFILE ? INPUTFILE : (DIST === 'standard' ? 'src/index.js' : 'src/index-'+DIST+'.js')
|
||||
OUTPUTFILE = OUTPUTFILE ? OUTPUTFILE : ('dist/kute'+(DIST!=='standard'?'-'+DIST:'')+(FORMAT==='esm'?'.esm':'')+(MIN?'.min':'')+'.js')
|
||||
|
||||
const OUTPUT = {
|
||||
file: OUTPUTFILE,
|
||||
format: FORMAT, // or iife
|
||||
}
|
||||
|
||||
const PLUGINS = [
|
||||
node({mainFields: ['jsnext','module'], dedupe: ['svg-path-commander']}) ,
|
||||
json(),
|
||||
]
|
||||
|
||||
if (FORMAT!=='esm'){
|
||||
PLUGINS.push(buble({objectAssign: 'Object.assign'}));
|
||||
}
|
||||
|
||||
if (MIN){
|
||||
PLUGINS.push(terser({output: {preamble: miniBanner}}));
|
||||
} else {
|
||||
OUTPUT.banner = banner;
|
||||
}
|
||||
|
||||
if (FORMAT!=='esm') {
|
||||
OUTPUT.name = 'KUTE';
|
||||
}
|
||||
|
||||
export default [
|
||||
{
|
||||
input: INPUTFILE,
|
||||
output: OUTPUT,
|
||||
plugins: PLUGINS
|
||||
}
|
||||
]
|
|
@ -1,54 +0,0 @@
|
|||
'use strict'
|
||||
import buble from '@rollup/plugin-buble'
|
||||
import node from '@rollup/plugin-node-resolve'
|
||||
import json from '@rollup/plugin-json'
|
||||
import {terser} from 'rollup-plugin-terser'
|
||||
import * as pkg from "./package.json";
|
||||
|
||||
// set headers
|
||||
const year = (new Date).getFullYear()
|
||||
const banner = `/*!
|
||||
* KUTE.js Polyfill v${pkg.version} (${pkg.homepage})
|
||||
* Copyright 2015-${year} © ${pkg.author}
|
||||
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
|
||||
*/
|
||||
"use strict";`
|
||||
|
||||
const miniBanner = `// KUTE.js Polyfill v${pkg.version} | ${year} © ${pkg.author} | ${pkg.license}-License
|
||||
"use strict";`
|
||||
|
||||
// set config
|
||||
const MIN = process.env.MIN === 'true' // true/false|unset
|
||||
const FORMAT = 'esm' // umd|iife|esm|cjs
|
||||
|
||||
const INPUTFILE = process.env.INPUTFILE ? process.env.INPUTFILE : 'src/util/polyfill.js'
|
||||
const OUTPUTFILE = process.env.OUTPUTFILE ? process.env.OUTPUTFILE : 'dist/polyfill'+(MIN?'.min':'')+'.js'
|
||||
|
||||
const OUTPUT = {
|
||||
file: OUTPUTFILE,
|
||||
format: FORMAT, // or iife
|
||||
}
|
||||
|
||||
const PLUGINS = [
|
||||
node(),
|
||||
json(),
|
||||
buble(),
|
||||
]
|
||||
|
||||
if (MIN){
|
||||
PLUGINS.push(terser({output: {preamble: miniBanner}}));
|
||||
} else {
|
||||
OUTPUT.banner = banner;
|
||||
}
|
||||
|
||||
// if (FORMAT!=='esm') {
|
||||
// OUTPUT.name = 'BSN';
|
||||
// }
|
||||
|
||||
export default [
|
||||
{
|
||||
input: INPUTFILE,
|
||||
output: OUTPUT,
|
||||
plugins: PLUGINS
|
||||
}
|
||||
]
|
|
@ -1,137 +0,0 @@
|
|||
import supportedProperties from '../objects/supportedProperties';
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import defaultOptions from '../objects/defaultOptions';
|
||||
import prepareProperty from '../objects/prepareProperty';
|
||||
import prepareStart from '../objects/prepareStart';
|
||||
import onStart from '../objects/onStart';
|
||||
import onComplete from '../objects/onComplete';
|
||||
import crossCheck from '../objects/crossCheck';
|
||||
import linkProperty from '../objects/linkProperty';
|
||||
import Util from '../objects/util';
|
||||
import Interpolate from '../objects/interpolate';
|
||||
|
||||
/**
|
||||
* Animation Class
|
||||
*
|
||||
* Registers components by populating KUTE.js objects and makes sure
|
||||
* no duplicate component / property is allowed.
|
||||
*/
|
||||
export default class Animation {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {KUTE.fullComponent} Component
|
||||
*/
|
||||
constructor(Component) {
|
||||
try {
|
||||
if (Component.component in supportedProperties) {
|
||||
throw Error(`KUTE - ${Component.component} already registered`);
|
||||
} else if (Component.property in defaultValues) {
|
||||
throw Error(`KUTE - ${Component.property} already registered`);
|
||||
}
|
||||
} catch (e) {
|
||||
throw Error(e);
|
||||
}
|
||||
|
||||
const propertyInfo = this;
|
||||
const ComponentName = Component.component;
|
||||
// const Objects = { defaultValues, defaultOptions, Interpolate, linkProperty, Util }
|
||||
const Functions = {
|
||||
prepareProperty, prepareStart, onStart, onComplete, crossCheck,
|
||||
};
|
||||
const Category = Component.category;
|
||||
const Property = Component.property;
|
||||
const Length = (Component.properties && Component.properties.length)
|
||||
|| (Component.subProperties && Component.subProperties.length);
|
||||
|
||||
// single property
|
||||
// {property,defaultvalue,defaultOptions,Interpolate,functions}
|
||||
|
||||
// category colors, boxModel, borderRadius
|
||||
// {category,properties,defaultvalues,defaultOptions,Interpolate,functions}
|
||||
|
||||
// property with multiple sub properties. Eg transform, filter
|
||||
// {property,subProperties,defaultvalues,defaultOptions,Interpolate,functions}
|
||||
|
||||
// property with multiple sub properties. Eg htmlAttributes
|
||||
// {category,subProperties,defaultvalues,defaultOptions,Interpolate,functions}
|
||||
|
||||
// set supported category/property
|
||||
supportedProperties[ComponentName] = Component.properties
|
||||
|| Component.subProperties || Component.property;
|
||||
|
||||
// set defaultValues
|
||||
if ('defaultValue' in Component) { // value 0 will invalidate
|
||||
defaultValues[Property] = Component.defaultValue;
|
||||
|
||||
// minimal info
|
||||
propertyInfo.supports = `${Property} property`;
|
||||
} else if (Component.defaultValues) {
|
||||
Object.keys(Component.defaultValues).forEach((dv) => {
|
||||
defaultValues[dv] = Component.defaultValues[dv];
|
||||
});
|
||||
|
||||
// minimal info
|
||||
propertyInfo.supports = `${Length || Property} ${Property || Category} properties`;
|
||||
}
|
||||
|
||||
// set additional options
|
||||
if (Component.defaultOptions) {
|
||||
// Object.keys(Component.defaultOptions).forEach((op) => {
|
||||
// defaultOptions[op] = Component.defaultOptions[op];
|
||||
// });
|
||||
Object.assign(defaultOptions, Component.defaultOptions);
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
Object.keys(Functions).forEach((fn) => {
|
||||
if (fn in Component.functions) {
|
||||
if (typeof (Component.functions[fn]) === 'function') {
|
||||
// if (!Functions[fn][ Category||Property ]) {
|
||||
// Functions[fn][ Category||Property ] = Component.functions[fn];
|
||||
// }
|
||||
if (!Functions[fn][ComponentName]) Functions[fn][ComponentName] = {};
|
||||
if (!Functions[fn][ComponentName][Category || Property]) {
|
||||
Functions[fn][ComponentName][Category || Property] = Component.functions[fn];
|
||||
}
|
||||
} else {
|
||||
Object.keys(Component.functions[fn]).forEach((ofn) => {
|
||||
// !Functions[fn][ofn] && (Functions[fn][ofn] = Component.functions[fn][ofn])
|
||||
if (!Functions[fn][ComponentName]) Functions[fn][ComponentName] = {};
|
||||
if (!Functions[fn][ComponentName][ofn]) {
|
||||
Functions[fn][ComponentName][ofn] = Component.functions[fn][ofn];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// set component interpolation functions
|
||||
if (Component.Interpolate) {
|
||||
Object.keys(Component.Interpolate).forEach((fni) => {
|
||||
const compIntObj = Component.Interpolate[fni];
|
||||
if (typeof (compIntObj) === 'function' && !Interpolate[fni]) {
|
||||
Interpolate[fni] = compIntObj;
|
||||
} else {
|
||||
Object.keys(compIntObj).forEach((sfn) => {
|
||||
if (typeof (compIntObj[sfn]) === 'function' && !Interpolate[fni]) {
|
||||
Interpolate[fni] = compIntObj[sfn];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
linkProperty[ComponentName] = Component.Interpolate;
|
||||
}
|
||||
|
||||
// set component util
|
||||
if (Component.Util) {
|
||||
Object.keys(Component.Util).forEach((fnu) => {
|
||||
if (!Util[fnu]) Util[fnu] = Component.Util[fnu];
|
||||
});
|
||||
}
|
||||
|
||||
return propertyInfo;
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
import supportedProperties from '../objects/supportedProperties';
|
||||
import defaultOptions from '../objects/defaultOptions';
|
||||
import onStart from '../objects/onStart';
|
||||
import onComplete from '../objects/onComplete';
|
||||
import linkProperty from '../objects/linkProperty';
|
||||
import Util from '../objects/util';
|
||||
import Interpolate from '../objects/interpolate';
|
||||
|
||||
/**
|
||||
* Animation Base Class
|
||||
*
|
||||
* Registers components by populating KUTE.js objects and makes sure
|
||||
* no duplicate component / property is allowed.
|
||||
*
|
||||
* This class only registers the minimal amount of component information
|
||||
* required to enable components animation, which means value processing
|
||||
* as well as `to()` and `allTo()` methods are not supported.
|
||||
*/
|
||||
export default class AnimationBase {
|
||||
/**
|
||||
* @class
|
||||
* @param {KUTE.baseComponent} Component
|
||||
*/
|
||||
constructor(Component) {
|
||||
const ComponentName = Component.component;
|
||||
// const Objects = { defaultValues, defaultOptions, Interpolate, linkProperty }
|
||||
const Functions = { onStart, onComplete };
|
||||
const Category = Component.category;
|
||||
const Property = Component.property;
|
||||
// ESLint
|
||||
this._ = 0;
|
||||
|
||||
// set supported category/property
|
||||
supportedProperties[ComponentName] = Component.properties
|
||||
|| Component.subProperties || Component.property;
|
||||
|
||||
// set additional options
|
||||
if (Component.defaultOptions) {
|
||||
// Object.keys(Component.defaultOptions).forEach((op) => {
|
||||
// defaultOptions[op] = Component.defaultOptions[op];
|
||||
// });
|
||||
Object.assign(defaultOptions, Component.defaultOptions);
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
Object.keys(Functions).forEach((fn) => {
|
||||
if (fn in Component.functions) {
|
||||
if (typeof (Component.functions[fn]) === 'function') {
|
||||
// if (!Functions[fn][ Category||Property ]) {
|
||||
// Functions[fn][ Category||Property ] = Component.functions[fn];
|
||||
// }
|
||||
if (!Functions[fn][ComponentName]) Functions[fn][ComponentName] = {};
|
||||
if (!Functions[fn][ComponentName][Category || Property]) {
|
||||
Functions[fn][ComponentName][Category || Property] = Component.functions[fn];
|
||||
}
|
||||
} else {
|
||||
Object.keys(Component.functions[fn]).forEach((ofn) => {
|
||||
// if (!Functions[fn][ofn]) Functions[fn][ofn] = Component.functions[fn][ofn];
|
||||
if (!Functions[fn][ComponentName]) Functions[fn][ComponentName] = {};
|
||||
if (!Functions[fn][ComponentName][ofn]) {
|
||||
Functions[fn][ComponentName][ofn] = Component.functions[fn][ofn];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// set interpolate
|
||||
if (Component.Interpolate) {
|
||||
Object.keys(Component.Interpolate).forEach((fni) => {
|
||||
const compIntObj = Component.Interpolate[fni];
|
||||
if (typeof (compIntObj) === 'function' && !Interpolate[fni]) {
|
||||
Interpolate[fni] = compIntObj;
|
||||
} else {
|
||||
Object.keys(compIntObj).forEach((sfn) => {
|
||||
if (typeof (compIntObj[sfn]) === 'function' && !Interpolate[fni]) {
|
||||
Interpolate[fni] = compIntObj[sfn];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
linkProperty[ComponentName] = Component.Interpolate;
|
||||
}
|
||||
|
||||
// set component util
|
||||
if (Component.Util) {
|
||||
Object.keys(Component.Util).forEach((fnu) => {
|
||||
if (!Util[fnu]) Util[fnu] = Component.Util[fnu];
|
||||
});
|
||||
}
|
||||
|
||||
return { name: ComponentName };
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
import prepareProperty from '../objects/prepareProperty';
|
||||
import prepareStart from '../objects/prepareStart';
|
||||
import onStart from '../objects/onStart';
|
||||
import onComplete from '../objects/onComplete';
|
||||
import crossCheck from '../objects/crossCheck';
|
||||
import Interpolate from '../objects/interpolate';
|
||||
|
||||
import Animation from './animation';
|
||||
|
||||
/**
|
||||
* Animation Development Class
|
||||
*
|
||||
* Registers components by populating KUTE.js objects and makes sure
|
||||
* no duplicate component / property is allowed.
|
||||
*
|
||||
* In addition to the default class, this one provides more component
|
||||
* information to help you with custom component development.
|
||||
*/
|
||||
export default class AnimationDevelopment extends Animation {
|
||||
/**
|
||||
*
|
||||
* @param {KUTE.fullComponent} args
|
||||
*/
|
||||
constructor(Component) {
|
||||
super(Component);
|
||||
|
||||
const propertyInfo = this;
|
||||
// const Objects = { defaultValues, defaultOptions, Interpolate, linkProperty, Util }
|
||||
const Functions = {
|
||||
prepareProperty, prepareStart, onStart, onComplete, crossCheck,
|
||||
};
|
||||
const Category = Component.category;
|
||||
const Property = Component.property;
|
||||
const Length = (Component.properties && Component.properties.length)
|
||||
|| (Component.subProperties && Component.subProperties.length);
|
||||
|
||||
// set defaultValues
|
||||
if ('defaultValue' in Component) { // value 0 will invalidate
|
||||
propertyInfo.supports = `${Property} property`;
|
||||
propertyInfo.defaultValue = `${(`${Component.defaultValue}`).length ? 'YES' : 'not set or incorrect'}`;
|
||||
} else if (Component.defaultValues) {
|
||||
propertyInfo.supports = `${Length || Property} ${Property || Category} properties`;
|
||||
propertyInfo.defaultValues = Object.keys(Component.defaultValues).length === Length ? 'YES' : 'Not set or incomplete';
|
||||
}
|
||||
|
||||
// set additional options
|
||||
if (Component.defaultOptions) {
|
||||
propertyInfo.extends = [];
|
||||
|
||||
Object.keys(Component.defaultOptions).forEach((op) => {
|
||||
propertyInfo.extends.push(op);
|
||||
});
|
||||
|
||||
if (propertyInfo.extends.length) {
|
||||
propertyInfo.extends = `with <${propertyInfo.extends.join(', ')}> new option(s)`;
|
||||
} else {
|
||||
delete propertyInfo.extends;
|
||||
}
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
propertyInfo.interface = [];
|
||||
propertyInfo.render = [];
|
||||
propertyInfo.warning = [];
|
||||
|
||||
Object.keys(Functions).forEach((fnf) => {
|
||||
if (fnf in Component.functions) {
|
||||
if (fnf === 'prepareProperty') propertyInfo.interface.push('fromTo()');
|
||||
if (fnf === 'prepareStart') propertyInfo.interface.push('to()');
|
||||
if (fnf === 'onStart') propertyInfo.render = 'can render update';
|
||||
} else {
|
||||
if (fnf === 'prepareProperty') propertyInfo.warning.push('fromTo()');
|
||||
if (fnf === 'prepareStart') propertyInfo.warning.push('to()');
|
||||
if (fnf === 'onStart') propertyInfo.render = 'no function to render update';
|
||||
}
|
||||
});
|
||||
|
||||
if (propertyInfo.interface.length) {
|
||||
propertyInfo.interface = `${Category || Property} can use [${propertyInfo.interface.join(', ')}] method(s)`;
|
||||
} else {
|
||||
delete propertyInfo.uses;
|
||||
}
|
||||
|
||||
if (propertyInfo.warning.length) {
|
||||
propertyInfo.warning = `${Category || Property} can't use [${propertyInfo.warning.join(', ')}] method(s) because values aren't processed`;
|
||||
} else {
|
||||
delete propertyInfo.warning;
|
||||
}
|
||||
}
|
||||
|
||||
// register Interpolation functions
|
||||
if (Component.Interpolate) {
|
||||
propertyInfo.uses = [];
|
||||
propertyInfo.adds = [];
|
||||
|
||||
Object.keys(Component.Interpolate).forEach((fni) => {
|
||||
const compIntObj = Component.Interpolate[fni];
|
||||
// register new Interpolation functions
|
||||
if (typeof (compIntObj) === 'function') {
|
||||
if (!Interpolate[fni]) {
|
||||
propertyInfo.adds.push(`${fni}`);
|
||||
}
|
||||
propertyInfo.uses.push(`${fni}`);
|
||||
} else {
|
||||
Object.keys(compIntObj).forEach((sfn) => {
|
||||
if (typeof (compIntObj[sfn]) === 'function' && !Interpolate[fni]) {
|
||||
propertyInfo.adds.push(`${sfn}`);
|
||||
}
|
||||
propertyInfo.uses.push(`${sfn}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (propertyInfo.uses.length) {
|
||||
propertyInfo.uses = `[${propertyInfo.uses.join(', ')}] interpolation function(s)`;
|
||||
} else {
|
||||
delete propertyInfo.uses;
|
||||
}
|
||||
|
||||
if (propertyInfo.adds.length) {
|
||||
propertyInfo.adds = `new [${propertyInfo.adds.join(', ')}] interpolation function(s)`;
|
||||
} else {
|
||||
delete propertyInfo.adds;
|
||||
}
|
||||
} else {
|
||||
propertyInfo.critical = `For ${Property || Category} no interpolation function[s] is set`;
|
||||
}
|
||||
|
||||
// set component util
|
||||
if (Component.Util) {
|
||||
propertyInfo.hasUtil = Object.keys(Component.Util).join(',');
|
||||
}
|
||||
|
||||
return propertyInfo;
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import { onStartBgPos } from './backgroundPositionBase';
|
||||
|
||||
// Component Functions
|
||||
|
||||
/**
|
||||
* Returns the property computed style.
|
||||
* @param {string} prop the property
|
||||
* @returns {string} the property computed style
|
||||
*/
|
||||
function getBgPos(prop/* , value */) {
|
||||
return getStyleForProperty(this.element, prop) || defaultValues[prop];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number[]} the property tween object
|
||||
*/
|
||||
function prepareBgPos(/* prop, */_, value) {
|
||||
if (value instanceof Array) {
|
||||
const x = trueDimension(value[0]).v;
|
||||
const y = trueDimension(value[1]).v;
|
||||
return [!Number.isNaN(x * 1) ? x : 50, !Number.isNaN(y * 1) ? y : 50];
|
||||
}
|
||||
|
||||
let posxy = value.replace(/top|left/g, 0)
|
||||
.replace(/right|bottom/g, 100)
|
||||
.replace(/center|middle/g, 50);
|
||||
|
||||
posxy = posxy.split(/(,|\s)/g);
|
||||
posxy = posxy.length === 2 ? posxy : [posxy[0], 50];
|
||||
return [trueDimension(posxy[0]).v, trueDimension(posxy[1]).v];
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const bgPositionFunctions = {
|
||||
prepareStart: getBgPos,
|
||||
prepareProperty: prepareBgPos,
|
||||
onStart: onStartBgPos,
|
||||
};
|
||||
|
||||
// Component Full Object
|
||||
const BackgroundPosition = {
|
||||
component: 'backgroundPositionProp',
|
||||
property: 'backgroundPosition',
|
||||
defaultValue: [50, 50],
|
||||
Interpolate: { numbers },
|
||||
functions: bgPositionFunctions,
|
||||
Util: { trueDimension },
|
||||
};
|
||||
|
||||
export default BackgroundPosition;
|
|
@ -1,26 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} prop the property name
|
||||
*/
|
||||
export function onStartBgPos(prop) {
|
||||
if (this.valuesEnd[prop] && !KEC[prop]) {
|
||||
KEC[prop] = (elem, a, b, v) => {
|
||||
/* eslint-disable -- no-bitwise & no-param-reassign impossible to satisfy */
|
||||
elem.style[prop] = `${(numbers(a[0], b[0], v) * 100 >> 0) / 100}% ${((numbers(a[1], b[1], v) * 100 >> 0) / 100)}%`;
|
||||
/* eslint-enable -- no-bitwise & no-param-reassign impossible to satisfy */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base Object
|
||||
const BackgroundPositionBase = {
|
||||
component: 'baseBackgroundPosition',
|
||||
property: 'backgroundPosition',
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartBgPos },
|
||||
};
|
||||
export default BackgroundPositionBase;
|
|
@ -1,58 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import units from '../interpolation/units';
|
||||
import { radiusOnStartFn } from './borderRadiusBase';
|
||||
|
||||
// Component Properties
|
||||
const radiusProps = [
|
||||
'borderRadius',
|
||||
'borderTopLeftRadius', 'borderTopRightRadius',
|
||||
'borderBottomLeftRadius', 'borderBottomRightRadius'];
|
||||
|
||||
const radiusValues = {};
|
||||
radiusProps.forEach((x) => { radiusValues[x] = 0; });
|
||||
|
||||
// Component Functions
|
||||
const radiusOnStart = {};
|
||||
radiusProps.forEach((tweenProp) => {
|
||||
radiusOnStart[tweenProp] = radiusOnStartFn;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} the property computed style
|
||||
*/
|
||||
export function getRadius(tweenProp) {
|
||||
return getStyleForProperty(this.element, tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} value the property value
|
||||
* @returns {{v: number, u: string}} the property tween object
|
||||
*/
|
||||
export function prepareRadius(/* tweenProp, */_, value) {
|
||||
return trueDimension(value);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
export const radiusFunctions = {
|
||||
prepareStart: getRadius,
|
||||
prepareProperty: prepareRadius,
|
||||
onStart: radiusOnStart,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const BorderRadius = {
|
||||
component: 'borderRadiusProperties',
|
||||
category: 'borderRadius',
|
||||
properties: radiusProps,
|
||||
defaultValues: radiusValues,
|
||||
Interpolate: { units },
|
||||
functions: radiusFunctions,
|
||||
Util: { trueDimension },
|
||||
};
|
||||
|
||||
export default BorderRadius;
|
|
@ -1,43 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import units from '../interpolation/units';
|
||||
|
||||
/* borderRadius = {
|
||||
category: 'borderRadius',
|
||||
properties : [..],
|
||||
defaultValues: {..},
|
||||
interpolation: {units}
|
||||
} */
|
||||
|
||||
// Component Properties
|
||||
const radiusProps = [
|
||||
'borderRadius',
|
||||
'borderTopLeftRadius', 'borderTopRightRadius',
|
||||
'borderBottomLeftRadius', 'borderBottomRightRadius',
|
||||
];
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function radiusOnStartFn(tweenProp) {
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// eslint-disable-next-line no-param-reassign -- impossible to satisfy
|
||||
elem.style[tweenProp] = units(a.v, b.v, b.u, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
const radiusOnStart = {};
|
||||
radiusProps.forEach((tweenProp) => {
|
||||
radiusOnStart[tweenProp] = radiusOnStartFn;
|
||||
});
|
||||
|
||||
// Base Component
|
||||
const BorderRadiusBase = {
|
||||
component: 'baseBorderRadius',
|
||||
category: 'borderRadius',
|
||||
Interpolate: { units },
|
||||
functions: { onStart: radiusOnStart },
|
||||
};
|
||||
export default BorderRadiusBase;
|
|
@ -1,57 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import { boxModelOnStart } from './boxModelBase';
|
||||
|
||||
// Component Properties
|
||||
const boxModelProperties = ['top', 'left', 'width', 'height', 'right', 'bottom', 'minWidth', 'minHeight', 'maxWidth', 'maxHeight',
|
||||
'padding', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight',
|
||||
'margin', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight',
|
||||
'borderWidth', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'outlineWidth'];
|
||||
|
||||
const boxModelValues = {};
|
||||
boxModelProperties.forEach((x) => { boxModelValues[x] = 0; });
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
function getBoxModel(tweenProp) {
|
||||
return getStyleForProperty(this.element, tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number} the property tween object
|
||||
*/
|
||||
function prepareBoxModel(tweenProp, value) {
|
||||
const boxValue = trueDimension(value); const
|
||||
offsetProp = tweenProp === 'height' ? 'offsetHeight' : 'offsetWidth';
|
||||
return boxValue.u === '%' ? (boxValue.v * this.element[offsetProp]) / 100 : boxValue.v;
|
||||
}
|
||||
const boxPropsOnStart = {};
|
||||
boxModelProperties.forEach((x) => { boxPropsOnStart[x] = boxModelOnStart; });
|
||||
|
||||
// All Component Functions
|
||||
const boxModelFunctions = {
|
||||
prepareStart: getBoxModel,
|
||||
prepareProperty: prepareBoxModel,
|
||||
onStart: boxPropsOnStart,
|
||||
};
|
||||
|
||||
// Component Full Component
|
||||
const BoxModel = {
|
||||
component: 'boxModelProperties',
|
||||
category: 'boxModel',
|
||||
properties: boxModelProperties,
|
||||
defaultValues: boxModelValues,
|
||||
Interpolate: { numbers },
|
||||
functions: boxModelFunctions,
|
||||
};
|
||||
|
||||
export default BoxModel;
|
|
@ -1,37 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the update function for the property.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function boxModelOnStart(tweenProp) {
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable no-param-reassign -- impossible to satisfy */
|
||||
/* eslint-disable no-bitwise -- impossible to satisfy */
|
||||
elem.style[tweenProp] = `${v > 0.99 || v < 0.01
|
||||
? ((numbers(a, b, v) * 10) >> 0) / 10
|
||||
: (numbers(a, b, v)) >> 0}px`;
|
||||
/* eslint-enable no-bitwise */
|
||||
/* eslint-enable no-param-reassign */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base Props
|
||||
const baseBoxProps = ['top', 'left', 'width', 'height'];
|
||||
const baseBoxOnStart = {};
|
||||
baseBoxProps.forEach((x) => { baseBoxOnStart[x] = boxModelOnStart; });
|
||||
|
||||
// Component Base
|
||||
const BoxModelBase = {
|
||||
component: 'baseBoxModel',
|
||||
category: 'boxModel',
|
||||
properties: baseBoxProps,
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: baseBoxOnStart },
|
||||
};
|
||||
|
||||
export default BoxModelBase;
|
|
@ -1,56 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import { boxModelOnStart } from './boxModelBase';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
function getBoxModel(tweenProp) {
|
||||
return getStyleForProperty(this.element, tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} value the property name
|
||||
* @returns {number} the property tween object
|
||||
*/
|
||||
function prepareBoxModel(tweenProp, value) {
|
||||
const boxValue = trueDimension(value);
|
||||
const offsetProp = tweenProp === 'height' ? 'offsetHeight' : 'offsetWidth';
|
||||
return boxValue.u === '%' ? (boxValue.v * this.element[offsetProp]) / 100 : boxValue.v;
|
||||
}
|
||||
|
||||
// Component Base Props
|
||||
const essentialBoxProps = ['top', 'left', 'width', 'height'];
|
||||
const essentialBoxPropsValues = {
|
||||
top: 0, left: 0, width: 0, height: 0,
|
||||
};
|
||||
|
||||
const essentialBoxOnStart = {};
|
||||
essentialBoxProps.forEach((x) => { essentialBoxOnStart[x] = boxModelOnStart; });
|
||||
|
||||
// All Component Functions
|
||||
const essentialBoxModelFunctions = {
|
||||
prepareStart: getBoxModel,
|
||||
prepareProperty: prepareBoxModel,
|
||||
onStart: essentialBoxOnStart,
|
||||
};
|
||||
|
||||
// Component Essential
|
||||
const BoxModelEssential = {
|
||||
component: 'essentialBoxModel',
|
||||
category: 'boxModel',
|
||||
properties: essentialBoxProps,
|
||||
defaultValues: essentialBoxPropsValues,
|
||||
Interpolate: { numbers },
|
||||
functions: essentialBoxModelFunctions,
|
||||
Util: { trueDimension },
|
||||
};
|
||||
|
||||
export default BoxModelEssential;
|
|
@ -1,52 +0,0 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import { onStartClip } from './clipPropertyBase';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string | number[]} computed style for property
|
||||
*/
|
||||
function getClip(tweenProp/* , value */) {
|
||||
const { element } = this;
|
||||
const currentClip = getStyleForProperty(element, tweenProp);
|
||||
const width = getStyleForProperty(element, 'width');
|
||||
const height = getStyleForProperty(element, 'height');
|
||||
return !/rect/.test(currentClip) ? [0, width, height, 0] : currentClip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number[]} the property tween object
|
||||
*/
|
||||
function prepareClip(/* tweenProp, */_, value) {
|
||||
if (value instanceof Array) {
|
||||
return value.map((x) => trueDimension(x));
|
||||
}
|
||||
let clipValue = value.replace(/rect|\(|\)/g, '');
|
||||
clipValue = /,/g.test(clipValue) ? clipValue.split(',') : clipValue.split(/\s/);
|
||||
return clipValue.map((x) => trueDimension(x));
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const clipFunctions = {
|
||||
prepareStart: getClip,
|
||||
prepareProperty: prepareClip,
|
||||
onStart: onStartClip,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const ClipProperty = {
|
||||
component: 'clipProperty',
|
||||
property: 'clip',
|
||||
defaultValue: [0, 0, 0, 0],
|
||||
Interpolate: { numbers },
|
||||
functions: clipFunctions,
|
||||
Util: { trueDimension },
|
||||
};
|
||||
|
||||
export default ClipProperty;
|
|
@ -1,36 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartClip(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp] && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
let h = 0; const
|
||||
cl = [];
|
||||
for (h; h < 4; h += 1) {
|
||||
const c1 = a[h].v;
|
||||
const c2 = b[h].v;
|
||||
const cu = b[h].u || 'px';
|
||||
// eslint-disable-next-line no-bitwise -- impossible to satisfy
|
||||
cl[h] = ((numbers(c1, c2, v) * 100 >> 0) / 100) + cu;
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign -- impossible to satisfy
|
||||
elem.style.clip = `rect(${cl})`;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const ClipPropertyBase = {
|
||||
component: 'baseClip',
|
||||
property: 'clip',
|
||||
// defaultValue: [0,0,0,0],
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartClip },
|
||||
};
|
||||
|
||||
export default ClipPropertyBase;
|
|
@ -1,65 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueColor from '../util/trueColor';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
import { onStartColors } from './colorPropertiesBase';
|
||||
|
||||
// Component Properties
|
||||
// supported formats
|
||||
// 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+)
|
||||
const supportedColors = [
|
||||
'color', 'backgroundColor', 'outlineColor',
|
||||
'borderColor', 'borderTopColor', 'borderRightColor',
|
||||
'borderBottomColor', 'borderLeftColor',
|
||||
];
|
||||
|
||||
const defaultColors = {};
|
||||
supportedColors.forEach((tweenProp) => {
|
||||
defaultColors[tweenProp] = '#000';
|
||||
});
|
||||
|
||||
// Component Functions
|
||||
const colorsOnStart = {};
|
||||
supportedColors.forEach((x) => {
|
||||
colorsOnStart[x] = onStartColors;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} prop the property name
|
||||
* @returns {string} property computed style
|
||||
*/
|
||||
function getColor(prop/* , value */) {
|
||||
return getStyleForProperty(this.element, prop) || defaultValues[prop];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {KUTE.colorObject} the property tween object
|
||||
*/
|
||||
function prepareColor(/* prop, */_, value) {
|
||||
return trueColor(value);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const colorFunctions = {
|
||||
prepareStart: getColor,
|
||||
prepareProperty: prepareColor,
|
||||
onStart: colorsOnStart,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const colorProperties = {
|
||||
component: 'colorProperties',
|
||||
category: 'colors',
|
||||
properties: supportedColors,
|
||||
defaultValues: defaultColors,
|
||||
Interpolate: { numbers, colors },
|
||||
functions: colorFunctions,
|
||||
Util: { trueColor },
|
||||
};
|
||||
|
||||
export default colorProperties;
|
|
@ -1,45 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
|
||||
// Component Interpolation
|
||||
// rgba1, rgba2, progress
|
||||
|
||||
// Component Properties
|
||||
// supported formats
|
||||
// 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+)
|
||||
const supportedColors = [
|
||||
'color', 'backgroundColor', 'outlineColor',
|
||||
'borderColor',
|
||||
'borderTopColor', 'borderRightColor',
|
||||
'borderBottomColor', 'borderLeftColor',
|
||||
];
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartColors(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp] && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
elem.style[tweenProp] = colors(a, b, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const colorsOnStart = {};
|
||||
supportedColors.forEach((x) => { colorsOnStart[x] = onStartColors; });
|
||||
|
||||
// Component Base
|
||||
export const baseColors = {
|
||||
component: 'baseColors',
|
||||
category: 'colors',
|
||||
// properties: supportedColors,
|
||||
// defaultValues: defaultColors,
|
||||
Interpolate: { numbers, colors },
|
||||
functions: { onStart: colorsOnStart },
|
||||
};
|
||||
|
||||
export default baseColors;
|
|
@ -1,95 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import getInlineStyle from '../process/getInlineStyle';
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import trueProperty from '../util/trueProperty';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Const
|
||||
const transformProperty = trueProperty('transform');
|
||||
const supportTransform = transformProperty in document.body.style ? 1 : 0;
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the property current style.
|
||||
*/
|
||||
function getComponentCurrentValue(/* tweenProp, value */) {
|
||||
const currentTransform = getInlineStyle(this.element);
|
||||
const { left } = this.element.style;
|
||||
const { top } = this.element.style;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
if (supportTransform && currentTransform.translate) {
|
||||
[x, y] = currentTransform.translate;
|
||||
} else {
|
||||
x = Number.isFinite(left * 1) ? left : defaultValues.move[0];
|
||||
y = Number.isFinite(top * 1) ? top : defaultValues.move[1];
|
||||
}
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ property name
|
||||
* @param {string} value property value
|
||||
* @returns {number[]} the property tween object
|
||||
*/
|
||||
function prepareComponentValue(/* tweenProp */_, value) {
|
||||
const x = Number.isFinite(value * 1) ? parseInt(value, 10) : parseInt(value[0], 10) || 0;
|
||||
const y = parseInt(value[1], 10) || 0;
|
||||
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the `path` property
|
||||
*/
|
||||
export function onStartComponent(tweenProp/* , value */) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
if (supportTransform) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable-next-line no-param-reassign -- impossible to satisfy */
|
||||
elem.style[transformProperty] = `translate(${numbers(a[0], b[0], v)}px,${numbers(a[1], b[1], v)}px)`;
|
||||
};
|
||||
} else {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
if (a[0] || b[0]) {
|
||||
/* eslint-disable-next-line no-param-reassign -- impossible to satisfy */
|
||||
elem.style.left = `${numbers(a[0], b[0], v)}px`;
|
||||
}
|
||||
if (a[1] || b[1]) {
|
||||
/* eslint-disable-next-line no-param-reassign -- impossible to satisfy */
|
||||
elem.style.top = `${numbers(a[1], b[1], v)}px`;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const componentFunctions = {
|
||||
prepareStart: getComponentCurrentValue,
|
||||
prepareProperty: prepareComponentValue,
|
||||
onStart: onStartComponent,
|
||||
};
|
||||
|
||||
// Base Component
|
||||
export const baseCrossBrowserMove = {
|
||||
component: 'baseCrossBrowserMove',
|
||||
property: 'move',
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartComponent },
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const crossBrowserMove = {
|
||||
component: 'crossBrowserMove',
|
||||
property: 'move',
|
||||
defaultValue: [0, 0],
|
||||
Interpolate: { numbers },
|
||||
functions: componentFunctions,
|
||||
Util: { trueProperty },
|
||||
};
|
||||
|
||||
export default crossBrowserMove;
|
|
@ -1,201 +0,0 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import trueColor from '../util/trueColor';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
import { dropshadow, onStartFilter } from './filterEffectsBase';
|
||||
|
||||
/* filterEffects = {
|
||||
property: 'filter',
|
||||
subProperties: {},
|
||||
defaultValue: {},
|
||||
interpolators: {},
|
||||
functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
} */
|
||||
|
||||
// Component Util
|
||||
/**
|
||||
* Returns camelCase filter sub-property.
|
||||
* @param {string} str source string
|
||||
* @returns {string} camelCase property name
|
||||
*/
|
||||
function replaceDashNamespace(str) {
|
||||
return str.replace('-r', 'R').replace('-s', 'S');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `drop-shadow` sub-property object.
|
||||
* @param {(string | number)[]} shadow and `Array` with `drop-shadow` parameters
|
||||
* @returns {KUTE.filterList['dropShadow']} the expected `drop-shadow` values
|
||||
*/
|
||||
function parseDropShadow(shadow) {
|
||||
let newShadow;
|
||||
|
||||
if (shadow.length === 3) { // [h-shadow, v-shadow, color]
|
||||
newShadow = [shadow[0], shadow[1], 0, shadow[2]];
|
||||
} else if (shadow.length === 4) { // ideal [<offset-x>, <offset-y>, <blur-radius>, <color>]
|
||||
newShadow = [shadow[0], shadow[1], shadow[2], shadow[3]];
|
||||
}
|
||||
|
||||
// make sure the values are ready to tween
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
newShadow[i] = parseFloat(newShadow[i]);
|
||||
}
|
||||
// also the color must be a rgb object
|
||||
newShadow[3] = trueColor(newShadow[3]);
|
||||
return newShadow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with current filter sub-properties values.
|
||||
* @param {string} currentStyle the current filter computed style
|
||||
* @returns {{[x: string]: number}} the filter tuple
|
||||
*/
|
||||
function parseFilterString(currentStyle) {
|
||||
const result = {};
|
||||
const fnReg = /(([a-z].*?)\(.*?\))(?=\s([a-z].*?)\(.*?\)|\s*$)/g;
|
||||
const matches = currentStyle.match(fnReg);
|
||||
const fnArray = currentStyle !== 'none' ? matches : 'none';
|
||||
|
||||
if (fnArray instanceof Array) {
|
||||
for (let j = 0, jl = fnArray.length; j < jl; j += 1) {
|
||||
const p = fnArray[j].trim().split(/\((.+)/);
|
||||
const pp = replaceDashNamespace(p[0]);
|
||||
if (pp === 'dropShadow') {
|
||||
const shadowColor = p[1].match(/(([a-z].*?)\(.*?\))(?=\s(.*?))/)[0];
|
||||
const params = p[1].replace(shadowColor, '').split(/\s/).map(parseFloat);
|
||||
result[pp] = params.filter((el) => !Number.isNaN(el)).concat(shadowColor);
|
||||
} else {
|
||||
result[pp] = p[1].replace(/'|"|\)/g, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
function getFilter(tweenProp, value) {
|
||||
const currentStyle = getStyleForProperty(this.element, tweenProp);
|
||||
const filterObject = parseFilterString(currentStyle);
|
||||
let fnp;
|
||||
|
||||
Object.keys(value).forEach((fn) => {
|
||||
fnp = replaceDashNamespace(fn);
|
||||
if (!filterObject[fnp]) {
|
||||
filterObject[fnp] = defaultValues[tweenProp][fn];
|
||||
}
|
||||
});
|
||||
|
||||
return filterObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property name
|
||||
* @returns {KUTE.filterList} the property tween object
|
||||
*/
|
||||
function prepareFilter(/* tweenProp, */_, value) {
|
||||
const filterObject = {};
|
||||
let fnp;
|
||||
|
||||
// property: range | default
|
||||
// opacity: [0-100%] | 100
|
||||
// blur: [0-Nem] | 0
|
||||
// saturate: [0-N%] | 100
|
||||
// invert: [0-100%] | 0
|
||||
// grayscale: [0-100%] | 0
|
||||
// brightness: [0-N%] | 100
|
||||
// contrast: [0-N%] | 100
|
||||
// sepia: [0-N%] | 0
|
||||
// 'hueRotate': [0-Ndeg] | 0
|
||||
// 'dropShadow': [0,0,0,(r:0,g:0,b:0)] | 0
|
||||
// url: '' | ''
|
||||
|
||||
Object.keys(value).forEach((fn) => {
|
||||
fnp = replaceDashNamespace(fn);
|
||||
if (/hue/.test(fn)) {
|
||||
filterObject[fnp] = parseFloat(value[fn]);
|
||||
} else if (/drop/.test(fn)) {
|
||||
filterObject[fnp] = parseDropShadow(value[fn]);
|
||||
} else if (fn === 'url') {
|
||||
filterObject[fn] = value[fn];
|
||||
// } else if ( /blur|opacity|grayscale|sepia/.test(fn) ) {
|
||||
} else {
|
||||
filterObject[fn] = parseFloat(value[fn]);
|
||||
}
|
||||
});
|
||||
|
||||
return filterObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds missing sub-properties in `valuesEnd` from `valuesStart`.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
function crossCheckFilter(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
Object.keys(this.valuesStart[tweenProp]).forEach((fn) => {
|
||||
if (!this.valuesEnd[tweenProp][fn]) {
|
||||
this.valuesEnd[tweenProp][fn] = this.valuesStart[tweenProp][fn];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const filterFunctions = {
|
||||
prepareStart: getFilter,
|
||||
prepareProperty: prepareFilter,
|
||||
onStart: onStartFilter,
|
||||
crossCheck: crossCheckFilter,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const filterEffects = {
|
||||
component: 'filterEffects',
|
||||
property: 'filter',
|
||||
// opacity function interfere with opacityProperty
|
||||
// subProperties: [
|
||||
// 'blur', 'brightness','contrast','dropShadow',
|
||||
// 'hueRotate','grayscale','invert','opacity','saturate','sepia','url'
|
||||
// ],
|
||||
defaultValue: {
|
||||
opacity: 100,
|
||||
blur: 0,
|
||||
saturate: 100,
|
||||
grayscale: 0,
|
||||
brightness: 100,
|
||||
contrast: 100,
|
||||
sepia: 0,
|
||||
invert: 0,
|
||||
hueRotate: 0,
|
||||
dropShadow: [0, 0, 0, { r: 0, g: 0, b: 0 }],
|
||||
url: '',
|
||||
},
|
||||
Interpolate: {
|
||||
opacity: numbers,
|
||||
blur: numbers,
|
||||
saturate: numbers,
|
||||
grayscale: numbers,
|
||||
brightness: numbers,
|
||||
contrast: numbers,
|
||||
sepia: numbers,
|
||||
invert: numbers,
|
||||
hueRotate: numbers,
|
||||
dropShadow: { numbers, colors, dropshadow },
|
||||
},
|
||||
functions: filterFunctions,
|
||||
Util: {
|
||||
parseDropShadow, parseFilterString, replaceDashNamespace, trueColor,
|
||||
},
|
||||
};
|
||||
|
||||
export default filterEffects;
|
|
@ -1,74 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
|
||||
// Component Interpolation
|
||||
/**
|
||||
* Sets the `drop-shadow` sub-property update function.
|
||||
* * disimbiguation `dropshadow` interpolation function and `dropShadow` property
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function dropshadow(a, b, v) {
|
||||
const params = [];
|
||||
const unit = 'px';
|
||||
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
params[i] = ((numbers(a[i], b[i], v) * 100 >> 0) / 100) + unit;
|
||||
}
|
||||
return `drop-shadow(${params.concat(colors(a[3], b[3], v)).join(' ')})`;
|
||||
}
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartFilter(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp] && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable-next-line no-param-reassign -- impossible to satisfy */
|
||||
elem.style[tweenProp] = (b.url ? `url(${b.url})` : '')
|
||||
/* eslint-disable no-bitwise -- impossible to satisfy */
|
||||
+ (a.opacity || b.opacity ? `opacity(${((numbers(a.opacity, b.opacity, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.blur || b.blur ? `blur(${((numbers(a.blur, b.blur, v) * 100) >> 0) / 100}em)` : '')
|
||||
+ (a.saturate || b.saturate ? `saturate(${((numbers(a.saturate, b.saturate, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.invert || b.invert ? `invert(${((numbers(a.invert, b.invert, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.grayscale || b.grayscale ? `grayscale(${((numbers(a.grayscale, b.grayscale, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.hueRotate || b.hueRotate ? `hue-rotate(${((numbers(a.hueRotate, b.hueRotate, v) * 100) >> 0) / 100}deg)` : '')
|
||||
+ (a.sepia || b.sepia ? `sepia(${((numbers(a.sepia, b.sepia, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.brightness || b.brightness ? `brightness(${((numbers(a.brightness, b.brightness, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.contrast || b.contrast ? `contrast(${((numbers(a.contrast, b.contrast, v) * 100) >> 0) / 100}%)` : '')
|
||||
+ (a.dropShadow || b.dropShadow ? dropshadow(a.dropShadow, b.dropShadow, v) : '');
|
||||
/* eslint-enable no-bitwise -- impossible to satisfy */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const baseFilter = {
|
||||
component: 'baseFilter',
|
||||
property: 'filter',
|
||||
// opacity function interfere with opacityProperty
|
||||
// subProperties: ['blur', 'brightness','contrast','dropShadow',
|
||||
// 'hueRotate','grayscale','invert','opacity','saturate','sepia','url'],
|
||||
// defaultValue: {
|
||||
// opacity: 100, blur: 0, saturate: 100, grayscale: 0,
|
||||
// brightness: 100, contrast: 100, sepia: 0, invert: 0, hueRotate:0,
|
||||
// dropShadow: [0,0,0,{r:0,g:0,b:0}], url:''
|
||||
// },
|
||||
Interpolate: {
|
||||
opacity: numbers,
|
||||
blur: numbers,
|
||||
saturate: numbers,
|
||||
grayscale: numbers,
|
||||
brightness: numbers,
|
||||
contrast: numbers,
|
||||
sepia: numbers,
|
||||
invert: numbers,
|
||||
hueRotate: numbers,
|
||||
dropShadow: { numbers, colors, dropshadow },
|
||||
},
|
||||
functions: { onStart: onStartFilter },
|
||||
};
|
||||
|
||||
export default baseFilter;
|
|
@ -1,131 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import onStart from '../objects/onStart';
|
||||
import trueColor from '../util/trueColor';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
import { attributes, onStartAttr } from './htmlAttributesBase';
|
||||
|
||||
// Component Name
|
||||
const ComponentName = 'htmlAttributes';
|
||||
|
||||
// Component Properties
|
||||
const svgColors = ['fill', 'stroke', 'stop-color'];
|
||||
|
||||
// Component Util
|
||||
/**
|
||||
* Returns non-camelcase property name.
|
||||
* @param {string} a the camelcase property name
|
||||
* @returns {string} the non-camelcase property name
|
||||
*/
|
||||
function replaceUppercase(a) { return a.replace(/[A-Z]/g, '-$&').toLowerCase(); }
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current attribute value.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {{[x:string]: string}} attribute value
|
||||
*/
|
||||
export function getAttr(/* tweenProp, */_, value) {
|
||||
const attrStartValues = {};
|
||||
Object.keys(value).forEach((attr) => {
|
||||
// get the value for 'fill-opacity' not fillOpacity
|
||||
// also 'width' not the internal 'width_px'
|
||||
const attribute = replaceUppercase(attr).replace(/_+[a-z]+/, '');
|
||||
const currentValue = this.element.getAttribute(attribute);
|
||||
attrStartValues[attribute] = svgColors.includes(attribute)
|
||||
? (currentValue || 'rgba(0,0,0,0)')
|
||||
: (currentValue || (/opacity/i.test(attr) ? 1 : 0));
|
||||
});
|
||||
|
||||
return attrStartValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} attrObj the property value
|
||||
* @returns {number} the property tween object
|
||||
*/
|
||||
export function prepareAttr(tweenProp, attrObj) { // attr (string),attrObj (object)
|
||||
const attributesObject = {};
|
||||
|
||||
Object.keys(attrObj).forEach((p) => {
|
||||
const prop = replaceUppercase(p);
|
||||
const regex = /(%|[a-z]+)$/;
|
||||
const currentValue = this.element.getAttribute(prop.replace(/_+[a-z]+/, ''));
|
||||
|
||||
if (!svgColors.includes(prop)) {
|
||||
// attributes set with unit suffixes
|
||||
if (currentValue !== null && regex.test(currentValue)) {
|
||||
const unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u;
|
||||
const suffix = /%/.test(unit) ? '_percent' : `_${unit}`;
|
||||
|
||||
// most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
onStart[ComponentName][prop + suffix] = (tp) => {
|
||||
if (this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes)) {
|
||||
attributes[tp] = (elem, oneAttr, a, b, v) => {
|
||||
const _p = oneAttr.replace(suffix, '');
|
||||
/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
|
||||
elem.setAttribute(_p, ((numbers(a.v, b.v, v) * 1000 >> 0) / 1000) + b.u);
|
||||
};
|
||||
}
|
||||
};
|
||||
attributesObject[prop + suffix] = trueDimension(attrObj[p]);
|
||||
} else if (!regex.test(attrObj[p]) || currentValue === null
|
||||
|| (currentValue !== null && !regex.test(currentValue))) {
|
||||
// most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
onStart[ComponentName][prop] = (tp) => {
|
||||
if (this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes)) {
|
||||
attributes[tp] = (elem, oneAttr, a, b, v) => {
|
||||
elem.setAttribute(oneAttr, (numbers(a, b, v) * 1000 >> 0) / 1000);
|
||||
};
|
||||
}
|
||||
};
|
||||
attributesObject[prop] = parseFloat(attrObj[p]);
|
||||
}
|
||||
} else { // colors
|
||||
// most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
onStart[ComponentName][prop] = (tp) => {
|
||||
if (this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes)) {
|
||||
attributes[tp] = (elem, oneAttr, a, b, v) => {
|
||||
elem.setAttribute(oneAttr, colors(a, b, v));
|
||||
};
|
||||
}
|
||||
};
|
||||
attributesObject[prop] = trueColor(attrObj[p]) || defaultValues.htmlAttributes[p];
|
||||
}
|
||||
});
|
||||
|
||||
return attributesObject;
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const attrFunctions = {
|
||||
prepareStart: getAttr,
|
||||
prepareProperty: prepareAttr,
|
||||
onStart: onStartAttr,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const htmlAttributes = {
|
||||
component: ComponentName,
|
||||
property: 'attr',
|
||||
// the Animation class will need some values to validate this Object attribute
|
||||
subProperties: ['fill', 'stroke', 'stop-color', 'fill-opacity', 'stroke-opacity'],
|
||||
defaultValue: {
|
||||
fill: 'rgb(0,0,0)',
|
||||
stroke: 'rgb(0,0,0)',
|
||||
'stop-color': 'rgb(0,0,0)',
|
||||
opacity: 1,
|
||||
'stroke-opacity': 1,
|
||||
'fill-opacity': 1, // same here
|
||||
},
|
||||
Interpolate: { numbers, colors },
|
||||
functions: attrFunctions,
|
||||
// export to global for faster execution
|
||||
Util: { replaceUppercase, trueColor, trueDimension },
|
||||
};
|
||||
|
||||
export default htmlAttributes;
|
|
@ -1,59 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
|
||||
// Component Name
|
||||
const ComponentName = 'baseHTMLAttributes';
|
||||
|
||||
// Component Special
|
||||
const attributes = {};
|
||||
export { attributes };
|
||||
|
||||
export const onStartAttr = {
|
||||
/**
|
||||
* onStartAttr.attr
|
||||
*
|
||||
* Sets the sub-property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
attr(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, vS, vE, v) => {
|
||||
Object.keys(vE).forEach((oneAttr) => {
|
||||
KEC.attributes[oneAttr](elem, oneAttr, vS[oneAttr], vE[oneAttr], v);
|
||||
});
|
||||
};
|
||||
}
|
||||
},
|
||||
/**
|
||||
* onStartAttr.attributes
|
||||
*
|
||||
* Sets the update function for the property.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
attributes(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd.attr) {
|
||||
KEC[tweenProp] = attributes;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Component Base
|
||||
const baseAttributes = {
|
||||
component: ComponentName,
|
||||
property: 'attr',
|
||||
// the Animation class will need some values to validate this Object attribute
|
||||
// subProperties: ['fill','stroke','stop-color','fill-opacity','stroke-opacity'],
|
||||
// defaultValue:
|
||||
// fill : 'rgb(0,0,0)',
|
||||
// stroke: 'rgb(0,0,0)',
|
||||
// 'stop-color': 'rgb(0,0,0)',
|
||||
// opacity: 1,
|
||||
// 'stroke-opacity': 1,
|
||||
// 'fill-opacity': 1 // same here
|
||||
// },
|
||||
Interpolate: { numbers, colors },
|
||||
functions: { onStart: onStartAttr },
|
||||
};
|
||||
|
||||
export default baseAttributes;
|
|
@ -1,41 +0,0 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import { onStartOpacity } from './opacityPropertyBase';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
function getOpacity(tweenProp/* , value */) {
|
||||
return getStyleForProperty(this.element, tweenProp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number} the property tween object
|
||||
*/
|
||||
function prepareOpacity(/* tweenProp, */_, value) {
|
||||
return parseFloat(value); // opacity always FLOAT
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const opacityFunctions = {
|
||||
prepareStart: getOpacity,
|
||||
prepareProperty: prepareOpacity,
|
||||
onStart: onStartOpacity,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const OpacityProperty = {
|
||||
component: 'opacityProperty',
|
||||
property: 'opacity',
|
||||
defaultValue: 1,
|
||||
Interpolate: { numbers },
|
||||
functions: opacityFunctions,
|
||||
};
|
||||
|
||||
export default OpacityProperty;
|
|
@ -1,36 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
/* opacityProperty = {
|
||||
property: 'opacity',
|
||||
defaultValue: 1,
|
||||
interpolators: {numbers},
|
||||
functions = { prepareStart, prepareProperty, onStart }
|
||||
} */
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartOpacity(tweenProp/* , value */) {
|
||||
// opacity could be 0 sometimes, we need to check regardless
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable */
|
||||
elem.style[tweenProp] = ((numbers(a, b, v) * 1000) >> 0) / 1000;
|
||||
/* eslint-enable */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const OpacityPropertyBase = {
|
||||
component: 'baseOpacity',
|
||||
property: 'opacity',
|
||||
// defaultValue: 1,
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartOpacity },
|
||||
};
|
||||
|
||||
export default OpacityPropertyBase;
|
|
@ -1,59 +0,0 @@
|
|||
import numbers from '../interpolation/numbers';
|
||||
|
||||
import {
|
||||
scrollContainer,
|
||||
onStartScroll,
|
||||
onCompleteScroll,
|
||||
scrollIn,
|
||||
scrollOut,
|
||||
getScrollTargets,
|
||||
preventScroll,
|
||||
toggleScrollEvents,
|
||||
} from './scrollPropertyBase';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @returns {number} computed style for property
|
||||
*/
|
||||
function getScroll() {
|
||||
this.element = ('scroll' in this.valuesEnd) && (!this.element || this.element === window)
|
||||
? scrollContainer : this.element;
|
||||
|
||||
return this.element === scrollContainer
|
||||
? (window.pageYOffset || scrollContainer.scrollTop)
|
||||
: this.element.scrollTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number} the property tween object
|
||||
*/
|
||||
function prepareScroll(/* prop, */_, value) {
|
||||
return parseInt(value, 10);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const scrollFunctions = {
|
||||
prepareStart: getScroll,
|
||||
prepareProperty: prepareScroll,
|
||||
onStart: onStartScroll,
|
||||
onComplete: onCompleteScroll,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const ScrollProperty = {
|
||||
component: 'scrollProperty',
|
||||
property: 'scroll',
|
||||
defaultValue: 0,
|
||||
Interpolate: { numbers },
|
||||
functions: scrollFunctions,
|
||||
// export stuff to global
|
||||
Util: {
|
||||
preventScroll, scrollIn, scrollOut, getScrollTargets, toggleScrollEvents,
|
||||
},
|
||||
};
|
||||
|
||||
export default ScrollProperty;
|
|
@ -1,113 +0,0 @@
|
|||
import passiveHandler from 'shorter-js/src/misc/passiveHandler';
|
||||
import mouseHoverEvents from 'shorter-js/src/strings/mouseHoverEvents';
|
||||
import supportTouch from 'shorter-js/src/boolean/supportTouch';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import KEC from '../objects/kute';
|
||||
|
||||
// Component Util
|
||||
// events preventing scroll
|
||||
const touchOrWheel = supportTouch ? 'touchstart' : 'mousewheel';
|
||||
|
||||
// true scroll container
|
||||
// very important and specific to the component
|
||||
export const scrollContainer = navigator && /(EDGE|Mac)/i.test(navigator.userAgent)
|
||||
? document.body
|
||||
: document.documentElement;
|
||||
|
||||
/**
|
||||
* Prevent further scroll events until scroll animation is over.
|
||||
* @param {Event} e event object
|
||||
*/
|
||||
export function preventScroll(e) {
|
||||
if (this.scrolling) e.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scroll element / target.
|
||||
* @returns {{el: Element, st: Element}}
|
||||
*/
|
||||
export function getScrollTargets() {
|
||||
const el = this.element;
|
||||
return el === scrollContainer ? { el: document, st: document.body } : { el, st: el };
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles scroll prevention callback on scroll events.
|
||||
* @param {string} action addEventListener / removeEventListener
|
||||
* @param {Element} element target
|
||||
*/
|
||||
export function toggleScrollEvents(action, element) {
|
||||
element[action](mouseHoverEvents[0], preventScroll, passiveHandler);
|
||||
element[action](touchOrWheel, preventScroll, passiveHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action performed before scroll animation start.
|
||||
*/
|
||||
export function scrollIn() {
|
||||
const targets = getScrollTargets.call(this);
|
||||
|
||||
if ('scroll' in this.valuesEnd && !targets.el.scrolling) {
|
||||
targets.el.scrolling = 1;
|
||||
toggleScrollEvents('addEventListener', targets.el);
|
||||
targets.st.style.pointerEvents = 'none';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Action performed when scroll animation ends.
|
||||
*/
|
||||
export function scrollOut() { // prevent scroll when tweening scroll
|
||||
const targets = getScrollTargets.call(this);
|
||||
|
||||
if ('scroll' in this.valuesEnd && targets.el.scrolling) {
|
||||
targets.el.scrolling = 0;
|
||||
toggleScrollEvents('removeEventListener', targets.el);
|
||||
targets.st.style.pointerEvents = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* * Sets the scroll target.
|
||||
* * Adds the scroll prevention event listener.
|
||||
* * Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartScroll(tweenProp) {
|
||||
// checking 0 will NOT add the render function
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) {
|
||||
this.element = ('scroll' in this.valuesEnd) && (!this.element || this.element === window)
|
||||
? scrollContainer : this.element;
|
||||
scrollIn.call(this);
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable */
|
||||
elem.scrollTop = (numbers(a, b, v)) >> 0;
|
||||
/* eslint-enable */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the scroll prevention event listener.
|
||||
*/
|
||||
export function onCompleteScroll(/* tweenProp */) {
|
||||
scrollOut.call(this);
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const ScrollPropertyBase = {
|
||||
component: 'baseScroll',
|
||||
property: 'scroll',
|
||||
// defaultValue: 0,
|
||||
Interpolate: { numbers },
|
||||
functions: {
|
||||
onStart: onStartScroll,
|
||||
onComplete: onCompleteScroll,
|
||||
},
|
||||
// unfortunatelly scroll needs all them no matter the packaging
|
||||
Util: {
|
||||
preventScroll, scrollIn, scrollOut, getScrollTargets,
|
||||
},
|
||||
};
|
||||
|
||||
export default ScrollPropertyBase;
|
|
@ -1,127 +0,0 @@
|
|||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueColor from '../util/trueColor';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
import { onStartShadow } from './shadowPropertiesBase';
|
||||
|
||||
// Component Properties
|
||||
const shadowProps = ['boxShadow', 'textShadow'];
|
||||
|
||||
// Component Util
|
||||
|
||||
/**
|
||||
* Return the box-shadow / text-shadow tween object.
|
||||
* * box-shadow: none | h-shadow v-shadow blur spread color inset|initial|inherit
|
||||
* * text-shadow: none | offset-x offset-y blur-radius color |initial|inherit
|
||||
* * numbers must be floats and color must be rgb object
|
||||
*
|
||||
* @param {(number | string)[]} shadow an `Array` with shadow parameters
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {KUTE.shadowObject} the property tween object
|
||||
*/
|
||||
function processShadowArray(shadow, tweenProp) {
|
||||
let newShadow;
|
||||
|
||||
// [h-shadow, v-shadow, color]
|
||||
if (shadow.length === 3) {
|
||||
newShadow = [shadow[0], shadow[1], 0, 0, shadow[2], 'none'];
|
||||
// [h-shadow, v-shadow, color, inset] | [h-shadow, v-shadow, blur, color]
|
||||
} else if (shadow.length === 4) {
|
||||
newShadow = /inset|none/.test(shadow[3])
|
||||
? [shadow[0], shadow[1], 0, 0, shadow[2], shadow[3]]
|
||||
: [shadow[0], shadow[1], shadow[2], 0, shadow[3], 'none'];
|
||||
// [h-shadow, v-shadow, blur, color, inset] | [h-shadow, v-shadow, blur, spread, color]
|
||||
} else if (shadow.length === 5) {
|
||||
newShadow = /inset|none/.test(shadow[4])
|
||||
? [shadow[0], shadow[1], shadow[2], 0, shadow[3], shadow[4]]
|
||||
: [shadow[0], shadow[1], shadow[2], shadow[3], shadow[4], 'none'];
|
||||
// ideal [h-shadow, v-shadow, blur, spread, color, inset]
|
||||
} else if (shadow.length === 6) {
|
||||
newShadow = shadow;
|
||||
}
|
||||
|
||||
// make sure the values are ready to tween
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
newShadow[i] = parseFloat(newShadow[i]);
|
||||
}
|
||||
|
||||
// also the color must be a rgb object
|
||||
newShadow[4] = trueColor(newShadow[4]);
|
||||
|
||||
newShadow = tweenProp === 'boxShadow'
|
||||
? newShadow
|
||||
: newShadow.filter((_, i) => [0, 1, 2, 4].includes(i));
|
||||
|
||||
return newShadow;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
export function getShadow(tweenProp/* , value */) {
|
||||
const cssShadow = getStyleForProperty(this.element, tweenProp);
|
||||
// '0px 0px 0px 0px rgb(0,0,0)'
|
||||
return /^none$|^initial$|^inherit$|^inset$/.test(cssShadow)
|
||||
? defaultValues[tweenProp]
|
||||
: cssShadow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} propValue the property value
|
||||
* @returns {KUTE.shadowObject} the property tween object
|
||||
*/
|
||||
export function prepareShadow(tweenProp, propValue) {
|
||||
// [horizontal, vertical, blur, spread, color: {r:0,g:0,b:0}, inset]
|
||||
// parseProperty for boxShadow, builds basic structure with ready to tween values
|
||||
let value = propValue;
|
||||
if (typeof value === 'string') {
|
||||
let inset = 'none';
|
||||
// a full RegEx for color strings
|
||||
const colRegEx = /(\s?(?:#(?:[\da-f]{3}){1,2}|rgba?\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\))\s?)/gi;
|
||||
const currentColor = value.match(colRegEx);
|
||||
|
||||
// make sure to always have the inset last if possible
|
||||
inset = /inset/.test(value) ? 'inset' : inset;
|
||||
value = /inset/.test(value) ? value.replace(/(\s+inset|inset+\s)/g, '') : value;
|
||||
|
||||
// also getComputedStyle often returns color first "rgb(0, 0, 0) 15px 15px 6px 0px inset"
|
||||
value = value.replace(currentColor[0], '').split(' ').concat([currentColor[0].replace(/\s/g, '')], [inset]);
|
||||
|
||||
value = processShadowArray(value, tweenProp);
|
||||
} else if (value instanceof Array) {
|
||||
value = processShadowArray(value, tweenProp);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
const shadowPropOnStart = {};
|
||||
shadowProps.forEach((x) => { shadowPropOnStart[x] = onStartShadow; });
|
||||
|
||||
// All Component Functions
|
||||
const shadowFunctions = {
|
||||
prepareStart: getShadow,
|
||||
prepareProperty: prepareShadow,
|
||||
onStart: shadowPropOnStart,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const ShadowProperties = {
|
||||
component: 'shadowProperties',
|
||||
properties: shadowProps,
|
||||
defaultValues: {
|
||||
boxShadow: '0px 0px 0px 0px rgb(0,0,0)',
|
||||
textShadow: '0px 0px 0px rgb(0,0,0)',
|
||||
},
|
||||
Interpolate: { numbers, colors },
|
||||
functions: shadowFunctions,
|
||||
Util: { processShadowArray, trueColor },
|
||||
};
|
||||
|
||||
export default ShadowProperties;
|
|
@ -1,46 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import colors from '../interpolation/colors';
|
||||
|
||||
// Component Properties
|
||||
const shadowProps = ['boxShadow', 'textShadow'];
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartShadow(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp] && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// let's start with the numbers | set unit | also determine inset
|
||||
const params = [];
|
||||
const unit = 'px';
|
||||
const sl = tweenProp === 'textShadow' ? 3 : 4;
|
||||
const colA = sl === 3 ? a[3] : a[4];
|
||||
const colB = sl === 3 ? b[3] : b[4];
|
||||
const inset = (a[5] && a[5] !== 'none') || (b[5] && b[5] !== 'none') ? ' inset' : false;
|
||||
|
||||
for (let i = 0; i < sl; i += 1) {
|
||||
/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
|
||||
params.push(((numbers(a[i], b[i], v) * 1000 >> 0) / 1000) + unit);
|
||||
}
|
||||
// the final piece of the puzzle, the DOM update
|
||||
// eslint-disable-next-line no-param-reassign -- impossible to satisfy
|
||||
elem.style[tweenProp] = inset
|
||||
? colors(colA, colB, v) + params.join(' ') + inset
|
||||
: colors(colA, colB, v) + params.join(' ');
|
||||
};
|
||||
}
|
||||
}
|
||||
const shadowPropOnStart = {};
|
||||
shadowProps.forEach((x) => { shadowPropOnStart[x] = onStartShadow; });
|
||||
|
||||
// Component Base
|
||||
const ShadowPropertiesBase = {
|
||||
component: 'baseShadow',
|
||||
Interpolate: { numbers, colors },
|
||||
functions: { onStart: shadowPropOnStart },
|
||||
};
|
||||
|
||||
export default ShadowPropertiesBase;
|
|
@ -1,229 +0,0 @@
|
|||
import parsePathString from 'svg-path-commander/src/parser/parsePathString';
|
||||
import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute';
|
||||
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve';
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString';
|
||||
import reverseCurve from 'svg-path-commander/src/process/reverseCurve';
|
||||
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection';
|
||||
import clonePath from 'svg-path-commander/src/process/clonePath';
|
||||
import splitCubic from 'svg-path-commander/src/process/splitCubic';
|
||||
import splitPath from 'svg-path-commander/src/process/splitPath';
|
||||
import fixPath from 'svg-path-commander/src/process/fixPath';
|
||||
import segmentCubicFactory from 'svg-path-commander/src/util/segmentCubicFactory';
|
||||
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot';
|
||||
|
||||
import { onStartCubicMorph } from './svgCubicMorphBase';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import selector from '../util/selector';
|
||||
|
||||
// Component Util
|
||||
/**
|
||||
* Returns first `pathArray` from multi-paths path.
|
||||
* @param {SVGPathCommander.pathArray | string} source the source `pathArray` or string
|
||||
* @returns {KUTE.curveSpecs[]} an `Array` with a custom tuple for `equalizeSegments`
|
||||
*/
|
||||
function getCurveArray(source) {
|
||||
return pathToCurve(splitPath(source)[0])
|
||||
.map((segment, i, pathArray) => {
|
||||
const segmentData = i && [...pathArray[i - 1].slice(-2), ...segment.slice(1)];
|
||||
const curveLength = i ? segmentCubicFactory(...segmentData) : 0;
|
||||
|
||||
let subsegs;
|
||||
if (i) {
|
||||
// must be [segment,segment]
|
||||
subsegs = curveLength ? splitCubic(segmentData) : [segment, segment];
|
||||
} else {
|
||||
subsegs = [segment];
|
||||
}
|
||||
|
||||
return {
|
||||
s: segment,
|
||||
ss: subsegs,
|
||||
l: curveLength,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns two `curveArray` with same amount of segments.
|
||||
* @param {SVGPathCommander.curveArray} path1 the first `curveArray`
|
||||
* @param {SVGPathCommander.curveArray} path2 the second `curveArray`
|
||||
* @param {number} TL the maximum `curveArray` length
|
||||
* @returns {SVGPathCommander.curveArray[]} equalized segments
|
||||
*/
|
||||
function equalizeSegments(path1, path2, TL) {
|
||||
const c1 = getCurveArray(path1);
|
||||
const c2 = getCurveArray(path2);
|
||||
const L1 = c1.length;
|
||||
const L2 = c2.length;
|
||||
const l1 = c1.filter((x) => x.l).length;
|
||||
const l2 = c2.filter((x) => x.l).length;
|
||||
const m1 = c1.filter((x) => x.l).reduce((a, { l }) => a + l, 0) / l1 || 0;
|
||||
const m2 = c2.filter((x) => x.l).reduce((a, { l }) => a + l, 0) / l2 || 0;
|
||||
const tl = TL || Math.max(L1, L2);
|
||||
const mm = [m1, m2];
|
||||
const dif = [tl - L1, tl - L2];
|
||||
let canSplit = 0;
|
||||
const result = [c1, c2]
|
||||
.map((x, i) => (x.l === tl
|
||||
? x.map((y) => y.s)
|
||||
: x.map((y, j) => {
|
||||
canSplit = j && dif[i] && y.l >= mm[i];
|
||||
dif[i] -= canSplit ? 1 : 0;
|
||||
return canSplit ? y.ss : [y.s];
|
||||
}).flat()));
|
||||
|
||||
return result[0].length === result[1].length
|
||||
? result
|
||||
: equalizeSegments(result[0], result[1], tl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all possible path rotations for `curveArray`.
|
||||
* @param {SVGPathCommander.curveArray} a the source `curveArray`
|
||||
* @returns {SVGPathCommander.curveArray[]} all rotations for source
|
||||
*/
|
||||
function getRotations(a) {
|
||||
const segCount = a.length;
|
||||
const pointCount = segCount - 1;
|
||||
|
||||
return a.map((_, idx) => a.map((__, i) => {
|
||||
let oldSegIdx = idx + i;
|
||||
let seg;
|
||||
|
||||
if (i === 0 || (a[oldSegIdx] && a[oldSegIdx][0] === 'M')) {
|
||||
seg = a[oldSegIdx];
|
||||
return ['M', ...seg.slice(-2)];
|
||||
}
|
||||
if (oldSegIdx >= segCount) oldSegIdx -= pointCount;
|
||||
return a[oldSegIdx];
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `curveArray` rotation for the best morphing animation.
|
||||
* @param {SVGPathCommander.curveArray} a the target `curveArray`
|
||||
* @param {SVGPathCommander.curveArray} b the reference `curveArray`
|
||||
* @returns {SVGPathCommander.curveArray} the best `a` rotation
|
||||
*/
|
||||
function getRotatedCurve(a, b) {
|
||||
const segCount = a.length - 1;
|
||||
const lineLengths = [];
|
||||
let computedIndex = 0;
|
||||
let sumLensSqrd = 0;
|
||||
const rotations = getRotations(a);
|
||||
|
||||
rotations.forEach((_, i) => {
|
||||
a.slice(1).forEach((__, j) => {
|
||||
sumLensSqrd += distanceSquareRoot(a[(i + j) % segCount].slice(-2), b[j % segCount].slice(-2));
|
||||
});
|
||||
lineLengths[i] = sumLensSqrd;
|
||||
sumLensSqrd = 0;
|
||||
});
|
||||
|
||||
computedIndex = lineLengths.indexOf(Math.min.apply(null, lineLengths));
|
||||
|
||||
return rotations[computedIndex];
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current `d` attribute value.
|
||||
* @returns {string}
|
||||
*/
|
||||
function getCubicMorph(/* tweenProp, value */) {
|
||||
return this.element.getAttribute('d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @see KUTE.curveObject
|
||||
*
|
||||
* @param {string} _ is the `path` property name, not needed
|
||||
* @param {string | KUTE.curveObject} value the `path` property value
|
||||
* @returns {KUTE.curveObject}
|
||||
*/
|
||||
function prepareCubicMorph(/* tweenProp, */_, value) {
|
||||
// get path d attribute or create a path from string value
|
||||
const pathObject = {};
|
||||
// remove newlines, they break some JSON strings
|
||||
const pathReg = new RegExp('\\n', 'ig');
|
||||
|
||||
let el = null;
|
||||
if (value instanceof SVGElement) {
|
||||
el = value;
|
||||
} else if (/^\.|^#/.test(value)) {
|
||||
el = selector(value);
|
||||
}
|
||||
|
||||
// make sure to return pre-processed values
|
||||
if (typeof (value) === 'object' && value.curve) {
|
||||
return value;
|
||||
} if (el && /path|glyph/.test(el.tagName)) {
|
||||
pathObject.original = el.getAttribute('d').replace(pathReg, '');
|
||||
// maybe it's a string path already
|
||||
} else if (!el && typeof (value) === 'string') {
|
||||
pathObject.original = value.replace(pathReg, '');
|
||||
}
|
||||
return pathObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the `to()` method by preparing the tween object in advance.
|
||||
* @param {string} tweenProp is `path` tween property, but it's not needed
|
||||
*/
|
||||
function crossCheckCubicMorph(tweenProp/** , value */) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
const pathCurve1 = this.valuesStart[tweenProp].curve;
|
||||
const pathCurve2 = this.valuesEnd[tweenProp].curve;
|
||||
|
||||
if (!pathCurve1 || !pathCurve2
|
||||
|| (pathCurve1 && pathCurve2 && pathCurve1[0][0] === 'M' && pathCurve1.length !== pathCurve2.length)) {
|
||||
const path1 = this.valuesStart[tweenProp].original;
|
||||
const path2 = this.valuesEnd[tweenProp].original;
|
||||
const curves = equalizeSegments(path1, path2);
|
||||
const curve0 = getDrawDirection(curves[0]) !== getDrawDirection(curves[1])
|
||||
? reverseCurve(curves[0])
|
||||
: clonePath(curves[0]);
|
||||
|
||||
this.valuesStart[tweenProp].curve = curve0;
|
||||
this.valuesEnd[tweenProp].curve = getRotatedCurve(curves[1], curve0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const svgCubicMorphFunctions = {
|
||||
prepareStart: getCubicMorph,
|
||||
prepareProperty: prepareCubicMorph,
|
||||
onStart: onStartCubicMorph,
|
||||
crossCheck: crossCheckCubicMorph,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const svgCubicMorph = {
|
||||
component: 'svgCubicMorph',
|
||||
property: 'path',
|
||||
defaultValue: [],
|
||||
Interpolate: { numbers, pathToString },
|
||||
functions: svgCubicMorphFunctions,
|
||||
// export utils to global for faster execution
|
||||
Util: {
|
||||
pathToCurve,
|
||||
pathToAbsolute,
|
||||
pathToString,
|
||||
parsePathString,
|
||||
getRotatedCurve,
|
||||
getRotations,
|
||||
equalizeSegments,
|
||||
reverseCurve,
|
||||
clonePath,
|
||||
getDrawDirection,
|
||||
segmentCubicFactory,
|
||||
splitCubic,
|
||||
splitPath,
|
||||
fixPath,
|
||||
getCurveArray,
|
||||
},
|
||||
};
|
||||
|
||||
export default svgCubicMorph;
|
|
@ -1,38 +0,0 @@
|
|||
import pathToString from 'svg-path-commander/src/convert/pathToString';
|
||||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the `path` property
|
||||
*/
|
||||
export function onStartCubicMorph(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KEC[tweenProp] = function updateMorph(elem, a, b, v) {
|
||||
const curve = [];
|
||||
const path1 = a.curve;
|
||||
const path2 = b.curve;
|
||||
for (let i = 0, l = path2.length; i < l; i += 1) { // each path command
|
||||
curve.push([path1[i][0]]);
|
||||
for (let j = 1, l2 = path1[i].length; j < l2; j += 1) { // each command coordinate
|
||||
/* eslint-disable-next-line no-bitwise -- impossible to satisfy */
|
||||
curve[i].push((numbers(path1[i][j], path2[i][j], v) * 1000 >> 0) / 1000);
|
||||
}
|
||||
}
|
||||
elem.setAttribute('d', v === 1 ? b.original : pathToString(curve));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseSvgCubicMorph = {
|
||||
component: 'baseSVGCubicMorph',
|
||||
property: 'path',
|
||||
// defaultValue: [],
|
||||
Interpolate: { numbers, pathToString },
|
||||
functions: { onStart: onStartCubicMorph },
|
||||
};
|
||||
|
||||
export default baseSvgCubicMorph;
|
|
@ -1,210 +0,0 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import { onStartDraw } from './svgDrawBase';
|
||||
|
||||
// Component Util
|
||||
/**
|
||||
* Convert a `<path>` length percent value to absolute.
|
||||
* @param {string} v raw value
|
||||
* @param {number} l length value
|
||||
* @returns {number} the absolute value
|
||||
*/
|
||||
function percent(v, l) {
|
||||
return (parseFloat(v) / 100) * l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<rect>` length.
|
||||
* It doesn't compute `rx` and / or `ry` of the element.
|
||||
* @see http://stackoverflow.com/a/30376660
|
||||
* @param {SVGRectElement} el target element
|
||||
* @returns {number} the `<rect>` length
|
||||
*/
|
||||
function getRectLength(el) {
|
||||
const w = el.getAttribute('width');
|
||||
const h = el.getAttribute('height');
|
||||
return (w * 2) + (h * 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<polyline>` / `<polygon>` length.
|
||||
* @param {SVGPolylineElement | SVGPolygonElement} el target element
|
||||
* @returns {number} the element length
|
||||
*/
|
||||
function getPolyLength(el) {
|
||||
const points = el.getAttribute('points').split(' ');
|
||||
|
||||
let len = 0;
|
||||
if (points.length > 1) {
|
||||
const coord = (p) => {
|
||||
const c = p.split(',');
|
||||
if (c.length !== 2) { return 0; } // return undefined
|
||||
if (Number.isNaN(c[0] * 1) || Number.isNaN(c[1] * 1)) { return 0; }
|
||||
return [parseFloat(c[0]), parseFloat(c[1])];
|
||||
};
|
||||
|
||||
const dist = (c1, c2) => {
|
||||
if (c1 !== undefined && c2 !== undefined) {
|
||||
return Math.sqrt((c2[0] - c1[0]) ** 2 + (c2[1] - c1[1]) ** 2);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
if (points.length > 2) {
|
||||
for (let i = 0; i < points.length - 1; i += 1) {
|
||||
len += dist(coord(points[i]), coord(points[i + 1]));
|
||||
}
|
||||
}
|
||||
len += el.tagName === 'polygon'
|
||||
? dist(coord(points[0]), coord(points[points.length - 1])) : 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<line>` length.
|
||||
* @param {SVGLineElement} el target element
|
||||
* @returns {number} the element length
|
||||
*/
|
||||
function getLineLength(el) {
|
||||
const x1 = el.getAttribute('x1');
|
||||
const x2 = el.getAttribute('x2');
|
||||
const y1 = el.getAttribute('y1');
|
||||
const y2 = el.getAttribute('y2');
|
||||
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `<circle>` length.
|
||||
* @param {SVGCircleElement} el target element
|
||||
* @returns {number} the element length
|
||||
*/
|
||||
function getCircleLength(el) {
|
||||
const r = el.getAttribute('r');
|
||||
return 2 * Math.PI * r;
|
||||
}
|
||||
|
||||
// returns the length of an ellipse
|
||||
/**
|
||||
* Returns the `<ellipse>` length.
|
||||
* @param {SVGEllipseElement} el target element
|
||||
* @returns {number} the element length
|
||||
*/
|
||||
function getEllipseLength(el) {
|
||||
const rx = el.getAttribute('rx');
|
||||
const ry = el.getAttribute('ry');
|
||||
const len = 2 * rx;
|
||||
const wid = 2 * ry;
|
||||
return ((Math.sqrt(0.5 * ((len * len) + (wid * wid)))) * (Math.PI * 2)) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shape length.
|
||||
* @param {SVGPathCommander.shapeTypes} el target element
|
||||
* @returns {number} the element length
|
||||
*/
|
||||
function getTotalLength(el) {
|
||||
if (el.tagName === 'rect') {
|
||||
return getRectLength(el);
|
||||
} if (el.tagName === 'circle') {
|
||||
return getCircleLength(el);
|
||||
} if (el.tagName === 'ellipse') {
|
||||
return getEllipseLength(el);
|
||||
} if (['polygon', 'polyline'].includes(el.tagName)) {
|
||||
return getPolyLength(el);
|
||||
} if (el.tagName === 'line') {
|
||||
return getLineLength(el);
|
||||
}
|
||||
// ESLint
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {SVGPathCommander.shapeTypes} element the target element
|
||||
* @param {string | KUTE.drawObject} value the property value
|
||||
* @returns {KUTE.drawObject} the property tween object
|
||||
*/
|
||||
function getDraw(element, value) {
|
||||
const length = /path|glyph/.test(element.tagName)
|
||||
? element.getTotalLength()
|
||||
: getTotalLength(element);
|
||||
let start;
|
||||
let end;
|
||||
let dasharray;
|
||||
let offset;
|
||||
|
||||
if (value instanceof Object && Object.keys(value).every((v) => ['s', 'e', 'l'].includes(v))) {
|
||||
return value;
|
||||
} if (typeof value === 'string') {
|
||||
const v = value.split(/,|\s/);
|
||||
start = /%/.test(v[0]) ? percent(v[0].trim(), length) : parseFloat(v[0]);
|
||||
end = /%/.test(v[1]) ? percent(v[1].trim(), length) : parseFloat(v[1]);
|
||||
} else if (typeof value === 'undefined') {
|
||||
offset = parseFloat(getStyleForProperty(element, 'stroke-dashoffset'));
|
||||
dasharray = getStyleForProperty(element, 'stroke-dasharray').split(',');
|
||||
|
||||
start = 0 - offset;
|
||||
end = parseFloat(dasharray[0]) + start || length;
|
||||
}
|
||||
return { s: start, e: end, l: length };
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset CSS properties associated with the `draw` property.
|
||||
* @param {SVGPathCommander.shapeTypes} element target
|
||||
*/
|
||||
function resetDraw(elem) {
|
||||
/* eslint-disable no-param-reassign -- impossible to satisfy */
|
||||
elem.style.strokeDashoffset = '';
|
||||
elem.style.strokeDasharray = '';
|
||||
/* eslint-disable no-param-reassign -- impossible to satisfy */
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @returns {KUTE.drawObject} the property tween object
|
||||
*/
|
||||
function getDrawValue(/* prop, value */) {
|
||||
return getDraw(this.element);
|
||||
}
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string | KUTE.drawObject} value the property value
|
||||
* @returns {KUTE.drawObject} the property tween object
|
||||
*/
|
||||
function prepareDraw(_, value) {
|
||||
return getDraw(this.element, value);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const svgDrawFunctions = {
|
||||
prepareStart: getDrawValue,
|
||||
prepareProperty: prepareDraw,
|
||||
onStart: onStartDraw,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const SvgDrawProperty = {
|
||||
component: 'svgDraw',
|
||||
property: 'draw',
|
||||
defaultValue: '0% 0%',
|
||||
Interpolate: { numbers },
|
||||
functions: svgDrawFunctions,
|
||||
// Export to global for faster execution
|
||||
Util: {
|
||||
getRectLength,
|
||||
getPolyLength,
|
||||
getLineLength,
|
||||
getCircleLength,
|
||||
getEllipseLength,
|
||||
getTotalLength,
|
||||
resetDraw,
|
||||
getDraw,
|
||||
percent,
|
||||
},
|
||||
};
|
||||
|
||||
export default SvgDrawProperty;
|
|
@ -1,35 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartDraw(tweenProp) {
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable no-bitwise -- impossible to satisfy */
|
||||
const pathLength = (a.l * 100 >> 0) / 100;
|
||||
const start = (numbers(a.s, b.s, v) * 100 >> 0) / 100;
|
||||
const end = (numbers(a.e, b.e, v) * 100 >> 0) / 100;
|
||||
const offset = 0 - start;
|
||||
const dashOne = end + offset;
|
||||
// eslint-disable-next-line no-param-reassign -- impossible to satisfy
|
||||
elem.style.strokeDashoffset = `${offset}px`;
|
||||
// eslint-disable-next-line no-param-reassign -- impossible to satisfy
|
||||
elem.style.strokeDasharray = `${((dashOne < 1 ? 0 : dashOne) * 100 >> 0) / 100}px, ${pathLength}px`;
|
||||
/* eslint-disable no-bitwise -- impossible to satisfy */
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const SvgDrawBase = {
|
||||
component: 'baseSVGDraw',
|
||||
property: 'draw',
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartDraw },
|
||||
};
|
||||
|
||||
export default SvgDrawBase;
|
|
@ -1,367 +0,0 @@
|
|||
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve';
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString';
|
||||
import normalizePath from 'svg-path-commander/src/process/normalizePath';
|
||||
import splitPath from 'svg-path-commander/src/process/splitPath';
|
||||
import roundPath from 'svg-path-commander/src/process/roundPath';
|
||||
import getTotalLength from 'svg-path-commander/src/util/getTotalLength';
|
||||
import invalidPathValue from 'svg-path-commander/src/parser/invalidPathValue';
|
||||
import getPointAtLength from 'svg-path-commander/src/util/getPointAtLength';
|
||||
import polygonArea from 'svg-path-commander/src/math/polygonArea';
|
||||
import polygonLength from 'svg-path-commander/src/math/polygonLength';
|
||||
import epsilon from 'svg-path-commander/src/math/epsilon';
|
||||
import midPoint from 'svg-path-commander/src/math/midPoint';
|
||||
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot';
|
||||
import { onStartSVGMorph } from './svgMorphBase';
|
||||
import coords from '../interpolation/coords';
|
||||
import defaultOptions from '../objects/defaultOptions';
|
||||
import selector from '../util/selector';
|
||||
|
||||
// Component Util
|
||||
// original script flubber
|
||||
// https://github.com/veltman/flubber
|
||||
|
||||
/**
|
||||
* Returns an existing polygon or false if it's not a polygon.
|
||||
* @param {SVGPathCommander.pathArray} pathArray target `pathArray`
|
||||
* @returns {KUTE.exactPolygon | false} the resulted polygon
|
||||
*/
|
||||
function exactPolygon(pathArray) {
|
||||
const polygon = [];
|
||||
const pathlen = pathArray.length;
|
||||
let segment = [];
|
||||
let pathCommand = '';
|
||||
|
||||
if (!pathArray.length || pathArray[0][0] !== 'M') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < pathlen; i += 1) {
|
||||
segment = pathArray[i];
|
||||
[pathCommand] = segment;
|
||||
|
||||
if ((pathCommand === 'M' && i) || pathCommand === 'Z') {
|
||||
break; // !!
|
||||
} else if ('ML'.includes(pathCommand)) {
|
||||
polygon.push([segment[1], segment[2]]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return pathlen ? { polygon } : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new polygon polygon.
|
||||
* @param {SVGPathCommander.pathArray} parsed target `pathArray`
|
||||
* @param {number} maxLength the maximum segment length
|
||||
* @returns {KUTE.exactPolygon} the resulted polygon
|
||||
*/
|
||||
function approximatePolygon(parsed, maxLength) {
|
||||
const ringPath = splitPath(pathToString(parsed))[0];
|
||||
const normalPath = normalizePath(ringPath);
|
||||
const pathLength = getTotalLength(normalPath);
|
||||
const polygon = [];
|
||||
let numPoints = 3;
|
||||
let point;
|
||||
|
||||
if (maxLength && !Number.isNaN(maxLength) && +maxLength > 0) {
|
||||
numPoints = Math.max(numPoints, Math.ceil(pathLength / maxLength));
|
||||
}
|
||||
|
||||
for (let i = 0; i < numPoints; i += 1) {
|
||||
point = getPointAtLength(normalPath, (pathLength * i) / numPoints);
|
||||
polygon.push([point.x, point.y]);
|
||||
}
|
||||
|
||||
// Make all rings clockwise
|
||||
if (polygonArea(polygon) > 0) {
|
||||
polygon.reverse();
|
||||
}
|
||||
|
||||
return {
|
||||
polygon,
|
||||
skipBisect: true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a path string and returns a polygon array.
|
||||
* @param {string} str path string
|
||||
* @param {number} maxLength maximum amount of points
|
||||
* @returns {KUTE.exactPolygon} the polygon array we need
|
||||
*/
|
||||
function pathStringToPolygon(str, maxLength) {
|
||||
const parsed = normalizePath(str);
|
||||
return exactPolygon(parsed) || approximatePolygon(parsed, maxLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates a polygon to better match its pair.
|
||||
* @param {KUTE.polygonMorph} polygon the target polygon
|
||||
* @param {KUTE.polygonMorph} vs the reference polygon
|
||||
*/
|
||||
function rotatePolygon(polygon, vs) {
|
||||
const len = polygon.length;
|
||||
let min = Infinity;
|
||||
let bestOffset;
|
||||
let sumOfSquares = 0;
|
||||
let spliced;
|
||||
let d;
|
||||
let p;
|
||||
|
||||
for (let offset = 0; offset < len; offset += 1) {
|
||||
sumOfSquares = 0;
|
||||
|
||||
for (let i = 0; i < vs.length; i += 1) {
|
||||
p = vs[i];
|
||||
d = distanceSquareRoot(polygon[(offset + i) % len], p);
|
||||
sumOfSquares += d * d;
|
||||
}
|
||||
|
||||
if (sumOfSquares < min) {
|
||||
min = sumOfSquares;
|
||||
bestOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOffset) {
|
||||
spliced = polygon.splice(0, bestOffset);
|
||||
polygon.splice(polygon.length, 0, ...spliced);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample additional points for a polygon to better match its pair.
|
||||
* @param {KUTE.polygonObject} polygon the target polygon
|
||||
* @param {number} numPoints the amount of points needed
|
||||
*/
|
||||
function addPoints(polygon, numPoints) {
|
||||
const desiredLength = polygon.length + numPoints;
|
||||
const step = polygonLength(polygon) / numPoints;
|
||||
|
||||
let i = 0;
|
||||
let cursor = 0;
|
||||
let insertAt = step / 2;
|
||||
let a;
|
||||
let b;
|
||||
let segment;
|
||||
|
||||
while (polygon.length < desiredLength) {
|
||||
a = polygon[i];
|
||||
b = polygon[(i + 1) % polygon.length];
|
||||
|
||||
segment = distanceSquareRoot(a, b);
|
||||
|
||||
if (insertAt <= cursor + segment) {
|
||||
polygon.splice(i + 1, 0, segment
|
||||
? midPoint(a, b, (insertAt - cursor) / segment)
|
||||
: a.slice(0));
|
||||
insertAt += step;
|
||||
} else {
|
||||
cursor += segment;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split segments of a polygon until it reaches a certain
|
||||
* amount of points.
|
||||
* @param {number[][]} polygon the target polygon
|
||||
* @param {number} maxSegmentLength the maximum amount of points
|
||||
*/
|
||||
function bisect(polygon, maxSegmentLength = Infinity) {
|
||||
let a = [];
|
||||
let b = [];
|
||||
|
||||
for (let i = 0; i < polygon.length; i += 1) {
|
||||
a = polygon[i];
|
||||
b = i === polygon.length - 1 ? polygon[0] : polygon[i + 1];
|
||||
|
||||
// Could splice the whole set for a segment instead, but a bit messy
|
||||
while (distanceSquareRoot(a, b) > maxSegmentLength) {
|
||||
b = midPoint(a, b, 0.5);
|
||||
polygon.splice(i + 1, 0, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the validity of a polygon.
|
||||
* @param {KUTE.polygonMorph} polygon the target polygon
|
||||
* @returns {boolean} the result of the check
|
||||
*/
|
||||
function validPolygon(polygon) {
|
||||
return Array.isArray(polygon)
|
||||
&& polygon.every((point) => Array.isArray(point)
|
||||
&& point.length === 2
|
||||
&& !Number.isNaN(point[0])
|
||||
&& !Number.isNaN(point[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new polygon and its length from string or another `Array`.
|
||||
* @param {KUTE.polygonMorph | string} input the target polygon
|
||||
* @param {number} maxSegmentLength the maximum amount of points
|
||||
* @returns {KUTE.polygonMorph} normalized polygon
|
||||
*/
|
||||
function getPolygon(input, maxSegmentLength) {
|
||||
let skipBisect;
|
||||
let polygon;
|
||||
|
||||
if (typeof (input) === 'string') {
|
||||
const converted = pathStringToPolygon(input, maxSegmentLength);
|
||||
({ polygon, skipBisect } = converted);
|
||||
} else if (!Array.isArray(input)) {
|
||||
throw Error(`${invalidPathValue}: ${input}`);
|
||||
}
|
||||
|
||||
/** @type {KUTE.polygonMorph} */
|
||||
const points = [...polygon];
|
||||
|
||||
if (!validPolygon(points)) {
|
||||
throw Error(`${invalidPathValue}: ${points}`);
|
||||
}
|
||||
|
||||
// TODO skip this test to avoid scale issues?
|
||||
// Chosen epsilon (1e-6) is problematic for small coordinate range, we now use 1e-9
|
||||
if (points.length > 1 && distanceSquareRoot(points[0], points[points.length - 1]) < epsilon) {
|
||||
points.pop();
|
||||
}
|
||||
|
||||
if (!skipBisect && maxSegmentLength
|
||||
&& !Number.isNaN(maxSegmentLength) && (+maxSegmentLength) > 0) {
|
||||
bisect(points, maxSegmentLength);
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns two new polygons ready to tween.
|
||||
* @param {string} path1 the first path string
|
||||
* @param {string} path2 the second path string
|
||||
* @param {number} precision the morphPrecision option value
|
||||
* @returns {KUTE.polygonMorph[]} the two polygons
|
||||
*/
|
||||
function getInterpolationPoints(path1, path2, precision) {
|
||||
const morphPrecision = precision || defaultOptions.morphPrecision;
|
||||
const fromRing = getPolygon(path1, morphPrecision);
|
||||
const toRing = getPolygon(path2, morphPrecision);
|
||||
const diff = fromRing.length - toRing.length;
|
||||
|
||||
addPoints(fromRing, diff < 0 ? diff * -1 : 0);
|
||||
addPoints(toRing, diff > 0 ? diff : 0);
|
||||
|
||||
rotatePolygon(fromRing, toRing);
|
||||
|
||||
return [roundPath(fromRing), roundPath(toRing)];
|
||||
}
|
||||
|
||||
// Component functions
|
||||
/**
|
||||
* Returns the current `d` attribute value.
|
||||
* @returns {string} the `d` attribute value
|
||||
*/
|
||||
function getSVGMorph(/* tweenProp */) {
|
||||
return this.element.getAttribute('d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string | KUTE.polygonObject} value the property value
|
||||
* @returns {KUTE.polygonObject} the property tween object
|
||||
*/
|
||||
function prepareSVGMorph(/* tweenProp */_, value) {
|
||||
const pathObject = {};
|
||||
// remove newlines, they brake JSON strings sometimes
|
||||
const pathReg = new RegExp('\\n', 'ig');
|
||||
let elem = null;
|
||||
|
||||
if (value instanceof SVGPathElement) {
|
||||
elem = value;
|
||||
} else if (/^\.|^#/.test(value)) {
|
||||
elem = selector(value);
|
||||
}
|
||||
|
||||
// first make sure we return pre-processed values
|
||||
if (typeof (value) === 'object' && value.polygon) {
|
||||
return value;
|
||||
} if (elem && ['path', 'glyph'].includes(elem.tagName)) {
|
||||
pathObject.original = elem.getAttribute('d').replace(pathReg, '');
|
||||
// maybe it's a string path already
|
||||
} else if (!elem && typeof (value) === 'string') {
|
||||
pathObject.original = value.replace(pathReg, '');
|
||||
}
|
||||
|
||||
return pathObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the `to()` method by preparing the tween object in advance.
|
||||
* @param {string} prop the `path` property name
|
||||
*/
|
||||
function crossCheckSVGMorph(prop) {
|
||||
if (this.valuesEnd[prop]) {
|
||||
const pathArray1 = this.valuesStart[prop].polygon;
|
||||
const pathArray2 = this.valuesEnd[prop].polygon;
|
||||
// skip already processed paths
|
||||
// allow the component to work with pre-processed values
|
||||
if (!pathArray1 || !pathArray2
|
||||
|| (pathArray1 && pathArray2 && pathArray1.length !== pathArray2.length)) {
|
||||
const p1 = this.valuesStart[prop].original;
|
||||
const p2 = this.valuesEnd[prop].original;
|
||||
// process morphPrecision
|
||||
const morphPrecision = this._morphPrecision
|
||||
? parseInt(this._morphPrecision, 10)
|
||||
: defaultOptions.morphPrecision;
|
||||
|
||||
const [path1, path2] = getInterpolationPoints(p1, p2, morphPrecision);
|
||||
this.valuesStart[prop].polygon = path1;
|
||||
this.valuesEnd[prop].polygon = path2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const svgMorphFunctions = {
|
||||
prepareStart: getSVGMorph,
|
||||
prepareProperty: prepareSVGMorph,
|
||||
onStart: onStartSVGMorph,
|
||||
crossCheck: crossCheckSVGMorph,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const SVGMorph = {
|
||||
component: 'svgMorph',
|
||||
property: 'path',
|
||||
defaultValue: [],
|
||||
Interpolate: coords,
|
||||
defaultOptions: { morphPrecision: 10 },
|
||||
functions: svgMorphFunctions,
|
||||
// Export utils to global for faster execution
|
||||
Util: {
|
||||
// component
|
||||
addPoints,
|
||||
bisect,
|
||||
getPolygon,
|
||||
validPolygon,
|
||||
getInterpolationPoints,
|
||||
pathStringToPolygon,
|
||||
distanceSquareRoot,
|
||||
midPoint,
|
||||
approximatePolygon,
|
||||
rotatePolygon,
|
||||
// svg-path-commander
|
||||
pathToString,
|
||||
pathToCurve,
|
||||
getTotalLength,
|
||||
getPointAtLength,
|
||||
polygonArea,
|
||||
roundPath,
|
||||
},
|
||||
};
|
||||
|
||||
export default SVGMorph;
|
|
@ -1,34 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import coords from '../interpolation/coords';
|
||||
|
||||
/* SVGMorph = {
|
||||
property: 'path',
|
||||
defaultValue: [],
|
||||
interpolators: {numbers,coords} },
|
||||
functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
} */
|
||||
|
||||
// Component functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartSVGMorph(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
const path1 = a.polygon; const path2 = b.polygon;
|
||||
const len = path2.length;
|
||||
elem.setAttribute('d', (v === 1 ? b.original : `M${coords(path1, path2, len, v).join('L')}Z`));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const SVGMorphBase = {
|
||||
component: 'baseSVGMorph',
|
||||
property: 'path',
|
||||
Interpolate: coords,
|
||||
functions: { onStart: onStartSVGMorph },
|
||||
};
|
||||
|
||||
export default SVGMorphBase;
|
|
@ -1,196 +0,0 @@
|
|||
import numbers from '../interpolation/numbers';
|
||||
import { svgTransformOnStart } from './svgTransformBase';
|
||||
|
||||
// Component Util
|
||||
/**
|
||||
* Returns a correct transform origin consistent with the shape bounding box.
|
||||
* @param {string} origin transform origin string
|
||||
* @param {SVGPathCommander.pathBBox} bbox path bounding box
|
||||
* @returns {number}
|
||||
*/
|
||||
function parseStringOrigin(origin, bbox) {
|
||||
let result;
|
||||
const { x, width } = bbox;
|
||||
if (/[a-z]/i.test(origin) && !/px/.test(origin)) {
|
||||
result = origin.replace(/top|left/, 0)
|
||||
.replace(/right|bottom/, 100)
|
||||
.replace(/center|middle/, 50);
|
||||
} else {
|
||||
result = /%/.test(origin) ? (x + (parseFloat(origin) * width) / 100) : parseFloat(origin);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse SVG transform string and return an object.
|
||||
* @param {string} a transform string
|
||||
* @returns {Object<string, (string | number)>}
|
||||
*/
|
||||
function parseTransformString(a) {
|
||||
const c = {};
|
||||
const d = a && /\)/.test(a)
|
||||
? a.substring(0, a.length - 1).split(/\)\s|\)/)
|
||||
: 'none';
|
||||
|
||||
if (d instanceof Array) {
|
||||
for (let j = 0, jl = d.length; j < jl; j += 1) {
|
||||
const [prop, val] = d[j].trim().split('(');
|
||||
c[prop] = val;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SVG transform tween object.
|
||||
* @param {string} _ property name
|
||||
* @param {Object<string, (string | number)>} v property value object
|
||||
* @returns {KUTE.transformSVGObject} the SVG transform tween object
|
||||
*/
|
||||
function parseTransformSVG(/* prop */_, v) {
|
||||
/** @type {KUTE.transformSVGObject} */
|
||||
const svgTransformObject = {};
|
||||
|
||||
// by default the transformOrigin is "50% 50%" of the shape box
|
||||
const bb = this.element.getBBox();
|
||||
const cx = bb.x + bb.width / 2;
|
||||
const cy = bb.y + bb.height / 2;
|
||||
|
||||
let origin = this._transformOrigin;
|
||||
let translation;
|
||||
|
||||
if (typeof (origin) !== 'undefined') {
|
||||
origin = origin instanceof Array ? origin : origin.split(/\s/);
|
||||
} else {
|
||||
origin = [cx, cy];
|
||||
}
|
||||
|
||||
origin[0] = typeof origin[0] === 'number' ? origin[0] : parseStringOrigin(origin[0], bb);
|
||||
origin[1] = typeof origin[1] === 'number' ? origin[1] : parseStringOrigin(origin[1], bb);
|
||||
|
||||
svgTransformObject.origin = origin;
|
||||
|
||||
// populate the valuesStart and / or valuesEnd
|
||||
Object.keys(v).forEach((i) => {
|
||||
if (i === 'rotate') {
|
||||
if (typeof v[i] === 'number') {
|
||||
svgTransformObject[i] = v[i];
|
||||
} else if (v[i] instanceof Array) {
|
||||
[svgTransformObject[i]] = v[i];
|
||||
} else {
|
||||
svgTransformObject[i] = v[i].split(/\s/)[0] * 1;
|
||||
}
|
||||
} else if (i === 'translate') {
|
||||
if (v[i] instanceof Array) {
|
||||
translation = v[i];
|
||||
} else if (/,|\s/.test(v[i])) {
|
||||
translation = v[i].split(',');
|
||||
} else {
|
||||
translation = [v[i], 0];
|
||||
}
|
||||
svgTransformObject[i] = [translation[0] * 1 || 0, translation[1] * 1 || 0];
|
||||
} else if (/skew/.test(i)) {
|
||||
svgTransformObject[i] = v[i] * 1 || 0;
|
||||
} else if (i === 'scale') {
|
||||
svgTransformObject[i] = parseFloat(v[i]) || 1;
|
||||
}
|
||||
});
|
||||
|
||||
return svgTransformObject;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} prop the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {KUTE.transformSVGObject} the property tween object
|
||||
*/
|
||||
function prepareSvgTransform(prop, value) {
|
||||
return parseTransformSVG.call(this, prop, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object with the current transform attribute value.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {string} current transform object
|
||||
*/
|
||||
function getStartSvgTransform(/* tweenProp */_, value) {
|
||||
const transformObject = {};
|
||||
const currentTransform = parseTransformString(this.element.getAttribute('transform'));
|
||||
|
||||
// find a value in current attribute value or add a default value
|
||||
Object.keys(value).forEach((j) => {
|
||||
const scaleValue = j === 'scale' ? 1 : 0;
|
||||
transformObject[j] = j in currentTransform ? currentTransform[j] : scaleValue;
|
||||
});
|
||||
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
function svgTransformCrossCheck(prop) {
|
||||
if (!this._resetStart) return; // fix since 1.6.1 for fromTo() method
|
||||
|
||||
if (this.valuesEnd[prop]) {
|
||||
const valuesStart = this.valuesStart[prop];
|
||||
const valuesEnd = this.valuesEnd[prop];
|
||||
const currentTransform = parseTransformSVG.call(this, prop,
|
||||
parseTransformString(this.element.getAttribute('transform')));
|
||||
|
||||
// populate the valuesStart first
|
||||
Object.keys(currentTransform).forEach((tp) => {
|
||||
valuesStart[tp] = currentTransform[tp];
|
||||
});
|
||||
|
||||
// now try to determine the REAL translation
|
||||
const parentSVG = this.element.ownerSVGElement;
|
||||
const startMatrix = parentSVG.createSVGTransformFromMatrix(
|
||||
parentSVG.createSVGMatrix()
|
||||
.translate(-valuesStart.origin[0], -valuesStart.origin[1]) // - origin
|
||||
.translate('translate' in valuesStart // the current translate
|
||||
? valuesStart.translate[0] : 0, 'translate' in valuesStart ? valuesStart.translate[1]
|
||||
: 0)
|
||||
.rotate(valuesStart.rotate || 0)
|
||||
.skewX(valuesStart.skewX || 0)
|
||||
.skewY(valuesStart.skewY || 0)
|
||||
.scale(valuesStart.scale || 1)// the other functions
|
||||
.translate(+valuesStart.origin[0], +valuesStart.origin[1]), // + origin
|
||||
);
|
||||
// finally the translate we're looking for
|
||||
valuesStart.translate = [startMatrix.matrix.e, startMatrix.matrix.f];
|
||||
|
||||
// copy existing and unused properties to the valuesEnd
|
||||
Object.keys(valuesStart).forEach((s) => {
|
||||
if (!(s in valuesEnd) || s === 'origin') {
|
||||
valuesEnd[s] = valuesStart[s];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
export const svgTransformFunctions = {
|
||||
prepareStart: getStartSvgTransform,
|
||||
prepareProperty: prepareSvgTransform,
|
||||
onStart: svgTransformOnStart,
|
||||
crossCheck: svgTransformCrossCheck,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
export const svgTransform = {
|
||||
component: 'svgTransformProperty',
|
||||
property: 'svgTransform',
|
||||
// subProperties: ['translate','rotate','skewX','skewY','scale'],
|
||||
defaultOptions: { transformOrigin: '50% 50%' },
|
||||
defaultValue: {
|
||||
translate: 0, rotate: 0, skewX: 0, skewY: 0, scale: 1,
|
||||
},
|
||||
Interpolate: { numbers },
|
||||
functions: svgTransformFunctions,
|
||||
|
||||
// export utils to globals for faster execution
|
||||
Util: { parseStringOrigin, parseTransformString, parseTransformSVG },
|
||||
};
|
||||
|
||||
export default svgTransform;
|
|
@ -1,63 +0,0 @@
|
|||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function svgTransformOnStart(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KEC[tweenProp] = (l, a, b, v) => {
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
const deg = Math.PI / 180;
|
||||
const scale = 'scale' in b ? numbers(a.scale, b.scale, v) : 1;
|
||||
const rotate = 'rotate' in b ? numbers(a.rotate, b.rotate, v) : 0;
|
||||
const sin = Math.sin(rotate * deg);
|
||||
const cos = Math.cos(rotate * deg);
|
||||
const skewX = 'skewX' in b ? numbers(a.skewX, b.skewX, v) : 0;
|
||||
const skewY = 'skewY' in b ? numbers(a.skewY, b.skewY, v) : 0;
|
||||
const complex = rotate || skewX || skewY || scale !== 1 || 0;
|
||||
|
||||
// start normalizing the translation, we start from last to first
|
||||
// (from last chained translation)
|
||||
// the normalized translation will handle the transformOrigin tween option
|
||||
// and makes sure to have a consistent transformation
|
||||
|
||||
// we start with removing transformOrigin from translation
|
||||
x -= complex ? b.origin[0] : 0; y -= complex ? b.origin[1] : 0;
|
||||
x *= scale; y *= scale; // we now apply the scale
|
||||
// now we apply skews
|
||||
y += skewY ? x * Math.tan(skewY * deg) : 0; x += skewX ? y * Math.tan(skewX * deg) : 0;
|
||||
const cxsy = cos * x - sin * y; // apply rotation as well
|
||||
y = rotate ? sin * x + cos * y : y; x = rotate ? cxsy : x;
|
||||
// now we apply the actual translation
|
||||
x += 'translate' in b ? numbers(a.translate[0], b.translate[0], v) : 0;
|
||||
y += 'translate' in b ? numbers(a.translate[1], b.translate[1], v) : 0;
|
||||
// normalizing ends with the addition of the transformOrigin to the translation
|
||||
x += complex ? b.origin[0] : 0; y += complex ? b.origin[1] : 0;
|
||||
|
||||
// finally we apply the transform attribute value
|
||||
/* eslint no-bitwise: ["error", { "allow": [">>"] }] */
|
||||
l.setAttribute('transform', (x || y ? (`translate(${(x * 1000 >> 0) / 1000}${y ? (`,${(y * 1000 >> 0) / 1000}`) : ''})`) : '')
|
||||
+ (rotate ? `rotate(${(rotate * 1000 >> 0) / 1000})` : '')
|
||||
+ (skewX ? `skewX(${(skewX * 1000 >> 0) / 1000})` : '')
|
||||
+ (skewY ? `skewY(${(skewY * 1000 >> 0) / 1000})` : '')
|
||||
+ (scale !== 1 ? `scale(${(scale * 1000 >> 0) / 1000})` : ''));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseSVGTransform = {
|
||||
component: 'baseSVGTransform',
|
||||
property: 'svgTransform',
|
||||
// subProperties: ['translate','rotate','skewX','skewY','scale'],
|
||||
// defaultValue: {translate:0, rotate:0, skewX:0, skewY:0, scale:1},
|
||||
defaultOptions: { transformOrigin: '50% 50%' },
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: svgTransformOnStart },
|
||||
};
|
||||
|
||||
export default baseSVGTransform;
|