Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
ae0b200694 | |||
91fb7aad8f | |||
3835b6e95c | |||
5c8b75f15b | |||
8f5c58195e | |||
0dac43bc88 | |||
a17bacbd58 | |||
2a5bac2bb3 | |||
e5456b86e9 | |||
d96d08a36b | |||
0290fa67cb | |||
5dfbf91ce3 | |||
c786e062c0 | |||
cd0898b67f | |||
b70d46d387 | |||
f56e19369a | |||
b36f26195c | |||
ebd86bf9e3 | |||
b0f6220413 | |||
0efd9a10e4 | |||
2a309434c1 | |||
a1f59fe181 | |||
c011a9368b | |||
933d61de19 | |||
bfc3fabc92 | |||
14585d7a51 |
41
.eslintrc
Normal file
41
.eslintrc
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
}
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
node_modules/
|
||||
experiments/
|
||||
.npmignore
|
||||
package-lock.json
|
|
@ -1,4 +1,5 @@
|
|||
node_modules/
|
||||
demo/
|
||||
experiments/
|
||||
package-lock.json
|
||||
.gitignore
|
|
@ -1,6 +1,6 @@
|
|||
# KUTE.js
|
||||
|
||||
A modern JavaScript animation engine built on ES6+ standards with most essential features for the web, delivering easy to use methods to set up high performance, cross-browser animations. The focus is code quality, flexibility, performance and size.
|
||||
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)
|
||||
|
@ -41,9 +41,11 @@ All above mentioned components have a BASE version which doesn't include value p
|
|||
# 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.
|
||||
|
@ -51,8 +53,10 @@ KUTE.js is redeveloped for maximum performance on modern browsers. Some legacy b
|
|||
* [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)
|
||||
|
|
|
@ -440,7 +440,7 @@ pre.language-markup:after {
|
|||
font-size: 12px; color: #999;
|
||||
}
|
||||
|
||||
pre.language-javascript:after {content: 'Javascript';}
|
||||
pre.language-javascript:after {content: 'JavaScript';}
|
||||
pre.language-clike:after {content: 'node';}
|
||||
pre.language-markup:after {content: 'HTML';}
|
||||
pre code {background: none;padding: 0; font-weight: normal; font-size: 100%;}
|
||||
|
|
|
@ -78,18 +78,18 @@ function complete(){
|
|||
container.style.display = 'none';
|
||||
}
|
||||
|
||||
var engine = document.getElementById('kute'),
|
||||
fromCSS = { rotate3d: [ 0, 0,0 ], perspective:600 },
|
||||
fromMX = { transform: { rotate3d: [ 0, 0,0 ], perspective:600 }},
|
||||
toCSS = { rotate3d: [ 360,0,0 ], perspective:600 },
|
||||
toMX = { transform: { rotate3d: [ 0,360,0 ], perspective:600 }},
|
||||
ops = { duration: 2000, repeat: 5 }
|
||||
var engine = document.getElementById('kute'),
|
||||
fromCSS = { rotate3d: [ 0, 0,0 ], perspective:600 },
|
||||
fromMX = { transform: { rotate3d: [ 0, 0,0 ], perspective:600 }},
|
||||
toCSS = { rotate3d: [ 360,0,0 ], perspective:600 },
|
||||
toMX = { transform: { rotate3d: [ 0,360,0 ], perspective:600 }},
|
||||
ops = { duration: 2000, repeat: 5 }
|
||||
|
||||
// since our engines don't do sync, we make it our own here
|
||||
if (engine.src.indexOf('kute.min.js')>-1) {
|
||||
if (!engine.src.includes('extra')) {
|
||||
[].slice.call(collection).map((el,i) => { i===lastIdx && (ops.onComplete = complete); tws.push ( KUTE.fromTo(el,fromCSS,toCSS,ops) ) })
|
||||
}
|
||||
if (engine.src.indexOf('kute-extra.min.js')>-1) {
|
||||
if (engine.src.includes('extra')) {
|
||||
[].slice.call(collection).map((el,i) => { i===lastIdx && (ops.onComplete = complete); tws.push ( KUTE.fromTo(el,fromMX,toMX,ops) ) })
|
||||
}
|
||||
|
||||
|
@ -98,15 +98,13 @@ function startTest(){
|
|||
infoContainer.style.display = 'none';
|
||||
container.style.display = 'block'
|
||||
|
||||
!tws[0].playing && startKUTE();
|
||||
tws.length && !tws[0].playing && startKUTE();
|
||||
}
|
||||
|
||||
|
||||
function startKUTE() {
|
||||
var now = window.performance.now(), count = tws.length;
|
||||
for (var t=0; t<count; t++){
|
||||
tws[t].start(now)
|
||||
}
|
||||
tws.forEach((t) => t.start(now));
|
||||
}
|
||||
|
||||
// the start button handle
|
||||
|
|
|
@ -5,28 +5,22 @@ var morphOps = {
|
|||
|
||||
// basic morph
|
||||
var morphTween = KUTE.to('#rectangle', { path: '#star' }, morphOps);
|
||||
var morphTween1 = KUTE.to('#rectangle1', { path: '#star1' }, morphOps);
|
||||
var morphTween2 = KUTE.to('#rectangle2', { path: '#star2' }, morphOps);
|
||||
|
||||
var morphBtn = document.getElementById('morphBtn');
|
||||
morphBtn.addEventListener('click', function(){
|
||||
!morphTween.playing && morphTween.start();
|
||||
!morphTween1.playing && morphTween1.start();
|
||||
!morphTween2.playing && morphTween2.start();
|
||||
}, false);
|
||||
|
||||
// line to circle
|
||||
var lineMorph = KUTE.to('#line' ,{path:'#circle' }, morphOps);
|
||||
var lineMorph1 = KUTE.to('#line1',{path:'#circle1'}, morphOps);
|
||||
var lineMorph2 = KUTE.to('#line2',{path:'#circle2'}, morphOps);
|
||||
var lineMorph3 = KUTE.to('#line3',{path:'#circle3'}, morphOps);
|
||||
var morphBtnClosed = document.getElementById('morphBtnClosed')
|
||||
|
||||
var morphBtnClosed = document.getElementById('morphBtnClosed')
|
||||
morphBtnClosed.addEventListener('click', function(){
|
||||
!lineMorph.playing && lineMorph.start();
|
||||
!lineMorph1.playing && lineMorph1.start();
|
||||
!lineMorph2.playing && lineMorph2.start();
|
||||
!lineMorph3.playing && lineMorph3.start();
|
||||
}, false);
|
||||
|
||||
var morphOps1 = {
|
||||
|
@ -63,19 +57,14 @@ var compliMorph2 = KUTE.fromTo('#symbol-left', {path: '#symbol-left'}, { path:
|
|||
var compliMorph3 = KUTE.fromTo('#symbol-left-clone', {path: '#symbol-left-clone'}, { path: '#mouth' }, morphOps1);
|
||||
var compliMorph4 = KUTE.fromTo('#symbol-right', {path: '#symbol-right'}, { path: '#eye-right' }, morphOps1);
|
||||
|
||||
var compliMorph11 = KUTE.fromTo('#rectangle-container1', {path: '#rectangle-container1', attr:{ fill: "#9C27B0"} }, { path: '#circle-container1', attr:{ fill: "#FF5722"} }, morphOps1);
|
||||
var compliMorph21 = KUTE.fromTo('#symbol-left1', {path: '#symbol-left1'}, { path: '#eye-left1' }, morphOps1);
|
||||
var compliMorph31 = KUTE.fromTo('#symbol-left-clone1', {path: '#symbol-left-clone1'}, { path: '#mouth1' }, morphOps1);
|
||||
var compliMorph41 = KUTE.fromTo('#symbol-right1', {path: '#symbol-right1'}, { path: '#eye-right1' }, morphOps1);
|
||||
|
||||
var compliMorph12 = KUTE.fromTo('#rectangle-container2', {path: '#rectangle-container2', attr:{ fill: "#e91b1f"} }, { path: '#circle-container2', attr:{ fill: "#FF5722"} }, morphOps1);
|
||||
var compliMorph22 = KUTE.fromTo('#symbol-left2', {path: '#symbol-left2'}, { path: '#eye-left2' }, morphOps1);
|
||||
var compliMorph32 = KUTE.fromTo('#sample-shape2', {path: '#sample-shape2'}, { path: '#mouth2' }, morphOps1);
|
||||
var compliMorph42 = KUTE.fromTo('#symbol-right2', {path: '#symbol-right2'}, { path: '#eye-right2' }, morphOps1);
|
||||
|
||||
compliMorphBtn.addEventListener('click', function(){
|
||||
!compliMorph1.playing && compliMorph1.start() && compliMorph11.start() && compliMorph12.start();
|
||||
!compliMorph2.playing && compliMorph2.start() && compliMorph21.start() && compliMorph22.start();
|
||||
!compliMorph3.playing && compliMorph3.start() && compliMorph31.start() && compliMorph32.start();
|
||||
!compliMorph4.playing && compliMorph4.start() && compliMorph41.start() && compliMorph42.start();
|
||||
!compliMorph1.playing && compliMorph1.start() && compliMorph12.start();
|
||||
!compliMorph2.playing && compliMorph2.start() && compliMorph22.start();
|
||||
!compliMorph3.playing && compliMorph3.start() && compliMorph32.start();
|
||||
!compliMorph4.playing && compliMorph4.start() && compliMorph42.start();
|
||||
}, false);
|
|
@ -6,10 +6,11 @@ var translateExamples = document.getElementById('translate-examples'),
|
|||
trx = translateExamples.getElementsByTagName('div')[1],
|
||||
trry = translateExamples.getElementsByTagName('div')[2],
|
||||
trz = translateExamples.getElementsByTagName('div')[3],
|
||||
tr2dTween = KUTE.to(tr2d, {translate:[170,0]}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500}),
|
||||
trxTween = KUTE.to(trx, {translateX:-170}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500})
|
||||
tr2dTween = KUTE.to(tr2d, {translate:[170,170]}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500}),
|
||||
trxTween = KUTE.to(trx, {translateX:-170}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500}),
|
||||
trryTween = KUTE.to(trry, {translate3d:[0,170,0]}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500}),
|
||||
trzTween = KUTE.to(trz, {perspective:200, translate3d:[0,0,-100]}, {easing:'easingCubicOut', yoyo:true, repeat: 1, duration:1500});
|
||||
|
||||
translateBtn.addEventListener('click', function(){
|
||||
!tr2dTween.playing && tr2dTween.start();
|
||||
!trxTween.playing && trxTween.start();
|
||||
|
@ -27,6 +28,7 @@ var rotExamples = document.getElementById('rotExamples'),
|
|||
rxTween = KUTE.to(rx, {rotateX:180}, {easing:'linear', yoyo:true, repeat: 1, duration:1500}),
|
||||
ryTween = KUTE.to(ry, {perspective:200, rotate3d:[0,-180,0],scale:1.2}, {easing:'easingCubicInOut', yoyo:true, repeat: 1, duration:1500}),
|
||||
rzTween = KUTE.to(rz, {rotateZ:360}, {easing:'easingBackOut', yoyo:true, repeat: 1, duration:1500});
|
||||
|
||||
rotBtn.addEventListener('click', function(){
|
||||
!r2dTween.playing && r2dTween.start();
|
||||
!rxTween.playing && rxTween.start();
|
||||
|
|
|
@ -135,7 +135,7 @@ let bgPosTween = KUTE.to('selector1',{backgroundPosition:"left center"}).start()
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ KUTE.to('selector5',{borderBottomRightRadius:'20px'}).start();
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ let tween8 = KUTE.to('selector1',{margin:'5px'})
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ KUTE.to('selector1',{borderColor:'turquoise'}).start(); // IE9+
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ let fe4 = KUTE.to('selector4', {filter :{ url: '#mySVGFilter', opacity: 40, drop
|
|||
<div class="example-item example-box" style="background: url('https://picsum.photos/400/300') center center no-repeat; filter: url(#mySVGFilter)">FE1</div>
|
||||
<div class="example-item example-box" style="background: url('https://picsum.photos/400/300') center center no-repeat; filter: url(#mySVGFilter)">FE2</div>
|
||||
<div class="example-item example-box" style="background: url('https://picsum.photos/400/300') center center no-repeat; filter: url(#mySVGFilter)">FE3</div>
|
||||
<div class="example-item example-box" style="background: url('https://picsum.photos/400/300') center center no-repeat; filter: url(#mySVGFilter)">FE4</div>
|
||||
<div class="example-item example-box" style="background: url('https://picsum.photos/400/300') center center no-repeat">FE4</div>
|
||||
|
||||
<div class="example-buttons">
|
||||
<a class="btn btn-blue" href="javascript:void(0)">Start</a>
|
||||
|
@ -169,7 +169,7 @@ let fe4 = KUTE.to('selector4', {filter :{ url: '#mySVGFilter', opacity: 40, drop
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ var rotatingGradient = KUTE.to('#gradient', {attr: {x1:'49%', x2:'51%', y1:'51%'
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div><!-- /.site-wrapper -->
|
||||
|
|
|
@ -270,7 +270,7 @@
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ let fadeInTween = KUTE.to('selector1',{opacity:1}).start()
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -203,7 +203,9 @@
|
|||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/bootstrap.native/1.0.1/bootstrap-native.min.js"></script>
|
||||
<!-- <script src="../experiments/CSSMatrix.js"></script> -->
|
||||
<script id="kute" src="./src/kute-extra.min.js"></script>
|
||||
<!-- <script id="kute" src="./src/kute-extra.js"></script> -->
|
||||
<script src="./assets/js/perf-matrix.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ document.getElementById('rectangle').addEventListener('click',function(){
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ KUTE.to('#myElement',{scroll: 0 }).start()
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ var myTSTween2 = KUTE.fromTo(
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
4
demo/src/kute-base.min.js
vendored
4
demo/src/kute-base.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
4
demo/src/kute-extra.min.js
vendored
4
demo/src/kute-extra.min.js
vendored
File diff suppressed because one or more lines are too long
4
demo/src/kute.min.js
vendored
4
demo/src/kute.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/src/polyfill-legacy.min.js
vendored
2
demo/src/polyfill-legacy.min.js
vendored
|
@ -1,3 +1,3 @@
|
|||
// KUTE.js Polyfill v2.0.14 | 2020 © thednp | MIT-License
|
||||
// KUTE.js Polyfill v2.1.1-alpha1 | 2021 © thednp | MIT-License
|
||||
"use strict";
|
||||
var r,t,n,e;if(Function.prototype.bind||(Function.prototype.bind=function(){var r=Array.prototype.slice,t=this,n=arguments[0],e=r.call(arguments,1);if("function"!=typeof t)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");return function(){var o=e.concat(r.call(arguments));return t.apply(n,o)}}),Array.from||(Array.from=(r=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===r.call(t)},n=Math.pow(2,53)-1,e=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),n)},function(r){var n=this,o=Object(r);if(null==r)throw new TypeError("Array.from requires an array-like object - not null or undefined");var i,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&&(i=arguments[2])}for(var u,f=e(o.length),p=t(n)?Object(new n(f)):new Array(f),c=0;c<f;)u=o[c],p[c]=a?void 0===i?a(u,c):a.call(i,u,c):u,c+=1;return p.length=f,p})),Array.prototype.map||(Array.prototype.map=function(r){var t,n,e;if(null==this)throw new TypeError("this is null or not defined");var o=Object(this),i=o.length>>>0;if("function"!=typeof r)throw new TypeError(r+" is not a function");for(arguments.length>1&&(t=arguments[1]),n=new Array(i),e=0;e<i;){var a,u;e in o&&(a=o[e],u=r.call(t,a,e,o),n[e]=u),e++}return n}),Array.prototype.some||(Array.prototype.some=function(r,t){if(null==this)throw new TypeError("Array.prototype.some called on null or undefined");if("function"!=typeof r)throw new TypeError;for(var n=Object(this),e=n.length>>>0,o=0;o<e;o++)if(o in n&&r.call(t,n[o],o,n))return!0;return!1}),Array.prototype.every||(Array.prototype.every=function(r,t){var n,e;if(null==this)throw new TypeError("this is null or not defined");var o=Object(this),i=o.length>>>0;if("function"!=typeof r&&"[object Function]"!==Object.prototype.toString.call(r))throw new TypeError;for(arguments.length>1&&(n=t),e=0;e<i;){var a;if(e in o)if(a=o[e],!(n?r.call(n,a,e,o):r(a,e,o)))return!1;e++}return!0}),Array.prototype.includes||(Array.prototype.includes=function(r){var t=Object(this),n=parseInt(t.length)||0;if(0===n)return!1;var e,o,i=parseInt(arguments[1])||0;for(i>=0?e=i:(e=n+i)<0&&(e=0);e<n;){if(r===(o=t[e])||r!=r&&o!=o)return!0;e++}return!1}),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(n,e){return Array.isArray(e)?n.push.apply(n,r.call(e,t-1)):n.push(e),n}),[]):Array.prototype.slice.call(this)},writable:!0}),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)}),Date.now||(Date.now=function(){return(new Date).getTime()}),self.performance||(self.performance={}),!self.performance.now){var o=Date.now();self.performance.now=function(){return Date.now()-o}}if(!window.requestAnimationFrame){var i=Date.now();window.requestAnimationFrame=function(r){if("function"!=typeof r)throw new TypeError(r+"is not a function");var t=Date.now(),n=16+i-t;return n<0&&(n=0),i=t,setTimeout((function(){i=Date.now(),r(performance.now())}),n)},window.cancelAnimationFrame=function(r){clearTimeout(r)}}
|
||||
|
|
4
demo/src/polyfill.min.js
vendored
4
demo/src/polyfill.min.js
vendored
|
@ -1,3 +1,3 @@
|
|||
// KUTE.js Polyfill v2.0.14 | 2020 © thednp | MIT-License
|
||||
// KUTE.js Polyfill v2.1.1-alpha1 | 2021 © thednp | MIT-License
|
||||
"use strict";
|
||||
var r,t,n,e;Array.from||(Array.from=(r=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===r.call(t)},n=Math.pow(2,53)-1,e=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),n)},function(r){var n=this,o=Object(r);if(null==r)throw new TypeError("Array.from requires an array-like object - not null or undefined");var i,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&&(i=arguments[2])}for(var u,f=e(o.length),c=t(n)?Object(new n(f)):new Array(f),p=0;p<f;)u=o[p],c[p]=a?void 0===i?a(u,p):a.call(i,u,p):u,p+=1;return c.length=f,c})),Array.prototype.includes||(Array.prototype.includes=function(r){var t=Object(this),n=parseInt(t.length)||0;if(0===n)return!1;var e,o,i=parseInt(arguments[1])||0;for(i>=0?e=i:(e=n+i)<0&&(e=0);e<n;){if(r===(o=t[e])||r!=r&&o!=o)return!0;e++}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)});
|
||||
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});
|
||||
|
|
|
@ -94,9 +94,9 @@
|
|||
<p>The component will process paths and out of the box will provide the closest possible interpolation by default. It also implements a series of solutions from
|
||||
<a href="https://github.com/paperjs/paper.js/">Paper.js</a> to determine paths draw direction and automatically reverse one of them for most accurate presentation and as a result
|
||||
the previously featured options <kbd>reverseFirstPath</kbd> and <kbd>reverseSecondPath</kbd> have been deprecated.</p>
|
||||
<p>The main difference with the <a href="svgMorph.html">SVG Morph</a> component is the fact that this components is converting all path commands to <i>cubicBezierTo</i>,
|
||||
giving it the upper hand over the original morph component. While the other component will spend time to process the path data and create polygons, this component should deliver
|
||||
the animation faster and using considerably less power.</p>
|
||||
<p>The main difference with the <a href="svgMorph.html">SVG Morph</a> component is the fact that this components is converting all path commands to <i>cubicBezierTo</i>, giving it
|
||||
the upper hand over the original morph component in many regards. While the other component will spend time to process the path data and create polygons, this component should
|
||||
deliver the animation faster and using considerably less power.</p>
|
||||
<p>All path processing is powered by our <a href="https://github.com/thednp/svg-path-commander">SVGPathCommander</a> starting KUTE.js version 2.0.14, which aims to modernize and
|
||||
improve the path processing and enable transition from closed to and from un-closed shapes.</p>
|
||||
</div>
|
||||
|
@ -131,13 +131,9 @@ var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864
|
|||
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="rectangle" class="bg-red" d="M559,597.4H43.6c-21,0-38-17-38-38V44c0-21,17-38,38-38H559c21,0,38,17,38,38v515.4 C597,580.4,580,597.4,559,597.4z"/>
|
||||
<path id="rectangle" class="bg-olive" d="M559,597.4H43.6c-21,0-38-17-38-38V44c0-21,17-38,38-38H559c21,0,38,17,38,38v515.4 C597,580.4,580,597.4,559,597.4z"/>
|
||||
<path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011z"/>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="morph-example1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="rectangle1" class="bg-olive" d="M559,597.4H43.6c-21,0-38-17-38-38V44c0-21,17-38,38-38H559c21,0,38,17,38,38v515.4 C597,580.4,580,597.4,559,597.4"/>
|
||||
<path id="star1" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"/>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="morph-example2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="rectangle2" class="bg-blue" d="M559,597.4H302.1H43.6c-21,0-38-17-38-38V300V44c0-21,17-38,38-38H300h259c21,0,38,17,38,38
|
||||
v257.7v257.7C597,580.4,580,597.4,559,597.4"/>
|
||||
|
@ -153,15 +149,12 @@ var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864
|
|||
|
||||
<p><b>Some takeaways:</b></p>
|
||||
<ul>
|
||||
<li>The <b class="text-red">red shape</b> and its corresponding end shape are both the originals, un-edited shapes, both have the <code>Z</code> path command, notice a strange line at the bottom-right of the rectangle
|
||||
during the animation. We'll have another example about that line.</li>
|
||||
<li>The <b class="text-olive">olive shape</b> and its corresponding end shape both have been edited by removing the <code>Z</code> path command, notice the strange line during the animation is gone, also a different
|
||||
presentation.</li>
|
||||
<li>The <b class="text-olive">olive shape</b> and its corresponding end shape are both the originals, un-edited shapes.</li>
|
||||
<li>The <b class="text-blue">blue shape</b> and its corresponding end shape have been edited by removing their <code>Z</code> path commands and by adding additional curve points using a vector graphics editor to match
|
||||
the amount of points in both shapes.</li>
|
||||
</ul>
|
||||
<p>In this example we focus on experimentation to discover ways to optimize the morph animation so that the points travel optimal distance. Keep in mind that the <code>Z</code> path command is actually a shorthand
|
||||
for <code>L</code> (line path command), sometimes it's required to close the shape, our shapes here happen to be OK without it.</p>
|
||||
for <code>L</code> (line path command), sometimes it's required to close the shape, however the path processing tools will remove it or replace it when converting path segments to <code>C</code> cubic-bezier.</p>
|
||||
<p>Each morph animation as well as each pair of shapes can have its own quirks. You can use the technique on your shapes to optimize the animation to your style. Chris Coyier wrote
|
||||
<a href="https://css-tricks.com/svg-shape-morphing-works/">an excelent article</a> in which he explains the terminology and workflow on how SVG morphing animation works with simple examples.</p>
|
||||
|
||||
|
@ -192,14 +185,6 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
|
|||
<path id="line1" fill="transparent" stroke="#4CAF50" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300"/>
|
||||
<path id="circle1" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0z"/>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="morph-example-closed2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="line2" fill="transparent" stroke="#2196F3" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300z"/>
|
||||
<path id="circle2" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0"/>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="morph-example-closed3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="line3" fill="transparent" stroke="#e91b1f" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300"/>
|
||||
<path id="circle3" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0"/>
|
||||
</svg>
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtnClosed" class="btn btn-green" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
|
@ -208,16 +193,12 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
|
|||
<p>As you can see, the functionality of this component is very different from the <a href="svgMorph.html">svgMorph</a> component in the sense that it will
|
||||
morph shapes as authored. If you replay the above animations, here are a few takeaways:</p>
|
||||
<ul>
|
||||
<li>the <b class="text-orange">orange</b> line and its corresponding shape are both closed, this makes the last <code>Z</code> path command behave like a regular
|
||||
line, perhaps not the best visual presentation;</li>
|
||||
<li>the <b class="text-green">green</b> line is not closed, but its corresponding shape is, still the <code>Z</code> path command seems to cause trouble, while
|
||||
the presentation looks a bit different;</li>
|
||||
<li>the <b class="text-blue">blue</b> line is now closed, but its corresponding shape isn't and with the <code>Z</code> path command missing from the second shape,
|
||||
the animation looks significantly better;</li>
|
||||
<li>the <b class="text-red">red</b> line and its corresponding shape are both not closed, another combination that delivers excellent outcome.</li>
|
||||
<li>the <b class="text-orange">orange</b> line is <b>closed</b>, this makes the last <code>Z</code> path command behave like a regular line;</li>
|
||||
<li>the <b class="text-green">green</b> line is <b>not closed</b>, and the presentation looks quite different compared to the other example as well as
|
||||
the other <a href="./cubicMorph.html">cubicMorph</a> component.</li>
|
||||
</ul>
|
||||
<p>As you can see, this is another case where easy steps can be made to optimize the visual presentation. Keep in mind that stroke attributes like
|
||||
<code>stroke-linejoin</code> such can have a small impact on your animation, particularly on start and end.</p>
|
||||
<p>This is the visual presentation you can expect with this component. Keep in mind that stroke attributes like <code>stroke-linejoin</code> such can have
|
||||
a small impact on your animation, particularly on start and end points.</p>
|
||||
|
||||
|
||||
<h3>Subpath Example</h3>
|
||||
|
@ -310,31 +291,6 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
|
|||
<path id="rectangle-container" fill="#2196F3" mask="url(#symbol)" d="M426.671 0h-341.328c-46.937 0-85.343 38.405-85.343 85.345v341.311c0 46.969 38.406 85.344 85.343 85.344h341.328c46.938 0 85.329-38.375 85.329-85.345v-341.31c0-46.94-38.391-85.345-85.329-85.345z"></path>
|
||||
<path id="circle-container" style="visibility: hidden;" d="M0,256a256,256 0 1,0 512,0a256,256 0 1,0 -512,0z"></path>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="complex-morph-example1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 513 513">
|
||||
<defs>
|
||||
<mask id="symbol1">
|
||||
<rect width="100%" height="100%" fill="#fff"></rect>
|
||||
<path id="symbol-left1" fill="#000" d="M155.889 333.394h-55.632c-3.351 0-5.854-1.504-7.271-3.792-1.467-2.379-1.542-5.464 0-8.534l59.11-104.313c0.063-0.114 0.063-0.19 0-0.316l-37.615-65.116c-1.556-3.098-1.783-6.157-0.316-8.534 1.417-2.301 4.235-3.477 7.586-3.477h55.632c8.535 0 12.72 5.499 15.489 10.431 0 0 38.020 66.33 38.249 66.696-2.252 3.97-60.059 106.21-60.059 106.21-2.844 5.131-6.852 10.745-15.173 10.745z"></path>
|
||||
<path id="symbol-left-clone1" fill="#000" d="M155.889 333.394h-55.632c-3.351 0-5.854-1.504-7.271-3.792-1.467-2.379-1.542-5.464 0-8.534l59.11-104.313c0.063-0.114 0.063-0.19 0-0.316l-37.615-65.116c-1.556-3.098-1.783-6.157-0.316-8.534 1.417-2.301 4.235-3.477 7.586-3.477h55.632c8.535 0 12.72 5.499 15.489 10.431 0 0 38.020 66.33 38.249 66.696-2.252 3.97-60.059 106.21-60.059 106.21-2.844 5.131-6.852 10.745-15.173 10.745z"></path>
|
||||
<path id="symbol-right1" fill="#000" d="M418.956 75.269l-123.176 217.79c-0.075 0.115-0.075 0.255 0 0.367l78.431 143.295c1.556 3.084 1.593 6.221 0.113 8.597-1.415 2.288-4.033 3.552-7.383 3.552h-55.57c-8.522 0-12.783-5.663-15.54-10.596 0 0-78.848-144.646-79.050-145.023 3.944-6.98 123.797-219.523 123.797-219.523 2.984-5.362 6.587-10.596 14.894-10.596h56.203c3.351 0 5.981 1.265 7.396 3.553 1.466 2.376 1.428 5.511-0.115 8.584z"></path>
|
||||
<path id="eye-right1" style="visibility: hidden;" d="M352,128c2.6,0,5,0.5,7.4,1.3c2.3,0.8,4.5,2,6.6,3.6c10.6,7.8,18,24.2,18,43.1c0,16.2-5.3,30.5-13.5,39.2
|
||||
c-3.1,3.3-6.6,5.8-10.5,7.3c-2.6,1-5.3,1.5-8,1.5c-4,0-7.8-1.1-11.3-3.1c-2.7-1.6-5.3-3.7-7.6-6.2c-7.9-8.7-13-22.8-13-38.7
|
||||
c0-19.2,7.5-35.7,18.4-43.4c1.9-1.4,4-2.5,6.1-3.2C346.9,128.5,349.4,128,352,128z"></path>
|
||||
<path id="eye-left1" style="visibility: hidden;" d="M176,156c10.4,0,19.7,1.4,27.5,3.9c14.5,4.7,23.5,13.4,23.5,24.8c0,3.7,1.9,21.5-0.1,24.8
|
||||
c-3.3-5.5-9.2-10.3-16.7-13.9c-5.6-2.7-12.2-4.8-19.4-6c-4.7-0.8-9.6-1.2-14.7-1.2c-8.9,0-17.3,1.3-24.7,3.5
|
||||
c-12.2,3.7-21.6,10-26.3,17.6c-2-3.3-0.1-21.1-0.1-24.8c0-11.3,8.8-19.9,23-24.6c3.7-1.2,7.8-2.2,12.2-2.9
|
||||
C165.1,156.4,170.4,156,176,156z"></path>
|
||||
<path id="mouth1" style="visibility: hidden;" d="M250.2,416c-42.9,0-82-16.6-111.5-43.9c-7-6.5-13.5-13.6-19.4-21.2c-3.8-4.9-7.3-10-10.6-15.4
|
||||
c5.6,4.4,11.9,8.2,18.7,11.5c7.1,3.4,14.8,6.2,23,8.4c33.9,9.2,76.7,8.9,120.9,0.1c47.2-9.3,87.3-26.8,114.5-50.3
|
||||
c6-5.1,11.3-10.6,16-16.3c5.6-6.9,10.3-14.2,13.8-21.8c-1.2,9.2-3.1,18.2-5.7,26.9c-2.6,8.8-5.9,17.3-9.7,25.5
|
||||
C373.1,376.7,316.1,416,250.2,416L250.2,416z"></path>
|
||||
</mask>
|
||||
</defs>
|
||||
<path id="rectangle-container1" fill="#9C27B0" mask="url(#symbol1)" d="M426.7,0H85.3C38.4,0,0,38.4,0,85.3v341.3c0,47,38.4,85.3,85.3,85.3h341.3
|
||||
c46.9,0,85.3-38.4,85.3-85.3V85.3C512,38.4,473.6,0,426.7,0z"></path>
|
||||
<path id="circle-container1" style="visibility: hidden;" d="M0,256c0,100.9,59.8,165.3,72,177.9c11.2,11.6,77.7,78.1,184,78.1c14.5,0,115.8-1.7,190.7-85.3
|
||||
C510.1,356,512,274.1,512,256c0-18.9-2.1-96.7-61-165.9C375.7,1.8,269.4,0,256,0C241,0,141.3,1.7,66.6,83.7C1.9,154.8,0,237.9,0,256 z"></path>
|
||||
</svg>
|
||||
<svg class="example-box-model example-box" id="complex-morph-example2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 513 513">
|
||||
<defs>
|
||||
<mask id="symbol2">
|
||||
|
@ -372,7 +328,7 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
|
|||
<ul>
|
||||
<li>Starting with KUTE.js version 2.0.14 the component implements <a href="https://github.com/thednp/svg-path-commander">SVGPathCommander</a> for path processing, solving previous issues with over-optimized
|
||||
path strings among other issues. You can try the <a href="https://thednp.github.io/svg-path-commander/">SVGPathCommander demo page</a> to prepare your path strings.</li>
|
||||
<li>Since animation works only with <code>path</code> <b>SVGElement</b>s, you might need a <a href="https://github.com/Waest/SVGPathConverter" target="_blank">convertToPath</a> utility.</li>
|
||||
<li>Since animation works only with <code>path</code> <b>SVGElement</b>s, you might need a <a href="https://thednp.github.io/svg-path-commander/convert.html" target="_blank">shapeToPath</a> utility.</li>
|
||||
<li>Both SVG morph components will always animate first sub-path from both starting and ending shapes, and for any case hopefully this demo will guide you in mastering the technique.</li>
|
||||
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or <a href="https://github.com/Waest/SVGPathConverter">SVGPathCommander</a>
|
||||
to apply a scale transformation to your shapes' path commands.</li>
|
||||
|
@ -393,20 +349,17 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<!-- /.site-wrapper -->
|
||||
|
||||
|
||||
|
||||
<!-- JavaScript =============================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="./src/polyfill.min.js"></script>
|
||||
<!-- <script src="./src/kute-extra.js"></script> -->
|
||||
<script src="./src/kute-extra.min.js"></script>
|
||||
<script src="./src/kute-extra.js"></script>
|
||||
<script src="./assets/js/svgCubicMorph.js"></script>
|
||||
<script src="./assets/js/prism.js"></script>
|
||||
<script src="./assets/js/scripts.js"></script>
|
||||
|
|
|
@ -143,7 +143,7 @@ var tween3 = KUTE.fromTo('selector1',{draw:'0% 100%'}, {draw:'50% 50%'});
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
|
|||
<li>Starting with KUTE.js version 2.0.14 the component implements <a href="https://github.com/thednp/svg-path-commander">SVGPathCommander</a> for path processing, solving previous issues with over-optimized
|
||||
path strings among other issues. You can try the <a href="https://thednp.github.io/svg-path-commander/">SVGPathCommander demo page</a> to prepare your path strings.</li>
|
||||
<li>Since <b>SVG Morph</b> animation works only with <code>path</code> elements, you might need a <code>convertToPath</code> feature, so
|
||||
<a href="https://github.com/Waest/SVGPathConverter" target="_blank">grab one here</a>.</li>
|
||||
<a href="https://thednp.github.io/svg-path-commander/convert.html" target="_blank">grab one here</a>.</li>
|
||||
<li>Both SVG morph components will always animate first sub-path from both starting and ending shapes, and for any case hopefully this demo will guide you in mastering the technique.</li>
|
||||
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or <a href="https://github.com/Waest/SVGPathConverter">SVGPathCommander</a>
|
||||
to apply a scale transformation to your shapes' path commands.</li>
|
||||
|
@ -408,7 +408,7 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
@ -419,8 +419,7 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
|
|||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
|
||||
<script src="./src/polyfill.min.js"></script>
|
||||
<!-- <script src="./src/kute.min.js"></script> -->
|
||||
<script src="../dist/kute.js"></script>
|
||||
<script src="./src/kute.min.js"></script>
|
||||
<script src="./assets/js/prism.js"></script>
|
||||
<script src="./assets/js/scripts.js"></script>
|
||||
<script src="./assets/js/svgMorph.js"></script>
|
||||
|
|
|
@ -366,7 +366,7 @@ KUTE.fromTo(element,
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ let tween3 = KUTE.to('selector1',{wordSpacing:50})
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@ tweenObjects.start();
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ var tween2 = KUTE.fromTo(
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ let mx4 = KUTE.to('el4', { transform: { translate3d:[-50,-50,-50], rotate3d:[0,-
|
|||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2015 - 2020 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
<p>© 2015 - 2021 · <a href="https://github.com/thednp">thednp</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
5923
dist/kute.esm.js
vendored
5923
dist/kute.esm.js
vendored
File diff suppressed because it is too large
Load diff
4
dist/kute.esm.min.js
vendored
4
dist/kute.esm.min.js
vendored
File diff suppressed because one or more lines are too long
4997
dist/kute.js
vendored
4997
dist/kute.js
vendored
File diff suppressed because it is too large
Load diff
4
dist/kute.min.js
vendored
4
dist/kute.min.js
vendored
File diff suppressed because one or more lines are too long
215
dist/polyfill.js
vendored
215
dist/polyfill.js
vendored
|
@ -1,93 +1,140 @@
|
|||
/*!
|
||||
* KUTE.js Polyfill v2.0.14 (http://thednp.github.io/kute.js)
|
||||
* Copyright 2015-2020 © thednp
|
||||
* 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) {
|
||||
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;
|
||||
}
|
||||
}());
|
||||
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;
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
if (!Array.prototype.includes) {
|
||||
Array.prototype.includes = function(searchElement ) {
|
||||
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;
|
||||
};
|
||||
// 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 (!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 (!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;
|
||||
};
|
||||
}
|
||||
|
|
4
dist/polyfill.min.js
vendored
4
dist/polyfill.min.js
vendored
|
@ -1,3 +1,3 @@
|
|||
// KUTE.js Polyfill v2.0.14 | 2020 © thednp | MIT-License
|
||||
// KUTE.js Polyfill v2.1.1-alpha1 | 2021 © thednp | MIT-License
|
||||
"use strict";
|
||||
var r,t,n,e;Array.from||(Array.from=(r=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===r.call(t)},n=Math.pow(2,53)-1,e=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),n)},function(r){var n=this,o=Object(r);if(null==r)throw new TypeError("Array.from requires an array-like object - not null or undefined");var i,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&&(i=arguments[2])}for(var u,f=e(o.length),c=t(n)?Object(new n(f)):new Array(f),p=0;p<f;)u=o[p],c[p]=a?void 0===i?a(u,p):a.call(i,u,p):u,p+=1;return c.length=f,c})),Array.prototype.includes||(Array.prototype.includes=function(r){var t=Object(this),n=parseInt(t.length)||0;if(0===n)return!1;var e,o,i=parseInt(arguments[1])||0;for(i>=0?e=i:(e=n+i)<0&&(e=0);e<n;){if(r===(o=t[e])||r!=r&&o!=o)return!0;e++}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)});
|
||||
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});
|
||||
|
|
35
package.json
35
package.json
|
@ -1,22 +1,27 @@
|
|||
{
|
||||
"name": "kute.js",
|
||||
"version": "2.0.16",
|
||||
"description": "JavaScript animation engine of the future is called 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/*.{js,map}",
|
||||
"src/**/*.{js,map}",
|
||||
"src/*.{js,map}"
|
||||
"dist",
|
||||
"types",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"help": "rollup --help",
|
||||
"build": "npm-run-all --parallel copy-build build-*",
|
||||
"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",
|
||||
|
@ -54,18 +59,22 @@
|
|||
},
|
||||
"homepage": "http://thednp.github.io/kute.js",
|
||||
"dependencies": {
|
||||
"cubic-bezier-easing": "^1.0.2",
|
||||
"minifill": "^0.0.14",
|
||||
"shorter-js": "^0.1.4",
|
||||
"svg-path-commander": "0.0.9"
|
||||
"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.28.1",
|
||||
"rollup-plugin-cleanup": "^3.1.1",
|
||||
"rollup-plugin-terser": "^7.0.2"
|
||||
"rollup": "^2.38.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.5.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import buble from '@rollup/plugin-buble'
|
||||
import {terser} from 'rollup-plugin-terser'
|
||||
import node from '@rollup/plugin-node-resolve'
|
||||
import cleanup from 'rollup-plugin-cleanup'
|
||||
import json from '@rollup/plugin-json'
|
||||
import * as pkg from "./package.json"
|
||||
|
||||
|
@ -34,10 +33,12 @@ const OUTPUT = {
|
|||
const PLUGINS = [
|
||||
node({mainFields: ['jsnext','module'], dedupe: ['svg-path-commander']}) ,
|
||||
json(),
|
||||
buble(),
|
||||
cleanup()
|
||||
]
|
||||
|
||||
if (FORMAT!=='esm'){
|
||||
PLUGINS.push(buble({objectAssign: 'Object.assign'}));
|
||||
}
|
||||
|
||||
if (MIN){
|
||||
PLUGINS.push(terser({output: {preamble: miniBanner}}));
|
||||
} else {
|
||||
|
|
|
@ -3,7 +3,6 @@ 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 cleanup from 'rollup-plugin-cleanup'
|
||||
import * as pkg from "./package.json";
|
||||
|
||||
// set headers
|
||||
|
@ -34,7 +33,6 @@ const PLUGINS = [
|
|||
node(),
|
||||
json(),
|
||||
buble(),
|
||||
cleanup()
|
||||
]
|
||||
|
||||
if (MIN){
|
||||
|
|
|
@ -1,116 +1,137 @@
|
|||
import supportedProperties from '../objects/supportedProperties.js'
|
||||
import defaultValues from '../objects/defaultValues.js'
|
||||
import defaultOptions from '../objects/defaultOptions.js'
|
||||
import prepareProperty from '../objects/prepareProperty.js'
|
||||
import prepareStart from '../objects/prepareStart.js'
|
||||
import onStart from '../objects/onStart.js'
|
||||
import onComplete from '../objects/onComplete.js'
|
||||
import crossCheck from '../objects/crossCheck.js'
|
||||
import linkProperty from '../objects/linkProperty.js'
|
||||
import Util from '../objects/util.js'
|
||||
import Interpolate from '../objects/interpolate.js'
|
||||
|
||||
// Animation class
|
||||
// * builds KUTE components
|
||||
// * populate KUTE objects
|
||||
// * AnimatonBase creates a KUTE.js build for pre-made Tween objects
|
||||
// * AnimatonDevelopment can help you debug your new components
|
||||
export default class Animation {
|
||||
constructor(Component){
|
||||
try {
|
||||
if ( Component.component in supportedProperties ) {
|
||||
console.error(`KUTE.js - ${Component.component} already registered`);
|
||||
} else if ( Component.property in defaultValues ) {
|
||||
console.error(`KUTE.js - ${Component.property} already registered`);
|
||||
} else {
|
||||
this.setComponent(Component)
|
||||
}
|
||||
} catch(e){
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
setComponent(Component){
|
||||
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
|
||||
|
||||
// {property,defaultvalue,defaultOptions,Interpolate,functions} // single property
|
||||
// {category,properties,defaultvalues,defaultOptions,Interpolate,functions} // category colors, boxModel, borderRadius
|
||||
// {property,subProperties,defaultvalues,defaultOptions,Interpolate,functions} // property with multiple sub properties. Eg transform, filter
|
||||
// {category,subProperties,defaultvalues,defaultOptions,Interpolate,functions} // property with multiple sub properties. Eg attr
|
||||
|
||||
// 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) {
|
||||
for (const dv in Component.defaultValues) {
|
||||
defaultValues[dv] = Component.defaultValues[dv]
|
||||
}
|
||||
// minimal info
|
||||
propertyInfo.supports = `${Length||Property} ${Property||Category} properties`
|
||||
}
|
||||
|
||||
// set additional options
|
||||
if (Component.defaultOptions) {
|
||||
for (const op in Component.defaultOptions) {
|
||||
defaultOptions[op] = Component.defaultOptions[op]
|
||||
}
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
for (const fn in Functions) {
|
||||
if (fn in Component.functions) {
|
||||
if (typeof (Component.functions[fn]) === 'function' ) {
|
||||
// !Functions[fn][ Category||Property ] && (Functions[fn][ Category||Property ] = Component.functions[fn])
|
||||
!Functions[fn][ComponentName] && (Functions[fn][ComponentName] = {})
|
||||
!Functions[fn][ComponentName][ Category||Property ] && (Functions[fn][ComponentName][ Category||Property ] = Component.functions[fn])
|
||||
} else {
|
||||
for ( const ofn in Component.functions[fn] ){
|
||||
// !Functions[fn][ofn] && (Functions[fn][ofn] = Component.functions[fn][ofn])
|
||||
!Functions[fn][ComponentName] && (Functions[fn][ComponentName] = {})
|
||||
!Functions[fn][ComponentName][ofn] && (Functions[fn][ComponentName][ofn] = Component.functions[fn][ofn])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set component interpolate
|
||||
if (Component.Interpolate) {
|
||||
for (const fni in Component.Interpolate) {
|
||||
const compIntObj = Component.Interpolate[fni]
|
||||
if ( typeof(compIntObj) === 'function' && !Interpolate[fni] ) {
|
||||
Interpolate[fni] = compIntObj;
|
||||
} else {
|
||||
for ( const sfn in compIntObj ) {
|
||||
if ( typeof(compIntObj[sfn]) === 'function' && !Interpolate[fni] ) {
|
||||
Interpolate[fni] = compIntObj[sfn];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
linkProperty[ComponentName] = Component.Interpolate
|
||||
}
|
||||
|
||||
// set component util
|
||||
if (Component.Util) {
|
||||
for (const fnu in Component.Util){
|
||||
!Util[fnu] && (Util[fnu] = Component.Util[fnu])
|
||||
}
|
||||
}
|
||||
|
||||
return propertyInfo
|
||||
}
|
||||
}
|
||||
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,76 +1,97 @@
|
|||
import supportedProperties from '../objects/supportedProperties.js'
|
||||
import defaultOptions from '../objects/defaultOptions.js'
|
||||
import onStart from '../objects/onStart.js'
|
||||
import onComplete from '../objects/onComplete.js'
|
||||
import linkProperty from '../objects/linkProperty.js'
|
||||
import Util from '../objects/util.js'
|
||||
import Interpolate from '../objects/interpolate.js'
|
||||
|
||||
// Animation class
|
||||
export default class AnimationBase {
|
||||
constructor(Component){
|
||||
return this.setComponent(Component)
|
||||
}
|
||||
setComponent(Component){
|
||||
const ComponentName = Component.component
|
||||
// const Objects = { defaultValues, defaultOptions, Interpolate, linkProperty }
|
||||
const Functions = { onStart, onComplete }
|
||||
const Category = Component.category
|
||||
const Property = Component.property
|
||||
|
||||
// set supported category/property
|
||||
supportedProperties[ComponentName] = Component.properties || Component.subProperties || Component.property
|
||||
|
||||
// set additional options
|
||||
if (Component.defaultOptions) {
|
||||
for (const op in Component.defaultOptions) {
|
||||
defaultOptions[op] = Component.defaultOptions[op]
|
||||
}
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
for (const fn in Functions) {
|
||||
if (fn in Component.functions) {
|
||||
if ( typeof (Component.functions[fn]) === 'function' ) {
|
||||
// !Functions[fn][ Category||Property ] && (Functions[fn][ Category||Property ] = Component.functions[fn])
|
||||
!Functions[fn][ComponentName] && (Functions[fn][ComponentName] = {})
|
||||
!Functions[fn][ComponentName][ Category||Property ] && (Functions[fn][ComponentName][ Category||Property ] = Component.functions[fn])
|
||||
} else {
|
||||
for ( const ofn in Component.functions[fn] ){
|
||||
// !Functions[fn][ofn] && (Functions[fn][ofn] = Component.functions[fn][ofn])
|
||||
!Functions[fn][ComponentName] && (Functions[fn][ComponentName] = {})
|
||||
!Functions[fn][ComponentName][ofn] && (Functions[fn][ComponentName][ofn] = Component.functions[fn][ofn])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set interpolate
|
||||
if (Component.Interpolate) {
|
||||
for (const fni in Component.Interpolate) {
|
||||
const compIntObj = Component.Interpolate[fni]
|
||||
if ( typeof(compIntObj) === 'function' && !Interpolate[fni] ) {
|
||||
Interpolate[fni] = compIntObj;
|
||||
} else {
|
||||
for ( const sfn in compIntObj ) {
|
||||
if ( typeof(compIntObj[sfn]) === 'function' && !Interpolate[fni] ) {
|
||||
Interpolate[fni] = compIntObj[sfn];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
linkProperty[ComponentName] = Component.Interpolate
|
||||
}
|
||||
|
||||
// set component util
|
||||
if (Component.Util) {
|
||||
for (const fnu in Component.Util){
|
||||
!Util[fnu] && (Util[fnu] = Component.Util[fnu])
|
||||
}
|
||||
}
|
||||
|
||||
return {name:ComponentName}
|
||||
}
|
||||
}
|
||||
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,103 +1,137 @@
|
|||
import prepareProperty from '../objects/prepareProperty.js'
|
||||
import prepareStart from '../objects/prepareStart.js'
|
||||
import onStart from '../objects/onStart.js'
|
||||
import onComplete from '../objects/onComplete.js'
|
||||
import crossCheck from '../objects/crossCheck.js'
|
||||
import Interpolate from '../objects/interpolate.js'
|
||||
|
||||
import Animation from './animation.js'
|
||||
|
||||
// AnimationDevelopment class
|
||||
export default class AnimationDevelopment extends Animation {
|
||||
constructor(...args){
|
||||
super(...args)
|
||||
}
|
||||
setComponent(Component){
|
||||
super.setComponent(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 = []
|
||||
|
||||
for (const op in Component.defaultOptions) {
|
||||
propertyInfo.extends.push(op)
|
||||
}
|
||||
|
||||
propertyInfo.extends.length ? propertyInfo.extends = `with <${propertyInfo.extends.join(', ')}> new option(s)` : delete propertyInfo.extends
|
||||
}
|
||||
|
||||
// set functions
|
||||
if (Component.functions) {
|
||||
propertyInfo.interface = []
|
||||
propertyInfo.render = []
|
||||
propertyInfo.warning = []
|
||||
for (const fnf in Functions) {
|
||||
if (fnf in Component.functions) {
|
||||
fnf === 'prepareProperty' ? propertyInfo.interface.push(`fromTo()`) : 0
|
||||
fnf === 'prepareStart' ? propertyInfo.interface.push(`to()`) : 0
|
||||
fnf === 'onStart' ? propertyInfo.render = `can render update` : 0
|
||||
} else {
|
||||
fnf === 'prepareProperty' ? propertyInfo.warning.push(`fromTo()`) : 0
|
||||
fnf === 'prepareStart' ? propertyInfo.warning.push(`to()`) : 0
|
||||
fnf === 'onStart' ? propertyInfo.render = `no function to render update` : 0
|
||||
}
|
||||
}
|
||||
propertyInfo.interface.length ? propertyInfo.interface = `${Category||Property} can use [${propertyInfo.interface.join(', ')}] method(s)` : delete propertyInfo.uses
|
||||
propertyInfo.warning.length ? propertyInfo.warning = `${Category||Property} can't use [${propertyInfo.warning.join(', ')}] method(s) because values aren't processed` : delete propertyInfo.warning
|
||||
}
|
||||
|
||||
// register Interpolation functions
|
||||
if (Component.Interpolate) {
|
||||
propertyInfo.uses = []
|
||||
propertyInfo.adds = []
|
||||
|
||||
for (let fni in Component.Interpolate) {
|
||||
let compIntObj = Component.Interpolate[fni]
|
||||
// register new Interpolation functions
|
||||
if ( typeof(compIntObj) === 'function' ) {
|
||||
if ( !Interpolate[fni] ) {
|
||||
propertyInfo.adds.push(`${fni}`)
|
||||
}
|
||||
propertyInfo.uses.push(`${fni}`)
|
||||
} else {
|
||||
for ( let sfn in compIntObj ) {
|
||||
if ( typeof(compIntObj[sfn]) === 'function' && !Interpolate[fni] ) {
|
||||
propertyInfo.adds.push(`${sfn}`)
|
||||
}
|
||||
propertyInfo.uses.push(`${sfn}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
propertyInfo.uses.length ? propertyInfo.uses = `[${propertyInfo.uses.join(', ')}] interpolation function(s)` : delete propertyInfo.uses
|
||||
propertyInfo.adds.length ? propertyInfo.adds = `new [${propertyInfo.adds.join(', ')}] interpolation function(s)` : 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
|
||||
}
|
||||
}
|
||||
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,46 +1,57 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import {onStartBgPos} from './backgroundPositionBase.js'
|
||||
|
||||
// const bgPosProp = { property : 'backgroundPosition', defaultValue: [0,0], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Functions
|
||||
function getBgPos(prop){
|
||||
return getStyleForProperty(this.element,prop) || defaultValues[prop];
|
||||
}
|
||||
function prepareBgPos(prop,value){
|
||||
if ( value instanceof Array ){
|
||||
const x = trueDimension(value[0]).v,
|
||||
y = trueDimension(value[1]).v;
|
||||
return [ x !== NaN ? x : 50, y !== NaN ? y : 50 ];
|
||||
} else {
|
||||
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
|
||||
|
||||
Components.BackgroundPosition = BackgroundPosition
|
||||
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,22 +1,26 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// const bgPosProp = { property : 'backgroundPosition', defaultValue: [0,0], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Functions
|
||||
export function onStartBgPos(prop){
|
||||
if ( this.valuesEnd[prop] && !KUTE[prop]) { // opacity could be 0
|
||||
KUTE[prop] = (elem, a, b, v) => {
|
||||
elem.style[prop] = `${(numbers(a[0],b[0],v)*100>>0)/100}% ${((numbers(a[1],b[1],v)*100>>0)/100)}%`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base Object
|
||||
const baseBgPosOps = {
|
||||
component: 'baseBackgroundPosition',
|
||||
property: 'backgroundPosition',
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart: onStartBgPos}
|
||||
}
|
||||
export default baseBgPosOps
|
||||
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,48 +1,58 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import units from '../interpolation/units.js'
|
||||
import {radiusOnStartFn} from './borderRadiusBase.js'
|
||||
|
||||
// const borderRadius = { category : 'borderRadius', properties : [..], defaultValues: {..}, interpolation: {units} }
|
||||
|
||||
// Component Properties
|
||||
const radiusProps = ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius']
|
||||
const radiusValues = {}
|
||||
|
||||
radiusProps.map(x => radiusValues[x] = 0);
|
||||
|
||||
// Component Functions
|
||||
const radiusOnStart = {}
|
||||
radiusProps.forEach(tweenProp => {
|
||||
radiusOnStart[tweenProp] = radiusOnStartFn
|
||||
});
|
||||
export function getRadius(tweenProp){
|
||||
return getStyleForProperty(this.element,tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
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
|
||||
|
||||
Components.BorderRadiusProperties = BorderRadius
|
||||
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,29 +1,43 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import units from '../interpolation/units.js'
|
||||
|
||||
// const borderRadius = { category : 'borderRadius', properties : [..], defaultValues: {..}, interpolation: {units} }
|
||||
|
||||
// Component Properties
|
||||
const radiusProps = ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius']
|
||||
|
||||
// Component Functions
|
||||
export function radiusOnStartFn(tweenProp){
|
||||
if (tweenProp in this.valuesEnd && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] = units(a.v,b.v,b.u,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
const radiusOnStart = {}
|
||||
radiusProps.forEach(tweenProp => {
|
||||
radiusOnStart[tweenProp] = radiusOnStartFn
|
||||
});
|
||||
|
||||
// Base Component
|
||||
const baseBorderRadius = {
|
||||
component: 'baseBorderRadius',
|
||||
category: 'borderRadius',
|
||||
Interpolate: {units},
|
||||
functions: {onStart: radiusOnStart}
|
||||
}
|
||||
export default baseBorderRadius
|
||||
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,46 +1,57 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import {boxModelOnStart} from './boxModelBase.js'
|
||||
|
||||
// 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.map(x => boxModelValues[x] = 0);
|
||||
|
||||
// Component Functions
|
||||
function getBoxModel(tweenProp){
|
||||
return getStyleForProperty(this.element,tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
function prepareBoxModel(tweenProp,value){
|
||||
const boxValue = trueDimension(value), offsetProp = tweenProp === 'height' ? 'offsetHeight' : 'offsetWidth';
|
||||
return boxValue.u === '%' ? boxValue.v * this.element[offsetProp] / 100 : boxValue.v;
|
||||
}
|
||||
const boxPropsOnStart = {}
|
||||
boxModelProperties.map(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
|
||||
|
||||
Components.BoxModelProperties = boxModel
|
||||
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,28 +1,37 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// Component Functions
|
||||
export function boxModelOnStart(tweenProp){
|
||||
if (tweenProp in this.valuesEnd && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] = `${v > 0.99 || v < 0.01 ? ((numbers(a,b,v)*10)>>0)/10 : (numbers(a,b,v) ) >> 0}px`;
|
||||
// elem.style[tweenProp] = `${(numbers(a,b,v) ) >> 0}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base Props
|
||||
const baseBoxProps = ['top','left','width','height']
|
||||
const baseBoxOnStart = {}
|
||||
baseBoxProps.map(x=>baseBoxOnStart[x] = boxModelOnStart)
|
||||
|
||||
// Component Base
|
||||
const baseBoxModel = {
|
||||
component: 'baseBoxModel',
|
||||
category: 'boxModel',
|
||||
properties: baseBoxProps,
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart: baseBoxOnStart}
|
||||
}
|
||||
|
||||
export default baseBoxModel
|
||||
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,44 +1,56 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import {boxModelOnStart} from './boxModelBase.js'
|
||||
|
||||
|
||||
// Component Functions
|
||||
function getBoxModel(tweenProp){
|
||||
return getStyleForProperty(this.element,tweenProp) || defaultValues[tweenProp];
|
||||
}
|
||||
function prepareBoxModel(tweenProp,value){
|
||||
const boxValue = trueDimension(value), 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.map(x=>essentialBoxOnStart[x] = boxModelOnStart)
|
||||
|
||||
// All Component Functions
|
||||
const essentialBoxModelFunctions = {
|
||||
prepareStart: getBoxModel,
|
||||
prepareProperty: prepareBoxModel,
|
||||
onStart: essentialBoxOnStart
|
||||
}
|
||||
|
||||
// Component Essential
|
||||
const essentialBoxModel = {
|
||||
component: 'essentialBoxModel',
|
||||
category: 'boxModel',
|
||||
properties: essentialBoxProps,
|
||||
defaultValues: essentialBoxPropsValues,
|
||||
Interpolate: {numbers},
|
||||
functions: essentialBoxModelFunctions,
|
||||
Util:{trueDimension}
|
||||
}
|
||||
|
||||
export default essentialBoxModel
|
||||
|
||||
Components.BoxModelEssential = essentialBoxModel
|
||||
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,43 +1,52 @@
|
|||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import {onStartClip} from './clipPropertyBase.js'
|
||||
|
||||
// Component Functions
|
||||
function getClip(tweenProp,v){
|
||||
const currentClip = getStyleForProperty(this.element,tweenProp),
|
||||
width = getStyleForProperty(this.element,'width'),
|
||||
height = getStyleForProperty(this.element,'height');
|
||||
return !/rect/.test(currentClip) ? [0, width, height, 0] : currentClip;
|
||||
}
|
||||
function prepareClip(tweenProp,value) {
|
||||
if ( value instanceof Array ){
|
||||
return [ trueDimension(value[0]), trueDimension(value[1]), trueDimension(value[2]), trueDimension(value[3]) ];
|
||||
} else {
|
||||
var clipValue = value.replace(/rect|\(|\)/g,'');
|
||||
clipValue = /\,/g.test(clipValue) ? clipValue.split(/\,/g) : clipValue.split(/\s/g);
|
||||
return [ trueDimension(clipValue[0]), trueDimension(clipValue[1]), trueDimension(clipValue[2]), trueDimension(clipValue[3]) ];
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
Components.ClipProperty = clipProperty
|
||||
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,27 +1,36 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// Component Functions
|
||||
export function onStartClip(tweenProp) {
|
||||
if ( this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
var h = 0, cl = [];
|
||||
for (h;h<4;h++){
|
||||
var c1 = a[h].v, c2 = b[h].v, cu = b[h].u || 'px';
|
||||
cl[h] = ((numbers(c1,c2,v)*100 >> 0)/100) + cu;
|
||||
}
|
||||
elem.style.clip = `rect(${cl})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseClip = {
|
||||
component: 'baseClip',
|
||||
property: 'clip',
|
||||
// defaultValue: [0,0,0,0],
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart:onStartClip}
|
||||
}
|
||||
|
||||
export default baseClip
|
||||
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,51 +1,65 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueColor from '../util/trueColor.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
import {onStartColors} from './colorPropertiesBase.js'
|
||||
|
||||
// Component Interpolation
|
||||
// Component Properties
|
||||
// supported formats
|
||||
// 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+)
|
||||
const supportedColors = ['color', 'backgroundColor','borderColor', 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor', 'outlineColor']
|
||||
const defaultColors = {}
|
||||
|
||||
supportedColors.map(tweenProp => {
|
||||
defaultColors[tweenProp] = '#000'
|
||||
});
|
||||
|
||||
// Component Functions
|
||||
const colorsOnStart = {}
|
||||
supportedColors.map(x => colorsOnStart[x] = onStartColors)
|
||||
|
||||
function getColor(prop,value) {
|
||||
return getStyleForProperty(this.element,prop) || defaultValues[prop];
|
||||
}
|
||||
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
|
||||
|
||||
Components.ColorProperties = colorProperties
|
||||
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,35 +1,45 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
|
||||
// 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','borderColor', 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor', 'outlineColor']
|
||||
|
||||
// Component Functions
|
||||
export function onStartColors(tweenProp){
|
||||
if (this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] = colors(a,b,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
const colorsOnStart = {}
|
||||
supportedColors.map(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
|
||||
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,79 +1,95 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import getInlineStyle from '../process/getInlineStyle.js'
|
||||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import trueProperty from '../util/trueProperty.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// Component Const
|
||||
const transformProperty = trueProperty('transform');
|
||||
const supportTransform = transformProperty in document.body.style ? 1 : 0;
|
||||
|
||||
// Component Functions
|
||||
function getComponentCurrentValue(tweenProp,value){
|
||||
let currentTransform = getInlineStyle(this.element);
|
||||
let left = this.element.style.left;
|
||||
let top = this.element.style.top;
|
||||
let x = supportTransform && currentTransform.translate ? currentTransform.translate[0]
|
||||
: isFinite(left*1) ? left
|
||||
: defaultValues.move[0];
|
||||
let y = supportTransform && currentTransform.translate ? currentTransform.translate[1]
|
||||
: isFinite(top*1) ? top
|
||||
: defaultValues.move[1];
|
||||
return [x,y]
|
||||
}
|
||||
function prepareComponentValue(tweenProp,value){
|
||||
let x = isFinite(value*1) ? parseInt(value) : parseInt(value[0]) || 0;
|
||||
let y = parseInt(value[1]) || 0;
|
||||
|
||||
return [ x, y ]
|
||||
}
|
||||
|
||||
export function onStartComponent(tweenProp,value){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
|
||||
if (supportTransform){
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[transformProperty] = 'translate('+numbers(a[0],b[0],v)+'px,'+numbers(a[1],b[1],v)+'px)';
|
||||
}
|
||||
} else {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
if (a[0]||b[0]) {
|
||||
elem.style.left = numbers(a[0],b[0],v)+'px';
|
||||
}
|
||||
if (a[1]||b[1]) {
|
||||
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
|
||||
|
||||
Components.CrossBrowserMove = crossBrowserMove
|
||||
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,134 +1,201 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import trueColor from '../util/trueColor.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
import {dropShadow,onStartFilter} from './filterEffectsBase.js'
|
||||
|
||||
// const filterEffects = { property : 'filter', subProperties: {}, defaultValue: {}, interpolators: {} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Util
|
||||
function replaceDashNamespace(str){
|
||||
return str.replace('-r','R').replace('-s','S')
|
||||
}
|
||||
|
||||
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++){
|
||||
newShadow[i] = parseFloat(newShadow[i]);
|
||||
}
|
||||
// also the color must be a rgb object
|
||||
newShadow[3] = trueColor(newShadow[3]);
|
||||
return newShadow;
|
||||
}
|
||||
|
||||
function parseFilterString(currentStyle){
|
||||
let result = {}
|
||||
let fnReg = /(([a-z].*?)\(.*?\))(?=\s([a-z].*?)\(.*?\)|\s*$)/g
|
||||
let matches = currentStyle.match(fnReg);
|
||||
const fnArray = currentStyle !== 'none' ? matches : 'none'
|
||||
|
||||
if (fnArray instanceof Array) {
|
||||
for (let j=0, jl = fnArray.length; j<jl; j++){
|
||||
let p = fnArray[j].trim().split(/\((.+)/);
|
||||
let pp = replaceDashNamespace(p[0]);
|
||||
if ( pp === 'dropShadow' ) {
|
||||
let shadowColor = p[1].match(/(([a-z].*?)\(.*?\))(?=\s(.*?))/)[0]
|
||||
let params = p[1].replace(shadowColor,'').split(/\s/).map(parseFloat)
|
||||
result[pp] = params.filter((el)=>!isNaN(el)).concat(shadowColor);
|
||||
} else {
|
||||
result[pp] = p[1].replace(/\'|\"|\)/g,'');
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
function getFilter(tweenProp,value) {
|
||||
let currentStyle = getStyleForProperty(this.element,tweenProp),
|
||||
filterObject = parseFilterString(currentStyle), fnp
|
||||
|
||||
for (let fn in value){
|
||||
fnp = replaceDashNamespace(fn)
|
||||
if ( !filterObject[fnp] ){
|
||||
filterObject[fnp] = defaultValues[tweenProp][fn]
|
||||
}
|
||||
}
|
||||
return filterObject;
|
||||
}
|
||||
function prepareFilter(tweenProp,value) {
|
||||
let filterObject = {}, fnp
|
||||
|
||||
// {opacity: [0-100%], blur: [0-Nem], saturate: [0-N%], invert: 0, grayscale: [0-100%], brightness: [0-N%], contrast: [0-N%], sepia: [0-N%], 'hueRotate': [0-Ndeg], 'dropShadow': [0,0,0,(r:0,g:0,b:0)], url:''},
|
||||
// {opacity: 100, blur: 0, saturate: 100, invert: 0, grayscale: 0, brightness: 100, contrast: 100, sepia: 0, 'hueRotate':0, 'dropShadow': 0, url:''},
|
||||
|
||||
for (let fn in value){
|
||||
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;
|
||||
}
|
||||
|
||||
function crossCheckFilter(tweenProp){
|
||||
if ( this.valuesEnd[tweenProp] ) {
|
||||
for (const fn in this.valuesStart[tweenProp]){
|
||||
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',
|
||||
// subProperties: ['blur', 'brightness','contrast','dropShadow','hueRotate','grayscale','invert','opacity','saturate','sepia','url'], // opacity function interfere with opacityProperty
|
||||
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
|
||||
|
||||
Components.FilterEffects = filterEffects
|
||||
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,57 +1,74 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
|
||||
// const filterEffects = { property : 'filter', subProperties: {}, defaultValue: {}, interpolators: {} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Interpolation
|
||||
export function dropShadow(a,b,v){
|
||||
let params = [], unit = 'px'
|
||||
|
||||
for (let i=0; i<3; i++){
|
||||
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
|
||||
export function onStartFilter(tweenProp) {
|
||||
if ( this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] = (b.url ? `url(${b.url})` : '')
|
||||
+ (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) : '')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Base Component
|
||||
const baseFilter = {
|
||||
component: 'baseFilter',
|
||||
property: 'filter',
|
||||
// subProperties: ['blur', 'brightness','contrast','dropShadow','hueRotate','grayscale','invert','opacity','saturate','sepia','url'], // opacity function interfere with opacityProperty
|
||||
// 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
|
||||
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,93 +1,131 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import onStart from '../objects/onStart.js'
|
||||
import Components from '../objects/components.js'
|
||||
import trueColor from '../util/trueColor.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
import {attributes,onStartAttr} from './htmlAttributesBase.js'
|
||||
|
||||
// Component Name
|
||||
let ComponentName = 'htmlAttributes'
|
||||
|
||||
// Component Properties
|
||||
const svgColors = ['fill','stroke','stop-color'];
|
||||
|
||||
// Component Util
|
||||
function replaceUppercase (a) { return a.replace(/[A-Z]/g, "-$&").toLowerCase(); }
|
||||
|
||||
// Component Functions
|
||||
export function getAttr(tweenProp,value){
|
||||
let attrStartValues = {};
|
||||
for (let attr in value){
|
||||
let attribute = replaceUppercase(attr).replace(/_+[a-z]+/,''), // get the value for 'fill-opacity' not fillOpacity, also 'width' not the internal 'width_px'
|
||||
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;
|
||||
}
|
||||
export function prepareAttr(tweenProp,attrObj){ // attr (string),attrObj (object)
|
||||
let attributesObject = {};
|
||||
for ( let p in attrObj ) {
|
||||
let prop = replaceUppercase(p),
|
||||
regex = /(%|[a-z]+)$/,
|
||||
currentValue = this.element.getAttribute(prop.replace(/_+[a-z]+/,''));
|
||||
if ( !svgColors.includes(prop)) {
|
||||
if ( currentValue !== null && regex.test(currentValue) ) { // attributes set with unit suffixes
|
||||
let unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u,
|
||||
suffix = /%/.test(unit) ? '_percent' : `_${unit}`;
|
||||
onStart[ComponentName][prop+suffix] = function(tp) { // most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
|
||||
attributes[tp] = (elem, p, a, b, v) => {
|
||||
let _p = p.replace(suffix,'');
|
||||
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) ) {
|
||||
onStart[ComponentName][prop] = function(tp) { // most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
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
|
||||
onStart[ComponentName][prop] = function(tp) { // most "unknown" attributes cannot register into onStart, so we manually add them
|
||||
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',
|
||||
subProperties: ['fill','stroke','stop-color','fill-opacity','stroke-opacity'], // the Animation class will need some values to validate this Object attribute
|
||||
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
|
||||
|
||||
Components.HTMLAttributes = htmlAttributes
|
||||
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,39 +1,59 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
|
||||
// Component Name
|
||||
let ComponentName = 'baseHTMLAttributes'
|
||||
|
||||
// Component Special
|
||||
let attributes = {};
|
||||
export {attributes}
|
||||
|
||||
export const onStartAttr = {
|
||||
attr : function(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, vS, vE, v) => {
|
||||
for ( const oneAttr in vE ){
|
||||
KUTE.attributes[oneAttr](elem,oneAttr,vS[oneAttr],vE[oneAttr],v);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
attributes : function(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd.attr) {
|
||||
KUTE[tweenProp] = attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseAttributes = {
|
||||
component: ComponentName,
|
||||
property: 'attr',
|
||||
// subProperties: ['fill','stroke','stop-color','fill-opacity','stroke-opacity'], // the Animation class will need some values to validate this Object attribute
|
||||
// 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
|
||||
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,34 +1,41 @@
|
|||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import Components from '../objects/components.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import {onStartOpacity} from './opacityPropertyBase.js'
|
||||
|
||||
// const opacityProperty = { property : 'opacity', defaultValue: 1, interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Functions
|
||||
function getOpacity(tweenProp){
|
||||
return getStyleForProperty(this.element,tweenProp)
|
||||
}
|
||||
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
|
||||
|
||||
Components.OpacityProperty = opacityProperty
|
||||
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,24 +1,36 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// const opacityProperty = { property : 'opacity', defaultValue: 1, interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Functions
|
||||
export function onStartOpacity(tweenProp){
|
||||
if ( tweenProp in this.valuesEnd && !KUTE[tweenProp]) { // opacity could be 0
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] = ((numbers(a,b,v) * 1000)>>0)/1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const baseOpacity = {
|
||||
component: 'baseOpacity',
|
||||
property: 'opacity',
|
||||
// defaultValue: 1,
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart: onStartOpacity}
|
||||
}
|
||||
|
||||
export default baseOpacity
|
||||
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,38 +1,59 @@
|
|||
import Components from '../objects/components.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import supportPassive from 'shorter-js/src/boolean/supportPassive.js'
|
||||
|
||||
|
||||
import {scrollContainer,onStartScroll,onCompleteScroll,scrollIn,scrollOut,getScrollTargets,preventScroll,toggleScrollEvents} from './scrollPropertyBase.js'
|
||||
|
||||
// Component Functions
|
||||
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;
|
||||
}
|
||||
function prepareScroll(prop,value){
|
||||
return parseInt(value);
|
||||
}
|
||||
|
||||
// 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, supportPassive }
|
||||
}
|
||||
|
||||
export default scrollProperty
|
||||
|
||||
Components.ScrollProperty = scrollProperty
|
||||
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,79 +1,113 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import supportPassive from 'shorter-js/src/boolean/supportPassive.js'
|
||||
import mouseHoverEvents from 'shorter-js/src/strings/mouseHoverEvents.js'
|
||||
import supportTouch from 'shorter-js/src/boolean/supportTouch.js'
|
||||
|
||||
// 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
|
||||
|
||||
// scroll event options
|
||||
// it's important to stop propagating when animating scroll
|
||||
const passiveHandler = supportPassive ? { passive: false } : false
|
||||
|
||||
// prevent mousewheel or touch events while tweening scroll
|
||||
export function preventScroll(e) {
|
||||
this.scrolling && e.preventDefault()
|
||||
}
|
||||
export function getScrollTargets(){
|
||||
let el = this.element
|
||||
return el === scrollContainer ? { el: document, st: document.body } : { el: el, st: el}
|
||||
}
|
||||
export function toggleScrollEvents(action,element){
|
||||
element[action]( mouseHoverEvents[0], preventScroll, passiveHandler);
|
||||
element[action]( touchOrWheel, preventScroll, passiveHandler);
|
||||
}
|
||||
export function scrollIn(){
|
||||
let 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'
|
||||
}
|
||||
}
|
||||
export function scrollOut(){ //prevent scroll when tweening scroll
|
||||
let 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
|
||||
export function onStartScroll(tweenProp){
|
||||
if ( tweenProp in this.valuesEnd && !KUTE[tweenProp]) { // checking 0 will NOT add the render function
|
||||
this.element = ('scroll' in this.valuesEnd) && (!this.element || this.element === window) ? scrollContainer : this.element;
|
||||
scrollIn.call(this);
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.scrollTop = (numbers(a,b,v))>>0;
|
||||
};
|
||||
}
|
||||
}
|
||||
export function onCompleteScroll(tweenProp){
|
||||
scrollOut.call(this)
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const baseScroll = {
|
||||
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, supportPassive }
|
||||
}
|
||||
|
||||
export default baseScroll
|
||||
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,93 +1,127 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueColor from '../util/trueColor.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
import {onStartShadow} from './shadowPropertiesBase.js'
|
||||
|
||||
// Component Properties
|
||||
const shadowProps = ['boxShadow','textShadow']
|
||||
|
||||
// Component Util
|
||||
|
||||
// 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
|
||||
// utility function to process values accordingly
|
||||
// numbers must be floats and color must be rgb object
|
||||
function processShadowArray (shadow,tweenProp){
|
||||
let newShadow, i;
|
||||
|
||||
if (shadow.length === 3) { // [h-shadow, v-shadow, color]
|
||||
newShadow = [shadow[0], shadow[1], 0, 0, shadow[2], 'none'];
|
||||
} else if (shadow.length === 4) { // [h-shadow, v-shadow, color, inset] | [h-shadow, v-shadow, blur, color]
|
||||
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'];
|
||||
} else if (shadow.length === 5) { // [h-shadow, v-shadow, blur, color, inset] | [h-shadow, v-shadow, blur, spread, color]
|
||||
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'];
|
||||
} else if (shadow.length === 6) { // ideal [h-shadow, v-shadow, blur, spread, color, inset]
|
||||
newShadow = shadow;
|
||||
}
|
||||
|
||||
// make sure the values are ready to tween
|
||||
for (i=0;i<4;i++){
|
||||
newShadow[i] = parseFloat(newShadow[i]);
|
||||
}
|
||||
// also the color must be a rgb object
|
||||
newShadow[4] = trueColor(newShadow[4]);
|
||||
|
||||
// return tweenProp === 'boxShadow' ? newShadow : [newShadow[0],newShadow[1],newShadow[2],newShadow[4]];
|
||||
newShadow = tweenProp === 'boxShadow' ? newShadow : newShadow.filter((x,i)=>[0,1,2,4].indexOf(i)>-1);
|
||||
return newShadow;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
export function getShadow(tweenProp,value){
|
||||
let cssShadow = getStyleForProperty(this.element,tweenProp);
|
||||
return /^none$|^initial$|^inherit$|^inset$/.test(cssShadow) ? defaultValues[tweenProp] : cssShadow; // '0px 0px 0px 0px rgb(0,0,0)'
|
||||
}
|
||||
export function prepareShadow(tweenProp,value) {
|
||||
// [horizontal, vertical, blur, spread, color: {r:0,g:0,b:0}, inset]
|
||||
// parseProperty for boxShadow, builds basic structure with ready to tween values
|
||||
if (typeof value === 'string'){
|
||||
let currentColor, 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
|
||||
|
||||
// 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"
|
||||
currentColor = value.match(colRegEx);
|
||||
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.map(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
|
||||
|
||||
Components.ShadowProperties = shadowProperties
|
||||
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,38 +1,46 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import colors from '../interpolation/colors.js'
|
||||
|
||||
// Component Properties
|
||||
const shadowProps = ['boxShadow','textShadow']
|
||||
|
||||
// Component Functions
|
||||
export function onStartShadow(tweenProp) {
|
||||
if ( this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
// let's start with the numbers | set unit | also determine inset
|
||||
let params = [], unit = 'px', sl = tweenProp === 'textShadow' ? 3 : 4,
|
||||
colA = sl === 3 ? a[3] : a[4], colB = sl === 3 ? b[3] : b[4],
|
||||
inset = a[5] && a[5] !== 'none' || b[5] && b[5] !== 'none' ? ' inset' : false;
|
||||
|
||||
for (let i=0; i<sl; i++){
|
||||
params.push( ((numbers( a[i], b[i], v ) * 1000 >> 0) / 1000) + unit );
|
||||
}
|
||||
// the final piece of the puzzle, the DOM update
|
||||
elem.style[tweenProp] = inset ? colors(colA,colB,v) + params.join(' ') + inset
|
||||
: colors(colA,colB,v) + params.join(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
const shadowPropOnStart = {}
|
||||
shadowProps.map(x=>shadowPropOnStart[x]=onStartShadow)
|
||||
|
||||
// Component Base
|
||||
const baseShadow = {
|
||||
component: 'baseShadow',
|
||||
// properties: shadowProps,
|
||||
// defaultValues: {boxShadow :'0px 0px 0px 0px rgb(0,0,0)', textShadow: '0px 0px 0px 0px rgb(0,0,0)'},
|
||||
Interpolate: {numbers,colors},
|
||||
functions: {onStart: shadowPropOnStart}
|
||||
}
|
||||
|
||||
export default baseShadow
|
||||
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,159 +1,229 @@
|
|||
import Components from '../objects/components.js'
|
||||
import selector from '../util/selector.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import {onStartCubicMorph} from './svgCubicMorphBase.js'
|
||||
|
||||
import parsePathString from 'svg-path-commander/src/process/parsePathString.js'
|
||||
import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute.js'
|
||||
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve.js'
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
import reverseCurve from 'svg-path-commander/src/process/reverseCurve.js'
|
||||
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection.js'
|
||||
import clonePath from 'svg-path-commander/src/process/clonePath.js'
|
||||
import splitCubic from 'svg-path-commander/src/process/splitCubic.js'
|
||||
import splitPath from 'svg-path-commander/src/process/splitPath.js'
|
||||
import getSegCubicLength from 'svg-path-commander/src/util/getSegCubicLength.js'
|
||||
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot.js'
|
||||
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Util
|
||||
function getCurveArray(pathString){
|
||||
return pathToCurve(splitPath(pathToString(pathToAbsolute(pathString)))[0]).map((segment,i,pathArray)=>{
|
||||
let segmentData = i && pathArray[i-1].slice(-2).concat(segment.slice(1)),
|
||||
curveLength = i ? getSegCubicLength.apply(0, segmentData ) : 0,
|
||||
subsegs = i ? (curveLength ? splitCubic( segmentData ) : [segment,segment]) : [segment]; // must be [segment,segment]
|
||||
return {
|
||||
s: segment,
|
||||
ss: subsegs,
|
||||
l: curveLength
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function equalizeSegments(path1,path2,TL){
|
||||
let c1 = getCurveArray(path1),
|
||||
c2 = getCurveArray(path2),
|
||||
L1 = c1.length,
|
||||
L2 = c2.length,
|
||||
l1 = c1.filter(x=>x.l).length,
|
||||
l2 = c2.filter(x=>x.l).length,
|
||||
m1 = c1.filter(x=>x.l).reduce((a,{l})=>a+l,0) / l1 || 0,
|
||||
m2 = c2.filter(x=>x.l).reduce((a,{l})=>a+l,0) / l2 || 0,
|
||||
tl = TL || Math.max(L1,L2),
|
||||
mm = [m1,m2],
|
||||
dif = [tl-L1,tl-L2],
|
||||
canSplit = 0,
|
||||
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)
|
||||
}
|
||||
|
||||
function getRotations(a) {
|
||||
let segCount = a.length, pointCount = segCount - 1
|
||||
|
||||
return a.map((f,idx) => {
|
||||
return a.map((p,i)=>{
|
||||
let oldSegIdx = idx + i, seg;
|
||||
if (i===0 || a[oldSegIdx] && a[oldSegIdx][0] === 'M') {
|
||||
seg = a[oldSegIdx]
|
||||
return ['M'].concat(seg.slice(-2))
|
||||
} else {
|
||||
if (oldSegIdx >= segCount) oldSegIdx -= pointCount;
|
||||
return a[oldSegIdx]
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getRotatedCurve(a,b) {
|
||||
let segCount = a.length - 1,
|
||||
lineLengths = [],
|
||||
computedIndex = 0,
|
||||
sumLensSqrd = 0,
|
||||
rotations = getRotations(a);
|
||||
|
||||
rotations.map((r,i)=>{
|
||||
a.slice(1).map((s,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
|
||||
function getCubicMorph(tweenProp){
|
||||
return this.element.getAttribute('d');
|
||||
}
|
||||
function prepareCubicMorph(tweenProp,value){
|
||||
// get path d attribute or create a path from string value
|
||||
let pathObject = {},
|
||||
el = value instanceof SVGElement ? value : /^\.|^\#/.test(value) ? selector(value) : null,
|
||||
pathReg = new RegExp('\\n','ig'); // remove newlines, they break some JSON strings
|
||||
|
||||
// make sure to return pre-processed values
|
||||
if ( typeof(value) === 'object' && value.curve ) {
|
||||
return value;
|
||||
} else if ( el && /path|glyph/.test(el.tagName) ) {
|
||||
pathObject.original = el.getAttribute('d').replace(pathReg,'');
|
||||
} else if (!el && typeof(value) === 'string') { // maybe it's a string path already
|
||||
pathObject.original = value.replace(pathReg,'');
|
||||
}
|
||||
return pathObject;
|
||||
}
|
||||
function crossCheckCubicMorph(tweenProp){
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
let pathCurve1 = this.valuesStart[tweenProp].curve,
|
||||
pathCurve2 = this.valuesEnd[tweenProp].curve
|
||||
|
||||
if ( !pathCurve1 || !pathCurve2 || ( pathCurve1 && pathCurve2 && pathCurve1[0][0] === 'M' && pathCurve1.length !== pathCurve2.length) ) {
|
||||
let path1 = this.valuesStart[tweenProp].original,
|
||||
path2 = this.valuesEnd[tweenProp].original,
|
||||
curves = equalizeSegments(path1,path2),
|
||||
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,
|
||||
splitCubic, getCurveArray
|
||||
}
|
||||
}
|
||||
|
||||
export default svgCubicMorph
|
||||
|
||||
Components.SVGCubicMorph = svgCubicMorph
|
||||
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,33 +1,38 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Functions
|
||||
export function onStartCubicMorph(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = function(elem,a,b,v){
|
||||
let curve = [], path1 = a.curve, path2 = b.curve;
|
||||
for(let i=0, l=path2.length; i<l; i++) { // each path command
|
||||
curve.push([path1[i][0]]);
|
||||
for(var j=1,l2=path1[i].length;j<l2;j++) { // each command coordinate
|
||||
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
|
||||
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,145 +1,210 @@
|
|||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import {onStartDraw} from './svgDrawBase.js'
|
||||
|
||||
// const svgDraw = { property : 'draw', defaultValue, Interpolate: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Util
|
||||
function percent (v,l) {
|
||||
return parseFloat(v) / 100 * l
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/30376660
|
||||
function getRectLength(el) { // returns the length of a Rect
|
||||
let w = el.getAttribute('width'),
|
||||
h = el.getAttribute('height');
|
||||
return (w*2)+(h*2);
|
||||
}
|
||||
|
||||
function getPolyLength(el) {
|
||||
// getPolygonLength / getPolylineLength - return the length of the Polygon / Polyline
|
||||
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; } // return undefined
|
||||
if (isNaN(c[0]) || isNaN(c[1])) { return; }
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
|
||||
function getLineLength(el) { // return the length of the line
|
||||
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);
|
||||
}
|
||||
|
||||
function getCircleLength(el) { // return the length of the circle
|
||||
const r = el.getAttribute('r');
|
||||
return 2 * Math.PI * r;
|
||||
}
|
||||
|
||||
function getEllipseLength(el) { // returns the length of an ellipse
|
||||
const rx = el.getAttribute('rx'), ry = el.getAttribute('ry'), len = 2*rx, wid = 2*ry;
|
||||
return ((Math.sqrt(.5 * ((len * len) + (wid * wid)))) * (Math.PI * 2)) / 2;
|
||||
}
|
||||
|
||||
function getTotalLength(el) { // returns the result of any of the below functions
|
||||
if ('rect'===el.tagName) {
|
||||
return getRectLength(el);
|
||||
} else if ('circle'===el.tagName) {
|
||||
return getCircleLength(el);
|
||||
} else if ('ellipse'===el.tagName) {
|
||||
return getEllipseLength(el);
|
||||
} else if (['polygon,polyline'].indexOf(el.tagName)>-1) {
|
||||
return getPolyLength(el);
|
||||
} else if ('line'===el.tagName) {
|
||||
return getLineLength(el);
|
||||
}
|
||||
}
|
||||
|
||||
function getDraw(e,v) {
|
||||
let length = /path|glyph/.test(e.tagName) ? e.getTotalLength() : getTotalLength(e),
|
||||
start, end, d, o;
|
||||
|
||||
if ( v instanceof Object ) {
|
||||
return v;
|
||||
} else if (typeof v === 'string') {
|
||||
v = v.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 v === 'undefined') {
|
||||
o = parseFloat(getStyleForProperty(e,'stroke-dashoffset'));
|
||||
d = getStyleForProperty(e,'stroke-dasharray').split(/\,/);
|
||||
|
||||
start = 0-o;
|
||||
end = parseFloat(d[0]) + start || length;
|
||||
}
|
||||
return { s: start, e: end, l: length };
|
||||
}
|
||||
|
||||
function resetDraw(elem) {
|
||||
elem.style.strokeDashoffset = ``;
|
||||
elem.style.strokeDasharray = ``;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
function getDrawValue(){
|
||||
return getDraw(this.element);
|
||||
}
|
||||
function prepareDraw(a,o){
|
||||
return getDraw(this.element,o);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const svgDrawFunctions = {
|
||||
prepareStart: getDrawValue,
|
||||
prepareProperty: prepareDraw,
|
||||
onStart: onStartDraw
|
||||
}
|
||||
|
||||
// Component Full
|
||||
const svgDraw = {
|
||||
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 svgDraw
|
||||
|
||||
Components.SVGDraw = svgDraw
|
||||
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,30 +1,35 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// const svgDraw = { property : 'draw', defaultValue, Interpolate: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Component Functions
|
||||
export function onStartDraw(tweenProp){
|
||||
if ( tweenProp in this.valuesEnd && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem,a,b,v) => {
|
||||
let pathLength = (a.l*100>>0)/100,
|
||||
start = (numbers(a.s,b.s,v)*100>>0)/100,
|
||||
end = (numbers(a.e,b.e,v)*100>>0)/100,
|
||||
offset = 0 - start,
|
||||
dashOne = end+offset;
|
||||
|
||||
elem.style.strokeDashoffset = `${offset}px`;
|
||||
elem.style.strokeDasharray = `${((dashOne <1 ? 0 : dashOne)*100>>0)/100}px, ${pathLength}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseSVGDraw = {
|
||||
component: 'baseSVGDraw',
|
||||
property: 'draw',
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart:onStartDraw}
|
||||
}
|
||||
|
||||
export default baseSVGDraw
|
||||
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,267 +1,367 @@
|
|||
import selector from '../util/selector.js'
|
||||
import defaultOptions from '../objects/defaultOptions.js'
|
||||
import Components from '../objects/components.js'
|
||||
import coords from '../interpolation/coords.js'
|
||||
import {onStartSVGMorph} from './svgMorphBase.js'
|
||||
|
||||
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve.js'
|
||||
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
|
||||
import normalizePath from 'svg-path-commander/src/process/normalizePath.js'
|
||||
import splitPath from 'svg-path-commander/src/process/splitPath.js'
|
||||
import roundPath from 'svg-path-commander/src/process/roundPath.js'
|
||||
import invalidPathValue from 'svg-path-commander/src/util/invalidPathValue.js'
|
||||
import getPathLength from 'svg-path-commander/src/util/getPathLength.js'
|
||||
import getPointAtLength from 'svg-path-commander/src/util/getPointAtLength.js'
|
||||
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection.js'
|
||||
import epsilon from 'svg-path-commander/src/math/epsilon.js'
|
||||
import midPoint from 'svg-path-commander/src/math/midPoint.js'
|
||||
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers,coords} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component Interpolation
|
||||
// function function(array1, array2, length, progress)
|
||||
|
||||
// Component Util
|
||||
// original script flubber
|
||||
// https://github.com/veltman/flubber
|
||||
|
||||
function polygonLength(ring){
|
||||
return ring.reduce((length, point, i) =>
|
||||
i ? length + distanceSquareRoot(ring[i-1],point) : 0, 0 )
|
||||
}
|
||||
|
||||
function pathStringToRing(str, maxSegmentLength) {
|
||||
let parsed = normalizePath(str,0)
|
||||
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
|
||||
}
|
||||
function exactRing(pathArray) {
|
||||
let ring = [],
|
||||
segment = [], pathCommand = '',
|
||||
pathlen = pathArray.length,
|
||||
pathLength = 0;
|
||||
|
||||
if (!pathArray.length || pathArray[0][0] !== "M") {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < pathlen; i++) {
|
||||
segment = pathArray[i]
|
||||
pathCommand = segment[0]
|
||||
|
||||
if (pathCommand === "M" && i || pathCommand === "Z") {
|
||||
break; // !!
|
||||
} else if ('ML'.indexOf( pathCommand) > -1) {
|
||||
ring.push([segment[1], segment[2]]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pathLength = polygonLength(ring)
|
||||
|
||||
return pathlen ? { ring, pathLength } : false;
|
||||
}
|
||||
|
||||
function approximateRing(parsed, maxSegmentLength) {
|
||||
let ringPath = splitPath(pathToString(parsed))[0],
|
||||
curvePath = pathToCurve(ringPath,4),
|
||||
pathLength = getPathLength(curvePath),
|
||||
ring = [], numPoints = 3, point;
|
||||
|
||||
if ( maxSegmentLength && !isNaN(maxSegmentLength) && +maxSegmentLength > 0 ) {
|
||||
numPoints = Math.max(numPoints, Math.ceil(pathLength / maxSegmentLength));
|
||||
}
|
||||
|
||||
for (let i = 0; i < numPoints; i++) {
|
||||
point = getPointAtLength(curvePath,pathLength * i / numPoints)
|
||||
ring.push([point.x, point.y]);
|
||||
}
|
||||
|
||||
// Make all rings clockwise
|
||||
if (!getDrawDirection(curvePath)) {
|
||||
ring.reverse();
|
||||
}
|
||||
|
||||
return {
|
||||
pathLength,
|
||||
ring,
|
||||
skipBisect: true
|
||||
};
|
||||
}
|
||||
function rotateRing(ring, vs) {
|
||||
let len = ring.length, min = Infinity, bestOffset, sumOfSquares, spliced;
|
||||
|
||||
for (let offset = 0; offset < len; offset++) {
|
||||
sumOfSquares = 0;
|
||||
|
||||
vs.forEach(function(p, i) {
|
||||
let d = distanceSquareRoot(ring[(offset + i) % len], p);
|
||||
sumOfSquares += d * d;
|
||||
});
|
||||
|
||||
if (sumOfSquares < min) {
|
||||
min = sumOfSquares;
|
||||
bestOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestOffset) {
|
||||
spliced = ring.splice(0, bestOffset);
|
||||
ring.splice(ring.length, 0, ...spliced);
|
||||
}
|
||||
}
|
||||
function addPoints(ring, numPoints) {
|
||||
let desiredLength = ring.length + numPoints,
|
||||
// step = ring.pathLength / numPoints;
|
||||
step = polygonLength(ring) / numPoints;
|
||||
|
||||
let i = 0, cursor = 0, insertAt = step / 2, a, b, segment;
|
||||
|
||||
while (ring.length < desiredLength) {
|
||||
a = ring[i]
|
||||
b = ring[(i + 1) % ring.length]
|
||||
// console.log(step,a,b)
|
||||
segment = distanceSquareRoot(a, b)
|
||||
|
||||
if (insertAt <= cursor + segment) {
|
||||
ring.splice( i + 1, 0, segment ? midPoint(a, b, (insertAt - cursor) / segment) : a.slice(0) );
|
||||
insertAt += step;
|
||||
continue;
|
||||
}
|
||||
|
||||
cursor += segment;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
function bisect(ring, maxSegmentLength = Infinity) {
|
||||
let a = [], b = []
|
||||
for (let i = 0; i < ring.length; i++) {
|
||||
a = ring[i], b = i === ring.length - 1 ? ring[0] : ring[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);
|
||||
ring.splice(i + 1, 0, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeRing(ring, maxSegmentLength) {
|
||||
let points, skipBisect, pathLength;
|
||||
|
||||
if (typeof ring === "string") {
|
||||
let converted = pathStringToRing(ring, maxSegmentLength)
|
||||
ring = converted.ring
|
||||
skipBisect = converted.skipBisect
|
||||
pathLength = converted.pathLength
|
||||
} else if (!Array.isArray(ring)) {
|
||||
throw (invalidPathValue)
|
||||
}
|
||||
|
||||
points = ring.slice(0)
|
||||
points.pathLength = pathLength
|
||||
|
||||
if (!validRing(points)) {
|
||||
throw (invalidPathValue)
|
||||
}
|
||||
|
||||
// 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 && !isNaN(maxSegmentLength) && (+maxSegmentLength) > 0 ) {
|
||||
bisect(points, maxSegmentLength)
|
||||
}
|
||||
|
||||
return points
|
||||
}
|
||||
function validRing(ring) {
|
||||
return Array.isArray(ring) && ring.every( point =>
|
||||
Array.isArray(point) && point.length === 2 && !isNaN(point[0]) && !isNaN(point[1]))
|
||||
}
|
||||
|
||||
function getInterpolationPoints(pathArray1, pathArray2, morphPrecision) {
|
||||
morphPrecision = morphPrecision || defaultOptions.morphPrecision
|
||||
let fromRing = normalizeRing(pathArray1, morphPrecision),
|
||||
toRing = normalizeRing(pathArray2, morphPrecision),
|
||||
diff = fromRing.length - toRing.length;
|
||||
|
||||
addPoints(fromRing, diff < 0 ? diff * -1 : 0);
|
||||
addPoints(toRing, diff > 0 ? diff : 0);
|
||||
|
||||
rotateRing(fromRing,toRing);
|
||||
|
||||
return [roundPath(fromRing),roundPath(toRing)]
|
||||
}
|
||||
|
||||
|
||||
// Component functions
|
||||
function getSVGMorph(tweenProp){
|
||||
return this.element.getAttribute('d');
|
||||
}
|
||||
function prepareSVGMorph(tweenProp,value){
|
||||
let pathObject = {}, elem = value instanceof SVGElement ? value : /^\.|^\#/.test(value) ? selector(value) : null,
|
||||
pathReg = new RegExp('\\n','ig'); // remove newlines, they brake JSON strings sometimes
|
||||
|
||||
// first make sure we return pre-processed values
|
||||
if ( typeof(value) === 'object' && value.pathArray ) {
|
||||
return value;
|
||||
} else if ( elem && /path|glyph/.test(elem.tagName) ) {
|
||||
pathObject.original = elem.getAttribute('d').replace(pathReg,'');
|
||||
} else if ( !elem && typeof(value) === 'string' ) { // maybe it's a string path already
|
||||
pathObject.original = value.replace(pathReg,'');
|
||||
}
|
||||
return pathObject;
|
||||
}
|
||||
function crossCheckSVGMorph(prop){
|
||||
if ( this.valuesEnd[prop]){
|
||||
let pathArray1 = this.valuesStart[prop].pathArray,
|
||||
pathArray2 = this.valuesEnd[prop].pathArray
|
||||
// skip already processed paths
|
||||
// allow the component to work with pre-processed values
|
||||
if ( !pathArray1 || !pathArray2 || pathArray1 && pathArray2 && pathArray1.length !== pathArray2.length ) {
|
||||
let p1 = this.valuesStart[prop].original,
|
||||
p2 = this.valuesEnd[prop].original,
|
||||
// process morphPrecision
|
||||
morphPrecision = this._morphPrecision ? parseInt(this._morphPrecision) : defaultOptions.morphPrecision,
|
||||
paths = getInterpolationPoints(p1,p2,morphPrecision);
|
||||
this.valuesStart[prop].pathArray = paths[0];
|
||||
this.valuesEnd[prop].pathArray = paths[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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, morphIndex:0},
|
||||
functions: svgMorphFunctions,
|
||||
// Export utils to global for faster execution
|
||||
Util: {
|
||||
addPoints,bisect,normalizeRing,validRing, // component
|
||||
getInterpolationPoints,pathStringToRing,
|
||||
distanceSquareRoot,midPoint,
|
||||
approximateRing,rotateRing,
|
||||
pathToString,pathToCurve,// svg-path-commander
|
||||
getPathLength,getPointAtLength,getDrawDirection,roundPath
|
||||
}
|
||||
}
|
||||
|
||||
export default svgMorph
|
||||
|
||||
Components.SVGMorph = svgMorph
|
||||
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,24 +1,34 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import coords from '../interpolation/coords.js'
|
||||
|
||||
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers,coords} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component functions
|
||||
export function onStartSVGMorph(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
let path1 = a.pathArray, path2 = b.pathArray, len = path2.length;
|
||||
elem.setAttribute("d", (v === 1 ? b.original : `M${coords( path1, path2, len, v ).join('L')}Z`) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component Base
|
||||
const baseSVGMorph = {
|
||||
component: 'baseSVGMorph',
|
||||
property: 'path',
|
||||
Interpolate: coords,
|
||||
functions: {onStart:onStartSVGMorph}
|
||||
}
|
||||
|
||||
export default baseSVGMorph
|
||||
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,130 +1,196 @@
|
|||
import numbers from '../interpolation/numbers.js'
|
||||
import Components from '../objects/components.js'
|
||||
import {svgTransformOnStart} from './svgTransformBase.js'
|
||||
|
||||
// const svgTransform = { property : 'svgTransform', subProperties, defaultValue, Interpolate: {numbers}, functions }
|
||||
|
||||
// Component Util
|
||||
function parseStringOrigin (origin, {x, width}) {
|
||||
return /[a-z]/i.test(origin) && !/px/.test(origin)
|
||||
? origin.replace(/top|left/,0).replace(/right|bottom/,100).replace(/center|middle/,50)
|
||||
: /%/.test(origin) ? (x + parseFloat(origin) * width / 100) : parseFloat(origin);
|
||||
}
|
||||
// helper function that turns transform value from string to object
|
||||
function parseTransformString (a) {
|
||||
let d = a && /\)/.test(a) ? a.substring(0, a.length-1).split(/\)\s|\)/) : 'none', c = {};
|
||||
|
||||
if (d instanceof Array) {
|
||||
for (let j=0, jl = d.length; j<jl; j++){
|
||||
let p = d[j].trim().split('(');
|
||||
c[p[0]] = p[1];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
function parseTransformSVG (p,v){
|
||||
let svgTransformObject = {};
|
||||
|
||||
// by default the transformOrigin is "50% 50%" of the shape box
|
||||
let bb = this.element.getBBox();
|
||||
let cx = bb.x + bb.width/2;
|
||||
let cy = bb.y + bb.height/2;
|
||||
|
||||
let origin = this._transformOrigin;
|
||||
let translation;
|
||||
|
||||
origin = typeof (origin) !== 'undefined' ? (origin.constructor === Array ? origin : origin.split(/\s/)) : [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;
|
||||
|
||||
for ( let i in v ) { // populate the valuesStart and / or valuesEnd
|
||||
if (i === 'rotate'){
|
||||
svgTransformObject[i] = typeof v[i] === 'number' ? v[i] : v[i] instanceof Array ? v[i][0] : v[i].split(/\s/)[0]*1;
|
||||
} else if (i === 'translate'){
|
||||
translation = v[i] instanceof Array ? v[i] : /\,|\s/.test(v[i]) ? v[i].split(',') : [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
|
||||
function prepareSvgTransform(p,v){
|
||||
return parseTransformSVG.call(this,p,v);
|
||||
}
|
||||
// returns an obect with current transform attribute value
|
||||
function getStartSvgTransform (tweenProp,value) {
|
||||
const transformObject = {};
|
||||
const currentTransform = parseTransformString(this.element.getAttribute('transform'));
|
||||
for (let j in value) {
|
||||
// find a value in current attribute value or add a default value
|
||||
transformObject[j] = j in currentTransform ? currentTransform[j] : (j==='scale'?1:0);
|
||||
}
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
function svgTransformCrossCheck(prop) {
|
||||
if (!this._resetStart) return; // fix since 1.6.1 for fromTo() method
|
||||
|
||||
if ( this.valuesEnd[prop] ) {
|
||||
let valuesStart = this.valuesStart[prop];
|
||||
let valuesEnd = this.valuesEnd[prop];
|
||||
let currentTransform = parseTransformSVG.call(this, prop, parseTransformString(this.element.getAttribute('transform')) );
|
||||
|
||||
// populate the valuesStart first
|
||||
for ( let tp in currentTransform ) {
|
||||
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 ? valuesStart.translate[0] : 0,'translate' in valuesStart ? valuesStart.translate[1] : 0) // the current translate
|
||||
.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
|
||||
);
|
||||
valuesStart.translate = [startMatrix.matrix.e,startMatrix.matrix.f]; // finally the translate we're looking for
|
||||
// copy existing and unused properties to the valuesEnd
|
||||
for ( let s in valuesStart) {
|
||||
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
|
||||
|
||||
Components.SVGTransformProperty = svgTransform
|
||||
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,54 +1,63 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
// const svgTransform = { property : 'svgTransform', subProperties, defaultValue, Interpolate: {numbers}, functions }
|
||||
|
||||
// Component Functions
|
||||
export function svgTransformOnStart (tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = (l, a, b, v) => {
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
let tmp;
|
||||
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
|
||||
x -= complex ? b.origin[0] : 0;y -= complex ? b.origin[1] : 0; // we start with removing transformOrigin from translation
|
||||
x *= scale;y *= scale; // we now apply the scale
|
||||
y += skewY ? x*Math.tan(skewY*deg) : 0;x += skewX ? y*Math.tan(skewX*deg) : 0; // now we apply skews
|
||||
tmp = cos*x - sin*y; // apply rotation as well
|
||||
y = rotate ? sin*x + cos*y : y;x = rotate ? tmp : x;
|
||||
x += 'translate' in b ? numbers(a.translate[0],b.translate[0],v) : 0; // now we apply the actual translation
|
||||
y += 'translate' in b ? numbers(a.translate[1],b.translate[1],v) : 0;
|
||||
x += complex ? b.origin[0] : 0;y += complex ? b.origin[1] : 0; // normalizing ends with the addition of the transformOrigin to the translation
|
||||
|
||||
// finally we apply the transform attribute value
|
||||
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
|
||||
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;
|
||||
|
|
|
@ -1,45 +1,55 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getStyleForProperty from '../process/getStyleForProperty.js'
|
||||
import trueDimension from '../util/trueDimension.js'
|
||||
import units from '../interpolation/units.js'
|
||||
import {textPropOnStart} from './textPropertiesBase.js'
|
||||
|
||||
// const textProperties = { category : 'textProperties', defaultValues: [], interpolators: {units} }, functions = { prepareStart, prepareProperty, onStart:{} }
|
||||
|
||||
// Component Properties
|
||||
const textProps = ['fontSize','lineHeight','letterSpacing','wordSpacing']
|
||||
const textOnStart = {}
|
||||
|
||||
// Component Functions
|
||||
textProps.forEach(tweenProp => {
|
||||
textOnStart[tweenProp] = textPropOnStart
|
||||
})
|
||||
export function getTextProp(prop) {
|
||||
return getStyleForProperty(this.element,prop) || defaultValues[prop];
|
||||
}
|
||||
export function prepareTextProp(prop,value) {
|
||||
return trueDimension(value);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const textPropFunctions = {
|
||||
prepareStart: getTextProp,
|
||||
prepareProperty: prepareTextProp,
|
||||
onStart: textOnStart
|
||||
}
|
||||
|
||||
// Component Full
|
||||
const textProperties = {
|
||||
component: 'textProperties',
|
||||
category: 'textProperties',
|
||||
properties: textProps,
|
||||
defaultValues: {fontSize:0,lineHeight:0,letterSpacing:0,wordSpacing:0},
|
||||
Interpolate: {units},
|
||||
functions: textPropFunctions,
|
||||
Util: {trueDimension}
|
||||
}
|
||||
|
||||
export default textProperties
|
||||
|
||||
Components.TextProperties = textProperties
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import getStyleForProperty from '../process/getStyleForProperty';
|
||||
import trueDimension from '../util/trueDimension';
|
||||
import units from '../interpolation/units';
|
||||
import { textPropOnStart } from './textPropertiesBase';
|
||||
|
||||
// Component Properties
|
||||
const textProps = ['fontSize', 'lineHeight', 'letterSpacing', 'wordSpacing'];
|
||||
const textOnStart = {};
|
||||
|
||||
// Component Functions
|
||||
textProps.forEach((tweenProp) => {
|
||||
textOnStart[tweenProp] = textPropOnStart;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the current property computed style.
|
||||
* @param {string} prop the property name
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
export function getTextProp(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
|
||||
*/
|
||||
export function prepareTextProp(/* prop */_, value) {
|
||||
return trueDimension(value);
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const textPropFunctions = {
|
||||
prepareStart: getTextProp,
|
||||
prepareProperty: prepareTextProp,
|
||||
onStart: textOnStart,
|
||||
};
|
||||
|
||||
// Component Full
|
||||
const TextProperties = {
|
||||
component: 'textProperties',
|
||||
category: 'textProperties',
|
||||
properties: textProps,
|
||||
defaultValues: {
|
||||
fontSize: 0, lineHeight: 0, letterSpacing: 0, wordSpacing: 0,
|
||||
},
|
||||
Interpolate: { units },
|
||||
functions: textPropFunctions,
|
||||
Util: { trueDimension },
|
||||
};
|
||||
|
||||
export default TextProperties;
|
||||
|
|
|
@ -1,31 +1,35 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import units from '../interpolation/units.js'
|
||||
|
||||
// const opacity = { category : 'textProperties', defaultValues: [], interpolators: {units} }, functions = { prepareStart, prepareProperty, onStart:{} }
|
||||
|
||||
// Component Properties
|
||||
const textProperties = ['fontSize','lineHeight','letterSpacing','wordSpacing']
|
||||
const textOnStart = {}
|
||||
|
||||
export function textPropOnStart(tweenProp){
|
||||
if (this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem,a,b,v) => {
|
||||
elem.style[tweenProp] = units(a.v,b.v,b.u,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
textProperties.forEach(tweenProp => {
|
||||
textOnStart[tweenProp] = textPropOnStart
|
||||
})
|
||||
|
||||
// Component Base
|
||||
const baseTextProperties = {
|
||||
component: 'baseTextProperties',
|
||||
category: 'textProps',
|
||||
// properties: textProperties,
|
||||
// defaultValues: {fontSize:0,lineHeight:0,letterSpacing:0,wordSpacing:0},
|
||||
Interpolate: {units},
|
||||
functions: {onStart:textOnStart}
|
||||
}
|
||||
|
||||
export default baseTextProperties
|
||||
import KEC from '../objects/kute';
|
||||
import units from '../interpolation/units';
|
||||
|
||||
// Component Properties
|
||||
const textProperties = ['fontSize', 'lineHeight', 'letterSpacing', 'wordSpacing'];
|
||||
const textOnStart = {};
|
||||
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function textPropOnStart(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] = units(a.v, b.v, b.u, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
textProperties.forEach((tweenProp) => {
|
||||
textOnStart[tweenProp] = textPropOnStart;
|
||||
});
|
||||
|
||||
// Component Base
|
||||
const TextPropertiesBase = {
|
||||
component: 'baseTextProperties',
|
||||
category: 'textProps',
|
||||
// properties: textProperties,
|
||||
// defaultValues: {fontSize:0,lineHeight:0,letterSpacing:0,wordSpacing:0},
|
||||
Interpolate: { units },
|
||||
functions: { onStart: textOnStart },
|
||||
};
|
||||
|
||||
export default TextPropertiesBase;
|
||||
|
|
|
@ -1,159 +1,188 @@
|
|||
import connect from '../objects/connect.js'
|
||||
import Components from '../objects/components.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
|
||||
import {onStartWrite,charSet} from './textWriteBase.js'
|
||||
|
||||
// Component Util
|
||||
// utility for multi-child targets
|
||||
// wrapContentsSpan returns an [Element] with the SPAN.tagName and a desired class
|
||||
function wrapContentsSpan(el,classNAME){
|
||||
let textWriteWrapper;
|
||||
let newElem;
|
||||
if ( typeof(el) === 'string' ) {
|
||||
newElem = document.createElement('SPAN')
|
||||
newElem.innerHTML = el
|
||||
newElem.className = classNAME
|
||||
return newElem
|
||||
} else if (!el.children.length || el.children.length && el.children[0].className !== classNAME ) {
|
||||
let elementInnerHTML = el.innerHTML
|
||||
textWriteWrapper = document.createElement('SPAN')
|
||||
textWriteWrapper.className = classNAME
|
||||
textWriteWrapper.innerHTML = elementInnerHTML
|
||||
el.appendChild(textWriteWrapper)
|
||||
el.innerHTML = textWriteWrapper.outerHTML
|
||||
} else if (el.children.length && el.children[0].className === classNAME){
|
||||
textWriteWrapper = el.children[0]
|
||||
}
|
||||
return textWriteWrapper
|
||||
}
|
||||
|
||||
function getTextPartsArray(el,classNAME){
|
||||
let elementsArray = []
|
||||
if (el.children.length) {
|
||||
let textParts = [];
|
||||
let remainingMarkup = el.innerHTML;
|
||||
let wrapperParts;
|
||||
|
||||
for ( let i=0, l = el.children.length, currentChild, childOuter, unTaggedContent; i<l; i++) {
|
||||
|
||||
currentChild = el.children[i]
|
||||
childOuter = currentChild.outerHTML
|
||||
wrapperParts = remainingMarkup.split(childOuter)
|
||||
|
||||
if (wrapperParts[0] !== '') {
|
||||
unTaggedContent = wrapContentsSpan(wrapperParts[0],classNAME)
|
||||
textParts.push( unTaggedContent )
|
||||
remainingMarkup = remainingMarkup.replace(wrapperParts[0],'')
|
||||
} else if (wrapperParts[1] !== '') {
|
||||
unTaggedContent = wrapContentsSpan(wrapperParts[1].split('<')[0],classNAME)
|
||||
textParts.push( unTaggedContent )
|
||||
remainingMarkup = remainingMarkup.replace(wrapperParts[0].split('<')[0],'')
|
||||
}
|
||||
|
||||
!currentChild.classList.contains(classNAME) && currentChild.classList.add(classNAME)
|
||||
textParts.push( currentChild )
|
||||
remainingMarkup = remainingMarkup.replace(childOuter,'')
|
||||
}
|
||||
|
||||
if (remainingMarkup!==''){
|
||||
let unTaggedRemaining = wrapContentsSpan(remainingMarkup,classNAME)
|
||||
textParts.push( unTaggedRemaining )
|
||||
}
|
||||
|
||||
elementsArray = elementsArray.concat(textParts)
|
||||
} else {
|
||||
elementsArray = elementsArray.concat([wrapContentsSpan(el,classNAME)])
|
||||
}
|
||||
return elementsArray
|
||||
}
|
||||
|
||||
function setSegments(target,newText){
|
||||
const oldTargetSegs = getTextPartsArray( target,'text-part');
|
||||
const newTargetSegs = getTextPartsArray( wrapContentsSpan( newText ), 'text-part' );
|
||||
|
||||
target.innerHTML = ''
|
||||
target.innerHTML += oldTargetSegs.map(s=>{ s.className += ' oldText'; return s.outerHTML }).join('')
|
||||
target.innerHTML += newTargetSegs.map(s=>{ s.className += ' newText'; return s.outerHTML.replace(s.innerHTML,'') }).join('')
|
||||
|
||||
return [oldTargetSegs,newTargetSegs]
|
||||
}
|
||||
|
||||
export function createTextTweens(target,newText,options){
|
||||
if (target.playing) return;
|
||||
|
||||
options = options || {}
|
||||
options.duration = options.duration === 'auto' ? 'auto' : isFinite(options.duration*1) ? options.duration*1 : 1000;
|
||||
|
||||
const segs = setSegments(target,newText);
|
||||
const oldTargetSegs = segs[0];
|
||||
const newTargetSegs = segs[1];
|
||||
let oldTargets = [].slice.call(target.getElementsByClassName('oldText')).reverse();
|
||||
let newTargets = [].slice.call(target.getElementsByClassName('newText'));
|
||||
|
||||
let textTween = [], totalDelay = 0
|
||||
|
||||
textTween = textTween.concat(oldTargets.map((el,i) => {
|
||||
options.duration = options.duration === 'auto' ? oldTargetSegs[i].innerHTML.length * 75 : options.duration;
|
||||
options.delay = totalDelay;
|
||||
options.onComplete = null
|
||||
|
||||
totalDelay += options.duration
|
||||
return new connect.tween(el, {text:el.innerHTML}, {text:''}, options );
|
||||
}));
|
||||
textTween = textTween.concat(newTargets.map((el,i)=> {
|
||||
const onComplete = () => {target.innerHTML = newText, target.playing = false};
|
||||
|
||||
options.duration = options.duration === 'auto' ? newTargetSegs[i].innerHTML.length * 75 : options.duration;
|
||||
options.delay = totalDelay;
|
||||
options.onComplete = i === newTargetSegs.length-1 ? onComplete : null
|
||||
totalDelay += options.duration
|
||||
|
||||
return new connect.tween(el, {text:''}, {text:newTargetSegs[i].innerHTML}, options );
|
||||
}));
|
||||
|
||||
textTween.start = function(){
|
||||
!target.playing && textTween.map(tw=>tw.start()) && (target.playing = true)
|
||||
}
|
||||
|
||||
return textTween
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
function getWrite(tweenProp,value){
|
||||
return this.element.innerHTML;
|
||||
}
|
||||
function prepareText(tweenProp,value) {
|
||||
if( tweenProp === 'number' ) {
|
||||
return parseFloat(value)
|
||||
} else {
|
||||
// empty strings crash the update function
|
||||
return value === '' ? ' ' : value
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
export const textWriteFunctions = {
|
||||
prepareStart: getWrite,
|
||||
prepareProperty: prepareText,
|
||||
onStart: onStartWrite
|
||||
}
|
||||
|
||||
// const textWrite = { category : 'textWrite', defaultValues: {}, interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart }
|
||||
|
||||
// Full Component
|
||||
export const textWrite = {
|
||||
component: 'textWriteProperties',
|
||||
category: 'textWrite',
|
||||
properties: ['text','number'],
|
||||
defaultValues: {text: ' ',numbers:'0'},
|
||||
defaultOptions: { textChars: 'alpha' },
|
||||
Interpolate: {numbers},
|
||||
functions: textWriteFunctions,
|
||||
// export to global for faster execution
|
||||
Util: { charSet, createTextTweens }
|
||||
}
|
||||
|
||||
export default textWrite
|
||||
|
||||
Components.TextWriteProperties = textWrite
|
||||
import connect from '../objects/connect';
|
||||
import numbers from '../interpolation/numbers';
|
||||
|
||||
import { onStartWrite, charSet } from './textWriteBase';
|
||||
|
||||
// Component Util
|
||||
// utility for multi-child targets
|
||||
// wrapContentsSpan returns an [Element] with the SPAN.tagName and a desired class
|
||||
function wrapContentsSpan(el, classNAME) {
|
||||
let textWriteWrapper;
|
||||
let newElem;
|
||||
if (typeof (el) === 'string') {
|
||||
newElem = document.createElement('SPAN');
|
||||
newElem.innerHTML = el;
|
||||
newElem.className = classNAME;
|
||||
return newElem;
|
||||
}
|
||||
if (!el.children.length || (el.children.length && el.children[0].className !== classNAME)) {
|
||||
const elementInnerHTML = el.innerHTML;
|
||||
textWriteWrapper = document.createElement('SPAN');
|
||||
textWriteWrapper.className = classNAME;
|
||||
textWriteWrapper.innerHTML = elementInnerHTML;
|
||||
/* eslint-disable no-param-reassign -- impossible to satisfy */
|
||||
el.appendChild(textWriteWrapper);
|
||||
el.innerHTML = textWriteWrapper.outerHTML;
|
||||
/* eslint-enable no-param-reassign -- impossible to satisfy */
|
||||
} else if (el.children.length && el.children[0].className === classNAME) {
|
||||
[textWriteWrapper] = el.children;
|
||||
}
|
||||
return textWriteWrapper;
|
||||
}
|
||||
|
||||
function getTextPartsArray(el, classNAME) {
|
||||
let elementsArray = [];
|
||||
const len = el.children.length;
|
||||
if (len) {
|
||||
const textParts = [];
|
||||
let remainingMarkup = el.innerHTML;
|
||||
let wrapperParts;
|
||||
|
||||
for (let i = 0, currentChild, childOuter, unTaggedContent; i < len; i += 1) {
|
||||
currentChild = el.children[i];
|
||||
childOuter = currentChild.outerHTML;
|
||||
wrapperParts = remainingMarkup.split(childOuter);
|
||||
|
||||
if (wrapperParts[0] !== '') {
|
||||
unTaggedContent = wrapContentsSpan(wrapperParts[0], classNAME);
|
||||
textParts.push(unTaggedContent);
|
||||
remainingMarkup = remainingMarkup.replace(wrapperParts[0], '');
|
||||
} else if (wrapperParts[1] !== '') {
|
||||
unTaggedContent = wrapContentsSpan(wrapperParts[1].split('<')[0], classNAME);
|
||||
textParts.push(unTaggedContent);
|
||||
remainingMarkup = remainingMarkup.replace(wrapperParts[0].split('<')[0], '');
|
||||
}
|
||||
|
||||
if (!currentChild.classList.contains(classNAME)) currentChild.classList.add(classNAME);
|
||||
textParts.push(currentChild);
|
||||
remainingMarkup = remainingMarkup.replace(childOuter, '');
|
||||
}
|
||||
|
||||
if (remainingMarkup !== '') {
|
||||
const unTaggedRemaining = wrapContentsSpan(remainingMarkup, classNAME);
|
||||
textParts.push(unTaggedRemaining);
|
||||
}
|
||||
|
||||
elementsArray = elementsArray.concat(textParts);
|
||||
} else {
|
||||
elementsArray = elementsArray.concat([wrapContentsSpan(el, classNAME)]);
|
||||
}
|
||||
return elementsArray;
|
||||
}
|
||||
|
||||
function setSegments(target, newText) {
|
||||
const oldTargetSegs = getTextPartsArray(target, 'text-part');
|
||||
const newTargetSegs = getTextPartsArray(wrapContentsSpan(newText), 'text-part');
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
target.innerHTML = '';
|
||||
target.innerHTML += oldTargetSegs.map((s) => { s.className += ' oldText'; return s.outerHTML; }).join('');
|
||||
target.innerHTML += newTargetSegs.map((s) => { s.className += ' newText'; return s.outerHTML.replace(s.innerHTML, ''); }).join('');
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
return [oldTargetSegs, newTargetSegs];
|
||||
}
|
||||
|
||||
export function createTextTweens(target, newText, ops) {
|
||||
if (target.playing) return false;
|
||||
|
||||
const options = ops || {};
|
||||
options.duration = 1000;
|
||||
|
||||
if (ops.duration === 'auto') {
|
||||
options.duration = 'auto';
|
||||
} else if (Number.isFinite(ops.duration * 1)) {
|
||||
options.duration = ops.duration * 1;
|
||||
}
|
||||
|
||||
const TweenContructor = connect.tween;
|
||||
const segs = setSegments(target, newText);
|
||||
const oldTargetSegs = segs[0];
|
||||
const newTargetSegs = segs[1];
|
||||
const oldTargets = [].slice.call(target.getElementsByClassName('oldText')).reverse();
|
||||
const newTargets = [].slice.call(target.getElementsByClassName('newText'));
|
||||
|
||||
let textTween = [];
|
||||
let totalDelay = 0;
|
||||
|
||||
textTween = textTween.concat(oldTargets.map((el, i) => {
|
||||
options.duration = options.duration === 'auto'
|
||||
? oldTargetSegs[i].innerHTML.length * 75
|
||||
: options.duration;
|
||||
options.delay = totalDelay;
|
||||
options.onComplete = null;
|
||||
|
||||
totalDelay += options.duration;
|
||||
return new TweenContructor(el, { text: el.innerHTML }, { text: '' }, options);
|
||||
}));
|
||||
textTween = textTween.concat(newTargets.map((el, i) => {
|
||||
function onComplete() {
|
||||
/* eslint-disable no-param-reassign */
|
||||
target.innerHTML = newText;
|
||||
target.playing = false;
|
||||
/* eslint-enable no-param-reassign */
|
||||
}
|
||||
|
||||
options.duration = options.duration === 'auto' ? newTargetSegs[i].innerHTML.length * 75 : options.duration;
|
||||
options.delay = totalDelay;
|
||||
options.onComplete = i === newTargetSegs.length - 1 ? onComplete : null;
|
||||
totalDelay += options.duration;
|
||||
|
||||
return new TweenContructor(el, { text: '' }, { text: newTargetSegs[i].innerHTML }, options);
|
||||
}));
|
||||
|
||||
textTween.start = function startTweens() {
|
||||
if (!target.playing) {
|
||||
textTween.forEach((tw) => tw.start());
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target.playing = true;
|
||||
}
|
||||
};
|
||||
|
||||
return textTween;
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current element `innerHTML`.
|
||||
* @returns {string} computed style for property
|
||||
*/
|
||||
function getWrite(/* tweenProp, value */) {
|
||||
return this.element.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} tweenProp the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {number | string} the property tween object
|
||||
*/
|
||||
function prepareText(tweenProp, value) {
|
||||
if (tweenProp === 'number') {
|
||||
return parseFloat(value);
|
||||
}
|
||||
// empty strings crash the update function
|
||||
return value === '' ? ' ' : value;
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
export const textWriteFunctions = {
|
||||
prepareStart: getWrite,
|
||||
prepareProperty: prepareText,
|
||||
onStart: onStartWrite,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
export const TextWrite = {
|
||||
component: 'textWriteProperties',
|
||||
category: 'textWrite',
|
||||
properties: ['text', 'number'],
|
||||
defaultValues: { text: ' ', number: '0' },
|
||||
defaultOptions: { textChars: 'alpha' },
|
||||
Interpolate: { numbers },
|
||||
functions: textWriteFunctions,
|
||||
// export to global for faster execution
|
||||
Util: { charSet, createTextTweens },
|
||||
};
|
||||
|
||||
export default TextWrite;
|
||||
|
|
|
@ -1,78 +1,102 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import defaultOptions from '../objects/defaultOptions.js'
|
||||
|
||||
// Component Values
|
||||
const lowerCaseAlpha = String("abcdefghijklmnopqrstuvwxyz").split(""), // lowercase
|
||||
upperCaseAlpha = String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""), // uppercase
|
||||
nonAlpha = String("~!@#$%^&*()_+{}[];'<>,./?\=-").split(""), // symbols
|
||||
numeric = String("0123456789").split(""), // numeric
|
||||
alphaNumeric = lowerCaseAlpha.concat(upperCaseAlpha,numeric), // alpha numeric
|
||||
allTypes = alphaNumeric.concat(nonAlpha); // all caracters
|
||||
|
||||
const charSet = {
|
||||
alpha: lowerCaseAlpha, // lowercase
|
||||
upper: upperCaseAlpha, // uppercase
|
||||
symbols: nonAlpha, // symbols
|
||||
numeric: numeric,
|
||||
alphanumeric: alphaNumeric,
|
||||
all: allTypes,
|
||||
}
|
||||
|
||||
export {charSet}
|
||||
|
||||
// Component Functions
|
||||
export const onStartWrite = {
|
||||
text: function(tweenProp){
|
||||
if ( !KUTE[tweenProp] && this.valuesEnd[tweenProp] ) {
|
||||
|
||||
let chars = this._textChars,
|
||||
charsets = chars in charSet ? charSet[chars]
|
||||
: chars && chars.length ? chars
|
||||
: charSet[defaultOptions.textChars]
|
||||
|
||||
KUTE[tweenProp] = function(elem,a,b,v) {
|
||||
|
||||
let initialText = '',
|
||||
endText = '',
|
||||
firstLetterA = a.substring(0),
|
||||
firstLetterB = b.substring(0),
|
||||
pointer = charsets[(Math.random() * charsets.length)>>0];
|
||||
|
||||
if (a === ' ') {
|
||||
endText = firstLetterB.substring(Math.min(v * firstLetterB.length, firstLetterB.length)>>0, 0 );
|
||||
elem.innerHTML = v < 1 ? ( ( endText + pointer ) ) : (b === '' ? ' ' : b);
|
||||
} else if (b === ' ') {
|
||||
initialText = firstLetterA.substring(0, Math.min((1-v) * firstLetterA.length, firstLetterA.length)>>0 );
|
||||
elem.innerHTML = v < 1 ? ( ( initialText + pointer ) ) : (b === '' ? ' ' : b);
|
||||
} else {
|
||||
initialText = firstLetterA.substring(firstLetterA.length, Math.min(v * firstLetterA.length, firstLetterA.length)>>0 );
|
||||
endText = firstLetterB.substring(0, Math.min(v * firstLetterB.length, firstLetterB.length)>>0 );
|
||||
elem.innerHTML = v < 1 ? ( (endText + pointer + initialText) ) : (b === '' ? ' ' : b);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
number: function(tweenProp) {
|
||||
if ( tweenProp in this.valuesEnd && !KUTE[tweenProp]) { // numbers can be 0
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.innerHTML = numbers(a, b, v)>>0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
export const baseTextWrite = {
|
||||
component: 'baseTextWrite',
|
||||
category: 'textWrite',
|
||||
// properties: ['text','number'],
|
||||
// defaultValues: {text: ' ',numbers:'0'},
|
||||
defaultOptions: { textChars: 'alpha' },
|
||||
Interpolate: {numbers},
|
||||
functions: {onStart:onStartWrite},
|
||||
// export to global for faster execution
|
||||
Util: { charSet }
|
||||
}
|
||||
|
||||
export default baseTextWrite
|
||||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import defaultOptions from '../objects/defaultOptions';
|
||||
|
||||
// Component Values
|
||||
const lowerCaseAlpha = String('abcdefghijklmnopqrstuvwxyz').split(''); // lowercase
|
||||
const upperCaseAlpha = String('abcdefghijklmnopqrstuvwxyz').toUpperCase().split(''); // uppercase
|
||||
const nonAlpha = String("~!@#$%^&*()_+{}[];'<>,./?=-").split(''); // symbols
|
||||
const numeric = String('0123456789').split(''); // numeric
|
||||
const alphaNumeric = lowerCaseAlpha.concat(upperCaseAlpha, numeric); // alpha numeric
|
||||
const allTypes = alphaNumeric.concat(nonAlpha); // all caracters
|
||||
|
||||
const charSet = {
|
||||
alpha: lowerCaseAlpha, // lowercase
|
||||
upper: upperCaseAlpha, // uppercase
|
||||
symbols: nonAlpha, // symbols
|
||||
numeric,
|
||||
alphanumeric: alphaNumeric,
|
||||
all: allTypes,
|
||||
};
|
||||
|
||||
export { charSet };
|
||||
|
||||
// Component Functions
|
||||
export const onStartWrite = {
|
||||
/**
|
||||
* onStartWrite.text
|
||||
*
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
text(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
const chars = this._textChars;
|
||||
let charsets = charSet[defaultOptions.textChars];
|
||||
|
||||
if (chars in charSet) {
|
||||
charsets = charSet[chars];
|
||||
} else if (chars && chars.length) {
|
||||
charsets = chars;
|
||||
}
|
||||
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
let initialText = '';
|
||||
let endText = '';
|
||||
const finalText = b === '' ? ' ' : b;
|
||||
const firstLetterA = a.substring(0);
|
||||
const firstLetterB = b.substring(0);
|
||||
/* eslint-disable */
|
||||
const pointer = charsets[(Math.random() * charsets.length) >> 0];
|
||||
|
||||
if (a === ' ') {
|
||||
endText = firstLetterB
|
||||
.substring(Math.min(v * firstLetterB.length, firstLetterB.length) >> 0, 0);
|
||||
elem.innerHTML = v < 1 ? ((endText + pointer)) : finalText;
|
||||
} else if (b === ' ') {
|
||||
initialText = firstLetterA
|
||||
.substring(0, Math.min((1 - v) * firstLetterA.length, firstLetterA.length) >> 0);
|
||||
elem.innerHTML = v < 1 ? ((initialText + pointer)) : finalText;
|
||||
} else {
|
||||
initialText = firstLetterA
|
||||
.substring(firstLetterA.length,
|
||||
Math.min(v * firstLetterA.length, firstLetterA.length) >> 0);
|
||||
endText = firstLetterB
|
||||
.substring(0, Math.min(v * firstLetterB.length, firstLetterB.length) >> 0);
|
||||
elem.innerHTML = v < 1 ? ((endText + pointer + initialText)) : finalText;
|
||||
}
|
||||
/* eslint-enable */
|
||||
};
|
||||
}
|
||||
},
|
||||
/**
|
||||
* onStartWrite.number
|
||||
*
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
number(tweenProp) {
|
||||
if (tweenProp in this.valuesEnd && !KEC[tweenProp]) { // numbers can be 0
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
/* eslint-disable */
|
||||
elem.innerHTML = numbers(a, b, v) >> 0;
|
||||
/* eslint-enable */
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Base Component
|
||||
export const TextWriteBase = {
|
||||
component: 'baseTextWrite',
|
||||
category: 'textWrite',
|
||||
// properties: ['text','number'],
|
||||
// defaultValues: {text: ' ',numbers:'0'},
|
||||
defaultOptions: { textChars: 'alpha' },
|
||||
Interpolate: { numbers },
|
||||
functions: { onStart: onStartWrite },
|
||||
// export to global for faster execution
|
||||
Util: { charSet },
|
||||
};
|
||||
|
||||
export default TextWriteBase;
|
||||
|
|
|
@ -1,109 +1,152 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getInlineStyle from '../process/getInlineStyle.js'
|
||||
import perspective from '../interpolation/perspective.js'
|
||||
import translate3d from '../interpolation/translate3d.js'
|
||||
import rotate3d from '../interpolation/rotate3d.js'
|
||||
import translate from '../interpolation/translate.js'
|
||||
import rotate from '../interpolation/rotate.js'
|
||||
import scale from '../interpolation/scale.js'
|
||||
import skew from '../interpolation/skew.js'
|
||||
import {onStartTransform} from './transformFunctionsBase.js'
|
||||
|
||||
// const transformFunctions = { property : 'transform', subProperties, defaultValues, Interpolate: {translate,rotate,skew,scale}, functions } // same to svg transform, attr
|
||||
// the component developed for modern browsers supporting non-prefixed transform
|
||||
|
||||
// Component Functions
|
||||
function getTransform(tweenProperty,value){
|
||||
let currentStyle = getInlineStyle(this.element);
|
||||
return currentStyle[tweenProperty] ? currentStyle[tweenProperty] : defaultValues[tweenProperty];
|
||||
}
|
||||
function prepareTransform(prop,obj){
|
||||
let prepAxis = ['X', 'Y', 'Z'], // coordinates
|
||||
transformObject = {},
|
||||
translateArray = [], rotateArray = [], skewArray = [],
|
||||
arrayFunctions = ['translate3d','translate','rotate3d','skew']
|
||||
|
||||
for (let x in obj) {
|
||||
let pv = typeof obj[x] === 'object' && obj[x].length ? obj[x].map(v=>parseInt(v)) : parseInt(obj[x]);
|
||||
|
||||
if (arrayFunctions.includes(x)) {
|
||||
let propId = x === 'translate' || x === 'rotate' ? `${x}3d` : x;
|
||||
|
||||
transformObject[propId] = x === 'skew' ? (pv.length ? [pv[0]||0, pv[1]||0] : [pv||0,0] )
|
||||
: x === 'translate' ? (pv.length ? [pv[0]||0, pv[1]||0, pv[2]||0] : [pv||0,0,0] )
|
||||
: [pv[0]||0, pv[1]||0,pv[2]||0] // translate3d | rotate3d
|
||||
|
||||
} else if ( /[XYZ]/.test(x) ) {
|
||||
let fn = x.replace(/[XYZ]/,''),
|
||||
fnId = fn === 'skew' ? fn : `${fn}3d`,
|
||||
fnLen = fn === 'skew' ? 2 : 3,
|
||||
fnArray = fn === 'translate' ? translateArray
|
||||
: fn === 'rotate' ? rotateArray
|
||||
: fn === 'skew' ? skewArray : {}
|
||||
for (let fnIndex = 0; fnIndex < fnLen; fnIndex++) {
|
||||
let fnAxis = prepAxis[fnIndex];
|
||||
fnArray[fnIndex] = (`${fn}${fnAxis}` in obj) ? parseInt(obj[`${fn}${fnAxis}`]) : 0;
|
||||
}
|
||||
transformObject[fnId] = fnArray;
|
||||
} else if (x==='rotate') { // rotate
|
||||
transformObject['rotate3d'] = [0,0,pv]
|
||||
} else { // scale | perspective
|
||||
transformObject[x] = x === 'scale' ? parseFloat(obj[x]) : pv
|
||||
}
|
||||
}
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
function crossCheckTransform(tweenProp){
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if ( this.valuesEnd[tweenProp] ) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective){
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const transformFunctions = {
|
||||
prepareStart: getTransform,
|
||||
prepareProperty: prepareTransform,
|
||||
onStart: onStartTransform,
|
||||
crossCheck: crossCheckTransform
|
||||
}
|
||||
|
||||
const supportedTransformProperties = [
|
||||
'perspective',
|
||||
'translate3d', 'translateX', 'translateY', 'translateZ', 'translate',
|
||||
'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'rotate',
|
||||
'skewX', 'skewY', 'skew',
|
||||
'scale'
|
||||
]
|
||||
|
||||
const defaultTransformValues = {
|
||||
perspective: 400,
|
||||
translate3d : [0,0,0], translateX : 0, translateY : 0, translateZ : 0, translate : [0,0],
|
||||
rotate3d: [0,0,0], rotateX : 0, rotateY : 0, rotateZ : 0, rotate : 0,
|
||||
skewX : 0, skewY : 0, skew: [0,0],
|
||||
scale : 1
|
||||
}
|
||||
|
||||
// Full Component
|
||||
const transformFunctionsComponent = {
|
||||
component: 'transformFunctions',
|
||||
property: 'transform',
|
||||
subProperties: supportedTransformProperties,
|
||||
defaultValues: defaultTransformValues,
|
||||
functions: transformFunctions,
|
||||
Interpolate: {
|
||||
perspective: perspective,
|
||||
translate3d: translate3d,
|
||||
rotate3d: rotate3d,
|
||||
translate: translate, rotate: rotate, scale: scale, skew: skew
|
||||
}
|
||||
}
|
||||
|
||||
export default transformFunctionsComponent
|
||||
|
||||
Components.TransformFunctions = transformFunctionsComponent
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import getInlineStyle from '../process/getInlineStyle';
|
||||
import perspective from '../interpolation/perspective';
|
||||
import translate3d from '../interpolation/translate3d';
|
||||
import rotate3d from '../interpolation/rotate3d';
|
||||
import translate from '../interpolation/translate';
|
||||
import rotate from '../interpolation/rotate';
|
||||
import scale from '../interpolation/scale';
|
||||
import skew from '../interpolation/skew';
|
||||
import { onStartTransform } from './transformFunctionsBase';
|
||||
|
||||
// same to svg transform, attr
|
||||
// the component developed for modern browsers supporting non-prefixed transform
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property inline style.
|
||||
* @param {string} tweenProp the property name
|
||||
* @returns {string} inline style for property
|
||||
*/
|
||||
function getTransform(tweenProp/* , value */) {
|
||||
const currentStyle = getInlineStyle(this.element);
|
||||
return currentStyle[tweenProp] ? currentStyle[tweenProp] : defaultValues[tweenProp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {Object<string, string | number | (string | number)[]>} obj the property value
|
||||
* @returns {KUTE.transformFObject} the property tween object
|
||||
*/
|
||||
function prepareTransform(/* prop, */_, obj) {
|
||||
const prepAxis = ['X', 'Y', 'Z']; // coordinates
|
||||
const transformObject = {};
|
||||
const translateArray = []; const rotateArray = []; const skewArray = [];
|
||||
const arrayFunctions = ['translate3d', 'translate', 'rotate3d', 'skew'];
|
||||
|
||||
Object.keys(obj).forEach((x) => {
|
||||
const pv = typeof obj[x] === 'object' && obj[x].length
|
||||
? obj[x].map((v) => parseInt(v, 10))
|
||||
: parseInt(obj[x], 10);
|
||||
|
||||
if (arrayFunctions.includes(x)) {
|
||||
const propId = x === 'translate' || x === 'rotate' ? `${x}3d` : x;
|
||||
|
||||
if (x === 'skew') {
|
||||
transformObject[propId] = pv.length
|
||||
? [pv[0] || 0, pv[1] || 0]
|
||||
: [pv || 0, 0];
|
||||
} else if (x === 'translate') {
|
||||
transformObject[propId] = pv.length
|
||||
? [pv[0] || 0, pv[1] || 0, pv[2] || 0]
|
||||
: [pv || 0, 0, 0];
|
||||
} else { // translate3d | rotate3d
|
||||
transformObject[propId] = [pv[0] || 0, pv[1] || 0, pv[2] || 0];
|
||||
}
|
||||
} else if (/[XYZ]/.test(x)) {
|
||||
const fn = x.replace(/[XYZ]/, '');
|
||||
const fnId = fn === 'skew' ? fn : `${fn}3d`;
|
||||
const fnLen = fn === 'skew' ? 2 : 3;
|
||||
let fnArray = [];
|
||||
|
||||
if (fn === 'translate') {
|
||||
fnArray = translateArray;
|
||||
} else if (fn === 'rotate') {
|
||||
fnArray = rotateArray;
|
||||
} else if (fn === 'skew') {
|
||||
fnArray = skewArray;
|
||||
}
|
||||
|
||||
for (let fnIndex = 0; fnIndex < fnLen; fnIndex += 1) {
|
||||
const fnAxis = prepAxis[fnIndex];
|
||||
fnArray[fnIndex] = (`${fn}${fnAxis}` in obj) ? parseInt(obj[`${fn}${fnAxis}`], 10) : 0;
|
||||
}
|
||||
transformObject[fnId] = fnArray;
|
||||
} else if (x === 'rotate') { // rotate
|
||||
transformObject.rotate3d = [0, 0, pv];
|
||||
} else { // scale | perspective
|
||||
transformObject[x] = x === 'scale' ? parseFloat(obj[x]) : pv;
|
||||
}
|
||||
});
|
||||
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare tween object in advance for `to()` method.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
function crossCheckTransform(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective) {
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const transformFunctions = {
|
||||
prepareStart: getTransform,
|
||||
prepareProperty: prepareTransform,
|
||||
onStart: onStartTransform,
|
||||
crossCheck: crossCheckTransform,
|
||||
};
|
||||
|
||||
const supportedTransformProperties = [
|
||||
'perspective',
|
||||
'translate3d', 'translateX', 'translateY', 'translateZ', 'translate',
|
||||
'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'rotate',
|
||||
'skewX', 'skewY', 'skew',
|
||||
'scale',
|
||||
];
|
||||
|
||||
const defaultTransformValues = {
|
||||
perspective: 400,
|
||||
translate3d: [0, 0, 0],
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
translateZ: 0,
|
||||
translate: [0, 0],
|
||||
rotate3d: [0, 0, 0],
|
||||
rotateX: 0,
|
||||
rotateY: 0,
|
||||
rotateZ: 0,
|
||||
rotate: 0,
|
||||
skewX: 0,
|
||||
skewY: 0,
|
||||
skew: [0, 0],
|
||||
scale: 1,
|
||||
};
|
||||
|
||||
// Full Component
|
||||
const TransformFunctions = {
|
||||
component: 'transformFunctions',
|
||||
property: 'transform',
|
||||
subProperties: supportedTransformProperties,
|
||||
defaultValues: defaultTransformValues,
|
||||
functions: transformFunctions,
|
||||
Interpolate: {
|
||||
perspective,
|
||||
translate3d,
|
||||
rotate3d,
|
||||
translate,
|
||||
rotate,
|
||||
scale,
|
||||
skew,
|
||||
},
|
||||
};
|
||||
|
||||
export default TransformFunctions;
|
||||
|
|
|
@ -1,39 +1,45 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import perspective from '../interpolation/perspective.js'
|
||||
import translate3d from '../interpolation/translate3d.js'
|
||||
import rotate3d from '../interpolation/rotate3d.js'
|
||||
import translate from '../interpolation/translate.js'
|
||||
import rotate from '../interpolation/rotate.js'
|
||||
import scale from '../interpolation/scale.js'
|
||||
import skew from '../interpolation/skew.js'
|
||||
|
||||
// const transformFunctions = { property : 'transform', subProperties, defaultValues, Interpolate: {translate,rotate,skew,scale}, functions } // same to svg transform, attr
|
||||
|
||||
// Component Functions
|
||||
export function onStartTransform(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[tweenProp] =
|
||||
(a.perspective||b.perspective ? perspective(a.perspective,b.perspective,'px',v) : '') // one side might be 0
|
||||
+ (a.translate3d ? translate3d(a.translate3d,b.translate3d,'px',v):'') // array [x,y,z]
|
||||
+ (a.rotate3d ? rotate3d(a.rotate3d,b.rotate3d,'deg',v):'') // array [x,y,z]
|
||||
+ (a.skew ? skew(a.skew,b.skew,'deg',v):'') // array [x,y]
|
||||
+ (a.scale||b.scale ? scale(a.scale,b.scale,v):'') // one side might be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const BaseTransform = {
|
||||
component: 'baseTransform',
|
||||
property: 'transform',
|
||||
functions: {onStart: onStartTransform},
|
||||
Interpolate: {
|
||||
perspective: perspective,
|
||||
translate3d: translate3d,
|
||||
rotate3d: rotate3d,
|
||||
translate: translate, rotate: rotate, scale: scale, skew: skew
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseTransform
|
||||
import KEC from '../objects/kute';
|
||||
import perspective from '../interpolation/perspective';
|
||||
import translate3d from '../interpolation/translate3d';
|
||||
import rotate3d from '../interpolation/rotate3d';
|
||||
import translate from '../interpolation/translate';
|
||||
import rotate from '../interpolation/rotate';
|
||||
import scale from '../interpolation/scale';
|
||||
import skew from '../interpolation/skew';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* * same to svgTransform, htmlAttributes
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartTransform(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
elem.style[tweenProp] = (a.perspective || b.perspective ? perspective(a.perspective, b.perspective, 'px', v) : '') // one side might be 0
|
||||
+ (a.translate3d ? translate3d(a.translate3d, b.translate3d, 'px', v) : '') // array [x,y,z]
|
||||
+ (a.rotate3d ? rotate3d(a.rotate3d, b.rotate3d, 'deg', v) : '') // array [x,y,z]
|
||||
+ (a.skew ? skew(a.skew, b.skew, 'deg', v) : '') // array [x,y]
|
||||
+ (a.scale || b.scale ? scale(a.scale, b.scale, v) : ''); // one side might be 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const TransformFunctionsBase = {
|
||||
component: 'baseTransform',
|
||||
property: 'transform',
|
||||
functions: { onStart: onStartTransform },
|
||||
Interpolate: {
|
||||
perspective,
|
||||
translate3d,
|
||||
rotate3d,
|
||||
translate,
|
||||
rotate,
|
||||
scale,
|
||||
skew,
|
||||
},
|
||||
};
|
||||
|
||||
export default TransformFunctionsBase;
|
||||
|
|
|
@ -1,134 +1,172 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import getInlineStyleLegacy from '../process/getInlineStyleLegacy.js'
|
||||
import perspective from '../interpolation/perspective.js'
|
||||
import translate3d from '../interpolation/translate3d.js'
|
||||
import rotate3d from '../interpolation/rotate3d.js'
|
||||
import translate from '../interpolation/translate.js'
|
||||
import rotate from '../interpolation/rotate.js'
|
||||
import scale from '../interpolation/scale.js'
|
||||
import skew from '../interpolation/skew.js'
|
||||
|
||||
import support3DTransform from 'shorter-js/src/boolean/support3DTransform.js'
|
||||
import {onStartLegacyTransform} from './transformLegacyBase.js'
|
||||
import transformProperty from '../util/transformProperty.js'
|
||||
import supportTransform from '../util/supportLegacyTransform.js'
|
||||
|
||||
|
||||
// const transformFunctions = { property : 'transform', subProperties, defaultValues, Interpolate: {translate,rotate,skew,scale}, functions } // same to svg transform, attr
|
||||
// the component to handle all kinds of input values and process according to browser supported API,
|
||||
// the component that handles all browsers IE9+
|
||||
|
||||
// Component Functions
|
||||
function getLegacyTransform(tweenProperty,value){
|
||||
const currentStyle = getInlineStyleLegacy(this.element);
|
||||
return currentStyle[tweenProperty] ? currentStyle[tweenProperty] : defaultValues[tweenProperty];
|
||||
}
|
||||
function prepareLegacyTransform(prop,obj){
|
||||
let prepAxis = ['X', 'Y', 'Z'], // coordinates
|
||||
translateArray = [], rotateArray = [], skewArray = [],
|
||||
transformObject = {},
|
||||
arrayFunctions = ['translate3d','translate','rotate3d','skew']
|
||||
|
||||
for (let x in obj) {
|
||||
let pv = typeof(obj[x]) === 'object' && obj[x].length ? obj[x].map(v=>parseInt(v)) : parseInt(obj[x])
|
||||
|
||||
if (arrayFunctions.includes(x)) {
|
||||
|
||||
if (support3DTransform){
|
||||
if (x==='translate3d' || x==='rotate3d') {
|
||||
transformObject[x] = pv
|
||||
} else if (x==='translate'){
|
||||
transformObject['translate3d'] = pv.length ? pv.concat(0) : [pv||0,0,0]
|
||||
} else if (x==='rotate'){
|
||||
transformObject['rotate3d'] = [0,0,pv||0]
|
||||
} else if (x==='skew'){
|
||||
transformObject[x] = pv.length ? pv : [pv||0,0]
|
||||
}
|
||||
} else if (supportTransform) {
|
||||
if (x==='translate3d') {
|
||||
transformObject['translate'] = [pv[0]||0,pv[1]||0]
|
||||
} else if (x==='translate' || x==='skew'){
|
||||
transformObject[x] = pv.length ? pv : [pv||0,0]
|
||||
} else if (x==='rotate3d'){
|
||||
transformObject['rotate'] = pv[2]||pv[1]||pv[0]
|
||||
} else if (x==='rotate'){
|
||||
transformObject[x] = pv
|
||||
}
|
||||
}
|
||||
|
||||
} else if ( /[XYZ]/.test(x) ) {
|
||||
let fn = x.replace(/[XYZ]/,''),
|
||||
fnId = fn === 'skew' || !support3DTransform ? fn : `${fn}3d`,
|
||||
fnLen = fn === 'skew' || (!support3DTransform && fn === 'translate') ? 2 : 3,
|
||||
fnArray = fn === 'translate' ? translateArray
|
||||
: fn === 'rotate' && support3DTransform ? rotateArray
|
||||
: fn === 'skew' ? skewArray : {}
|
||||
for (let fnIndex = 0; fnIndex < fnLen; fnIndex++) {
|
||||
let fnAxis = prepAxis[fnIndex];
|
||||
fnArray[fnIndex] = (`${fn}${fnAxis}` in obj) ? parseInt(obj[`${fn}${fnAxis}`]) : 0;
|
||||
}
|
||||
transformObject[fnId] = support3DTransform ? fnArray : fn === 'rotate' ? fnArray[2]||fnArray[1]||fnArray[0] : fnArray;
|
||||
} else if (x==='rotate') { // 2d rotate
|
||||
let pType = support3DTransform ? 'rotate3d' : 'rotate';
|
||||
transformObject[pType] = support3DTransform ? [0,0,pv] : pv
|
||||
} else { // scale | perspective
|
||||
transformObject[x] = x === 'scale' ? parseFloat(obj[x]) : pv
|
||||
}
|
||||
}
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
function crossCheckLegacyTransform(tweenProp){
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if ( this.valuesEnd[tweenProp] && support3DTransform) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective){
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const transformLegacyFunctions = {
|
||||
prepareStart: getLegacyTransform,
|
||||
prepareProperty: prepareLegacyTransform,
|
||||
onStart: onStartLegacyTransform,
|
||||
crossCheck: crossCheckLegacyTransform
|
||||
}
|
||||
|
||||
const legacyTransformValues = {
|
||||
perspective: 400,
|
||||
translate3d: [0,0,0], translateX: 0, translateY: 0, translateZ: 0, translate: [0,0],
|
||||
rotate3d: [0,0,0], rotateX: 0, rotateY: 0, rotateZ: 0, rotate: 0,
|
||||
skewX: 0, skewY: 0, skew: [0,0],
|
||||
scale: 1
|
||||
}
|
||||
|
||||
const legacyTransformProperties = [
|
||||
'perspective',
|
||||
'translate3d', 'translateX', 'translateY', 'translateZ', 'translate',
|
||||
'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'rotate',
|
||||
'skewX', 'skewY', 'skew',
|
||||
'scale'
|
||||
]
|
||||
|
||||
// Full Component
|
||||
const transformLegacyComponent = {
|
||||
component: 'transformFunctions',
|
||||
property: 'transform',
|
||||
subProperties: legacyTransformProperties,
|
||||
defaultValues: legacyTransformValues,
|
||||
functions: transformLegacyFunctions,
|
||||
Interpolate: {
|
||||
perspective: perspective,
|
||||
translate3d: translate3d,
|
||||
rotate3d: rotate3d,
|
||||
translate: translate, rotate: rotate, scale: scale, skew: skew
|
||||
},
|
||||
Util: [transformProperty]
|
||||
}
|
||||
|
||||
export default transformLegacyComponent
|
||||
|
||||
Components.TransformLegacy = transformLegacyComponent
|
||||
import support3DTransform from 'shorter-js/src/boolean/support3DTransform';
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import getInlineStyleLegacy from '../process/getInlineStyleLegacy';
|
||||
import perspective from '../interpolation/perspective';
|
||||
import translate3d from '../interpolation/translate3d';
|
||||
import rotate3d from '../interpolation/rotate3d';
|
||||
import translate from '../interpolation/translate';
|
||||
import rotate from '../interpolation/rotate';
|
||||
import scale from '../interpolation/scale';
|
||||
import skew from '../interpolation/skew';
|
||||
|
||||
import { onStartLegacyTransform } from './transformLegacyBase';
|
||||
import transformProperty from '../util/transformProperty';
|
||||
import supportTransform from '../util/supportLegacyTransform';
|
||||
|
||||
// same to svg transform, attr
|
||||
// the component to handle all kinds of input values and process according to browser supported API,
|
||||
// the component that handles all browsers IE9+
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current property inline style.
|
||||
* @param {string} tweenProperty the property name
|
||||
* @returns {string} inline style for property
|
||||
*/
|
||||
function getLegacyTransform(tweenProperty/* , value */) {
|
||||
const currentStyle = getInlineStyleLegacy(this.element);
|
||||
return currentStyle[tweenProperty] ? currentStyle[tweenProperty] : defaultValues[tweenProperty];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {Object<string, string | number | (string | number)[]>} obj the property value
|
||||
* @returns {KUTE.transformFObject} the property tween object
|
||||
*/
|
||||
function prepareLegacyTransform(/* prop */_, obj) {
|
||||
const prepAxis = ['X', 'Y', 'Z']; // coordinates
|
||||
const translateArray = []; const rotateArray = []; const skewArray = [];
|
||||
const transformObject = {};
|
||||
const arrayFunctions = ['translate3d', 'translate', 'rotate3d', 'skew'];
|
||||
|
||||
Object.keys(obj).forEach((x) => {
|
||||
const pv = typeof (obj[x]) === 'object' && obj[x].length
|
||||
? obj[x].map((v) => parseInt(v, 10))
|
||||
: parseInt(obj[x], 10);
|
||||
|
||||
if (arrayFunctions.includes(x)) {
|
||||
if (support3DTransform) {
|
||||
if (x === 'translate3d' || x === 'rotate3d') {
|
||||
transformObject[x] = pv;
|
||||
} else if (x === 'translate') {
|
||||
transformObject.translate3d = pv.length ? pv.concat(0) : [pv || 0, 0, 0];
|
||||
} else if (x === 'rotate') {
|
||||
transformObject.rotate3d = [0, 0, pv || 0];
|
||||
} else if (x === 'skew') {
|
||||
transformObject[x] = pv.length ? pv : [pv || 0, 0];
|
||||
}
|
||||
} else if (supportTransform) {
|
||||
if (x === 'translate3d') {
|
||||
transformObject.translate = [pv[0] || 0, pv[1] || 0];
|
||||
} else if (x === 'translate' || x === 'skew') {
|
||||
transformObject[x] = pv.length ? pv : [pv || 0, 0];
|
||||
} else if (x === 'rotate3d') {
|
||||
transformObject.rotate = pv[2] || pv[1] || pv[0];
|
||||
} else if (x === 'rotate') {
|
||||
transformObject[x] = pv;
|
||||
}
|
||||
}
|
||||
} else if (/[XYZ]/.test(x)) {
|
||||
const fn = x.replace(/[XYZ]/, '');
|
||||
const fnId = fn === 'skew' || !support3DTransform ? fn : `${fn}3d`;
|
||||
const fnLen = fn === 'skew' || (!support3DTransform && fn === 'translate') ? 2 : 3;
|
||||
let fnArray = [];
|
||||
|
||||
if (fn === 'translate') {
|
||||
fnArray = translateArray;
|
||||
} else if (fn === 'rotate') {
|
||||
fnArray = rotateArray;
|
||||
} else if (fn === 'skew') {
|
||||
fnArray = skewArray;
|
||||
}
|
||||
|
||||
for (let fnIndex = 0; fnIndex < fnLen; fnIndex += 1) {
|
||||
const fnAxis = prepAxis[fnIndex];
|
||||
fnArray[fnIndex] = (`${fn}${fnAxis}` in obj) ? parseInt(obj[`${fn}${fnAxis}`], 10) : 0;
|
||||
}
|
||||
|
||||
if (support3DTransform) {
|
||||
transformObject[fnId] = fnArray;
|
||||
} else {
|
||||
transformObject[fnId] = fn === 'rotate' ? (fnArray[2] || fnArray[1] || fnArray[0]) : fnArray;
|
||||
}
|
||||
} else if (x === 'rotate') { // 2d rotate
|
||||
const pType = support3DTransform ? 'rotate3d' : 'rotate';
|
||||
transformObject[pType] = support3DTransform ? [0, 0, pv] : pv;
|
||||
} else { // scale | perspective
|
||||
transformObject[x] = x === 'scale' ? parseFloat(obj[x]) : pv;
|
||||
}
|
||||
});
|
||||
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare tween object in advance for `to()` method.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
function crossCheckLegacyTransform(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if (this.valuesEnd[tweenProp] && support3DTransform) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective) {
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const transformLegacyFunctions = {
|
||||
prepareStart: getLegacyTransform,
|
||||
prepareProperty: prepareLegacyTransform,
|
||||
onStart: onStartLegacyTransform,
|
||||
crossCheck: crossCheckLegacyTransform,
|
||||
};
|
||||
|
||||
const legacyTransformValues = {
|
||||
perspective: 400,
|
||||
translate3d: [0, 0, 0],
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
translateZ: 0,
|
||||
translate: [0, 0],
|
||||
rotate3d: [0, 0, 0],
|
||||
rotateX: 0,
|
||||
rotateY: 0,
|
||||
rotateZ: 0,
|
||||
rotate: 0,
|
||||
skewX: 0,
|
||||
skewY: 0,
|
||||
skew: [0, 0],
|
||||
scale: 1,
|
||||
};
|
||||
|
||||
const legacyTransformProperties = [
|
||||
'perspective',
|
||||
'translate3d', 'translateX', 'translateY', 'translateZ', 'translate',
|
||||
'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'rotate',
|
||||
'skewX', 'skewY', 'skew',
|
||||
'scale',
|
||||
];
|
||||
|
||||
// Full Component
|
||||
const transformLegacyComponent = {
|
||||
component: 'transformFunctions',
|
||||
property: 'transform',
|
||||
subProperties: legacyTransformProperties,
|
||||
defaultValues: legacyTransformValues,
|
||||
functions: transformLegacyFunctions,
|
||||
Interpolate: {
|
||||
perspective,
|
||||
translate3d,
|
||||
rotate3d,
|
||||
translate,
|
||||
rotate,
|
||||
scale,
|
||||
skew,
|
||||
},
|
||||
Util: [transformProperty],
|
||||
};
|
||||
|
||||
export default transformLegacyComponent;
|
||||
|
|
|
@ -1,56 +1,62 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import perspective from '../interpolation/perspective.js'
|
||||
import translate3d from '../interpolation/translate3d.js'
|
||||
import rotate3d from '../interpolation/rotate3d.js'
|
||||
import translate from '../interpolation/translate.js'
|
||||
import rotate from '../interpolation/rotate.js'
|
||||
import scale from '../interpolation/scale.js'
|
||||
import skew from '../interpolation/skew.js'
|
||||
|
||||
import support3DTransform from 'shorter-js/src/boolean/support3DTransform.js'
|
||||
import supportTransform from '../util/supportLegacyTransform.js'
|
||||
import transformProperty from '../util/transformProperty.js'
|
||||
|
||||
|
||||
// const baseLegacyTransform = { property : 'transform', subProperties, defaultValues, Interpolate: {translate,rotate,skew,scale}, functions } // same to svg transform, attr
|
||||
// the component that handles all browsers IE9+
|
||||
|
||||
// Component Functions
|
||||
export function onStartLegacyTransform(tweenProp){
|
||||
if (!KUTE[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
if (support3DTransform){
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[transformProperty] =
|
||||
(a.perspective||b.perspective ? perspective(a.perspective,b.perspective,'px',v) : '') // one side might be 0
|
||||
+ (a.translate3d ? translate3d(a.translate3d,b.translate3d,'px',v):'') // array [x,y,z]
|
||||
+ (a.rotate3d ? rotate3d(a.rotate3d,b.rotate3d,'deg',v):'') // array [x,y,z]
|
||||
+ (a.skew ? skew(a.skew,b.skew,'deg',v):'') // array [x,y]
|
||||
+ (a.scale||b.scale ? scale(a.scale,b.scale,v):'') // one side might be 0
|
||||
}
|
||||
} else if (supportTransform) {
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
elem.style[transformProperty] =
|
||||
(a.translate ? translate(a.translate,b.translate,'px',v):'') // array [x,y]
|
||||
+ ((a.rotate||b.rotate) ? rotate(a.rotate,b.rotate,'deg',v):'') // one side might be 0
|
||||
+ (a.skew ? skew(a.skew,b.skew,'deg',v):'') // array [x,y]
|
||||
+ (a.scale||b.scale ? scale(a.scale,b.scale,v):'') // one side might be 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const BaseLegacyTransform = {
|
||||
component: 'baseLegacyTransform',
|
||||
property: 'transform',
|
||||
functions: {onStart: onStartLegacyTransform},
|
||||
Interpolate: {
|
||||
perspective: perspective,
|
||||
translate3d: translate3d,
|
||||
rotate3d: rotate3d,
|
||||
translate: translate, rotate: rotate, scale: scale, skew: skew
|
||||
},
|
||||
Util: {transformProperty}
|
||||
}
|
||||
|
||||
export default BaseLegacyTransform
|
||||
import support3DTransform from 'shorter-js/src/boolean/support3DTransform';
|
||||
import KEC from '../objects/kute';
|
||||
import perspective from '../interpolation/perspective';
|
||||
import translate3d from '../interpolation/translate3d';
|
||||
import rotate3d from '../interpolation/rotate3d';
|
||||
import translate from '../interpolation/translate';
|
||||
import rotate from '../interpolation/rotate';
|
||||
import scale from '../interpolation/scale';
|
||||
import skew from '../interpolation/skew';
|
||||
|
||||
import supportTransform from '../util/supportLegacyTransform';
|
||||
import transformProperty from '../util/transformProperty';
|
||||
|
||||
// same as svgTransform, htmlAttributes
|
||||
// the component that handles all browsers IE9+
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
export function onStartLegacyTransform(tweenProp) {
|
||||
if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) {
|
||||
if (support3DTransform) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
elem.style[transformProperty] = (a.perspective || b.perspective ? perspective(a.perspective, b.perspective, 'px', v) : '') // one side might be 0
|
||||
+ (a.translate3d ? translate3d(a.translate3d, b.translate3d, 'px', v) : '') // array [x,y,z]
|
||||
+ (a.rotate3d ? rotate3d(a.rotate3d, b.rotate3d, 'deg', v) : '') // array [x,y,z]
|
||||
+ (a.skew ? skew(a.skew, b.skew, 'deg', v) : '') // array [x,y]
|
||||
+ (a.scale || b.scale ? scale(a.scale, b.scale, v) : ''); // one side might be 0
|
||||
};
|
||||
} else if (supportTransform) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
elem.style[transformProperty] = (a.translate ? translate(a.translate, b.translate, 'px', v) : '') // array [x,y]
|
||||
+ ((a.rotate || b.rotate) ? rotate(a.rotate, b.rotate, 'deg', v) : '') // one side might be 0
|
||||
+ (a.skew ? skew(a.skew, b.skew, 'deg', v) : '') // array [x,y]
|
||||
+ (a.scale || b.scale ? scale(a.scale, b.scale, v) : ''); // one side might be 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base Component
|
||||
const BaseLegacyTransform = {
|
||||
component: 'baseLegacyTransform',
|
||||
property: 'transform',
|
||||
functions: { onStart: onStartLegacyTransform },
|
||||
Interpolate: {
|
||||
perspective,
|
||||
translate3d,
|
||||
rotate3d,
|
||||
translate,
|
||||
rotate,
|
||||
scale,
|
||||
skew,
|
||||
},
|
||||
Util: { transformProperty },
|
||||
};
|
||||
|
||||
export default BaseLegacyTransform;
|
||||
|
|
|
@ -1,117 +1,165 @@
|
|||
import defaultValues from '../objects/defaultValues.js'
|
||||
import Components from '../objects/components.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import arrays from '../interpolation/arrays.js'
|
||||
import {onStartTransform} from './transformMatrixBase.js'
|
||||
|
||||
// const transformMatrix = { property : 'transform', defaultValue: {}, interpolators: {} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component name
|
||||
const matrixComponent = 'transformMatrix'
|
||||
|
||||
// Component Functions
|
||||
function getTransform(tweenProp, value){
|
||||
let transformObject = {}
|
||||
|
||||
if (this.element[matrixComponent]) {
|
||||
const currentValue = this.element[matrixComponent]
|
||||
for (const vS in currentValue) {
|
||||
transformObject[vS] = currentValue[vS]
|
||||
}
|
||||
} else {
|
||||
for (const vE in value){
|
||||
transformObject[vE] = vE === 'perspective' ? value[vE] : defaultValues.transform[vE]
|
||||
}
|
||||
}
|
||||
return transformObject
|
||||
}
|
||||
function prepareTransform(tweenProp,value){
|
||||
if ( typeof(value) === 'object' && !value.length) {
|
||||
let pv,
|
||||
transformObject = {},
|
||||
translate3dObj = {},
|
||||
rotate3dObj = {},
|
||||
scale3dObj = {},
|
||||
skewObj = {},
|
||||
axis = [{translate3d:translate3dObj},{rotate3d:rotate3dObj},{skew:skewObj},{scale3d:scale3dObj}];
|
||||
|
||||
for (const prop in value) {
|
||||
if ( /3d/.test(prop) && typeof(value[prop]) === 'object' && value[prop].length ){
|
||||
pv = value[prop].map( (v) => prop === 'scale3d' ? parseFloat(v) : parseInt(v) )
|
||||
transformObject[prop] = prop === 'scale3d' ? [pv[0]||1, pv[1]||1, pv[2]||1] : [pv[0]||0, pv[1]||0, pv[2]||0]
|
||||
} else if ( /[XYZ]/.test(prop) ) {
|
||||
let obj = /translate/.test(prop) ? translate3dObj
|
||||
: /rotate/.test(prop) ? rotate3dObj
|
||||
: /scale/.test(prop) ? scale3dObj
|
||||
: /skew/.test(prop) ? skewObj : {};
|
||||
let idx = prop.replace(/translate|rotate|scale|skew/,'').toLowerCase()
|
||||
obj[idx] = /scale/.test(prop) ? parseFloat(value[prop]) : parseInt(value[prop])
|
||||
} else if ('skew' === prop ) {
|
||||
pv = value[prop].map(v => parseInt(v)||0)
|
||||
transformObject[prop] = [pv[0]||0, pv[1]||0]
|
||||
} else { // perspective
|
||||
transformObject[prop] = parseInt(value[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
axis.map((o) => {
|
||||
let tp = Object.keys(o)[0], tv = o[tp]
|
||||
if ( Object.keys(tv).length && !transformObject[tp]) {
|
||||
transformObject[tp] = tp === 'scale3d' ? [tv.x || 1, tv.y || 1, tv.z || 1]
|
||||
: tp === 'skew' ? [tv.x || 0, tv.y || 0]
|
||||
: [tv.x || 0, tv.y || 0, tv.z || 0]; // translate|rotate
|
||||
}
|
||||
})
|
||||
return transformObject;
|
||||
} else { // string | array
|
||||
// if ( typeof (value) === 'object' && value.length ) {
|
||||
// } else if ( typeof (value) === string && value.includes('matrix')) {
|
||||
// decompose matrix to object
|
||||
console.error(`KUTE.js - "${value}" is not valid/supported transform function`)
|
||||
}
|
||||
}
|
||||
|
||||
function onCompleteTransform(tweenProp){
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
this.element[matrixComponent] = {}
|
||||
for (const tf in this.valuesEnd[tweenProp]){
|
||||
this.element[matrixComponent][tf] = this.valuesEnd[tweenProp][tf]
|
||||
}
|
||||
}
|
||||
}
|
||||
function crossCheckTransform(tweenProp){
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective){
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const matrixFunctions = {
|
||||
prepareStart: getTransform,
|
||||
prepareProperty: prepareTransform,
|
||||
onStart: onStartTransform,
|
||||
onComplete: onCompleteTransform,
|
||||
crossCheck: crossCheckTransform
|
||||
}
|
||||
|
||||
// Component Full Object
|
||||
const matrixTransform = {
|
||||
component: matrixComponent,
|
||||
property: 'transform',
|
||||
// subProperties: ['perspective','translate3d','translateX','translateY','translateZ','rotate3d','rotateX','rotateY','rotateZ','skew','skewX','skewY','scale3d','scaleX','scaleY','scaleZ'],
|
||||
defaultValue: {perspective:400,translate3d:[0,0,0],translateX:0,translateY:0,translateZ:0,rotate3d:[0,0,0],rotateX:0,rotateY:0,rotateZ:0,skew:[0,0],skewX:0,skewY:0,scale3d:[1,1,1],scaleX:1,scaleY:1,scaleZ:1},
|
||||
functions: matrixFunctions,
|
||||
Interpolate: {
|
||||
perspective: numbers,
|
||||
translate3d: arrays,
|
||||
rotate3d: arrays,
|
||||
skew: arrays,
|
||||
scale3d: arrays
|
||||
}
|
||||
}
|
||||
|
||||
export default matrixTransform
|
||||
|
||||
Components.TransformMatrix = matrixTransform
|
||||
import defaultValues from '../objects/defaultValues';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import arrays from '../interpolation/arrays';
|
||||
import { onStartTransform } from './transformMatrixBase';
|
||||
|
||||
// Component name
|
||||
const matrixComponent = 'transformMatrix';
|
||||
|
||||
// Component Functions
|
||||
/**
|
||||
* Returns the current transform object.
|
||||
* @param {string} _ the property name
|
||||
* @param {string} value the property value
|
||||
* @returns {KUTE.transformMObject} transform object
|
||||
*/
|
||||
function getTransform(/* tweenProp, */_, value) {
|
||||
const transformObject = {};
|
||||
const currentValue = this.element[matrixComponent];
|
||||
|
||||
if (currentValue) {
|
||||
Object.keys(currentValue).forEach((vS) => {
|
||||
transformObject[vS] = currentValue[vS];
|
||||
});
|
||||
} else {
|
||||
Object.keys(value).forEach((vE) => {
|
||||
transformObject[vE] = vE === 'perspective' ? value[vE] : defaultValues.transform[vE];
|
||||
});
|
||||
}
|
||||
return transformObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property tween object.
|
||||
* @param {string} _ the property name
|
||||
* @param {Object<string, string | number | (string | number)[]>} obj the property value
|
||||
* @returns {KUTE.transformMObject} the property tween object
|
||||
*/
|
||||
function prepareTransform(/* tweenProp, */_, value) {
|
||||
if (typeof (value) === 'object' && !value.length) {
|
||||
let pv;
|
||||
const transformObject = {};
|
||||
const translate3dObj = {};
|
||||
const rotate3dObj = {};
|
||||
const scale3dObj = {};
|
||||
const skewObj = {};
|
||||
const axis = [{ translate3d: translate3dObj },
|
||||
{ rotate3d: rotate3dObj },
|
||||
{ skew: skewObj },
|
||||
{ scale3d: scale3dObj }];
|
||||
|
||||
Object.keys(value).forEach((prop) => {
|
||||
if (/3d/.test(prop) && typeof (value[prop]) === 'object' && value[prop].length) {
|
||||
pv = value[prop].map((v) => (prop === 'scale3d' ? parseFloat(v) : parseInt(v, 10)));
|
||||
transformObject[prop] = prop === 'scale3d' ? [pv[0] || 1, pv[1] || 1, pv[2] || 1] : [pv[0] || 0, pv[1] || 0, pv[2] || 0];
|
||||
} else if (/[XYZ]/.test(prop)) {
|
||||
let obj = {};
|
||||
if (/translate/.test(prop)) {
|
||||
obj = translate3dObj;
|
||||
} else if (/rotate/.test(prop)) {
|
||||
obj = rotate3dObj;
|
||||
} else if (/scale/.test(prop)) {
|
||||
obj = scale3dObj;
|
||||
} else if (/skew/.test(prop)) {
|
||||
obj = skewObj;
|
||||
}
|
||||
const idx = prop.replace(/translate|rotate|scale|skew/, '').toLowerCase();
|
||||
obj[idx] = /scale/.test(prop) ? parseFloat(value[prop]) : parseInt(value[prop], 10);
|
||||
} else if (prop === 'skew') {
|
||||
pv = value[prop].map((v) => parseInt(v, 10) || 0);
|
||||
transformObject[prop] = [pv[0] || 0, pv[1] || 0];
|
||||
} else { // perspective
|
||||
transformObject[prop] = parseInt(value[prop], 10);
|
||||
}
|
||||
});
|
||||
|
||||
axis.forEach((o) => {
|
||||
const tp = Object.keys(o)[0];
|
||||
const tv = o[tp];
|
||||
if (Object.keys(tv).length && !transformObject[tp]) {
|
||||
if (tp === 'scale3d') {
|
||||
transformObject[tp] = [tv.x || 1, tv.y || 1, tv.z || 1];
|
||||
} else if (tp === 'skew') {
|
||||
transformObject[tp] = [tv.x || 0, tv.y || 0];
|
||||
} else { // translate | rotate
|
||||
transformObject[tp] = [tv.x || 0, tv.y || 0, tv.z || 0];
|
||||
}
|
||||
}
|
||||
});
|
||||
return transformObject;
|
||||
} // string | array
|
||||
// if ( typeof (value) === 'object' && value.length ) {
|
||||
// } else if ( typeof (value) === string && value.includes('matrix')) {
|
||||
// decompose matrix to object
|
||||
throw Error(`KUTE.js - "${value}" is not valid/supported transform function`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end values for the next `to()` method call.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
function onCompleteTransform(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
this.element[matrixComponent] = { ...this.valuesEnd[tweenProp] };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare tween object in advance for `to()` method.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
function crossCheckTransform(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp]) {
|
||||
if (this.valuesEnd[tweenProp].perspective && !this.valuesStart[tweenProp].perspective) {
|
||||
this.valuesStart[tweenProp].perspective = this.valuesEnd[tweenProp].perspective;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All Component Functions
|
||||
const matrixFunctions = {
|
||||
prepareStart: getTransform,
|
||||
prepareProperty: prepareTransform,
|
||||
onStart: onStartTransform,
|
||||
onComplete: onCompleteTransform,
|
||||
crossCheck: crossCheckTransform,
|
||||
};
|
||||
|
||||
// Component Full Object
|
||||
const matrixTransform = {
|
||||
component: matrixComponent,
|
||||
property: 'transform',
|
||||
/* subProperties: [
|
||||
'perspective', 'translate3d', 'translateX', 'translateY', 'translateZ',
|
||||
'rotate3d', 'rotateX', 'rotateY', 'rotateZ',
|
||||
'skew','skewX','skewY',
|
||||
'scale3d', 'scaleX', 'scaleY', 'scaleZ'], */
|
||||
defaultValue: {
|
||||
perspective: 400,
|
||||
translate3d: [0, 0, 0],
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
translateZ: 0,
|
||||
rotate3d: [0, 0, 0],
|
||||
rotateX: 0,
|
||||
rotateY: 0,
|
||||
rotateZ: 0,
|
||||
skew: [0, 0],
|
||||
skewX: 0,
|
||||
skewY: 0,
|
||||
scale3d: [1, 1, 1],
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
scaleZ: 1,
|
||||
},
|
||||
functions: matrixFunctions,
|
||||
Interpolate: {
|
||||
perspective: numbers,
|
||||
translate3d: arrays,
|
||||
rotate3d: arrays,
|
||||
skew: arrays,
|
||||
scale3d: arrays,
|
||||
},
|
||||
};
|
||||
|
||||
export default matrixTransform;
|
||||
|
|
|
@ -1,62 +1,85 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import numbers from '../interpolation/numbers.js'
|
||||
import arrays from '../interpolation/arrays.js'
|
||||
|
||||
// const transformMatrix = { property : 'transform', defaultValue: {}, interpolators: {} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
|
||||
|
||||
// Component name
|
||||
const matrixComponent = 'transformMatrixBase'
|
||||
|
||||
// Component special
|
||||
const CSS3Matrix = typeof(DOMMatrix) !== 'undefined' ? DOMMatrix
|
||||
: typeof(WebKitCSSMatrix) !== 'undefined' ? WebKitCSSMatrix
|
||||
: typeof(CSSMatrix) !== 'undefined' ? CSSMatrix
|
||||
: typeof(MSCSSMatrix) !== 'undefined' ? MSCSSMatrix
|
||||
: null
|
||||
|
||||
// Component Functions
|
||||
export const onStartTransform = {
|
||||
transform : function(tweenProp) {
|
||||
if (this.valuesEnd[tweenProp] && !KUTE[tweenProp]) {
|
||||
|
||||
KUTE[tweenProp] = (elem, a, b, v) => {
|
||||
let matrix = new CSS3Matrix(), transformObject = {}
|
||||
|
||||
for ( const p in b ) {
|
||||
transformObject[p] = p === 'perspective' ? numbers(a[p],b[p],v) : arrays(a[p],b[p],v)
|
||||
}
|
||||
|
||||
transformObject.perspective && (matrix.m34 = -1/transformObject.perspective)// set perspective
|
||||
matrix = transformObject.translate3d ? (matrix.translate(transformObject.translate3d[0],transformObject.translate3d[1],transformObject.translate3d[2])) : matrix // set translate
|
||||
matrix = transformObject.rotate3d ? (matrix.rotate(transformObject.rotate3d[0],transformObject.rotate3d[1],transformObject.rotate3d[2])) : matrix // set rotation
|
||||
if (transformObject.skew) { // set skew
|
||||
matrix = transformObject.skew[0] ? matrix.skewX(transformObject.skew[0]) : matrix;
|
||||
matrix = transformObject.skew[1] ? matrix.skewY(transformObject.skew[1]) : matrix;
|
||||
}
|
||||
matrix = transformObject.scale3d ? (matrix.scale(transformObject.scale3d[0],transformObject.scale3d[1],transformObject.scale3d[2])): matrix // set scale
|
||||
elem.style[tweenProp] = matrix.toString() // set element style
|
||||
}
|
||||
}
|
||||
},
|
||||
CSS3Matrix: function(prop) {
|
||||
if (this.valuesEnd.transform){
|
||||
!KUTE[prop] && (KUTE[prop] = CSS3Matrix)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Component Base Object
|
||||
export const baseMatrixTransform = {
|
||||
component: matrixComponent,
|
||||
property: 'transform',
|
||||
functions: {onStart: onStartTransform},
|
||||
Interpolate: {
|
||||
perspective: numbers,
|
||||
translate3d: arrays,
|
||||
rotate3d: arrays,
|
||||
skew: arrays,
|
||||
scale3d: arrays
|
||||
}
|
||||
}
|
||||
|
||||
export default baseMatrixTransform
|
||||
import KEC from '../objects/kute';
|
||||
import numbers from '../interpolation/numbers';
|
||||
import arrays from '../interpolation/arrays';
|
||||
|
||||
// Component name
|
||||
const matrixComponent = 'transformMatrixBase';
|
||||
|
||||
// Component special
|
||||
// this component is restricted to modern browsers only
|
||||
const CSS3Matrix = typeof (DOMMatrix) !== 'undefined' ? DOMMatrix : null;
|
||||
|
||||
// Component Functions
|
||||
export const onStartTransform = {
|
||||
/**
|
||||
* Sets the property update function.
|
||||
* @param {string} tweenProp the property name
|
||||
*/
|
||||
transform(tweenProp) {
|
||||
if (CSS3Matrix && this.valuesEnd[tweenProp] && !KEC[tweenProp]) {
|
||||
KEC[tweenProp] = (elem, a, b, v) => {
|
||||
let matrix = new CSS3Matrix();
|
||||
const tObject = {};
|
||||
|
||||
Object.keys(b).forEach((p) => {
|
||||
tObject[p] = p === 'perspective' ? numbers(a[p], b[p], v) : arrays(a[p], b[p], v);
|
||||
});
|
||||
|
||||
// set perspective
|
||||
if (tObject.perspective) matrix.m34 = -1 / tObject.perspective;
|
||||
|
||||
// set translate
|
||||
matrix = tObject.translate3d
|
||||
? matrix.translate(tObject.translate3d[0], tObject.translate3d[1], tObject.translate3d[2])
|
||||
: matrix;
|
||||
|
||||
// set rotation
|
||||
matrix = tObject.rotate3d
|
||||
? matrix.rotate(tObject.rotate3d[0], tObject.rotate3d[1], tObject.rotate3d[2])
|
||||
: matrix;
|
||||
|
||||
// set skew
|
||||
if (tObject.skew) {
|
||||
matrix = tObject.skew[0] ? matrix.skewX(tObject.skew[0]) : matrix;
|
||||
matrix = tObject.skew[1] ? matrix.skewY(tObject.skew[1]) : matrix;
|
||||
}
|
||||
|
||||
// set scale
|
||||
matrix = tObject.scale3d
|
||||
? matrix.scale(tObject.scale3d[0], tObject.scale3d[1], tObject.scale3d[2])
|
||||
: matrix;
|
||||
|
||||
// set element style
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
elem.style[tweenProp] = matrix.toString();
|
||||
};
|
||||
}
|
||||
},
|
||||
/**
|
||||
* onStartTransform.CSS3Matrix
|
||||
*
|
||||
* Sets the update function for the property.
|
||||
* @param {string} prop the property name
|
||||
*/
|
||||
CSS3Matrix(prop) {
|
||||
if (CSS3Matrix && this.valuesEnd.transform) {
|
||||
if (!KEC[prop]) KEC[prop] = CSS3Matrix;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Component Base Object
|
||||
export const TransformMatrixBase = {
|
||||
component: matrixComponent,
|
||||
property: 'transform',
|
||||
functions: { onStart: onStartTransform },
|
||||
Interpolate: {
|
||||
perspective: numbers,
|
||||
translate3d: arrays,
|
||||
rotate3d: arrays,
|
||||
skew: arrays,
|
||||
scale3d: arrays,
|
||||
},
|
||||
};
|
||||
|
||||
export default TransformMatrixBase;
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
import Tweens from '../objects/tweens.js'
|
||||
export default (tw) => Tweens.push(tw)
|
||||
import Tweens from '../objects/tweens';
|
||||
|
||||
/**
|
||||
* KUTE.add(Tween)
|
||||
*
|
||||
* @param {KUTE.Tween} tw a new tween to add
|
||||
*/
|
||||
const add = (tw) => Tweens.push(tw);
|
||||
|
||||
export default add;
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
import Tweens from '../objects/tweens.js'
|
||||
export default () => Tweens
|
||||
import Tweens from '../objects/tweens';
|
||||
|
||||
/**
|
||||
* KUTE.add(Tween)
|
||||
*
|
||||
* @return {KUTE.Tween[]} tw a new tween to add
|
||||
*/
|
||||
const getAll = () => Tweens;
|
||||
|
||||
export default getAll;
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import add from './add.js'
|
||||
import remove from './remove.js'
|
||||
import getAll from './getAll.js'
|
||||
import removeAll from './removeAll.js'
|
||||
import {stop} from './render.js'
|
||||
import linkInterpolation from './linkInterpolation.js'
|
||||
|
||||
export default {
|
||||
add,
|
||||
remove,
|
||||
getAll,
|
||||
removeAll,
|
||||
stop,
|
||||
linkInterpolation
|
||||
}
|
||||
import add from './add';
|
||||
import remove from './remove';
|
||||
import getAll from './getAll';
|
||||
import removeAll from './removeAll';
|
||||
import { stop } from './render';
|
||||
import linkInterpolation from './linkInterpolation';
|
||||
|
||||
const internals = {
|
||||
add,
|
||||
remove,
|
||||
getAll,
|
||||
removeAll,
|
||||
stop,
|
||||
linkInterpolation,
|
||||
};
|
||||
|
||||
export default internals;
|
||||
|
|
|
@ -1,34 +1,39 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import linkProperty from '../objects/linkProperty.js'
|
||||
import supportedProperties from '../objects/supportedProperties.js'
|
||||
|
||||
export default function() { // DON'T change
|
||||
for (const component in linkProperty){
|
||||
const componentLink = linkProperty[component]
|
||||
const componentProps = supportedProperties[component]
|
||||
|
||||
for ( const fnObj in componentLink ) {
|
||||
if ( typeof(componentLink[fnObj]) === 'function'
|
||||
&& Object.keys(this.valuesEnd).some(i => componentProps && componentProps.includes(i)
|
||||
|| i=== 'attr' && Object.keys(this.valuesEnd[i]).some(j => componentProps && componentProps.includes(j)) ) )
|
||||
{ // ATTR, colors, scroll, boxModel, borderRadius
|
||||
!KUTE[fnObj] && (KUTE[fnObj] = componentLink[fnObj])
|
||||
} else {
|
||||
|
||||
for ( const prop in this.valuesEnd ) {
|
||||
for ( const i in this.valuesEnd[prop] ) {
|
||||
if ( typeof(componentLink[i]) === 'function' ) { // transformCSS3
|
||||
!KUTE[i] && (KUTE[i] = componentLink[i])
|
||||
} else {
|
||||
for (const j in componentLink[fnObj]){
|
||||
if (componentLink[i] && typeof(componentLink[i][j]) === 'function' ) { // transformMatrix
|
||||
!KUTE[j] && (KUTE[j] = componentLink[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import KEC from '../objects/kute';
|
||||
import linkProperty from '../objects/linkProperty';
|
||||
import supportedProperties from '../objects/supportedProperties';
|
||||
|
||||
/**
|
||||
* linkInterpolation
|
||||
* @this {KUTE.Tween}
|
||||
*/
|
||||
export default function linkInterpolation() { // DON'T change
|
||||
Object.keys(linkProperty).forEach((component) => {
|
||||
const componentLink = linkProperty[component];
|
||||
const componentProps = supportedProperties[component];
|
||||
|
||||
Object.keys(componentLink).forEach((fnObj) => {
|
||||
if (typeof (componentLink[fnObj]) === 'function' // ATTR, colors, scroll, boxModel, borderRadius
|
||||
&& Object.keys(this.valuesEnd).some((i) => (componentProps && componentProps.includes(i))
|
||||
|| (i === 'attr' && Object.keys(this.valuesEnd[i]).some((j) => componentProps && componentProps.includes(j))))) {
|
||||
if (!KEC[fnObj]) KEC[fnObj] = componentLink[fnObj];
|
||||
} else {
|
||||
Object.keys(this.valuesEnd).forEach((prop) => {
|
||||
const propObject = this.valuesEnd[prop];
|
||||
if (propObject instanceof Object) {
|
||||
Object.keys(propObject).forEach((i) => {
|
||||
if (typeof (componentLink[i]) === 'function') { // transformCSS3
|
||||
if (!KEC[i]) KEC[i] = componentLink[i];
|
||||
} else {
|
||||
Object.keys(componentLink[fnObj]).forEach((j) => {
|
||||
if (componentLink[i] && typeof (componentLink[i][j]) === 'function') { // transformMatrix
|
||||
if (!KEC[j]) KEC[j] = componentLink[i][j];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import onStart from '../objects/onStart.js'
|
||||
import linkInterpolation from './linkInterpolation.js'
|
||||
|
||||
export default function(){
|
||||
// fire onStart actions
|
||||
for (let obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this,obj) // easing functions
|
||||
} else {
|
||||
for (let prop in onStart[obj]) {
|
||||
onStart[obj][prop].call(this,prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
// add interpolations
|
||||
linkInterpolation.call(this)
|
||||
}
|
||||
import onStart from '../objects/onStart';
|
||||
import linkInterpolation from './linkInterpolation';
|
||||
|
||||
export default function queueStart() {
|
||||
// fire onStart actions
|
||||
Object.keys(onStart).forEach((obj) => {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
onStart[obj].call(this, obj); // easing functions
|
||||
} else {
|
||||
Object.keys(onStart[obj]).forEach((prop) => {
|
||||
onStart[obj][prop].call(this, prop);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// add interpolations
|
||||
linkInterpolation.call(this);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
import Tweens from '../objects/tweens.js'
|
||||
export default (tw) => {
|
||||
let i = Tweens.indexOf(tw)
|
||||
i !== -1 && Tweens.splice(i, 1)
|
||||
}
|
||||
import Tweens from '../objects/tweens';
|
||||
|
||||
/**
|
||||
* KUTE.remove(Tween)
|
||||
*
|
||||
* @param {KUTE.Tween} tw a new tween to add
|
||||
*/
|
||||
const remove = (tw) => {
|
||||
const i = Tweens.indexOf(tw);
|
||||
if (i !== -1) Tweens.splice(i, 1);
|
||||
};
|
||||
|
||||
export default remove;
|
||||
|
|
|
@ -1,2 +1,8 @@
|
|||
import Tweens from '../objects/tweens.js'
|
||||
export default () => { Tweens.length = 0 }
|
||||
import Tweens from '../objects/tweens';
|
||||
|
||||
/**
|
||||
* KUTE.removeAll()
|
||||
*/
|
||||
const removeAll = () => { Tweens.length = 0; };
|
||||
|
||||
export default removeAll;
|
||||
|
|
|
@ -1,61 +1,67 @@
|
|||
import KUTE from '../objects/kute.js'
|
||||
import Tweens from '../objects/tweens.js'
|
||||
import globalObject from '../objects/globalObject.js'
|
||||
import Interpolate from '../objects/interpolate.js'
|
||||
import onStart from '../objects/onStart.js'
|
||||
|
||||
// const Time = window.performance
|
||||
|
||||
const Time = {}
|
||||
Time.now = self.performance.now.bind(self.performance)
|
||||
// export {Time}
|
||||
|
||||
let Tick = 0
|
||||
export {Tick}
|
||||
|
||||
let Ticker = (time) => {
|
||||
let i = 0;
|
||||
while ( i < Tweens.length ) {
|
||||
if ( Tweens[i].update(time) ) {
|
||||
i++;
|
||||
} else {
|
||||
Tweens.splice(i, 1);
|
||||
}
|
||||
}
|
||||
Tick = requestAnimationFrame(Ticker);
|
||||
}
|
||||
export {Ticker}
|
||||
|
||||
|
||||
// stop requesting animation frame
|
||||
export function stop() {
|
||||
setTimeout(() => { // re-added for #81
|
||||
if (!Tweens.length && Tick) {
|
||||
cancelAnimationFrame(Tick);
|
||||
Tick = null;
|
||||
for (let obj in onStart) {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
KUTE[obj] && (delete KUTE[obj])
|
||||
} else {
|
||||
for (let prop in onStart[obj]) {
|
||||
KUTE[prop] && (delete KUTE[prop])
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i in Interpolate) {
|
||||
KUTE[i] && (delete KUTE[i])
|
||||
}
|
||||
}
|
||||
},64)
|
||||
}
|
||||
|
||||
// KUTE.js render update functions
|
||||
// ===============================
|
||||
const Render = {Tick,Ticker,Tweens,Time}
|
||||
for ( const blob in Render ) {
|
||||
if (!KUTE[blob]) {
|
||||
KUTE[blob] = blob === 'Time' ? Time.now : Render[blob];
|
||||
}
|
||||
}
|
||||
export default Render
|
||||
globalObject[`_KUTE`] = KUTE
|
||||
import KEC from '../objects/kute';
|
||||
import Tweens from '../objects/tweens';
|
||||
import globalObject from '../objects/globalObject';
|
||||
import Interpolate from '../objects/interpolate';
|
||||
import onStart from '../objects/onStart';
|
||||
import now from '../util/now';
|
||||
|
||||
const Time = {};
|
||||
Time.now = now;
|
||||
|
||||
// eslint-disable-next-line import/no-mutable-exports -- impossible to satisfy
|
||||
let Tick = 0;
|
||||
export { Tick };
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number | Date} time
|
||||
*/
|
||||
const Ticker = (time) => {
|
||||
let i = 0;
|
||||
while (i < Tweens.length) {
|
||||
if (Tweens[i].update(time)) {
|
||||
i += 1;
|
||||
} else {
|
||||
Tweens.splice(i, 1);
|
||||
}
|
||||
}
|
||||
Tick = requestAnimationFrame(Ticker);
|
||||
};
|
||||
export { Ticker };
|
||||
|
||||
// stop requesting animation frame
|
||||
export function stop() {
|
||||
setTimeout(() => { // re-added for #81
|
||||
if (!Tweens.length && Tick) {
|
||||
cancelAnimationFrame(Tick);
|
||||
Tick = null;
|
||||
Object.keys(onStart).forEach((obj) => {
|
||||
if (typeof (onStart[obj]) === 'function') {
|
||||
if (KEC[obj]) delete KEC[obj];
|
||||
} else {
|
||||
Object.keys(onStart[obj]).forEach((prop) => {
|
||||
if (KEC[prop]) delete KEC[prop];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(Interpolate).forEach((i) => {
|
||||
if (KEC[i]) delete KEC[i];
|
||||
});
|
||||
}
|
||||
}, 64);
|
||||
}
|
||||
|
||||
// render update functions
|
||||
// =======================
|
||||
const Render = {
|
||||
Tick, Ticker, Tweens, Time,
|
||||
};
|
||||
Object.keys(Render).forEach((blob) => {
|
||||
if (!KEC[blob]) {
|
||||
KEC[blob] = blob === 'Time' ? Time.now : Render[blob];
|
||||
}
|
||||
});
|
||||
|
||||
globalObject._KUTE = KEC;
|
||||
export default Render;
|
||||
|
|
|
@ -1,36 +1,64 @@
|
|||
import connect from '../objects/connect.js'
|
||||
|
||||
// Select Robert Penner's Easing Functions
|
||||
const Easing = {
|
||||
linear : (t) => t,
|
||||
easingQuadraticIn : (t) => t*t,
|
||||
easingQuadraticOut : (t) => t*(2-t),
|
||||
easingQuadraticInOut : (t) => t<.5 ? 2*t*t : -1+(4-2*t)*t,
|
||||
easingCubicIn : (t) => t*t*t,
|
||||
easingCubicOut : (t) => (--t)*t*t+1,
|
||||
easingCubicInOut : (t) => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1,
|
||||
easingCircularIn : (t) => -(Math.sqrt(1 - (t * t)) - 1),
|
||||
easingCircularOut : (t) => Math.sqrt(1 - (t = t - 1) * t),
|
||||
easingCircularInOut : (t) => ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
|
||||
easingBackIn : (t) => { const s = 1.70158; return t * t * ((s + 1) * t - s) },
|
||||
easingBackOut : (t) => { const s = 1.70158; return --t * t * ((s + 1) * t + s) + 1 },
|
||||
easingBackInOut : (t) => {
|
||||
const s = 1.70158 * 1.525;
|
||||
if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s))
|
||||
return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2)
|
||||
}
|
||||
}
|
||||
|
||||
function processEasing(fn) {
|
||||
if ( typeof fn === 'function') {
|
||||
return fn;
|
||||
} else if ( typeof Easing[fn] === 'function' ) {
|
||||
return Easing[fn]; // regular Robert Penner Easing Functions
|
||||
} else {
|
||||
return Easing.linear
|
||||
}
|
||||
}
|
||||
|
||||
connect.processEasing = processEasing
|
||||
|
||||
export default Easing
|
||||
import connect from '../objects/connect';
|
||||
|
||||
// Select Robert Penner's Easing Functions
|
||||
// updated for ESLint
|
||||
const Easing = {
|
||||
/** @type {KUTE.easingFunction} */
|
||||
linear: (t) => t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticIn: (t) => t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticOut: (t) => t * (2 - t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticInOut: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicIn: (t) => t * t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicOut: (t0) => { const t = t0 - 1; return t * t * t + 1; },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicInOut: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularIn: (t) => -(Math.sqrt(1 - (t * t)) - 1),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularOut: (t0) => { const t = t0 - 1; return Math.sqrt(1 - t * t); },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularInOut: (t0) => {
|
||||
let t = t0 * 2;
|
||||
if (t < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);
|
||||
t -= 2; return 0.5 * (Math.sqrt(1 - t * t) + 1);
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackIn: (t) => { const s = 1.70158; return t * t * ((s + 1) * t - s); },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackOut: (t0) => {
|
||||
const s = 1.70158;
|
||||
const t = t0 - 1;
|
||||
return t * t * ((s + 1) * t + s) + 1;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackInOut: (t0) => {
|
||||
const s = 1.70158 * 1.525;
|
||||
let t = t0 * 2;
|
||||
if (t < 1) return 0.5 * (t * t * ((s + 1) * t - s));
|
||||
t -= 2; return 0.5 * (t * t * ((s + 1) * t + s) + 2);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a valid `easingFunction`.
|
||||
*
|
||||
* @param {KUTE.easingFunction | string} fn function name or constructor name
|
||||
* @returns {KUTE.easingFunction} a valid easing function
|
||||
*/
|
||||
function processEasing(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
return fn;
|
||||
} if (typeof Easing[fn] === 'function') {
|
||||
return Easing[fn]; // regular Robert Penner Easing Functions
|
||||
}
|
||||
return Easing.linear;
|
||||
}
|
||||
|
||||
connect.processEasing = processEasing;
|
||||
|
||||
export default Easing;
|
||||
|
|
|
@ -1,57 +1,62 @@
|
|||
import connect from '../objects/connect.js'
|
||||
import CubicBezier from 'cubic-bezier-easing'
|
||||
|
||||
const Easing = {
|
||||
linear : new CubicBezier(0, 0, 1, 1,'linear'),
|
||||
easingSinusoidalIn : new CubicBezier(0.47, 0, 0.745, 0.715,'easingSinusoidalIn'),
|
||||
easingSinusoidalOut : new CubicBezier(0.39, 0.575, 0.565, 1,'easingSinusoidalOut'),
|
||||
easingSinusoidalInOut : new CubicBezier(0.445, 0.05, 0.55, 0.95,'easingSinusoidalInOut'),
|
||||
|
||||
easingQuadraticIn : new CubicBezier(0.550, 0.085, 0.680, 0.530,'easingQuadraticIn'),
|
||||
easingQuadraticOut : new CubicBezier(0.250, 0.460, 0.450, 0.940,'easingQuadraticOut'),
|
||||
easingQuadraticInOut : new CubicBezier(0.455, 0.030, 0.515, 0.955,'easingQuadraticInOut'),
|
||||
|
||||
easingCubicIn : new CubicBezier(0.55, 0.055, 0.675, 0.19,'easingCubicIn'),
|
||||
easingCubicOut : new CubicBezier(0.215, 0.61, 0.355, 1,'easingCubicOut'),
|
||||
easingCubicInOut : new CubicBezier(0.645, 0.045, 0.355, 1,'easingCubicInOut'),
|
||||
|
||||
easingQuarticIn : new CubicBezier(0.895, 0.03, 0.685, 0.22,'easingQuarticIn'),
|
||||
easingQuarticOut : new CubicBezier(0.165, 0.84, 0.44, 1,'easingQuarticOut'),
|
||||
easingQuarticInOut : new CubicBezier(0.77, 0, 0.175, 1,'easingQuarticInOut'),
|
||||
|
||||
easingQuinticIn : new CubicBezier(0.755, 0.05, 0.855, 0.06,'easingQuinticIn'),
|
||||
easingQuinticOut : new CubicBezier(0.23, 1, 0.32, 1,'easingQuinticOut'),
|
||||
easingQuinticInOut : new CubicBezier(0.86, 0, 0.07, 1,'easingQuinticInOut'),
|
||||
|
||||
easingExponentialIn : new CubicBezier(0.95, 0.05, 0.795, 0.035,'easingExponentialIn'),
|
||||
easingExponentialOut : new CubicBezier(0.19, 1, 0.22, 1,'easingExponentialOut'),
|
||||
easingExponentialInOut : new CubicBezier(1, 0, 0, 1,'easingExponentialInOut'),
|
||||
|
||||
easingCircularIn : new CubicBezier(0.6, 0.04, 0.98, 0.335,'easingCircularIn'),
|
||||
easingCircularOut : new CubicBezier(0.075, 0.82, 0.165, 1,'easingCircularOut'),
|
||||
easingCircularInOut : new CubicBezier(0.785, 0.135, 0.15, 0.86,'easingCircularInOut'),
|
||||
|
||||
easingBackIn : new CubicBezier(0.6, -0.28, 0.735, 0.045,'easingBackIn'),
|
||||
easingBackOut : new CubicBezier(0.175, 0.885, 0.32, 1.275,'easingBackOut'),
|
||||
easingBackInOut : new CubicBezier(0.68, -0.55, 0.265, 1.55,'easingBackInOut')
|
||||
}
|
||||
|
||||
function processBezierEasing(fn) {
|
||||
if ( typeof fn === 'function') {
|
||||
return fn;
|
||||
} else if (typeof(Easing[fn]) === 'function') {
|
||||
return Easing[fn];
|
||||
} else if ( /bezier/.test(fn) ) {
|
||||
var bz = fn.replace(/bezier|\s|\(|\)/g,'').split(',');
|
||||
return new CubicBezier( bz[0]*1,bz[1]*1,bz[2]*1,bz[3]*1 ); //bezier easing
|
||||
} else {
|
||||
if ( /elastic|bounce/i.test(fn) ) {
|
||||
console.warn(`KUTE.js - CubicBezier doesn't support ${fn} easing.`)
|
||||
}
|
||||
return Easing.linear
|
||||
}
|
||||
}
|
||||
|
||||
connect.processEasing = processBezierEasing
|
||||
|
||||
export default Easing
|
||||
import CubicBezier from 'cubic-bezier-easing';
|
||||
import connect from '../objects/connect';
|
||||
|
||||
const Easing = {
|
||||
linear: new CubicBezier(0, 0, 1, 1, 'linear'),
|
||||
easingSinusoidalIn: new CubicBezier(0.47, 0, 0.745, 0.715, 'easingSinusoidalIn'),
|
||||
easingSinusoidalOut: new CubicBezier(0.39, 0.575, 0.565, 1, 'easingSinusoidalOut'),
|
||||
easingSinusoidalInOut: new CubicBezier(0.445, 0.05, 0.55, 0.95, 'easingSinusoidalInOut'),
|
||||
|
||||
easingQuadraticIn: new CubicBezier(0.550, 0.085, 0.680, 0.530, 'easingQuadraticIn'),
|
||||
easingQuadraticOut: new CubicBezier(0.250, 0.460, 0.450, 0.940, 'easingQuadraticOut'),
|
||||
easingQuadraticInOut: new CubicBezier(0.455, 0.030, 0.515, 0.955, 'easingQuadraticInOut'),
|
||||
|
||||
easingCubicIn: new CubicBezier(0.55, 0.055, 0.675, 0.19, 'easingCubicIn'),
|
||||
easingCubicOut: new CubicBezier(0.215, 0.61, 0.355, 1, 'easingCubicOut'),
|
||||
easingCubicInOut: new CubicBezier(0.645, 0.045, 0.355, 1, 'easingCubicInOut'),
|
||||
|
||||
easingQuarticIn: new CubicBezier(0.895, 0.03, 0.685, 0.22, 'easingQuarticIn'),
|
||||
easingQuarticOut: new CubicBezier(0.165, 0.84, 0.44, 1, 'easingQuarticOut'),
|
||||
easingQuarticInOut: new CubicBezier(0.77, 0, 0.175, 1, 'easingQuarticInOut'),
|
||||
|
||||
easingQuinticIn: new CubicBezier(0.755, 0.05, 0.855, 0.06, 'easingQuinticIn'),
|
||||
easingQuinticOut: new CubicBezier(0.23, 1, 0.32, 1, 'easingQuinticOut'),
|
||||
easingQuinticInOut: new CubicBezier(0.86, 0, 0.07, 1, 'easingQuinticInOut'),
|
||||
|
||||
easingExponentialIn: new CubicBezier(0.95, 0.05, 0.795, 0.035, 'easingExponentialIn'),
|
||||
easingExponentialOut: new CubicBezier(0.19, 1, 0.22, 1, 'easingExponentialOut'),
|
||||
easingExponentialInOut: new CubicBezier(1, 0, 0, 1, 'easingExponentialInOut'),
|
||||
|
||||
easingCircularIn: new CubicBezier(0.6, 0.04, 0.98, 0.335, 'easingCircularIn'),
|
||||
easingCircularOut: new CubicBezier(0.075, 0.82, 0.165, 1, 'easingCircularOut'),
|
||||
easingCircularInOut: new CubicBezier(0.785, 0.135, 0.15, 0.86, 'easingCircularInOut'),
|
||||
|
||||
easingBackIn: new CubicBezier(0.6, -0.28, 0.735, 0.045, 'easingBackIn'),
|
||||
easingBackOut: new CubicBezier(0.175, 0.885, 0.32, 1.275, 'easingBackOut'),
|
||||
easingBackInOut: new CubicBezier(0.68, -0.55, 0.265, 1.55, 'easingBackInOut'),
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a valid `easingFunction`.
|
||||
*
|
||||
* @param {KUTE.easingFunction | string} fn function name or constructor name
|
||||
* @returns {KUTE.easingFunction} a valid easingfunction
|
||||
*/
|
||||
function processBezierEasing(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
return fn;
|
||||
} if (typeof (Easing[fn]) === 'function') {
|
||||
return Easing[fn];
|
||||
} if (/bezier/.test(fn)) {
|
||||
const bz = fn.replace(/bezier|\s|\(|\)/g, '').split(',');
|
||||
return new CubicBezier(bz[0] * 1, bz[1] * 1, bz[2] * 1, bz[3] * 1); // bezier easing
|
||||
}
|
||||
// if (/elastic|bounce/i.test(fn)) {
|
||||
// throw TypeError(`KUTE - CubicBezier doesn't support ${fn} easing.`);
|
||||
// }
|
||||
return Easing.linear;
|
||||
}
|
||||
|
||||
connect.processEasing = processBezierEasing;
|
||||
|
||||
export default Easing;
|
||||
|
|
|
@ -1,79 +1,169 @@
|
|||
import connect from '../objects/connect.js'
|
||||
|
||||
// Robert Penner's Easing Functions
|
||||
const Easing = {
|
||||
linear : (t) => t,
|
||||
easingSinusoidalIn : (t) => -Math.cos(t * Math.PI / 2) + 1,
|
||||
easingSinusoidalOut : (t) => Math.sin(t * Math.PI / 2),
|
||||
easingSinusoidalInOut : (t) => -0.5 * (Math.cos(Math.PI * t) - 1),
|
||||
easingQuadraticIn : (t) => t*t,
|
||||
easingQuadraticOut : (t) => t*(2-t),
|
||||
easingQuadraticInOut : (t) => t<.5 ? 2*t*t : -1+(4-2*t)*t,
|
||||
easingCubicIn : (t) => t*t*t,
|
||||
easingCubicOut : (t) => (--t)*t*t+1,
|
||||
easingCubicInOut : (t) => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1,
|
||||
easingQuarticIn : (t) => t*t*t*t,
|
||||
easingQuarticOut : (t) => 1-(--t)*t*t*t,
|
||||
easingQuarticInOut : (t) => t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t,
|
||||
easingQuinticIn : (t) => t*t*t*t*t,
|
||||
easingQuinticOut : (t) => 1+(--t)*t*t*t*t,
|
||||
easingQuinticInOut : (t) => t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t,
|
||||
easingCircularIn : (t) => -(Math.sqrt(1 - (t * t)) - 1),
|
||||
easingCircularOut : (t) => Math.sqrt(1 - (t = t - 1) * t),
|
||||
easingCircularInOut : (t) => ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
|
||||
easingExponentialIn : (t) => 2 ** (10 * (t - 1)) - 0.001,
|
||||
easingExponentialOut : (t) => 1 - 2 ** (-10 * t),
|
||||
easingExponentialInOut : (t) => (t *= 2) < 1 ? 0.5 * (2 ** (10 * (t - 1))) : 0.5 * (2 - 2 ** (-10 * (t - 1))),
|
||||
easingBackIn : (t) => { const s = 1.70158; return t * t * ((s + 1) * t - s) },
|
||||
easingBackOut : (t) => { const s = 1.70158; return --t * t * ((s + 1) * t + s) + 1 },
|
||||
easingBackInOut : (t) => {
|
||||
const s = 1.70158 * 1.525;
|
||||
if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s))
|
||||
return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2)
|
||||
},
|
||||
easingElasticIn : (t) => {
|
||||
let s, _kea = 0.1, _kep = 0.4
|
||||
if ( t === 0 ) return 0;if ( t === 1 ) return 1
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2
|
||||
return - ( _kea * (2 ** (10 * (t -= 1))) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) )
|
||||
},
|
||||
easingElasticOut : (t) => {
|
||||
let s, _kea = 0.1, _kep = 0.4
|
||||
if ( t === 0 ) return 0;if ( t === 1 ) return 1
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2
|
||||
return _kea * (2 ** (- 10 * t)) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) + 1
|
||||
},
|
||||
easingElasticInOut : (t) => {
|
||||
let s, _kea = 0.1, _kep = 0.4
|
||||
if ( t === 0 ) return 0;if ( t === 1 ) return 1
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2
|
||||
if ( ( t *= 2 ) < 1 ) return - 0.5 * ( _kea * (2 ** (10 * (t -= 1))) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) )
|
||||
return _kea * (2 ** (-10 * (t -= 1))) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) * 0.5 + 1
|
||||
},
|
||||
easingBounceIn : (t) => { return 1 - Easing.easingBounceOut( 1 - t ) },
|
||||
easingBounceOut : (t) => {
|
||||
if ( t < ( 1 / 2.75 ) ) { return 7.5625 * t * t; }
|
||||
else if ( t < ( 2 / 2.75 ) ) { return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75; }
|
||||
else if ( t < ( 2.5 / 2.75 ) ) { return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375; }
|
||||
else {return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375; }
|
||||
},
|
||||
easingBounceInOut : (t) => {
|
||||
if ( t < 0.5 ) return Easing.easingBounceIn( t * 2 ) * 0.5;
|
||||
return Easing.easingBounceOut( t * 2 - 1 ) * 0.5 + 0.5
|
||||
}
|
||||
}
|
||||
|
||||
function processEasing(fn) {
|
||||
if ( typeof fn === 'function') {
|
||||
return fn;
|
||||
} else if ( typeof Easing[fn] === 'function' ) {
|
||||
return Easing[fn]; // regular Robert Penner Easing Functions
|
||||
} else {
|
||||
return Easing.linear
|
||||
}
|
||||
}
|
||||
|
||||
// Tween constructor needs to know who will process easing functions
|
||||
connect.processEasing = processEasing
|
||||
|
||||
export default Easing
|
||||
import connect from '../objects/connect';
|
||||
|
||||
// Robert Penner's Easing Functions
|
||||
// updated for ESLint
|
||||
const Easing = {
|
||||
/** @type {KUTE.easingFunction} */
|
||||
linear: (t) => t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingSinusoidalIn: (t) => -Math.cos((t * Math.PI) / 2) + 1,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingSinusoidalOut: (t) => Math.sin((t * Math.PI) / 2),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingSinusoidalInOut: (t) => -0.5 * (Math.cos(Math.PI * t) - 1),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticIn: (t) => t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticOut: (t) => t * (2 - t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuadraticInOut: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicIn: (t) => t * t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicOut: (t0) => { const t = t0 - 1; return t * t * t + 1; },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCubicInOut: (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuarticIn: (t) => t * t * t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuarticOut: (t0) => { const t = t0 - 1; return 1 - t * t * t * t; },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuarticInOut: (t0) => {
|
||||
let t = t0;
|
||||
if (t < 0.5) return 8 * t * t * t * t;
|
||||
t -= 1; return 1 - 8 * t * t * t * t;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuinticIn: (t) => t * t * t * t * t,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuinticOut: (t0) => { const t = t0 - 1; return 1 + t * t * t * t * t; },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingQuinticInOut: (t0) => {
|
||||
let t = t0;
|
||||
if (t < 0.5) return 16 * t * t * t * t * t;
|
||||
t -= 1; return 1 + 16 * t * t * t * t * t;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularIn: (t) => -(Math.sqrt(1 - (t * t)) - 1),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularOut: (t0) => { const t = t0 - 1; return Math.sqrt(1 - t * t); },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingCircularInOut: (t0) => {
|
||||
let t = t0 * 2;
|
||||
if (t < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);
|
||||
t -= 2; return 0.5 * (Math.sqrt(1 - t * t) + 1);
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingExponentialIn: (t) => 2 ** (10 * (t - 1)) - 0.001,
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingExponentialOut: (t) => 1 - 2 ** (-10 * t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingExponentialInOut: (t0) => {
|
||||
const t = t0 * 2;
|
||||
if (t < 1) return 0.5 * (2 ** (10 * (t - 1)));
|
||||
return 0.5 * (2 - 2 ** (-10 * (t - 1)));
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackIn: (t) => { const s = 1.70158; return t * t * ((s + 1) * t - s); },
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackOut: (t0) => {
|
||||
const s = 1.70158;
|
||||
const t = t0 - 1;
|
||||
return t * t * ((s + 1) * t + s) + 1;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBackInOut: (t0) => {
|
||||
const s = 1.70158 * 1.525;
|
||||
let t = t0 * 2;
|
||||
if (t < 1) return 0.5 * (t * t * ((s + 1) * t - s));
|
||||
t -= 2; return 0.5 * (t * t * ((s + 1) * t + s) + 2);
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingElasticIn: (t0) => {
|
||||
let s;
|
||||
let k1 = 0.1;
|
||||
const k2 = 0.4;
|
||||
let t = t0;
|
||||
if (t === 0) return 0;
|
||||
if (t === 1) return 1;
|
||||
if (!k1 || k1 < 1) {
|
||||
k1 = 1; s = k2 / 4;
|
||||
} else {
|
||||
s = ((k2 * Math.asin(1 / k1)) / Math.PI) * 2;
|
||||
}
|
||||
t -= 1;
|
||||
return -(k1 * (2 ** (10 * t)) * Math.sin(((t - s) * Math.PI * 2) / k2));
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingElasticOut: (t) => {
|
||||
let s;
|
||||
let k1 = 0.1;
|
||||
const k2 = 0.4;
|
||||
if (t === 0) return 0;
|
||||
if (t === 1) return 1;
|
||||
if (!k1 || k1 < 1) {
|
||||
k1 = 1;
|
||||
s = k2 / 4;
|
||||
} else {
|
||||
s = ((k2 * Math.asin(1 / k1)) / Math.PI) * 2;
|
||||
}
|
||||
return k1 * (2 ** (-10 * t)) * Math.sin(((t - s) * Math.PI * 2) / k2) + 1;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingElasticInOut: (t0) => {
|
||||
let t = t0;
|
||||
let s;
|
||||
let k1 = 0.1;
|
||||
const k2 = 0.4;
|
||||
if (t === 0) return 0;
|
||||
if (t === 1) return 1;
|
||||
if (!k1 || k1 < 1) {
|
||||
k1 = 1; s = k2 / 4;
|
||||
} else {
|
||||
s = k2 * (Math.asin(1 / k1) / Math.PI) * 2;
|
||||
}
|
||||
t *= 2;
|
||||
if (t < 1) {
|
||||
return -0.5 * (k1 * (2 ** (10 * (t - 1)))
|
||||
* Math.sin(((t - 1 - s) * Math.PI * 2) / k2));
|
||||
}
|
||||
t -= 1;
|
||||
return k1 * (2 ** (-10 * t)) * Math.sin(((t - s) * Math.PI * 2) / k2) * 0.5 + 1;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBounceIn: (t) => 1 - Easing.easingBounceOut(1 - t),
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBounceOut: (t0) => {
|
||||
let t = t0;
|
||||
if (t < (1 / 2.75)) { return 7.5625 * t * t; }
|
||||
if (t < (2 / 2.75)) { t -= (1.5 / 2.75); return 7.5625 * t * t + 0.75; }
|
||||
if (t < (2.5 / 2.75)) { t -= (2.25 / 2.75); return 7.5625 * t * t + 0.9375; }
|
||||
t -= (2.625 / 2.75);
|
||||
return 7.5625 * t * t + 0.984375;
|
||||
},
|
||||
/** @type {KUTE.easingFunction} */
|
||||
easingBounceInOut: (t) => {
|
||||
if (t < 0.5) return Easing.easingBounceIn(t * 2) * 0.5;
|
||||
return Easing.easingBounceOut(t * 2 - 1) * 0.5 + 0.5;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a valid `easingFunction`.
|
||||
*
|
||||
* @param {KUTE.easingFunction | string} fn function name or constructor
|
||||
* @returns {KUTE.easingFunction} a valid easing function
|
||||
*/
|
||||
function processEasing(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
return fn;
|
||||
} if (typeof Easing[fn] === 'function') {
|
||||
return Easing[fn]; // regular Robert Penner Easing Functions
|
||||
}
|
||||
return Easing.linear;
|
||||
}
|
||||
|
||||
// Tween constructor needs to know who will process easing functions
|
||||
connect.processEasing = processEasing;
|
||||
|
||||
export default Easing;
|
||||
|
|
|
@ -1,50 +1,36 @@
|
|||
import {version as Version} from './../package.json'
|
||||
import Render from './core/render.js'
|
||||
import Interpolate from './objects/interpolate.js'
|
||||
import Objects from './objects/objectsBase.js'
|
||||
import Util from './objects/util.js'
|
||||
import Easing from './easing/easing-base.js'
|
||||
import Internals from './core/internals.js'
|
||||
import Selector from './util/selector.js'
|
||||
|
||||
import Animation from './animation/animationBase.js'
|
||||
|
||||
// TweenConstructor
|
||||
import Tween from './tween/tweenBase.js'
|
||||
// Interface only fromTo
|
||||
import fromTo from './interface/fromTo.js'
|
||||
|
||||
// import baseTransform from './components/transformFunctionsBase.js'
|
||||
import baseTransformMatrix from './components/transformMatrixBase.js'
|
||||
import baseBoxModel from './components/boxModelBase.js'
|
||||
import baseOpacity from './components/opacityPropertyBase.js'
|
||||
// import {baseCrossBrowserMove} from './components/crossBrowserMove.js'
|
||||
|
||||
// const Transform = new Animation(baseTransform)
|
||||
const Transform = new Animation(baseTransformMatrix)
|
||||
const BoxModel = new Animation(baseBoxModel)
|
||||
const Opacity = new Animation(baseOpacity)
|
||||
// const Move = new Animation(baseCrossBrowserMove)
|
||||
// support for kute-base.js ends here
|
||||
|
||||
export default {
|
||||
Animation,
|
||||
Components: {
|
||||
Transform,
|
||||
BoxModel,
|
||||
Opacity,
|
||||
// Move
|
||||
},
|
||||
|
||||
Tween,
|
||||
fromTo,
|
||||
|
||||
Objects,
|
||||
Easing,
|
||||
Util,
|
||||
Render,
|
||||
Interpolate,
|
||||
Internals,
|
||||
Selector,
|
||||
Version
|
||||
}
|
||||
import Render from './core/render';
|
||||
import Interpolate from './objects/interpolate';
|
||||
import Objects from './objects/objectsBase';
|
||||
import Util from './objects/util';
|
||||
import Easing from './easing/easing-base';
|
||||
import Internals from './core/internals';
|
||||
import Selector from './util/selector';
|
||||
|
||||
// Animation
|
||||
import Animation from './animation/animationBase';
|
||||
// Base Components
|
||||
import Components from './objects/componentsBase';
|
||||
|
||||
// TweenConstructor
|
||||
import Tween from './tween/tweenBase';
|
||||
// Interface only fromTo
|
||||
import fromTo from './interface/fromTo';
|
||||
|
||||
import Version from './util/version';
|
||||
|
||||
export default {
|
||||
Animation,
|
||||
Components,
|
||||
|
||||
Tween,
|
||||
fromTo,
|
||||
|
||||
Objects,
|
||||
Easing,
|
||||
Util,
|
||||
Render,
|
||||
Interpolate,
|
||||
Internals,
|
||||
Selector,
|
||||
Version,
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue