diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..31039dd --- /dev/null +++ b/.eslintrc @@ -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 + } +} diff --git a/.gitignore b/.gitignore index a8cbe9d..b6d5063 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ - -node_modules -package-lock.json -experiments +node_modules/ +experiments/ +.npmignore +package-lock.json \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..de05e63 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +node_modules/ +demo/ +experiments/ +package-lock.json +.gitignore \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0de8c9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 thednp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..90c2187 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# KUTE.js + +A modern JavaScript animation engine built on ES6+ standards with strong TypeScript definitions and most essential features for the web with easy to use methods to set up high performance, cross-browser animations. The focus is code quality, flexibility, performance and size. + +[![NPM Version](https://img.shields.io/npm/v/kute.js.svg?style=flat-square)](https://www.npmjs.com/package/kute.js) +[![NPM Downloads](https://img.shields.io/npm/dm/kute.js.svg?style=flat-square)](http://npm-stat.com/charts.html?package=kute.js) +[![jsDeliver](https://data.jsdelivr.com/v1/package/npm/kute.js/badge)](https://www.jsdelivr.com/package/npm/kute.js) +[![CDNJS](https://img.shields.io/cdnjs/v/kute.js.svg?style=flat-square)](https://cdnjs.com/libraries/kute.js) + +KUTE.js packs a series of components for presentation attributes, SVG transform, draw SVG strokes and path morphing, text string write up or number countdowns, plus additional CSS properties like colors, border-radius or typographic properties. + +For components documentation, examples and other cool tips, check the [demo](http://thednp.github.io/kute.js/). + + +# Components +KUTE.js includes 18 components, but not all of them are bundled with the default distribution package: + +* [backgroundPosition](http://thednp.github.io/kute.js/backgroundPosition.html) - enables the animation for the `backgroundPosition` CSS property +* [borderRadius](http://thednp.github.io/kute.js/borderRadius.html) - enables the animation for all the **borderRadius** properties +* [boxModel](http://thednp.github.io/kute.js/boxModel.html) - enables the animation for the **boxModel** properties like `top` , `left`, `width`, etc +* [clipProperty](http://thednp.github.io/kute.js/clipProperty.html) - enables the animation for the `clip` property +* [colorProperties](http://thednp.github.io/kute.js/colorProperties.html) - enables the animation for the **color** properties like `color`, `backgroundColor` +* [filterEffects](http://thednp.github.io/kute.js/filterEffects.html) - enables the animation for the `filter` property +* [htmlAttributes](http://thednp.github.io/kute.js/htmlAttributes.html) - enables the animation for any numeric as well as some color based **HTML Attributes** +* [opacityProperty](http://thednp.github.io/kute.js/opacityProperty.html) - enables the animation for the `opacity` property +* [scrollProperty](http://thednp.github.io/kute.js/scrollProperty.html) - enables the animation for the window/Element `scrollTop` Object property +* [shadowProperties](http://thednp.github.io/kute.js/shadowProperties.html) - enables the animation for the **shadowProperties** properties: `textShadow` & `boxShadow` +* [svgCubicMorph](http://thednp.github.io/kute.js/svgCubicMorph.html) - enables the animation for the `d` Presentation Attribute of the `` SVGElement targets; this implements some [Raphael.js](https://dmitrybaranovskiy.github.io/raphael/) functionality +* [svgMorph](http://thednp.github.io/kute.js/svgMorph.html) - enables the animation for the `d` Presentation Attribute of the `` SVGElement targets; this component implements some [D3.js](https://github.com/d3/d3) and [flubber](https://github.com/veltman/flubber) functionality +* [svgDraw](http://thednp.github.io/kute.js/svgDraw.html) - enables the animation for the `strokeDasharray` and `strokeDashoffset` CSS properties specific to `` SVGElement +* [svgTransform](http://thednp.github.io/kute.js/svgTransform.html) - enables the animation for the `transform` presentation attribute +* [textProperties](http://thednp.github.io/kute.js/textProperties.html) - enables the animation for numeric `HTMLTextElement` related CSS properties like `fontSize` or `letterSpacing` +* [textWrite](http://thednp.github.io/kute.js/textWrite.html) - enables the animation for the content of various strings +* [transformFunctions](http://thednp.github.io/kute.js/transformFunctions.html) - enables the animation for the `transform` CSS3 property, the default component bundled with the official build +* transformLegacy - enables the animation for the `transform` CSS3 property on legacy browsers IE9+, not included with the official build, but can be used in your custom builds +* [transformMatrix](http://thednp.github.io/kute.js/transformMatrix.html) - enables the animation for the `transform` CSS3 property; this component implements `DOMMatrix()` API and is super light + +All above mentioned components have a BASE version which doesn't include value processing, and their purpose is to provide a way to ship your super light version of your application. + + +# Wiki +For a complete developer guide, usage and stuff like npm, visit [the wiki](https://github.com/thednp/kute.js/wiki). + + +# Browser Support +KUTE.js is redeveloped for maximum performance on modern browsers. Some legacy browsers might some help, so give them a small polyfill set with most essential features required by KUTE.js to work, powered by [minifill](https://github.com/thednp/minifill), try it. For broader projects you might want to consider polyfills. + + +# Special Thanks +* [Mike Bostock](https://bost.ocks.org/mike/) for his awesome [D3.js](https://github.com/d3/d3), one of the sources for our reworked [SVGMorph](http://thednp.github.io/kute.js/svgMorph.html) component. +* [Noah Veltman](https://github.com/veltman) for his awesome [flubber](https://github.com/veltman/flubber), another one of the sources for the SVGMorph component. +* [Andrew Willems](https://stackoverflow.com/users/5218951/andrew-willems) for his awesome [Stackoverflow answer](https://stackoverflow.com/questions/35560989/javascript-how-to-determine-a-svg-path-draw-direction) resulting in the creation of our [SVGCubicMorph](http://thednp.github.io/kute.js/svgCubicMorph.html) component. +* [Dmitry Baranovskiy](https://dmitry.baranovskiy.com/) for his awesome [Raphael.js](https://dmitrybaranovskiy.github.io/raphael/), another source for our SVGCubicMorph component. +* [@dalisoft](https://github.com/dalisoft) contributed a great deal to the performance and functionality of previous versions of KUTE.js. + + +# Contributions +* [Contributors & Collaborators](https://github.com/thednp/kute.js/graphs/contributors) + + +# License +[MIT License](https://github.com/thednp/kute.js/blob/master/LICENSE) diff --git a/assets/css/kute.css b/demo/assets/css/kute.css similarity index 100% rename from assets/css/kute.css rename to demo/assets/css/kute.css diff --git a/assets/css/prism.css b/demo/assets/css/prism.css similarity index 100% rename from assets/css/prism.css rename to demo/assets/css/prism.css diff --git a/assets/css/reset.css b/demo/assets/css/reset.css similarity index 100% rename from assets/css/reset.css rename to demo/assets/css/reset.css diff --git a/assets/css/spicr-theme.css b/demo/assets/css/spicr-theme.css similarity index 100% rename from assets/css/spicr-theme.css rename to demo/assets/css/spicr-theme.css diff --git a/assets/img/apple-touch-icon.png b/demo/assets/img/apple-touch-icon.png similarity index 100% rename from assets/img/apple-touch-icon.png rename to demo/assets/img/apple-touch-icon.png diff --git a/assets/img/favicon.ico b/demo/assets/img/favicon.ico similarity index 100% rename from assets/img/favicon.ico rename to demo/assets/img/favicon.ico diff --git a/assets/img/home.svg b/demo/assets/img/home.svg similarity index 100% rename from assets/img/home.svg rename to demo/assets/img/home.svg diff --git a/assets/img/img-blank.gif b/demo/assets/img/img-blank.gif similarity index 100% rename from assets/img/img-blank.gif rename to demo/assets/img/img-blank.gif diff --git a/assets/img/loader.gif b/demo/assets/img/loader.gif similarity index 100% rename from assets/img/loader.gif rename to demo/assets/img/loader.gif diff --git a/assets/img/ms.svg b/demo/assets/img/ms.svg similarity index 100% rename from assets/img/ms.svg rename to demo/assets/img/ms.svg diff --git a/assets/img/rectangle.svg b/demo/assets/img/rectangle.svg similarity index 100% rename from assets/img/rectangle.svg rename to demo/assets/img/rectangle.svg diff --git a/assets/img/social.svg b/demo/assets/img/social.svg similarity index 100% rename from assets/img/social.svg rename to demo/assets/img/social.svg diff --git a/assets/js/backgroundPosition.js b/demo/assets/js/backgroundPosition.js similarity index 100% rename from assets/js/backgroundPosition.js rename to demo/assets/js/backgroundPosition.js diff --git a/assets/js/borderRadius.js b/demo/assets/js/borderRadius.js similarity index 100% rename from assets/js/borderRadius.js rename to demo/assets/js/borderRadius.js diff --git a/assets/js/boxModel.js b/demo/assets/js/boxModel.js similarity index 100% rename from assets/js/boxModel.js rename to demo/assets/js/boxModel.js diff --git a/assets/js/clipProperty.js b/demo/assets/js/clipProperty.js similarity index 100% rename from assets/js/clipProperty.js rename to demo/assets/js/clipProperty.js diff --git a/assets/js/colorProperties.js b/demo/assets/js/colorProperties.js similarity index 100% rename from assets/js/colorProperties.js rename to demo/assets/js/colorProperties.js diff --git a/assets/js/filterEffects.js b/demo/assets/js/filterEffects.js similarity index 100% rename from assets/js/filterEffects.js rename to demo/assets/js/filterEffects.js diff --git a/assets/js/home.js b/demo/assets/js/home.js similarity index 100% rename from assets/js/home.js rename to demo/assets/js/home.js diff --git a/assets/js/htmlAttributes.js b/demo/assets/js/htmlAttributes.js similarity index 100% rename from assets/js/htmlAttributes.js rename to demo/assets/js/htmlAttributes.js diff --git a/assets/js/opacityProperty.js b/demo/assets/js/opacityProperty.js similarity index 100% rename from assets/js/opacityProperty.js rename to demo/assets/js/opacityProperty.js diff --git a/assets/js/perf-matrix.js b/demo/assets/js/perf-matrix.js similarity index 100% rename from assets/js/perf-matrix.js rename to demo/assets/js/perf-matrix.js diff --git a/assets/js/perf.js b/demo/assets/js/perf.js similarity index 100% rename from assets/js/perf.js rename to demo/assets/js/perf.js diff --git a/assets/js/prism.js b/demo/assets/js/prism.js similarity index 100% rename from assets/js/prism.js rename to demo/assets/js/prism.js diff --git a/assets/js/progress.js b/demo/assets/js/progress.js similarity index 100% rename from assets/js/progress.js rename to demo/assets/js/progress.js diff --git a/assets/js/sampleComponent.js b/demo/assets/js/sampleComponent.js similarity index 100% rename from assets/js/sampleComponent.js rename to demo/assets/js/sampleComponent.js diff --git a/assets/js/scripts.js b/demo/assets/js/scripts.js similarity index 100% rename from assets/js/scripts.js rename to demo/assets/js/scripts.js diff --git a/assets/js/scrollProperty.js b/demo/assets/js/scrollProperty.js similarity index 100% rename from assets/js/scrollProperty.js rename to demo/assets/js/scrollProperty.js diff --git a/assets/js/shadowProperties.js b/demo/assets/js/shadowProperties.js similarity index 100% rename from assets/js/shadowProperties.js rename to demo/assets/js/shadowProperties.js diff --git a/assets/js/svgCubicMorph.js b/demo/assets/js/svgCubicMorph.js similarity index 100% rename from assets/js/svgCubicMorph.js rename to demo/assets/js/svgCubicMorph.js diff --git a/assets/js/svgDraw.js b/demo/assets/js/svgDraw.js similarity index 100% rename from assets/js/svgDraw.js rename to demo/assets/js/svgDraw.js diff --git a/assets/js/svgMorph.js b/demo/assets/js/svgMorph.js similarity index 100% rename from assets/js/svgMorph.js rename to demo/assets/js/svgMorph.js diff --git a/assets/js/svgTransform.js b/demo/assets/js/svgTransform.js similarity index 100% rename from assets/js/svgTransform.js rename to demo/assets/js/svgTransform.js diff --git a/assets/js/textProperties.js b/demo/assets/js/textProperties.js similarity index 100% rename from assets/js/textProperties.js rename to demo/assets/js/textProperties.js diff --git a/assets/js/textWrite.js b/demo/assets/js/textWrite.js similarity index 100% rename from assets/js/textWrite.js rename to demo/assets/js/textWrite.js diff --git a/assets/js/transformFunctions.js b/demo/assets/js/transformFunctions.js similarity index 100% rename from assets/js/transformFunctions.js rename to demo/assets/js/transformFunctions.js diff --git a/assets/js/transformMatrix.js b/demo/assets/js/transformMatrix.js similarity index 100% rename from assets/js/transformMatrix.js rename to demo/assets/js/transformMatrix.js diff --git a/assets/js/tween.min.js b/demo/assets/js/tween.min.js similarity index 100% rename from assets/js/tween.min.js rename to demo/assets/js/tween.min.js diff --git a/backgroundPosition.html b/demo/backgroundPosition.html similarity index 100% rename from backgroundPosition.html rename to demo/backgroundPosition.html diff --git a/borderRadius.html b/demo/borderRadius.html similarity index 100% rename from borderRadius.html rename to demo/borderRadius.html diff --git a/boxModel.html b/demo/boxModel.html similarity index 100% rename from boxModel.html rename to demo/boxModel.html diff --git a/clipProperty.html b/demo/clipProperty.html similarity index 100% rename from clipProperty.html rename to demo/clipProperty.html diff --git a/colorProperties.html b/demo/colorProperties.html similarity index 100% rename from colorProperties.html rename to demo/colorProperties.html diff --git a/filterEffects.html b/demo/filterEffects.html similarity index 100% rename from filterEffects.html rename to demo/filterEffects.html diff --git a/htmlAttributes.html b/demo/htmlAttributes.html similarity index 100% rename from htmlAttributes.html rename to demo/htmlAttributes.html diff --git a/index.html b/demo/index.html similarity index 100% rename from index.html rename to demo/index.html diff --git a/opacityProperty.html b/demo/opacityProperty.html similarity index 100% rename from opacityProperty.html rename to demo/opacityProperty.html diff --git a/performance-matrix.html b/demo/performance-matrix.html similarity index 100% rename from performance-matrix.html rename to demo/performance-matrix.html diff --git a/performance-transform.html b/demo/performance-transform.html similarity index 100% rename from performance-transform.html rename to demo/performance-transform.html diff --git a/performance.html b/demo/performance.html similarity index 100% rename from performance.html rename to demo/performance.html diff --git a/progress.html b/demo/progress.html similarity index 100% rename from progress.html rename to demo/progress.html diff --git a/scrollProperty.html b/demo/scrollProperty.html similarity index 100% rename from scrollProperty.html rename to demo/scrollProperty.html diff --git a/shadowProperties.html b/demo/shadowProperties.html similarity index 100% rename from shadowProperties.html rename to demo/shadowProperties.html diff --git a/src/kute-base.js b/demo/src/kute-base.js similarity index 99% rename from src/kute-base.js rename to demo/src/kute-base.js index cbc1834..fe676be 100644 --- a/src/kute-base.js +++ b/demo/src/kute-base.js @@ -1,5 +1,5 @@ /*! -* KUTE.js Base v2.2.2 (http://thednp.github.io/kute.js) +* KUTE.js Base v2.2.3 (http://thednp.github.io/kute.js) * Copyright 2015-2021 © thednp * Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE) */ @@ -876,7 +876,7 @@ return new TweenConstructor(selector(element), startObject, endObject, options); } - var version = "2.2.2"; + var version = "2.2.3"; // @ts-ignore diff --git a/src/kute-base.min.js b/demo/src/kute-base.min.js similarity index 98% rename from src/kute-base.min.js rename to demo/src/kute-base.min.js index 72e48c4..3eee4ab 100644 --- a/src/kute-base.min.js +++ b/demo/src/kute-base.min.js @@ -1,2 +1,2 @@ -// KUTE.js Base v2.2.2 | thednp © 2021 | MIT-License -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t={},e=[],n="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},i={},o={},r="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},a={};a.now=r;var s=0,c=function(t){for(var n=0;n>0)/1e3+n+")"}function T(t,e,n,i){for(var o=[],r=0;r<3;r+=1)o[r]=(t[r]||e[r]?(1e3*(t[r]+(e[r]-t[r])*i)>>0)/1e3:0)+n;return"translate3d("+o.join(",")+")"}function I(t,e,n,i){var o="";return o+=t[0]||e[0]?"rotateX("+(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3+n+")":"",o+=t[1]||e[1]?"rotateY("+(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3+n+")":"",o+=t[2]||e[2]?"rotateZ("+(1e3*(t[2]+(e[2]-t[2])*i)>>0)/1e3+n+")":""}function S(t,e,n){return"scale("+(1e3*(t+(e-t)*n)>>0)/1e3+")"}function C(t,e,n,i){var o=[];return o[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3)+n,o[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3)+n:"0","skew("+o.join(",")+")"}var x={component:"baseTransform",property:"transform",functions:{onStart:function(e){!t[e]&&this.valuesEnd[e]&&(t[e]=function(t,n,i,o){t.style[e]=(n.perspective||i.perspective?w(n.perspective,i.perspective,"px",o):"")+(n.translate3d?T(n.translate3d,i.translate3d,"px",o):"")+(n.rotate3d?I(n.rotate3d,i.rotate3d,"deg",o):"")+(n.skew?C(n.skew,i.skew,"deg",o):"")+(n.scale||i.scale?S(n.scale,i.scale,o):"")})}},Interpolate:{perspective:w,translate3d:T,rotate3d:I,translate:function(t,e,n,i){var o=[];return o[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3)+n,o[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3)+n:"0","translate("+o.join(",")+")"},rotate:function(t,e,n,i){return"rotate("+(1e3*(t+(e-t)*i)>>0)/1e3+n+")"},scale:S,skew:C}};function U(t,e,n){return+t+(e-t)*n}function M(e){e in this.valuesEnd&&!t[e]&&(t[e]=function(t,n,i,o){t.style[e]=(o>.99||o<.01?(10*U(n,i,o)>>0)/10:U(n,i,o)>>0)+"px"})}var q=["top","left","width","height"],A={};q.forEach((function(t){A[t]=M}));var F={component:"baseBoxModel",category:"boxModel",properties:q,Interpolate:{numbers:U},functions:{onStart:A}};var B={component:"baseOpacity",property:"opacity",Interpolate:{numbers:U},functions:{onStart:function(e){e in this.valuesEnd&&!t[e]&&(t[e]=function(t,n,i,o){t.style[e]=(1e3*U(n,i,o)>>0)/1e3})}}},D={Transform:new j(x),BoxModel:new j(F),Opacity:new j(B)};function K(){var t=this;Object.keys(o).forEach((function(e){"function"==typeof o[e]?o[e].call(t,e):Object.keys(o[e]).forEach((function(n){o[e][n].call(t,n)}))})),_.call(this)}var Q=function(e,n,i,r){var a=this;this.element=e,this.playing=!1,this._startTime=null,this._startFired=!1,this.valuesEnd=i,this.valuesStart=n;var s=r||{};this._resetStart=s.resetStart||0,this._easing="function"==typeof s.easing?s.easing:v.processEasing(s.easing),this._duration=s.duration||l.duration,this._delay=s.delay||l.delay,Object.keys(s).forEach((function(t){var e="_"+t;e in a||(a[e]=s[t])}));var c=this._easing.name;return o[c]||(o[c]=function(e){t[e]||e!==this._easing.name||(t[e]=this._easing)}),this};Q.prototype.start=function(e){return g(this),this.playing=!0,this._startTime=void 0!==e?e:t.Time(),this._startTime+=this._delay,this._startFired||(this._onStart&&this._onStart.call(this),K.call(this),this._startFired=!0),s||c(),this},Q.prototype.stop=function(){return this.playing&&(E(this),this.playing=!1,this._onStop&&this._onStop.call(this),this.close()),this},Q.prototype.close=function(){var t=this;Object.keys(p).forEach((function(e){Object.keys(p[e]).forEach((function(n){p[e][n].call(t,n)}))})),this._startFired=!1,u.call(this)},Q.prototype.chain=function(t){return this._chain=[],this._chain=t.length?t:this._chain.concat(t),this},Q.prototype.stopChainedTweens=function(){this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.stop()}))},Q.prototype.update=function(e){var n,i=this,o=void 0!==e?e:t.Time();if(o1?1:n;var r=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(e){t[e](i.element,i.valuesStart[e],i.valuesEnd[e],r)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},v.tween=Q;var L=v.tween;return{Animation:j,Components:D,Tween:Q,fromTo:function(t,e,n,i){var o=i||{};return new L(k(t),e,n,o)},Objects:d,Easing:m,Util:y,Render:f,Interpolate:i,Internals:O,Selector:k,Version:"2.2.2"}})); +// KUTE.js Base v2.2.3 | thednp © 2021 | MIT-License +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t={},e=[],n="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},i={},o={},r="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},a={};a.now=r;var s=0,c=function(t){for(var n=0;n>0)/1e3+n+")"}function T(t,e,n,i){for(var o=[],r=0;r<3;r+=1)o[r]=(t[r]||e[r]?(1e3*(t[r]+(e[r]-t[r])*i)>>0)/1e3:0)+n;return"translate3d("+o.join(",")+")"}function I(t,e,n,i){var o="";return o+=t[0]||e[0]?"rotateX("+(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3+n+")":"",o+=t[1]||e[1]?"rotateY("+(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3+n+")":"",o+=t[2]||e[2]?"rotateZ("+(1e3*(t[2]+(e[2]-t[2])*i)>>0)/1e3+n+")":""}function S(t,e,n){return"scale("+(1e3*(t+(e-t)*n)>>0)/1e3+")"}function C(t,e,n,i){var o=[];return o[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3)+n,o[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3)+n:"0","skew("+o.join(",")+")"}var x={component:"baseTransform",property:"transform",functions:{onStart:function(e){!t[e]&&this.valuesEnd[e]&&(t[e]=function(t,n,i,o){t.style[e]=(n.perspective||i.perspective?w(n.perspective,i.perspective,"px",o):"")+(n.translate3d?T(n.translate3d,i.translate3d,"px",o):"")+(n.rotate3d?I(n.rotate3d,i.rotate3d,"deg",o):"")+(n.skew?C(n.skew,i.skew,"deg",o):"")+(n.scale||i.scale?S(n.scale,i.scale,o):"")})}},Interpolate:{perspective:w,translate3d:T,rotate3d:I,translate:function(t,e,n,i){var o=[];return o[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*i)>>0)/1e3)+n,o[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*i)>>0)/1e3)+n:"0","translate("+o.join(",")+")"},rotate:function(t,e,n,i){return"rotate("+(1e3*(t+(e-t)*i)>>0)/1e3+n+")"},scale:S,skew:C}};function U(t,e,n){return+t+(e-t)*n}function M(e){e in this.valuesEnd&&!t[e]&&(t[e]=function(t,n,i,o){t.style[e]=(o>.99||o<.01?(10*U(n,i,o)>>0)/10:U(n,i,o)>>0)+"px"})}var q=["top","left","width","height"],A={};q.forEach((function(t){A[t]=M}));var F={component:"baseBoxModel",category:"boxModel",properties:q,Interpolate:{numbers:U},functions:{onStart:A}};var B={component:"baseOpacity",property:"opacity",Interpolate:{numbers:U},functions:{onStart:function(e){e in this.valuesEnd&&!t[e]&&(t[e]=function(t,n,i,o){t.style[e]=(1e3*U(n,i,o)>>0)/1e3})}}},D={Transform:new j(x),BoxModel:new j(F),Opacity:new j(B)};function K(){var t=this;Object.keys(o).forEach((function(e){"function"==typeof o[e]?o[e].call(t,e):Object.keys(o[e]).forEach((function(n){o[e][n].call(t,n)}))})),_.call(this)}var Q=function(e,n,i,r){var a=this;this.element=e,this.playing=!1,this._startTime=null,this._startFired=!1,this.valuesEnd=i,this.valuesStart=n;var s=r||{};this._resetStart=s.resetStart||0,this._easing="function"==typeof s.easing?s.easing:v.processEasing(s.easing),this._duration=s.duration||l.duration,this._delay=s.delay||l.delay,Object.keys(s).forEach((function(t){var e="_"+t;e in a||(a[e]=s[t])}));var c=this._easing.name;return o[c]||(o[c]=function(e){t[e]||e!==this._easing.name||(t[e]=this._easing)}),this};Q.prototype.start=function(e){return g(this),this.playing=!0,this._startTime=void 0!==e?e:t.Time(),this._startTime+=this._delay,this._startFired||(this._onStart&&this._onStart.call(this),K.call(this),this._startFired=!0),s||c(),this},Q.prototype.stop=function(){return this.playing&&(E(this),this.playing=!1,this._onStop&&this._onStop.call(this),this.close()),this},Q.prototype.close=function(){var t=this;Object.keys(p).forEach((function(e){Object.keys(p[e]).forEach((function(n){p[e][n].call(t,n)}))})),this._startFired=!1,u.call(this)},Q.prototype.chain=function(t){return this._chain=[],this._chain=t.length?t:this._chain.concat(t),this},Q.prototype.stopChainedTweens=function(){this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.stop()}))},Q.prototype.update=function(e){var n,i=this,o=void 0!==e?e:t.Time();if(o1?1:n;var r=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(e){t[e](i.element,i.valuesStart[e],i.valuesEnd[e],r)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},v.tween=Q;var L=v.tween;return{Animation:j,Components:D,Tween:Q,fromTo:function(t,e,n,i){var o=i||{};return new L(k(t),e,n,o)},Objects:d,Easing:m,Util:y,Render:f,Interpolate:i,Internals:O,Selector:k,Version:"2.2.3"}})); diff --git a/src/kute-extra.js b/demo/src/kute-extra.js similarity index 99% rename from src/kute-extra.js rename to demo/src/kute-extra.js index ede7275..b557f0a 100644 --- a/src/kute-extra.js +++ b/demo/src/kute-extra.js @@ -1,5 +1,5 @@ /*! -* KUTE.js Extra v2.2.2 (http://thednp.github.io/kute.js) +* KUTE.js Extra v2.2.3 (http://thednp.github.io/kute.js) * Copyright 2015-2021 © thednp * Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE) */ @@ -5689,7 +5689,7 @@ Components[component] = new AnimationDevelopment(compOps); }); - var version = "2.2.2"; + var version = "2.2.3"; // @ts-ignore diff --git a/src/kute-extra.min.js b/demo/src/kute-extra.min.js similarity index 99% rename from src/kute-extra.min.js rename to demo/src/kute-extra.min.js index 8ad4417..b592e58 100644 --- a/src/kute-extra.min.js +++ b/demo/src/kute-extra.min.js @@ -1,2 +1,2 @@ -// KUTE.js Extra v2.2.2 | thednp © 2021 | MIT-License -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t=function(t,e,n,r,a){var i=this;this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by;var o=function(t){return i.sampleCurveY(i.solveCurveX(t))};return Object.defineProperty(o,"name",{writable:!0}),o.name=a||"cubic-bezier("+[t,e,n,r]+")",o};t.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},t.prototype.sampleCurveY=function(t){return((this.ay*t+this.by)*t+this.cy)*t},t.prototype.sampleCurveDerivativeX=function(t){return(3*this.ax*t+2*this.bx)*t+this.cx},t.prototype.solveCurveX=function(t){var e,n,r,a,i,o,s=1e-5;for(r=t,o=0;o<32;o+=1){if(a=this.sampleCurveX(r)-t,Math.abs(a)(n=1))return n;for(;ea?e=r:n=r,r=.5*(n-e)+e}return r};Object.assign(t,{Version:"1.0.18"});var e={},n=[],r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},a={},i={},o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},s={};s.now=o;var u=0,c=function(t){for(var e=0;e1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},I.tween=V;var N=function(t){function n(){for(var e=this,n=[],r=arguments.length;r--;)n[r]=arguments[r];t.apply(this,n),this.valuesStart={},this.valuesEnd={};var a=n.slice(1),i=a[0],o=a[1],s=a[2];return _.call(this,o,"end"),this._resetStart?this.valuesStart=i:_.call(this,i,"start"),this._resetStart||Object.keys(m).forEach((function(t){Object.keys(m[t]).forEach((function(n){m[t][n].call(e,n)}))})),this.paused=!1,this._pauseTime=null,this._repeat=s.repeat||d.repeat,this._repeatDelay=s.repeatDelay||d.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=s.yoyo||d.yoyo,this._reversed=!1,this}return t&&(n.__proto__=t),n.prototype=Object.create(t&&t.prototype),n.prototype.constructor=n,n.prototype.start=function(e){var n=this;return this._resetStart&&(this.valuesStart=this._resetStart,C.call(this),Object.keys(m).forEach((function(t){Object.keys(m[t]).forEach((function(e){m[t][e].call(n,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((function(t){n.valuesRepeat[t]=n.valuesStart[t]})),t.prototype.start.call(this,e),this},n.prototype.stop=function(){return t.prototype.stop.call(this),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this},n.prototype.close=function(){return t.prototype.close.call(this),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this},n.prototype.resume=function(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),L.call(this),this._startTime+=e.Time()-this._pauseTime,x(this),u||c()),this},n.prototype.pause=function(){return!this.paused&&this.playing&&(S(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this},n.prototype.reverse=function(){var t=this;Object.keys(this.valuesEnd).forEach((function(e){var n=t.valuesRepeat[e];t.valuesRepeat[e]=t.valuesEnd[e],t.valuesEnd[e]=n,t.valuesStart[e]=t.valuesRepeat[e]}))},n.prototype.update=function(t){var n,r=this,a=void 0!==t?t:e.Time();if(a1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=a,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.start()})),!1))},n}(V);I.tween=N;var R=function(t){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];return t.apply(this,e),this}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.on=function(t,e){return["start","stop","update","complete","pause","resume"].indexOf(t)>-1&&(this["_on"+(t.charAt(0).toUpperCase()+t.slice(1))]=e),this},e.prototype.option=function(t,e){return this["_"+t]=e,this},e}(N);I.tween=R;var U=function(t,e,n,r){var a=this,i=I.tween;this.tweens=[];var o=r||{};o.delay=o.delay||d.delay;var s=[];return Array.from(t).forEach((function(t,r){if(s[r]=o||{},s[r].delay=r>0?o.delay+(o.offset||d.offset):o.delay,!(t instanceof Element))throw Error("KUTE - "+t+" is not instanceof Element");a.tweens.push(new i(t,e,n,s[r]))})),this.length=this.tweens.length,this};U.prototype.start=function(t){var n=void 0===t?e.Time():t;return this.tweens.map((function(t){return t.start(n)})),this},U.prototype.stop=function(){return this.tweens.map((function(t){return t.stop()})),this},U.prototype.pause=function(){return this.tweens.map((function(t){return t.pause()})),this},U.prototype.resume=function(){return this.tweens.map((function(t){return t.resume()})),this},U.prototype.chain=function(t){var e=this.tweens[this.length-1];if(t instanceof U)e.chain(t.tweens);else{if(!(t instanceof I.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this},U.prototype.playing=function(){return this.tweens.some((function(t){return t.playing}))},U.prototype.removeTweens=function(){this.tweens=[]},U.prototype.getMaxDuration=function(){var t=[];return this.tweens.forEach((function(e){t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)};var F=function(t,e){var n;if(this.element=P(t),this.element.tween=e,this.element.tween.toolbar=this.element,this.element.toolbar=this,n=this.element.parentNode.getElementsByTagName("OUTPUT"),this.element.output=n[0],!(this.element instanceof HTMLInputElement))throw TypeError("Target element is not [HTMLInputElement]");if("range"!==this.element.type)throw TypeError("Target element is not a range input");if(!(e instanceof I.tween))throw TypeError("tween parameter is not ["+I.tween+"]");this.element.setAttribute("value",0),this.element.setAttribute("min",0),this.element.setAttribute("max",1),this.element.setAttribute("step",1e-4),this.element.tween._onUpdate=this.updateBar,this.element.addEventListener("mousedown",this.downAction,!1)};F.prototype.updateBar=function(){var t,n=this.toolbar.output;(t=this.paused?this.toolbar.value:(e.Time()-this._startTime)/this._duration)>.9999&&(t=1),t<.01&&(t=0);var r=this._reversed?1-t:t;this.toolbar.value=r,n&&(n.value=(1e4*r>>0)/100+"%")},F.prototype.toggleEvents=function(t){this.element[t+"EventListener"]("mousemove",this.moveAction,!1),this.element[t+"EventListener"]("mouseup",this.upAction,!1)},F.prototype.updateTween=function(){var t=(this.tween._reversed?1-this.value:this.value)*this.tween._duration-1e-4;this.tween._startTime=0,this.tween.update(t)},F.prototype.moveAction=function(){this.toolbar.updateTween.call(this)},F.prototype.downAction=function(){this.tween.playing||this.tween.start(),this.tween.paused||(this.tween.pause(),this.toolbar.toggleEvents("add"),e.Tick=cancelAnimationFrame(e.Ticker))},F.prototype.upAction=function(){this.tween.paused&&(this.tween.paused&&this.tween.resume(),this.tween._startTime=e.Time()-(this.tween._reversed?1-this.value:this.value)*this.tween._duration,this.toolbar.toggleEvents("remove"),e.Tick=requestAnimationFrame(e.Ticker))};var D=I.tween;var H=I.tween;var q=function(t){try{if(t.component in h)throw Error("KUTE - "+t.component+" already registered");if(t.property in f)throw Error("KUTE - "+t.property+" already registered")}catch(t){throw Error(t)}var e=this,n=t.component,r={prepareProperty:v,prepareStart:g,onStart:i,onComplete:y,crossCheck:m},o=t.category,s=t.property,u=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return h[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(f[s]=t.defaultValue,e.supports=s+" property"):t.defaultValues&&(Object.keys(t.defaultValues).forEach((function(e){f[e]=t.defaultValues[e]})),e.supports=(u||s)+" "+(s||o)+" properties"),t.defaultOptions&&Object.assign(d,t.defaultOptions),t.functions&&Object.keys(r).forEach((function(e){e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][o||s]||(r[e][n][o||s]=t.functions[e])):Object.keys(t.functions[e]).forEach((function(a){r[e][n]||(r[e][n]={}),r[e][n][a]||(r[e][n][a]=t.functions[e][a])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((function(e){var n=t.Interpolate[e];"function"!=typeof n||a[e]?Object.keys(n).forEach((function(t){"function"!=typeof n[t]||a[e]||(a[e]=n[t])})):a[e]=n})),b[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((function(e){E[e]||(E[e]=t.Util[e])})),e},B=function(t){function e(e){t.call(this,e);var n=this,r={prepareProperty:v,prepareStart:g,onStart:i,onComplete:y,crossCheck:m},o=e.category,s=e.property,u=e.properties&&e.properties.length||e.subProperties&&e.subProperties.length;return"defaultValue"in e?(n.supports=s+" property",n.defaultValue=(""+e.defaultValue).length?"YES":"not set or incorrect"):e.defaultValues&&(n.supports=(u||s)+" "+(s||o)+" properties",n.defaultValues=Object.keys(e.defaultValues).length===u?"YES":"Not set or incomplete"),e.defaultOptions&&(n.extends=[],Object.keys(e.defaultOptions).forEach((function(t){n.extends.push(t)})),n.extends.length?n.extends="with <"+n.extends.join(", ")+"> new option(s)":delete n.extends),e.functions&&(n.interface=[],n.render=[],n.warning=[],Object.keys(r).forEach((function(t){t in e.functions?("prepareProperty"===t&&n.interface.push("fromTo()"),"prepareStart"===t&&n.interface.push("to()"),"onStart"===t&&(n.render="can render update")):("prepareProperty"===t&&n.warning.push("fromTo()"),"prepareStart"===t&&n.warning.push("to()"),"onStart"===t&&(n.render="no function to render update"))})),n.interface.length?n.interface=(o||s)+" can use ["+n.interface.join(", ")+"] method(s)":delete n.uses,n.warning.length?n.warning=(o||s)+" can't use ["+n.warning.join(", ")+"] method(s) because values aren't processed":delete n.warning),e.Interpolate?(n.uses=[],n.adds=[],Object.keys(e.Interpolate).forEach((function(t){var r=e.Interpolate[t];"function"==typeof r?(a[t]||n.adds.push(""+t),n.uses.push(""+t)):Object.keys(r).forEach((function(e){"function"!=typeof r[e]||a[t]||n.adds.push(""+e),n.uses.push(""+e)}))})),n.uses.length?n.uses="["+n.uses.join(", ")+"] interpolation function(s)":delete n.uses,n.adds.length?n.adds="new ["+n.adds.join(", ")+"] interpolation function(s)":delete n.adds):n.critical="For "+(s||o)+" no interpolation function[s] is set",e.Util&&(n.hasUtil=Object.keys(e.Util).join(",")),n}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(q);function Q(t,e,n){return+t+(e-t)*n}var z=function(t,e){for(var n,r=parseInt(t,10)||0,a=["px","%","deg","rad","em","rem","vh","vw"],i=0;i>0)/100+"% "+(100*Q(n[1],r[1],a)>>0)/100+"%"})}},Y={component:"backgroundPositionProp",property:"backgroundPosition",defaultValue:[50,50],Interpolate:{numbers:Q},functions:X,Util:{trueDimension:z}};function W(t,e,n,r){return+t+(e-t)*r+n}function $(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=W(n.v,r.v,r.u,a)})}var G={};["borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius"].forEach((function(t){G[t]=$}));var Z=["borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius"],K={};Z.forEach((function(t){K[t]=0}));var J={};Z.forEach((function(t){J[t]=$}));var tt={component:"borderRadiusProperties",category:"borderRadius",properties:Z,defaultValues:K,Interpolate:{units:W},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return z(e)},onStart:J},Util:{trueDimension:z}};function et(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(a>.99||a<.01?(10*Q(n,r,a)>>0)/10:Q(n,r,a)>>0)+"px"})}var nt={};["top","left","width","height"].forEach((function(t){nt[t]=et}));var rt=["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"],at={};rt.forEach((function(t){at[t]=0}));var it={};rt.forEach((function(t){it[t]=et}));var ot={component:"boxModelProperties",category:"boxModel",properties:rt,defaultValues:at,Interpolate:{numbers:Q},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){var n=z(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:it}};var st={prepareStart:function(t){var e=this.element,n=M(e,t),r=M(e,"width"),a=M(e,"height");return/rect/.test(n)?n:[0,r,a,0]},prepareProperty:function(t,e){if(e instanceof Array)return e.map((function(t){return z(t)}));var n=e.replace(/rect|\(|\)/g,"");return(n=/,/g.test(n)?n.split(","):n.split(/\s/)).map((function(t){return z(t)}))},onStart:function(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(t,e,n,r){for(var a=0,i=[];a<4;a+=1){var o=e[a].v,s=n[a].v,u=n[a].u||"px";i[a]=(100*Q(o,s,r)>>0)/100+u}t.style.clip="rect("+i+")"})}},ut={component:"clipProperty",property:"clip",defaultValue:[0,0,0,0],Interpolate:{numbers:Q},functions:st,Util:{trueDimension:z}},ct=function(t){var e;if(/rgb|rgba/.test(t)){var n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){var a=function(t){var e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,n,r){return e+e+n+n+r+r})),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}(t);e={r:a.r,g:a.g,b:a.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){var i=document.getElementsByTagName("head")[0];i.style.color=t;var o=getComputedStyle(i,null).color;o=/rgb/.test(o)?o.replace(/[^\d,]/g,"").split(","):[0,0,0],i.style.color="",e={r:parseInt(o[0],10),g:parseInt(o[1],10),b:parseInt(o[2],10)}}return e};function lt(t,e,n){var r={},a=",";return Object.keys(e).forEach((function(a){"a"!==a?r[a]=Q(t[a],e[a],n)>>0||0:t[a]&&e[a]&&(r[a]=(100*Q(t[a],e[a],n)>>0)/100)})),r.a?"rgba("+r.r+a+r.g+a+r.b+a+r.a+")":"rgb("+r.r+a+r.g+a+r.b+")"}function pt(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=lt(n,r,a)})}var ht={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((function(t){ht[t]=pt}));var ft=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],dt={};ft.forEach((function(t){dt[t]="#000"}));var vt={};ft.forEach((function(t){vt[t]=pt}));var gt={component:"colorProperties",category:"colors",properties:ft,defaultValues:dt,Interpolate:{numbers:Q,colors:lt},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return ct(e)},onStart:vt},Util:{trueColor:ct}};function mt(t,e,n){for(var r=[],a=0;a<3;a+=1)r[a]=(100*Q(t[a],e[a],n)>>0)/100+"px";return"drop-shadow("+r.concat(lt(t[3],e[3],n)).join(" ")+")"}function yt(t){return t.replace("-r","R").replace("-s","S")}function bt(t){var e;3===t.length?e=[t[0],t[1],0,t[2]]:4===t.length&&(e=[t[0],t[1],t[2],t[3]]);for(var n=0;n<3;n+=1)e[n]=parseFloat(e[n]);return e[3]=ct(e[3]),e}function wt(t){var e={},n=t.match(/(([a-z].*?)\(.*?\))(?=\s([a-z].*?)\(.*?\)|\s*$)/g),r="none"!==t?n:"none";if(r instanceof Array)for(var a=0,i=r.length;a>0)/100+"%)":"")+(n.blur||r.blur?"blur("+(100*Q(n.blur,r.blur,a)>>0)/100+"em)":"")+(n.saturate||r.saturate?"saturate("+(100*Q(n.saturate,r.saturate,a)>>0)/100+"%)":"")+(n.invert||r.invert?"invert("+(100*Q(n.invert,r.invert,a)>>0)/100+"%)":"")+(n.grayscale||r.grayscale?"grayscale("+(100*Q(n.grayscale,r.grayscale,a)>>0)/100+"%)":"")+(n.hueRotate||r.hueRotate?"hue-rotate("+(100*Q(n.hueRotate,r.hueRotate,a)>>0)/100+"deg)":"")+(n.sepia||r.sepia?"sepia("+(100*Q(n.sepia,r.sepia,a)>>0)/100+"%)":"")+(n.brightness||r.brightness?"brightness("+(100*Q(n.brightness,r.brightness,a)>>0)/100+"%)":"")+(n.contrast||r.contrast?"contrast("+(100*Q(n.contrast,r.contrast,a)>>0)/100+"%)":"")+(n.dropShadow||r.dropShadow?mt(n.dropShadow,r.dropShadow,a):"")})},crossCheck:function(t){var e=this;this.valuesEnd[t]&&Object.keys(this.valuesStart[t]).forEach((function(n){e.valuesEnd[t][n]||(e.valuesEnd[t][n]=e.valuesStart[t][n])}))}},xt={component:"filterEffects",property:"filter",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:Q,blur:Q,saturate:Q,grayscale:Q,brightness:Q,contrast:Q,sepia:Q,invert:Q,hueRotate:Q,dropShadow:{numbers:Q,colors:lt,dropshadow:mt}},functions:Et,Util:{parseDropShadow:bt,parseFilterString:wt,replaceDashNamespace:yt,trueColor:ct}},St={},kt="htmlAttributes",Tt=["fill","stroke","stop-color"];function Ot(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}var Mt={prepareStart:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(t){var e=Ot(t).replace(/_+[a-z]+/,""),a=n.element.getAttribute(e);r[e]=Tt.includes(e)?a||"rgba(0,0,0,0)":a||(/opacity/i.test(t)?1:0)})),r},prepareProperty:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(a){var o=Ot(a),s=/(%|[a-z]+)$/,u=n.element.getAttribute(o.replace(/_+[a-z]+/,""));if(Tt.includes(o))i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){t.setAttribute(e,lt(n,r,a))})},r[o]=ct(e[a])||f.htmlAttributes[a];else if(null!==u&&s.test(u)){var c=z(u).u||z(e[a]).u,l=/%/.test(c)?"_percent":"_"+c;i.htmlAttributes[o+l]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){var i=e.replace(l,"");t.setAttribute(i,(1e3*Q(n.v,r.v,a)>>0)/1e3+r.u)})},r[o+l]=z(e[a])}else s.test(e[a])&&null!==u&&(null===u||s.test(u))||(i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){t.setAttribute(e,(1e3*Q(n,r,a)>>0)/1e3)})},r[o]=parseFloat(e[a]))})),r},onStart:{attr:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,n,r,a){Object.keys(r).forEach((function(i){e.attributes[i](t,i,n[i],r[i],a)}))})},attributes:function(t){!e[t]&&this.valuesEnd.attr&&(e[t]=St)}}},_t={component:kt,property:"attr",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},Interpolate:{numbers:Q,colors:lt},functions:Mt,Util:{replaceUppercase:Ot,trueColor:ct,trueDimension:z}};var Ct={prepareStart:function(t){return M(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(1e3*Q(n,r,a)>>0)/1e3})}},jt={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:Q},functions:Ct};function It(t,e){return parseFloat(t)/100*e}function At(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Pt(t){var e=t.getAttribute("points").split(" "),n=0;if(e.length>1){var r=function(t){var e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},a=function(t,e){return void 0!==t&&void 0!==e?Math.sqrt(Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)):0};if(e.length>2)for(var i=0;i>0)/100,i=0-(100*Q(e.s,n.s,r)>>0)/100,o=(100*Q(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=i+"px",t.style.strokeDasharray=(100*(o<1?0:o)>>0)/100+"px, "+a+"px"})}},Dt={component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:Q},functions:Ft,Util:{getRectLength:At,getPolyLength:Pt,getLineLength:Lt,getCircleLength:Vt,getEllipseLength:Nt,getTotalLength:Rt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:Ut,percent:It}},Ht={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){var e=t.pathValue[t.segmentStart],n=e.toLowerCase(),r=t.data;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Ht[n]&&(t.segments.push([e].concat(r.splice(0,Ht[n]))),Ht[n]););}var Bt="Invalid path value";function Qt(t){var e=t.index,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=Bt+': invalid Arc flag "'+n+'", expecting 0 or 1 at index '+e)}function zt(t){return t>=48&&t<=57}function Xt(t){var e,n=t.max,r=t.pathValue,a=t.index,i=a,o=!1,s=!1,u=!1,c=!1;if(i>=n)t.err=Bt+" at "+i+": missing param "+r[i];else if(43!==(e=r.charCodeAt(i))&&45!==e||(e=(i+=1)=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0);)t.index+=1}function Wt(t){return t>=48&&t<=57||43===t||45===t||46===t}function $t(t){var e=t.max,n=t.pathValue,r=t.index,a=n.charCodeAt(r),i=Ht[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(a))if(t.index+=1,Yt(t),t.data=[],i){for(;;){for(var o=i;o>0;o-=1){if(97!=(32|a)||3!==o&&4!==o?Xt(t):Qt(t),t.err.length)return;t.data.push(t.param),Yt(t),t.index=t.max)break;if(!Wt(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=Bt+": "+n[r]+" not a path command"}function Gt(t){return t.map((function(t){return Array.isArray(t)?[].concat(t):t}))}function Zt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Kt(t){return Array.isArray(t)&&t.every((function(t){var e=t[0].toLowerCase();return Ht[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Jt(t){if(Kt(t))return Gt(t);var e=new Zt(t);for(Yt(e);e.index7){t[n].shift();for(var r=t[n],a=n;r.length;)e[n]="A",t.splice(a+=1,0,["C"].concat(r.splice(0,6)));t.splice(n,1)}}function re(t,e,n){var r=t[0],a=e.x1,i=e.y1,o=e.x2,s=e.y2,u=t.slice(1).map(Number),c=t;if("TQ".includes(r)||(e.qx=null,e.qy=null),"H"===r)c=["L",t[1],i];else if("V"===r)c=["L",a,t[1]];else if("S"===r){var l=function(t,e,n,r,a){return"CS".includes(a)?{x1:2*t-n,y1:2*e-r}:{x1:t,y1:e}}(a,i,o,s,n),p=l.x1,h=l.y1;e.x1=p,e.y1=h,c=["C",p,h].concat(u)}else if("T"===r){var f=function(t,e,n,r,a){return"QT".includes(a)?{qx:2*t-n,qy:2*e-r}:{qx:t,qy:e}}(a,i,e.qx,e.qy,n),d=f.qx,v=f.qy;e.qx=d,e.qy=v,c=["Q",d,v].concat(u)}else if("Q"===r){var g=u[0],m=u[1];e.qx=g,e.qy=m}return c}var ae={x1:0,y1:0,x2:0,y2:0,x:0,y:0,qx:null,qy:null};function ie(t){if(function(t){return te(t)&&t.every((function(t){return"ACLMQZ".includes(t[0])}))}(t))return Gt(t);for(var e=ee(t),n=Object.assign({},ae),r=[],a=e.length,i="",o="",s=0;s1&&(y*=M=Math.sqrt(M),b*=M);var _=y*y,C=b*b,j=(i===o?-1:1)*Math.sqrt(Math.abs((_*C-_*O*O-C*T*T)/(_*O*O+C*T*T)));d=j*y*O/b+(g+w)/2,v=j*-b*T/y+(m+E)/2,h=(Math.asin((m-v)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),f=(Math.asin((E-v)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),h=gf&&(h-=2*Math.PI),!o&&f>h&&(f-=2*Math.PI)}var I=f-h;if(Math.abs(I)>x){var A=f,P=w,L=E;f=h+x*(o&&f>h?1:-1),k=ue(w=d+y*Math.cos(f),E=v+b*Math.sin(f),y,b,a,0,o,P,L,[f,A,d,v])}I=f-h;var V=Math.cos(h),N=Math.sin(h),R=Math.cos(f),U=Math.sin(f),F=Math.tan(I/4),D=4/3*y*F,H=4/3*b*F,q=[g,m],B=[g+D*N,m-H*V],Q=[w+D*U,E-H*R],z=[w,E];if(B[0]=2*q[0]-B[0],B[1]=2*q[1]-B[1],c)return B.concat(Q,z,k);for(var X=[],Y=0,W=(k=B.concat(Q,z,k)).length;Yi+.001)return{x:n,y:r};var o=le([t,e],[n,r],a/i);return{x:o[0],y:o[1]}}return i}function fe(t,e,n,r){var a=.5,i=[t,e],o=[n,r],s=le(i,o,a),u=le(o,s,a),c=le(s,u,a),l=le(u,c,a),p=le(c,l,a),h=i.concat(s,c,p,[a]),f=he.apply(void 0,h),d=p.concat(l,u,o,[0]),v=he.apply(void 0,d);return[f.x,f.y,v.x,v.y,n,r]}function de(t,e){var n,r=t[0],a=t.slice(1).map((function(t){return+t})),i=a[0],o=a[1],s=e.x1,u=e.y1,c=e.x,l=e.y;switch("TQ".includes(r)||(e.qx=null,e.qy=null),r){case"M":return e.x=i,e.y=o,t;case"A":return n=[s,u].concat(a),["C"].concat(ue.apply(void 0,n));case"Q":return e.qx=i,e.qy=o,n=[s,u].concat(a),["C"].concat(ce.apply(void 0,n));case"L":return["C"].concat(fe(s,u,i,o));case"Z":return["C"].concat(fe(s,u,c,l))}return t}function ve(t){if(function(t){return Kt(t)&&t.every((function(t){return"MC".includes(t[0])}))}(t))return Gt(t);for(var e=oe(ie(t)),n=Object.assign({},ae),r=[],a="",i=e.length,o=0;o=1?e:n)>=1?Math.pow(10,n):1;return t.map((function(t){var e=t.slice(1).map(Number).map((function(t){return t%1==0?t:Math.round(t*r)/r}));return[t[0]].concat(e)}))}(t,e).map((function(t){return t[0]+t.slice(1).join(" ")})).join("")}function ye(t){var e=t.slice(1).map((function(e,n,r){return n?r[n-1].slice(-2).concat(e.slice(1)):t[0].slice(1).concat(e.slice(1))})).map((function(t){return t.map((function(e,n){return t[t.length-n-2*(1-n%2)]}))})).reverse();return[["M"].concat(e[0].slice(0,2))].concat(e.map((function(t){return["C"].concat(t.slice(2))})))}function be(t,e,n,r,a,i,o,s){return 3*((s-e)*(n+a)-(o-t)*(r+i)+r*(t-a)-n*(e-i)+s*(a+t/3)-o*(i+e/3))/20}function we(t){return function(t){var e=0,n=0,r=0;return ve(t).map((function(t){var a,i;return"M"===t[0]?(e=(a=t)[1],n=a[2],0):(r=be.apply(void 0,[e,n].concat(t.slice(1))),i=t.slice(-2),e=i[0],n=i[1],r)})).reduce((function(t,e){return t+e}),0)}(ve(t))>=0}function Ee(t){var e=.5,n=t.slice(0,2),r=t.slice(2,4),a=t.slice(4,6),i=t.slice(6,8),o=le(n,r,e),s=le(r,a,e),u=le(a,i,e),c=le(o,s,e),l=le(s,u,e),p=le(c,l,e);return[["C"].concat(o,c,p),["C"].concat(l,u,i)]}function xe(t){return me(ee(t),0).replace(/(m|M)/g,"|$1").split("|").map((function(t){return t.trim()})).filter((function(t){return t}))}function Se(t,e,n,r,a,i,o,s,u){var c=1-u;return{x:Math.pow(c,3)*t+3*Math.pow(c,2)*u*n+3*c*Math.pow(u,2)*a+Math.pow(u,3)*o,y:Math.pow(c,3)*e+3*Math.pow(c,2)*u*r+3*c*Math.pow(u,2)*i+Math.pow(u,3)*s}}function ke(t,e,n,r,a,i,o,s,u){var c,l=t,p=e,h=0,f=[t,e,h],d=[t,e];if("number"==typeof u&&u<.001)return{x:l,y:p};for(var v=0;v<=100;v+=1){if(h+=pe(d,[l=(c=Se(t,e,n,r,a,i,o,s,v/100)).x,p=c.y]),d=[l,p],"number"==typeof u&&h>=u){var g=(h-u)/(h-f[2]);return{x:d[0]*(1-g)+f[0]*g,y:d[1]*(1-g)+f[1]*g}}f=[l,p,h]}return"number"==typeof u&&u>=h?{x:o,y:s}:h}function Te(t){return ve(xe(t)[0]).map((function(t,e,n){var r=e&&n[e-1].slice(-2).concat(t.slice(1)),a=e?ke.apply(void 0,r):0;return{s:t,ss:e?a?Ee(r):[t,t]:[t],l:a}}))}function Oe(t,e,n){var r=Te(t),a=Te(e),i=r.length,o=a.length,s=r.filter((function(t){return t.l})).length,u=a.filter((function(t){return t.l})).length,c=r.filter((function(t){return t.l})).reduce((function(t,e){return t+e.l}),0)/s||0,l=a.filter((function(t){return t.l})).reduce((function(t,e){return t+e.l}),0)/u||0,p=n||Math.max(i,o),h=[c,l],f=[p-i,p-o],d=0,v=[r,a].map((function(t,e){return t.l===p?t.map((function(t){return t.s})):t.map((function(t,n){return d=n&&f[e]&&t.l>=h[e],f[e]-=d?1:0,d?t.ss:[t.s]})).flat()}));return v[0].length===v[1].length?v:Oe(v[0],v[1],p)}function Me(t){var e=t.length,n=e-1;return t.map((function(r,a){return t.map((function(r,i){var o,s=a+i;return 0===i||t[s]&&"M"===t[s][0]?(o=t[s],["M"].concat(o.slice(-2))):(s>=e&&(s-=n),t[s])}))}))}function _e(t,e){var n=t.length-1,r=[],a=0,i=Me(t);return i.forEach((function(i,o){t.slice(1).forEach((function(r,i){a+=pe(t[(o+i)%n].slice(-2),e[i%n].slice(-2))})),r[o]=a,a=0})),i[r.indexOf(Math.min.apply(null,r))]}var Ce={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){var n={},r=new RegExp("\\n","ig"),a=null;return e instanceof SVGElement?a=e:/^\.|^#/.test(e)&&(a=P(e)),"object"==typeof e&&e.curve?e:(a&&/path|glyph/.test(a.tagName)?n.original=a.getAttribute("d").replace(r,""):a||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,e,n,r){for(var a=[],i=e.curve,o=n.curve,s=0,u=o.length;s>0)/1e3)}t.setAttribute("d",1===r?n.original:me(a))})},crossCheck:function(t){if(this.valuesEnd[t]){var e=this.valuesStart[t].curve,n=this.valuesEnd[t].curve;if(!e||!n||e&&n&&"M"===e[0][0]&&e.length!==n.length){var r=Oe(this.valuesStart[t].original,this.valuesEnd[t].original),a=we(r[0])!==we(r[1])?ye(r[0]):Gt(r[0]);this.valuesStart[t].curve=a,this.valuesEnd[t].curve=_e(r[1],a)}}}},je={component:"svgCubicMorph",property:"path",defaultValue:[],Interpolate:{numbers:Q,pathToString:me},functions:Ce,Util:{pathToCurve:ve,pathToAbsolute:ee,pathToString:me,parsePathString:Jt,getRotatedCurve:_e,getRotations:Me,equalizeSegments:Oe,reverseCurve:ye,clonePath:Gt,getDrawDirection:we,segmentCubicFactory:ke,splitCubic:Ee,splitPath:xe,fixPath:oe,getCurveArray:Te}};function Ie(t,e){var n=e.x,r=e.width;return/[a-z]/i.test(t)&&!/px/.test(t)?t.replace(/top|left/,0).replace(/right|bottom/,100).replace(/center|middle/,50):/%/.test(t)?n+parseFloat(t)*r/100:parseFloat(t)}function Ae(t){var e={},n=t&&/\)/.test(t)?t.substring(0,t.length-1).split(/\)\s|\)/):"none";if(n instanceof Array)for(var r=0,a=n.length;r>0)/1e3+(i?","+(1e3*i>>0)/1e3:"")+")":"")+(u?"rotate("+(1e3*u>>0)/1e3+")":"")+(p?"skewX("+(1e3*p>>0)/1e3+")":"")+(h?"skewY("+(1e3*h>>0)/1e3+")":"")+(1!==s?"scale("+(1e3*s>>0)/1e3+")":""))})},crossCheck:function(t){if(this._resetStart&&this.valuesEnd[t]){var e=this.valuesStart[t],n=this.valuesEnd[t],r=Pe.call(this,t,Ae(this.element.getAttribute("transform")));Object.keys(r).forEach((function(t){e[t]=r[t]}));var a=this.element.ownerSVGElement,i=a.createSVGTransformFromMatrix(a.createSVGMatrix().translate(-e.origin[0],-e.origin[1]).translate("translate"in e?e.translate[0]:0,"translate"in e?e.translate[1]:0).rotate(e.rotate||0).skewX(e.skewX||0).skewY(e.skewY||0).scale(e.scale||1).translate(+e.origin[0],+e.origin[1]));e.translate=[i.matrix.e,i.matrix.f],Object.keys(e).forEach((function(t){t in n&&"origin"!==t||(n[t]=e[t])}))}}},Ve={component:"svgTransformProperty",property:"svgTransform",defaultOptions:{transformOrigin:"50% 50%"},defaultValue:{translate:0,rotate:0,skewX:0,skewY:0,scale:1},Interpolate:{numbers:Q},functions:Le,Util:{parseStringOrigin:Ie,parseTransformString:Ae,parseTransformSVG:Pe}},Ne=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){return t=!0}});document.addEventListener("DOMContentLoaded",(function t(){document.removeEventListener("DOMContentLoaded",t,e)}),e)}catch(t){throw Error("Passive events are not supported")}return t}()&&{passive:!0},Re="onmouseleave"in document?["mouseenter","mouseleave"]:["mouseover","mouseout"],Ue="ontouchstart"in window||"msMaxTouchPoints"in navigator?"touchstart":"mousewheel",Fe=navigator&&/(EDGE|Mac)/i.test(navigator.userAgent)?document.body:document.documentElement;function De(t){this.scrolling&&t.preventDefault()}function He(){var t=this.element;return t===Fe?{el:document,st:document.body}:{el:t,st:t}}function qe(t,e){e[t](Re[0],De,Ne),e[t](Ue,De,Ne)}function Be(){var t=He.call(this);"scroll"in this.valuesEnd&&!t.el.scrolling&&(t.el.scrolling=1,qe("addEventListener",t.el),t.st.style.pointerEvents="none")}function Qe(){var t=He.call(this);"scroll"in this.valuesEnd&&t.el.scrolling&&(t.el.scrolling=0,qe("removeEventListener",t.el),t.st.style.pointerEvents="")}var ze={prepareStart:function(){return this.element=!("scroll"in this.valuesEnd)||this.element&&this.element!==window?this.element:Fe,this.element===Fe?window.pageYOffset||Fe.scrollTop:this.element.scrollTop},prepareProperty:function(t,e){return parseInt(e,10)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(this.element=!("scroll"in this.valuesEnd)||this.element&&this.element!==window?this.element:Fe,Be.call(this),e[t]=function(t,e,n,r){t.scrollTop=Q(e,n,r)>>0})},onComplete:function(){Qe.call(this)}},Xe={component:"scrollProperty",property:"scroll",defaultValue:0,Interpolate:{numbers:Q},functions:ze,Util:{preventScroll:De,scrollIn:Be,scrollOut:Qe,getScrollTargets:He,toggleScrollEvents:qe}};function Ye(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){for(var i=[],o="textShadow"===t?3:4,s=3===o?n[3]:n[4],u=3===o?r[3]:r[4],c=!!(n[5]&&"none"!==n[5]||r[5]&&"none"!==r[5])&&" inset",l=0;l>0)/1e3+"px");e.style[t]=c?lt(s,u,a)+i.join(" ")+c:lt(s,u,a)+i.join(" ")})}var We={};["boxShadow","textShadow"].forEach((function(t){We[t]=Ye}));var $e=["boxShadow","textShadow"];function Ge(t,e){var n;3===t.length?n=[t[0],t[1],0,0,t[2],"none"]:4===t.length?n=/inset|none/.test(t[3])?[t[0],t[1],0,0,t[2],t[3]]:[t[0],t[1],t[2],0,t[3],"none"]:5===t.length?n=/inset|none/.test(t[4])?[t[0],t[1],t[2],0,t[3],t[4]]:[t[0],t[1],t[2],t[3],t[4],"none"]:6===t.length&&(n=t);for(var r=0;r<4;r+=1)n[r]=parseFloat(n[r]);return n[4]=ct(n[4]),n="boxShadow"===e?n:n.filter((function(t,e){return[0,1,2,4].includes(e)})),n}var Ze={};$e.forEach((function(t){Ze[t]=Ye}));var Ke={component:"shadowProperties",properties:$e,defaultValues:{boxShadow:"0px 0px 0px 0px rgb(0,0,0)",textShadow:"0px 0px 0px rgb(0,0,0)"},Interpolate:{numbers:Q,colors:lt},functions:{prepareStart:function(t){var e=M(this.element,t);return/^none$|^initial$|^inherit$|^inset$/.test(e)?f[t]:e},prepareProperty:function(t,e){var n=e;if("string"==typeof n){var r="none",a=n.match(/(\s?(?:#(?:[\da-f]{3}){1,2}|rgba?\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\))\s?)/gi);r=/inset/.test(n)?"inset":r,n=Ge(n=(n=/inset/.test(n)?n.replace(/(\s+inset|inset+\s)/g,""):n).replace(a[0],"").split(" ").concat([a[0].replace(/\s/g,"")],[r]),t)}else n instanceof Array&&(n=Ge(n,t));return n},onStart:Ze},Util:{processShadowArray:Ge,trueColor:ct}},Je={};function tn(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=W(n.v,r.v,r.u,a)})}["fontSize","lineHeight","letterSpacing","wordSpacing"].forEach((function(t){Je[t]=tn}));var en=["fontSize","lineHeight","letterSpacing","wordSpacing"],nn={};en.forEach((function(t){nn[t]=tn}));var rn={component:"textProperties",category:"textProperties",properties:en,defaultValues:{fontSize:0,lineHeight:0,letterSpacing:0,wordSpacing:0},Interpolate:{units:W},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return z(e)},onStart:nn},Util:{trueDimension:z}},an=String("abcdefghijklmnopqrstuvwxyz").split(""),on=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),sn=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),un=String("0123456789").split(""),cn=an.concat(on,un),ln=cn.concat(sn),pn={alpha:an,upper:on,symbols:sn,numeric:un,alphanumeric:cn,all:ln},hn={text:function(t){if(!e[t]&&this.valuesEnd[t]){var n=this._textChars,r=pn[d.textChars];n in pn?r=pn[n]:n&&n.length&&(r=n),e[t]=function(t,e,n,a){var i="",o="",s=""===n?" ":n,u=e.substring(0),c=n.substring(0),l=r[Math.random()*r.length>>0];" "===e?(o=c.substring(Math.min(a*c.length,c.length)>>0,0),t.innerHTML=a<1?o+l:s):" "===n?(i=u.substring(0,Math.min((1-a)*u.length,u.length)>>0),t.innerHTML=a<1?i+l:s):(i=u.substring(u.length,Math.min(a*u.length,u.length)>>0),o=c.substring(0,Math.min(a*c.length,c.length)>>0),t.innerHTML=a<1?o+l+i:s)}}},number:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(t,e,n,r){t.innerHTML=Q(e,n,r)>>0})}};function fn(t,e){var n,r;if("string"==typeof t)return(r=document.createElement("SPAN")).innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){var a=t.innerHTML;(n=document.createElement("SPAN")).className=e,n.innerHTML=a,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&(n=t.children[0]);return n}function dn(t,e){var n=[],r=t.children.length;if(r){for(var a,i=[],o=t.innerHTML,s=0,u=void 0,c=void 0,l=void 0;s>0)/1e3;return r}var gn="undefined"!=typeof DOMMatrix?DOMMatrix:null,mn="transformMatrix";var yn={BackgroundPosition:Y,BorderRadius:tt,BoxModel:ot,ClipProperty:ut,ColorProperties:gt,FilterEffects:xt,HTMLAttributes:_t,OpacityProperty:jt,SVGDraw:Dt,SVGCubicMorph:je,SVGTransform:Ve,ScrollProperty:Xe,ShadowProperties:Ke,TextProperties:rn,TextWriteProperties:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:Q},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:hn},Util:{charSet:pn,createTextTweens:function(t,e,n){if(t.playing)return!1;var r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);var a=I.tween,i=function(t,e){var n=dn(t,"text-part"),r=dn(fn(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((function(t){return t.className+=" oldText",t.outerHTML})).join(""),t.innerHTML+=r.map((function(t){return t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")})).join(""),[n,r]}(t,e),o=i[0],s=i[1],u=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText")),l=[],p=0;return(l=(l=l.concat(u.map((function(t,e){return r.duration="auto"===r.duration?75*o[e].innerHTML.length:r.duration,r.delay=p,r.onComplete=null,p+=r.duration,new a(t,{text:t.innerHTML},{text:""},r)})))).concat(c.map((function(n,i){return r.duration="auto"===r.duration?75*s[i].innerHTML.length:r.duration,r.delay=p,r.onComplete=i===s.length-1?function(){t.innerHTML=e,t.playing=!1}:null,p+=r.duration,new a(n,{text:""},{text:s[i].innerHTML},r)})))).start=function(){t.playing||(l.forEach((function(t){return t.start()})),t.playing=!0)},l}}},MatrixTransform:{component:mn,property:"transform",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:{prepareStart:function(t,e){var n={},r=this.element.transformMatrix;return r?Object.keys(r).forEach((function(t){n[t]=r[t]})):Object.keys(e).forEach((function(t){n[t]="perspective"===t?e[t]:f.transform[t]})),n},prepareProperty:function(t,e){if("object"==typeof e&&!e.length){var n,r={},a={},i={},o={},s={},u=[{translate3d:a},{rotate3d:i},{skew:s},{scale3d:o}];return Object.keys(e).forEach((function(t){if(/3d/.test(t)&&"object"==typeof e[t]&&e[t].length)n=e[t].map((function(e){return"scale3d"===t?parseFloat(e):parseInt(e,10)})),r[t]="scale3d"===t?[n[0]||1,n[1]||1,n[2]||1]:[n[0]||0,n[1]||0,n[2]||0];else if(/[XYZ]/.test(t)){var u={};/translate/.test(t)?u=a:/rotate/.test(t)?u=i:/scale/.test(t)?u=o:/skew/.test(t)&&(u=s),u[t.replace(/translate|rotate|scale|skew/,"").toLowerCase()]=/scale/.test(t)?parseFloat(e[t]):parseInt(e[t],10)}else"skew"===t?(n=e[t].map((function(t){return parseInt(t,10)||0})),r[t]=[n[0]||0,n[1]||0]):r[t]=parseInt(e[t],10)})),u.forEach((function(t){var e=Object.keys(t)[0],n=t[e];Object.keys(n).length&&!r[e]&&(r[e]="scale3d"===e?[n.x||1,n.y||1,n.z||1]:"skew"===e?[n.x||0,n.y||0]:[n.x||0,n.y||0,n.z||0])})),r}throw Error('KUTE.js - "'+e+'" is not valid/supported transform function')},onStart:{transform:function(t){gn&&this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){var i=new gn,o={};Object.keys(r).forEach((function(t){o[t]="perspective"===t?Q(n[t],r[t],a):vn(n[t],r[t],a)})),o.perspective&&(i.m34=-1/o.perspective),i=o.translate3d?i.translate(o.translate3d[0],o.translate3d[1],o.translate3d[2]):i,i=o.rotate3d?i.rotate(o.rotate3d[0],o.rotate3d[1],o.rotate3d[2]):i,o.skew&&(i=o.skew[0]?i.skewX(o.skew[0]):i,i=o.skew[1]?i.skewY(o.skew[1]):i),i=o.scale3d?i.scale(o.scale3d[0],o.scale3d[1],o.scale3d[2]):i,e.style[t]=i.toString()})},CSS3Matrix:function(t){gn&&this.valuesEnd.transform&&(e[t]||(e[t]=gn))}},onComplete:function(t){this.valuesEnd[t]&&(this.element.transformMatrix=Object.assign({},this.valuesEnd[t]))},crossCheck:function(t){this.valuesEnd[t]&&this.valuesEnd[t].perspective&&!this.valuesStart[t].perspective&&(this.valuesStart[t].perspective=this.valuesEnd[t].perspective)}},Interpolate:{perspective:Q,translate3d:vn,rotate3d:vn,skew:vn,scale3d:vn}}};Object.keys(yn).forEach((function(t){var e=yn[t];yn[t]=new B(e)}));return{Animation:B,Components:yn,Tween:R,fromTo:function(t,e,n,r){var a=r||{};return new H(P(t),e,n,a)},to:function(t,e,n){var r=n||{};return r.resetStart=e,new D(P(t),e,e,r)},TweenCollection:U,ProgressBar:F,allFromTo:function(t,e,n,r){var a=r||{};return new U(P(t,!0),e,n,a)},allTo:function(t,e,n){var r=n||{};return r.resetStart=e,new U(P(t,!0),e,e,r)},Objects:w,Util:E,Easing:A,CubicBezier:t,Render:p,Interpolate:a,Process:j,Internals:T,Selector:P,Version:"2.2.2"}})); +// KUTE.js Extra v2.2.3 | thednp © 2021 | MIT-License +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t=function(t,e,n,r,a){var i=this;this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by;var o=function(t){return i.sampleCurveY(i.solveCurveX(t))};return Object.defineProperty(o,"name",{writable:!0}),o.name=a||"cubic-bezier("+[t,e,n,r]+")",o};t.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},t.prototype.sampleCurveY=function(t){return((this.ay*t+this.by)*t+this.cy)*t},t.prototype.sampleCurveDerivativeX=function(t){return(3*this.ax*t+2*this.bx)*t+this.cx},t.prototype.solveCurveX=function(t){var e,n,r,a,i,o,s=1e-5;for(r=t,o=0;o<32;o+=1){if(a=this.sampleCurveX(r)-t,Math.abs(a)(n=1))return n;for(;ea?e=r:n=r,r=.5*(n-e)+e}return r};Object.assign(t,{Version:"1.0.18"});var e={},n=[],r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},a={},i={},o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},s={};s.now=o;var u=0,c=function(t){for(var e=0;e1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},I.tween=V;var N=function(t){function n(){for(var e=this,n=[],r=arguments.length;r--;)n[r]=arguments[r];t.apply(this,n),this.valuesStart={},this.valuesEnd={};var a=n.slice(1),i=a[0],o=a[1],s=a[2];return _.call(this,o,"end"),this._resetStart?this.valuesStart=i:_.call(this,i,"start"),this._resetStart||Object.keys(m).forEach((function(t){Object.keys(m[t]).forEach((function(n){m[t][n].call(e,n)}))})),this.paused=!1,this._pauseTime=null,this._repeat=s.repeat||d.repeat,this._repeatDelay=s.repeatDelay||d.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=s.yoyo||d.yoyo,this._reversed=!1,this}return t&&(n.__proto__=t),n.prototype=Object.create(t&&t.prototype),n.prototype.constructor=n,n.prototype.start=function(e){var n=this;return this._resetStart&&(this.valuesStart=this._resetStart,C.call(this),Object.keys(m).forEach((function(t){Object.keys(m[t]).forEach((function(e){m[t][e].call(n,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((function(t){n.valuesRepeat[t]=n.valuesStart[t]})),t.prototype.start.call(this,e),this},n.prototype.stop=function(){return t.prototype.stop.call(this),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this},n.prototype.close=function(){return t.prototype.close.call(this),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this},n.prototype.resume=function(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),L.call(this),this._startTime+=e.Time()-this._pauseTime,x(this),u||c()),this},n.prototype.pause=function(){return!this.paused&&this.playing&&(S(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this},n.prototype.reverse=function(){var t=this;Object.keys(this.valuesEnd).forEach((function(e){var n=t.valuesRepeat[e];t.valuesRepeat[e]=t.valuesEnd[e],t.valuesEnd[e]=n,t.valuesStart[e]=t.valuesRepeat[e]}))},n.prototype.update=function(t){var n,r=this,a=void 0!==t?t:e.Time();if(a1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=a,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.start()})),!1))},n}(V);I.tween=N;var R=function(t){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];return t.apply(this,e),this}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.on=function(t,e){return["start","stop","update","complete","pause","resume"].indexOf(t)>-1&&(this["_on"+(t.charAt(0).toUpperCase()+t.slice(1))]=e),this},e.prototype.option=function(t,e){return this["_"+t]=e,this},e}(N);I.tween=R;var U=function(t,e,n,r){var a=this,i=I.tween;this.tweens=[];var o=r||{};o.delay=o.delay||d.delay;var s=[];return Array.from(t).forEach((function(t,r){if(s[r]=o||{},s[r].delay=r>0?o.delay+(o.offset||d.offset):o.delay,!(t instanceof Element))throw Error("KUTE - "+t+" is not instanceof Element");a.tweens.push(new i(t,e,n,s[r]))})),this.length=this.tweens.length,this};U.prototype.start=function(t){var n=void 0===t?e.Time():t;return this.tweens.map((function(t){return t.start(n)})),this},U.prototype.stop=function(){return this.tweens.map((function(t){return t.stop()})),this},U.prototype.pause=function(){return this.tweens.map((function(t){return t.pause()})),this},U.prototype.resume=function(){return this.tweens.map((function(t){return t.resume()})),this},U.prototype.chain=function(t){var e=this.tweens[this.length-1];if(t instanceof U)e.chain(t.tweens);else{if(!(t instanceof I.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this},U.prototype.playing=function(){return this.tweens.some((function(t){return t.playing}))},U.prototype.removeTweens=function(){this.tweens=[]},U.prototype.getMaxDuration=function(){var t=[];return this.tweens.forEach((function(e){t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)};var F=function(t,e){var n;if(this.element=P(t),this.element.tween=e,this.element.tween.toolbar=this.element,this.element.toolbar=this,n=this.element.parentNode.getElementsByTagName("OUTPUT"),this.element.output=n[0],!(this.element instanceof HTMLInputElement))throw TypeError("Target element is not [HTMLInputElement]");if("range"!==this.element.type)throw TypeError("Target element is not a range input");if(!(e instanceof I.tween))throw TypeError("tween parameter is not ["+I.tween+"]");this.element.setAttribute("value",0),this.element.setAttribute("min",0),this.element.setAttribute("max",1),this.element.setAttribute("step",1e-4),this.element.tween._onUpdate=this.updateBar,this.element.addEventListener("mousedown",this.downAction,!1)};F.prototype.updateBar=function(){var t,n=this.toolbar.output;(t=this.paused?this.toolbar.value:(e.Time()-this._startTime)/this._duration)>.9999&&(t=1),t<.01&&(t=0);var r=this._reversed?1-t:t;this.toolbar.value=r,n&&(n.value=(1e4*r>>0)/100+"%")},F.prototype.toggleEvents=function(t){this.element[t+"EventListener"]("mousemove",this.moveAction,!1),this.element[t+"EventListener"]("mouseup",this.upAction,!1)},F.prototype.updateTween=function(){var t=(this.tween._reversed?1-this.value:this.value)*this.tween._duration-1e-4;this.tween._startTime=0,this.tween.update(t)},F.prototype.moveAction=function(){this.toolbar.updateTween.call(this)},F.prototype.downAction=function(){this.tween.playing||this.tween.start(),this.tween.paused||(this.tween.pause(),this.toolbar.toggleEvents("add"),e.Tick=cancelAnimationFrame(e.Ticker))},F.prototype.upAction=function(){this.tween.paused&&(this.tween.paused&&this.tween.resume(),this.tween._startTime=e.Time()-(this.tween._reversed?1-this.value:this.value)*this.tween._duration,this.toolbar.toggleEvents("remove"),e.Tick=requestAnimationFrame(e.Ticker))};var D=I.tween;var H=I.tween;var q=function(t){try{if(t.component in h)throw Error("KUTE - "+t.component+" already registered");if(t.property in f)throw Error("KUTE - "+t.property+" already registered")}catch(t){throw Error(t)}var e=this,n=t.component,r={prepareProperty:v,prepareStart:g,onStart:i,onComplete:y,crossCheck:m},o=t.category,s=t.property,u=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return h[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(f[s]=t.defaultValue,e.supports=s+" property"):t.defaultValues&&(Object.keys(t.defaultValues).forEach((function(e){f[e]=t.defaultValues[e]})),e.supports=(u||s)+" "+(s||o)+" properties"),t.defaultOptions&&Object.assign(d,t.defaultOptions),t.functions&&Object.keys(r).forEach((function(e){e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][o||s]||(r[e][n][o||s]=t.functions[e])):Object.keys(t.functions[e]).forEach((function(a){r[e][n]||(r[e][n]={}),r[e][n][a]||(r[e][n][a]=t.functions[e][a])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((function(e){var n=t.Interpolate[e];"function"!=typeof n||a[e]?Object.keys(n).forEach((function(t){"function"!=typeof n[t]||a[e]||(a[e]=n[t])})):a[e]=n})),b[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((function(e){E[e]||(E[e]=t.Util[e])})),e},B=function(t){function e(e){t.call(this,e);var n=this,r={prepareProperty:v,prepareStart:g,onStart:i,onComplete:y,crossCheck:m},o=e.category,s=e.property,u=e.properties&&e.properties.length||e.subProperties&&e.subProperties.length;return"defaultValue"in e?(n.supports=s+" property",n.defaultValue=(""+e.defaultValue).length?"YES":"not set or incorrect"):e.defaultValues&&(n.supports=(u||s)+" "+(s||o)+" properties",n.defaultValues=Object.keys(e.defaultValues).length===u?"YES":"Not set or incomplete"),e.defaultOptions&&(n.extends=[],Object.keys(e.defaultOptions).forEach((function(t){n.extends.push(t)})),n.extends.length?n.extends="with <"+n.extends.join(", ")+"> new option(s)":delete n.extends),e.functions&&(n.interface=[],n.render=[],n.warning=[],Object.keys(r).forEach((function(t){t in e.functions?("prepareProperty"===t&&n.interface.push("fromTo()"),"prepareStart"===t&&n.interface.push("to()"),"onStart"===t&&(n.render="can render update")):("prepareProperty"===t&&n.warning.push("fromTo()"),"prepareStart"===t&&n.warning.push("to()"),"onStart"===t&&(n.render="no function to render update"))})),n.interface.length?n.interface=(o||s)+" can use ["+n.interface.join(", ")+"] method(s)":delete n.uses,n.warning.length?n.warning=(o||s)+" can't use ["+n.warning.join(", ")+"] method(s) because values aren't processed":delete n.warning),e.Interpolate?(n.uses=[],n.adds=[],Object.keys(e.Interpolate).forEach((function(t){var r=e.Interpolate[t];"function"==typeof r?(a[t]||n.adds.push(""+t),n.uses.push(""+t)):Object.keys(r).forEach((function(e){"function"!=typeof r[e]||a[t]||n.adds.push(""+e),n.uses.push(""+e)}))})),n.uses.length?n.uses="["+n.uses.join(", ")+"] interpolation function(s)":delete n.uses,n.adds.length?n.adds="new ["+n.adds.join(", ")+"] interpolation function(s)":delete n.adds):n.critical="For "+(s||o)+" no interpolation function[s] is set",e.Util&&(n.hasUtil=Object.keys(e.Util).join(",")),n}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(q);function Q(t,e,n){return+t+(e-t)*n}var z=function(t,e){for(var n,r=parseInt(t,10)||0,a=["px","%","deg","rad","em","rem","vh","vw"],i=0;i>0)/100+"% "+(100*Q(n[1],r[1],a)>>0)/100+"%"})}},Y={component:"backgroundPositionProp",property:"backgroundPosition",defaultValue:[50,50],Interpolate:{numbers:Q},functions:X,Util:{trueDimension:z}};function W(t,e,n,r){return+t+(e-t)*r+n}function $(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=W(n.v,r.v,r.u,a)})}var G={};["borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius"].forEach((function(t){G[t]=$}));var Z=["borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","borderBottomRightRadius"],K={};Z.forEach((function(t){K[t]=0}));var J={};Z.forEach((function(t){J[t]=$}));var tt={component:"borderRadiusProperties",category:"borderRadius",properties:Z,defaultValues:K,Interpolate:{units:W},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return z(e)},onStart:J},Util:{trueDimension:z}};function et(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(a>.99||a<.01?(10*Q(n,r,a)>>0)/10:Q(n,r,a)>>0)+"px"})}var nt={};["top","left","width","height"].forEach((function(t){nt[t]=et}));var rt=["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"],at={};rt.forEach((function(t){at[t]=0}));var it={};rt.forEach((function(t){it[t]=et}));var ot={component:"boxModelProperties",category:"boxModel",properties:rt,defaultValues:at,Interpolate:{numbers:Q},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){var n=z(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:it}};var st={prepareStart:function(t){var e=this.element,n=M(e,t),r=M(e,"width"),a=M(e,"height");return/rect/.test(n)?n:[0,r,a,0]},prepareProperty:function(t,e){if(e instanceof Array)return e.map((function(t){return z(t)}));var n=e.replace(/rect|\(|\)/g,"");return(n=/,/g.test(n)?n.split(","):n.split(/\s/)).map((function(t){return z(t)}))},onStart:function(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(t,e,n,r){for(var a=0,i=[];a<4;a+=1){var o=e[a].v,s=n[a].v,u=n[a].u||"px";i[a]=(100*Q(o,s,r)>>0)/100+u}t.style.clip="rect("+i+")"})}},ut={component:"clipProperty",property:"clip",defaultValue:[0,0,0,0],Interpolate:{numbers:Q},functions:st,Util:{trueDimension:z}},ct=function(t){var e;if(/rgb|rgba/.test(t)){var n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){var a=function(t){var e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,n,r){return e+e+n+n+r+r})),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}(t);e={r:a.r,g:a.g,b:a.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){var i=document.getElementsByTagName("head")[0];i.style.color=t;var o=getComputedStyle(i,null).color;o=/rgb/.test(o)?o.replace(/[^\d,]/g,"").split(","):[0,0,0],i.style.color="",e={r:parseInt(o[0],10),g:parseInt(o[1],10),b:parseInt(o[2],10)}}return e};function lt(t,e,n){var r={},a=",";return Object.keys(e).forEach((function(a){"a"!==a?r[a]=Q(t[a],e[a],n)>>0||0:t[a]&&e[a]&&(r[a]=(100*Q(t[a],e[a],n)>>0)/100)})),r.a?"rgba("+r.r+a+r.g+a+r.b+a+r.a+")":"rgb("+r.r+a+r.g+a+r.b+")"}function pt(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=lt(n,r,a)})}var ht={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((function(t){ht[t]=pt}));var ft=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],dt={};ft.forEach((function(t){dt[t]="#000"}));var vt={};ft.forEach((function(t){vt[t]=pt}));var gt={component:"colorProperties",category:"colors",properties:ft,defaultValues:dt,Interpolate:{numbers:Q,colors:lt},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return ct(e)},onStart:vt},Util:{trueColor:ct}};function mt(t,e,n){for(var r=[],a=0;a<3;a+=1)r[a]=(100*Q(t[a],e[a],n)>>0)/100+"px";return"drop-shadow("+r.concat(lt(t[3],e[3],n)).join(" ")+")"}function yt(t){return t.replace("-r","R").replace("-s","S")}function bt(t){var e;3===t.length?e=[t[0],t[1],0,t[2]]:4===t.length&&(e=[t[0],t[1],t[2],t[3]]);for(var n=0;n<3;n+=1)e[n]=parseFloat(e[n]);return e[3]=ct(e[3]),e}function wt(t){var e={},n=t.match(/(([a-z].*?)\(.*?\))(?=\s([a-z].*?)\(.*?\)|\s*$)/g),r="none"!==t?n:"none";if(r instanceof Array)for(var a=0,i=r.length;a>0)/100+"%)":"")+(n.blur||r.blur?"blur("+(100*Q(n.blur,r.blur,a)>>0)/100+"em)":"")+(n.saturate||r.saturate?"saturate("+(100*Q(n.saturate,r.saturate,a)>>0)/100+"%)":"")+(n.invert||r.invert?"invert("+(100*Q(n.invert,r.invert,a)>>0)/100+"%)":"")+(n.grayscale||r.grayscale?"grayscale("+(100*Q(n.grayscale,r.grayscale,a)>>0)/100+"%)":"")+(n.hueRotate||r.hueRotate?"hue-rotate("+(100*Q(n.hueRotate,r.hueRotate,a)>>0)/100+"deg)":"")+(n.sepia||r.sepia?"sepia("+(100*Q(n.sepia,r.sepia,a)>>0)/100+"%)":"")+(n.brightness||r.brightness?"brightness("+(100*Q(n.brightness,r.brightness,a)>>0)/100+"%)":"")+(n.contrast||r.contrast?"contrast("+(100*Q(n.contrast,r.contrast,a)>>0)/100+"%)":"")+(n.dropShadow||r.dropShadow?mt(n.dropShadow,r.dropShadow,a):"")})},crossCheck:function(t){var e=this;this.valuesEnd[t]&&Object.keys(this.valuesStart[t]).forEach((function(n){e.valuesEnd[t][n]||(e.valuesEnd[t][n]=e.valuesStart[t][n])}))}},xt={component:"filterEffects",property:"filter",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:Q,blur:Q,saturate:Q,grayscale:Q,brightness:Q,contrast:Q,sepia:Q,invert:Q,hueRotate:Q,dropShadow:{numbers:Q,colors:lt,dropshadow:mt}},functions:Et,Util:{parseDropShadow:bt,parseFilterString:wt,replaceDashNamespace:yt,trueColor:ct}},St={},kt="htmlAttributes",Tt=["fill","stroke","stop-color"];function Ot(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}var Mt={prepareStart:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(t){var e=Ot(t).replace(/_+[a-z]+/,""),a=n.element.getAttribute(e);r[e]=Tt.includes(e)?a||"rgba(0,0,0,0)":a||(/opacity/i.test(t)?1:0)})),r},prepareProperty:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(a){var o=Ot(a),s=/(%|[a-z]+)$/,u=n.element.getAttribute(o.replace(/_+[a-z]+/,""));if(Tt.includes(o))i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){t.setAttribute(e,lt(n,r,a))})},r[o]=ct(e[a])||f.htmlAttributes[a];else if(null!==u&&s.test(u)){var c=z(u).u||z(e[a]).u,l=/%/.test(c)?"_percent":"_"+c;i.htmlAttributes[o+l]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){var i=e.replace(l,"");t.setAttribute(i,(1e3*Q(n.v,r.v,a)>>0)/1e3+r.u)})},r[o+l]=z(e[a])}else s.test(e[a])&&null!==u&&(null===u||s.test(u))||(i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in St)&&(St[e]=function(t,e,n,r,a){t.setAttribute(e,(1e3*Q(n,r,a)>>0)/1e3)})},r[o]=parseFloat(e[a]))})),r},onStart:{attr:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,n,r,a){Object.keys(r).forEach((function(i){e.attributes[i](t,i,n[i],r[i],a)}))})},attributes:function(t){!e[t]&&this.valuesEnd.attr&&(e[t]=St)}}},_t={component:kt,property:"attr",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},Interpolate:{numbers:Q,colors:lt},functions:Mt,Util:{replaceUppercase:Ot,trueColor:ct,trueDimension:z}};var Ct={prepareStart:function(t){return M(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(1e3*Q(n,r,a)>>0)/1e3})}},jt={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:Q},functions:Ct};function It(t,e){return parseFloat(t)/100*e}function At(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Pt(t){var e=t.getAttribute("points").split(" "),n=0;if(e.length>1){var r=function(t){var e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},a=function(t,e){return void 0!==t&&void 0!==e?Math.sqrt(Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)):0};if(e.length>2)for(var i=0;i>0)/100,i=0-(100*Q(e.s,n.s,r)>>0)/100,o=(100*Q(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=i+"px",t.style.strokeDasharray=(100*(o<1?0:o)>>0)/100+"px, "+a+"px"})}},Dt={component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:Q},functions:Ft,Util:{getRectLength:At,getPolyLength:Pt,getLineLength:Lt,getCircleLength:Vt,getEllipseLength:Nt,getTotalLength:Rt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:Ut,percent:It}},Ht={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){var e=t.pathValue[t.segmentStart],n=e.toLowerCase(),r=t.data;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Ht[n]&&(t.segments.push([e].concat(r.splice(0,Ht[n]))),Ht[n]););}var Bt="Invalid path value";function Qt(t){var e=t.index,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=Bt+': invalid Arc flag "'+n+'", expecting 0 or 1 at index '+e)}function zt(t){return t>=48&&t<=57}function Xt(t){var e,n=t.max,r=t.pathValue,a=t.index,i=a,o=!1,s=!1,u=!1,c=!1;if(i>=n)t.err=Bt+" at "+i+": missing param "+r[i];else if(43!==(e=r.charCodeAt(i))&&45!==e||(e=(i+=1)=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0);)t.index+=1}function Wt(t){return t>=48&&t<=57||43===t||45===t||46===t}function $t(t){var e=t.max,n=t.pathValue,r=t.index,a=n.charCodeAt(r),i=Ht[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(a))if(t.index+=1,Yt(t),t.data=[],i){for(;;){for(var o=i;o>0;o-=1){if(97!=(32|a)||3!==o&&4!==o?Xt(t):Qt(t),t.err.length)return;t.data.push(t.param),Yt(t),t.index=t.max)break;if(!Wt(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=Bt+": "+n[r]+" not a path command"}function Gt(t){return t.map((function(t){return Array.isArray(t)?[].concat(t):t}))}function Zt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Kt(t){return Array.isArray(t)&&t.every((function(t){var e=t[0].toLowerCase();return Ht[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Jt(t){if(Kt(t))return Gt(t);var e=new Zt(t);for(Yt(e);e.index7){t[n].shift();for(var r=t[n],a=n;r.length;)e[n]="A",t.splice(a+=1,0,["C"].concat(r.splice(0,6)));t.splice(n,1)}}function re(t,e,n){var r=t[0],a=e.x1,i=e.y1,o=e.x2,s=e.y2,u=t.slice(1).map(Number),c=t;if("TQ".includes(r)||(e.qx=null,e.qy=null),"H"===r)c=["L",t[1],i];else if("V"===r)c=["L",a,t[1]];else if("S"===r){var l=function(t,e,n,r,a){return"CS".includes(a)?{x1:2*t-n,y1:2*e-r}:{x1:t,y1:e}}(a,i,o,s,n),p=l.x1,h=l.y1;e.x1=p,e.y1=h,c=["C",p,h].concat(u)}else if("T"===r){var f=function(t,e,n,r,a){return"QT".includes(a)?{qx:2*t-n,qy:2*e-r}:{qx:t,qy:e}}(a,i,e.qx,e.qy,n),d=f.qx,v=f.qy;e.qx=d,e.qy=v,c=["Q",d,v].concat(u)}else if("Q"===r){var g=u[0],m=u[1];e.qx=g,e.qy=m}return c}var ae={x1:0,y1:0,x2:0,y2:0,x:0,y:0,qx:null,qy:null};function ie(t){if(function(t){return te(t)&&t.every((function(t){return"ACLMQZ".includes(t[0])}))}(t))return Gt(t);for(var e=ee(t),n=Object.assign({},ae),r=[],a=e.length,i="",o="",s=0;s1&&(y*=M=Math.sqrt(M),b*=M);var _=y*y,C=b*b,j=(i===o?-1:1)*Math.sqrt(Math.abs((_*C-_*O*O-C*T*T)/(_*O*O+C*T*T)));d=j*y*O/b+(g+w)/2,v=j*-b*T/y+(m+E)/2,h=(Math.asin((m-v)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),f=(Math.asin((E-v)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),h=gf&&(h-=2*Math.PI),!o&&f>h&&(f-=2*Math.PI)}var I=f-h;if(Math.abs(I)>x){var A=f,P=w,L=E;f=h+x*(o&&f>h?1:-1),k=ue(w=d+y*Math.cos(f),E=v+b*Math.sin(f),y,b,a,0,o,P,L,[f,A,d,v])}I=f-h;var V=Math.cos(h),N=Math.sin(h),R=Math.cos(f),U=Math.sin(f),F=Math.tan(I/4),D=4/3*y*F,H=4/3*b*F,q=[g,m],B=[g+D*N,m-H*V],Q=[w+D*U,E-H*R],z=[w,E];if(B[0]=2*q[0]-B[0],B[1]=2*q[1]-B[1],c)return B.concat(Q,z,k);for(var X=[],Y=0,W=(k=B.concat(Q,z,k)).length;Yi+.001)return{x:n,y:r};var o=le([t,e],[n,r],a/i);return{x:o[0],y:o[1]}}return i}function fe(t,e,n,r){var a=.5,i=[t,e],o=[n,r],s=le(i,o,a),u=le(o,s,a),c=le(s,u,a),l=le(u,c,a),p=le(c,l,a),h=i.concat(s,c,p,[a]),f=he.apply(void 0,h),d=p.concat(l,u,o,[0]),v=he.apply(void 0,d);return[f.x,f.y,v.x,v.y,n,r]}function de(t,e){var n,r=t[0],a=t.slice(1).map((function(t){return+t})),i=a[0],o=a[1],s=e.x1,u=e.y1,c=e.x,l=e.y;switch("TQ".includes(r)||(e.qx=null,e.qy=null),r){case"M":return e.x=i,e.y=o,t;case"A":return n=[s,u].concat(a),["C"].concat(ue.apply(void 0,n));case"Q":return e.qx=i,e.qy=o,n=[s,u].concat(a),["C"].concat(ce.apply(void 0,n));case"L":return["C"].concat(fe(s,u,i,o));case"Z":return["C"].concat(fe(s,u,c,l))}return t}function ve(t){if(function(t){return Kt(t)&&t.every((function(t){return"MC".includes(t[0])}))}(t))return Gt(t);for(var e=oe(ie(t)),n=Object.assign({},ae),r=[],a="",i=e.length,o=0;o=1?e:n)>=1?Math.pow(10,n):1;return t.map((function(t){var e=t.slice(1).map(Number).map((function(t){return t%1==0?t:Math.round(t*r)/r}));return[t[0]].concat(e)}))}(t,e).map((function(t){return t[0]+t.slice(1).join(" ")})).join("")}function ye(t){var e=t.slice(1).map((function(e,n,r){return n?r[n-1].slice(-2).concat(e.slice(1)):t[0].slice(1).concat(e.slice(1))})).map((function(t){return t.map((function(e,n){return t[t.length-n-2*(1-n%2)]}))})).reverse();return[["M"].concat(e[0].slice(0,2))].concat(e.map((function(t){return["C"].concat(t.slice(2))})))}function be(t,e,n,r,a,i,o,s){return 3*((s-e)*(n+a)-(o-t)*(r+i)+r*(t-a)-n*(e-i)+s*(a+t/3)-o*(i+e/3))/20}function we(t){return function(t){var e=0,n=0,r=0;return ve(t).map((function(t){var a,i;return"M"===t[0]?(e=(a=t)[1],n=a[2],0):(r=be.apply(void 0,[e,n].concat(t.slice(1))),i=t.slice(-2),e=i[0],n=i[1],r)})).reduce((function(t,e){return t+e}),0)}(ve(t))>=0}function Ee(t){var e=.5,n=t.slice(0,2),r=t.slice(2,4),a=t.slice(4,6),i=t.slice(6,8),o=le(n,r,e),s=le(r,a,e),u=le(a,i,e),c=le(o,s,e),l=le(s,u,e),p=le(c,l,e);return[["C"].concat(o,c,p),["C"].concat(l,u,i)]}function xe(t){return me(ee(t),0).replace(/(m|M)/g,"|$1").split("|").map((function(t){return t.trim()})).filter((function(t){return t}))}function Se(t,e,n,r,a,i,o,s,u){var c=1-u;return{x:Math.pow(c,3)*t+3*Math.pow(c,2)*u*n+3*c*Math.pow(u,2)*a+Math.pow(u,3)*o,y:Math.pow(c,3)*e+3*Math.pow(c,2)*u*r+3*c*Math.pow(u,2)*i+Math.pow(u,3)*s}}function ke(t,e,n,r,a,i,o,s,u){var c,l=t,p=e,h=0,f=[t,e,h],d=[t,e];if("number"==typeof u&&u<.001)return{x:l,y:p};for(var v=0;v<=100;v+=1){if(h+=pe(d,[l=(c=Se(t,e,n,r,a,i,o,s,v/100)).x,p=c.y]),d=[l,p],"number"==typeof u&&h>=u){var g=(h-u)/(h-f[2]);return{x:d[0]*(1-g)+f[0]*g,y:d[1]*(1-g)+f[1]*g}}f=[l,p,h]}return"number"==typeof u&&u>=h?{x:o,y:s}:h}function Te(t){return ve(xe(t)[0]).map((function(t,e,n){var r=e&&n[e-1].slice(-2).concat(t.slice(1)),a=e?ke.apply(void 0,r):0;return{s:t,ss:e?a?Ee(r):[t,t]:[t],l:a}}))}function Oe(t,e,n){var r=Te(t),a=Te(e),i=r.length,o=a.length,s=r.filter((function(t){return t.l})).length,u=a.filter((function(t){return t.l})).length,c=r.filter((function(t){return t.l})).reduce((function(t,e){return t+e.l}),0)/s||0,l=a.filter((function(t){return t.l})).reduce((function(t,e){return t+e.l}),0)/u||0,p=n||Math.max(i,o),h=[c,l],f=[p-i,p-o],d=0,v=[r,a].map((function(t,e){return t.l===p?t.map((function(t){return t.s})):t.map((function(t,n){return d=n&&f[e]&&t.l>=h[e],f[e]-=d?1:0,d?t.ss:[t.s]})).flat()}));return v[0].length===v[1].length?v:Oe(v[0],v[1],p)}function Me(t){var e=t.length,n=e-1;return t.map((function(r,a){return t.map((function(r,i){var o,s=a+i;return 0===i||t[s]&&"M"===t[s][0]?(o=t[s],["M"].concat(o.slice(-2))):(s>=e&&(s-=n),t[s])}))}))}function _e(t,e){var n=t.length-1,r=[],a=0,i=Me(t);return i.forEach((function(i,o){t.slice(1).forEach((function(r,i){a+=pe(t[(o+i)%n].slice(-2),e[i%n].slice(-2))})),r[o]=a,a=0})),i[r.indexOf(Math.min.apply(null,r))]}var Ce={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){var n={},r=new RegExp("\\n","ig"),a=null;return e instanceof SVGElement?a=e:/^\.|^#/.test(e)&&(a=P(e)),"object"==typeof e&&e.curve?e:(a&&/path|glyph/.test(a.tagName)?n.original=a.getAttribute("d").replace(r,""):a||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,e,n,r){for(var a=[],i=e.curve,o=n.curve,s=0,u=o.length;s>0)/1e3)}t.setAttribute("d",1===r?n.original:me(a))})},crossCheck:function(t){if(this.valuesEnd[t]){var e=this.valuesStart[t].curve,n=this.valuesEnd[t].curve;if(!e||!n||e&&n&&"M"===e[0][0]&&e.length!==n.length){var r=Oe(this.valuesStart[t].original,this.valuesEnd[t].original),a=we(r[0])!==we(r[1])?ye(r[0]):Gt(r[0]);this.valuesStart[t].curve=a,this.valuesEnd[t].curve=_e(r[1],a)}}}},je={component:"svgCubicMorph",property:"path",defaultValue:[],Interpolate:{numbers:Q,pathToString:me},functions:Ce,Util:{pathToCurve:ve,pathToAbsolute:ee,pathToString:me,parsePathString:Jt,getRotatedCurve:_e,getRotations:Me,equalizeSegments:Oe,reverseCurve:ye,clonePath:Gt,getDrawDirection:we,segmentCubicFactory:ke,splitCubic:Ee,splitPath:xe,fixPath:oe,getCurveArray:Te}};function Ie(t,e){var n=e.x,r=e.width;return/[a-z]/i.test(t)&&!/px/.test(t)?t.replace(/top|left/,0).replace(/right|bottom/,100).replace(/center|middle/,50):/%/.test(t)?n+parseFloat(t)*r/100:parseFloat(t)}function Ae(t){var e={},n=t&&/\)/.test(t)?t.substring(0,t.length-1).split(/\)\s|\)/):"none";if(n instanceof Array)for(var r=0,a=n.length;r>0)/1e3+(i?","+(1e3*i>>0)/1e3:"")+")":"")+(u?"rotate("+(1e3*u>>0)/1e3+")":"")+(p?"skewX("+(1e3*p>>0)/1e3+")":"")+(h?"skewY("+(1e3*h>>0)/1e3+")":"")+(1!==s?"scale("+(1e3*s>>0)/1e3+")":""))})},crossCheck:function(t){if(this._resetStart&&this.valuesEnd[t]){var e=this.valuesStart[t],n=this.valuesEnd[t],r=Pe.call(this,t,Ae(this.element.getAttribute("transform")));Object.keys(r).forEach((function(t){e[t]=r[t]}));var a=this.element.ownerSVGElement,i=a.createSVGTransformFromMatrix(a.createSVGMatrix().translate(-e.origin[0],-e.origin[1]).translate("translate"in e?e.translate[0]:0,"translate"in e?e.translate[1]:0).rotate(e.rotate||0).skewX(e.skewX||0).skewY(e.skewY||0).scale(e.scale||1).translate(+e.origin[0],+e.origin[1]));e.translate=[i.matrix.e,i.matrix.f],Object.keys(e).forEach((function(t){t in n&&"origin"!==t||(n[t]=e[t])}))}}},Ve={component:"svgTransformProperty",property:"svgTransform",defaultOptions:{transformOrigin:"50% 50%"},defaultValue:{translate:0,rotate:0,skewX:0,skewY:0,scale:1},Interpolate:{numbers:Q},functions:Le,Util:{parseStringOrigin:Ie,parseTransformString:Ae,parseTransformSVG:Pe}},Ne=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){return t=!0}});document.addEventListener("DOMContentLoaded",(function t(){document.removeEventListener("DOMContentLoaded",t,e)}),e)}catch(t){throw Error("Passive events are not supported")}return t}()&&{passive:!0},Re="onmouseleave"in document?["mouseenter","mouseleave"]:["mouseover","mouseout"],Ue="ontouchstart"in window||"msMaxTouchPoints"in navigator?"touchstart":"mousewheel",Fe=navigator&&/(EDGE|Mac)/i.test(navigator.userAgent)?document.body:document.documentElement;function De(t){this.scrolling&&t.preventDefault()}function He(){var t=this.element;return t===Fe?{el:document,st:document.body}:{el:t,st:t}}function qe(t,e){e[t](Re[0],De,Ne),e[t](Ue,De,Ne)}function Be(){var t=He.call(this);"scroll"in this.valuesEnd&&!t.el.scrolling&&(t.el.scrolling=1,qe("addEventListener",t.el),t.st.style.pointerEvents="none")}function Qe(){var t=He.call(this);"scroll"in this.valuesEnd&&t.el.scrolling&&(t.el.scrolling=0,qe("removeEventListener",t.el),t.st.style.pointerEvents="")}var ze={prepareStart:function(){return this.element=!("scroll"in this.valuesEnd)||this.element&&this.element!==window?this.element:Fe,this.element===Fe?window.pageYOffset||Fe.scrollTop:this.element.scrollTop},prepareProperty:function(t,e){return parseInt(e,10)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(this.element=!("scroll"in this.valuesEnd)||this.element&&this.element!==window?this.element:Fe,Be.call(this),e[t]=function(t,e,n,r){t.scrollTop=Q(e,n,r)>>0})},onComplete:function(){Qe.call(this)}},Xe={component:"scrollProperty",property:"scroll",defaultValue:0,Interpolate:{numbers:Q},functions:ze,Util:{preventScroll:De,scrollIn:Be,scrollOut:Qe,getScrollTargets:He,toggleScrollEvents:qe}};function Ye(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){for(var i=[],o="textShadow"===t?3:4,s=3===o?n[3]:n[4],u=3===o?r[3]:r[4],c=!!(n[5]&&"none"!==n[5]||r[5]&&"none"!==r[5])&&" inset",l=0;l>0)/1e3+"px");e.style[t]=c?lt(s,u,a)+i.join(" ")+c:lt(s,u,a)+i.join(" ")})}var We={};["boxShadow","textShadow"].forEach((function(t){We[t]=Ye}));var $e=["boxShadow","textShadow"];function Ge(t,e){var n;3===t.length?n=[t[0],t[1],0,0,t[2],"none"]:4===t.length?n=/inset|none/.test(t[3])?[t[0],t[1],0,0,t[2],t[3]]:[t[0],t[1],t[2],0,t[3],"none"]:5===t.length?n=/inset|none/.test(t[4])?[t[0],t[1],t[2],0,t[3],t[4]]:[t[0],t[1],t[2],t[3],t[4],"none"]:6===t.length&&(n=t);for(var r=0;r<4;r+=1)n[r]=parseFloat(n[r]);return n[4]=ct(n[4]),n="boxShadow"===e?n:n.filter((function(t,e){return[0,1,2,4].includes(e)})),n}var Ze={};$e.forEach((function(t){Ze[t]=Ye}));var Ke={component:"shadowProperties",properties:$e,defaultValues:{boxShadow:"0px 0px 0px 0px rgb(0,0,0)",textShadow:"0px 0px 0px rgb(0,0,0)"},Interpolate:{numbers:Q,colors:lt},functions:{prepareStart:function(t){var e=M(this.element,t);return/^none$|^initial$|^inherit$|^inset$/.test(e)?f[t]:e},prepareProperty:function(t,e){var n=e;if("string"==typeof n){var r="none",a=n.match(/(\s?(?:#(?:[\da-f]{3}){1,2}|rgba?\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\))\s?)/gi);r=/inset/.test(n)?"inset":r,n=Ge(n=(n=/inset/.test(n)?n.replace(/(\s+inset|inset+\s)/g,""):n).replace(a[0],"").split(" ").concat([a[0].replace(/\s/g,"")],[r]),t)}else n instanceof Array&&(n=Ge(n,t));return n},onStart:Ze},Util:{processShadowArray:Ge,trueColor:ct}},Je={};function tn(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=W(n.v,r.v,r.u,a)})}["fontSize","lineHeight","letterSpacing","wordSpacing"].forEach((function(t){Je[t]=tn}));var en=["fontSize","lineHeight","letterSpacing","wordSpacing"],nn={};en.forEach((function(t){nn[t]=tn}));var rn={component:"textProperties",category:"textProperties",properties:en,defaultValues:{fontSize:0,lineHeight:0,letterSpacing:0,wordSpacing:0},Interpolate:{units:W},functions:{prepareStart:function(t){return M(this.element,t)||f[t]},prepareProperty:function(t,e){return z(e)},onStart:nn},Util:{trueDimension:z}},an=String("abcdefghijklmnopqrstuvwxyz").split(""),on=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),sn=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),un=String("0123456789").split(""),cn=an.concat(on,un),ln=cn.concat(sn),pn={alpha:an,upper:on,symbols:sn,numeric:un,alphanumeric:cn,all:ln},hn={text:function(t){if(!e[t]&&this.valuesEnd[t]){var n=this._textChars,r=pn[d.textChars];n in pn?r=pn[n]:n&&n.length&&(r=n),e[t]=function(t,e,n,a){var i="",o="",s=""===n?" ":n,u=e.substring(0),c=n.substring(0),l=r[Math.random()*r.length>>0];" "===e?(o=c.substring(Math.min(a*c.length,c.length)>>0,0),t.innerHTML=a<1?o+l:s):" "===n?(i=u.substring(0,Math.min((1-a)*u.length,u.length)>>0),t.innerHTML=a<1?i+l:s):(i=u.substring(u.length,Math.min(a*u.length,u.length)>>0),o=c.substring(0,Math.min(a*c.length,c.length)>>0),t.innerHTML=a<1?o+l+i:s)}}},number:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(t,e,n,r){t.innerHTML=Q(e,n,r)>>0})}};function fn(t,e){var n,r;if("string"==typeof t)return(r=document.createElement("SPAN")).innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){var a=t.innerHTML;(n=document.createElement("SPAN")).className=e,n.innerHTML=a,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&(n=t.children[0]);return n}function dn(t,e){var n=[],r=t.children.length;if(r){for(var a,i=[],o=t.innerHTML,s=0,u=void 0,c=void 0,l=void 0;s>0)/1e3;return r}var gn="undefined"!=typeof DOMMatrix?DOMMatrix:null,mn="transformMatrix";var yn={BackgroundPosition:Y,BorderRadius:tt,BoxModel:ot,ClipProperty:ut,ColorProperties:gt,FilterEffects:xt,HTMLAttributes:_t,OpacityProperty:jt,SVGDraw:Dt,SVGCubicMorph:je,SVGTransform:Ve,ScrollProperty:Xe,ShadowProperties:Ke,TextProperties:rn,TextWriteProperties:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:Q},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:hn},Util:{charSet:pn,createTextTweens:function(t,e,n){if(t.playing)return!1;var r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);var a=I.tween,i=function(t,e){var n=dn(t,"text-part"),r=dn(fn(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((function(t){return t.className+=" oldText",t.outerHTML})).join(""),t.innerHTML+=r.map((function(t){return t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")})).join(""),[n,r]}(t,e),o=i[0],s=i[1],u=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText")),l=[],p=0;return(l=(l=l.concat(u.map((function(t,e){return r.duration="auto"===r.duration?75*o[e].innerHTML.length:r.duration,r.delay=p,r.onComplete=null,p+=r.duration,new a(t,{text:t.innerHTML},{text:""},r)})))).concat(c.map((function(n,i){return r.duration="auto"===r.duration?75*s[i].innerHTML.length:r.duration,r.delay=p,r.onComplete=i===s.length-1?function(){t.innerHTML=e,t.playing=!1}:null,p+=r.duration,new a(n,{text:""},{text:s[i].innerHTML},r)})))).start=function(){t.playing||(l.forEach((function(t){return t.start()})),t.playing=!0)},l}}},MatrixTransform:{component:mn,property:"transform",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:{prepareStart:function(t,e){var n={},r=this.element.transformMatrix;return r?Object.keys(r).forEach((function(t){n[t]=r[t]})):Object.keys(e).forEach((function(t){n[t]="perspective"===t?e[t]:f.transform[t]})),n},prepareProperty:function(t,e){if("object"==typeof e&&!e.length){var n,r={},a={},i={},o={},s={},u=[{translate3d:a},{rotate3d:i},{skew:s},{scale3d:o}];return Object.keys(e).forEach((function(t){if(/3d/.test(t)&&"object"==typeof e[t]&&e[t].length)n=e[t].map((function(e){return"scale3d"===t?parseFloat(e):parseInt(e,10)})),r[t]="scale3d"===t?[n[0]||1,n[1]||1,n[2]||1]:[n[0]||0,n[1]||0,n[2]||0];else if(/[XYZ]/.test(t)){var u={};/translate/.test(t)?u=a:/rotate/.test(t)?u=i:/scale/.test(t)?u=o:/skew/.test(t)&&(u=s),u[t.replace(/translate|rotate|scale|skew/,"").toLowerCase()]=/scale/.test(t)?parseFloat(e[t]):parseInt(e[t],10)}else"skew"===t?(n=e[t].map((function(t){return parseInt(t,10)||0})),r[t]=[n[0]||0,n[1]||0]):r[t]=parseInt(e[t],10)})),u.forEach((function(t){var e=Object.keys(t)[0],n=t[e];Object.keys(n).length&&!r[e]&&(r[e]="scale3d"===e?[n.x||1,n.y||1,n.z||1]:"skew"===e?[n.x||0,n.y||0]:[n.x||0,n.y||0,n.z||0])})),r}throw Error('KUTE.js - "'+e+'" is not valid/supported transform function')},onStart:{transform:function(t){gn&&this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){var i=new gn,o={};Object.keys(r).forEach((function(t){o[t]="perspective"===t?Q(n[t],r[t],a):vn(n[t],r[t],a)})),o.perspective&&(i.m34=-1/o.perspective),i=o.translate3d?i.translate(o.translate3d[0],o.translate3d[1],o.translate3d[2]):i,i=o.rotate3d?i.rotate(o.rotate3d[0],o.rotate3d[1],o.rotate3d[2]):i,o.skew&&(i=o.skew[0]?i.skewX(o.skew[0]):i,i=o.skew[1]?i.skewY(o.skew[1]):i),i=o.scale3d?i.scale(o.scale3d[0],o.scale3d[1],o.scale3d[2]):i,e.style[t]=i.toString()})},CSS3Matrix:function(t){gn&&this.valuesEnd.transform&&(e[t]||(e[t]=gn))}},onComplete:function(t){this.valuesEnd[t]&&(this.element.transformMatrix=Object.assign({},this.valuesEnd[t]))},crossCheck:function(t){this.valuesEnd[t]&&this.valuesEnd[t].perspective&&!this.valuesStart[t].perspective&&(this.valuesStart[t].perspective=this.valuesEnd[t].perspective)}},Interpolate:{perspective:Q,translate3d:vn,rotate3d:vn,skew:vn,scale3d:vn}}};Object.keys(yn).forEach((function(t){var e=yn[t];yn[t]=new B(e)}));return{Animation:B,Components:yn,Tween:R,fromTo:function(t,e,n,r){var a=r||{};return new H(P(t),e,n,a)},to:function(t,e,n){var r=n||{};return r.resetStart=e,new D(P(t),e,e,r)},TweenCollection:U,ProgressBar:F,allFromTo:function(t,e,n,r){var a=r||{};return new U(P(t,!0),e,n,a)},allTo:function(t,e,n){var r=n||{};return r.resetStart=e,new U(P(t,!0),e,e,r)},Objects:w,Util:E,Easing:A,CubicBezier:t,Render:p,Interpolate:a,Process:j,Internals:T,Selector:P,Version:"2.2.3"}})); diff --git a/src/kute.min.js b/demo/src/kute.min.js similarity index 99% rename from src/kute.min.js rename to demo/src/kute.min.js index 2887b84..f0c3fa3 100644 --- a/src/kute.min.js +++ b/demo/src/kute.min.js @@ -1,2 +1,2 @@ -// KUTE.js Standard v2.2.2 | thednp © 2021 | MIT-License -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t=function(t,e,n,r,a){var i=this;this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by;var o=function(t){return i.sampleCurveY(i.solveCurveX(t))};return Object.defineProperty(o,"name",{writable:!0}),o.name=a||"cubic-bezier("+[t,e,n,r]+")",o};t.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},t.prototype.sampleCurveY=function(t){return((this.ay*t+this.by)*t+this.cy)*t},t.prototype.sampleCurveDerivativeX=function(t){return(3*this.ax*t+2*this.bx)*t+this.cx},t.prototype.solveCurveX=function(t){var e,n,r,a,i,o,s=1e-5;for(r=t,o=0;o<32;o+=1){if(a=this.sampleCurveX(r)-t,Math.abs(a)(n=1))return n;for(;ea?e=r:n=r,r=.5*(n-e)+e}return r};Object.assign(t,{Version:"1.0.18"});var e={},n=[],r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},a={},i={},o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},s={};s.now=o;var u=0,c=function(t){for(var e=0;e1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},j.tween=N;var q=function(t){function n(){for(var e=this,n=[],r=arguments.length;r--;)n[r]=arguments[r];t.apply(this,n),this.valuesStart={},this.valuesEnd={};var a=n.slice(1),i=a[0],o=a[1],s=a[2];return T.call(this,o,"end"),this._resetStart?this.valuesStart=i:T.call(this,i,"start"),this._resetStart||Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(n){g[t][n].call(e,n)}))})),this.paused=!1,this._pauseTime=null,this._repeat=s.repeat||d.repeat,this._repeatDelay=s.repeatDelay||d.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=s.yoyo||d.yoyo,this._reversed=!1,this}return t&&(n.__proto__=t),n.prototype=Object.create(t&&t.prototype),n.prototype.constructor=n,n.prototype.start=function(e){var n=this;return this._resetStart&&(this.valuesStart=this._resetStart,S.call(this),Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(e){g[t][e].call(n,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((function(t){n.valuesRepeat[t]=n.valuesStart[t]})),t.prototype.start.call(this,e),this},n.prototype.stop=function(){return t.prototype.stop.call(this),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this},n.prototype.close=function(){return t.prototype.close.call(this),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this},n.prototype.resume=function(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),L.call(this),this._startTime+=e.Time()-this._pauseTime,E(this),u||c()),this},n.prototype.pause=function(){return!this.paused&&this.playing&&(M(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this},n.prototype.reverse=function(){var t=this;Object.keys(this.valuesEnd).forEach((function(e){var n=t.valuesRepeat[e];t.valuesRepeat[e]=t.valuesEnd[e],t.valuesEnd[e]=n,t.valuesStart[e]=t.valuesRepeat[e]}))},n.prototype.update=function(t){var n,r=this,a=void 0!==t?t:e.Time();if(a1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=a,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.start()})),!1))},n}(N);j.tween=q;var V=function(t,e,n,r){var a=this,i=j.tween;this.tweens=[];var o=r||{};o.delay=o.delay||d.delay;var s=[];return Array.from(t).forEach((function(t,r){if(s[r]=o||{},s[r].delay=r>0?o.delay+(o.offset||d.offset):o.delay,!(t instanceof Element))throw Error("KUTE - "+t+" is not instanceof Element");a.tweens.push(new i(t,e,n,s[r]))})),this.length=this.tweens.length,this};V.prototype.start=function(t){var n=void 0===t?e.Time():t;return this.tweens.map((function(t){return t.start(n)})),this},V.prototype.stop=function(){return this.tweens.map((function(t){return t.stop()})),this},V.prototype.pause=function(){return this.tweens.map((function(t){return t.pause()})),this},V.prototype.resume=function(){return this.tweens.map((function(t){return t.resume()})),this},V.prototype.chain=function(t){var e=this.tweens[this.length-1];if(t instanceof V)e.chain(t.tweens);else{if(!(t instanceof j.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this},V.prototype.playing=function(){return this.tweens.some((function(t){return t.playing}))},V.prototype.removeTweens=function(){this.tweens=[]},V.prototype.getMaxDuration=function(){var t=[];return this.tweens.forEach((function(e){t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)};var H=j.tween;var Q=j.tween;var F=function(t){try{if(t.component in f)throw Error("KUTE - "+t.component+" already registered");if(t.property in h)throw Error("KUTE - "+t.property+" already registered")}catch(t){throw Error(t)}var e=this,n=t.component,r={prepareProperty:y,prepareStart:v,onStart:i,onComplete:m,crossCheck:g},o=t.category,s=t.property,u=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return f[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(h[s]=t.defaultValue,e.supports=s+" property"):t.defaultValues&&(Object.keys(t.defaultValues).forEach((function(e){h[e]=t.defaultValues[e]})),e.supports=(u||s)+" "+(s||o)+" properties"),t.defaultOptions&&Object.assign(d,t.defaultOptions),t.functions&&Object.keys(r).forEach((function(e){e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][o||s]||(r[e][n][o||s]=t.functions[e])):Object.keys(t.functions[e]).forEach((function(a){r[e][n]||(r[e][n]={}),r[e][n][a]||(r[e][n][a]=t.functions[e][a])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((function(e){var n=t.Interpolate[e];"function"!=typeof n||a[e]?Object.keys(n).forEach((function(t){"function"!=typeof n[t]||a[e]||(a[e]=n[t])})):a[e]=n})),b[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((function(e){w[e]||(w[e]=t.Util[e])})),e},U=function(t,e){for(var n,r=parseInt(t,10)||0,a=["px","%","deg","rad","em","rem","vh","vw"],i=0;i.99||a<.01?(10*D(n,r,a)>>0)/10:D(n,r,a)>>0)+"px"})}var Z={};["top","left","width","height"].forEach((function(t){Z[t]=X}));var B=["top","left","width","height"],R={};B.forEach((function(t){R[t]=X}));var Y={component:"essentialBoxModel",category:"boxModel",properties:B,defaultValues:{top:0,left:0,width:0,height:0},Interpolate:{numbers:D},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){var n=U(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:R},Util:{trueDimension:U}},z=function(t){var e;if(/rgb|rgba/.test(t)){var n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){var a=function(t){var e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,n,r){return e+e+n+n+r+r})),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}(t);e={r:a.r,g:a.g,b:a.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){var i=document.getElementsByTagName("head")[0];i.style.color=t;var o=getComputedStyle(i,null).color;o=/rgb/.test(o)?o.replace(/[^\d,]/g,"").split(","):[0,0,0],i.style.color="",e={r:parseInt(o[0],10),g:parseInt(o[1],10),b:parseInt(o[2],10)}}return e};function K(t,e,n){var r={},a=",";return Object.keys(e).forEach((function(a){"a"!==a?r[a]=D(t[a],e[a],n)>>0||0:t[a]&&e[a]&&(r[a]=(100*D(t[a],e[a],n)>>0)/100)})),r.a?"rgba("+r.r+a+r.g+a+r.b+a+r.a+")":"rgb("+r.r+a+r.g+a+r.b+")"}function $(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=K(n,r,a)})}var W={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((function(t){W[t]=$}));var G=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],J={};G.forEach((function(t){J[t]="#000"}));var tt={};G.forEach((function(t){tt[t]=$}));var et={component:"colorProperties",category:"colors",properties:G,defaultValues:J,Interpolate:{numbers:D,colors:K},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){return z(e)},onStart:tt},Util:{trueColor:z}},nt={},rt="htmlAttributes",at=["fill","stroke","stop-color"];function it(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}var ot={prepareStart:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(t){var e=it(t).replace(/_+[a-z]+/,""),a=n.element.getAttribute(e);r[e]=at.includes(e)?a||"rgba(0,0,0,0)":a||(/opacity/i.test(t)?1:0)})),r},prepareProperty:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(a){var o=it(a),s=/(%|[a-z]+)$/,u=n.element.getAttribute(o.replace(/_+[a-z]+/,""));if(at.includes(o))i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,K(n,r,a))})},r[o]=z(e[a])||h.htmlAttributes[a];else if(null!==u&&s.test(u)){var c=U(u).u||U(e[a]).u,l=/%/.test(c)?"_percent":"_"+c;i.htmlAttributes[o+l]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){var i=e.replace(l,"");t.setAttribute(i,(1e3*D(n.v,r.v,a)>>0)/1e3+r.u)})},r[o+l]=U(e[a])}else s.test(e[a])&&null!==u&&(null===u||s.test(u))||(i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,(1e3*D(n,r,a)>>0)/1e3)})},r[o]=parseFloat(e[a]))})),r},onStart:{attr:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,n,r,a){Object.keys(r).forEach((function(i){e.attributes[i](t,i,n[i],r[i],a)}))})},attributes:function(t){!e[t]&&this.valuesEnd.attr&&(e[t]=nt)}}},st={component:rt,property:"attr",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},Interpolate:{numbers:D,colors:K},functions:ot,Util:{replaceUppercase:it,trueColor:z,trueDimension:U}};var ut={prepareStart:function(t){return O(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(1e3*D(n,r,a)>>0)/1e3})}},ct={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:D},functions:ut},lt=String("abcdefghijklmnopqrstuvwxyz").split(""),pt=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),ft=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),ht=String("0123456789").split(""),dt=lt.concat(pt,ht),yt=dt.concat(ft),vt={alpha:lt,upper:pt,symbols:ft,numeric:ht,alphanumeric:dt,all:yt},gt={text:function(t){if(!e[t]&&this.valuesEnd[t]){var n=this._textChars,r=vt[d.textChars];n in vt?r=vt[n]:n&&n.length&&(r=n),e[t]=function(t,e,n,a){var i="",o="",s=""===n?" ":n,u=e.substring(0),c=n.substring(0),l=r[Math.random()*r.length>>0];" "===e?(o=c.substring(Math.min(a*c.length,c.length)>>0,0),t.innerHTML=a<1?o+l:s):" "===n?(i=u.substring(0,Math.min((1-a)*u.length,u.length)>>0),t.innerHTML=a<1?i+l:s):(i=u.substring(u.length,Math.min(a*u.length,u.length)>>0),o=c.substring(0,Math.min(a*c.length,c.length)>>0),t.innerHTML=a<1?o+l+i:s)}}},number:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(t,e,n,r){t.innerHTML=D(e,n,r)>>0})}};function mt(t,e){var n,r;if("string"==typeof t)return(r=document.createElement("SPAN")).innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){var a=t.innerHTML;(n=document.createElement("SPAN")).className=e,n.innerHTML=a,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&(n=t.children[0]);return n}function bt(t,e){var n=[],r=t.children.length;if(r){for(var a,i=[],o=t.innerHTML,s=0,u=void 0,c=void 0,l=void 0;s>0)/1e3+n+")"}function wt(t,e,n,r){for(var a=[],i=0;i<3;i+=1)a[i]=(t[i]||e[i]?(1e3*(t[i]+(e[i]-t[i])*r)>>0)/1e3:0)+n;return"translate3d("+a.join(",")+")"}function Et(t,e,n,r){var a="";return a+=t[0]||e[0]?"rotateX("+(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3+n+")":"",a+=t[1]||e[1]?"rotateY("+(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3+n+")":"",a+=t[2]||e[2]?"rotateZ("+(1e3*(t[2]+(e[2]-t[2])*r)>>0)/1e3+n+")":""}function Mt(t,e,n){return"scale("+(1e3*(t+(e-t)*n)>>0)/1e3+")"}function _t(t,e,n,r){var a=[];return a[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","skew("+a.join(",")+")"}function kt(t,e){return parseFloat(t)/100*e}function Ct(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Ot(t){var e=t.getAttribute("points").split(" "),n=0;if(e.length>1){var r=function(t){var e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},a=function(t,e){return void 0!==t&&void 0!==e?Math.sqrt(Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)):0};if(e.length>2)for(var i=0;i>0)/100,i=0-(100*D(e.s,n.s,r)>>0)/100,o=(100*D(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=i+"px",t.style.strokeDasharray=(100*(o<1?0:o)>>0)/100+"px, "+a+"px"})}};function Lt(t,e,n){if(t[n].length>7){t[n].shift();for(var r=t[n],a=n;r.length;)e[n]="A",t.splice(a+=1,0,["C"].concat(r.splice(0,6)));t.splice(n,1)}}var Nt={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){var e=t.pathValue[t.segmentStart],n=e.toLowerCase(),r=t.data;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Nt[n]&&(t.segments.push([e].concat(r.splice(0,Nt[n]))),Nt[n]););}var Vt="Invalid path value";function Ht(t){var e=t.index,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=Vt+': invalid Arc flag "'+n+'", expecting 0 or 1 at index '+e)}function Qt(t){return t>=48&&t<=57}function Ft(t){var e,n=t.max,r=t.pathValue,a=t.index,i=a,o=!1,s=!1,u=!1,c=!1;if(i>=n)t.err=Vt+" at "+i+": missing param "+r[i];else if(43!==(e=r.charCodeAt(i))&&45!==e||(e=(i+=1)=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0);)t.index+=1}function Dt(t){return t>=48&&t<=57||43===t||45===t||46===t}function Xt(t){var e=t.max,n=t.pathValue,r=t.index,a=n.charCodeAt(r),i=Nt[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(a))if(t.index+=1,Ut(t),t.data=[],i){for(;;){for(var o=i;o>0;o-=1){if(97!=(32|a)||3!==o&&4!==o?Ft(t):Ht(t),t.err.length)return;t.data.push(t.param),Ut(t),t.index=t.max)break;if(!Dt(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=Vt+": "+n[r]+" not a path command"}function Zt(t){return t.map((function(t){return Array.isArray(t)?[].concat(t):t}))}function Bt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Rt(t){return Array.isArray(t)&&t.every((function(t){var e=t[0].toLowerCase();return Nt[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Yt(t){if(Rt(t))return Zt(t);var e=new Bt(t);for(Ut(e);e.index1&&(m*=O=Math.sqrt(O),b*=O);var T=m*m,S=b*b,I=(i===o?-1:1)*Math.sqrt(Math.abs((T*S-T*C*C-S*k*k)/(T*C*C+S*k*k)));d=I*m*C/b+(v+x)/2,y=I*-b*k/m+(g+w)/2,f=(Math.asin((g-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),h=(Math.asin((w-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),f=vh&&(f-=2*Math.PI),!o&&h>f&&(h-=2*Math.PI)}var j=h-f;if(Math.abs(j)>E){var A=h,P=x,L=w;h=f+E*(o&&h>f?1:-1),_=ee(x=d+m*Math.cos(h),w=y+b*Math.sin(h),m,b,a,0,o,P,L,[h,A,d,y])}j=h-f;var N=Math.cos(f),q=Math.sin(f),V=Math.cos(h),H=Math.sin(h),Q=Math.tan(j/4),F=4/3*m*Q,U=4/3*b*Q,D=[v,g],X=[v+F*q,g-U*N],Z=[x+F*H,w-U*V],B=[x,w];if(X[0]=2*D[0]-X[0],X[1]=2*D[1]-X[1],c)return X.concat(Z,B,_);for(var R=[],Y=0,z=(_=X.concat(Z,B,_)).length;Yi+.001)return{x:n,y:r};var o=re([t,e],[n,r],a/i);return{x:o[0],y:o[1]}}return i}function oe(t,e,n,r){var a=.5,i=[t,e],o=[n,r],s=re(i,o,a),u=re(o,s,a),c=re(s,u,a),l=re(u,c,a),p=re(c,l,a),f=i.concat(s,c,p,[a]),h=ie.apply(void 0,f),d=p.concat(l,u,o,[0]),y=ie.apply(void 0,d);return[h.x,h.y,y.x,y.y,n,r]}function se(t,e){var n,r=t[0],a=t.slice(1).map((function(t){return+t})),i=a[0],o=a[1],s=e.x1,u=e.y1,c=e.x,l=e.y;switch("TQ".includes(r)||(e.qx=null,e.qy=null),r){case"M":return e.x=i,e.y=o,t;case"A":return n=[s,u].concat(a),["C"].concat(ee.apply(void 0,n));case"Q":return e.qx=i,e.qy=o,n=[s,u].concat(a),["C"].concat(ne.apply(void 0,n));case"L":return["C"].concat(oe(s,u,i,o));case"Z":return["C"].concat(oe(s,u,c,l))}return t}var ue=4;function ce(t,e){var n=ue;if(!1===e||!1===n)return Zt(t);var r=(n=e>=1?e:n)>=1?Math.pow(10,n):1;return t.map((function(t){var e=t.slice(1).map(Number).map((function(t){return t%1==0?t:Math.round(t*r)/r}));return[t[0]].concat(e)}))}function le(t,e){return ce(t,e).map((function(t){return t[0]+t.slice(1).join(" ")})).join("")}function pe(t,e,n,r,a,i,o,s,u){var c=1-u;return{x:Math.pow(c,3)*t+3*Math.pow(c,2)*u*n+3*c*Math.pow(u,2)*a+Math.pow(u,3)*o,y:Math.pow(c,3)*e+3*Math.pow(c,2)*u*r+3*c*Math.pow(u,2)*i+Math.pow(u,3)*s}}function fe(t,e,n,r,a,i,o,s,u){var c,l=t,p=e,f=0,h=[t,e,f],d=[t,e];if("number"==typeof u&&u<.001)return{x:l,y:p};for(var y=0;y<=100;y+=1){if(f+=ae(d,[l=(c=pe(t,e,n,r,a,i,o,s,y/100)).x,p=c.y]),d=[l,p],"number"==typeof u&&f>=u){var v=(f-u)/(f-h[2]);return{x:d[0]*(1-v)+h[0]*v,y:d[1]*(1-v)+h[1]*v}}h=[l,p,f]}return"number"==typeof u&&u>=f?{x:o,y:s}:f}function he(t,e,n,r,a,i,o,s,u,c){var l,p=[t,e],f=p[0],h=p[1],d=ee(t,e,n,r,a,i,o,s,u),y=0,v=[],g=[],m=0;if("number"==typeof c&&c<.001)return{x:f,y:h};for(var b=0,x=d.length;b=c)return fe.apply(void 0,g.concat([c-y]));y+=m,f=(l=v.slice(-2))[0],h=l[1]}return"number"==typeof c&&c>=y?{x:s,y:u}:y}function de(t,e,n,r,a,i,o){var s=1-o;return{x:Math.pow(s,2)*t+2*s*o*n+Math.pow(o,2)*a,y:Math.pow(s,2)*e+2*s*o*r+Math.pow(o,2)*i}}function ye(t,e,n,r,a,i,o){var s,u=t,c=e,l=0,p=[t,e,l],f=[t,e];if("number"==typeof o&&o<.001)return{x:u,y:c};for(var h=0;h<=100;h+=1){if(l+=ae(f,[u=(s=de(t,e,n,r,a,i,h/100)).x,c=s.y]),f=[u,c],"number"==typeof o&&l>=o){var d=(l-o)/(l-p[2]);return{x:f[0]*(1-d)+p[0]*d,y:f[1]*(1-d)+p[1]*d}}p=[u,c,l]}return"number"==typeof o&&o>=l?{x:a,y:i}:l}function ve(t,e){for(var n,r,a,i=0,o=!0,s=[],u="M",c=0,l=0,p=0,f=0,h=0,d=Jt(Gt(t)),y=0,v=d.length;y=e)return ie.apply(void 0,s.concat([e-i]));i+=c}else if("A"===u){if(c=he.apply(void 0,s),e&&i+c>=e)return he.apply(void 0,s.concat([e-i]));i+=c}else if("C"===u){if(c=fe.apply(void 0,s),e&&i+c>=e)return fe.apply(void 0,s.concat([e-i]));i+=c}else if("Q"===u){if(c=ye.apply(void 0,s),e&&i+c>=e)return ye.apply(void 0,s.concat([e-i]));i+=c}else if("Z"===u){if(s=[l,p,f,h],c=ie.apply(void 0,s),e&&i+c>=e)return ie.apply(void 0,s.concat([e-i]));i+=c}l=(r="Z"!==u?a.slice(-2):[f,h])[0],p=r[1]}return e&&e>=i?{x:l,y:p}:i}function ge(t){return ve(t)}function me(t,e){return ve(t,e)}function be(t){for(var e,n=t.length,r=-1,a=t[n-1],i=0;++r>0)/1e3)}return a}function we(t,e){var n,r,a=Gt((n=le(t),le(Kt(n),0).replace(/(m|M)/g,"|$1").split("|").map((function(t){return t.trim()})).filter((function(t){return t})))[0]),i=ge(a),o=[],s=3;e&&!Number.isNaN(e)&&+e>0&&(s=Math.max(s,Math.ceil(i/e)));for(var u=0;u0&&o.reverse(),{polygon:o,skipBisect:!0}}function Ee(t,e){var n=Gt(t);return function(t){var e=[],n=t.length,r=[],a="";if(!t.length||"M"!==t[0][0])return!1;for(var i=0;ie;)r=re(n,r,.5),t.splice(a+1,0,r)}function Ce(t){return Array.isArray(t)&&t.every((function(t){return Array.isArray(t)&&2===t.length&&!Number.isNaN(t[0])&&!Number.isNaN(t[1])}))}function Oe(t,e){var n,r,a;if("string"==typeof t)a=(n=Ee(t,e)).polygon,r=n.skipBisect;else if(!Array.isArray(t))throw Error(Vt+": "+t);var i=[].concat(a);if(!Ce(i))throw Error(Vt+": "+i);return i.length>1&&ae(i[0],i[i.length-1])<1e-9&&i.pop(),!r&&e&&!Number.isNaN(e)&&+e>0&&ke(i,e),i}function Te(t,e,n){var r=n||d.morphPrecision,a=Oe(t,r),i=Oe(e,r),o=a.length-i.length;return _e(a,o<0?-1*o:0),_e(i,o>0?o:0),Me(a,i),[ce(a),ce(i)]}var Se={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){var n={},r=new RegExp("\\n","ig"),a=null;return e instanceof SVGPathElement?a=e:/^\.|^#/.test(e)&&(a=P(e)),"object"==typeof e&&e.polygon?e:(a&&["path","glyph"].includes(a.tagName)?n.original=a.getAttribute("d").replace(r,""):a||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,e,n,r){var a=e.polygon,i=n.polygon,o=i.length;t.setAttribute("d",1===r?n.original:"M"+xe(a,i,o,r).join("L")+"Z")})},crossCheck:function(t){if(this.valuesEnd[t]){var e=this.valuesStart[t].polygon,n=this.valuesEnd[t].polygon;if(!e||!n||e&&n&&e.length!==n.length){var r=Te(this.valuesStart[t].original,this.valuesEnd[t].original,this._morphPrecision?parseInt(this._morphPrecision,10):d.morphPrecision),a=r[0],i=r[1];this.valuesStart[t].polygon=a,this.valuesEnd[t].polygon=i}}}},Ie={EssentialBoxModel:Y,ColorsProperties:et,HTMLAttributes:st,OpacityProperty:ct,TextWriteProp:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:D},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:gt},Util:{charSet:vt,createTextTweens:function(t,e,n){if(t.playing)return!1;var r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);var a=j.tween,i=function(t,e){var n=bt(t,"text-part"),r=bt(mt(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((function(t){return t.className+=" oldText",t.outerHTML})).join(""),t.innerHTML+=r.map((function(t){return t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")})).join(""),[n,r]}(t,e),o=i[0],s=i[1],u=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText")),l=[],p=0;return(l=(l=l.concat(u.map((function(t,e){return r.duration="auto"===r.duration?75*o[e].innerHTML.length:r.duration,r.delay=p,r.onComplete=null,p+=r.duration,new a(t,{text:t.innerHTML},{text:""},r)})))).concat(c.map((function(n,i){return r.duration="auto"===r.duration?75*s[i].innerHTML.length:r.duration,r.delay=p,r.onComplete=i===s.length-1?function(){t.innerHTML=e,t.playing=!1}:null,p+=r.duration,new a(n,{text:""},{text:s[i].innerHTML},r)})))).start=function(){t.playing||(l.forEach((function(t){return t.start()})),t.playing=!0)},l}}},TransformFunctions:{component:"transformFunctions",property:"transform",subProperties:["perspective","translate3d","translateX","translateY","translateZ","translate","rotate3d","rotateX","rotateY","rotateZ","rotate","skewX","skewY","skew","scale"],defaultValues:{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},functions:{prepareStart:function(t){var e=C(this.element);return e[t]?e[t]:h[t]},prepareProperty:function(t,e){var n=["X","Y","Z"],r={},a=[],i=[],o=[],s=["translate3d","translate","rotate3d","skew"];return Object.keys(e).forEach((function(t){var u="object"==typeof e[t]&&e[t].length?e[t].map((function(t){return parseInt(t,10)})):parseInt(e[t],10);if(s.includes(t)){var c="translate"===t||"rotate"===t?t+"3d":t;r[c]="skew"===t?u.length?[u[0]||0,u[1]||0]:[u||0,0]:"translate"===t?u.length?[u[0]||0,u[1]||0,u[2]||0]:[u||0,0,0]:[u[0]||0,u[1]||0,u[2]||0]}else if(/[XYZ]/.test(t)){var l=t.replace(/[XYZ]/,""),p="skew"===l?l:l+"3d",f="skew"===l?2:3,h=[];"translate"===l?h=a:"rotate"===l?h=i:"skew"===l&&(h=o);for(var d=0;d>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","translate("+a.join(",")+")"},rotate:function(t,e,n,r){return"rotate("+(1e3*(t+(e-t)*r)>>0)/1e3+n+")"},scale:Mt,skew:_t}},SVGDraw:{component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:D},functions:Pt,Util:{getRectLength:Ct,getPolyLength:Ot,getLineLength:Tt,getCircleLength:St,getEllipseLength:It,getTotalLength:jt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:At,percent:kt}},SVGMorph:{component:"svgMorph",property:"path",defaultValue:[],Interpolate:xe,defaultOptions:{morphPrecision:10},functions:Se,Util:{addPoints:_e,bisect:ke,getPolygon:Oe,validPolygon:Ce,getInterpolationPoints:Te,pathStringToPolygon:Ee,distanceSquareRoot:ae,midPoint:re,approximatePolygon:we,rotatePolygon:Me,pathToString:le,pathToCurve:function(t){if(function(t){return Rt(t)&&t.every((function(t){return"MC".includes(t[0])}))}(t))return Zt(t);for(var e=Jt(Gt(t)),n=Object.assign({},Wt),r=[],a="",i=e.length,o=0;o(n=1))return n;for(;ea?e=r:n=r,r=.5*(n-e)+e}return r};Object.assign(t,{Version:"1.0.18"});var e={},n=[],r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},a={},i={},o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},s={};s.now=o;var u=0,c=function(t){for(var e=0;e1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},j.tween=N;var q=function(t){function n(){for(var e=this,n=[],r=arguments.length;r--;)n[r]=arguments[r];t.apply(this,n),this.valuesStart={},this.valuesEnd={};var a=n.slice(1),i=a[0],o=a[1],s=a[2];return T.call(this,o,"end"),this._resetStart?this.valuesStart=i:T.call(this,i,"start"),this._resetStart||Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(n){g[t][n].call(e,n)}))})),this.paused=!1,this._pauseTime=null,this._repeat=s.repeat||d.repeat,this._repeatDelay=s.repeatDelay||d.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=s.yoyo||d.yoyo,this._reversed=!1,this}return t&&(n.__proto__=t),n.prototype=Object.create(t&&t.prototype),n.prototype.constructor=n,n.prototype.start=function(e){var n=this;return this._resetStart&&(this.valuesStart=this._resetStart,S.call(this),Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(e){g[t][e].call(n,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((function(t){n.valuesRepeat[t]=n.valuesStart[t]})),t.prototype.start.call(this,e),this},n.prototype.stop=function(){return t.prototype.stop.call(this),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this},n.prototype.close=function(){return t.prototype.close.call(this),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this},n.prototype.resume=function(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),L.call(this),this._startTime+=e.Time()-this._pauseTime,E(this),u||c()),this},n.prototype.pause=function(){return!this.paused&&this.playing&&(M(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this},n.prototype.reverse=function(){var t=this;Object.keys(this.valuesEnd).forEach((function(e){var n=t.valuesRepeat[e];t.valuesRepeat[e]=t.valuesEnd[e],t.valuesEnd[e]=n,t.valuesStart[e]=t.valuesRepeat[e]}))},n.prototype.update=function(t){var n,r=this,a=void 0!==t?t:e.Time();if(a1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=a,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.start()})),!1))},n}(N);j.tween=q;var V=function(t,e,n,r){var a=this,i=j.tween;this.tweens=[];var o=r||{};o.delay=o.delay||d.delay;var s=[];return Array.from(t).forEach((function(t,r){if(s[r]=o||{},s[r].delay=r>0?o.delay+(o.offset||d.offset):o.delay,!(t instanceof Element))throw Error("KUTE - "+t+" is not instanceof Element");a.tweens.push(new i(t,e,n,s[r]))})),this.length=this.tweens.length,this};V.prototype.start=function(t){var n=void 0===t?e.Time():t;return this.tweens.map((function(t){return t.start(n)})),this},V.prototype.stop=function(){return this.tweens.map((function(t){return t.stop()})),this},V.prototype.pause=function(){return this.tweens.map((function(t){return t.pause()})),this},V.prototype.resume=function(){return this.tweens.map((function(t){return t.resume()})),this},V.prototype.chain=function(t){var e=this.tweens[this.length-1];if(t instanceof V)e.chain(t.tweens);else{if(!(t instanceof j.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this},V.prototype.playing=function(){return this.tweens.some((function(t){return t.playing}))},V.prototype.removeTweens=function(){this.tweens=[]},V.prototype.getMaxDuration=function(){var t=[];return this.tweens.forEach((function(e){t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)};var H=j.tween;var Q=j.tween;var F=function(t){try{if(t.component in f)throw Error("KUTE - "+t.component+" already registered");if(t.property in h)throw Error("KUTE - "+t.property+" already registered")}catch(t){throw Error(t)}var e=this,n=t.component,r={prepareProperty:y,prepareStart:v,onStart:i,onComplete:m,crossCheck:g},o=t.category,s=t.property,u=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return f[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(h[s]=t.defaultValue,e.supports=s+" property"):t.defaultValues&&(Object.keys(t.defaultValues).forEach((function(e){h[e]=t.defaultValues[e]})),e.supports=(u||s)+" "+(s||o)+" properties"),t.defaultOptions&&Object.assign(d,t.defaultOptions),t.functions&&Object.keys(r).forEach((function(e){e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][o||s]||(r[e][n][o||s]=t.functions[e])):Object.keys(t.functions[e]).forEach((function(a){r[e][n]||(r[e][n]={}),r[e][n][a]||(r[e][n][a]=t.functions[e][a])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((function(e){var n=t.Interpolate[e];"function"!=typeof n||a[e]?Object.keys(n).forEach((function(t){"function"!=typeof n[t]||a[e]||(a[e]=n[t])})):a[e]=n})),b[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((function(e){w[e]||(w[e]=t.Util[e])})),e},U=function(t,e){for(var n,r=parseInt(t,10)||0,a=["px","%","deg","rad","em","rem","vh","vw"],i=0;i.99||a<.01?(10*D(n,r,a)>>0)/10:D(n,r,a)>>0)+"px"})}var Z={};["top","left","width","height"].forEach((function(t){Z[t]=X}));var B=["top","left","width","height"],R={};B.forEach((function(t){R[t]=X}));var Y={component:"essentialBoxModel",category:"boxModel",properties:B,defaultValues:{top:0,left:0,width:0,height:0},Interpolate:{numbers:D},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){var n=U(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:R},Util:{trueDimension:U}},z=function(t){var e;if(/rgb|rgba/.test(t)){var n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){var a=function(t){var e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,n,r){return e+e+n+n+r+r})),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}(t);e={r:a.r,g:a.g,b:a.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){var i=document.getElementsByTagName("head")[0];i.style.color=t;var o=getComputedStyle(i,null).color;o=/rgb/.test(o)?o.replace(/[^\d,]/g,"").split(","):[0,0,0],i.style.color="",e={r:parseInt(o[0],10),g:parseInt(o[1],10),b:parseInt(o[2],10)}}return e};function K(t,e,n){var r={},a=",";return Object.keys(e).forEach((function(a){"a"!==a?r[a]=D(t[a],e[a],n)>>0||0:t[a]&&e[a]&&(r[a]=(100*D(t[a],e[a],n)>>0)/100)})),r.a?"rgba("+r.r+a+r.g+a+r.b+a+r.a+")":"rgb("+r.r+a+r.g+a+r.b+")"}function $(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=K(n,r,a)})}var W={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((function(t){W[t]=$}));var G=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],J={};G.forEach((function(t){J[t]="#000"}));var tt={};G.forEach((function(t){tt[t]=$}));var et={component:"colorProperties",category:"colors",properties:G,defaultValues:J,Interpolate:{numbers:D,colors:K},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){return z(e)},onStart:tt},Util:{trueColor:z}},nt={},rt="htmlAttributes",at=["fill","stroke","stop-color"];function it(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}var ot={prepareStart:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(t){var e=it(t).replace(/_+[a-z]+/,""),a=n.element.getAttribute(e);r[e]=at.includes(e)?a||"rgba(0,0,0,0)":a||(/opacity/i.test(t)?1:0)})),r},prepareProperty:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(a){var o=it(a),s=/(%|[a-z]+)$/,u=n.element.getAttribute(o.replace(/_+[a-z]+/,""));if(at.includes(o))i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,K(n,r,a))})},r[o]=z(e[a])||h.htmlAttributes[a];else if(null!==u&&s.test(u)){var c=U(u).u||U(e[a]).u,l=/%/.test(c)?"_percent":"_"+c;i.htmlAttributes[o+l]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){var i=e.replace(l,"");t.setAttribute(i,(1e3*D(n.v,r.v,a)>>0)/1e3+r.u)})},r[o+l]=U(e[a])}else s.test(e[a])&&null!==u&&(null===u||s.test(u))||(i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,(1e3*D(n,r,a)>>0)/1e3)})},r[o]=parseFloat(e[a]))})),r},onStart:{attr:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,n,r,a){Object.keys(r).forEach((function(i){e.attributes[i](t,i,n[i],r[i],a)}))})},attributes:function(t){!e[t]&&this.valuesEnd.attr&&(e[t]=nt)}}},st={component:rt,property:"attr",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},Interpolate:{numbers:D,colors:K},functions:ot,Util:{replaceUppercase:it,trueColor:z,trueDimension:U}};var ut={prepareStart:function(t){return O(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(1e3*D(n,r,a)>>0)/1e3})}},ct={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:D},functions:ut},lt=String("abcdefghijklmnopqrstuvwxyz").split(""),pt=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),ft=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),ht=String("0123456789").split(""),dt=lt.concat(pt,ht),yt=dt.concat(ft),vt={alpha:lt,upper:pt,symbols:ft,numeric:ht,alphanumeric:dt,all:yt},gt={text:function(t){if(!e[t]&&this.valuesEnd[t]){var n=this._textChars,r=vt[d.textChars];n in vt?r=vt[n]:n&&n.length&&(r=n),e[t]=function(t,e,n,a){var i="",o="",s=""===n?" ":n,u=e.substring(0),c=n.substring(0),l=r[Math.random()*r.length>>0];" "===e?(o=c.substring(Math.min(a*c.length,c.length)>>0,0),t.innerHTML=a<1?o+l:s):" "===n?(i=u.substring(0,Math.min((1-a)*u.length,u.length)>>0),t.innerHTML=a<1?i+l:s):(i=u.substring(u.length,Math.min(a*u.length,u.length)>>0),o=c.substring(0,Math.min(a*c.length,c.length)>>0),t.innerHTML=a<1?o+l+i:s)}}},number:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(t,e,n,r){t.innerHTML=D(e,n,r)>>0})}};function mt(t,e){var n,r;if("string"==typeof t)return(r=document.createElement("SPAN")).innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){var a=t.innerHTML;(n=document.createElement("SPAN")).className=e,n.innerHTML=a,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&(n=t.children[0]);return n}function bt(t,e){var n=[],r=t.children.length;if(r){for(var a,i=[],o=t.innerHTML,s=0,u=void 0,c=void 0,l=void 0;s>0)/1e3+n+")"}function wt(t,e,n,r){for(var a=[],i=0;i<3;i+=1)a[i]=(t[i]||e[i]?(1e3*(t[i]+(e[i]-t[i])*r)>>0)/1e3:0)+n;return"translate3d("+a.join(",")+")"}function Et(t,e,n,r){var a="";return a+=t[0]||e[0]?"rotateX("+(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3+n+")":"",a+=t[1]||e[1]?"rotateY("+(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3+n+")":"",a+=t[2]||e[2]?"rotateZ("+(1e3*(t[2]+(e[2]-t[2])*r)>>0)/1e3+n+")":""}function Mt(t,e,n){return"scale("+(1e3*(t+(e-t)*n)>>0)/1e3+")"}function _t(t,e,n,r){var a=[];return a[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","skew("+a.join(",")+")"}function kt(t,e){return parseFloat(t)/100*e}function Ct(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Ot(t){var e=t.getAttribute("points").split(" "),n=0;if(e.length>1){var r=function(t){var e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},a=function(t,e){return void 0!==t&&void 0!==e?Math.sqrt(Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)):0};if(e.length>2)for(var i=0;i>0)/100,i=0-(100*D(e.s,n.s,r)>>0)/100,o=(100*D(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=i+"px",t.style.strokeDasharray=(100*(o<1?0:o)>>0)/100+"px, "+a+"px"})}};function Lt(t,e,n){if(t[n].length>7){t[n].shift();for(var r=t[n],a=n;r.length;)e[n]="A",t.splice(a+=1,0,["C"].concat(r.splice(0,6)));t.splice(n,1)}}var Nt={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){var e=t.pathValue[t.segmentStart],n=e.toLowerCase(),r=t.data;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Nt[n]&&(t.segments.push([e].concat(r.splice(0,Nt[n]))),Nt[n]););}var Vt="Invalid path value";function Ht(t){var e=t.index,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=Vt+': invalid Arc flag "'+n+'", expecting 0 or 1 at index '+e)}function Qt(t){return t>=48&&t<=57}function Ft(t){var e,n=t.max,r=t.pathValue,a=t.index,i=a,o=!1,s=!1,u=!1,c=!1;if(i>=n)t.err=Vt+" at "+i+": missing param "+r[i];else if(43!==(e=r.charCodeAt(i))&&45!==e||(e=(i+=1)=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0);)t.index+=1}function Dt(t){return t>=48&&t<=57||43===t||45===t||46===t}function Xt(t){var e=t.max,n=t.pathValue,r=t.index,a=n.charCodeAt(r),i=Nt[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(a))if(t.index+=1,Ut(t),t.data=[],i){for(;;){for(var o=i;o>0;o-=1){if(97!=(32|a)||3!==o&&4!==o?Ft(t):Ht(t),t.err.length)return;t.data.push(t.param),Ut(t),t.index=t.max)break;if(!Dt(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=Vt+": "+n[r]+" not a path command"}function Zt(t){return t.map((function(t){return Array.isArray(t)?[].concat(t):t}))}function Bt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Rt(t){return Array.isArray(t)&&t.every((function(t){var e=t[0].toLowerCase();return Nt[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Yt(t){if(Rt(t))return Zt(t);var e=new Bt(t);for(Ut(e);e.index1&&(m*=O=Math.sqrt(O),b*=O);var T=m*m,S=b*b,I=(i===o?-1:1)*Math.sqrt(Math.abs((T*S-T*C*C-S*k*k)/(T*C*C+S*k*k)));d=I*m*C/b+(v+x)/2,y=I*-b*k/m+(g+w)/2,f=(Math.asin((g-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),h=(Math.asin((w-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),f=vh&&(f-=2*Math.PI),!o&&h>f&&(h-=2*Math.PI)}var j=h-f;if(Math.abs(j)>E){var A=h,P=x,L=w;h=f+E*(o&&h>f?1:-1),_=ee(x=d+m*Math.cos(h),w=y+b*Math.sin(h),m,b,a,0,o,P,L,[h,A,d,y])}j=h-f;var N=Math.cos(f),q=Math.sin(f),V=Math.cos(h),H=Math.sin(h),Q=Math.tan(j/4),F=4/3*m*Q,U=4/3*b*Q,D=[v,g],X=[v+F*q,g-U*N],Z=[x+F*H,w-U*V],B=[x,w];if(X[0]=2*D[0]-X[0],X[1]=2*D[1]-X[1],c)return X.concat(Z,B,_);for(var R=[],Y=0,z=(_=X.concat(Z,B,_)).length;Yi+.001)return{x:n,y:r};var o=re([t,e],[n,r],a/i);return{x:o[0],y:o[1]}}return i}function oe(t,e,n,r){var a=.5,i=[t,e],o=[n,r],s=re(i,o,a),u=re(o,s,a),c=re(s,u,a),l=re(u,c,a),p=re(c,l,a),f=i.concat(s,c,p,[a]),h=ie.apply(void 0,f),d=p.concat(l,u,o,[0]),y=ie.apply(void 0,d);return[h.x,h.y,y.x,y.y,n,r]}function se(t,e){var n,r=t[0],a=t.slice(1).map((function(t){return+t})),i=a[0],o=a[1],s=e.x1,u=e.y1,c=e.x,l=e.y;switch("TQ".includes(r)||(e.qx=null,e.qy=null),r){case"M":return e.x=i,e.y=o,t;case"A":return n=[s,u].concat(a),["C"].concat(ee.apply(void 0,n));case"Q":return e.qx=i,e.qy=o,n=[s,u].concat(a),["C"].concat(ne.apply(void 0,n));case"L":return["C"].concat(oe(s,u,i,o));case"Z":return["C"].concat(oe(s,u,c,l))}return t}var ue=4;function ce(t,e){var n=ue;if(!1===e||!1===n)return Zt(t);var r=(n=e>=1?e:n)>=1?Math.pow(10,n):1;return t.map((function(t){var e=t.slice(1).map(Number).map((function(t){return t%1==0?t:Math.round(t*r)/r}));return[t[0]].concat(e)}))}function le(t,e){return ce(t,e).map((function(t){return t[0]+t.slice(1).join(" ")})).join("")}function pe(t,e,n,r,a,i,o,s,u){var c=1-u;return{x:Math.pow(c,3)*t+3*Math.pow(c,2)*u*n+3*c*Math.pow(u,2)*a+Math.pow(u,3)*o,y:Math.pow(c,3)*e+3*Math.pow(c,2)*u*r+3*c*Math.pow(u,2)*i+Math.pow(u,3)*s}}function fe(t,e,n,r,a,i,o,s,u){var c,l=t,p=e,f=0,h=[t,e,f],d=[t,e];if("number"==typeof u&&u<.001)return{x:l,y:p};for(var y=0;y<=100;y+=1){if(f+=ae(d,[l=(c=pe(t,e,n,r,a,i,o,s,y/100)).x,p=c.y]),d=[l,p],"number"==typeof u&&f>=u){var v=(f-u)/(f-h[2]);return{x:d[0]*(1-v)+h[0]*v,y:d[1]*(1-v)+h[1]*v}}h=[l,p,f]}return"number"==typeof u&&u>=f?{x:o,y:s}:f}function he(t,e,n,r,a,i,o,s,u,c){var l,p=[t,e],f=p[0],h=p[1],d=ee(t,e,n,r,a,i,o,s,u),y=0,v=[],g=[],m=0;if("number"==typeof c&&c<.001)return{x:f,y:h};for(var b=0,x=d.length;b=c)return fe.apply(void 0,g.concat([c-y]));y+=m,f=(l=v.slice(-2))[0],h=l[1]}return"number"==typeof c&&c>=y?{x:s,y:u}:y}function de(t,e,n,r,a,i,o){var s=1-o;return{x:Math.pow(s,2)*t+2*s*o*n+Math.pow(o,2)*a,y:Math.pow(s,2)*e+2*s*o*r+Math.pow(o,2)*i}}function ye(t,e,n,r,a,i,o){var s,u=t,c=e,l=0,p=[t,e,l],f=[t,e];if("number"==typeof o&&o<.001)return{x:u,y:c};for(var h=0;h<=100;h+=1){if(l+=ae(f,[u=(s=de(t,e,n,r,a,i,h/100)).x,c=s.y]),f=[u,c],"number"==typeof o&&l>=o){var d=(l-o)/(l-p[2]);return{x:f[0]*(1-d)+p[0]*d,y:f[1]*(1-d)+p[1]*d}}p=[u,c,l]}return"number"==typeof o&&o>=l?{x:a,y:i}:l}function ve(t,e){for(var n,r,a,i=0,o=!0,s=[],u="M",c=0,l=0,p=0,f=0,h=0,d=Jt(Gt(t)),y=0,v=d.length;y=e)return ie.apply(void 0,s.concat([e-i]));i+=c}else if("A"===u){if(c=he.apply(void 0,s),e&&i+c>=e)return he.apply(void 0,s.concat([e-i]));i+=c}else if("C"===u){if(c=fe.apply(void 0,s),e&&i+c>=e)return fe.apply(void 0,s.concat([e-i]));i+=c}else if("Q"===u){if(c=ye.apply(void 0,s),e&&i+c>=e)return ye.apply(void 0,s.concat([e-i]));i+=c}else if("Z"===u){if(s=[l,p,f,h],c=ie.apply(void 0,s),e&&i+c>=e)return ie.apply(void 0,s.concat([e-i]));i+=c}l=(r="Z"!==u?a.slice(-2):[f,h])[0],p=r[1]}return e&&e>=i?{x:l,y:p}:i}function ge(t){return ve(t)}function me(t,e){return ve(t,e)}function be(t){for(var e,n=t.length,r=-1,a=t[n-1],i=0;++r>0)/1e3)}return a}function we(t,e){var n,r,a=Gt((n=le(t),le(Kt(n),0).replace(/(m|M)/g,"|$1").split("|").map((function(t){return t.trim()})).filter((function(t){return t})))[0]),i=ge(a),o=[],s=3;e&&!Number.isNaN(e)&&+e>0&&(s=Math.max(s,Math.ceil(i/e)));for(var u=0;u0&&o.reverse(),{polygon:o,skipBisect:!0}}function Ee(t,e){var n=Gt(t);return function(t){var e=[],n=t.length,r=[],a="";if(!t.length||"M"!==t[0][0])return!1;for(var i=0;ie;)r=re(n,r,.5),t.splice(a+1,0,r)}function Ce(t){return Array.isArray(t)&&t.every((function(t){return Array.isArray(t)&&2===t.length&&!Number.isNaN(t[0])&&!Number.isNaN(t[1])}))}function Oe(t,e){var n,r,a;if("string"==typeof t)a=(n=Ee(t,e)).polygon,r=n.skipBisect;else if(!Array.isArray(t))throw Error(Vt+": "+t);var i=[].concat(a);if(!Ce(i))throw Error(Vt+": "+i);return i.length>1&&ae(i[0],i[i.length-1])<1e-9&&i.pop(),!r&&e&&!Number.isNaN(e)&&+e>0&&ke(i,e),i}function Te(t,e,n){var r=n||d.morphPrecision,a=Oe(t,r),i=Oe(e,r),o=a.length-i.length;return _e(a,o<0?-1*o:0),_e(i,o>0?o:0),Me(a,i),[ce(a),ce(i)]}var Se={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){var n={},r=new RegExp("\\n","ig"),a=null;return e instanceof SVGPathElement?a=e:/^\.|^#/.test(e)&&(a=P(e)),"object"==typeof e&&e.polygon?e:(a&&["path","glyph"].includes(a.tagName)?n.original=a.getAttribute("d").replace(r,""):a||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,e,n,r){var a=e.polygon,i=n.polygon,o=i.length;t.setAttribute("d",1===r?n.original:"M"+xe(a,i,o,r).join("L")+"Z")})},crossCheck:function(t){if(this.valuesEnd[t]){var e=this.valuesStart[t].polygon,n=this.valuesEnd[t].polygon;if(!e||!n||e&&n&&e.length!==n.length){var r=Te(this.valuesStart[t].original,this.valuesEnd[t].original,this._morphPrecision?parseInt(this._morphPrecision,10):d.morphPrecision),a=r[0],i=r[1];this.valuesStart[t].polygon=a,this.valuesEnd[t].polygon=i}}}},Ie={EssentialBoxModel:Y,ColorsProperties:et,HTMLAttributes:st,OpacityProperty:ct,TextWriteProp:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:D},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:gt},Util:{charSet:vt,createTextTweens:function(t,e,n){if(t.playing)return!1;var r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);var a=j.tween,i=function(t,e){var n=bt(t,"text-part"),r=bt(mt(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((function(t){return t.className+=" oldText",t.outerHTML})).join(""),t.innerHTML+=r.map((function(t){return t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")})).join(""),[n,r]}(t,e),o=i[0],s=i[1],u=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText")),l=[],p=0;return(l=(l=l.concat(u.map((function(t,e){return r.duration="auto"===r.duration?75*o[e].innerHTML.length:r.duration,r.delay=p,r.onComplete=null,p+=r.duration,new a(t,{text:t.innerHTML},{text:""},r)})))).concat(c.map((function(n,i){return r.duration="auto"===r.duration?75*s[i].innerHTML.length:r.duration,r.delay=p,r.onComplete=i===s.length-1?function(){t.innerHTML=e,t.playing=!1}:null,p+=r.duration,new a(n,{text:""},{text:s[i].innerHTML},r)})))).start=function(){t.playing||(l.forEach((function(t){return t.start()})),t.playing=!0)},l}}},TransformFunctions:{component:"transformFunctions",property:"transform",subProperties:["perspective","translate3d","translateX","translateY","translateZ","translate","rotate3d","rotateX","rotateY","rotateZ","rotate","skewX","skewY","skew","scale"],defaultValues:{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},functions:{prepareStart:function(t){var e=C(this.element);return e[t]?e[t]:h[t]},prepareProperty:function(t,e){var n=["X","Y","Z"],r={},a=[],i=[],o=[],s=["translate3d","translate","rotate3d","skew"];return Object.keys(e).forEach((function(t){var u="object"==typeof e[t]&&e[t].length?e[t].map((function(t){return parseInt(t,10)})):parseInt(e[t],10);if(s.includes(t)){var c="translate"===t||"rotate"===t?t+"3d":t;r[c]="skew"===t?u.length?[u[0]||0,u[1]||0]:[u||0,0]:"translate"===t?u.length?[u[0]||0,u[1]||0,u[2]||0]:[u||0,0,0]:[u[0]||0,u[1]||0,u[2]||0]}else if(/[XYZ]/.test(t)){var l=t.replace(/[XYZ]/,""),p="skew"===l?l:l+"3d",f="skew"===l?2:3,h=[];"translate"===l?h=a:"rotate"===l?h=i:"skew"===l&&(h=o);for(var d=0;d>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","translate("+a.join(",")+")"},rotate:function(t,e,n,r){return"rotate("+(1e3*(t+(e-t)*r)>>0)/1e3+n+")"},scale:Mt,skew:_t}},SVGDraw:{component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:D},functions:Pt,Util:{getRectLength:Ct,getPolyLength:Ot,getLineLength:Tt,getCircleLength:St,getEllipseLength:It,getTotalLength:jt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:At,percent:kt}},SVGMorph:{component:"svgMorph",property:"path",defaultValue:[],Interpolate:xe,defaultOptions:{morphPrecision:10},functions:Se,Util:{addPoints:_e,bisect:ke,getPolygon:Oe,validPolygon:Ce,getInterpolationPoints:Te,pathStringToPolygon:Ee,distanceSquareRoot:ae,midPoint:re,approximatePolygon:we,rotatePolygon:Me,pathToString:le,pathToCurve:function(t){if(function(t){return Rt(t)&&t.every((function(t){return"MC".includes(t[0])}))}(t))return Zt(t);for(var e=Jt(Gt(t)),n=Object.assign({},Wt),r=[],a="",i=e.length,o=0;o number} a new CubicBezier easing function + */ + constructor(p1x, p1y, p2x, p2y, functionName) { + // pre-calculate the polynomial coefficients + // First and last control points are implied to be (0,0) and (1.0, 1.0) + + /** @type {number} */ + this.cx = 3.0 * p1x; + + /** @type {number} */ + this.bx = 3.0 * (p2x - p1x) - this.cx; + + /** @type {number} */ + this.ax = 1.0 - this.cx - this.bx; + + /** @type {number} */ + this.cy = 3.0 * p1y; + + /** @type {number} */ + this.by = 3.0 * (p2y - p1y) - this.cy; + + /** @type {number} */ + this.ay = 1.0 - this.cy - this.by; + + /** @type {(t: number) => number} */ + const BezierEasing = (t) => this.sampleCurveY(this.solveCurveX(t)); + + // this function needs a name + Object.defineProperty(BezierEasing, 'name', { writable: true }); + BezierEasing.name = functionName || `cubic-bezier(${[p1x, p1y, p2x, p2y]})`; + + return BezierEasing; + } + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled X value + */ + sampleCurveX(t) { + return ((this.ax * t + this.bx) * t + this.cx) * t; + } + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled Y value + */ + sampleCurveY(t) { + return ((this.ay * t + this.by) * t + this.cy) * t; + } + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled curve derivative X value + */ + sampleCurveDerivativeX(t) { + return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx; + } + + /** + * @param {number} x - progress [0-1] + * @return {number} - solved curve X value + */ + solveCurveX(x) { + let t0; + let t1; + let t2; + let x2; + let d2; + let i; + const epsilon = 1e-5; // Precision + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 32; i += 1) { + x2 = this.sampleCurveX(t2) - x; + if (Math.abs(x2) < epsilon) return t2; + d2 = this.sampleCurveDerivativeX(t2); + if (Math.abs(d2) < epsilon) break; + t2 -= x2 / d2; + } + + // No solution found - use bi-section + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) return t0; + if (t2 > t1) return t1; + + while (t0 < t1) { + x2 = this.sampleCurveX(t2); + if (Math.abs(x2 - x) < epsilon) return t2; + if (x > x2) t0 = t2; + else t1 = t2; + + t2 = (t1 - t0) * 0.5 + t0; + } + + // Give up + return t2; + } +} + +var version$1 = "1.0.18"; + +// @ts-ignore + +/** + * A global namespace for library version. + * @type {string} + */ +const Version$1 = version$1; + +Object.assign(CubicBezier, { Version: Version$1 }); + +/** + * The KUTE.js Execution Context + */ +const KEC = {}; + +const Tweens = []; + +let gl0bal; + +if (typeof global !== 'undefined') gl0bal = global; +else if (typeof window !== 'undefined') gl0bal = window.self; +else gl0bal = {}; + +const globalObject = gl0bal; + +// KUTE.js INTERPOLATE FUNCTIONS +// ============================= +const interpolate = {}; + +// schedule property specific function on animation start +// link property update function to KUTE.js execution context +const onStart = {}; + +// Include a performance.now polyfill. +// source https://github.com/tweenjs/tween.js/blob/master/src/Now.ts +let performanceNow; + +// In node.js, use process.hrtime. +// eslint-disable-next-line +// @ts-ignore +if (typeof self === 'undefined' && typeof process !== 'undefined' && process.hrtime) { + performanceNow = () => { + // eslint-disable-next-line + // @ts-ignore + const time = process.hrtime(); + + // Convert [seconds, nanoseconds] to milliseconds. + return time[0] * 1000 + time[1] / 1000000; + }; +} else if (typeof self !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) { + // In a browser, use self.performance.now if it is available. + // This must be bound, because directly assigning this function + // leads to an invocation exception in Chrome. + performanceNow = self.performance.now.bind(self.performance); +} else if (typeof Date !== 'undefined' && Date.now) { + // Use Date.now if it is available. + performanceNow = Date.now; +} else { + // Otherwise, use 'new Date().getTime()'. + performanceNow = () => new Date().getTime(); +} + +const now = performanceNow; + +const Time = {}; +Time.now = now; + +// eslint-disable-next-line import/no-mutable-exports -- impossible to satisfy +let Tick = 0; + +/** + * + * @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); +}; + +// stop requesting animation frame +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; + +// all supported properties +const supportedProperties = {}; + +const defaultValues = {}; + +const defaultOptions$1 = { + duration: 700, + delay: 0, + easing: 'linear', + repeat: 0, + repeatDelay: 0, + yoyo: false, + resetStart: false, + offset: 0, +}; + +// used in preparePropertiesObject +const prepareProperty = {}; + +// check current property value when .to() method is used +const prepareStart = {}; + +// checks for differences between the processed start and end values, +// can be set to make sure start unit and end unit are same, +// stack transforms, process SVG paths, +// any type of post processing the component needs +const crossCheck = {}; + +// schedule property specific function on animation complete +const onComplete = {}; + +// link properties to interpolate functions +const linkProperty = {}; + +const Objects = { + supportedProperties, + defaultValues, + defaultOptions: defaultOptions$1, + prepareProperty, + prepareStart, + crossCheck, + onStart, + onComplete, + linkProperty, +}; + +// util - a general object for utils like rgbToHex, processEasing +const Util = {}; + +/** + * KUTE.add(Tween) + * + * @param {KUTE.Tween} tw a new tween to add + */ +const add = (tw) => Tweens.push(tw); + +/** + * 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); +}; + +/** + * KUTE.add(Tween) + * + * @return {KUTE.Tween[]} tw a new tween to add + */ +const getAll = () => Tweens; + +/** + * KUTE.removeAll() + */ +const removeAll = () => { Tweens.length = 0; }; + +/** + * linkInterpolation + * @this {KUTE.Tween} + */ +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]; + } + }); + } + }); + } + }); + } + }); + }); +} + +const internals = { + add, + remove, + getAll, + removeAll, + stop, + linkInterpolation, +}; + +/** + * getInlineStyle + * Returns the transform style for element from + * cssText. Used by for the `.to()` static method. + * + * @param {Element} el target element + * @returns {object} + */ +function getInlineStyle(el) { + // if the scroll applies to `window` it returns as it has no styling + if (!el.style) return false; + // the cssText | the resulting transform object + const css = el.style.cssText.replace(/\s/g, '').split(';'); + const transformObject = {}; + const arrayFn = ['translate3d', 'translate', 'scale3d', 'skew']; + + css.forEach((cs) => { + if (/transform/i.test(cs)) { + // all transform properties + const tps = cs.split(':')[1].split(')'); + tps.forEach((tpi) => { + const tpv = tpi.split('('); + const tp = tpv[0]; + // each transform property + const tv = tpv[1]; + if (!/matrix/.test(tp)) { + transformObject[tp] = arrayFn.includes(tp) ? tv.split(',') : tv; + } + }); + } + }); + + return transformObject; +} + +/** + * getStyleForProperty + * + * Returns the computed style property for element for .to() method. + * Used by for the `.to()` static method. + * + * @param {Element} elem + * @param {string} propertyName + * @returns {string} + */ +function getStyleForProperty(elem, propertyName) { + let result = defaultValues[propertyName]; + const styleAttribute = elem.style; + const computedStyle = getComputedStyle(elem) || elem.currentStyle; + const styleValue = styleAttribute[propertyName] && !/auto|initial|none|unset/.test(styleAttribute[propertyName]) + ? styleAttribute[propertyName] + : computedStyle[propertyName]; + + if (propertyName !== 'transform' && (propertyName in computedStyle || propertyName in styleAttribute)) { + result = styleValue; + } + + return result; +} + +/** + * prepareObject + * + * Returns all processed valuesStart / valuesEnd. + * + * @param {Element} obj the values start/end object + * @param {string} fn toggles between the two + */ +function prepareObject(obj, fn) { // this, props object, type: start/end + const propertiesObject = fn === 'start' ? this.valuesStart : this.valuesEnd; + + Object.keys(prepareProperty).forEach((component) => { + const prepareComponent = prepareProperty[component]; + const supportComponent = supportedProperties[component]; + + Object.keys(prepareComponent).forEach((tweenCategory) => { + const transformObject = {}; + + Object.keys(obj).forEach((tweenProp) => { + // scroll, opacity, other components + if (defaultValues[tweenProp] && prepareComponent[tweenProp]) { + propertiesObject[tweenProp] = prepareComponent[tweenProp] + .call(this, tweenProp, obj[tweenProp]); + + // transform + } else if (!defaultValues[tweenCategory] && tweenCategory === 'transform' + && supportComponent.includes(tweenProp)) { + transformObject[tweenProp] = obj[tweenProp]; + + // allow transformFunctions to work with preprocessed input values + } else if (!defaultValues[tweenProp] && tweenProp === 'transform') { + propertiesObject[tweenProp] = obj[tweenProp]; + + // colors, boxModel, category + } else if (!defaultValues[tweenCategory] + && supportComponent && supportComponent.includes(tweenProp)) { + propertiesObject[tweenProp] = prepareComponent[tweenCategory] + .call(this, tweenProp, obj[tweenProp]); + } + }); + + // we filter out older browsers by checking Object.keys + if (Object.keys(transformObject).length) { + propertiesObject[tweenCategory] = prepareComponent[tweenCategory] + .call(this, tweenCategory, transformObject); + } + }); + }); +} + +/** + * getStartValues + * + * Returns the start values for to() method. + * Used by for the `.to()` static method. + * + * @this {KUTE.Tween} the tween instance + */ +function getStartValues() { + const startValues = {}; + const currentStyle = getInlineStyle(this.element); + + Object.keys(this.valuesStart).forEach((tweenProp) => { + Object.keys(prepareStart).forEach((component) => { + const componentStart = prepareStart[component]; + + Object.keys(componentStart).forEach((tweenCategory) => { + // clip, opacity, scroll + if (tweenCategory === tweenProp && componentStart[tweenProp]) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this, tweenProp, this.valuesStart[tweenProp]); + // find in an array of properties + } else if (supportedProperties[component] + && supportedProperties[component].includes(tweenProp)) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this, tweenProp, this.valuesStart[tweenProp]); + } + }); + }); + }); + + // stack transformCSS props for .to() chains + // also add to startValues values from previous tweens + Object.keys(currentStyle).forEach((current) => { + if (!(current in this.valuesStart)) { + startValues[current] = currentStyle[current] || defaultValues[current]; + } + }); + + this.valuesStart = {}; + prepareObject.call(this, startValues, 'start'); +} + +var Process = { + getInlineStyle, + getStyleForProperty, + getStartValues, + prepareObject, +}; + +const connect = {}; +/** @type {KUTE.TweenBase | KUTE.Tween | KUTE.TweenExtra} */ +connect.tween = null; +connect.processEasing = null; + +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; + +/** + * selector + * + * A selector utility for KUTE.js. + * + * @param {KUTE.selectorType} el target(s) or string selector + * @param {boolean | number} multi when true returns an array/collection of elements + * @returns {Element | Element[] | null} + */ +function selector(el, multi) { + try { + let requestedElem; + let itemsArray; + if (multi) { + itemsArray = el instanceof Array && el.every((x) => x instanceof Element); + requestedElem = el instanceof HTMLCollection || el instanceof NodeList || itemsArray + ? el : document.querySelectorAll(el); + } else { + requestedElem = el instanceof Element || el === window // scroll + ? el : document.querySelector(el); + } + return requestedElem; + } catch (e) { + throw TypeError(`KUTE.js - Element(s) not found: ${el}.`); + } +} + +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); +} + +/** + * The `TweenBase` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * `TweenBase` is meant to be used with pre-processed values. + */ +class TweenBase { + /** + * @param {Element} targetElement the target element + * @param {KUTE.tweenProps} startObject the start values + * @param {KUTE.tweenProps} endObject the end values + * @param {KUTE.tweenOptions} opsObject the end values + * @returns {TweenBase} the resulting Tween object + */ + constructor(targetElement, startObject, endObject, opsObject) { + // element animation is applied to + this.element = targetElement; + + /** @type {boolean} */ + this.playing = false; + /** @type {number?} */ + this._startTime = null; + /** @type {boolean} */ + this._startFired = false; + + // type is set via KUTE.tweenProps + this.valuesEnd = endObject; + this.valuesStart = startObject; + + // OPTIONS + const options = opsObject || {}; + // internal option to process inline/computed style at start instead of init + // used by to() method and expects object : {} / false + this._resetStart = options.resetStart || 0; + // you can only set a core easing function as default + /** @type {KUTE.easingOption} */ + this._easing = typeof (options.easing) === 'function' ? options.easing : connect.processEasing(options.easing); + /** @type {number} */ + this._duration = options.duration || defaultOptions$1.duration; // duration option | default + /** @type {number} */ + this._delay = options.delay || defaultOptions$1.delay; // delay option | default + + // set other options + Object.keys(options).forEach((op) => { + const internalOption = `_${op}`; + if (!(internalOption in this)) this[internalOption] = options[op]; + }); + + // callbacks should not be set as undefined + // this._onStart = options.onStart + // this._onUpdate = options.onUpdate + // this._onStop = options.onStop + // this._onComplete = options.onComplete + + // queue the easing + const easingFnName = this._easing.name; + if (!onStart[easingFnName]) { + onStart[easingFnName] = function easingFn(prop) { + if (!KEC[prop] && prop === this._easing.name) KEC[prop] = this._easing; + }; + } + + return this; + } + + /** + * Starts tweening + * @param {number?} time the tween start time + * @returns {TweenBase} this instance + */ + start(time) { + // now it's a good time to start + add(this); + this.playing = true; + + this._startTime = typeof time !== 'undefined' ? time : KEC.Time(); + this._startTime += this._delay; + + if (!this._startFired) { + if (this._onStart) { + this._onStart.call(this); + } + + queueStart.call(this); + + this._startFired = true; + } + + if (!Tick) Ticker(); + return this; + } + + /** + * Stops tweening + * @returns {TweenBase} this instance + */ + stop() { + if (this.playing) { + remove(this); + this.playing = false; + + if (this._onStop) { + this._onStop.call(this); + } + this.close(); + } + return this; + } + + /** + * Trigger internal completion callbacks. + */ + close() { + // scroll|transformMatrix need this + Object.keys(onComplete).forEach((component) => { + Object.keys(onComplete[component]).forEach((toClose) => { + onComplete[component][toClose].call(this, toClose); + }); + }); + // when all animations are finished, stop ticking after ~3 frames + this._startFired = false; + stop.call(this); + } + + /** + * Schedule another tween instance to start once this one completes. + * @param {KUTE.chainOption} args the tween animation start time + * @returns {TweenBase} this instance + */ + chain(args) { + this._chain = []; + this._chain = args.length ? args : this._chain.concat(args); + return this; + } + + /** + * Stop tweening the chained tween instances. + */ + stopChainedTweens() { + if (this._chain && this._chain.length) this._chain.forEach((tw) => tw.stop()); + } + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + update(time) { + const T = time !== undefined ? time : KEC.Time(); + + let elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + const progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach((tweenProp) => { + KEC[tweenProp](this.element, + this.valuesStart[tweenProp], + this.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.map((tw) => tw.start()); + } + + return false; + } + + return true; + } +} + +// Update Tween Interface +connect.tween = TweenBase; + +/** + * The `KUTE.Tween()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor adds additional functionality and is the default + * Tween object constructor in KUTE.js. + */ +class Tween extends TweenBase { + /** + * @param {KUTE.tweenParams} args (*target*, *startValues*, *endValues*, *options*) + * @returns {Tween} the resulting Tween object + */ + constructor(...args) { + super(...args); // this calls the constructor of TweenBase + + // reset interpolation values + this.valuesStart = {}; + this.valuesEnd = {}; + + // const startObject = args[1]; + // const endObject = args[2]; + const [startObject, endObject, options] = args.slice(1); + + // set valuesEnd + prepareObject.call(this, endObject, 'end'); + + // set valuesStart + if (this._resetStart) { + this.valuesStart = startObject; + } else { + prepareObject.call(this, startObject, 'start'); + } + + // ready for crossCheck + if (!this._resetStart) { + Object.keys(crossCheck).forEach((component) => { + Object.keys(crossCheck[component]).forEach((checkProp) => { + crossCheck[component][checkProp].call(this, checkProp); + }); + }); + } + + // set paused state + /** @type {boolean} */ + this.paused = false; + /** @type {number?} */ + this._pauseTime = null; + + // additional properties and options + /** @type {number?} */ + this._repeat = options.repeat || defaultOptions$1.repeat; + /** @type {number?} */ + this._repeatDelay = options.repeatDelay || defaultOptions$1.repeatDelay; + // we cache the number of repeats to be able to put it back after all cycles finish + /** @type {number?} */ + this._repeatOption = this._repeat; + + // yoyo needs at least repeat: 1 + /** @type {KUTE.tweenProps} */ + this.valuesRepeat = {}; // valuesRepeat + /** @type {boolean} */ + this._yoyo = options.yoyo || defaultOptions$1.yoyo; + /** @type {boolean} */ + this._reversed = false; + + // don't load extra callbacks + // this._onPause = options.onPause || defaultOptions.onPause + // this._onResume = options.onResume || defaultOptions.onResume + + // chained Tweens + // this._chain = options.chain || defaultOptions.chain; + return this; + } + + /** + * Starts tweening, extended method + * @param {number?} time the tween start time + * @returns {Tween} this instance + */ + start(time) { + // on start we reprocess the valuesStart for TO() method + if (this._resetStart) { + this.valuesStart = this._resetStart; + getStartValues.call(this); + + // this is where we do the valuesStart and valuesEnd check for fromTo() method + Object.keys(crossCheck).forEach((component) => { + Object.keys(crossCheck[component]).forEach((checkProp) => { + crossCheck[component][checkProp].call(this, checkProp); + }); + }); + } + // still not paused + this.paused = false; + + // set yoyo values + if (this._yoyo) { + Object.keys(this.valuesEnd).forEach((endProp) => { + this.valuesRepeat[endProp] = this.valuesStart[endProp]; + }); + } + + super.start(time); + + return this; + } + + /** + * Stops tweening, extended method + * @returns {Tween} this instance + */ + stop() { + super.stop(); + if (!this.paused && this.playing) { + this.paused = false; + this.stopChainedTweens(); + } + return this; + } + + /** + * Trigger internal completion callbacks. + */ + close() { + super.close(); + + if (this._repeatOption > 0) { + this._repeat = this._repeatOption; + } + if (this._yoyo && this._reversed === true) { + this.reverse(); + this._reversed = false; + } + + return this; + } + + /** + * Resume tweening + * @returns {Tween} this instance + */ + resume() { + if (this.paused && this.playing) { + this.paused = false; + if (this._onResume !== undefined) { + this._onResume.call(this); + } + // re-queue execution context + queueStart.call(this); + // update time and let it roll + this._startTime += KEC.Time() - this._pauseTime; + add(this); + // restart ticker if stopped + if (!Tick) Ticker(); + } + return this; + } + + /** + * Pause tweening + * @returns {Tween} this instance + */ + pause() { + if (!this.paused && this.playing) { + remove(this); + this.paused = true; + this._pauseTime = KEC.Time(); + if (this._onPause !== undefined) { + this._onPause.call(this); + } + } + return this; + } + + /** + * Reverses start values with end values + */ + reverse() { + Object.keys(this.valuesEnd).forEach((reverseProp) => { + const tmp = this.valuesRepeat[reverseProp]; + this.valuesRepeat[reverseProp] = this.valuesEnd[reverseProp]; + this.valuesEnd[reverseProp] = tmp; + this.valuesStart[reverseProp] = this.valuesRepeat[reverseProp]; + }); + } + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + update(time) { + const T = time !== undefined ? time : KEC.Time(); + + let elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + const progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach((tweenProp) => { + KEC[tweenProp](this.element, + this.valuesStart[tweenProp], + this.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + if (this._repeat > 0) { + if (Number.isFinite(this._repeat)) this._repeat -= 1; + + // set the right time for delay + this._startTime = T; + if (Number.isFinite(this._repeat) && this._yoyo && !this._reversed) { + this._startTime += this._repeatDelay; + } + + if (this._yoyo) { // handle yoyo + this._reversed = !this._reversed; + this.reverse(); + } + + return true; + } + + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.forEach((tw) => tw.start()); + } + + return false; + } + return true; + } +} + +// Update Tween Interface Update +connect.tween = Tween; + +/** + * The static method creates a new `Tween` object for each `HTMLElement` + * from and `Array`, `HTMLCollection` or `NodeList`. + */ +class TweenCollection { + /** + * + * @param {Element[] | HTMLCollection | NodeList} els target elements + * @param {KUTE.tweenProps} vS the start values + * @param {KUTE.tweenProps} vE the end values + * @param {KUTE.tweenOptions} Options tween options + * @returns {TweenCollection} the Tween object collection + */ + constructor(els, vS, vE, Options) { + const TweenConstructor = connect.tween; + /** @type {KUTE.twCollection[]} */ + this.tweens = []; + + const Ops = Options || {}; + /** @type {number?} */ + Ops.delay = Ops.delay || defaultOptions$1.delay; + + // set all options + const options = []; + + Array.from(els).forEach((el, i) => { + options[i] = Ops || {}; + options[i].delay = i > 0 ? Ops.delay + (Ops.offset || defaultOptions$1.offset) : Ops.delay; + if (el instanceof Element) { + this.tweens.push(new TweenConstructor(el, vS, vE, options[i])); + } else { + throw Error(`KUTE - ${el} is not instanceof Element`); + } + }); + + /** @type {number?} */ + this.length = this.tweens.length; + return this; + } + + /** + * Starts tweening, all targets + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + start(time) { + const T = time === undefined ? KEC.Time() : time; + this.tweens.map((tween) => tween.start(T)); + return this; + } + + /** + * Stops tweening, all targets and their chains + * @returns {TweenCollection} this instance + */ + stop() { + this.tweens.map((tween) => tween.stop()); + return this; + } + + /** + * Pause tweening, all targets + * @returns {TweenCollection} this instance + */ + pause() { + this.tweens.map((tween) => tween.pause()); + return this; + } + + /** + * Resume tweening, all targets + * @returns {TweenCollection} this instance + */ + resume() { + this.tweens.map((tween) => tween.resume()); + return this; + } + + /** + * Schedule another tween or collection to start after + * this one is complete. + * @param {number?} args the tween start time + * @returns {TweenCollection} this instance + */ + chain(args) { + const lastTween = this.tweens[this.length - 1]; + if (args instanceof TweenCollection) { + lastTween.chain(args.tweens); + } else if (args instanceof connect.tween) { + lastTween.chain(args); + } else { + throw new TypeError('KUTE.js - invalid chain value'); + } + return this; + } + + /** + * Check if any tween instance is playing + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + playing() { + return this.tweens.some((tw) => tw.playing); + } + + /** + * Remove all tweens in the collection + */ + removeTweens() { + this.tweens = []; + } + + /** + * Returns the maximum animation duration + * @returns {number} this instance + */ + getMaxDuration() { + const durations = []; + this.tweens.forEach((tw) => { + durations.push(tw._duration + tw._delay + tw._repeat * tw._repeatDelay); + }); + return Math.max(durations); + } +} + +const { tween: TweenConstructor$1 } = connect; + +/** + * The `KUTE.to()` static method returns a new Tween object + * for a single `HTMLElement` at its current state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ +function to(element, endObject, optionsObj) { + const options = optionsObj || {}; + options.resetStart = endObject; + return new TweenConstructor$1(selector(element), endObject, endObject, options); +} + +const { tween: TweenConstructor } = connect; + +/** + * The `KUTE.fromTo()` static method returns a new Tween object + * for a single `HTMLElement` at a given state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ +function fromTo(element, startObject, endObject, optionsObj) { + const options = optionsObj || {}; + return new TweenConstructor(selector(element), startObject, endObject, options); +} + +/** + * The `KUTE.allTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at their current state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenProps} optionsObj progress + * @returns {TweenCollection} the Tween object collection + */ +function allTo(elements, endObject, optionsObj) { + const options = optionsObj || {}; + options.resetStart = endObject; + return new TweenCollection(selector(elements, true), endObject, endObject, options); +} + +/** + * The `KUTE.allFromTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at a given state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {TweenCollection} the Tween object collection + */ +function allFromTo(elements, startObject, endObject, optionsObj) { + const options = optionsObj || {}; + return new TweenCollection(selector(elements, true), startObject, endObject, options); +} + +/** + * Animation Class + * + * Registers components by populating KUTE.js objects and makes sure + * no duplicate component / property is allowed. + */ +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$1, 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; + } +} + +/** + * trueDimension + * + * Returns the string value of a specific CSS property converted into a nice + * { v = value, u = unit } object. + * + * @param {string} dimValue the property string value + * @param {boolean | number} isAngle sets the utility to investigate angles + * @returns {{v: number, u: string}} the true {value, unit} tuple + */ +const trueDimension = (dimValue, isAngle) => { + const intValue = parseInt(dimValue, 10) || 0; + const mUnits = ['px', '%', 'deg', 'rad', 'em', 'rem', 'vh', 'vw']; + let theUnit; + + for (let mIndex = 0; mIndex < mUnits.length; mIndex += 1) { + if (typeof dimValue === 'string' && dimValue.includes(mUnits[mIndex])) { + theUnit = mUnits[mIndex]; break; + } + } + if (theUnit === undefined) { + theUnit = isAngle ? 'deg' : 'px'; + } + + return { v: intValue, u: theUnit }; +}; + +/** + * Numbers Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {number} v progress + * @returns {number} the interpolated number + */ +function numbers(a, b, v) { + const A = +a; + const B = b - a; + // a = +a; b -= a; + return A + B * v; +} + +// Component Functions +/** + * Sets the update function for the property. + * @param {string} tweenProp the property name + */ +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 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 }, +}; + +/** + * hexToRGB + * + * Converts a #HEX color format into RGB + * and returns a color object {r,g,b}. + * + * @param {string} hex the degree angle + * @returns {KUTE.colorObject | null} the radian angle + */ +const hexToRGB = (hex) => { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const hexShorthand = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + const HEX = hex.replace(hexShorthand, (_, r, g, b) => r + r + g + g + b + b); + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(HEX); + + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } : null; +}; + +/** + * trueColor + * + * Transform any color to rgba()/rgb() and return a nice RGB(a) object. + * + * @param {string} colorString the color input + * @returns {KUTE.colorObject} the {r,g,b,a} color object + */ +const trueColor = (colorString) => { + let result; + if (/rgb|rgba/.test(colorString)) { // first check if it's a rgb string + const vrgb = colorString.replace(/\s|\)/, '').split('(')[1].split(','); + const colorAlpha = vrgb[3] ? vrgb[3] : null; + if (!colorAlpha) { + result = { r: parseInt(vrgb[0], 10), g: parseInt(vrgb[1], 10), b: parseInt(vrgb[2], 10) }; + } + result = { + r: parseInt(vrgb[0], 10), + g: parseInt(vrgb[1], 10), + b: parseInt(vrgb[2], 10), + a: parseFloat(colorAlpha), + }; + } if (/^#/.test(colorString)) { + const fromHex = hexToRGB(colorString); + result = { r: fromHex.r, g: fromHex.g, b: fromHex.b }; + } if (/transparent|none|initial|inherit/.test(colorString)) { + result = { + r: 0, g: 0, b: 0, a: 0, + }; + } + // maybe we can check for web safe colors + // only works in a browser + if (!/^#|^rgb/.test(colorString)) { + const siteHead = document.getElementsByTagName('head')[0]; + siteHead.style.color = colorString; + let webColor = getComputedStyle(siteHead, null).color; + webColor = /rgb/.test(webColor) ? webColor.replace(/[^\d,]/g, '').split(',') : [0, 0, 0]; + siteHead.style.color = ''; + result = { + r: parseInt(webColor[0], 10), + g: parseInt(webColor[1], 10), + b: parseInt(webColor[2], 10), + }; + } + return result; +}; + +/** + * Color Interpolation Function. + * + * @param {KUTE.colorObject} a start color + * @param {KUTE.colorObject} b end color + * @param {number} v progress + * @returns {string} the resulting color + */ +function colors(a, b, v) { + const _c = {}; + const ep = ')'; + const cm = ','; + const rgb = 'rgb('; + const rgba = 'rgba('; + + Object.keys(b).forEach((c) => { + if (c !== 'a') { + _c[c] = numbers(a[c], b[c], v) >> 0 || 0; // eslint-disable-line no-bitwise + } else if (a[c] && b[c]) { + _c[c] = (numbers(a[c], b[c], v) * 100 >> 0) / 100; // eslint-disable-line no-bitwise + } + }); + + return !_c.a + ? rgb + _c.r + cm + _c.g + cm + _c.b + ep + : rgba + _c.r + cm + _c.g + cm + _c.b + cm + _c.a + ep; +} + +// 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$1 = [ + 'color', 'backgroundColor', 'outlineColor', + 'borderColor', + 'borderTopColor', 'borderRightColor', + 'borderBottomColor', 'borderLeftColor', +]; + +// Component Functions +/** + * Sets the property update function. + * @param {string} tweenProp the property name + */ +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$1 = {}; +supportedColors$1.forEach((x) => { colorsOnStart$1[x] = onStartColors; }); + +// 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 }, +}; + +// Component Special +const attributes = {}; + +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 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 + */ +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 + */ +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 }, +}; + +/* opacityProperty = { + property: 'opacity', + defaultValue: 1, + interpolators: {numbers}, + functions = { prepareStart, prepareProperty, onStart } +} */ + +// Component Functions +/** + * Sets the property update function. + * @param {string} tweenProp the property name + */ +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 */ + }; + } +} + +// 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, +}; + +// 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, +}; + +// Component Functions +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$1.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 */ + }; + } + }, +}; + +// 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]; +} + +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 +const textWriteFunctions = { + prepareStart: getWrite, + prepareProperty: prepareText, + onStart: onStartWrite, +}; + +// Full Component +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 }, +}; + +/** + * Perspective Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the perspective function in string format + */ +function perspective(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `perspective(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} + +/** + * Translate 3D Interpolation Function. + * + * @param {number[]} a start [x,y,z] position + * @param {number[]} b end [x,y,z] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D translation string + */ +function translate3d(a, b, u, v) { + const translateArray = []; + for (let ax = 0; ax < 3; ax += 1) { + translateArray[ax] = (a[ax] || b[ax] + // eslint-disable-next-line no-bitwise + ? ((a[ax] + (b[ax] - a[ax]) * v) * 1000 >> 0) / 1000 : 0) + u; + } + return `translate3d(${translateArray.join(',')})`; +} + +/** + * 3D Rotation Interpolation Function. + * + * @param {number} a start [x,y,z] angles + * @param {number} b end [x,y,z] angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D rotation string + */ +function rotate3d(a, b, u, v) { + let rotateStr = ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[0] || b[0] ? `rotateX(${((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000}${u})` : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[1] || b[1] ? `rotateY(${((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000}${u})` : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[2] || b[2] ? `rotateZ(${((a[2] + (b[2] - a[2]) * v) * 1000 >> 0) / 1000}${u})` : ''; + return rotateStr; +} + +/** + * Translate 2D Interpolation Function. + * + * @param {number[]} a start [x,y] position + * @param {number[]} b end [x,y] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 2D translation string + */ +function translate(a, b, u, v) { + const translateArray = []; + // eslint-disable-next-line no-bitwise + translateArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + translateArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return `translate(${translateArray.join(',')})`; +} + +/** + * 2D Rotation Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated rotation + */ +function rotate(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `rotate(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} + +/** + * Scale Interpolation Function. + * + * @param {number} a start scale + * @param {number} b end scale + * @param {number} v progress + * @returns {string} the interpolated scale + */ +function scale(a, b, v) { + // eslint-disable-next-line no-bitwise + return `scale(${((a + (b - a) * v) * 1000 >> 0) / 1000})`; +} + +/** + * Skew Interpolation Function. + * + * @param {number} a start {x,y} angles + * @param {number} b end {x,y} angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated string value of skew(s) + */ +function skew(a, b, u, v) { + const skewArray = []; + // eslint-disable-next-line no-bitwise + skewArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + skewArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return `skew(${skewArray.join(',')})`; +} + +// Component Functions +/** + * Sets the property update function. + * * same to svgTransform, htmlAttributes + * @param {string} tweenProp the property name + */ +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 + }; + } +} + +// 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} 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, + }, +}; + +// Component Functions +/** + * Sets the property update function. + * @param {string} tweenProp the property name + */ +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 Util +/** + * Convert a `` 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 `` 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 `` length + */ +function getRectLength(el) { + const w = el.getAttribute('width'); + const h = el.getAttribute('height'); + return (w * 2) + (h * 2); +} + +/** + * Returns the `` / `` 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 `` 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 `` 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 `` 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$1(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$1(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: getTotalLength$1, + resetDraw, + getDraw, + percent, + }, +}; + +/** + * Splits an extended A (arc-to) segment into two cubic-bezier segments. + * + * @param {SVGPathCommander.pathArray} path the `pathArray` this segment belongs to + * @param {string[]} allPathCommands all previous path commands + * @param {number} i the segment index + */ + +function fixArc(path, allPathCommands, i) { + if (path[i].length > 7) { + path[i].shift(); + const segment = path[i]; + let ni = i; // ESLint + while (segment.length) { + // if created multiple C:s, their original seg is saved + allPathCommands[i] = 'A'; + // @ts-ignore + path.splice(ni += 1, 0, ['C', ...segment.splice(0, 6)]); + } + path.splice(i, 1); + } +} + +/** + * Segment params length + * @type {Record} + */ +const paramsCount = { + a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0, +}; + +/** + * Breaks the parsing of a pathString once a segment is finalized. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ +function finalizeSegment(path) { + let pathCommand = path.pathValue[path.segmentStart]; + let LK = pathCommand.toLowerCase(); + let { data } = path; + + // Process duplicated commands (without comand name) + if (LK === 'm' && data.length > 2) { + // @ts-ignore + path.segments.push([pathCommand, data[0], data[1]]); + data = data.slice(2); + LK = 'l'; + pathCommand = pathCommand === 'm' ? 'l' : 'L'; + } + + // @ts-ignore + while (data.length >= paramsCount[LK]) { + // path.segments.push([pathCommand].concat(data.splice(0, paramsCount[LK]))); + // @ts-ignore + path.segments.push([pathCommand, ...data.splice(0, paramsCount[LK])]); + // @ts-ignore + if (!paramsCount[LK]) { + break; + } + } +} + +const invalidPathValue = 'Invalid path value'; + +/** + * Validates an A (arc-to) specific path command value. + * Usually a `large-arc-flag` or `sweep-flag`. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ +function scanFlag(path) { + const { index } = path; + const ch = path.pathValue.charCodeAt(index); + + if (ch === 0x30/* 0 */) { + path.param = 0; + path.index += 1; + return; + } + + if (ch === 0x31/* 1 */) { + path.param = 1; + path.index += 1; + return; + } + + path.err = `${invalidPathValue}: invalid Arc flag "${ch}", expecting 0 or 1 at index ${index}`; +} + +/** + * Checks if a character is a digit. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ +function isDigit(code) { + return (code >= 48 && code <= 57); // 0..9 +} + +/** + * Validates every character of the path string, + * every path command, negative numbers or floating point numbers. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ +function scanParam(path) { + const { max, pathValue, index: start } = path; + let index = start; + let zeroFirst = false; + let hasCeiling = false; + let hasDecimal = false; + let hasDot = false; + let ch; + + if (index >= max) { + // path.err = 'SvgPath: missed param (at pos ' + index + ')'; + path.err = `${invalidPathValue} at ${index}: missing param ${pathValue[index]}`; + return; + } + ch = pathValue.charCodeAt(index); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + index += 1; + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + // This logic is shamelessly borrowed from Esprima + // https://github.com/ariya/esprimas + if (!isDigit(ch) && ch !== 0x2E/* . */) { + // path.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')'; + path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} is not a number`; + return; + } + + if (ch !== 0x2E/* . */) { + zeroFirst = (ch === 0x30/* 0 */); + index += 1; + + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + + if (zeroFirst && index < max) { + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDigit(ch)) { + // path.err = 'SvgPath: numbers started with `0` such as `09` + // are illegal (at pos ' + start + ')'; + path.err = `${invalidPathValue} at index ${start}: ${pathValue[start]} illegal number`; + return; + } + } + + while (index < max && isDigit(pathValue.charCodeAt(index))) { + index += 1; + hasCeiling = true; + } + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + if (ch === 0x2E/* . */) { + hasDot = true; + index += 1; + while (isDigit(pathValue.charCodeAt(index))) { + index += 1; + hasDecimal = true; + } + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + if (ch === 0x65/* e */ || ch === 0x45/* E */) { + if (hasDot && !hasCeiling && !hasDecimal) { + path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} invalid float exponent`; + return; + } + + index += 1; + + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + index += 1; + } + if (index < max && isDigit(pathValue.charCodeAt(index))) { + while (index < max && isDigit(pathValue.charCodeAt(index))) { + index += 1; + } + } else { + // path.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; + path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} invalid float exponent`; + return; + } + } + + path.index = index; + path.param = +path.pathValue.slice(start, index); +} + +/** + * Checks if the character is a space. + * + * @param {number} ch the character to check + * @returns {boolean} check result + */ +function isSpace(ch) { + const specialSpaces = [ + 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, + 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF]; + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) // Line terminators + // White spaces + || (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) + || (ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0); +} + +/** + * Points the parser to the next character in the + * path string every time it encounters any kind of + * space character. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ +function skipSpaces(path) { + const { pathValue, max } = path; + while (path.index < max && isSpace(pathValue.charCodeAt(path.index))) { + path.index += 1; + } +} + +/** + * Checks if the character is a path command. + * + * @param {any} code the character to check + * @returns {boolean} check result + */ +function isPathCommand(code) { + // eslint-disable-next-line no-bitwise -- Impossible to satisfy + switch (code | 0x20) { + case 0x6D/* m */: + case 0x7A/* z */: + case 0x6C/* l */: + case 0x68/* h */: + case 0x76/* v */: + case 0x63/* c */: + case 0x73/* s */: + case 0x71/* q */: + case 0x74/* t */: + case 0x61/* a */: + // case 0x72/* r */: + return true; + default: + return false; + } +} + +/** + * Checks if the character is or belongs to a number. + * [0-9]|+|-|. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ +function isDigitStart(code) { + return (code >= 48 && code <= 57) /* 0..9 */ + || code === 0x2B /* + */ + || code === 0x2D /* - */ + || code === 0x2E; /* . */ +} + +/** + * Checks if the character is an A (arc-to) path command. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ +function isArcCommand(code) { + // eslint-disable-next-line no-bitwise -- Impossible to satisfy + return (code | 0x20) === 0x61; +} + +/** + * Scans every character in the path string to determine + * where a segment starts and where it ends. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ +function scanSegment(path) { + const { max, pathValue, index } = path; + const cmdCode = pathValue.charCodeAt(index); + const reqParams = paramsCount[pathValue[index].toLowerCase()]; + + path.segmentStart = index; + + if (!isPathCommand(cmdCode)) { + path.err = `${invalidPathValue}: ${pathValue[index]} not a path command`; + return; + } + + path.index += 1; + skipSpaces(path); + + path.data = []; + + if (!reqParams) { + // Z + finalizeSegment(path); + return; + } + + for (;;) { + for (let i = reqParams; i > 0; i -= 1) { + if (isArcCommand(cmdCode) && (i === 3 || i === 4)) scanFlag(path); + else scanParam(path); + + if (path.err.length) { + return; + } + path.data.push(path.param); + + skipSpaces(path); + + // after ',' param is mandatory + if (path.index < max && pathValue.charCodeAt(path.index) === 0x2C/* , */) { + path.index += 1; + skipSpaces(path); + } + } + + if (path.index >= path.max) { + break; + } + + // Stop on next segment + if (!isDigitStart(pathValue.charCodeAt(path.index))) { + break; + } + } + + finalizeSegment(path); +} + +/** + * Returns a clone of an existing `pathArray`. + * + * @param {SVGPathCommander.pathArray | SVGPathCommander.pathSegment} path the source `pathArray` + * @returns {any} the cloned `pathArray` + */ +function clonePath(path) { + return path.map((x) => (Array.isArray(x) ? [...x] : x)); +} + +/** + * The `PathParser` is used by the `parsePathString` static method + * to generate a `pathArray`. + * + * @param {string} pathString + */ +function PathParser(pathString) { + /** @type {SVGPathCommander.pathArray} */ + // @ts-ignore + this.segments = []; + /** @type {string} */ + this.pathValue = pathString; + /** @type {number} */ + this.max = pathString.length; + /** @type {number} */ + this.index = 0; + /** @type {number} */ + this.param = 0.0; + /** @type {number} */ + this.segmentStart = 0; + /** @type {any} */ + this.data = []; + /** @type {string} */ + this.err = ''; +} + +/** + * Iterates an array to check if it's an actual `pathArray`. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ +function isPathArray(path) { + return Array.isArray(path) && path.every((seg) => { + const lk = seg[0].toLowerCase(); + return paramsCount[lk] === seg.length - 1 && 'achlmqstvz'.includes(lk); + }); +} + +/** + * Parses a path string value and returns an array + * of segments we like to call `pathArray`. + * + * @param {SVGPathCommander.pathArray | string} pathInput the string to be parsed + * @returns {SVGPathCommander.pathArray} the resulted `pathArray` + */ +function parsePathString(pathInput) { + if (isPathArray(pathInput)) { + // @ts-ignore -- isPathArray also checks if it's an `Array` + return clonePath(pathInput); + } + + // @ts-ignore -- pathInput is now string + const path = new PathParser(pathInput); + + skipSpaces(path); + + while (path.index < path.max && !path.err.length) { + scanSegment(path); + } + + if (path.err.length) { + // @ts-ignore + path.segments = []; + } else if (path.segments.length) { + if (!'mM'.includes(path.segments[0][0])) { + path.err = `${invalidPathValue}: missing M/m`; + // @ts-ignore + path.segments = []; + } else { + path.segments[0][0] = 'M'; + } + } + + return path.segments; +} + +/** + * Iterates an array to check if it's a `pathArray` + * with all absolute values. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ +function isAbsoluteArray(path) { + return isPathArray(path) + // @ts-ignore -- `isPathArray` also checks if it's `Array` + && path.every((x) => x[0] === x[0].toUpperCase()); +} + +/** + * Parses a path string value or object and returns an array + * of segments, all converted to absolute values. + * + * @param {string | SVGPathCommander.pathArray} pathInput the path string | object + * @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values + */ +function pathToAbsolute(pathInput) { + if (isAbsoluteArray(pathInput)) { + // @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + const path = parsePathString(pathInput); + let x = 0; let y = 0; + let mx = 0; let my = 0; + + // @ts-ignore -- the `absoluteSegment[]` is for sure an `absolutePath` + return path.map((segment) => { + const values = segment.slice(1).map(Number); + const [pathCommand] = segment; + /** @type {SVGPathCommander.absoluteCommand} */ + // @ts-ignore + const absCommand = pathCommand.toUpperCase(); + + if (pathCommand === 'M') { + [x, y] = values; + mx = x; + my = y; + return ['M', x, y]; + } + /** @type {SVGPathCommander.absoluteSegment} */ + // @ts-ignore + let absoluteSegment = []; + + if (pathCommand !== absCommand) { + switch (absCommand) { + case 'A': + absoluteSegment = [ + absCommand, values[0], values[1], values[2], + values[3], values[4], values[5] + x, values[6] + y]; + break; + case 'V': + absoluteSegment = [absCommand, values[0] + y]; + break; + case 'H': + absoluteSegment = [absCommand, values[0] + x]; + break; + default: { + // use brakets for `eslint: no-case-declaration` + // https://stackoverflow.com/a/50753272/803358 + const absValues = values.map((n, j) => n + (j % 2 ? y : x)); + // @ts-ignore for n, l, c, s, q, t + absoluteSegment = [absCommand, ...absValues]; + } + } + } else { + // @ts-ignore + absoluteSegment = [absCommand, ...values]; + } + + const segLength = absoluteSegment.length; + switch (absCommand) { + case 'Z': + x = mx; + y = my; + break; + case 'H': + // @ts-ignore + [, x] = absoluteSegment; + break; + case 'V': + // @ts-ignore + [, y] = absoluteSegment; + break; + default: + // @ts-ignore + x = absoluteSegment[segLength - 2]; + // @ts-ignore + y = absoluteSegment[segLength - 1]; + + if (absCommand === 'M') { + mx = x; + my = y; + } + } + return absoluteSegment; + }); +} + +/** + * Returns the missing control point from an + * T (shorthand quadratic bezier) segment. + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} qx control point x + * @param {number} qy control point y + * @param {string} prevCommand the previous path command + * @returns {{qx: number, qy: number}}} the missing control point + */ +function shorthandToQuad(x1, y1, qx, qy, prevCommand) { + return 'QT'.includes(prevCommand) + ? { qx: x1 * 2 - qx, qy: y1 * 2 - qy } + : { qx: x1, qy: y1 }; +} + +/** + * Returns the missing control point from an + * S (shorthand cubic bezier) segment. + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} x2 curve end x + * @param {number} y2 curve end y + * @param {string} prevCommand the previous path command + * @returns {{x1: number, y1: number}}} the missing control point + */ +function shorthandToCubic(x1, y1, x2, y2, prevCommand) { + return 'CS'.includes(prevCommand) + ? { x1: x1 * 2 - x2, y1: y1 * 2 - y2 } + : { x1, y1 }; +} + +/** + * Normalizes a single segment of a `pathArray` object. + * + * @param {SVGPathCommander.pathSegment} segment the segment object + * @param {any} params the coordinates of the previous segment + * @param {string} prevCommand the path command of the previous segment + * @returns {SVGPathCommander.normalSegment} the normalized segment + */ +function normalizeSegment(segment, params, prevCommand) { + const [pathCommand] = segment; + const { + x1: px1, y1: py1, x2: px2, y2: py2, + } = params; + const values = segment.slice(1).map(Number); + let result = segment; + + if (!'TQ'.includes(pathCommand)) { + // optional but good to be cautious + params.qx = null; + params.qy = null; + } + + if (pathCommand === 'H') { + result = ['L', segment[1], py1]; + } else if (pathCommand === 'V') { + result = ['L', px1, segment[1]]; + } else if (pathCommand === 'S') { + const { x1, y1 } = shorthandToCubic(px1, py1, px2, py2, prevCommand); + params.x1 = x1; + params.y1 = y1; + // @ts-ignore + result = ['C', x1, y1, ...values]; + } else if (pathCommand === 'T') { + const { qx, qy } = shorthandToQuad(px1, py1, params.qx, params.qy, prevCommand); + params.qx = qx; + params.qy = qy; + // @ts-ignore + result = ['Q', qx, qy, ...values]; + } else if (pathCommand === 'Q') { + const [nqx, nqy] = values; + params.qx = nqx; + params.qy = nqy; + } + + // @ts-ignore -- we-re switching `pathSegment` type + return result; +} + +/** + * Iterates an array to check if it's a `pathArray` + * with all segments are in non-shorthand notation + * with absolute values. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ +function isNormalizedArray(path) { + // @ts-ignore -- `isAbsoluteArray` also checks if it's `Array` + return isAbsoluteArray(path) && path.every((seg) => 'ACLMQZ'.includes(seg[0])); +} + +/** + * @type {SVGPathCommander.parserParams} + */ +const paramsParser = { + x1: 0, y1: 0, x2: 0, y2: 0, x: 0, y: 0, qx: null, qy: null, +}; + +/** + * Normalizes a `path` object for further processing: + * * convert segments to absolute values + * * convert shorthand path commands to their non-shorthand notation + * + * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray' + * @returns {SVGPathCommander.normalArray} the normalized `pathArray` + */ +function normalizePath(pathInput) { + if (isNormalizedArray(pathInput)) { + // @ts-ignore -- `isNormalizedArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + /** @type {SVGPathCommander.normalArray} */ + // @ts-ignore -- `absoluteArray` will become a `normalArray` + const path = pathToAbsolute(pathInput); + const params = { ...paramsParser }; + const allPathCommands = []; + const ii = path.length; + let pathCommand = ''; + let prevCommand = ''; + + for (let i = 0; i < ii; i += 1) { + [pathCommand] = path[i]; + + // Save current path command + allPathCommands[i] = pathCommand; + // Get previous path command + if (i) prevCommand = allPathCommands[i - 1]; + // Previous path command is used to normalizeSegment + // @ts-ignore -- expected on normalization + path[i] = normalizeSegment(path[i], params, prevCommand); + + const segment = path[i]; + const seglen = segment.length; + + params.x1 = +segment[seglen - 2]; + params.y1 = +segment[seglen - 1]; + params.x2 = +(segment[seglen - 4]) || params.x1; + params.y2 = +(segment[seglen - 3]) || params.y1; + } + + return path; +} + +/** + * Checks a `pathArray` for an unnecessary `Z` segment + * and returns a new `pathArray` without it. + * + * The `pathInput` must be a single path, without + * sub-paths. For multi-path `` elements, + * use `splitPath` first and apply this utility on each + * sub-path separately. + * + * @param {SVGPathCommander.pathArray | string} pathInput the `pathArray` source + * @return {SVGPathCommander.pathArray} a fixed `pathArray` + */ +function fixPath(pathInput) { + const pathArray = parsePathString(pathInput); + const normalArray = normalizePath(pathArray); + const { length } = pathArray; + const isClosed = normalArray.slice(-1)[0][0] === 'Z'; + const segBeforeZ = isClosed ? length - 2 : length - 1; + + const [mx, my] = normalArray[0].slice(1); + const [x, y] = normalArray[segBeforeZ].slice(-2); + + if (isClosed && mx === x && my === y) { + // @ts-ignore -- `pathSegment[]` is quite a `pathArray` + return pathArray.slice(0, -1); + } + return pathArray; +} + +/** + * Iterates an array to check if it's a `pathArray` + * with all C (cubic bezier) segments. + * + * @param {string | SVGPathCommander.pathArray} path the `Array` to be checked + * @returns {boolean} iteration result + */ +function isCurveArray(path) { + // @ts-ignore -- `isPathArray` also checks if it's `Array` + return isPathArray(path) && path.every((seg) => 'MC'.includes(seg[0])); +} + +/** + * Returns an {x,y} vector rotated by a given + * angle in radian. + * + * @param {number} x the initial vector x + * @param {number} y the initial vector y + * @param {number} rad the radian vector angle + * @returns {{x: number, y: number}} the rotated vector + */ +function rotateVector(x, y, rad) { + const X = x * Math.cos(rad) - y * Math.sin(rad); + const Y = x * Math.sin(rad) + y * Math.cos(rad); + return { x: X, y: Y }; +} + +/** + * Converts A (arc-to) segments to C (cubic-bezier-to). + * + * For more information of where this math came from visit: + * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + * + * @param {number} X1 the starting x position + * @param {number} Y1 the starting y position + * @param {number} RX x-radius of the arc + * @param {number} RY y-radius of the arc + * @param {number} angle x-axis-rotation of the arc + * @param {number} LAF large-arc-flag of the arc + * @param {number} SF sweep-flag of the arc + * @param {number} X2 the ending x position + * @param {number} Y2 the ending y position + * @param {number[]=} recursive the parameters needed to split arc into 2 segments + * @return {number[]} the resulting cubic-bezier segment(s) + */ +function arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, recursive) { + let x1 = X1; let y1 = Y1; let rx = RX; let ry = RY; let x2 = X2; let y2 = Y2; + // for more information of where this Math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + const d120 = (Math.PI * 120) / 180; + + const rad = (Math.PI / 180) * (+angle || 0); + /** @type {number[]} */ + let res = []; + let xy; + let f1; + let f2; + let cx; + let cy; + + if (!recursive) { + xy = rotateVector(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotateVector(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + + const x = (x1 - x2) / 2; + const y = (y1 - y2) / 2; + let h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = Math.sqrt(h); + rx *= h; + ry *= h; + } + const rx2 = rx * rx; + const ry2 = ry * ry; + + const k = (LAF === SF ? -1 : 1) + * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) + / (rx2 * y * y + ry2 * x * x))); + + cx = ((k * rx * y) / ry) + ((x1 + x2) / 2); + cy = ((k * -ry * x) / rx) + ((y1 + y2) / 2); + // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise + f1 = (Math.asin((((y1 - cy) / ry))) * (10 ** 9) >> 0) / (10 ** 9); + // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise + f2 = (Math.asin((((y2 - cy) / ry))) * (10 ** 9) >> 0) / (10 ** 9); + + f1 = x1 < cx ? Math.PI - f1 : f1; + f2 = x2 < cx ? Math.PI - f2 : f2; + if (f1 < 0) (f1 = Math.PI * 2 + f1); + if (f2 < 0) (f2 = Math.PI * 2 + f2); + if (SF && f1 > f2) { + f1 -= Math.PI * 2; + } + if (!SF && f2 > f1) { + f2 -= Math.PI * 2; + } + } else { + [f1, f2, cx, cy] = recursive; + } + let df = f2 - f1; + if (Math.abs(df) > d120) { + const f2old = f2; + const x2old = x2; + const y2old = y2; + f2 = f1 + d120 * (SF && f2 > f1 ? 1 : -1); + x2 = cx + rx * Math.cos(f2); + y2 = cy + ry * Math.sin(f2); + res = arcToCubic(x2, y2, rx, ry, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + const c1 = Math.cos(f1); + const s1 = Math.sin(f1); + const c2 = Math.cos(f2); + const s2 = Math.sin(f2); + const t = Math.tan(df / 4); + const hx = (4 / 3) * rx * t; + const hy = (4 / 3) * ry * t; + const m1 = [x1, y1]; + const m2 = [x1 + hx * s1, y1 - hy * c1]; + const m3 = [x2 + hx * s2, y2 - hy * c2]; + const m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [...m2, ...m3, ...m4, ...res]; + } + res = [...m2, ...m3, ...m4, ...res]; + const newres = []; + for (let i = 0, ii = res.length; i < ii; i += 1) { + newres[i] = i % 2 + ? rotateVector(res[i - 1], res[i], rad).y + : rotateVector(res[i], res[i + 1], rad).x; + } + return newres; +} + +/** + * Converts a Q (quadratic-bezier) segment to C (cubic-bezier). + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} qx control point x + * @param {number} qy control point y + * @param {number} x2 curve end x + * @param {number} y2 curve end y + * @returns {number[]} the cubic-bezier segment + */ +function quadToCubic(x1, y1, qx, qy, x2, y2) { + const r13 = 1 / 3; + const r23 = 2 / 3; + return [ + r13 * x1 + r23 * qx, // cpx1 + r13 * y1 + r23 * qy, // cpy1 + r13 * x2 + r23 * qx, // cpx2 + r13 * y2 + r23 * qy, // cpy2 + x2, y2, // x,y + ]; +} + +/** + * Returns the coordinates of a specified distance + * ratio between two points. + * + * @param {[number, number]} a the first point coordinates + * @param {[number, number]} b the second point coordinates + * @param {number} t the ratio + * @returns {[number, number]} the midpoint coordinates + */ +function midPoint(a, b, t) { + const [ax, ay] = a; const [bx, by] = b; + return [ax + (bx - ax) * t, ay + (by - ay) * t]; +} + +/** + * Returns the square root of the distance + * between two given points. + * + * @param {[number, number]} a the first point coordinates + * @param {[number, number]} b the second point coordinates + * @returns {number} the distance value + */ +function distanceSquareRoot(a, b) { + return Math.sqrt( + (a[0] - b[0]) * (a[0] - b[0]) + + (a[1] - b[1]) * (a[1] - b[1]), + ); +} + +/** + * Returns the length of a line (L,V,H,Z) segment, + * or a point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the distance to point + * @returns {{x: number, y: number} | number} the segment length or point + */ +function segmentLineFactory(x1, y1, x2, y2, distance) { + const length = distanceSquareRoot([x1, y1], [x2, y2]); + const margin = 0.001; + + if (typeof distance === 'number') { + if (distance < margin) { + return { x: x1, y: y1 }; + } + if (distance > length + margin) { + return { x: x2, y: y2 }; + } + const [x, y] = midPoint([x1, y1], [x2, y2], distance / length); + return { x, y }; + } + return length; +} + +/** + * Converts an L (line-to) segment to C (cubic-bezier). + * + * @param {number} x1 line start x + * @param {number} y1 line start y + * @param {number} x2 line end x + * @param {number} y2 line end y + * @returns {number[]} the cubic-bezier segment + */ +function lineToCubic(x1, y1, x2, y2) { + const t = 0.5; + /** @type {[number, number]} */ + const p0 = [x1, y1]; + /** @type {[number, number]} */ + const p1 = [x2, y2]; + const p2 = midPoint(p0, p1, t); + const p3 = midPoint(p1, p2, t); + const p4 = midPoint(p2, p3, t); + const p5 = midPoint(p3, p4, t); + const p6 = midPoint(p4, p5, t); + const seg1 = [...p0, ...p2, ...p4, ...p6, t]; + // @ts-ignore + const cp1 = segmentLineFactory(...seg1); + const seg2 = [...p6, ...p5, ...p3, ...p1, 0]; + // @ts-ignore + const cp2 = segmentLineFactory(...seg2); + + // @ts-ignore + return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2]; +} + +/** + * Converts any segment to C (cubic-bezier). + * + * @param {SVGPathCommander.pathSegment} segment the source segment + * @param {SVGPathCommander.parserParams} params the source segment parameters + * @returns {SVGPathCommander.cubicSegment | SVGPathCommander.MSegment} the cubic-bezier segment + */ +function segmentToCubic(segment, params) { + const [pathCommand] = segment; + const values = segment.slice(1).map((n) => +n); + const [x, y] = values; + let args; + const { + x1: px1, y1: py1, x: px, y: py, + } = params; + + if (!'TQ'.includes(pathCommand)) { + params.qx = null; + params.qy = null; + } + + switch (pathCommand) { + case 'M': + params.x = x; + params.y = y; + return segment; + case 'A': + args = [px1, py1, ...values]; + // @ts-ignore -- relax, the utility will return 6 numbers + return ['C', ...arcToCubic(...args)]; + case 'Q': + params.qx = x; + params.qy = y; + args = [px1, py1, ...values]; + // @ts-ignore -- also returning 6 numbers + return ['C', ...quadToCubic(...args)]; + case 'L': + // @ts-ignore -- also returning 6 numbers + return ['C', ...lineToCubic(px1, py1, x, y)]; + case 'Z': + // @ts-ignore -- also returning 6 numbers + return ['C', ...lineToCubic(px1, py1, px, py)]; + } + // @ts-ignore -- we're switching `pathSegment` type + return segment; +} + +/** + * Parses a path string value or 'pathArray' and returns a new one + * in which all segments are converted to cubic-bezier. + * + * In addition, un-necessary `Z` segment is removed if previous segment + * extends to the `M` segment. + * + * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray' + * @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier + */ +function pathToCurve(pathInput) { + if (isCurveArray(pathInput)) { + // @ts-ignore -- `isCurveArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + const path = fixPath(normalizePath(pathInput)); + const params = { ...paramsParser }; + const allPathCommands = []; + let pathCommand = ''; // ts-lint + let ii = path.length; + + for (let i = 0; i < ii; i += 1) { + [pathCommand] = path[i]; + allPathCommands[i] = pathCommand; + + path[i] = segmentToCubic(path[i], params); + + fixArc(path, allPathCommands, i); + ii = path.length; + + const segment = path[i]; + const seglen = segment.length; + params.x1 = +segment[seglen - 2]; + params.y1 = +segment[seglen - 1]; + params.x2 = +(segment[seglen - 4]) || params.x1; + params.y2 = +(segment[seglen - 3]) || params.y1; + } + + // @ts-ignore + return path; +} + +/** + * SVGPathCommander default options + * @type {SVGPathCommander.options} + */ +const defaultOptions = { + origin: [0, 0, 0], + round: 4, +}; + +/** + * Rounds the values of a `pathArray` instance to + * a specified amount of decimals and returns it. + * + * @param {SVGPathCommander.pathArray} path the source `pathArray` + * @param {number | boolean} roundOption the amount of decimals to round numbers to + * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with rounded values + */ +function roundPath(path, roundOption) { + let { round } = defaultOptions; + if (roundOption === false || round === false) return clonePath(path); + round = roundOption >= 1 ? roundOption : round; + // to round values to the power + // the `round` value must be integer + // @ts-ignore + const pow = round >= 1 ? (10 ** round) : 1; + + // @ts-ignore -- `pathSegment[]` is `pathArray` + return path.map((pi) => { + const values = pi.slice(1).map(Number) + .map((n) => (n % 1 === 0 ? n : Math.round(n * pow) / pow)); + return [pi[0], ...values]; + }); +} + +/** + * Returns a valid `d` attribute string value created + * by rounding values and concatenating the `pathArray` segments. + * + * @param {SVGPathCommander.pathArray} path the `pathArray` object + * @param {any} round amount of decimals to round values to + * @returns {string} the concatenated path string + */ +function pathToString(path, round) { + return roundPath(path, round) + .map((x) => x[0] + x.slice(1).join(' ')).join(''); +} + +/** + * Split a path into an `Array` of sub-path strings. + * + * In the process, values are converted to absolute + * for visual consistency. + * + * @param {SVGPathCommander.pathArray | string} pathInput the source `pathArray` + * @return {string[]} an array with all sub-path strings + */ +function splitPath(pathInput) { + return pathToString(pathToAbsolute(pathInput), 0) + .replace(/(m|M)/g, '|$1') + .split('|') + .map((s) => s.trim()) + .filter((s) => s); +} + +/** + * Returns a point at a given length of a C (cubic-bezier) segment. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} c1x the first control point X + * @param {number} c1y the first control point Y + * @param {number} c2x the second control point X + * @param {number} c2y the second control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number} t a [0-1] ratio + * @returns {{x: number, y: number}} the cubic-bezier segment length + */ +function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) { + const t1 = 1 - t; + return { + x: (t1 ** 3) * x1 + + 3 * (t1 ** 2) * t * c1x + + 3 * t1 * (t ** 2) * c2x + + (t ** 3) * x2, + y: (t1 ** 3) * y1 + + 3 * (t1 ** 2) * t * c1y + + 3 * t1 * (t ** 2) * c2y + + (t ** 3) * y2, + }; +} + +/** + * Returns the length of a C (cubic-bezier) segment, + * or an {x,y} point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} c1x the first control point X + * @param {number} c1y the first control point Y + * @param {number} c2x the second control point X + * @param {number} c2y the second control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the point distance + * @returns {{x: number, y: number} | number} the segment length or point + */ +function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) { + let x = x1; let y = y1; + const lengthMargin = 0.001; + let totalLength = 0; + let prev = [x1, y1, totalLength]; + /** @type {[number, number]} */ + let cur = [x1, y1]; + let t = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x, y }; + } + + const n = 100; + for (let j = 0; j <= n; j += 1) { + t = j / n; + + ({ x, y } = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t)); + totalLength += distanceSquareRoot(cur, [x, y]); + cur = [x, y]; + + if (typeof distance === 'number' && totalLength >= distance) { + const dv = (totalLength - distance) / (totalLength - prev[2]); + + return { + x: cur[0] * (1 - dv) + prev[0] * dv, + y: cur[1] * (1 - dv) + prev[1] * dv, + }; + } + prev = [x, y, totalLength]; + } + + if (typeof distance === 'number' && distance >= totalLength) { + return { x: x2, y: y2 }; + } + return totalLength; +} + +/** + * Returns the length of a A (arc-to) segment, + * or an {x,y} point at a given length. + * + * @param {number} X1 the starting x position + * @param {number} Y1 the starting y position + * @param {number} RX x-radius of the arc + * @param {number} RY y-radius of the arc + * @param {number} angle x-axis-rotation of the arc + * @param {number} LAF large-arc-flag of the arc + * @param {number} SF sweep-flag of the arc + * @param {number} X2 the ending x position + * @param {number} Y2 the ending y position + * @param {number} distance the point distance + * @returns {{x: number, y: number} | number} the segment length or point + */ +function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) { + let [x, y] = [X1, Y1]; + const cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2); + const lengthMargin = 0.001; + let totalLength = 0; + let cubicSubseg = []; + let argsc = []; + let segLen = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x, y }; + } + + for (let i = 0, ii = cubicSeg.length; i < ii; i += 6) { + cubicSubseg = cubicSeg.slice(i, i + 6); + argsc = [x, y, ...cubicSubseg]; + // @ts-ignore + segLen = segmentCubicFactory(...argsc); + if (typeof distance === 'number' && totalLength + segLen >= distance) { + // @ts-ignore -- this is a `cubicSegment` + return segmentCubicFactory(...argsc, distance - totalLength); + } + totalLength += segLen; + [x, y] = cubicSubseg.slice(-2); + } + + if (typeof distance === 'number' && distance >= totalLength) { + return { x: X2, y: Y2 }; + } + + return totalLength; +} + +/** + * Returns the {x,y} coordinates of a point at a + * given length of a quad-bezier segment. + * + * @see https://github.com/substack/point-at-length + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} cx the control point X + * @param {number} cy the control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number} t a [0-1] ratio + * @returns {{x: number, y: number}} the requested {x,y} coordinates + */ +function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) { + const t1 = 1 - t; + return { + x: (t1 ** 2) * x1 + + 2 * t1 * t * cx + + (t ** 2) * x2, + y: (t1 ** 2) * y1 + + 2 * t1 * t * cy + + (t ** 2) * y2, + }; +} + +/** + * Returns the Q (quadratic-bezier) segment length, + * or an {x,y} point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} qx the control point X + * @param {number} qy the control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the distance to point + * @returns {{x: number, y: number} | number} the segment length or point + */ +function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) { + let x = x1; let y = y1; + const lengthMargin = 0.001; + let totalLength = 0; + let prev = [x1, y1, totalLength]; + /** @type {[number, number]} */ + let cur = [x1, y1]; + let t = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x, y }; + } + + const n = 100; + for (let j = 0; j <= n; j += 1) { + t = j / n; + + ({ x, y } = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t)); + totalLength += distanceSquareRoot(cur, [x, y]); + cur = [x, y]; + + if (typeof distance === 'number' && totalLength >= distance) { + const dv = (totalLength - distance) / (totalLength - prev[2]); + + return { + x: cur[0] * (1 - dv) + prev[0] * dv, + y: cur[1] * (1 - dv) + prev[1] * dv, + }; + } + prev = [x, y, totalLength]; + } + if (typeof distance === 'number' && distance >= totalLength) { + return { x: x2, y: y2 }; + } + return totalLength; +} + +/** + * Returns a {x,y} point at a given length of a shape or the shape total length. + * + * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into + * @param {number=} distance the length of the shape to look at + * @returns {{x: number, y: number} | number} the total length or point + */ +function pathLengthFactory(pathInput, distance) { + let totalLength = 0; + let isM = true; + /** @type {number[]} */ + let data = []; + let pathCommand = 'M'; + let segLen = 0; + let x = 0; + let y = 0; + let mx = 0; + let my = 0; + let seg; + const path = fixPath(normalizePath(pathInput)); + + for (let i = 0, ll = path.length; i < ll; i += 1) { + seg = path[i]; + [pathCommand] = seg; + isM = pathCommand === 'M'; + // @ts-ignore + data = !isM ? [x, y, ...seg.slice(1)] : data; + + // this segment is always ZERO + if (isM) { + // remember mx, my for Z + // @ts-ignore + [, mx, my] = seg; + if (typeof distance === 'number' && distance < 0.001) { + return { x: mx, y: my }; + } + } else if (pathCommand === 'L') { + // @ts-ignore + segLen = segmentLineFactory(...data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentLineFactory(...data, distance - totalLength); + } + totalLength += segLen; + } else if (pathCommand === 'A') { + // @ts-ignore + segLen = segmentArcFactory(...data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentArcFactory(...data, distance - totalLength); + } + totalLength += segLen; + } else if (pathCommand === 'C') { + // @ts-ignore + segLen = segmentCubicFactory(...data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentCubicFactory(...data, distance - totalLength); + } + totalLength += segLen; + } else if (pathCommand === 'Q') { + // @ts-ignore + segLen = segmentQuadFactory(...data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentQuadFactory(...data, distance - totalLength); + } + totalLength += segLen; + } else if (pathCommand === 'Z') { + data = [x, y, mx, my]; + // @ts-ignore + segLen = segmentLineFactory(...data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentLineFactory(...data, distance - totalLength); + } + totalLength += segLen; + } + + // @ts-ignore -- needed for the below + [x, y] = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my]; + } + + // native `getPointAtLength` behavior when the given distance + // is higher than total length + if (distance && distance >= totalLength) { + return { x, y }; + } + + return totalLength; +} + +/** + * Returns the shape total length, or the equivalent to `shape.getTotalLength()`. + * + * The `normalizePath` version is lighter, faster, more efficient and more accurate + * with paths that are not `curveArray`. + * + * @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray` + * @returns {number} the shape total length + */ +function getTotalLength(pathInput) { + // @ts-ignore - it's fine + return pathLengthFactory(pathInput); +} + +/** + * Returns [x,y] coordinates of a point at a given length of a shape. + * + * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into + * @param {number} distance the length of the shape to look at + * @returns {{x: number, y: number}} the requested {x, y} point coordinates + */ +function getPointAtLength(pathInput, distance) { + // @ts-ignore + return pathLengthFactory(pathInput, distance); +} + +/** + * d3-polygon-area + * https://github.com/d3/d3-polygon + * + * Returns the area of a polygon. + * + * @param {number[][]} polygon an array of coordinates + * @returns {number} the polygon area + */ +function polygonArea(polygon) { + const n = polygon.length; + let i = -1; + let a; + let b = polygon[n - 1]; + let area = 0; + + /* eslint-disable-next-line */ + while (++i < n) { + a = b; + b = polygon[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + + return area / 2; +} + +/** + * d3-polygon-length + * https://github.com/d3/d3-polygon + * + * Returns the perimeter of a polygon. + * + * @param {number[][]} polygon an array of coordinates + * @returns {number} the polygon length + */ +function polygonLength(polygon) { + return polygon.reduce((length, point, i) => { + if (i) { + // @ts-ignore + return length + distanceSquareRoot(polygon[i - 1], point); + } + return 0; + }, 0); +} + +/** + * A global namespace for epsilon. + * + * @type {number} + */ +const epsilon = 1e-9; + +/** + * Coordinates Interpolation Function. + * + * @param {number[][]} a start coordinates + * @param {number[][]} b end coordinates + * @param {string} l amount of coordinates + * @param {number} v progress + * @returns {number[][]} the interpolated coordinates + */ +function coords(a, b, l, v) { + const points = []; + for (let i = 0; i < l; i += 1) { // for each point + points[i] = []; + for (let j = 0; j < 2; j += 1) { // each point coordinate + // eslint-disable-next-line no-bitwise + points[i].push(((a[i][j] + (b[i][j] - a[i][j]) * v) * 1000 >> 0) / 1000); + } + } + return points; +} + +/* 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 + */ +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 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$1.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$1.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, + }, +}; + +const Components = { + EssentialBoxModel: BoxModelEssential, + ColorsProperties: colorProperties, + HTMLAttributes: htmlAttributes, + OpacityProperty, + TextWriteProp: TextWrite, + TransformFunctions, + SVGDraw: SvgDrawProperty, + SVGMorph, +}; + +// init components +Object.keys(Components).forEach((component) => { + const compOps = Components[component]; + Components[component] = new Animation(compOps); +}); + +var version = "2.2.3"; + +// @ts-ignore + +/** + * A global namespace for library version. + * @type {string} + */ +const Version = version; + +// KUTE.js standard distribution version + +const KUTE = { + Animation, + Components, + + // Tween Interface + Tween, + fromTo, + to, + // Tween Collection + TweenCollection, + allFromTo, + allTo, + // Tween Interface + + Objects, + Util, + Easing, + CubicBezier, + Render, + Interpolate: interpolate, + Process, + Internals: internals, + Selector: selector, + Version, +}; + +export { KUTE as default }; diff --git a/dist/kute.esm.min.js b/dist/kute.esm.min.js new file mode 100644 index 0000000..e5705e2 --- /dev/null +++ b/dist/kute.esm.min.js @@ -0,0 +1,2 @@ +// KUTE.js Standard v2.2.3 | thednp © 2021 | MIT-License +class t{constructor(t,e,n,r,s){this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by;const i=t=>this.sampleCurveY(this.solveCurveX(t));return Object.defineProperty(i,"name",{writable:!0}),i.name=s||`cubic-bezier(${[t,e,n,r]})`,i}sampleCurveX(t){return((this.ax*t+this.bx)*t+this.cx)*t}sampleCurveY(t){return((this.ay*t+this.by)*t+this.cy)*t}sampleCurveDerivativeX(t){return(3*this.ax*t+2*this.bx)*t+this.cx}solveCurveX(t){let e,n,r,s,i,a;const o=1e-5;for(r=t,a=0;a<32;a+=1){if(s=this.sampleCurveX(r)-t,Math.abs(s)n)return n;for(;es?e=r:n=r,r=.5*(n-e)+e}return r}}Object.assign(t,{Version:"1.0.18"});const e={},n=[];let r;r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{};const s=r,i={},a={};let o;o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?()=>{const t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:()=>(new Date).getTime();const l=o,c={};c.now=l;let u=0;const h=t=>{let e=0;for(;e{!n.length&&u&&(cancelAnimationFrame(u),u=null,Object.keys(a).forEach((t=>{"function"==typeof a[t]?e[t]&&delete e[t]:Object.keys(a[t]).forEach((t=>{e[t]&&delete e[t]}))})),Object.keys(i).forEach((t=>{e[t]&&delete e[t]})))}),64)}const f={Tick:u,Ticker:h,Tweens:n,Time:c};Object.keys(f).forEach((t=>{e[t]||(e[t]="Time"===t?c.now:f[t])})),s._KUTE=e;const d={},g={},y={duration:700,delay:0,easing:"linear",repeat:0,repeatDelay:0,yoyo:!1,resetStart:!1,offset:0},m={},b={},v={},x={},E={},w={supportedProperties:d,defaultValues:g,defaultOptions:y,prepareProperty:m,prepareStart:b,crossCheck:v,onStart:a,onComplete:x,linkProperty:E},k={},_=t=>n.push(t),C=t=>{const e=n.indexOf(t);-1!==e&&n.splice(e,1)};function O(){Object.keys(E).forEach((t=>{const n=E[t],r=d[t];Object.keys(n).forEach((t=>{"function"==typeof n[t]&&Object.keys(this.valuesEnd).some((t=>r&&r.includes(t)||"attr"===t&&Object.keys(this.valuesEnd[t]).some((t=>r&&r.includes(t)))))?e[t]||(e[t]=n[t]):Object.keys(this.valuesEnd).forEach((r=>{const s=this.valuesEnd[r];s instanceof Object&&Object.keys(s).forEach((r=>{"function"==typeof n[r]?e[r]||(e[r]=n[r]):Object.keys(n[t]).forEach((t=>{n[r]&&"function"==typeof n[r][t]&&(e[t]||(e[t]=n[r][t]))}))}))}))}))}))}const M={add:_,remove:C,getAll:()=>n,removeAll:()=>{n.length=0},stop:p,linkInterpolation:O};function T(t){if(!t.style)return!1;const e=t.style.cssText.replace(/\s/g,"").split(";"),n={},r=["translate3d","translate","scale3d","skew"];return e.forEach((t=>{if(/transform/i.test(t)){t.split(":")[1].split(")").forEach((t=>{const e=t.split("("),s=e[0],i=e[1];/matrix/.test(s)||(n[s]=r.includes(s)?i.split(","):i)}))}})),n}function I(t,e){let n=g[e];const r=t.style,s=getComputedStyle(t)||t.currentStyle,i=r[e]&&!/auto|initial|none|unset/.test(r[e])?r[e]:s[e];return"transform"!==e&&(e in s||e in r)&&(n=i),n}function S(t,e){const n="start"===e?this.valuesStart:this.valuesEnd;Object.keys(m).forEach((e=>{const r=m[e],s=d[e];Object.keys(r).forEach((e=>{const i={};Object.keys(t).forEach((a=>{g[a]&&r[a]?n[a]=r[a].call(this,a,t[a]):!g[e]&&"transform"===e&&s.includes(a)?i[a]=t[a]:g[a]||"transform"!==a?!g[e]&&s&&s.includes(a)&&(n[a]=r[e].call(this,a,t[a])):n[a]=t[a]})),Object.keys(i).length&&(n[e]=r[e].call(this,e,i))}))}))}function A(){const t={},e=T(this.element);Object.keys(this.valuesStart).forEach((e=>{Object.keys(b).forEach((n=>{const r=b[n];Object.keys(r).forEach((s=>{(s===e&&r[e]||d[n]&&d[n].includes(e))&&(t[e]=r[s].call(this,e,this.valuesStart[e]))}))}))})),Object.keys(e).forEach((n=>{n in this.valuesStart||(t[n]=e[n]||g[n])})),this.valuesStart={},S.call(this,t,"start")}var j={getInlineStyle:T,getStyleForProperty:I,getStartValues:A,prepareObject:S};const P={tween:null,processEasing:null},$={linear:new t(0,0,1,1,"linear"),easingSinusoidalIn:new t(.47,0,.745,.715,"easingSinusoidalIn"),easingSinusoidalOut:new t(.39,.575,.565,1,"easingSinusoidalOut"),easingSinusoidalInOut:new t(.445,.05,.55,.95,"easingSinusoidalInOut"),easingQuadraticIn:new t(.55,.085,.68,.53,"easingQuadraticIn"),easingQuadraticOut:new t(.25,.46,.45,.94,"easingQuadraticOut"),easingQuadraticInOut:new t(.455,.03,.515,.955,"easingQuadraticInOut"),easingCubicIn:new t(.55,.055,.675,.19,"easingCubicIn"),easingCubicOut:new t(.215,.61,.355,1,"easingCubicOut"),easingCubicInOut:new t(.645,.045,.355,1,"easingCubicInOut"),easingQuarticIn:new t(.895,.03,.685,.22,"easingQuarticIn"),easingQuarticOut:new t(.165,.84,.44,1,"easingQuarticOut"),easingQuarticInOut:new t(.77,0,.175,1,"easingQuarticInOut"),easingQuinticIn:new t(.755,.05,.855,.06,"easingQuinticIn"),easingQuinticOut:new t(.23,1,.32,1,"easingQuinticOut"),easingQuinticInOut:new t(.86,0,.07,1,"easingQuinticInOut"),easingExponentialIn:new t(.95,.05,.795,.035,"easingExponentialIn"),easingExponentialOut:new t(.19,1,.22,1,"easingExponentialOut"),easingExponentialInOut:new t(1,0,0,1,"easingExponentialInOut"),easingCircularIn:new t(.6,.04,.98,.335,"easingCircularIn"),easingCircularOut:new t(.075,.82,.165,1,"easingCircularOut"),easingCircularInOut:new t(.785,.135,.15,.86,"easingCircularInOut"),easingBackIn:new t(.6,-.28,.735,.045,"easingBackIn"),easingBackOut:new t(.175,.885,.32,1.275,"easingBackOut"),easingBackInOut:new t(.68,-.55,.265,1.55,"easingBackInOut")};function L(t,e){try{let n,r;return e?(r=t instanceof Array&&t.every((t=>t instanceof Element)),n=t instanceof HTMLCollection||t instanceof NodeList||r?t:document.querySelectorAll(t)):n=t instanceof Element||t===window?t:document.querySelector(t),n}catch(e){throw TypeError(`KUTE.js - Element(s) not found: ${t}.`)}}function N(){Object.keys(a).forEach((t=>{"function"==typeof a[t]?a[t].call(this,t):Object.keys(a[t]).forEach((e=>{a[t][e].call(this,e)}))})),O.call(this)}P.processEasing=function(e){if("function"==typeof e)return e;if("function"==typeof $[e])return $[e];if(/bezier/.test(e)){const n=e.replace(/bezier|\s|\(|\)/g,"").split(",");return new t(1*n[0],1*n[1],1*n[2],1*n[3])}return $.linear};class q{constructor(t,n,r,s){this.element=t,this.playing=!1,this._startTime=null,this._startFired=!1,this.valuesEnd=r,this.valuesStart=n;const i=s||{};this._resetStart=i.resetStart||0,this._easing="function"==typeof i.easing?i.easing:P.processEasing(i.easing),this._duration=i.duration||y.duration,this._delay=i.delay||y.delay,Object.keys(i).forEach((t=>{const e=`_${t}`;e in this||(this[e]=i[t])}));const o=this._easing.name;return a[o]||(a[o]=function(t){e[t]||t!==this._easing.name||(e[t]=this._easing)}),this}start(t){return _(this),this.playing=!0,this._startTime=void 0!==t?t:e.Time(),this._startTime+=this._delay,this._startFired||(this._onStart&&this._onStart.call(this),N.call(this),this._startFired=!0),u||h(),this}stop(){return this.playing&&(C(this),this.playing=!1,this._onStop&&this._onStop.call(this),this.close()),this}close(){Object.keys(x).forEach((t=>{Object.keys(x[t]).forEach((e=>{x[t][e].call(this,e)}))})),this._startFired=!1,p.call(this)}chain(t){return this._chain=[],this._chain=t.length?t:this._chain.concat(t),this}stopChainedTweens(){this._chain&&this._chain.length&&this._chain.forEach((t=>t.stop()))}update(t){const n=void 0!==t?t:e.Time();let r;if(n1?1:r;const s=this._easing(r);return Object.keys(this.valuesEnd).forEach((t=>{e[t](this.element,this.valuesStart[t],this.valuesEnd[t],s)})),this._onUpdate&&this._onUpdate.call(this),1!==r||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((t=>t.start())),!1)}}P.tween=q;class V extends q{constructor(...t){super(...t),this.valuesStart={},this.valuesEnd={};const[e,n,r]=t.slice(1);return S.call(this,n,"end"),this._resetStart?this.valuesStart=e:S.call(this,e,"start"),this._resetStart||Object.keys(v).forEach((t=>{Object.keys(v[t]).forEach((e=>{v[t][e].call(this,e)}))})),this.paused=!1,this._pauseTime=null,this._repeat=r.repeat||y.repeat,this._repeatDelay=r.repeatDelay||y.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=r.yoyo||y.yoyo,this._reversed=!1,this}start(t){return this._resetStart&&(this.valuesStart=this._resetStart,A.call(this),Object.keys(v).forEach((t=>{Object.keys(v[t]).forEach((e=>{v[t][e].call(this,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((t=>{this.valuesRepeat[t]=this.valuesStart[t]})),super.start(t),this}stop(){return super.stop(),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this}close(){return super.close(),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this}resume(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),N.call(this),this._startTime+=e.Time()-this._pauseTime,_(this),u||h()),this}pause(){return!this.paused&&this.playing&&(C(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this}reverse(){Object.keys(this.valuesEnd).forEach((t=>{const e=this.valuesRepeat[t];this.valuesRepeat[t]=this.valuesEnd[t],this.valuesEnd[t]=e,this.valuesStart[t]=this.valuesRepeat[t]}))}update(t){const n=void 0!==t?t:e.Time();let r;if(n1?1:r;const s=this._easing(r);return Object.keys(this.valuesEnd).forEach((t=>{e[t](this.element,this.valuesStart[t],this.valuesEnd[t],s)})),this._onUpdate&&this._onUpdate.call(this),1!==r||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=n,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((t=>t.start())),!1))}}P.tween=V;class H{constructor(t,e,n,r){const s=P.tween;this.tweens=[];const i=r||{};i.delay=i.delay||y.delay;const a=[];return Array.from(t).forEach(((t,r)=>{if(a[r]=i||{},a[r].delay=r>0?i.delay+(i.offset||y.offset):i.delay,!(t instanceof Element))throw Error(`KUTE - ${t} is not instanceof Element`);this.tweens.push(new s(t,e,n,a[r]))})),this.length=this.tweens.length,this}start(t){const n=void 0===t?e.Time():t;return this.tweens.map((t=>t.start(n))),this}stop(){return this.tweens.map((t=>t.stop())),this}pause(){return this.tweens.map((t=>t.pause())),this}resume(){return this.tweens.map((t=>t.resume())),this}chain(t){const e=this.tweens[this.length-1];if(t instanceof H)e.chain(t.tweens);else{if(!(t instanceof P.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this}playing(){return this.tweens.some((t=>t.playing))}removeTweens(){this.tweens=[]}getMaxDuration(){const t=[];return this.tweens.forEach((e=>{t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)}}const{tween:Q}=P;const{tween:F}=P;class U{constructor(t){try{if(t.component in d)throw Error(`KUTE - ${t.component} already registered`);if(t.property in g)throw Error(`KUTE - ${t.property} already registered`)}catch(t){throw Error(t)}const e=this,n=t.component,r={prepareProperty:m,prepareStart:b,onStart:a,onComplete:x,crossCheck:v},s=t.category,o=t.property,l=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return d[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(g[o]=t.defaultValue,e.supports=`${o} property`):t.defaultValues&&(Object.keys(t.defaultValues).forEach((e=>{g[e]=t.defaultValues[e]})),e.supports=`${l||o} ${o||s} properties`),t.defaultOptions&&Object.assign(y,t.defaultOptions),t.functions&&Object.keys(r).forEach((e=>{e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][s||o]||(r[e][n][s||o]=t.functions[e])):Object.keys(t.functions[e]).forEach((s=>{r[e][n]||(r[e][n]={}),r[e][n][s]||(r[e][n][s]=t.functions[e][s])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((e=>{const n=t.Interpolate[e];"function"!=typeof n||i[e]?Object.keys(n).forEach((t=>{"function"!=typeof n[t]||i[e]||(i[e]=n[t])})):i[e]=n})),E[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((e=>{k[e]||(k[e]=t.Util[e])})),e}}const D=(t,e)=>{const n=parseInt(t,10)||0,r=["px","%","deg","rad","em","rem","vh","vw"];let s;for(let e=0;e{e.style[t]=(s>.99||s<.01?(10*X(n,r,s)>>0)/10:X(n,r,s)>>0)+"px"})}const B={};["top","left","width","height"].forEach((t=>{B[t]=Z}));const R=["top","left","width","height"],Y={};R.forEach((t=>{Y[t]=Z}));const z={component:"essentialBoxModel",category:"boxModel",properties:R,defaultValues:{top:0,left:0,width:0,height:0},Interpolate:{numbers:X},functions:{prepareStart:function(t){return I(this.element,t)||g[t]},prepareProperty:function(t,e){const n=D(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:Y},Util:{trueDimension:D}},K=t=>{let e;if(/rgb|rgba/.test(t)){const n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){const n=(t=>{const e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,((t,e,n,r)=>e+e+n+n+r+r)),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null})(t);e={r:n.r,g:n.g,b:n.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){const n=document.getElementsByTagName("head")[0];n.style.color=t;let r=getComputedStyle(n,null).color;r=/rgb/.test(r)?r.replace(/[^\d,]/g,"").split(","):[0,0,0],n.style.color="",e={r:parseInt(r[0],10),g:parseInt(r[1],10),b:parseInt(r[2],10)}}return e};function W(t,e,n){const r={},s=",";return Object.keys(e).forEach((s=>{"a"!==s?r[s]=X(t[s],e[s],n)>>0||0:t[s]&&e[s]&&(r[s]=(100*X(t[s],e[s],n)>>0)/100)})),r.a?"rgba("+r.r+s+r.g+s+r.b+s+r.a+")":"rgb("+r.r+s+r.g+s+r.b+")"}function G(t){this.valuesEnd[t]&&!e[t]&&(e[t]=(e,n,r,s)=>{e.style[t]=W(n,r,s)})}const J={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((t=>{J[t]=G}));const tt=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],et={};tt.forEach((t=>{et[t]="#000"}));const nt={};tt.forEach((t=>{nt[t]=G}));const rt={component:"colorProperties",category:"colors",properties:tt,defaultValues:et,Interpolate:{numbers:X,colors:W},functions:{prepareStart:function(t){return I(this.element,t)||g[t]},prepareProperty:function(t,e){return K(e)},onStart:nt},Util:{trueColor:K}},st={},it=["fill","stroke","stop-color"];function at(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}const ot={prepareStart:function(t,e){const n={};return Object.keys(e).forEach((t=>{const e=at(t).replace(/_+[a-z]+/,""),r=this.element.getAttribute(e);n[e]=it.includes(e)?r||"rgba(0,0,0,0)":r||(/opacity/i.test(t)?1:0)})),n},prepareProperty:function(t,e){const n={};return Object.keys(e).forEach((r=>{const s=at(r),i=/(%|[a-z]+)$/,o=this.element.getAttribute(s.replace(/_+[a-z]+/,""));if(it.includes(s))a.htmlAttributes[s]=e=>{this.valuesEnd[t]&&this.valuesEnd[t][e]&&!(e in st)&&(st[e]=(t,e,n,r,s)=>{t.setAttribute(e,W(n,r,s))})},n[s]=K(e[r])||g.htmlAttributes[r];else if(null!==o&&i.test(o)){const i=D(o).u||D(e[r]).u,l=/%/.test(i)?"_percent":`_${i}`;a.htmlAttributes[s+l]=e=>{this.valuesEnd[t]&&this.valuesEnd[t][e]&&!(e in st)&&(st[e]=(t,e,n,r,s)=>{const i=e.replace(l,"");t.setAttribute(i,(1e3*X(n.v,r.v,s)>>0)/1e3+r.u)})},n[s+l]=D(e[r])}else i.test(e[r])&&null!==o&&(null===o||i.test(o))||(a.htmlAttributes[s]=e=>{this.valuesEnd[t]&&this.valuesEnd[t][e]&&!(e in st)&&(st[e]=(t,e,n,r,s)=>{t.setAttribute(e,(1e3*X(n,r,s)>>0)/1e3)})},n[s]=parseFloat(e[r]))})),n},onStart:{attr(t){!e[t]&&this.valuesEnd[t]&&(e[t]=(t,n,r,s)=>{Object.keys(r).forEach((i=>{e.attributes[i](t,i,n[i],r[i],s)}))})},attributes(t){!e[t]&&this.valuesEnd.attr&&(e[t]=st)}}},lt={component:"htmlAttributes",property:"attr",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},Interpolate:{numbers:X,colors:W},functions:ot,Util:{replaceUppercase:at,trueColor:K,trueDimension:D}};const ct={prepareStart:function(t){return I(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=(e,n,r,s)=>{e.style[t]=(1e3*X(n,r,s)>>0)/1e3})}},ut={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:X},functions:ct},ht=String("abcdefghijklmnopqrstuvwxyz").split(""),pt=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),ft=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),dt=String("0123456789").split(""),gt=ht.concat(pt,dt),yt=gt.concat(ft),mt={alpha:ht,upper:pt,symbols:ft,numeric:dt,alphanumeric:gt,all:yt},bt={text(t){if(!e[t]&&this.valuesEnd[t]){const n=this._textChars;let r=mt[y.textChars];n in mt?r=mt[n]:n&&n.length&&(r=n),e[t]=(t,e,n,s)=>{let i="",a="";const o=""===n?" ":n,l=e.substring(0),c=n.substring(0),u=r[Math.random()*r.length>>0];" "===e?(a=c.substring(Math.min(s*c.length,c.length)>>0,0),t.innerHTML=s<1?a+u:o):" "===n?(i=l.substring(0,Math.min((1-s)*l.length,l.length)>>0),t.innerHTML=s<1?i+u:o):(i=l.substring(l.length,Math.min(s*l.length,l.length)>>0),a=c.substring(0,Math.min(s*c.length,c.length)>>0),t.innerHTML=s<1?a+u+i:o)}}},number(t){t in this.valuesEnd&&!e[t]&&(e[t]=(t,e,n,r)=>{t.innerHTML=X(e,n,r)>>0})}};function vt(t,e){let n,r;if("string"==typeof t)return r=document.createElement("SPAN"),r.innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){const r=t.innerHTML;n=document.createElement("SPAN"),n.className=e,n.innerHTML=r,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&([n]=t.children);return n}function xt(t,e){let n=[];const r=t.children.length;if(r){const s=[];let i,a=t.innerHTML;for(let n,o,l,c=0;c>0)/1e3}${n})`}function wt(t,e,n,r){const s=[];for(let i=0;i<3;i+=1)s[i]=(t[i]||e[i]?(1e3*(t[i]+(e[i]-t[i])*r)>>0)/1e3:0)+n;return`translate3d(${s.join(",")})`}function kt(t,e,n,r){let s="";return s+=t[0]||e[0]?`rotateX(${(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3}${n})`:"",s+=t[1]||e[1]?`rotateY(${(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3}${n})`:"",s+=t[2]||e[2]?`rotateZ(${(1e3*(t[2]+(e[2]-t[2])*r)>>0)/1e3}${n})`:"",s}function _t(t,e,n){return`scale(${(1e3*(t+(e-t)*n)>>0)/1e3})`}function Ct(t,e,n,r){const s=[];return s[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3)+n,s[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0",`skew(${s.join(",")})`}function Ot(t,e){return parseFloat(t)/100*e}function Mt(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Tt(t){const e=t.getAttribute("points").split(" ");let n=0;if(e.length>1){const r=t=>{const e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},s=(t,e)=>void 0!==t&&void 0!==e?Math.sqrt((e[0]-t[0])**2+(e[1]-t[1])**2):0;if(e.length>2)for(let t=0;t["s","e","l"].includes(t))))return e;if("string"==typeof e){const t=e.split(/,|\s/);r=/%/.test(t[0])?Ot(t[0].trim(),n):parseFloat(t[0]),s=/%/.test(t[1])?Ot(t[1].trim(),n):parseFloat(t[1])}else void 0===e&&(a=parseFloat(I(t,"stroke-dashoffset")),i=I(t,"stroke-dasharray").split(","),r=0-a,s=parseFloat(i[0])+r||n);return{s:r,e:s,l:n}}const $t={prepareStart:function(){return Pt(this.element)},prepareProperty:function(t,e){return Pt(this.element,e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=(t,e,n,r)=>{const s=(100*e.l>>0)/100,i=0-(100*X(e.s,n.s,r)>>0)/100,a=(100*X(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=`${i}px`,t.style.strokeDasharray=`${(100*(a<1?0:a)>>0)/100}px, ${s}px`})}};function Lt(t,e,n){if(t[n].length>7){t[n].shift();const r=t[n];let s=n;for(;r.length;)e[n]="A",t.splice(s+=1,0,["C",...r.splice(0,6)]);t.splice(n,1)}}const Nt={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){let e=t.pathValue[t.segmentStart],n=e.toLowerCase(),{data:r}=t;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Nt[n]&&(t.segments.push([e,...r.splice(0,Nt[n])]),Nt[n]););}function Vt(t){const{index:e}=t,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=`Invalid path value: invalid Arc flag "${n}", expecting 0 or 1 at index ${e}`)}function Ht(t){return t>=48&&t<=57}function Qt(t){const{max:e,pathValue:n,index:r}=t;let s,i=r,a=!1,o=!1,l=!1,c=!1;if(i>=e)t.err=`Invalid path value at ${i}: missing param ${n[i]}`;else if(s=n.charCodeAt(i),43!==s&&45!==s||(i+=1,s=i=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(r)>=0);)t.index+=1;var r}function Ut(t){return t>=48&&t<=57||43===t||45===t||46===t}function Dt(t){const{max:e,pathValue:n,index:r}=t,s=n.charCodeAt(r),i=Nt[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(s))if(t.index+=1,Ft(t),t.data=[],i){for(;;){for(let r=i;r>0;r-=1){if(97!=(32|s)||3!==r&&4!==r?Qt(t):Vt(t),t.err.length)return;t.data.push(t.param),Ft(t),t.index=t.max)break;if(!Ut(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=`Invalid path value: ${n[r]} not a path command`}function Xt(t){return t.map((t=>Array.isArray(t)?[...t]:t))}function Zt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Bt(t){return Array.isArray(t)&&t.every((t=>{const e=t[0].toLowerCase();return Nt[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Rt(t){if(Bt(t))return Xt(t);const e=new Zt(t);for(Ft(e);e.indext[0]===t[0].toUpperCase()))}function zt(t){if(Yt(t))return Xt(t);const e=Rt(t);let n=0,r=0,s=0,i=0;return e.map((t=>{const e=t.slice(1).map(Number),[a]=t,o=a.toUpperCase();if("M"===a)return[n,r]=e,s=n,i=r,["M",n,r];let l=[];if(a!==o)switch(o){case"A":l=[o,e[0],e[1],e[2],e[3],e[4],e[5]+n,e[6]+r];break;case"V":l=[o,e[0]+r];break;case"H":l=[o,e[0]+n];break;default:l=[o,...e.map(((t,e)=>t+(e%2?r:n)))]}else l=[o,...e];const c=l.length;switch(o){case"Z":n=s,r=i;break;case"H":[,n]=l;break;case"V":[,r]=l;break;default:n=l[c-2],r=l[c-1],"M"===o&&(s=n,i=r)}return l}))}function Kt(t,e,n){const[r]=t,{x1:s,y1:i,x2:a,y2:o}=e,l=t.slice(1).map(Number);let c=t;if("TQ".includes(r)||(e.qx=null,e.qy=null),"H"===r)c=["L",t[1],i];else if("V"===r)c=["L",s,t[1]];else if("S"===r){const{x1:t,y1:r}=function(t,e,n,r,s){return"CS".includes(s)?{x1:2*t-n,y1:2*e-r}:{x1:t,y1:e}}(s,i,a,o,n);e.x1=t,e.y1=r,c=["C",t,r,...l]}else if("T"===r){const{qx:t,qy:r}=function(t,e,n,r,s){return"QT".includes(s)?{qx:2*t-n,qy:2*e-r}:{qx:t,qy:e}}(s,i,e.qx,e.qy,n);e.qx=t,e.qy=r,c=["Q",t,r,...l]}else if("Q"===r){const[t,n]=l;e.qx=t,e.qy=n}return c}const Wt={x1:0,y1:0,x2:0,y2:0,x:0,y:0,qx:null,qy:null};function Gt(t){if(function(t){return Yt(t)&&t.every((t=>"ACLMQZ".includes(t[0])))}(t))return Xt(t);const e=zt(t),n={...Wt},r=[],s=e.length;let i="",a="";for(let t=0;t1&&(n=Math.sqrt(n),p*=n,f*=n);const r=p*p,s=f*f,o=(i===a?-1:1)*Math.sqrt(Math.abs((r*s-r*e*e-s*t*t)/(r*e*e+s*t*t)));E=o*p*e/f+(u+d)/2,w=o*-f*t/p+(h+g)/2,v=(Math.asin((h-w)/f)*10**9>>0)/10**9,x=(Math.asin((g-w)/f)*10**9>>0)/10**9,v=ux&&(v-=2*Math.PI),!a&&x>v&&(x-=2*Math.PI)}let _=x-v;if(Math.abs(_)>y){const t=x,e=d,n=g;x=v+y*(a&&x>v?1:-1),d=E+p*Math.cos(x),g=w+f*Math.sin(x),k=ee(d,g,p,f,s,0,a,e,n,[x,t,E,w])}_=x-v;const C=Math.cos(v),O=Math.sin(v),M=Math.cos(x),T=Math.sin(x),I=Math.tan(_/4),S=4/3*p*I,A=4/3*f*I,j=[u,h],P=[u+S*O,h-A*C],$=[d+S*T,g-A*M],L=[d,g];if(P[0]=2*j[0]-P[0],P[1]=2*j[1]-P[1],c)return[...P,...$,...L,...k];k=[...P,...$,...L,...k];const N=[];for(let t=0,e=k.length;ti+.001)return{x:n,y:r};const[a,o]=re([t,e],[n,r],s/i);return{x:a,y:o}}return i}function ae(t,e,n,r){const s=.5,i=[t,e],a=[n,r],o=re(i,a,s),l=re(a,o,s),c=re(o,l,s),u=re(l,c,s),h=re(c,u,s),p=ie(...[...i,...o,...c,...h,s]),f=ie(...[...h,...u,...l,...a,0]);return[p.x,p.y,f.x,f.y,n,r]}function oe(t,e){const[n]=t,r=t.slice(1).map((t=>+t)),[s,i]=r;let a;const{x1:o,y1:l,x:c,y:u}=e;switch("TQ".includes(n)||(e.qx=null,e.qy=null),n){case"M":return e.x=s,e.y=i,t;case"A":return a=[o,l,...r],["C",...ee(...a)];case"Q":return e.qx=s,e.qy=i,a=[o,l,...r],["C",...ne(...a)];case"L":return["C",...ae(o,l,s,i)];case"Z":return["C",...ae(o,l,c,u)]}return t}const le={origin:[0,0,0],round:4};function ce(t,e){let{round:n}=le;if(!1===e||!1===n)return Xt(t);n=e>=1?e:n;const r=n>=1?10**n:1;return t.map((t=>{const e=t.slice(1).map(Number).map((t=>t%1==0?t:Math.round(t*r)/r));return[t[0],...e]}))}function ue(t,e){return ce(t,e).map((t=>t[0]+t.slice(1).join(" "))).join("")}function he(t,e,n,r,s,i,a,o,l){const c=1-l;return{x:c**3*t+3*c**2*l*n+3*c*l**2*s+l**3*a,y:c**3*e+3*c**2*l*r+3*c*l**2*i+l**3*o}}function pe(t,e,n,r,s,i,a,o,l){let c=t,u=e;let h=0,p=[t,e,h],f=[t,e],d=0;if("number"==typeof l&&l<.001)return{x:c,y:u};for(let g=0;g<=100;g+=1){if(d=g/100,({x:c,y:u}=he(t,e,n,r,s,i,a,o,d)),h+=se(f,[c,u]),f=[c,u],"number"==typeof l&&h>=l){const t=(h-l)/(h-p[2]);return{x:f[0]*(1-t)+p[0]*t,y:f[1]*(1-t)+p[1]*t}}p=[c,u,h]}return"number"==typeof l&&l>=h?{x:a,y:o}:h}function fe(t,e,n,r,s,i,a,o,l,c){let[u,h]=[t,e];const p=ee(t,e,n,r,s,i,a,o,l);let f=0,d=[],g=[],y=0;if("number"==typeof c&&c<.001)return{x:u,y:h};for(let t=0,e=p.length;t=c)return pe(...g,c-f);f+=y,[u,h]=d.slice(-2)}return"number"==typeof c&&c>=f?{x:o,y:l}:f}function de(t,e,n,r,s,i,a){const o=1-a;return{x:o**2*t+2*o*a*n+a**2*s,y:o**2*e+2*o*a*r+a**2*i}}function ge(t,e,n,r,s,i,a){let o=t,l=e;let c=0,u=[t,e,c],h=[t,e],p=0;if("number"==typeof a&&a<.001)return{x:o,y:l};for(let f=0;f<=100;f+=1){if(p=f/100,({x:o,y:l}=de(t,e,n,r,s,i,p)),c+=se(h,[o,l]),h=[o,l],"number"==typeof a&&c>=a){const t=(c-a)/(c-u[2]);return{x:h[0]*(1-t)+u[0]*t,y:h[1]*(1-t)+u[1]*t}}u=[o,l,c]}return"number"==typeof a&&a>=c?{x:s,y:i}:c}function ye(t,e){let n,r=0,s=!0,i=[],a="M",o=0,l=0,c=0,u=0,h=0;const p=Jt(Gt(t));for(let t=0,f=p.length;t=e)return ie(...i,e-r);r+=o}else if("A"===a){if(o=fe(...i),e&&r+o>=e)return fe(...i,e-r);r+=o}else if("C"===a){if(o=pe(...i),e&&r+o>=e)return pe(...i,e-r);r+=o}else if("Q"===a){if(o=ge(...i),e&&r+o>=e)return ge(...i,e-r);r+=o}else if("Z"===a){if(i=[l,c,u,h],o=ie(...i),e&&r+o>=e)return ie(...i,e-r);r+=o}[l,c]="Z"!==a?n.slice(-2):[u,h]}return e&&e>=r?{x:l,y:c}:r}function me(t){return ye(t)}function be(t,e){return ye(t,e)}function ve(t){const e=t.length;let n,r=-1,s=t[e-1],i=0;for(;++r>0)/1e3)}return s}function Ee(t,e){var n;const r=Gt((n=ue(t),ue(zt(n),0).replace(/(m|M)/g,"|$1").split("|").map((t=>t.trim())).filter((t=>t)))[0]),s=me(r),i=[];let a,o=3;e&&!Number.isNaN(e)&&+e>0&&(o=Math.max(o,Math.ceil(s/e)));for(let t=0;t0&&i.reverse(),{polygon:i,skipBisect:!0}}function we(t,e){const n=Gt(t);return function(t){const e=[],n=t.length;let r=[],s="";if(!t.length||"M"!==t[0][0])return!1;for(let i=0;ir?e+se(t[r-1],n):0),0)}(t)/e;let s,i,a,o=0,l=0,c=r/2;for(;t.lengthe;)r=re(n,r,.5),t.splice(s+1,0,r)}function Oe(t){return Array.isArray(t)&&t.every((t=>Array.isArray(t)&&2===t.length&&!Number.isNaN(t[0])&&!Number.isNaN(t[1])))}function Me(t,e){let n,r;if("string"==typeof t){const s=we(t,e);({polygon:r,skipBisect:n}=s)}else if(!Array.isArray(t))throw Error(`Invalid path value: ${t}`);const s=[...r];if(!Oe(s))throw Error(`Invalid path value: ${s}`);return s.length>1&&se(s[0],s[s.length-1])<1e-9&&s.pop(),!n&&e&&!Number.isNaN(e)&&+e>0&&Ce(s,e),s}function Te(t,e,n){const r=n||y.morphPrecision,s=Me(t,r),i=Me(e,r),a=s.length-i.length;return _e(s,a<0?-1*a:0),_e(i,a>0?a:0),ke(s,i),[ce(s),ce(i)]}const Ie={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){const n={},r=new RegExp("\\n","ig");let s=null;return e instanceof SVGPathElement?s=e:/^\.|^#/.test(e)&&(s=L(e)),"object"==typeof e&&e.polygon?e:(s&&["path","glyph"].includes(s.tagName)?n.original=s.getAttribute("d").replace(r,""):s||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=(t,e,n,r)=>{const s=e.polygon,i=n.polygon,a=i.length;t.setAttribute("d",1===r?n.original:`M${xe(s,i,a,r).join("L")}Z`)})},crossCheck:function(t){if(this.valuesEnd[t]){const e=this.valuesStart[t].polygon,n=this.valuesEnd[t].polygon;if(!e||!n||e&&n&&e.length!==n.length){const e=this.valuesStart[t].original,n=this.valuesEnd[t].original,r=this._morphPrecision?parseInt(this._morphPrecision,10):y.morphPrecision,[s,i]=Te(e,n,r);this.valuesStart[t].polygon=s,this.valuesEnd[t].polygon=i}}}},Se={EssentialBoxModel:z,ColorsProperties:rt,HTMLAttributes:lt,OpacityProperty:ut,TextWriteProp:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:X},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:bt},Util:{charSet:mt,createTextTweens:function(t,e,n){if(t.playing)return!1;const r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);const s=P.tween,i=function(t,e){const n=xt(t,"text-part"),r=xt(vt(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((t=>(t.className+=" oldText",t.outerHTML))).join(""),t.innerHTML+=r.map((t=>(t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")))).join(""),[n,r]}(t,e),a=i[0],o=i[1],l=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText"));let u=[],h=0;return u=u.concat(l.map(((t,e)=>(r.duration="auto"===r.duration?75*a[e].innerHTML.length:r.duration,r.delay=h,r.onComplete=null,h+=r.duration,new s(t,{text:t.innerHTML},{text:""},r))))),u=u.concat(c.map(((n,i)=>(r.duration="auto"===r.duration?75*o[i].innerHTML.length:r.duration,r.delay=h,r.onComplete=i===o.length-1?function(){t.innerHTML=e,t.playing=!1}:null,h+=r.duration,new s(n,{text:""},{text:o[i].innerHTML},r))))),u.start=function(){t.playing||(u.forEach((t=>t.start())),t.playing=!0)},u}}},TransformFunctions:{component:"transformFunctions",property:"transform",subProperties:["perspective","translate3d","translateX","translateY","translateZ","translate","rotate3d","rotateX","rotateY","rotateZ","rotate","skewX","skewY","skew","scale"],defaultValues:{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},functions:{prepareStart:function(t){const e=T(this.element);return e[t]?e[t]:g[t]},prepareProperty:function(t,e){const n=["X","Y","Z"],r={},s=[],i=[],a=[],o=["translate3d","translate","rotate3d","skew"];return Object.keys(e).forEach((t=>{const l="object"==typeof e[t]&&e[t].length?e[t].map((t=>parseInt(t,10))):parseInt(e[t],10);if(o.includes(t)){const e="translate"===t||"rotate"===t?`${t}3d`:t;r[e]="skew"===t?l.length?[l[0]||0,l[1]||0]:[l||0,0]:"translate"===t?l.length?[l[0]||0,l[1]||0,l[2]||0]:[l||0,0,0]:[l[0]||0,l[1]||0,l[2]||0]}else if(/[XYZ]/.test(t)){const o=t.replace(/[XYZ]/,""),l="skew"===o?o:`${o}3d`,c="skew"===o?2:3;let u=[];"translate"===o?u=s:"rotate"===o?u=i:"skew"===o&&(u=a);for(let t=0;t{e.style[t]=(n.perspective||r.perspective?Et(n.perspective,r.perspective,"px",s):"")+(n.translate3d?wt(n.translate3d,r.translate3d,"px",s):"")+(n.rotate3d?kt(n.rotate3d,r.rotate3d,"deg",s):"")+(n.skew?Ct(n.skew,r.skew,"deg",s):"")+(n.scale||r.scale?_t(n.scale,r.scale,s):"")})},crossCheck:function(t){this.valuesEnd[t]&&this.valuesEnd[t]&&this.valuesEnd[t].perspective&&!this.valuesStart[t].perspective&&(this.valuesStart[t].perspective=this.valuesEnd[t].perspective)}},Interpolate:{perspective:Et,translate3d:wt,rotate3d:kt,translate:function(t,e,n,r){const s=[];return s[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3)+n,s[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0",`translate(${s.join(",")})`},rotate:function(t,e,n,r){return`rotate(${(1e3*(t+(e-t)*r)>>0)/1e3}${n})`},scale:_t,skew:Ct}},SVGDraw:{component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:X},functions:$t,Util:{getRectLength:Mt,getPolyLength:Tt,getLineLength:It,getCircleLength:St,getEllipseLength:At,getTotalLength:jt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:Pt,percent:Ot}},SVGMorph:{component:"svgMorph",property:"path",defaultValue:[],Interpolate:xe,defaultOptions:{morphPrecision:10},functions:Ie,Util:{addPoints:_e,bisect:Ce,getPolygon:Me,validPolygon:Oe,getInterpolationPoints:Te,pathStringToPolygon:we,distanceSquareRoot:se,midPoint:re,approximatePolygon:Ee,rotatePolygon:ke,pathToString:ue,pathToCurve:function(t){if(function(t){return Bt(t)&&t.every((t=>"MC".includes(t[0])))}(t))return Xt(t);const e=Jt(Gt(t)),n={...Wt},r=[];let s="",i=e.length;for(let t=0;t{const e=Se[t];Se[t]=new U(e)}));const Ae={Animation:U,Components:Se,Tween:V,fromTo:function(t,e,n,r){const s=r||{};return new F(L(t),e,n,s)},to:function(t,e,n){const r=n||{};return r.resetStart=e,new Q(L(t),e,e,r)},TweenCollection:H,allFromTo:function(t,e,n,r){const s=r||{};return new H(L(t,!0),e,n,s)},allTo:function(t,e,n){const r=n||{};return r.resetStart=e,new H(L(t,!0),e,e,r)},Objects:w,Util:k,Easing:$,CubicBezier:t,Render:f,Interpolate:i,Process:j,Internals:M,Selector:L,Version:"2.2.3"};export{Ae as default}; diff --git a/dist/kute.js b/dist/kute.js new file mode 100644 index 0000000..c750121 --- /dev/null +++ b/dist/kute.js @@ -0,0 +1,4675 @@ +/*! +* KUTE.js Standard v2.2.3 (http://thednp.github.io/kute.js) +* Copyright 2015-2021 © thednp +* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE) +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.KUTE = factory()); +})(this, (function () { 'use strict'; + + /** + * Creates cubic-bezier easing functions. + * + * @class + */ + var CubicBezier = function CubicBezier(p1x, p1y, p2x, p2y, functionName) { + var this$1$1 = this; + + // pre-calculate the polynomial coefficients + // First and last control points are implied to be (0,0) and (1.0, 1.0) + + /** @type {number} */ + this.cx = 3.0 * p1x; + + /** @type {number} */ + this.bx = 3.0 * (p2x - p1x) - this.cx; + + /** @type {number} */ + this.ax = 1.0 - this.cx - this.bx; + + /** @type {number} */ + this.cy = 3.0 * p1y; + + /** @type {number} */ + this.by = 3.0 * (p2y - p1y) - this.cy; + + /** @type {number} */ + this.ay = 1.0 - this.cy - this.by; + + /** @type {(t: number) => number} */ + var BezierEasing = function (t) { return this$1$1.sampleCurveY(this$1$1.solveCurveX(t)); }; + + // this function needs a name + Object.defineProperty(BezierEasing, 'name', { writable: true }); + BezierEasing.name = functionName || ("cubic-bezier(" + ([p1x, p1y, p2x, p2y]) + ")"); + + return BezierEasing; + }; + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled X value + */ + CubicBezier.prototype.sampleCurveX = function sampleCurveX (t) { + return ((this.ax * t + this.bx) * t + this.cx) * t; + }; + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled Y value + */ + CubicBezier.prototype.sampleCurveY = function sampleCurveY (t) { + return ((this.ay * t + this.by) * t + this.cy) * t; + }; + + /** + * @param {number} t - progress [0-1] + * @return {number} - sampled curve derivative X value + */ + CubicBezier.prototype.sampleCurveDerivativeX = function sampleCurveDerivativeX (t) { + return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx; + }; + + /** + * @param {number} x - progress [0-1] + * @return {number} - solved curve X value + */ + CubicBezier.prototype.solveCurveX = function solveCurveX (x) { + var t0; + var t1; + var t2; + var x2; + var d2; + var i; + var epsilon = 1e-5; // Precision + + // First try a few iterations of Newton's method -- normally very fast. + for (t2 = x, i = 0; i < 32; i += 1) { + x2 = this.sampleCurveX(t2) - x; + if (Math.abs(x2) < epsilon) { return t2; } + d2 = this.sampleCurveDerivativeX(t2); + if (Math.abs(d2) < epsilon) { break; } + t2 -= x2 / d2; + } + + // No solution found - use bi-section + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) { return t0; } + if (t2 > t1) { return t1; } + + while (t0 < t1) { + x2 = this.sampleCurveX(t2); + if (Math.abs(x2 - x) < epsilon) { return t2; } + if (x > x2) { t0 = t2; } + else { t1 = t2; } + + t2 = (t1 - t0) * 0.5 + t0; + } + + // Give up + return t2; + }; + + var version$1 = "1.0.18"; + + // @ts-ignore + + /** + * A global namespace for library version. + * @type {string} + */ + var Version$1 = version$1; + + Object.assign(CubicBezier, { Version: Version$1 }); + + /** + * The KUTE.js Execution Context + */ + var KEC = {}; + + var Tweens = []; + + var gl0bal; + + if (typeof global !== 'undefined') { gl0bal = global; } + else if (typeof window !== 'undefined') { gl0bal = window.self; } + else { gl0bal = {}; } + + var globalObject = gl0bal; + + // KUTE.js INTERPOLATE FUNCTIONS + // ============================= + var interpolate = {}; + + // schedule property specific function on animation start + // link property update function to KUTE.js execution context + var onStart = {}; + + // Include a performance.now polyfill. + // source https://github.com/tweenjs/tween.js/blob/master/src/Now.ts + var performanceNow; + + // In node.js, use process.hrtime. + // eslint-disable-next-line + // @ts-ignore + if (typeof self === 'undefined' && typeof process !== 'undefined' && process.hrtime) { + performanceNow = function () { + // eslint-disable-next-line + // @ts-ignore + var time = process.hrtime(); + + // Convert [seconds, nanoseconds] to milliseconds. + return time[0] * 1000 + time[1] / 1000000; + }; + } else if (typeof self !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) { + // In a browser, use self.performance.now if it is available. + // This must be bound, because directly assigning this function + // leads to an invocation exception in Chrome. + performanceNow = self.performance.now.bind(self.performance); + } else if (typeof Date !== 'undefined' && Date.now) { + // Use Date.now if it is available. + performanceNow = Date.now; + } else { + // Otherwise, use 'new Date().getTime()'. + performanceNow = function () { return new Date().getTime(); }; + } + + var now = performanceNow; + + var Time = {}; + Time.now = now; + + // eslint-disable-next-line import/no-mutable-exports -- impossible to satisfy + var Tick = 0; + + /** + * + * @param {number | Date} time + */ + var Ticker = function (time) { + var i = 0; + while (i < Tweens.length) { + if (Tweens[i].update(time)) { + i += 1; + } else { + Tweens.splice(i, 1); + } + } + Tick = requestAnimationFrame(Ticker); + }; + + // stop requesting animation frame + function stop() { + setTimeout(function () { // re-added for #81 + if (!Tweens.length && Tick) { + cancelAnimationFrame(Tick); + Tick = null; + Object.keys(onStart).forEach(function (obj) { + if (typeof (onStart[obj]) === 'function') { + if (KEC[obj]) { delete KEC[obj]; } + } else { + Object.keys(onStart[obj]).forEach(function (prop) { + if (KEC[prop]) { delete KEC[prop]; } + }); + } + }); + + Object.keys(interpolate).forEach(function (i) { + if (KEC[i]) { delete KEC[i]; } + }); + } + }, 64); + } + + // render update functions + // ======================= + var Render = { + Tick: Tick, Ticker: Ticker, Tweens: Tweens, Time: Time, + }; + Object.keys(Render).forEach(function (blob) { + if (!KEC[blob]) { + KEC[blob] = blob === 'Time' ? Time.now : Render[blob]; + } + }); + + globalObject._KUTE = KEC; + + // all supported properties + var supportedProperties = {}; + + var defaultValues = {}; + + var defaultOptions$1 = { + duration: 700, + delay: 0, + easing: 'linear', + repeat: 0, + repeatDelay: 0, + yoyo: false, + resetStart: false, + offset: 0, + }; + + // used in preparePropertiesObject + var prepareProperty = {}; + + // check current property value when .to() method is used + var prepareStart = {}; + + // checks for differences between the processed start and end values, + // can be set to make sure start unit and end unit are same, + // stack transforms, process SVG paths, + // any type of post processing the component needs + var crossCheck = {}; + + // schedule property specific function on animation complete + var onComplete = {}; + + // link properties to interpolate functions + var linkProperty = {}; + + var Objects = { + supportedProperties: supportedProperties, + defaultValues: defaultValues, + defaultOptions: defaultOptions$1, + prepareProperty: prepareProperty, + prepareStart: prepareStart, + crossCheck: crossCheck, + onStart: onStart, + onComplete: onComplete, + linkProperty: linkProperty, + }; + + // util - a general object for utils like rgbToHex, processEasing + var Util = {}; + + /** + * KUTE.add(Tween) + * + * @param {KUTE.Tween} tw a new tween to add + */ + var add = function (tw) { return Tweens.push(tw); }; + + /** + * KUTE.remove(Tween) + * + * @param {KUTE.Tween} tw a new tween to add + */ + var remove = function (tw) { + var i = Tweens.indexOf(tw); + if (i !== -1) { Tweens.splice(i, 1); } + }; + + /** + * KUTE.add(Tween) + * + * @return {KUTE.Tween[]} tw a new tween to add + */ + var getAll = function () { return Tweens; }; + + /** + * KUTE.removeAll() + */ + var removeAll = function () { Tweens.length = 0; }; + + /** + * linkInterpolation + * @this {KUTE.Tween} + */ + function linkInterpolation() { + var this$1$1 = this; + // DON'T change + Object.keys(linkProperty).forEach(function (component) { + var componentLink = linkProperty[component]; + var componentProps = supportedProperties[component]; + + Object.keys(componentLink).forEach(function (fnObj) { + if (typeof (componentLink[fnObj]) === 'function' // ATTR, colors, scroll, boxModel, borderRadius + && Object.keys(this$1$1.valuesEnd).some(function (i) { return (componentProps && componentProps.includes(i)) + || (i === 'attr' && Object.keys(this$1$1.valuesEnd[i]).some(function (j) { return componentProps && componentProps.includes(j); })); })) { + if (!KEC[fnObj]) { KEC[fnObj] = componentLink[fnObj]; } + } else { + Object.keys(this$1$1.valuesEnd).forEach(function (prop) { + var propObject = this$1$1.valuesEnd[prop]; + if (propObject instanceof Object) { + Object.keys(propObject).forEach(function (i) { + if (typeof (componentLink[i]) === 'function') { // transformCSS3 + if (!KEC[i]) { KEC[i] = componentLink[i]; } + } else { + Object.keys(componentLink[fnObj]).forEach(function (j) { + if (componentLink[i] && typeof (componentLink[i][j]) === 'function') { // transformMatrix + if (!KEC[j]) { KEC[j] = componentLink[i][j]; } + } + }); + } + }); + } + }); + } + }); + }); + } + + var internals = { + add: add, + remove: remove, + getAll: getAll, + removeAll: removeAll, + stop: stop, + linkInterpolation: linkInterpolation, + }; + + /** + * getInlineStyle + * Returns the transform style for element from + * cssText. Used by for the `.to()` static method. + * + * @param {Element} el target element + * @returns {object} + */ + function getInlineStyle(el) { + // if the scroll applies to `window` it returns as it has no styling + if (!el.style) { return false; } + // the cssText | the resulting transform object + var css = el.style.cssText.replace(/\s/g, '').split(';'); + var transformObject = {}; + var arrayFn = ['translate3d', 'translate', 'scale3d', 'skew']; + + css.forEach(function (cs) { + if (/transform/i.test(cs)) { + // all transform properties + var tps = cs.split(':')[1].split(')'); + tps.forEach(function (tpi) { + var tpv = tpi.split('('); + var tp = tpv[0]; + // each transform property + var tv = tpv[1]; + if (!/matrix/.test(tp)) { + transformObject[tp] = arrayFn.includes(tp) ? tv.split(',') : tv; + } + }); + } + }); + + return transformObject; + } + + /** + * getStyleForProperty + * + * Returns the computed style property for element for .to() method. + * Used by for the `.to()` static method. + * + * @param {Element} elem + * @param {string} propertyName + * @returns {string} + */ + function getStyleForProperty(elem, propertyName) { + var result = defaultValues[propertyName]; + var styleAttribute = elem.style; + var computedStyle = getComputedStyle(elem) || elem.currentStyle; + var styleValue = styleAttribute[propertyName] && !/auto|initial|none|unset/.test(styleAttribute[propertyName]) + ? styleAttribute[propertyName] + : computedStyle[propertyName]; + + if (propertyName !== 'transform' && (propertyName in computedStyle || propertyName in styleAttribute)) { + result = styleValue; + } + + return result; + } + + /** + * prepareObject + * + * Returns all processed valuesStart / valuesEnd. + * + * @param {Element} obj the values start/end object + * @param {string} fn toggles between the two + */ + function prepareObject(obj, fn) { + var this$1$1 = this; + // this, props object, type: start/end + var propertiesObject = fn === 'start' ? this.valuesStart : this.valuesEnd; + + Object.keys(prepareProperty).forEach(function (component) { + var prepareComponent = prepareProperty[component]; + var supportComponent = supportedProperties[component]; + + Object.keys(prepareComponent).forEach(function (tweenCategory) { + var transformObject = {}; + + Object.keys(obj).forEach(function (tweenProp) { + // scroll, opacity, other components + if (defaultValues[tweenProp] && prepareComponent[tweenProp]) { + propertiesObject[tweenProp] = prepareComponent[tweenProp] + .call(this$1$1, tweenProp, obj[tweenProp]); + + // transform + } else if (!defaultValues[tweenCategory] && tweenCategory === 'transform' + && supportComponent.includes(tweenProp)) { + transformObject[tweenProp] = obj[tweenProp]; + + // allow transformFunctions to work with preprocessed input values + } else if (!defaultValues[tweenProp] && tweenProp === 'transform') { + propertiesObject[tweenProp] = obj[tweenProp]; + + // colors, boxModel, category + } else if (!defaultValues[tweenCategory] + && supportComponent && supportComponent.includes(tweenProp)) { + propertiesObject[tweenProp] = prepareComponent[tweenCategory] + .call(this$1$1, tweenProp, obj[tweenProp]); + } + }); + + // we filter out older browsers by checking Object.keys + if (Object.keys(transformObject).length) { + propertiesObject[tweenCategory] = prepareComponent[tweenCategory] + .call(this$1$1, tweenCategory, transformObject); + } + }); + }); + } + + /** + * getStartValues + * + * Returns the start values for to() method. + * Used by for the `.to()` static method. + * + * @this {KUTE.Tween} the tween instance + */ + function getStartValues() { + var this$1$1 = this; + + var startValues = {}; + var currentStyle = getInlineStyle(this.element); + + Object.keys(this.valuesStart).forEach(function (tweenProp) { + Object.keys(prepareStart).forEach(function (component) { + var componentStart = prepareStart[component]; + + Object.keys(componentStart).forEach(function (tweenCategory) { + // clip, opacity, scroll + if (tweenCategory === tweenProp && componentStart[tweenProp]) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this$1$1, tweenProp, this$1$1.valuesStart[tweenProp]); + // find in an array of properties + } else if (supportedProperties[component] + && supportedProperties[component].includes(tweenProp)) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this$1$1, tweenProp, this$1$1.valuesStart[tweenProp]); + } + }); + }); + }); + + // stack transformCSS props for .to() chains + // also add to startValues values from previous tweens + Object.keys(currentStyle).forEach(function (current) { + if (!(current in this$1$1.valuesStart)) { + startValues[current] = currentStyle[current] || defaultValues[current]; + } + }); + + this.valuesStart = {}; + prepareObject.call(this, startValues, 'start'); + } + + var Process = { + getInlineStyle: getInlineStyle, + getStyleForProperty: getStyleForProperty, + getStartValues: getStartValues, + prepareObject: prepareObject, + }; + + var connect = {}; + /** @type {KUTE.TweenBase | KUTE.Tween | KUTE.TweenExtra} */ + connect.tween = null; + connect.processEasing = null; + + var 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)) { + 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 + } + // if (/elastic|bounce/i.test(fn)) { + // throw TypeError(`KUTE - CubicBezier doesn't support ${fn} easing.`); + // } + return Easing.linear; + } + + connect.processEasing = processBezierEasing; + + /** + * selector + * + * A selector utility for KUTE.js. + * + * @param {KUTE.selectorType} el target(s) or string selector + * @param {boolean | number} multi when true returns an array/collection of elements + * @returns {Element | Element[] | null} + */ + function selector(el, multi) { + try { + var requestedElem; + var itemsArray; + if (multi) { + itemsArray = el instanceof Array && el.every(function (x) { return x instanceof Element; }); + requestedElem = el instanceof HTMLCollection || el instanceof NodeList || itemsArray + ? el : document.querySelectorAll(el); + } else { + requestedElem = el instanceof Element || el === window // scroll + ? el : document.querySelector(el); + } + return requestedElem; + } catch (e) { + throw TypeError(("KUTE.js - Element(s) not found: " + el + ".")); + } + } + + function queueStart() { + var this$1$1 = this; + + // fire onStart actions + Object.keys(onStart).forEach(function (obj) { + if (typeof (onStart[obj]) === 'function') { + onStart[obj].call(this$1$1, obj); // easing functions + } else { + Object.keys(onStart[obj]).forEach(function (prop) { + onStart[obj][prop].call(this$1$1, prop); + }); + } + }); + + // add interpolations + linkInterpolation.call(this); + } + + /** + * The `TweenBase` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * `TweenBase` is meant to be used with pre-processed values. + */ + var TweenBase = function TweenBase(targetElement, startObject, endObject, opsObject) { + var this$1$1 = this; + + // element animation is applied to + this.element = targetElement; + + /** @type {boolean} */ + this.playing = false; + /** @type {number?} */ + this._startTime = null; + /** @type {boolean} */ + this._startFired = false; + + // type is set via KUTE.tweenProps + this.valuesEnd = endObject; + this.valuesStart = startObject; + + // OPTIONS + var options = opsObject || {}; + // internal option to process inline/computed style at start instead of init + // used by to() method and expects object : {} / false + this._resetStart = options.resetStart || 0; + // you can only set a core easing function as default + /** @type {KUTE.easingOption} */ + this._easing = typeof (options.easing) === 'function' ? options.easing : connect.processEasing(options.easing); + /** @type {number} */ + this._duration = options.duration || defaultOptions$1.duration; // duration option | default + /** @type {number} */ + this._delay = options.delay || defaultOptions$1.delay; // delay option | default + + // set other options + Object.keys(options).forEach(function (op) { + var internalOption = "_" + op; + if (!(internalOption in this$1$1)) { this$1$1[internalOption] = options[op]; } + }); + + // callbacks should not be set as undefined + // this._onStart = options.onStart + // this._onUpdate = options.onUpdate + // this._onStop = options.onStop + // this._onComplete = options.onComplete + + // queue the easing + var easingFnName = this._easing.name; + if (!onStart[easingFnName]) { + onStart[easingFnName] = function easingFn(prop) { + if (!KEC[prop] && prop === this._easing.name) { KEC[prop] = this._easing; } + }; + } + + return this; + }; + + /** + * Starts tweening + * @param {number?} time the tween start time + * @returns {TweenBase} this instance + */ + TweenBase.prototype.start = function start (time) { + // now it's a good time to start + add(this); + this.playing = true; + + this._startTime = typeof time !== 'undefined' ? time : KEC.Time(); + this._startTime += this._delay; + + if (!this._startFired) { + if (this._onStart) { + this._onStart.call(this); + } + + queueStart.call(this); + + this._startFired = true; + } + + if (!Tick) { Ticker(); } + return this; + }; + + /** + * Stops tweening + * @returns {TweenBase} this instance + */ + TweenBase.prototype.stop = function stop () { + if (this.playing) { + remove(this); + this.playing = false; + + if (this._onStop) { + this._onStop.call(this); + } + this.close(); + } + return this; + }; + + /** + * Trigger internal completion callbacks. + */ + TweenBase.prototype.close = function close () { + var this$1$1 = this; + + // scroll|transformMatrix need this + Object.keys(onComplete).forEach(function (component) { + Object.keys(onComplete[component]).forEach(function (toClose) { + onComplete[component][toClose].call(this$1$1, toClose); + }); + }); + // when all animations are finished, stop ticking after ~3 frames + this._startFired = false; + stop.call(this); + }; + + /** + * Schedule another tween instance to start once this one completes. + * @param {KUTE.chainOption} args the tween animation start time + * @returns {TweenBase} this instance + */ + TweenBase.prototype.chain = function chain (args) { + this._chain = []; + this._chain = args.length ? args : this._chain.concat(args); + return this; + }; + + /** + * Stop tweening the chained tween instances. + */ + TweenBase.prototype.stopChainedTweens = function stopChainedTweens () { + if (this._chain && this._chain.length) { this._chain.forEach(function (tw) { return tw.stop(); }); } + }; + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + TweenBase.prototype.update = function update (time) { + var this$1$1 = this; + + var T = time !== undefined ? time : KEC.Time(); + + var elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + var progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach(function (tweenProp) { + KEC[tweenProp](this$1$1.element, + this$1$1.valuesStart[tweenProp], + this$1$1.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.map(function (tw) { return tw.start(); }); + } + + return false; + } + + return true; + }; + + // Update Tween Interface + connect.tween = TweenBase; + + /** + * The `KUTE.Tween()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor adds additional functionality and is the default + * Tween object constructor in KUTE.js. + */ + var Tween = /*@__PURE__*/(function (TweenBase) { + function Tween() { + var this$1$1 = this; + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + TweenBase.apply(this, args); // this calls the constructor of TweenBase + + // reset interpolation values + this.valuesStart = {}; + this.valuesEnd = {}; + + // const startObject = args[1]; + // const endObject = args[2]; + var ref = args.slice(1); + var startObject = ref[0]; + var endObject = ref[1]; + var options = ref[2]; + + // set valuesEnd + prepareObject.call(this, endObject, 'end'); + + // set valuesStart + if (this._resetStart) { + this.valuesStart = startObject; + } else { + prepareObject.call(this, startObject, 'start'); + } + + // ready for crossCheck + if (!this._resetStart) { + Object.keys(crossCheck).forEach(function (component) { + Object.keys(crossCheck[component]).forEach(function (checkProp) { + crossCheck[component][checkProp].call(this$1$1, checkProp); + }); + }); + } + + // set paused state + /** @type {boolean} */ + this.paused = false; + /** @type {number?} */ + this._pauseTime = null; + + // additional properties and options + /** @type {number?} */ + this._repeat = options.repeat || defaultOptions$1.repeat; + /** @type {number?} */ + this._repeatDelay = options.repeatDelay || defaultOptions$1.repeatDelay; + // we cache the number of repeats to be able to put it back after all cycles finish + /** @type {number?} */ + this._repeatOption = this._repeat; + + // yoyo needs at least repeat: 1 + /** @type {KUTE.tweenProps} */ + this.valuesRepeat = {}; // valuesRepeat + /** @type {boolean} */ + this._yoyo = options.yoyo || defaultOptions$1.yoyo; + /** @type {boolean} */ + this._reversed = false; + + // don't load extra callbacks + // this._onPause = options.onPause || defaultOptions.onPause + // this._onResume = options.onResume || defaultOptions.onResume + + // chained Tweens + // this._chain = options.chain || defaultOptions.chain; + return this; + } + + if ( TweenBase ) Tween.__proto__ = TweenBase; + Tween.prototype = Object.create( TweenBase && TweenBase.prototype ); + Tween.prototype.constructor = Tween; + + /** + * Starts tweening, extended method + * @param {number?} time the tween start time + * @returns {Tween} this instance + */ + Tween.prototype.start = function start (time) { + var this$1$1 = this; + + // on start we reprocess the valuesStart for TO() method + if (this._resetStart) { + this.valuesStart = this._resetStart; + getStartValues.call(this); + + // this is where we do the valuesStart and valuesEnd check for fromTo() method + Object.keys(crossCheck).forEach(function (component) { + Object.keys(crossCheck[component]).forEach(function (checkProp) { + crossCheck[component][checkProp].call(this$1$1, checkProp); + }); + }); + } + // still not paused + this.paused = false; + + // set yoyo values + if (this._yoyo) { + Object.keys(this.valuesEnd).forEach(function (endProp) { + this$1$1.valuesRepeat[endProp] = this$1$1.valuesStart[endProp]; + }); + } + + TweenBase.prototype.start.call(this, time); + + return this; + }; + + /** + * Stops tweening, extended method + * @returns {Tween} this instance + */ + Tween.prototype.stop = function stop () { + TweenBase.prototype.stop.call(this); + if (!this.paused && this.playing) { + this.paused = false; + this.stopChainedTweens(); + } + return this; + }; + + /** + * Trigger internal completion callbacks. + */ + Tween.prototype.close = function close () { + TweenBase.prototype.close.call(this); + + if (this._repeatOption > 0) { + this._repeat = this._repeatOption; + } + if (this._yoyo && this._reversed === true) { + this.reverse(); + this._reversed = false; + } + + return this; + }; + + /** + * Resume tweening + * @returns {Tween} this instance + */ + Tween.prototype.resume = function resume () { + if (this.paused && this.playing) { + this.paused = false; + if (this._onResume !== undefined) { + this._onResume.call(this); + } + // re-queue execution context + queueStart.call(this); + // update time and let it roll + this._startTime += KEC.Time() - this._pauseTime; + add(this); + // restart ticker if stopped + if (!Tick) { Ticker(); } + } + return this; + }; + + /** + * Pause tweening + * @returns {Tween} this instance + */ + Tween.prototype.pause = function pause () { + if (!this.paused && this.playing) { + remove(this); + this.paused = true; + this._pauseTime = KEC.Time(); + if (this._onPause !== undefined) { + this._onPause.call(this); + } + } + return this; + }; + + /** + * Reverses start values with end values + */ + Tween.prototype.reverse = function reverse () { + var this$1$1 = this; + + Object.keys(this.valuesEnd).forEach(function (reverseProp) { + var tmp = this$1$1.valuesRepeat[reverseProp]; + this$1$1.valuesRepeat[reverseProp] = this$1$1.valuesEnd[reverseProp]; + this$1$1.valuesEnd[reverseProp] = tmp; + this$1$1.valuesStart[reverseProp] = this$1$1.valuesRepeat[reverseProp]; + }); + }; + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + Tween.prototype.update = function update (time) { + var this$1$1 = this; + + var T = time !== undefined ? time : KEC.Time(); + + var elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + var progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach(function (tweenProp) { + KEC[tweenProp](this$1$1.element, + this$1$1.valuesStart[tweenProp], + this$1$1.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + if (this._repeat > 0) { + if (Number.isFinite(this._repeat)) { this._repeat -= 1; } + + // set the right time for delay + this._startTime = T; + if (Number.isFinite(this._repeat) && this._yoyo && !this._reversed) { + this._startTime += this._repeatDelay; + } + + if (this._yoyo) { // handle yoyo + this._reversed = !this._reversed; + this.reverse(); + } + + return true; + } + + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.forEach(function (tw) { return tw.start(); }); + } + + return false; + } + return true; + }; + + return Tween; + }(TweenBase)); + + // Update Tween Interface Update + connect.tween = Tween; + + /** + * The static method creates a new `Tween` object for each `HTMLElement` + * from and `Array`, `HTMLCollection` or `NodeList`. + */ + var TweenCollection = function TweenCollection(els, vS, vE, Options) { + var this$1$1 = this; + + var TweenConstructor = connect.tween; + /** @type {KUTE.twCollection[]} */ + this.tweens = []; + + var Ops = Options || {}; + /** @type {number?} */ + Ops.delay = Ops.delay || defaultOptions$1.delay; + + // set all options + var options = []; + + Array.from(els).forEach(function (el, i) { + options[i] = Ops || {}; + options[i].delay = i > 0 ? Ops.delay + (Ops.offset || defaultOptions$1.offset) : Ops.delay; + if (el instanceof Element) { + this$1$1.tweens.push(new TweenConstructor(el, vS, vE, options[i])); + } else { + throw Error(("KUTE - " + el + " is not instanceof Element")); + } + }); + + /** @type {number?} */ + this.length = this.tweens.length; + return this; + }; + + /** + * Starts tweening, all targets + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.start = function start (time) { + var T = time === undefined ? KEC.Time() : time; + this.tweens.map(function (tween) { return tween.start(T); }); + return this; + }; + + /** + * Stops tweening, all targets and their chains + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.stop = function stop () { + this.tweens.map(function (tween) { return tween.stop(); }); + return this; + }; + + /** + * Pause tweening, all targets + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.pause = function pause () { + this.tweens.map(function (tween) { return tween.pause(); }); + return this; + }; + + /** + * Resume tweening, all targets + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.resume = function resume () { + this.tweens.map(function (tween) { return tween.resume(); }); + return this; + }; + + /** + * Schedule another tween or collection to start after + * this one is complete. + * @param {number?} args the tween start time + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.chain = function chain (args) { + var lastTween = this.tweens[this.length - 1]; + if (args instanceof TweenCollection) { + lastTween.chain(args.tweens); + } else if (args instanceof connect.tween) { + lastTween.chain(args); + } else { + throw new TypeError('KUTE.js - invalid chain value'); + } + return this; + }; + + /** + * Check if any tween instance is playing + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + TweenCollection.prototype.playing = function playing () { + return this.tweens.some(function (tw) { return tw.playing; }); + }; + + /** + * Remove all tweens in the collection + */ + TweenCollection.prototype.removeTweens = function removeTweens () { + this.tweens = []; + }; + + /** + * Returns the maximum animation duration + * @returns {number} this instance + */ + TweenCollection.prototype.getMaxDuration = function getMaxDuration () { + var durations = []; + this.tweens.forEach(function (tw) { + durations.push(tw._duration + tw._delay + tw._repeat * tw._repeatDelay); + }); + return Math.max(durations); + }; + + var TweenConstructor$1 = connect.tween; + + /** + * The `KUTE.to()` static method returns a new Tween object + * for a single `HTMLElement` at its current state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ + function to(element, endObject, optionsObj) { + var options = optionsObj || {}; + options.resetStart = endObject; + return new TweenConstructor$1(selector(element), endObject, endObject, options); + } + + var TweenConstructor = connect.tween; + + /** + * The `KUTE.fromTo()` static method returns a new Tween object + * for a single `HTMLElement` at a given state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ + function fromTo(element, startObject, endObject, optionsObj) { + var options = optionsObj || {}; + return new TweenConstructor(selector(element), startObject, endObject, options); + } + + /** + * The `KUTE.allTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at their current state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenProps} optionsObj progress + * @returns {TweenCollection} the Tween object collection + */ + function allTo(elements, endObject, optionsObj) { + var options = optionsObj || {}; + options.resetStart = endObject; + return new TweenCollection(selector(elements, true), endObject, endObject, options); + } + + /** + * The `KUTE.allFromTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at a given state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {TweenCollection} the Tween object collection + */ + function allFromTo(elements, startObject, endObject, optionsObj) { + var options = optionsObj || {}; + return new TweenCollection(selector(elements, true), startObject, endObject, options); + } + + /** + * Animation Class + * + * Registers components by populating KUTE.js objects and makes sure + * no duplicate component / property is allowed. + */ + var Animation = function Animation(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); + } + + var propertyInfo = this; + var ComponentName = Component.component; + // const Objects = { defaultValues, defaultOptions, Interpolate, linkProperty, Util } + var Functions = { + prepareProperty: prepareProperty, prepareStart: prepareStart, onStart: onStart, onComplete: onComplete, crossCheck: crossCheck, + }; + var Category = Component.category; + var Property = Component.property; + var Length = (Component.properties && Component.properties.length) + || (Component.subProperties && Component.subProperties.length); + + // 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(function (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$1, Component.defaultOptions); + } + + // set functions + if (Component.functions) { + Object.keys(Functions).forEach(function (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(function (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(function (fni) { + var compIntObj = Component.Interpolate[fni]; + if (typeof (compIntObj) === 'function' && !interpolate[fni]) { + interpolate[fni] = compIntObj; + } else { + Object.keys(compIntObj).forEach(function (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(function (fnu) { + if (!Util[fnu]) { Util[fnu] = Component.Util[fnu]; } + }); + } + + return propertyInfo; + }; + + /** + * trueDimension + * + * Returns the string value of a specific CSS property converted into a nice + * { v = value, u = unit } object. + * + * @param {string} dimValue the property string value + * @param {boolean | number} isAngle sets the utility to investigate angles + * @returns {{v: number, u: string}} the true {value, unit} tuple + */ + var trueDimension = function (dimValue, isAngle) { + var intValue = parseInt(dimValue, 10) || 0; + var mUnits = ['px', '%', 'deg', 'rad', 'em', 'rem', 'vh', 'vw']; + var theUnit; + + for (var mIndex = 0; mIndex < mUnits.length; mIndex += 1) { + if (typeof dimValue === 'string' && dimValue.includes(mUnits[mIndex])) { + theUnit = mUnits[mIndex]; break; + } + } + if (theUnit === undefined) { + theUnit = isAngle ? 'deg' : 'px'; + } + + return { v: intValue, u: theUnit }; + }; + + /** + * Numbers Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {number} v progress + * @returns {number} the interpolated number + */ + function numbers(a, b, v) { + var A = +a; + var B = b - a; + // a = +a; b -= a; + return A + B * v; + } + + // Component Functions + /** + * Sets the update function for the property. + * @param {string} tweenProp the property name + */ + function boxModelOnStart(tweenProp) { + if (tweenProp in this.valuesEnd && !KEC[tweenProp]) { + KEC[tweenProp] = function (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 + var baseBoxProps = ['top', 'left', 'width', 'height']; + var baseBoxOnStart = {}; + baseBoxProps.forEach(function (x) { baseBoxOnStart[x] = boxModelOnStart; }); + + // 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) { + var boxValue = trueDimension(value); + var offsetProp = tweenProp === 'height' ? 'offsetHeight' : 'offsetWidth'; + return boxValue.u === '%' ? (boxValue.v * this.element[offsetProp]) / 100 : boxValue.v; + } + + // Component Base Props + var essentialBoxProps = ['top', 'left', 'width', 'height']; + var essentialBoxPropsValues = { + top: 0, left: 0, width: 0, height: 0, + }; + + var essentialBoxOnStart = {}; + essentialBoxProps.forEach(function (x) { essentialBoxOnStart[x] = boxModelOnStart; }); + + // All Component Functions + var essentialBoxModelFunctions = { + prepareStart: getBoxModel, + prepareProperty: prepareBoxModel, + onStart: essentialBoxOnStart, + }; + + // Component Essential + var BoxModelEssential = { + component: 'essentialBoxModel', + category: 'boxModel', + properties: essentialBoxProps, + defaultValues: essentialBoxPropsValues, + Interpolate: { numbers: numbers }, + functions: essentialBoxModelFunctions, + Util: { trueDimension: trueDimension }, + }; + + /** + * hexToRGB + * + * Converts a #HEX color format into RGB + * and returns a color object {r,g,b}. + * + * @param {string} hex the degree angle + * @returns {KUTE.colorObject | null} the radian angle + */ + var hexToRGB = function (hex) { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + var hexShorthand = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + var HEX = hex.replace(hexShorthand, function (_, r, g, b) { return r + r + g + g + b + b; }); + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(HEX); + + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } : null; + }; + + /** + * trueColor + * + * Transform any color to rgba()/rgb() and return a nice RGB(a) object. + * + * @param {string} colorString the color input + * @returns {KUTE.colorObject} the {r,g,b,a} color object + */ + var trueColor = function (colorString) { + var result; + if (/rgb|rgba/.test(colorString)) { // first check if it's a rgb string + var vrgb = colorString.replace(/\s|\)/, '').split('(')[1].split(','); + var colorAlpha = vrgb[3] ? vrgb[3] : null; + if (!colorAlpha) { + result = { r: parseInt(vrgb[0], 10), g: parseInt(vrgb[1], 10), b: parseInt(vrgb[2], 10) }; + } + result = { + r: parseInt(vrgb[0], 10), + g: parseInt(vrgb[1], 10), + b: parseInt(vrgb[2], 10), + a: parseFloat(colorAlpha), + }; + } if (/^#/.test(colorString)) { + var fromHex = hexToRGB(colorString); + result = { r: fromHex.r, g: fromHex.g, b: fromHex.b }; + } if (/transparent|none|initial|inherit/.test(colorString)) { + result = { + r: 0, g: 0, b: 0, a: 0, + }; + } + // maybe we can check for web safe colors + // only works in a browser + if (!/^#|^rgb/.test(colorString)) { + var siteHead = document.getElementsByTagName('head')[0]; + siteHead.style.color = colorString; + var webColor = getComputedStyle(siteHead, null).color; + webColor = /rgb/.test(webColor) ? webColor.replace(/[^\d,]/g, '').split(',') : [0, 0, 0]; + siteHead.style.color = ''; + result = { + r: parseInt(webColor[0], 10), + g: parseInt(webColor[1], 10), + b: parseInt(webColor[2], 10), + }; + } + return result; + }; + + /** + * Color Interpolation Function. + * + * @param {KUTE.colorObject} a start color + * @param {KUTE.colorObject} b end color + * @param {number} v progress + * @returns {string} the resulting color + */ + function colors(a, b, v) { + var _c = {}; + var ep = ')'; + var cm = ','; + var rgb = 'rgb('; + var rgba = 'rgba('; + + Object.keys(b).forEach(function (c) { + if (c !== 'a') { + _c[c] = numbers(a[c], b[c], v) >> 0 || 0; // eslint-disable-line no-bitwise + } else if (a[c] && b[c]) { + _c[c] = (numbers(a[c], b[c], v) * 100 >> 0) / 100; // eslint-disable-line no-bitwise + } + }); + + return !_c.a + ? rgb + _c.r + cm + _c.g + cm + _c.b + ep + : rgba + _c.r + cm + _c.g + cm + _c.b + cm + _c.a + ep; + } + + // Component Interpolation + // rgba1, rgba2, progress + + // Component Properties + // supported formats + // 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+) + var supportedColors$1 = [ + 'color', 'backgroundColor', 'outlineColor', + 'borderColor', + 'borderTopColor', 'borderRightColor', + 'borderBottomColor', 'borderLeftColor' ]; + + // Component Functions + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function onStartColors(tweenProp) { + if (this.valuesEnd[tweenProp] && !KEC[tweenProp]) { + KEC[tweenProp] = function (elem, a, b, v) { + // eslint-disable-next-line no-param-reassign + elem.style[tweenProp] = colors(a, b, v); + }; + } + } + + var colorsOnStart$1 = {}; + supportedColors$1.forEach(function (x) { colorsOnStart$1[x] = onStartColors; }); + + // Component Properties + // supported formats + // 'hex', 'rgb', 'rgba' '#fff' 'rgb(0,0,0)' / 'rgba(0,0,0,0)' 'red' (IE9+) + var supportedColors = [ + 'color', 'backgroundColor', 'outlineColor', + 'borderColor', 'borderTopColor', 'borderRightColor', + 'borderBottomColor', 'borderLeftColor' ]; + + var defaultColors = {}; + supportedColors.forEach(function (tweenProp) { + defaultColors[tweenProp] = '#000'; + }); + + // Component Functions + var colorsOnStart = {}; + supportedColors.forEach(function (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 + var colorFunctions = { + prepareStart: getColor, + prepareProperty: prepareColor, + onStart: colorsOnStart, + }; + + // Component Full + var colorProperties = { + component: 'colorProperties', + category: 'colors', + properties: supportedColors, + defaultValues: defaultColors, + Interpolate: { numbers: numbers, colors: colors }, + functions: colorFunctions, + Util: { trueColor: trueColor }, + }; + + // Component Special + var attributes = {}; + + var onStartAttr = { + /** + * onStartAttr.attr + * + * Sets the sub-property update function. + * @param {string} tweenProp the property name + */ + attr: function attr(tweenProp) { + if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) { + KEC[tweenProp] = function (elem, vS, vE, v) { + Object.keys(vE).forEach(function (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: function attributes$1(tweenProp) { + if (!KEC[tweenProp] && this.valuesEnd.attr) { + KEC[tweenProp] = attributes; + } + }, + }; + + // Component Name + var ComponentName = 'htmlAttributes'; + + // Component Properties + var 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 + */ + function getAttr(/* tweenProp, */_, value) { + var this$1$1 = this; + + var attrStartValues = {}; + Object.keys(value).forEach(function (attr) { + // get the value for 'fill-opacity' not fillOpacity + // also 'width' not the internal 'width_px' + var attribute = replaceUppercase(attr).replace(/_+[a-z]+/, ''); + var currentValue = this$1$1.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 + */ + function prepareAttr(tweenProp, attrObj) { + var this$1$1 = this; + // attr (string),attrObj (object) + var attributesObject = {}; + + Object.keys(attrObj).forEach(function (p) { + var prop = replaceUppercase(p); + var regex = /(%|[a-z]+)$/; + var currentValue = this$1$1.element.getAttribute(prop.replace(/_+[a-z]+/, '')); + + if (!svgColors.includes(prop)) { + // attributes set with unit suffixes + if (currentValue !== null && regex.test(currentValue)) { + var unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u; + var suffix = /%/.test(unit) ? '_percent' : ("_" + unit); + + // most "unknown" attributes cannot register into onStart, so we manually add them + onStart[ComponentName][prop + suffix] = function (tp) { + if (this$1$1.valuesEnd[tweenProp] && this$1$1.valuesEnd[tweenProp][tp] && !(tp in attributes)) { + attributes[tp] = function (elem, oneAttr, a, b, v) { + var _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] = function (tp) { + if (this$1$1.valuesEnd[tweenProp] && this$1$1.valuesEnd[tweenProp][tp] && !(tp in attributes)) { + attributes[tp] = function (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] = function (tp) { + if (this$1$1.valuesEnd[tweenProp] && this$1$1.valuesEnd[tweenProp][tp] && !(tp in attributes)) { + attributes[tp] = function (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 + var attrFunctions = { + prepareStart: getAttr, + prepareProperty: prepareAttr, + onStart: onStartAttr, + }; + + // Component Full + var 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: numbers, colors: colors }, + functions: attrFunctions, + // export to global for faster execution + Util: { replaceUppercase: replaceUppercase, trueColor: trueColor, trueDimension: trueDimension }, + }; + + /* opacityProperty = { + property: 'opacity', + defaultValue: 1, + interpolators: {numbers}, + functions = { prepareStart, prepareProperty, onStart } + } */ + + // Component Functions + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function onStartOpacity(tweenProp/* , value */) { + // opacity could be 0 sometimes, we need to check regardless + if (tweenProp in this.valuesEnd && !KEC[tweenProp]) { + KEC[tweenProp] = function (elem, a, b, v) { + /* eslint-disable */ + elem.style[tweenProp] = ((numbers(a, b, v) * 1000) >> 0) / 1000; + /* eslint-enable */ + }; + } + } + + // 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 + var opacityFunctions = { + prepareStart: getOpacity, + prepareProperty: prepareOpacity, + onStart: onStartOpacity, + }; + + // Full Component + var OpacityProperty = { + component: 'opacityProperty', + property: 'opacity', + defaultValue: 1, + Interpolate: { numbers: numbers }, + functions: opacityFunctions, + }; + + // Component Values + var lowerCaseAlpha = String('abcdefghijklmnopqrstuvwxyz').split(''); // lowercase + var upperCaseAlpha = String('abcdefghijklmnopqrstuvwxyz').toUpperCase().split(''); // uppercase + var nonAlpha = String("~!@#$%^&*()_+{}[];'<>,./?=-").split(''); // symbols + var numeric = String('0123456789').split(''); // numeric + var alphaNumeric = lowerCaseAlpha.concat(upperCaseAlpha, numeric); // alpha numeric + var allTypes = alphaNumeric.concat(nonAlpha); // all caracters + + var charSet = { + alpha: lowerCaseAlpha, // lowercase + upper: upperCaseAlpha, // uppercase + symbols: nonAlpha, // symbols + numeric: numeric, + alphanumeric: alphaNumeric, + all: allTypes, + }; + + // Component Functions + var onStartWrite = { + /** + * onStartWrite.text + * + * Sets the property update function. + * @param {string} tweenProp the property name + */ + text: function text(tweenProp) { + if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) { + var chars = this._textChars; + var charsets = charSet[defaultOptions$1.textChars]; + + if (chars in charSet) { + charsets = charSet[chars]; + } else if (chars && chars.length) { + charsets = chars; + } + + KEC[tweenProp] = function (elem, a, b, v) { + var initialText = ''; + var endText = ''; + var finalText = b === '' ? ' ' : b; + var firstLetterA = a.substring(0); + var firstLetterB = b.substring(0); + /* eslint-disable */ + var 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: function number(tweenProp) { + if (tweenProp in this.valuesEnd && !KEC[tweenProp]) { // numbers can be 0 + KEC[tweenProp] = function (elem, a, b, v) { + /* eslint-disable */ + elem.innerHTML = numbers(a, b, v) >> 0; + /* eslint-enable */ + }; + } + }, + }; + + // Component Util + // utility for multi-child targets + // wrapContentsSpan returns an [Element] with the SPAN.tagName and a desired class + function wrapContentsSpan(el, classNAME) { + var assign; + + var textWriteWrapper; + var 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)) { + var 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) { + (assign = el.children, textWriteWrapper = assign[0]); + } + return textWriteWrapper; + } + + function getTextPartsArray(el, classNAME) { + var elementsArray = []; + var len = el.children.length; + if (len) { + var textParts = []; + var remainingMarkup = el.innerHTML; + var wrapperParts; + + for (var i = 0, currentChild = (void 0), childOuter = (void 0), unTaggedContent = (void 0); 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 !== '') { + var unTaggedRemaining = wrapContentsSpan(remainingMarkup, classNAME); + textParts.push(unTaggedRemaining); + } + + elementsArray = elementsArray.concat(textParts); + } else { + elementsArray = elementsArray.concat([wrapContentsSpan(el, classNAME)]); + } + return elementsArray; + } + + function setSegments(target, newText) { + var oldTargetSegs = getTextPartsArray(target, 'text-part'); + var newTargetSegs = getTextPartsArray(wrapContentsSpan(newText), 'text-part'); + + /* eslint-disable no-param-reassign */ + target.innerHTML = ''; + target.innerHTML += oldTargetSegs.map(function (s) { s.className += ' oldText'; return s.outerHTML; }).join(''); + target.innerHTML += newTargetSegs.map(function (s) { s.className += ' newText'; return s.outerHTML.replace(s.innerHTML, ''); }).join(''); + /* eslint-enable no-param-reassign */ + + return [oldTargetSegs, newTargetSegs]; + } + + function createTextTweens(target, newText, ops) { + if (target.playing) { return false; } + + var options = ops || {}; + options.duration = 1000; + + if (ops.duration === 'auto') { + options.duration = 'auto'; + } else if (Number.isFinite(ops.duration * 1)) { + options.duration = ops.duration * 1; + } + + var TweenContructor = connect.tween; + var segs = setSegments(target, newText); + var oldTargetSegs = segs[0]; + var newTargetSegs = segs[1]; + var oldTargets = [].slice.call(target.getElementsByClassName('oldText')).reverse(); + var newTargets = [].slice.call(target.getElementsByClassName('newText')); + + var textTween = []; + var totalDelay = 0; + + textTween = textTween.concat(oldTargets.map(function (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(function (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(function (tw) { return 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 + var textWriteFunctions = { + prepareStart: getWrite, + prepareProperty: prepareText, + onStart: onStartWrite, + }; + + // Full Component + var TextWrite = { + component: 'textWriteProperties', + category: 'textWrite', + properties: ['text', 'number'], + defaultValues: { text: ' ', number: '0' }, + defaultOptions: { textChars: 'alpha' }, + Interpolate: { numbers: numbers }, + functions: textWriteFunctions, + // export to global for faster execution + Util: { charSet: charSet, createTextTweens: createTextTweens }, + }; + + /** + * Perspective Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the perspective function in string format + */ + function perspective(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return ("perspective(" + (((a + (b - a) * v) * 1000 >> 0) / 1000) + u + ")"); + } + + /** + * Translate 3D Interpolation Function. + * + * @param {number[]} a start [x,y,z] position + * @param {number[]} b end [x,y,z] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D translation string + */ + function translate3d(a, b, u, v) { + var translateArray = []; + for (var ax = 0; ax < 3; ax += 1) { + translateArray[ax] = (a[ax] || b[ax] + // eslint-disable-next-line no-bitwise + ? ((a[ax] + (b[ax] - a[ax]) * v) * 1000 >> 0) / 1000 : 0) + u; + } + return ("translate3d(" + (translateArray.join(',')) + ")"); + } + + /** + * 3D Rotation Interpolation Function. + * + * @param {number} a start [x,y,z] angles + * @param {number} b end [x,y,z] angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D rotation string + */ + function rotate3d(a, b, u, v) { + var rotateStr = ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[0] || b[0] ? ("rotateX(" + (((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u + ")") : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[1] || b[1] ? ("rotateY(" + (((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u + ")") : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[2] || b[2] ? ("rotateZ(" + (((a[2] + (b[2] - a[2]) * v) * 1000 >> 0) / 1000) + u + ")") : ''; + return rotateStr; + } + + /** + * Translate 2D Interpolation Function. + * + * @param {number[]} a start [x,y] position + * @param {number[]} b end [x,y] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 2D translation string + */ + function translate(a, b, u, v) { + var translateArray = []; + // eslint-disable-next-line no-bitwise + translateArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + translateArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return ("translate(" + (translateArray.join(',')) + ")"); + } + + /** + * 2D Rotation Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated rotation + */ + function rotate(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return ("rotate(" + (((a + (b - a) * v) * 1000 >> 0) / 1000) + u + ")"); + } + + /** + * Scale Interpolation Function. + * + * @param {number} a start scale + * @param {number} b end scale + * @param {number} v progress + * @returns {string} the interpolated scale + */ + function scale(a, b, v) { + // eslint-disable-next-line no-bitwise + return ("scale(" + (((a + (b - a) * v) * 1000 >> 0) / 1000) + ")"); + } + + /** + * Skew Interpolation Function. + * + * @param {number} a start {x,y} angles + * @param {number} b end {x,y} angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated string value of skew(s) + */ + function skew(a, b, u, v) { + var skewArray = []; + // eslint-disable-next-line no-bitwise + skewArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + skewArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return ("skew(" + (skewArray.join(',')) + ")"); + } + + // Component Functions + /** + * Sets the property update function. + * * same to svgTransform, htmlAttributes + * @param {string} tweenProp the property name + */ + function onStartTransform(tweenProp) { + if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) { + KEC[tweenProp] = function (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 + }; + } + } + + // 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 */) { + var currentStyle = getInlineStyle(this.element); + return currentStyle[tweenProp] ? currentStyle[tweenProp] : defaultValues[tweenProp]; + } + + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {Object} obj the property value + * @returns {KUTE.transformFObject} the property tween object + */ + function prepareTransform(/* prop, */_, obj) { + var prepAxis = ['X', 'Y', 'Z']; // coordinates + var transformObject = {}; + var translateArray = []; var rotateArray = []; var skewArray = []; + var arrayFunctions = ['translate3d', 'translate', 'rotate3d', 'skew']; + + Object.keys(obj).forEach(function (x) { + var pv = typeof obj[x] === 'object' && obj[x].length + ? obj[x].map(function (v) { return parseInt(v, 10); }) + : parseInt(obj[x], 10); + + if (arrayFunctions.includes(x)) { + var 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)) { + var fn = x.replace(/[XYZ]/, ''); + var fnId = fn === 'skew' ? fn : (fn + "3d"); + var fnLen = fn === 'skew' ? 2 : 3; + var fnArray = []; + + if (fn === 'translate') { + fnArray = translateArray; + } else if (fn === 'rotate') { + fnArray = rotateArray; + } else if (fn === 'skew') { + fnArray = skewArray; + } + + for (var fnIndex = 0; fnIndex < fnLen; fnIndex += 1) { + var 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 + var transformFunctions = { + prepareStart: getTransform, + prepareProperty: prepareTransform, + onStart: onStartTransform, + crossCheck: crossCheckTransform, + }; + + var supportedTransformProperties = [ + 'perspective', + 'translate3d', 'translateX', 'translateY', 'translateZ', 'translate', + 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'rotate', + 'skewX', 'skewY', 'skew', + 'scale' ]; + + var 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 + var TransformFunctions = { + 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, + }, + }; + + // Component Functions + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function onStartDraw(tweenProp) { + if (tweenProp in this.valuesEnd && !KEC[tweenProp]) { + KEC[tweenProp] = function (elem, a, b, v) { + /* eslint-disable no-bitwise -- impossible to satisfy */ + var pathLength = (a.l * 100 >> 0) / 100; + var start = (numbers(a.s, b.s, v) * 100 >> 0) / 100; + var end = (numbers(a.e, b.e, v) * 100 >> 0) / 100; + var offset = 0 - start; + var 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 Util + /** + * Convert a `` 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 `` 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 `` length + */ + function getRectLength(el) { + var w = el.getAttribute('width'); + var h = el.getAttribute('height'); + return (w * 2) + (h * 2); + } + + /** + * Returns the `` / `` length. + * @param {SVGPolylineElement | SVGPolygonElement} el target element + * @returns {number} the element length + */ + function getPolyLength(el) { + var points = el.getAttribute('points').split(' '); + + var len = 0; + if (points.length > 1) { + var coord = function (p) { + var 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])]; + }; + + var dist = function (c1, c2) { + if (c1 !== undefined && c2 !== undefined) { + return Math.sqrt(Math.pow( (c2[0] - c1[0]), 2 ) + Math.pow( (c2[1] - c1[1]), 2 )); + } + return 0; + }; + + if (points.length > 2) { + for (var 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 `` length. + * @param {SVGLineElement} el target element + * @returns {number} the element length + */ + function getLineLength(el) { + var x1 = el.getAttribute('x1'); + var x2 = el.getAttribute('x2'); + var y1 = el.getAttribute('y1'); + var y2 = el.getAttribute('y2'); + return Math.sqrt(Math.pow( (x2 - x1), 2 ) + Math.pow( (y2 - y1), 2 )); + } + + /** + * Returns the `` length. + * @param {SVGCircleElement} el target element + * @returns {number} the element length + */ + function getCircleLength(el) { + var r = el.getAttribute('r'); + return 2 * Math.PI * r; + } + + // returns the length of an ellipse + /** + * Returns the `` length. + * @param {SVGEllipseElement} el target element + * @returns {number} the element length + */ + function getEllipseLength(el) { + var rx = el.getAttribute('rx'); + var ry = el.getAttribute('ry'); + var len = 2 * rx; + var 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$1(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) { + var length = /path|glyph/.test(element.tagName) + ? element.getTotalLength() + : getTotalLength$1(element); + var start; + var end; + var dasharray; + var offset; + + if (value instanceof Object && Object.keys(value).every(function (v) { return ['s', 'e', 'l'].includes(v); })) { + return value; + } if (typeof value === 'string') { + var 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 + var svgDrawFunctions = { + prepareStart: getDrawValue, + prepareProperty: prepareDraw, + onStart: onStartDraw, + }; + + // Component Full + var SvgDrawProperty = { + component: 'svgDraw', + property: 'draw', + defaultValue: '0% 0%', + Interpolate: { numbers: numbers }, + functions: svgDrawFunctions, + // Export to global for faster execution + Util: { + getRectLength: getRectLength, + getPolyLength: getPolyLength, + getLineLength: getLineLength, + getCircleLength: getCircleLength, + getEllipseLength: getEllipseLength, + getTotalLength: getTotalLength$1, + resetDraw: resetDraw, + getDraw: getDraw, + percent: percent, + }, + }; + + /** + * Splits an extended A (arc-to) segment into two cubic-bezier segments. + * + * @param {SVGPathCommander.pathArray} path the `pathArray` this segment belongs to + * @param {string[]} allPathCommands all previous path commands + * @param {number} i the segment index + */ + + function fixArc(path, allPathCommands, i) { + if (path[i].length > 7) { + path[i].shift(); + var segment = path[i]; + var ni = i; // ESLint + while (segment.length) { + // if created multiple C:s, their original seg is saved + allPathCommands[i] = 'A'; + // @ts-ignore + path.splice(ni += 1, 0, ['C' ].concat( segment.splice(0, 6))); + } + path.splice(i, 1); + } + } + + /** + * Segment params length + * @type {Record} + */ + var paramsCount = { + a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0, + }; + + /** + * Breaks the parsing of a pathString once a segment is finalized. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ + function finalizeSegment(path) { + var pathCommand = path.pathValue[path.segmentStart]; + var LK = pathCommand.toLowerCase(); + var data = path.data; + + // Process duplicated commands (without comand name) + if (LK === 'm' && data.length > 2) { + // @ts-ignore + path.segments.push([pathCommand, data[0], data[1]]); + data = data.slice(2); + LK = 'l'; + pathCommand = pathCommand === 'm' ? 'l' : 'L'; + } + + // @ts-ignore + while (data.length >= paramsCount[LK]) { + // path.segments.push([pathCommand].concat(data.splice(0, paramsCount[LK]))); + // @ts-ignore + path.segments.push([pathCommand ].concat( data.splice(0, paramsCount[LK]))); + // @ts-ignore + if (!paramsCount[LK]) { + break; + } + } + } + + var invalidPathValue = 'Invalid path value'; + + /** + * Validates an A (arc-to) specific path command value. + * Usually a `large-arc-flag` or `sweep-flag`. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ + function scanFlag(path) { + var index = path.index; + var ch = path.pathValue.charCodeAt(index); + + if (ch === 0x30/* 0 */) { + path.param = 0; + path.index += 1; + return; + } + + if (ch === 0x31/* 1 */) { + path.param = 1; + path.index += 1; + return; + } + + path.err = invalidPathValue + ": invalid Arc flag \"" + ch + "\", expecting 0 or 1 at index " + index; + } + + /** + * Checks if a character is a digit. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ + function isDigit(code) { + return (code >= 48 && code <= 57); // 0..9 + } + + /** + * Validates every character of the path string, + * every path command, negative numbers or floating point numbers. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ + function scanParam(path) { + var max = path.max; + var pathValue = path.pathValue; + var start = path.index; + var index = start; + var zeroFirst = false; + var hasCeiling = false; + var hasDecimal = false; + var hasDot = false; + var ch; + + if (index >= max) { + // path.err = 'SvgPath: missed param (at pos ' + index + ')'; + path.err = invalidPathValue + " at " + index + ": missing param " + (pathValue[index]); + return; + } + ch = pathValue.charCodeAt(index); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + index += 1; + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + // This logic is shamelessly borrowed from Esprima + // https://github.com/ariya/esprimas + if (!isDigit(ch) && ch !== 0x2E/* . */) { + // path.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')'; + path.err = invalidPathValue + " at index " + index + ": " + (pathValue[index]) + " is not a number"; + return; + } + + if (ch !== 0x2E/* . */) { + zeroFirst = (ch === 0x30/* 0 */); + index += 1; + + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + + if (zeroFirst && index < max) { + // decimal number starts with '0' such as '09' is illegal. + if (ch && isDigit(ch)) { + // path.err = 'SvgPath: numbers started with `0` such as `09` + // are illegal (at pos ' + start + ')'; + path.err = invalidPathValue + " at index " + start + ": " + (pathValue[start]) + " illegal number"; + return; + } + } + + while (index < max && isDigit(pathValue.charCodeAt(index))) { + index += 1; + hasCeiling = true; + } + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + if (ch === 0x2E/* . */) { + hasDot = true; + index += 1; + while (isDigit(pathValue.charCodeAt(index))) { + index += 1; + hasDecimal = true; + } + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + } + + if (ch === 0x65/* e */ || ch === 0x45/* E */) { + if (hasDot && !hasCeiling && !hasDecimal) { + path.err = invalidPathValue + " at index " + index + ": " + (pathValue[index]) + " invalid float exponent"; + return; + } + + index += 1; + + ch = (index < max) ? pathValue.charCodeAt(index) : 0; + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + index += 1; + } + if (index < max && isDigit(pathValue.charCodeAt(index))) { + while (index < max && isDigit(pathValue.charCodeAt(index))) { + index += 1; + } + } else { + // path.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; + path.err = invalidPathValue + " at index " + index + ": " + (pathValue[index]) + " invalid float exponent"; + return; + } + } + + path.index = index; + path.param = +path.pathValue.slice(start, index); + } + + /** + * Checks if the character is a space. + * + * @param {number} ch the character to check + * @returns {boolean} check result + */ + function isSpace(ch) { + var specialSpaces = [ + 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, + 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF]; + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) // Line terminators + // White spaces + || (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) + || (ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0); + } + + /** + * Points the parser to the next character in the + * path string every time it encounters any kind of + * space character. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ + function skipSpaces(path) { + var pathValue = path.pathValue; + var max = path.max; + while (path.index < max && isSpace(pathValue.charCodeAt(path.index))) { + path.index += 1; + } + } + + /** + * Checks if the character is a path command. + * + * @param {any} code the character to check + * @returns {boolean} check result + */ + function isPathCommand(code) { + // eslint-disable-next-line no-bitwise -- Impossible to satisfy + switch (code | 0x20) { + case 0x6D/* m */: + case 0x7A/* z */: + case 0x6C/* l */: + case 0x68/* h */: + case 0x76/* v */: + case 0x63/* c */: + case 0x73/* s */: + case 0x71/* q */: + case 0x74/* t */: + case 0x61/* a */: + // case 0x72/* r */: + return true; + default: + return false; + } + } + + /** + * Checks if the character is or belongs to a number. + * [0-9]|+|-|. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ + function isDigitStart(code) { + return (code >= 48 && code <= 57) /* 0..9 */ + || code === 0x2B /* + */ + || code === 0x2D /* - */ + || code === 0x2E; /* . */ + } + + /** + * Checks if the character is an A (arc-to) path command. + * + * @param {number} code the character to check + * @returns {boolean} check result + */ + function isArcCommand(code) { + // eslint-disable-next-line no-bitwise -- Impossible to satisfy + return (code | 0x20) === 0x61; + } + + /** + * Scans every character in the path string to determine + * where a segment starts and where it ends. + * + * @param {SVGPathCommander.PathParser} path the `PathParser` instance + */ + function scanSegment(path) { + var max = path.max; + var pathValue = path.pathValue; + var index = path.index; + var cmdCode = pathValue.charCodeAt(index); + var reqParams = paramsCount[pathValue[index].toLowerCase()]; + + path.segmentStart = index; + + if (!isPathCommand(cmdCode)) { + path.err = invalidPathValue + ": " + (pathValue[index]) + " not a path command"; + return; + } + + path.index += 1; + skipSpaces(path); + + path.data = []; + + if (!reqParams) { + // Z + finalizeSegment(path); + return; + } + + for (;;) { + for (var i = reqParams; i > 0; i -= 1) { + if (isArcCommand(cmdCode) && (i === 3 || i === 4)) { scanFlag(path); } + else { scanParam(path); } + + if (path.err.length) { + return; + } + path.data.push(path.param); + + skipSpaces(path); + + // after ',' param is mandatory + if (path.index < max && pathValue.charCodeAt(path.index) === 0x2C/* , */) { + path.index += 1; + skipSpaces(path); + } + } + + if (path.index >= path.max) { + break; + } + + // Stop on next segment + if (!isDigitStart(pathValue.charCodeAt(path.index))) { + break; + } + } + + finalizeSegment(path); + } + + /** + * Returns a clone of an existing `pathArray`. + * + * @param {SVGPathCommander.pathArray | SVGPathCommander.pathSegment} path the source `pathArray` + * @returns {any} the cloned `pathArray` + */ + function clonePath(path) { + return path.map(function (x) { return (Array.isArray(x) ? [].concat( x ) : x); }); + } + + /** + * The `PathParser` is used by the `parsePathString` static method + * to generate a `pathArray`. + * + * @param {string} pathString + */ + function PathParser(pathString) { + /** @type {SVGPathCommander.pathArray} */ + // @ts-ignore + this.segments = []; + /** @type {string} */ + this.pathValue = pathString; + /** @type {number} */ + this.max = pathString.length; + /** @type {number} */ + this.index = 0; + /** @type {number} */ + this.param = 0.0; + /** @type {number} */ + this.segmentStart = 0; + /** @type {any} */ + this.data = []; + /** @type {string} */ + this.err = ''; + } + + /** + * Iterates an array to check if it's an actual `pathArray`. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ + function isPathArray(path) { + return Array.isArray(path) && path.every(function (seg) { + var lk = seg[0].toLowerCase(); + return paramsCount[lk] === seg.length - 1 && 'achlmqstvz'.includes(lk); + }); + } + + /** + * Parses a path string value and returns an array + * of segments we like to call `pathArray`. + * + * @param {SVGPathCommander.pathArray | string} pathInput the string to be parsed + * @returns {SVGPathCommander.pathArray} the resulted `pathArray` + */ + function parsePathString(pathInput) { + if (isPathArray(pathInput)) { + // @ts-ignore -- isPathArray also checks if it's an `Array` + return clonePath(pathInput); + } + + // @ts-ignore -- pathInput is now string + var path = new PathParser(pathInput); + + skipSpaces(path); + + while (path.index < path.max && !path.err.length) { + scanSegment(path); + } + + if (path.err.length) { + // @ts-ignore + path.segments = []; + } else if (path.segments.length) { + if (!'mM'.includes(path.segments[0][0])) { + path.err = invalidPathValue + ": missing M/m"; + // @ts-ignore + path.segments = []; + } else { + path.segments[0][0] = 'M'; + } + } + + return path.segments; + } + + /** + * Iterates an array to check if it's a `pathArray` + * with all absolute values. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ + function isAbsoluteArray(path) { + return isPathArray(path) + // @ts-ignore -- `isPathArray` also checks if it's `Array` + && path.every(function (x) { return x[0] === x[0].toUpperCase(); }); + } + + /** + * Parses a path string value or object and returns an array + * of segments, all converted to absolute values. + * + * @param {string | SVGPathCommander.pathArray} pathInput the path string | object + * @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values + */ + function pathToAbsolute(pathInput) { + if (isAbsoluteArray(pathInput)) { + // @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + var path = parsePathString(pathInput); + var x = 0; var y = 0; + var mx = 0; var my = 0; + + // @ts-ignore -- the `absoluteSegment[]` is for sure an `absolutePath` + return path.map(function (segment) { + var assign, assign$1, assign$2; + + var values = segment.slice(1).map(Number); + var pathCommand = segment[0]; + /** @type {SVGPathCommander.absoluteCommand} */ + // @ts-ignore + var absCommand = pathCommand.toUpperCase(); + + if (pathCommand === 'M') { + (assign = values, x = assign[0], y = assign[1]); + mx = x; + my = y; + return ['M', x, y]; + } + /** @type {SVGPathCommander.absoluteSegment} */ + // @ts-ignore + var absoluteSegment = []; + + if (pathCommand !== absCommand) { + switch (absCommand) { + case 'A': + absoluteSegment = [ + absCommand, values[0], values[1], values[2], + values[3], values[4], values[5] + x, values[6] + y]; + break; + case 'V': + absoluteSegment = [absCommand, values[0] + y]; + break; + case 'H': + absoluteSegment = [absCommand, values[0] + x]; + break; + default: { + // use brakets for `eslint: no-case-declaration` + // https://stackoverflow.com/a/50753272/803358 + var absValues = values.map(function (n, j) { return n + (j % 2 ? y : x); }); + // @ts-ignore for n, l, c, s, q, t + absoluteSegment = [absCommand ].concat( absValues); + } + } + } else { + // @ts-ignore + absoluteSegment = [absCommand ].concat( values); + } + + var segLength = absoluteSegment.length; + switch (absCommand) { + case 'Z': + x = mx; + y = my; + break; + case 'H': + // @ts-ignore + (assign$1 = absoluteSegment, x = assign$1[1]); + break; + case 'V': + // @ts-ignore + (assign$2 = absoluteSegment, y = assign$2[1]); + break; + default: + // @ts-ignore + x = absoluteSegment[segLength - 2]; + // @ts-ignore + y = absoluteSegment[segLength - 1]; + + if (absCommand === 'M') { + mx = x; + my = y; + } + } + return absoluteSegment; + }); + } + + /** + * Returns the missing control point from an + * T (shorthand quadratic bezier) segment. + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} qx control point x + * @param {number} qy control point y + * @param {string} prevCommand the previous path command + * @returns {{qx: number, qy: number}}} the missing control point + */ + function shorthandToQuad(x1, y1, qx, qy, prevCommand) { + return 'QT'.includes(prevCommand) + ? { qx: x1 * 2 - qx, qy: y1 * 2 - qy } + : { qx: x1, qy: y1 }; + } + + /** + * Returns the missing control point from an + * S (shorthand cubic bezier) segment. + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} x2 curve end x + * @param {number} y2 curve end y + * @param {string} prevCommand the previous path command + * @returns {{x1: number, y1: number}}} the missing control point + */ + function shorthandToCubic(x1, y1, x2, y2, prevCommand) { + return 'CS'.includes(prevCommand) + ? { x1: x1 * 2 - x2, y1: y1 * 2 - y2 } + : { x1: x1, y1: y1 }; + } + + /** + * Normalizes a single segment of a `pathArray` object. + * + * @param {SVGPathCommander.pathSegment} segment the segment object + * @param {any} params the coordinates of the previous segment + * @param {string} prevCommand the path command of the previous segment + * @returns {SVGPathCommander.normalSegment} the normalized segment + */ + function normalizeSegment(segment, params, prevCommand) { + var pathCommand = segment[0]; + var px1 = params.x1; + var py1 = params.y1; + var px2 = params.x2; + var py2 = params.y2; + var values = segment.slice(1).map(Number); + var result = segment; + + if (!'TQ'.includes(pathCommand)) { + // optional but good to be cautious + params.qx = null; + params.qy = null; + } + + if (pathCommand === 'H') { + result = ['L', segment[1], py1]; + } else if (pathCommand === 'V') { + result = ['L', px1, segment[1]]; + } else if (pathCommand === 'S') { + var ref = shorthandToCubic(px1, py1, px2, py2, prevCommand); + var x1 = ref.x1; + var y1 = ref.y1; + params.x1 = x1; + params.y1 = y1; + // @ts-ignore + result = ['C', x1, y1 ].concat( values); + } else if (pathCommand === 'T') { + var ref$1 = shorthandToQuad(px1, py1, params.qx, params.qy, prevCommand); + var qx = ref$1.qx; + var qy = ref$1.qy; + params.qx = qx; + params.qy = qy; + // @ts-ignore + result = ['Q', qx, qy ].concat( values); + } else if (pathCommand === 'Q') { + var nqx = values[0]; + var nqy = values[1]; + params.qx = nqx; + params.qy = nqy; + } + + // @ts-ignore -- we-re switching `pathSegment` type + return result; + } + + /** + * Iterates an array to check if it's a `pathArray` + * with all segments are in non-shorthand notation + * with absolute values. + * + * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked + * @returns {boolean} iteration result + */ + function isNormalizedArray(path) { + // @ts-ignore -- `isAbsoluteArray` also checks if it's `Array` + return isAbsoluteArray(path) && path.every(function (seg) { return 'ACLMQZ'.includes(seg[0]); }); + } + + /** + * @type {SVGPathCommander.parserParams} + */ + var paramsParser = { + x1: 0, y1: 0, x2: 0, y2: 0, x: 0, y: 0, qx: null, qy: null, + }; + + /** + * Normalizes a `path` object for further processing: + * * convert segments to absolute values + * * convert shorthand path commands to their non-shorthand notation + * + * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray' + * @returns {SVGPathCommander.normalArray} the normalized `pathArray` + */ + function normalizePath(pathInput) { + var assign; + + if (isNormalizedArray(pathInput)) { + // @ts-ignore -- `isNormalizedArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + /** @type {SVGPathCommander.normalArray} */ + // @ts-ignore -- `absoluteArray` will become a `normalArray` + var path = pathToAbsolute(pathInput); + var params = Object.assign({}, paramsParser); + var allPathCommands = []; + var ii = path.length; + var pathCommand = ''; + var prevCommand = ''; + + for (var i = 0; i < ii; i += 1) { + (assign = path[i], pathCommand = assign[0]); + + // Save current path command + allPathCommands[i] = pathCommand; + // Get previous path command + if (i) { prevCommand = allPathCommands[i - 1]; } + // Previous path command is used to normalizeSegment + // @ts-ignore -- expected on normalization + path[i] = normalizeSegment(path[i], params, prevCommand); + + var segment = path[i]; + var seglen = segment.length; + + params.x1 = +segment[seglen - 2]; + params.y1 = +segment[seglen - 1]; + params.x2 = +(segment[seglen - 4]) || params.x1; + params.y2 = +(segment[seglen - 3]) || params.y1; + } + + return path; + } + + /** + * Checks a `pathArray` for an unnecessary `Z` segment + * and returns a new `pathArray` without it. + * + * The `pathInput` must be a single path, without + * sub-paths. For multi-path `` elements, + * use `splitPath` first and apply this utility on each + * sub-path separately. + * + * @param {SVGPathCommander.pathArray | string} pathInput the `pathArray` source + * @return {SVGPathCommander.pathArray} a fixed `pathArray` + */ + function fixPath(pathInput) { + var pathArray = parsePathString(pathInput); + var normalArray = normalizePath(pathArray); + var length = pathArray.length; + var isClosed = normalArray.slice(-1)[0][0] === 'Z'; + var segBeforeZ = isClosed ? length - 2 : length - 1; + + var ref = normalArray[0].slice(1); + var mx = ref[0]; + var my = ref[1]; + var ref$1 = normalArray[segBeforeZ].slice(-2); + var x = ref$1[0]; + var y = ref$1[1]; + + if (isClosed && mx === x && my === y) { + // @ts-ignore -- `pathSegment[]` is quite a `pathArray` + return pathArray.slice(0, -1); + } + return pathArray; + } + + /** + * Iterates an array to check if it's a `pathArray` + * with all C (cubic bezier) segments. + * + * @param {string | SVGPathCommander.pathArray} path the `Array` to be checked + * @returns {boolean} iteration result + */ + function isCurveArray(path) { + // @ts-ignore -- `isPathArray` also checks if it's `Array` + return isPathArray(path) && path.every(function (seg) { return 'MC'.includes(seg[0]); }); + } + + /** + * Returns an {x,y} vector rotated by a given + * angle in radian. + * + * @param {number} x the initial vector x + * @param {number} y the initial vector y + * @param {number} rad the radian vector angle + * @returns {{x: number, y: number}} the rotated vector + */ + function rotateVector(x, y, rad) { + var X = x * Math.cos(rad) - y * Math.sin(rad); + var Y = x * Math.sin(rad) + y * Math.cos(rad); + return { x: X, y: Y }; + } + + /** + * Converts A (arc-to) segments to C (cubic-bezier-to). + * + * For more information of where this math came from visit: + * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + * + * @param {number} X1 the starting x position + * @param {number} Y1 the starting y position + * @param {number} RX x-radius of the arc + * @param {number} RY y-radius of the arc + * @param {number} angle x-axis-rotation of the arc + * @param {number} LAF large-arc-flag of the arc + * @param {number} SF sweep-flag of the arc + * @param {number} X2 the ending x position + * @param {number} Y2 the ending y position + * @param {number[]=} recursive the parameters needed to split arc into 2 segments + * @return {number[]} the resulting cubic-bezier segment(s) + */ + function arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, recursive) { + var assign; + + var x1 = X1; var y1 = Y1; var rx = RX; var ry = RY; var x2 = X2; var y2 = Y2; + // for more information of where this Math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var d120 = (Math.PI * 120) / 180; + + var rad = (Math.PI / 180) * (+angle || 0); + /** @type {number[]} */ + var res = []; + var xy; + var f1; + var f2; + var cx; + var cy; + + if (!recursive) { + xy = rotateVector(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotateVector(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + + var x = (x1 - x2) / 2; + var y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = Math.sqrt(h); + rx *= h; + ry *= h; + } + var rx2 = rx * rx; + var ry2 = ry * ry; + + var k = (LAF === SF ? -1 : 1) + * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) + / (rx2 * y * y + ry2 * x * x))); + + cx = ((k * rx * y) / ry) + ((x1 + x2) / 2); + cy = ((k * -ry * x) / rx) + ((y1 + y2) / 2); + // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise + f1 = (Math.asin((((y1 - cy) / ry))) * (Math.pow( 10, 9 )) >> 0) / (Math.pow( 10, 9 )); + // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise + f2 = (Math.asin((((y2 - cy) / ry))) * (Math.pow( 10, 9 )) >> 0) / (Math.pow( 10, 9 )); + + f1 = x1 < cx ? Math.PI - f1 : f1; + f2 = x2 < cx ? Math.PI - f2 : f2; + if (f1 < 0) { (f1 = Math.PI * 2 + f1); } + if (f2 < 0) { (f2 = Math.PI * 2 + f2); } + if (SF && f1 > f2) { + f1 -= Math.PI * 2; + } + if (!SF && f2 > f1) { + f2 -= Math.PI * 2; + } + } else { + (assign = recursive, f1 = assign[0], f2 = assign[1], cx = assign[2], cy = assign[3]); + } + var df = f2 - f1; + if (Math.abs(df) > d120) { + var f2old = f2; + var x2old = x2; + var y2old = y2; + f2 = f1 + d120 * (SF && f2 > f1 ? 1 : -1); + x2 = cx + rx * Math.cos(f2); + y2 = cy + ry * Math.sin(f2); + res = arcToCubic(x2, y2, rx, ry, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = Math.cos(f1); + var s1 = Math.sin(f1); + var c2 = Math.cos(f2); + var s2 = Math.sin(f2); + var t = Math.tan(df / 4); + var hx = (4 / 3) * rx * t; + var hy = (4 / 3) * ry * t; + var m1 = [x1, y1]; + var m2 = [x1 + hx * s1, y1 - hy * c1]; + var m3 = [x2 + hx * s2, y2 - hy * c2]; + var m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return m2.concat( m3, m4, res); + } + res = m2.concat( m3, m4, res); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i += 1) { + newres[i] = i % 2 + ? rotateVector(res[i - 1], res[i], rad).y + : rotateVector(res[i], res[i + 1], rad).x; + } + return newres; + } + + /** + * Converts a Q (quadratic-bezier) segment to C (cubic-bezier). + * + * @param {number} x1 curve start x + * @param {number} y1 curve start y + * @param {number} qx control point x + * @param {number} qy control point y + * @param {number} x2 curve end x + * @param {number} y2 curve end y + * @returns {number[]} the cubic-bezier segment + */ + function quadToCubic(x1, y1, qx, qy, x2, y2) { + var r13 = 1 / 3; + var r23 = 2 / 3; + return [ + r13 * x1 + r23 * qx, // cpx1 + r13 * y1 + r23 * qy, // cpy1 + r13 * x2 + r23 * qx, // cpx2 + r13 * y2 + r23 * qy, // cpy2 + x2, y2 ]; + } + + /** + * Returns the coordinates of a specified distance + * ratio between two points. + * + * @param {[number, number]} a the first point coordinates + * @param {[number, number]} b the second point coordinates + * @param {number} t the ratio + * @returns {[number, number]} the midpoint coordinates + */ + function midPoint(a, b, t) { + var ax = a[0]; + var ay = a[1]; var bx = b[0]; + var by = b[1]; + return [ax + (bx - ax) * t, ay + (by - ay) * t]; + } + + /** + * Returns the square root of the distance + * between two given points. + * + * @param {[number, number]} a the first point coordinates + * @param {[number, number]} b the second point coordinates + * @returns {number} the distance value + */ + function distanceSquareRoot(a, b) { + return Math.sqrt( + (a[0] - b[0]) * (a[0] - b[0]) + + (a[1] - b[1]) * (a[1] - b[1]) + ); + } + + /** + * Returns the length of a line (L,V,H,Z) segment, + * or a point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the distance to point + * @returns {{x: number, y: number} | number} the segment length or point + */ + function segmentLineFactory(x1, y1, x2, y2, distance) { + var length = distanceSquareRoot([x1, y1], [x2, y2]); + var margin = 0.001; + + if (typeof distance === 'number') { + if (distance < margin) { + return { x: x1, y: y1 }; + } + if (distance > length + margin) { + return { x: x2, y: y2 }; + } + var ref = midPoint([x1, y1], [x2, y2], distance / length); + var x = ref[0]; + var y = ref[1]; + return { x: x, y: y }; + } + return length; + } + + /** + * Converts an L (line-to) segment to C (cubic-bezier). + * + * @param {number} x1 line start x + * @param {number} y1 line start y + * @param {number} x2 line end x + * @param {number} y2 line end y + * @returns {number[]} the cubic-bezier segment + */ + function lineToCubic(x1, y1, x2, y2) { + var t = 0.5; + /** @type {[number, number]} */ + var p0 = [x1, y1]; + /** @type {[number, number]} */ + var p1 = [x2, y2]; + var p2 = midPoint(p0, p1, t); + var p3 = midPoint(p1, p2, t); + var p4 = midPoint(p2, p3, t); + var p5 = midPoint(p3, p4, t); + var p6 = midPoint(p4, p5, t); + var seg1 = p0.concat( p2, p4, p6, [t]); + // @ts-ignore + var cp1 = segmentLineFactory.apply(void 0, seg1); + var seg2 = p6.concat( p5, p3, p1, [0]); + // @ts-ignore + var cp2 = segmentLineFactory.apply(void 0, seg2); + + // @ts-ignore + return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2]; + } + + /** + * Converts any segment to C (cubic-bezier). + * + * @param {SVGPathCommander.pathSegment} segment the source segment + * @param {SVGPathCommander.parserParams} params the source segment parameters + * @returns {SVGPathCommander.cubicSegment | SVGPathCommander.MSegment} the cubic-bezier segment + */ + function segmentToCubic(segment, params) { + var pathCommand = segment[0]; + var values = segment.slice(1).map(function (n) { return +n; }); + var x = values[0]; + var y = values[1]; + var args; + var px1 = params.x1; + var py1 = params.y1; + var px = params.x; + var py = params.y; + + if (!'TQ'.includes(pathCommand)) { + params.qx = null; + params.qy = null; + } + + switch (pathCommand) { + case 'M': + params.x = x; + params.y = y; + return segment; + case 'A': + args = [px1, py1 ].concat( values); + // @ts-ignore -- relax, the utility will return 6 numbers + return ['C' ].concat( arcToCubic.apply(void 0, args)); + case 'Q': + params.qx = x; + params.qy = y; + args = [px1, py1 ].concat( values); + // @ts-ignore -- also returning 6 numbers + return ['C' ].concat( quadToCubic.apply(void 0, args)); + case 'L': + // @ts-ignore -- also returning 6 numbers + return ['C' ].concat( lineToCubic(px1, py1, x, y)); + case 'Z': + // @ts-ignore -- also returning 6 numbers + return ['C' ].concat( lineToCubic(px1, py1, px, py)); + } + // @ts-ignore -- we're switching `pathSegment` type + return segment; + } + + /** + * Parses a path string value or 'pathArray' and returns a new one + * in which all segments are converted to cubic-bezier. + * + * In addition, un-necessary `Z` segment is removed if previous segment + * extends to the `M` segment. + * + * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray' + * @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier + */ + function pathToCurve(pathInput) { + var assign; + + if (isCurveArray(pathInput)) { + // @ts-ignore -- `isCurveArray` checks if it's `pathArray` + return clonePath(pathInput); + } + + var path = fixPath(normalizePath(pathInput)); + var params = Object.assign({}, paramsParser); + var allPathCommands = []; + var pathCommand = ''; // ts-lint + var ii = path.length; + + for (var i = 0; i < ii; i += 1) { + (assign = path[i], pathCommand = assign[0]); + allPathCommands[i] = pathCommand; + + path[i] = segmentToCubic(path[i], params); + + fixArc(path, allPathCommands, i); + ii = path.length; + + var segment = path[i]; + var seglen = segment.length; + params.x1 = +segment[seglen - 2]; + params.y1 = +segment[seglen - 1]; + params.x2 = +(segment[seglen - 4]) || params.x1; + params.y2 = +(segment[seglen - 3]) || params.y1; + } + + // @ts-ignore + return path; + } + + /** + * SVGPathCommander default options + * @type {SVGPathCommander.options} + */ + var defaultOptions = { + origin: [0, 0, 0], + round: 4, + }; + + /** + * Rounds the values of a `pathArray` instance to + * a specified amount of decimals and returns it. + * + * @param {SVGPathCommander.pathArray} path the source `pathArray` + * @param {number | boolean} roundOption the amount of decimals to round numbers to + * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with rounded values + */ + function roundPath(path, roundOption) { + var round = defaultOptions.round; + if (roundOption === false || round === false) { return clonePath(path); } + round = roundOption >= 1 ? roundOption : round; + // to round values to the power + // the `round` value must be integer + // @ts-ignore + var pow = round >= 1 ? (Math.pow( 10, round )) : 1; + + // @ts-ignore -- `pathSegment[]` is `pathArray` + return path.map(function (pi) { + var values = pi.slice(1).map(Number) + .map(function (n) { return (n % 1 === 0 ? n : Math.round(n * pow) / pow); }); + return [pi[0] ].concat( values); + }); + } + + /** + * Returns a valid `d` attribute string value created + * by rounding values and concatenating the `pathArray` segments. + * + * @param {SVGPathCommander.pathArray} path the `pathArray` object + * @param {any} round amount of decimals to round values to + * @returns {string} the concatenated path string + */ + function pathToString(path, round) { + return roundPath(path, round) + .map(function (x) { return x[0] + x.slice(1).join(' '); }).join(''); + } + + /** + * Split a path into an `Array` of sub-path strings. + * + * In the process, values are converted to absolute + * for visual consistency. + * + * @param {SVGPathCommander.pathArray | string} pathInput the source `pathArray` + * @return {string[]} an array with all sub-path strings + */ + function splitPath(pathInput) { + return pathToString(pathToAbsolute(pathInput), 0) + .replace(/(m|M)/g, '|$1') + .split('|') + .map(function (s) { return s.trim(); }) + .filter(function (s) { return s; }); + } + + /** + * Returns a point at a given length of a C (cubic-bezier) segment. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} c1x the first control point X + * @param {number} c1y the first control point Y + * @param {number} c2x the second control point X + * @param {number} c2y the second control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number} t a [0-1] ratio + * @returns {{x: number, y: number}} the cubic-bezier segment length + */ + function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) { + var t1 = 1 - t; + return { + x: (Math.pow( t1, 3 )) * x1 + + 3 * (Math.pow( t1, 2 )) * t * c1x + + 3 * t1 * (Math.pow( t, 2 )) * c2x + + (Math.pow( t, 3 )) * x2, + y: (Math.pow( t1, 3 )) * y1 + + 3 * (Math.pow( t1, 2 )) * t * c1y + + 3 * t1 * (Math.pow( t, 2 )) * c2y + + (Math.pow( t, 3 )) * y2, + }; + } + + /** + * Returns the length of a C (cubic-bezier) segment, + * or an {x,y} point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} c1x the first control point X + * @param {number} c1y the first control point Y + * @param {number} c2x the second control point X + * @param {number} c2y the second control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the point distance + * @returns {{x: number, y: number} | number} the segment length or point + */ + function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) { + var assign; + + var x = x1; var y = y1; + var lengthMargin = 0.001; + var totalLength = 0; + var prev = [x1, y1, totalLength]; + /** @type {[number, number]} */ + var cur = [x1, y1]; + var t = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x: x, y: y }; + } + + var n = 100; + for (var j = 0; j <= n; j += 1) { + t = j / n; + + ((assign = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t), x = assign.x, y = assign.y)); + totalLength += distanceSquareRoot(cur, [x, y]); + cur = [x, y]; + + if (typeof distance === 'number' && totalLength >= distance) { + var dv = (totalLength - distance) / (totalLength - prev[2]); + + return { + x: cur[0] * (1 - dv) + prev[0] * dv, + y: cur[1] * (1 - dv) + prev[1] * dv, + }; + } + prev = [x, y, totalLength]; + } + + if (typeof distance === 'number' && distance >= totalLength) { + return { x: x2, y: y2 }; + } + return totalLength; + } + + /** + * Returns the length of a A (arc-to) segment, + * or an {x,y} point at a given length. + * + * @param {number} X1 the starting x position + * @param {number} Y1 the starting y position + * @param {number} RX x-radius of the arc + * @param {number} RY y-radius of the arc + * @param {number} angle x-axis-rotation of the arc + * @param {number} LAF large-arc-flag of the arc + * @param {number} SF sweep-flag of the arc + * @param {number} X2 the ending x position + * @param {number} Y2 the ending y position + * @param {number} distance the point distance + * @returns {{x: number, y: number} | number} the segment length or point + */ + function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) { + var assign; + + var ref = [X1, Y1]; + var x = ref[0]; + var y = ref[1]; + var cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2); + var lengthMargin = 0.001; + var totalLength = 0; + var cubicSubseg = []; + var argsc = []; + var segLen = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x: x, y: y }; + } + + for (var i = 0, ii = cubicSeg.length; i < ii; i += 6) { + cubicSubseg = cubicSeg.slice(i, i + 6); + argsc = [x, y ].concat( cubicSubseg); + // @ts-ignore + segLen = segmentCubicFactory.apply(void 0, argsc); + if (typeof distance === 'number' && totalLength + segLen >= distance) { + // @ts-ignore -- this is a `cubicSegment` + return segmentCubicFactory.apply(void 0, argsc.concat( [distance - totalLength] )); + } + totalLength += segLen; + (assign = cubicSubseg.slice(-2), x = assign[0], y = assign[1]); + } + + if (typeof distance === 'number' && distance >= totalLength) { + return { x: X2, y: Y2 }; + } + + return totalLength; + } + + /** + * Returns the {x,y} coordinates of a point at a + * given length of a quad-bezier segment. + * + * @see https://github.com/substack/point-at-length + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} cx the control point X + * @param {number} cy the control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number} t a [0-1] ratio + * @returns {{x: number, y: number}} the requested {x,y} coordinates + */ + function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) { + var t1 = 1 - t; + return { + x: (Math.pow( t1, 2 )) * x1 + + 2 * t1 * t * cx + + (Math.pow( t, 2 )) * x2, + y: (Math.pow( t1, 2 )) * y1 + + 2 * t1 * t * cy + + (Math.pow( t, 2 )) * y2, + }; + } + + /** + * Returns the Q (quadratic-bezier) segment length, + * or an {x,y} point at a given length. + * + * @param {number} x1 the starting point X + * @param {number} y1 the starting point Y + * @param {number} qx the control point X + * @param {number} qy the control point Y + * @param {number} x2 the ending point X + * @param {number} y2 the ending point Y + * @param {number=} distance the distance to point + * @returns {{x: number, y: number} | number} the segment length or point + */ + function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) { + var assign; + + var x = x1; var y = y1; + var lengthMargin = 0.001; + var totalLength = 0; + var prev = [x1, y1, totalLength]; + /** @type {[number, number]} */ + var cur = [x1, y1]; + var t = 0; + + if (typeof distance === 'number' && distance < lengthMargin) { + return { x: x, y: y }; + } + + var n = 100; + for (var j = 0; j <= n; j += 1) { + t = j / n; + + ((assign = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t), x = assign.x, y = assign.y)); + totalLength += distanceSquareRoot(cur, [x, y]); + cur = [x, y]; + + if (typeof distance === 'number' && totalLength >= distance) { + var dv = (totalLength - distance) / (totalLength - prev[2]); + + return { + x: cur[0] * (1 - dv) + prev[0] * dv, + y: cur[1] * (1 - dv) + prev[1] * dv, + }; + } + prev = [x, y, totalLength]; + } + if (typeof distance === 'number' && distance >= totalLength) { + return { x: x2, y: y2 }; + } + return totalLength; + } + + /** + * Returns a {x,y} point at a given length of a shape or the shape total length. + * + * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into + * @param {number=} distance the length of the shape to look at + * @returns {{x: number, y: number} | number} the total length or point + */ + function pathLengthFactory(pathInput, distance) { + var assign, assign$1, assign$2; + + var totalLength = 0; + var isM = true; + /** @type {number[]} */ + var data = []; + var pathCommand = 'M'; + var segLen = 0; + var x = 0; + var y = 0; + var mx = 0; + var my = 0; + var seg; + var path = fixPath(normalizePath(pathInput)); + + for (var i = 0, ll = path.length; i < ll; i += 1) { + seg = path[i]; + (assign = seg, pathCommand = assign[0]); + isM = pathCommand === 'M'; + // @ts-ignore + data = !isM ? [x, y ].concat( seg.slice(1)) : data; + + // this segment is always ZERO + if (isM) { + // remember mx, my for Z + // @ts-ignore + (assign$1 = seg, mx = assign$1[1], my = assign$1[2]); + if (typeof distance === 'number' && distance < 0.001) { + return { x: mx, y: my }; + } + } else if (pathCommand === 'L') { + // @ts-ignore + segLen = segmentLineFactory.apply(void 0, data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] )); + } + totalLength += segLen; + } else if (pathCommand === 'A') { + // @ts-ignore + segLen = segmentArcFactory.apply(void 0, data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentArcFactory.apply(void 0, data.concat( [distance - totalLength] )); + } + totalLength += segLen; + } else if (pathCommand === 'C') { + // @ts-ignore + segLen = segmentCubicFactory.apply(void 0, data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentCubicFactory.apply(void 0, data.concat( [distance - totalLength] )); + } + totalLength += segLen; + } else if (pathCommand === 'Q') { + // @ts-ignore + segLen = segmentQuadFactory.apply(void 0, data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentQuadFactory.apply(void 0, data.concat( [distance - totalLength] )); + } + totalLength += segLen; + } else if (pathCommand === 'Z') { + data = [x, y, mx, my]; + // @ts-ignore + segLen = segmentLineFactory.apply(void 0, data); + if (distance && totalLength + segLen >= distance) { + // @ts-ignore + return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] )); + } + totalLength += segLen; + } + + // @ts-ignore -- needed for the below + (assign$2 = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my], x = assign$2[0], y = assign$2[1]); + } + + // native `getPointAtLength` behavior when the given distance + // is higher than total length + if (distance && distance >= totalLength) { + return { x: x, y: y }; + } + + return totalLength; + } + + /** + * Returns the shape total length, or the equivalent to `shape.getTotalLength()`. + * + * The `normalizePath` version is lighter, faster, more efficient and more accurate + * with paths that are not `curveArray`. + * + * @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray` + * @returns {number} the shape total length + */ + function getTotalLength(pathInput) { + // @ts-ignore - it's fine + return pathLengthFactory(pathInput); + } + + /** + * Returns [x,y] coordinates of a point at a given length of a shape. + * + * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into + * @param {number} distance the length of the shape to look at + * @returns {{x: number, y: number}} the requested {x, y} point coordinates + */ + function getPointAtLength(pathInput, distance) { + // @ts-ignore + return pathLengthFactory(pathInput, distance); + } + + /** + * d3-polygon-area + * https://github.com/d3/d3-polygon + * + * Returns the area of a polygon. + * + * @param {number[][]} polygon an array of coordinates + * @returns {number} the polygon area + */ + function polygonArea(polygon) { + var n = polygon.length; + var i = -1; + var a; + var b = polygon[n - 1]; + var area = 0; + + /* eslint-disable-next-line */ + while (++i < n) { + a = b; + b = polygon[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + + return area / 2; + } + + /** + * d3-polygon-length + * https://github.com/d3/d3-polygon + * + * Returns the perimeter of a polygon. + * + * @param {number[][]} polygon an array of coordinates + * @returns {number} the polygon length + */ + function polygonLength(polygon) { + return polygon.reduce(function (length, point, i) { + if (i) { + // @ts-ignore + return length + distanceSquareRoot(polygon[i - 1], point); + } + return 0; + }, 0); + } + + /** + * A global namespace for epsilon. + * + * @type {number} + */ + var epsilon = 1e-9; + + /** + * Coordinates Interpolation Function. + * + * @param {number[][]} a start coordinates + * @param {number[][]} b end coordinates + * @param {string} l amount of coordinates + * @param {number} v progress + * @returns {number[][]} the interpolated coordinates + */ + function coords(a, b, l, v) { + var points = []; + for (var i = 0; i < l; i += 1) { // for each point + points[i] = []; + for (var j = 0; j < 2; j += 1) { // each point coordinate + // eslint-disable-next-line no-bitwise + points[i].push(((a[i][j] + (b[i][j] - a[i][j]) * v) * 1000 >> 0) / 1000); + } + } + return points; + } + + /* 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 + */ + function onStartSVGMorph(tweenProp) { + if (!KEC[tweenProp] && this.valuesEnd[tweenProp]) { + KEC[tweenProp] = function (elem, a, b, v) { + var path1 = a.polygon; var path2 = b.polygon; + var len = path2.length; + elem.setAttribute('d', (v === 1 ? b.original : ("M" + (coords(path1, path2, len, v).join('L')) + "Z"))); + }; + } + } + + // 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) { + var assign; + + var polygon = []; + var pathlen = pathArray.length; + var segment = []; + var pathCommand = ''; + + if (!pathArray.length || pathArray[0][0] !== 'M') { + return false; + } + + for (var i = 0; i < pathlen; i += 1) { + segment = pathArray[i]; + (assign = segment, pathCommand = assign[0]); + + if ((pathCommand === 'M' && i) || pathCommand === 'Z') { + break; // !! + } else if ('ML'.includes(pathCommand)) { + polygon.push([segment[1], segment[2]]); + } else { + return false; + } + } + + return pathlen ? { polygon: 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) { + var ringPath = splitPath(pathToString(parsed))[0]; + var normalPath = normalizePath(ringPath); + var pathLength = getTotalLength(normalPath); + var polygon = []; + var numPoints = 3; + var point; + + if (maxLength && !Number.isNaN(maxLength) && +maxLength > 0) { + numPoints = Math.max(numPoints, Math.ceil(pathLength / maxLength)); + } + + for (var 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: 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) { + var 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) { + var len = polygon.length; + var min = Infinity; + var bestOffset; + var sumOfSquares = 0; + var spliced; + var d; + var p; + + for (var offset = 0; offset < len; offset += 1) { + sumOfSquares = 0; + + for (var 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.apply(polygon, [ polygon.length, 0 ].concat( 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) { + var desiredLength = polygon.length + numPoints; + var step = polygonLength(polygon) / numPoints; + + var i = 0; + var cursor = 0; + var insertAt = step / 2; + var a; + var b; + var 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) { + if ( maxSegmentLength === void 0 ) maxSegmentLength = Infinity; + + var a = []; + var b = []; + + for (var 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(function (point) { return 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) { + var assign; + + var skipBisect; + var polygon; + + if (typeof (input) === 'string') { + var converted = pathStringToPolygon(input, maxSegmentLength); + ((assign = converted, polygon = assign.polygon, skipBisect = assign.skipBisect)); + } else if (!Array.isArray(input)) { + throw Error((invalidPathValue + ": " + input)); + } + + /** @type {KUTE.polygonMorph} */ + var points = [].concat( 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) { + var morphPrecision = precision || defaultOptions$1.morphPrecision; + var fromRing = getPolygon(path1, morphPrecision); + var toRing = getPolygon(path2, morphPrecision); + var 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) { + var pathObject = {}; + // remove newlines, they brake JSON strings sometimes + var pathReg = new RegExp('\\n', 'ig'); + var 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]) { + var pathArray1 = this.valuesStart[prop].polygon; + var 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)) { + var p1 = this.valuesStart[prop].original; + var p2 = this.valuesEnd[prop].original; + // process morphPrecision + var morphPrecision = this._morphPrecision + ? parseInt(this._morphPrecision, 10) + : defaultOptions$1.morphPrecision; + + var ref = getInterpolationPoints(p1, p2, morphPrecision); + var path1 = ref[0]; + var path2 = ref[1]; + this.valuesStart[prop].polygon = path1; + this.valuesEnd[prop].polygon = path2; + } + } + } + + // All Component Functions + var svgMorphFunctions = { + prepareStart: getSVGMorph, + prepareProperty: prepareSVGMorph, + onStart: onStartSVGMorph, + crossCheck: crossCheckSVGMorph, + }; + + // Component Full + var SVGMorph = { + component: 'svgMorph', + property: 'path', + defaultValue: [], + Interpolate: coords, + defaultOptions: { morphPrecision: 10 }, + functions: svgMorphFunctions, + // Export utils to global for faster execution + Util: { + // component + addPoints: addPoints, + bisect: bisect, + getPolygon: getPolygon, + validPolygon: validPolygon, + getInterpolationPoints: getInterpolationPoints, + pathStringToPolygon: pathStringToPolygon, + distanceSquareRoot: distanceSquareRoot, + midPoint: midPoint, + approximatePolygon: approximatePolygon, + rotatePolygon: rotatePolygon, + // svg-path-commander + pathToString: pathToString, + pathToCurve: pathToCurve, + getTotalLength: getTotalLength, + getPointAtLength: getPointAtLength, + polygonArea: polygonArea, + roundPath: roundPath, + }, + }; + + var Components = { + EssentialBoxModel: BoxModelEssential, + ColorsProperties: colorProperties, + HTMLAttributes: htmlAttributes, + OpacityProperty: OpacityProperty, + TextWriteProp: TextWrite, + TransformFunctions: TransformFunctions, + SVGDraw: SvgDrawProperty, + SVGMorph: SVGMorph, + }; + + // init components + Object.keys(Components).forEach(function (component) { + var compOps = Components[component]; + Components[component] = new Animation(compOps); + }); + + var version = "2.2.3"; + + // @ts-ignore + + /** + * A global namespace for library version. + * @type {string} + */ + var Version = version; + + // KUTE.js standard distribution version + + var KUTE = { + Animation: Animation, + Components: Components, + + // Tween Interface + Tween: Tween, + fromTo: fromTo, + to: to, + // Tween Collection + TweenCollection: TweenCollection, + allFromTo: allFromTo, + allTo: allTo, + // Tween Interface + + Objects: Objects, + Util: Util, + Easing: Easing, + CubicBezier: CubicBezier, + Render: Render, + Interpolate: interpolate, + Process: Process, + Internals: internals, + Selector: selector, + Version: Version, + }; + + return KUTE; + +})); diff --git a/dist/kute.min.js b/dist/kute.min.js new file mode 100644 index 0000000..f0c3fa3 --- /dev/null +++ b/dist/kute.min.js @@ -0,0 +1,2 @@ +// KUTE.js Standard v2.2.3 | thednp © 2021 | MIT-License +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).KUTE=e()}(this,(function(){"use strict";var t=function(t,e,n,r,a){var i=this;this.cx=3*t,this.bx=3*(n-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(r-e)-this.cy,this.ay=1-this.cy-this.by;var o=function(t){return i.sampleCurveY(i.solveCurveX(t))};return Object.defineProperty(o,"name",{writable:!0}),o.name=a||"cubic-bezier("+[t,e,n,r]+")",o};t.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},t.prototype.sampleCurveY=function(t){return((this.ay*t+this.by)*t+this.cy)*t},t.prototype.sampleCurveDerivativeX=function(t){return(3*this.ax*t+2*this.bx)*t+this.cx},t.prototype.solveCurveX=function(t){var e,n,r,a,i,o,s=1e-5;for(r=t,o=0;o<32;o+=1){if(a=this.sampleCurveX(r)-t,Math.abs(a)(n=1))return n;for(;ea?e=r:n=r,r=.5*(n-e)+e}return r};Object.assign(t,{Version:"1.0.18"});var e={},n=[],r="undefined"!=typeof global?global:"undefined"!=typeof window?window.self:{},a={},i={},o="undefined"==typeof self&&"undefined"!=typeof process&&process.hrtime?function(){var t=process.hrtime();return 1e3*t[0]+t[1]/1e6}:"undefined"!=typeof self&&void 0!==self.performance&&void 0!==self.performance.now?self.performance.now.bind(self.performance):"undefined"!=typeof Date&&Date.now?Date.now:function(){return(new Date).getTime()},s={};s.now=o;var u=0,c=function(t){for(var e=0;e1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.map((function(t){return t.start()})),!1)},j.tween=N;var q=function(t){function n(){for(var e=this,n=[],r=arguments.length;r--;)n[r]=arguments[r];t.apply(this,n),this.valuesStart={},this.valuesEnd={};var a=n.slice(1),i=a[0],o=a[1],s=a[2];return T.call(this,o,"end"),this._resetStart?this.valuesStart=i:T.call(this,i,"start"),this._resetStart||Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(n){g[t][n].call(e,n)}))})),this.paused=!1,this._pauseTime=null,this._repeat=s.repeat||d.repeat,this._repeatDelay=s.repeatDelay||d.repeatDelay,this._repeatOption=this._repeat,this.valuesRepeat={},this._yoyo=s.yoyo||d.yoyo,this._reversed=!1,this}return t&&(n.__proto__=t),n.prototype=Object.create(t&&t.prototype),n.prototype.constructor=n,n.prototype.start=function(e){var n=this;return this._resetStart&&(this.valuesStart=this._resetStart,S.call(this),Object.keys(g).forEach((function(t){Object.keys(g[t]).forEach((function(e){g[t][e].call(n,e)}))}))),this.paused=!1,this._yoyo&&Object.keys(this.valuesEnd).forEach((function(t){n.valuesRepeat[t]=n.valuesStart[t]})),t.prototype.start.call(this,e),this},n.prototype.stop=function(){return t.prototype.stop.call(this),!this.paused&&this.playing&&(this.paused=!1,this.stopChainedTweens()),this},n.prototype.close=function(){return t.prototype.close.call(this),this._repeatOption>0&&(this._repeat=this._repeatOption),this._yoyo&&!0===this._reversed&&(this.reverse(),this._reversed=!1),this},n.prototype.resume=function(){return this.paused&&this.playing&&(this.paused=!1,void 0!==this._onResume&&this._onResume.call(this),L.call(this),this._startTime+=e.Time()-this._pauseTime,E(this),u||c()),this},n.prototype.pause=function(){return!this.paused&&this.playing&&(M(this),this.paused=!0,this._pauseTime=e.Time(),void 0!==this._onPause&&this._onPause.call(this)),this},n.prototype.reverse=function(){var t=this;Object.keys(this.valuesEnd).forEach((function(e){var n=t.valuesRepeat[e];t.valuesRepeat[e]=t.valuesEnd[e],t.valuesEnd[e]=n,t.valuesStart[e]=t.valuesRepeat[e]}))},n.prototype.update=function(t){var n,r=this,a=void 0!==t?t:e.Time();if(a1?1:n;var i=this._easing(n);return Object.keys(this.valuesEnd).forEach((function(t){e[t](r.element,r.valuesStart[t],r.valuesEnd[t],i)})),this._onUpdate&&this._onUpdate.call(this),1!==n||(this._repeat>0?(Number.isFinite(this._repeat)&&(this._repeat-=1),this._startTime=a,Number.isFinite(this._repeat)&&this._yoyo&&!this._reversed&&(this._startTime+=this._repeatDelay),this._yoyo&&(this._reversed=!this._reversed,this.reverse()),!0):(this._onComplete&&this._onComplete.call(this),this.playing=!1,this.close(),void 0!==this._chain&&this._chain.length&&this._chain.forEach((function(t){return t.start()})),!1))},n}(N);j.tween=q;var V=function(t,e,n,r){var a=this,i=j.tween;this.tweens=[];var o=r||{};o.delay=o.delay||d.delay;var s=[];return Array.from(t).forEach((function(t,r){if(s[r]=o||{},s[r].delay=r>0?o.delay+(o.offset||d.offset):o.delay,!(t instanceof Element))throw Error("KUTE - "+t+" is not instanceof Element");a.tweens.push(new i(t,e,n,s[r]))})),this.length=this.tweens.length,this};V.prototype.start=function(t){var n=void 0===t?e.Time():t;return this.tweens.map((function(t){return t.start(n)})),this},V.prototype.stop=function(){return this.tweens.map((function(t){return t.stop()})),this},V.prototype.pause=function(){return this.tweens.map((function(t){return t.pause()})),this},V.prototype.resume=function(){return this.tweens.map((function(t){return t.resume()})),this},V.prototype.chain=function(t){var e=this.tweens[this.length-1];if(t instanceof V)e.chain(t.tweens);else{if(!(t instanceof j.tween))throw new TypeError("KUTE.js - invalid chain value");e.chain(t)}return this},V.prototype.playing=function(){return this.tweens.some((function(t){return t.playing}))},V.prototype.removeTweens=function(){this.tweens=[]},V.prototype.getMaxDuration=function(){var t=[];return this.tweens.forEach((function(e){t.push(e._duration+e._delay+e._repeat*e._repeatDelay)})),Math.max(t)};var H=j.tween;var Q=j.tween;var F=function(t){try{if(t.component in f)throw Error("KUTE - "+t.component+" already registered");if(t.property in h)throw Error("KUTE - "+t.property+" already registered")}catch(t){throw Error(t)}var e=this,n=t.component,r={prepareProperty:y,prepareStart:v,onStart:i,onComplete:m,crossCheck:g},o=t.category,s=t.property,u=t.properties&&t.properties.length||t.subProperties&&t.subProperties.length;return f[n]=t.properties||t.subProperties||t.property,"defaultValue"in t?(h[s]=t.defaultValue,e.supports=s+" property"):t.defaultValues&&(Object.keys(t.defaultValues).forEach((function(e){h[e]=t.defaultValues[e]})),e.supports=(u||s)+" "+(s||o)+" properties"),t.defaultOptions&&Object.assign(d,t.defaultOptions),t.functions&&Object.keys(r).forEach((function(e){e in t.functions&&("function"==typeof t.functions[e]?(r[e][n]||(r[e][n]={}),r[e][n][o||s]||(r[e][n][o||s]=t.functions[e])):Object.keys(t.functions[e]).forEach((function(a){r[e][n]||(r[e][n]={}),r[e][n][a]||(r[e][n][a]=t.functions[e][a])})))})),t.Interpolate&&(Object.keys(t.Interpolate).forEach((function(e){var n=t.Interpolate[e];"function"!=typeof n||a[e]?Object.keys(n).forEach((function(t){"function"!=typeof n[t]||a[e]||(a[e]=n[t])})):a[e]=n})),b[n]=t.Interpolate),t.Util&&Object.keys(t.Util).forEach((function(e){w[e]||(w[e]=t.Util[e])})),e},U=function(t,e){for(var n,r=parseInt(t,10)||0,a=["px","%","deg","rad","em","rem","vh","vw"],i=0;i.99||a<.01?(10*D(n,r,a)>>0)/10:D(n,r,a)>>0)+"px"})}var Z={};["top","left","width","height"].forEach((function(t){Z[t]=X}));var B=["top","left","width","height"],R={};B.forEach((function(t){R[t]=X}));var Y={component:"essentialBoxModel",category:"boxModel",properties:B,defaultValues:{top:0,left:0,width:0,height:0},Interpolate:{numbers:D},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){var n=U(e),r="height"===t?"offsetHeight":"offsetWidth";return"%"===n.u?n.v*this.element[r]/100:n.v},onStart:R},Util:{trueDimension:U}},z=function(t){var e;if(/rgb|rgba/.test(t)){var n=t.replace(/\s|\)/,"").split("(")[1].split(","),r=n[3]?n[3]:null;r||(e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10)}),e={r:parseInt(n[0],10),g:parseInt(n[1],10),b:parseInt(n[2],10),a:parseFloat(r)}}if(/^#/.test(t)){var a=function(t){var e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(t,e,n,r){return e+e+n+n+r+r})),n=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:null}(t);e={r:a.r,g:a.g,b:a.b}}if(/transparent|none|initial|inherit/.test(t)&&(e={r:0,g:0,b:0,a:0}),!/^#|^rgb/.test(t)){var i=document.getElementsByTagName("head")[0];i.style.color=t;var o=getComputedStyle(i,null).color;o=/rgb/.test(o)?o.replace(/[^\d,]/g,"").split(","):[0,0,0],i.style.color="",e={r:parseInt(o[0],10),g:parseInt(o[1],10),b:parseInt(o[2],10)}}return e};function K(t,e,n){var r={},a=",";return Object.keys(e).forEach((function(a){"a"!==a?r[a]=D(t[a],e[a],n)>>0||0:t[a]&&e[a]&&(r[a]=(100*D(t[a],e[a],n)>>0)/100)})),r.a?"rgba("+r.r+a+r.g+a+r.b+a+r.a+")":"rgb("+r.r+a+r.g+a+r.b+")"}function $(t){this.valuesEnd[t]&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=K(n,r,a)})}var W={};["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"].forEach((function(t){W[t]=$}));var G=["color","backgroundColor","outlineColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor"],J={};G.forEach((function(t){J[t]="#000"}));var tt={};G.forEach((function(t){tt[t]=$}));var et={component:"colorProperties",category:"colors",properties:G,defaultValues:J,Interpolate:{numbers:D,colors:K},functions:{prepareStart:function(t){return O(this.element,t)||h[t]},prepareProperty:function(t,e){return z(e)},onStart:tt},Util:{trueColor:z}},nt={},rt="htmlAttributes",at=["fill","stroke","stop-color"];function it(t){return t.replace(/[A-Z]/g,"-$&").toLowerCase()}var ot={prepareStart:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(t){var e=it(t).replace(/_+[a-z]+/,""),a=n.element.getAttribute(e);r[e]=at.includes(e)?a||"rgba(0,0,0,0)":a||(/opacity/i.test(t)?1:0)})),r},prepareProperty:function(t,e){var n=this,r={};return Object.keys(e).forEach((function(a){var o=it(a),s=/(%|[a-z]+)$/,u=n.element.getAttribute(o.replace(/_+[a-z]+/,""));if(at.includes(o))i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,K(n,r,a))})},r[o]=z(e[a])||h.htmlAttributes[a];else if(null!==u&&s.test(u)){var c=U(u).u||U(e[a]).u,l=/%/.test(c)?"_percent":"_"+c;i.htmlAttributes[o+l]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){var i=e.replace(l,"");t.setAttribute(i,(1e3*D(n.v,r.v,a)>>0)/1e3+r.u)})},r[o+l]=U(e[a])}else s.test(e[a])&&null!==u&&(null===u||s.test(u))||(i.htmlAttributes[o]=function(e){n.valuesEnd[t]&&n.valuesEnd[t][e]&&!(e in nt)&&(nt[e]=function(t,e,n,r,a){t.setAttribute(e,(1e3*D(n,r,a)>>0)/1e3)})},r[o]=parseFloat(e[a]))})),r},onStart:{attr:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,n,r,a){Object.keys(r).forEach((function(i){e.attributes[i](t,i,n[i],r[i],a)}))})},attributes:function(t){!e[t]&&this.valuesEnd.attr&&(e[t]=nt)}}},st={component:rt,property:"attr",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},Interpolate:{numbers:D,colors:K},functions:ot,Util:{replaceUppercase:it,trueColor:z,trueDimension:U}};var ut={prepareStart:function(t){return O(this.element,t)},prepareProperty:function(t,e){return parseFloat(e)},onStart:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(e,n,r,a){e.style[t]=(1e3*D(n,r,a)>>0)/1e3})}},ct={component:"opacityProperty",property:"opacity",defaultValue:1,Interpolate:{numbers:D},functions:ut},lt=String("abcdefghijklmnopqrstuvwxyz").split(""),pt=String("abcdefghijklmnopqrstuvwxyz").toUpperCase().split(""),ft=String("~!@#$%^&*()_+{}[];'<>,./?=-").split(""),ht=String("0123456789").split(""),dt=lt.concat(pt,ht),yt=dt.concat(ft),vt={alpha:lt,upper:pt,symbols:ft,numeric:ht,alphanumeric:dt,all:yt},gt={text:function(t){if(!e[t]&&this.valuesEnd[t]){var n=this._textChars,r=vt[d.textChars];n in vt?r=vt[n]:n&&n.length&&(r=n),e[t]=function(t,e,n,a){var i="",o="",s=""===n?" ":n,u=e.substring(0),c=n.substring(0),l=r[Math.random()*r.length>>0];" "===e?(o=c.substring(Math.min(a*c.length,c.length)>>0,0),t.innerHTML=a<1?o+l:s):" "===n?(i=u.substring(0,Math.min((1-a)*u.length,u.length)>>0),t.innerHTML=a<1?i+l:s):(i=u.substring(u.length,Math.min(a*u.length,u.length)>>0),o=c.substring(0,Math.min(a*c.length,c.length)>>0),t.innerHTML=a<1?o+l+i:s)}}},number:function(t){t in this.valuesEnd&&!e[t]&&(e[t]=function(t,e,n,r){t.innerHTML=D(e,n,r)>>0})}};function mt(t,e){var n,r;if("string"==typeof t)return(r=document.createElement("SPAN")).innerHTML=t,r.className=e,r;if(!t.children.length||t.children.length&&t.children[0].className!==e){var a=t.innerHTML;(n=document.createElement("SPAN")).className=e,n.innerHTML=a,t.appendChild(n),t.innerHTML=n.outerHTML}else t.children.length&&t.children[0].className===e&&(n=t.children[0]);return n}function bt(t,e){var n=[],r=t.children.length;if(r){for(var a,i=[],o=t.innerHTML,s=0,u=void 0,c=void 0,l=void 0;s>0)/1e3+n+")"}function wt(t,e,n,r){for(var a=[],i=0;i<3;i+=1)a[i]=(t[i]||e[i]?(1e3*(t[i]+(e[i]-t[i])*r)>>0)/1e3:0)+n;return"translate3d("+a.join(",")+")"}function Et(t,e,n,r){var a="";return a+=t[0]||e[0]?"rotateX("+(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3+n+")":"",a+=t[1]||e[1]?"rotateY("+(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3+n+")":"",a+=t[2]||e[2]?"rotateZ("+(1e3*(t[2]+(e[2]-t[2])*r)>>0)/1e3+n+")":""}function Mt(t,e,n){return"scale("+(1e3*(t+(e-t)*n)>>0)/1e3+")"}function _t(t,e,n,r){var a=[];return a[0]=(t[0]===e[0]?e[0]:(1e3*(t[0]+(e[0]-t[0])*r)>>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","skew("+a.join(",")+")"}function kt(t,e){return parseFloat(t)/100*e}function Ct(t){return 2*t.getAttribute("width")+2*t.getAttribute("height")}function Ot(t){var e=t.getAttribute("points").split(" "),n=0;if(e.length>1){var r=function(t){var e=t.split(",");return 2!==e.length||Number.isNaN(1*e[0])||Number.isNaN(1*e[1])?0:[parseFloat(e[0]),parseFloat(e[1])]},a=function(t,e){return void 0!==t&&void 0!==e?Math.sqrt(Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)):0};if(e.length>2)for(var i=0;i>0)/100,i=0-(100*D(e.s,n.s,r)>>0)/100,o=(100*D(e.e,n.e,r)>>0)/100+i;t.style.strokeDashoffset=i+"px",t.style.strokeDasharray=(100*(o<1?0:o)>>0)/100+"px, "+a+"px"})}};function Lt(t,e,n){if(t[n].length>7){t[n].shift();for(var r=t[n],a=n;r.length;)e[n]="A",t.splice(a+=1,0,["C"].concat(r.splice(0,6)));t.splice(n,1)}}var Nt={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0};function qt(t){var e=t.pathValue[t.segmentStart],n=e.toLowerCase(),r=t.data;for("m"===n&&r.length>2&&(t.segments.push([e,r[0],r[1]]),r=r.slice(2),n="l",e="m"===e?"l":"L");r.length>=Nt[n]&&(t.segments.push([e].concat(r.splice(0,Nt[n]))),Nt[n]););}var Vt="Invalid path value";function Ht(t){var e=t.index,n=t.pathValue.charCodeAt(e);return 48===n?(t.param=0,void(t.index+=1)):49===n?(t.param=1,void(t.index+=1)):void(t.err=Vt+': invalid Arc flag "'+n+'", expecting 0 or 1 at index '+e)}function Qt(t){return t>=48&&t<=57}function Ft(t){var e,n=t.max,r=t.pathValue,a=t.index,i=a,o=!1,s=!1,u=!1,c=!1;if(i>=n)t.err=Vt+" at "+i+": missing param "+r[i];else if(43!==(e=r.charCodeAt(i))&&45!==e||(e=(i+=1)=5760&&[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0);)t.index+=1}function Dt(t){return t>=48&&t<=57||43===t||45===t||46===t}function Xt(t){var e=t.max,n=t.pathValue,r=t.index,a=n.charCodeAt(r),i=Nt[n[r].toLowerCase()];if(t.segmentStart=r,function(t){switch(32|t){case 109:case 122:case 108:case 104:case 118:case 99:case 115:case 113:case 116:case 97:return!0;default:return!1}}(a))if(t.index+=1,Ut(t),t.data=[],i){for(;;){for(var o=i;o>0;o-=1){if(97!=(32|a)||3!==o&&4!==o?Ft(t):Ht(t),t.err.length)return;t.data.push(t.param),Ut(t),t.index=t.max)break;if(!Dt(n.charCodeAt(t.index)))break}qt(t)}else qt(t);else t.err=Vt+": "+n[r]+" not a path command"}function Zt(t){return t.map((function(t){return Array.isArray(t)?[].concat(t):t}))}function Bt(t){this.segments=[],this.pathValue=t,this.max=t.length,this.index=0,this.param=0,this.segmentStart=0,this.data=[],this.err=""}function Rt(t){return Array.isArray(t)&&t.every((function(t){var e=t[0].toLowerCase();return Nt[e]===t.length-1&&"achlmqstvz".includes(e)}))}function Yt(t){if(Rt(t))return Zt(t);var e=new Bt(t);for(Ut(e);e.index1&&(m*=O=Math.sqrt(O),b*=O);var T=m*m,S=b*b,I=(i===o?-1:1)*Math.sqrt(Math.abs((T*S-T*C*C-S*k*k)/(T*C*C+S*k*k)));d=I*m*C/b+(v+x)/2,y=I*-b*k/m+(g+w)/2,f=(Math.asin((g-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),h=(Math.asin((w-y)/b)*Math.pow(10,9)>>0)/Math.pow(10,9),f=vh&&(f-=2*Math.PI),!o&&h>f&&(h-=2*Math.PI)}var j=h-f;if(Math.abs(j)>E){var A=h,P=x,L=w;h=f+E*(o&&h>f?1:-1),_=ee(x=d+m*Math.cos(h),w=y+b*Math.sin(h),m,b,a,0,o,P,L,[h,A,d,y])}j=h-f;var N=Math.cos(f),q=Math.sin(f),V=Math.cos(h),H=Math.sin(h),Q=Math.tan(j/4),F=4/3*m*Q,U=4/3*b*Q,D=[v,g],X=[v+F*q,g-U*N],Z=[x+F*H,w-U*V],B=[x,w];if(X[0]=2*D[0]-X[0],X[1]=2*D[1]-X[1],c)return X.concat(Z,B,_);for(var R=[],Y=0,z=(_=X.concat(Z,B,_)).length;Yi+.001)return{x:n,y:r};var o=re([t,e],[n,r],a/i);return{x:o[0],y:o[1]}}return i}function oe(t,e,n,r){var a=.5,i=[t,e],o=[n,r],s=re(i,o,a),u=re(o,s,a),c=re(s,u,a),l=re(u,c,a),p=re(c,l,a),f=i.concat(s,c,p,[a]),h=ie.apply(void 0,f),d=p.concat(l,u,o,[0]),y=ie.apply(void 0,d);return[h.x,h.y,y.x,y.y,n,r]}function se(t,e){var n,r=t[0],a=t.slice(1).map((function(t){return+t})),i=a[0],o=a[1],s=e.x1,u=e.y1,c=e.x,l=e.y;switch("TQ".includes(r)||(e.qx=null,e.qy=null),r){case"M":return e.x=i,e.y=o,t;case"A":return n=[s,u].concat(a),["C"].concat(ee.apply(void 0,n));case"Q":return e.qx=i,e.qy=o,n=[s,u].concat(a),["C"].concat(ne.apply(void 0,n));case"L":return["C"].concat(oe(s,u,i,o));case"Z":return["C"].concat(oe(s,u,c,l))}return t}var ue=4;function ce(t,e){var n=ue;if(!1===e||!1===n)return Zt(t);var r=(n=e>=1?e:n)>=1?Math.pow(10,n):1;return t.map((function(t){var e=t.slice(1).map(Number).map((function(t){return t%1==0?t:Math.round(t*r)/r}));return[t[0]].concat(e)}))}function le(t,e){return ce(t,e).map((function(t){return t[0]+t.slice(1).join(" ")})).join("")}function pe(t,e,n,r,a,i,o,s,u){var c=1-u;return{x:Math.pow(c,3)*t+3*Math.pow(c,2)*u*n+3*c*Math.pow(u,2)*a+Math.pow(u,3)*o,y:Math.pow(c,3)*e+3*Math.pow(c,2)*u*r+3*c*Math.pow(u,2)*i+Math.pow(u,3)*s}}function fe(t,e,n,r,a,i,o,s,u){var c,l=t,p=e,f=0,h=[t,e,f],d=[t,e];if("number"==typeof u&&u<.001)return{x:l,y:p};for(var y=0;y<=100;y+=1){if(f+=ae(d,[l=(c=pe(t,e,n,r,a,i,o,s,y/100)).x,p=c.y]),d=[l,p],"number"==typeof u&&f>=u){var v=(f-u)/(f-h[2]);return{x:d[0]*(1-v)+h[0]*v,y:d[1]*(1-v)+h[1]*v}}h=[l,p,f]}return"number"==typeof u&&u>=f?{x:o,y:s}:f}function he(t,e,n,r,a,i,o,s,u,c){var l,p=[t,e],f=p[0],h=p[1],d=ee(t,e,n,r,a,i,o,s,u),y=0,v=[],g=[],m=0;if("number"==typeof c&&c<.001)return{x:f,y:h};for(var b=0,x=d.length;b=c)return fe.apply(void 0,g.concat([c-y]));y+=m,f=(l=v.slice(-2))[0],h=l[1]}return"number"==typeof c&&c>=y?{x:s,y:u}:y}function de(t,e,n,r,a,i,o){var s=1-o;return{x:Math.pow(s,2)*t+2*s*o*n+Math.pow(o,2)*a,y:Math.pow(s,2)*e+2*s*o*r+Math.pow(o,2)*i}}function ye(t,e,n,r,a,i,o){var s,u=t,c=e,l=0,p=[t,e,l],f=[t,e];if("number"==typeof o&&o<.001)return{x:u,y:c};for(var h=0;h<=100;h+=1){if(l+=ae(f,[u=(s=de(t,e,n,r,a,i,h/100)).x,c=s.y]),f=[u,c],"number"==typeof o&&l>=o){var d=(l-o)/(l-p[2]);return{x:f[0]*(1-d)+p[0]*d,y:f[1]*(1-d)+p[1]*d}}p=[u,c,l]}return"number"==typeof o&&o>=l?{x:a,y:i}:l}function ve(t,e){for(var n,r,a,i=0,o=!0,s=[],u="M",c=0,l=0,p=0,f=0,h=0,d=Jt(Gt(t)),y=0,v=d.length;y=e)return ie.apply(void 0,s.concat([e-i]));i+=c}else if("A"===u){if(c=he.apply(void 0,s),e&&i+c>=e)return he.apply(void 0,s.concat([e-i]));i+=c}else if("C"===u){if(c=fe.apply(void 0,s),e&&i+c>=e)return fe.apply(void 0,s.concat([e-i]));i+=c}else if("Q"===u){if(c=ye.apply(void 0,s),e&&i+c>=e)return ye.apply(void 0,s.concat([e-i]));i+=c}else if("Z"===u){if(s=[l,p,f,h],c=ie.apply(void 0,s),e&&i+c>=e)return ie.apply(void 0,s.concat([e-i]));i+=c}l=(r="Z"!==u?a.slice(-2):[f,h])[0],p=r[1]}return e&&e>=i?{x:l,y:p}:i}function ge(t){return ve(t)}function me(t,e){return ve(t,e)}function be(t){for(var e,n=t.length,r=-1,a=t[n-1],i=0;++r>0)/1e3)}return a}function we(t,e){var n,r,a=Gt((n=le(t),le(Kt(n),0).replace(/(m|M)/g,"|$1").split("|").map((function(t){return t.trim()})).filter((function(t){return t})))[0]),i=ge(a),o=[],s=3;e&&!Number.isNaN(e)&&+e>0&&(s=Math.max(s,Math.ceil(i/e)));for(var u=0;u0&&o.reverse(),{polygon:o,skipBisect:!0}}function Ee(t,e){var n=Gt(t);return function(t){var e=[],n=t.length,r=[],a="";if(!t.length||"M"!==t[0][0])return!1;for(var i=0;ie;)r=re(n,r,.5),t.splice(a+1,0,r)}function Ce(t){return Array.isArray(t)&&t.every((function(t){return Array.isArray(t)&&2===t.length&&!Number.isNaN(t[0])&&!Number.isNaN(t[1])}))}function Oe(t,e){var n,r,a;if("string"==typeof t)a=(n=Ee(t,e)).polygon,r=n.skipBisect;else if(!Array.isArray(t))throw Error(Vt+": "+t);var i=[].concat(a);if(!Ce(i))throw Error(Vt+": "+i);return i.length>1&&ae(i[0],i[i.length-1])<1e-9&&i.pop(),!r&&e&&!Number.isNaN(e)&&+e>0&&ke(i,e),i}function Te(t,e,n){var r=n||d.morphPrecision,a=Oe(t,r),i=Oe(e,r),o=a.length-i.length;return _e(a,o<0?-1*o:0),_e(i,o>0?o:0),Me(a,i),[ce(a),ce(i)]}var Se={prepareStart:function(){return this.element.getAttribute("d")},prepareProperty:function(t,e){var n={},r=new RegExp("\\n","ig"),a=null;return e instanceof SVGPathElement?a=e:/^\.|^#/.test(e)&&(a=P(e)),"object"==typeof e&&e.polygon?e:(a&&["path","glyph"].includes(a.tagName)?n.original=a.getAttribute("d").replace(r,""):a||"string"!=typeof e||(n.original=e.replace(r,"")),n)},onStart:function(t){!e[t]&&this.valuesEnd[t]&&(e[t]=function(t,e,n,r){var a=e.polygon,i=n.polygon,o=i.length;t.setAttribute("d",1===r?n.original:"M"+xe(a,i,o,r).join("L")+"Z")})},crossCheck:function(t){if(this.valuesEnd[t]){var e=this.valuesStart[t].polygon,n=this.valuesEnd[t].polygon;if(!e||!n||e&&n&&e.length!==n.length){var r=Te(this.valuesStart[t].original,this.valuesEnd[t].original,this._morphPrecision?parseInt(this._morphPrecision,10):d.morphPrecision),a=r[0],i=r[1];this.valuesStart[t].polygon=a,this.valuesEnd[t].polygon=i}}}},Ie={EssentialBoxModel:Y,ColorsProperties:et,HTMLAttributes:st,OpacityProperty:ct,TextWriteProp:{component:"textWriteProperties",category:"textWrite",properties:["text","number"],defaultValues:{text:" ",number:"0"},defaultOptions:{textChars:"alpha"},Interpolate:{numbers:D},functions:{prepareStart:function(){return this.element.innerHTML},prepareProperty:function(t,e){return"number"===t?parseFloat(e):""===e?" ":e},onStart:gt},Util:{charSet:vt,createTextTweens:function(t,e,n){if(t.playing)return!1;var r=n||{};r.duration=1e3,"auto"===n.duration?r.duration="auto":Number.isFinite(1*n.duration)&&(r.duration=1*n.duration);var a=j.tween,i=function(t,e){var n=bt(t,"text-part"),r=bt(mt(e),"text-part");return t.innerHTML="",t.innerHTML+=n.map((function(t){return t.className+=" oldText",t.outerHTML})).join(""),t.innerHTML+=r.map((function(t){return t.className+=" newText",t.outerHTML.replace(t.innerHTML,"")})).join(""),[n,r]}(t,e),o=i[0],s=i[1],u=[].slice.call(t.getElementsByClassName("oldText")).reverse(),c=[].slice.call(t.getElementsByClassName("newText")),l=[],p=0;return(l=(l=l.concat(u.map((function(t,e){return r.duration="auto"===r.duration?75*o[e].innerHTML.length:r.duration,r.delay=p,r.onComplete=null,p+=r.duration,new a(t,{text:t.innerHTML},{text:""},r)})))).concat(c.map((function(n,i){return r.duration="auto"===r.duration?75*s[i].innerHTML.length:r.duration,r.delay=p,r.onComplete=i===s.length-1?function(){t.innerHTML=e,t.playing=!1}:null,p+=r.duration,new a(n,{text:""},{text:s[i].innerHTML},r)})))).start=function(){t.playing||(l.forEach((function(t){return t.start()})),t.playing=!0)},l}}},TransformFunctions:{component:"transformFunctions",property:"transform",subProperties:["perspective","translate3d","translateX","translateY","translateZ","translate","rotate3d","rotateX","rotateY","rotateZ","rotate","skewX","skewY","skew","scale"],defaultValues:{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},functions:{prepareStart:function(t){var e=C(this.element);return e[t]?e[t]:h[t]},prepareProperty:function(t,e){var n=["X","Y","Z"],r={},a=[],i=[],o=[],s=["translate3d","translate","rotate3d","skew"];return Object.keys(e).forEach((function(t){var u="object"==typeof e[t]&&e[t].length?e[t].map((function(t){return parseInt(t,10)})):parseInt(e[t],10);if(s.includes(t)){var c="translate"===t||"rotate"===t?t+"3d":t;r[c]="skew"===t?u.length?[u[0]||0,u[1]||0]:[u||0,0]:"translate"===t?u.length?[u[0]||0,u[1]||0,u[2]||0]:[u||0,0,0]:[u[0]||0,u[1]||0,u[2]||0]}else if(/[XYZ]/.test(t)){var l=t.replace(/[XYZ]/,""),p="skew"===l?l:l+"3d",f="skew"===l?2:3,h=[];"translate"===l?h=a:"rotate"===l?h=i:"skew"===l&&(h=o);for(var d=0;d>0)/1e3)+n,a[1]=t[1]||e[1]?(t[1]===e[1]?e[1]:(1e3*(t[1]+(e[1]-t[1])*r)>>0)/1e3)+n:"0","translate("+a.join(",")+")"},rotate:function(t,e,n,r){return"rotate("+(1e3*(t+(e-t)*r)>>0)/1e3+n+")"},scale:Mt,skew:_t}},SVGDraw:{component:"svgDraw",property:"draw",defaultValue:"0% 0%",Interpolate:{numbers:D},functions:Pt,Util:{getRectLength:Ct,getPolyLength:Ot,getLineLength:Tt,getCircleLength:St,getEllipseLength:It,getTotalLength:jt,resetDraw:function(t){t.style.strokeDashoffset="",t.style.strokeDasharray=""},getDraw:At,percent:kt}},SVGMorph:{component:"svgMorph",property:"path",defaultValue:[],Interpolate:xe,defaultOptions:{morphPrecision:10},functions:Se,Util:{addPoints:_e,bisect:ke,getPolygon:Oe,validPolygon:Ce,getInterpolationPoints:Te,pathStringToPolygon:Ee,distanceSquareRoot:ae,midPoint:re,approximatePolygon:we,rotatePolygon:Me,pathToString:le,pathToCurve:function(t){if(function(t){return Rt(t)&&t.every((function(t){return"MC".includes(t[0])}))}(t))return Zt(t);for(var e=Jt(Gt(t)),n=Object.assign({},Wt),r=[],a="",i=e.length,o=0;o 0 ? 1 : -1) * Math.floor(Math.abs(number)); + }; + var maxSafeInteger = Math.pow(2, 53) - 1; + var toLength = function (value) { + var len = toInteger(value); + return Math.min(Math.max(len, 0), maxSafeInteger); + }; + + return function from(arrayLike/*, mapFn, thisArg */) { + var C = this, items = Object(arrayLike); + if (arrayLike == null) { + throw new TypeError('Array.from requires an array-like object - not null or undefined'); + } + var mapFn = arguments.length > 1 ? arguments[1] : void undefined, T; + if (typeof mapFn !== 'undefined') { + if (!isCallable(mapFn)) { + throw new TypeError('Array.from: when provided, the second argument must be a function'); + } + + if (arguments.length > 2) { + T = arguments[2]; + } + } + var len = toLength(items.length); + var A = isCallable(C) ? Object(new C(len)) : new Array(len); + + var k = 0; + var kValue; + while (k < len) { + kValue = items[k]; + if (mapFn) { + A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); + } else { + A[k] = kValue; + } + k += 1; + } + A.length = len; + return A; + } + }()); +} + +// https://github.com/jonathantneal/array-flat-polyfill/blob/master/src/polyfill-flat.js + +if (!Array.prototype.flat) { + Object.defineProperty(Array.prototype, 'flat', { + configurable: true, + value: function flat () { + var depth = isNaN(arguments[0]) ? 1 : Number(arguments[0]); + + return depth ? Array.prototype.reduce.call(this, function (acc, cur) { + if (Array.isArray(cur)) { + acc.push.apply(acc, flat.call(cur, depth - 1)); + } else { + acc.push(cur); + } + + return acc; + }, []) : Array.prototype.slice.call(this); + }, + writable: true + }); +} + +if (!Array.prototype.includes) { + Array.prototype.includes = function(searchElement /*, fromIndex*/ ) { + var O = Object(this); + var len = parseInt(O.length) || 0; + if (len === 0) { + return false; + } + var n = parseInt(arguments[1]) || 0; + var k; + if (n >= 0) { + k = n; + } else { + k = len + n; + if (k < 0) {k = 0;} + } + var currentElement; + while (k < len) { + currentElement = O[k]; + if (searchElement === currentElement || + (searchElement !== searchElement && currentElement !== currentElement)) { + return true; + } + k++; + } + return false; + }; +} + +if (!String.prototype.includes) { + String.prototype.includes = function(search, start) { + if (search instanceof RegExp) { + throw TypeError('first argument must not be a RegExp'); + } + if (start === undefined) { start = 0; } + return this.indexOf(search, start) !== -1; + }; +} + +if (!Number.isFinite) { + Number.isFinite = function(value) { + return typeof value === 'number' + && isFinite(value); + }; +} + +if (!Number.isInteger) { + Number.isInteger = function(value) { + return typeof value === 'number' + && isFinite(value) + && Math.floor(value) === value; + }; +} + +if (!Number.isNaN) { + Number.isNaN = function(value) { + return typeof value === 'number' + && value !== value; + }; +} diff --git a/dist/polyfill.min.js b/dist/polyfill.min.js new file mode 100644 index 0000000..ab1cd05 --- /dev/null +++ b/dist/polyfill.min.js @@ -0,0 +1,3 @@ +// KUTE.js Polyfill v2.1.1-alpha1 | 2021 © thednp | MIT-License +"use strict"; +var r,t,e,n;Array.from||(Array.from=(r=Object.prototype.toString,t=function(t){return"function"==typeof t||"[object Function]"===r.call(t)},e=Math.pow(2,53)-1,n=function(r){var t=function(r){var t=Number(r);return isNaN(t)?0:0!==t&&isFinite(t)?(t>0?1:-1)*Math.floor(Math.abs(t)):t}(r);return Math.min(Math.max(t,0),e)},function(r){var e=this,i=Object(r);if(null==r)throw new TypeError("Array.from requires an array-like object - not null or undefined");var o,a=arguments.length>1?arguments[1]:void 0;if(void 0!==a){if(!t(a))throw new TypeError("Array.from: when provided, the second argument must be a function");arguments.length>2&&(o=arguments[2])}for(var u,f=n(i.length),p=t(e)?Object(new e(f)):new Array(f),c=0;c=0?n=o:(n=e+o)<0&&(n=0);n { + 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; + } +} diff --git a/src/animation/animationBase.js b/src/animation/animationBase.js new file mode 100644 index 0000000..ae3d763 --- /dev/null +++ b/src/animation/animationBase.js @@ -0,0 +1,97 @@ +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 }; + } +} diff --git a/src/animation/animationDevelopment.js b/src/animation/animationDevelopment.js new file mode 100644 index 0000000..dc067d4 --- /dev/null +++ b/src/animation/animationDevelopment.js @@ -0,0 +1,137 @@ +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; + } +} diff --git a/src/components/backgroundPosition.js b/src/components/backgroundPosition.js new file mode 100644 index 0000000..d6cb99b --- /dev/null +++ b/src/components/backgroundPosition.js @@ -0,0 +1,57 @@ +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; diff --git a/src/components/backgroundPositionBase.js b/src/components/backgroundPositionBase.js new file mode 100644 index 0000000..5105372 --- /dev/null +++ b/src/components/backgroundPositionBase.js @@ -0,0 +1,26 @@ +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; diff --git a/src/components/borderRadius.js b/src/components/borderRadius.js new file mode 100644 index 0000000..17cef65 --- /dev/null +++ b/src/components/borderRadius.js @@ -0,0 +1,58 @@ +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; diff --git a/src/components/borderRadiusBase.js b/src/components/borderRadiusBase.js new file mode 100644 index 0000000..1a48e4e --- /dev/null +++ b/src/components/borderRadiusBase.js @@ -0,0 +1,43 @@ +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; diff --git a/src/components/boxModel.js b/src/components/boxModel.js new file mode 100644 index 0000000..f40ac9e --- /dev/null +++ b/src/components/boxModel.js @@ -0,0 +1,57 @@ +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; diff --git a/src/components/boxModelBase.js b/src/components/boxModelBase.js new file mode 100644 index 0000000..40b5ef6 --- /dev/null +++ b/src/components/boxModelBase.js @@ -0,0 +1,37 @@ +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; diff --git a/src/components/boxModelEssential.js b/src/components/boxModelEssential.js new file mode 100644 index 0000000..ff0fbed --- /dev/null +++ b/src/components/boxModelEssential.js @@ -0,0 +1,56 @@ +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; diff --git a/src/components/clipProperty.js b/src/components/clipProperty.js new file mode 100644 index 0000000..d833ad9 --- /dev/null +++ b/src/components/clipProperty.js @@ -0,0 +1,52 @@ +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; diff --git a/src/components/clipPropertyBase.js b/src/components/clipPropertyBase.js new file mode 100644 index 0000000..af1f807 --- /dev/null +++ b/src/components/clipPropertyBase.js @@ -0,0 +1,36 @@ +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; diff --git a/src/components/colorProperties.js b/src/components/colorProperties.js new file mode 100644 index 0000000..7aed613 --- /dev/null +++ b/src/components/colorProperties.js @@ -0,0 +1,65 @@ +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; diff --git a/src/components/colorPropertiesBase.js b/src/components/colorPropertiesBase.js new file mode 100644 index 0000000..7b4d2e8 --- /dev/null +++ b/src/components/colorPropertiesBase.js @@ -0,0 +1,45 @@ +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; diff --git a/src/components/crossBrowserMove.js b/src/components/crossBrowserMove.js new file mode 100644 index 0000000..dea762d --- /dev/null +++ b/src/components/crossBrowserMove.js @@ -0,0 +1,95 @@ +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; diff --git a/src/components/filterEffects.js b/src/components/filterEffects.js new file mode 100644 index 0000000..0294f59 --- /dev/null +++ b/src/components/filterEffects.js @@ -0,0 +1,201 @@ +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 [, , , ] + 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; diff --git a/src/components/filterEffectsBase.js b/src/components/filterEffectsBase.js new file mode 100644 index 0000000..884b1e1 --- /dev/null +++ b/src/components/filterEffectsBase.js @@ -0,0 +1,74 @@ +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; diff --git a/src/components/htmlAttributes.js b/src/components/htmlAttributes.js new file mode 100644 index 0000000..d72f861 --- /dev/null +++ b/src/components/htmlAttributes.js @@ -0,0 +1,131 @@ +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; diff --git a/src/components/htmlAttributesBase.js b/src/components/htmlAttributesBase.js new file mode 100644 index 0000000..187abf6 --- /dev/null +++ b/src/components/htmlAttributesBase.js @@ -0,0 +1,59 @@ +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; diff --git a/src/components/opacityProperty.js b/src/components/opacityProperty.js new file mode 100644 index 0000000..c54eae7 --- /dev/null +++ b/src/components/opacityProperty.js @@ -0,0 +1,41 @@ +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; diff --git a/src/components/opacityPropertyBase.js b/src/components/opacityPropertyBase.js new file mode 100644 index 0000000..6eaf1d2 --- /dev/null +++ b/src/components/opacityPropertyBase.js @@ -0,0 +1,36 @@ +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; diff --git a/src/components/scrollProperty.js b/src/components/scrollProperty.js new file mode 100644 index 0000000..de3e66b --- /dev/null +++ b/src/components/scrollProperty.js @@ -0,0 +1,59 @@ +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; diff --git a/src/components/scrollPropertyBase.js b/src/components/scrollPropertyBase.js new file mode 100644 index 0000000..d15b3a7 --- /dev/null +++ b/src/components/scrollPropertyBase.js @@ -0,0 +1,113 @@ +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; diff --git a/src/components/shadowProperties.js b/src/components/shadowProperties.js new file mode 100644 index 0000000..952ec1c --- /dev/null +++ b/src/components/shadowProperties.js @@ -0,0 +1,127 @@ +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; diff --git a/src/components/shadowPropertiesBase.js b/src/components/shadowPropertiesBase.js new file mode 100644 index 0000000..40167c2 --- /dev/null +++ b/src/components/shadowPropertiesBase.js @@ -0,0 +1,46 @@ +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; diff --git a/src/components/svgCubicMorph.js b/src/components/svgCubicMorph.js new file mode 100644 index 0000000..a553477 --- /dev/null +++ b/src/components/svgCubicMorph.js @@ -0,0 +1,229 @@ +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; diff --git a/src/components/svgCubicMorphBase.js b/src/components/svgCubicMorphBase.js new file mode 100644 index 0000000..eca424f --- /dev/null +++ b/src/components/svgCubicMorphBase.js @@ -0,0 +1,38 @@ +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; diff --git a/src/components/svgDraw.js b/src/components/svgDraw.js new file mode 100644 index 0000000..346e09d --- /dev/null +++ b/src/components/svgDraw.js @@ -0,0 +1,210 @@ +import getStyleForProperty from '../process/getStyleForProperty'; +import numbers from '../interpolation/numbers'; +import { onStartDraw } from './svgDrawBase'; + +// Component Util +/** + * Convert a `` 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 `` 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 `` length + */ +function getRectLength(el) { + const w = el.getAttribute('width'); + const h = el.getAttribute('height'); + return (w * 2) + (h * 2); +} + +/** + * Returns the `` / `` 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 `` 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 `` 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 `` 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; diff --git a/src/components/svgDrawBase.js b/src/components/svgDrawBase.js new file mode 100644 index 0000000..5ad6680 --- /dev/null +++ b/src/components/svgDrawBase.js @@ -0,0 +1,35 @@ +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; diff --git a/src/components/svgMorph.js b/src/components/svgMorph.js new file mode 100644 index 0000000..f945d89 --- /dev/null +++ b/src/components/svgMorph.js @@ -0,0 +1,367 @@ +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; diff --git a/src/components/svgMorphBase.js b/src/components/svgMorphBase.js new file mode 100644 index 0000000..6c63d81 --- /dev/null +++ b/src/components/svgMorphBase.js @@ -0,0 +1,34 @@ +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; diff --git a/src/components/svgTransform.js b/src/components/svgTransform.js new file mode 100644 index 0000000..82c2599 --- /dev/null +++ b/src/components/svgTransform.js @@ -0,0 +1,196 @@ +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} + */ +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} 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; diff --git a/src/components/svgTransformBase.js b/src/components/svgTransformBase.js new file mode 100644 index 0000000..290ddd5 --- /dev/null +++ b/src/components/svgTransformBase.js @@ -0,0 +1,63 @@ +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; diff --git a/src/components/textProperties.js b/src/components/textProperties.js new file mode 100644 index 0000000..4f831ab --- /dev/null +++ b/src/components/textProperties.js @@ -0,0 +1,55 @@ +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; diff --git a/src/components/textPropertiesBase.js b/src/components/textPropertiesBase.js new file mode 100644 index 0000000..58dfa14 --- /dev/null +++ b/src/components/textPropertiesBase.js @@ -0,0 +1,35 @@ +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; diff --git a/src/components/textWrite.js b/src/components/textWrite.js new file mode 100644 index 0000000..e3d9363 --- /dev/null +++ b/src/components/textWrite.js @@ -0,0 +1,188 @@ +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; diff --git a/src/components/textWriteBase.js b/src/components/textWriteBase.js new file mode 100644 index 0000000..329c3e6 --- /dev/null +++ b/src/components/textWriteBase.js @@ -0,0 +1,102 @@ +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; diff --git a/src/components/transformFunctions.js b/src/components/transformFunctions.js new file mode 100644 index 0000000..0c912cf --- /dev/null +++ b/src/components/transformFunctions.js @@ -0,0 +1,152 @@ +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} 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; diff --git a/src/components/transformFunctionsBase.js b/src/components/transformFunctionsBase.js new file mode 100644 index 0000000..c1e9290 --- /dev/null +++ b/src/components/transformFunctionsBase.js @@ -0,0 +1,45 @@ +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; diff --git a/src/components/transformLegacy.js b/src/components/transformLegacy.js new file mode 100644 index 0000000..6a3453f --- /dev/null +++ b/src/components/transformLegacy.js @@ -0,0 +1,172 @@ +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} 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; diff --git a/src/components/transformLegacyBase.js b/src/components/transformLegacyBase.js new file mode 100644 index 0000000..e26315f --- /dev/null +++ b/src/components/transformLegacyBase.js @@ -0,0 +1,62 @@ +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; diff --git a/src/components/transformMatrix.js b/src/components/transformMatrix.js new file mode 100644 index 0000000..1a03f8e --- /dev/null +++ b/src/components/transformMatrix.js @@ -0,0 +1,165 @@ +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} 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; diff --git a/src/components/transformMatrixBase.js b/src/components/transformMatrixBase.js new file mode 100644 index 0000000..e4c483c --- /dev/null +++ b/src/components/transformMatrixBase.js @@ -0,0 +1,85 @@ +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; diff --git a/src/core/add.js b/src/core/add.js new file mode 100644 index 0000000..5541819 --- /dev/null +++ b/src/core/add.js @@ -0,0 +1,10 @@ +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; diff --git a/src/core/getAll.js b/src/core/getAll.js new file mode 100644 index 0000000..11804ef --- /dev/null +++ b/src/core/getAll.js @@ -0,0 +1,10 @@ +import Tweens from '../objects/tweens'; + +/** + * KUTE.add(Tween) + * + * @return {KUTE.Tween[]} tw a new tween to add + */ +const getAll = () => Tweens; + +export default getAll; diff --git a/src/core/internals.js b/src/core/internals.js new file mode 100644 index 0000000..5acd67b --- /dev/null +++ b/src/core/internals.js @@ -0,0 +1,17 @@ +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; diff --git a/src/core/linkInterpolation.js b/src/core/linkInterpolation.js new file mode 100644 index 0000000..a4313de --- /dev/null +++ b/src/core/linkInterpolation.js @@ -0,0 +1,39 @@ +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]; + } + }); + } + }); + } + }); + } + }); + }); +} diff --git a/src/core/queueStart.js b/src/core/queueStart.js new file mode 100644 index 0000000..8facc72 --- /dev/null +++ b/src/core/queueStart.js @@ -0,0 +1,18 @@ +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); +} diff --git a/src/core/remove.js b/src/core/remove.js new file mode 100644 index 0000000..3839303 --- /dev/null +++ b/src/core/remove.js @@ -0,0 +1,13 @@ +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; diff --git a/src/core/removeAll.js b/src/core/removeAll.js new file mode 100644 index 0000000..7760fd0 --- /dev/null +++ b/src/core/removeAll.js @@ -0,0 +1,8 @@ +import Tweens from '../objects/tweens'; + +/** + * KUTE.removeAll() + */ +const removeAll = () => { Tweens.length = 0; }; + +export default removeAll; diff --git a/src/core/render.js b/src/core/render.js new file mode 100644 index 0000000..c810476 --- /dev/null +++ b/src/core/render.js @@ -0,0 +1,67 @@ +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; diff --git a/src/easing/easing-base.js b/src/easing/easing-base.js new file mode 100644 index 0000000..752a682 --- /dev/null +++ b/src/easing/easing-base.js @@ -0,0 +1,64 @@ +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; diff --git a/src/easing/easing-bezier.js b/src/easing/easing-bezier.js new file mode 100644 index 0000000..47a511b --- /dev/null +++ b/src/easing/easing-bezier.js @@ -0,0 +1,62 @@ +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; diff --git a/src/easing/easing.js b/src/easing/easing.js new file mode 100644 index 0000000..2c58d86 --- /dev/null +++ b/src/easing/easing.js @@ -0,0 +1,169 @@ +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; diff --git a/src/index-base.js b/src/index-base.js new file mode 100644 index 0000000..dde2f09 --- /dev/null +++ b/src/index-base.js @@ -0,0 +1,36 @@ +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, +}; diff --git a/src/index-extra.js b/src/index-extra.js new file mode 100644 index 0000000..dd6759c --- /dev/null +++ b/src/index-extra.js @@ -0,0 +1,54 @@ +import CubicBezier from 'cubic-bezier-easing'; +import Render from './core/render'; +import Interpolate from './objects/interpolate'; +import Objects from './objects/objects'; +import Util from './objects/util'; +import Internals from './core/internals'; +import Process from './process/process'; +import Easing from './easing/easing-bezier'; +import Selector from './util/selector'; + +// TweenConstructor +import Tween from './tween/tweenExtra'; +import TweenCollection from './tween/tweenCollection'; +import ProgressBar from './util/progressBar'; +// interface +import to from './interface/to'; +import fromTo from './interface/fromTo'; +import allTo from './interface/allTo'; +import allFromTo from './interface/allFromTo'; + +// Animation +import Animation from './animation/animationDevelopment'; + +// Components Extra +import Components from './objects/componentsExtra'; + +import Version from './util/version'; + +export default { + Animation, + Components, + + // Tween Interface + Tween, + fromTo, + to, + // Tween Collection + TweenCollection, + ProgressBar, + allFromTo, + allTo, + // Tween Interface + + Objects, + Util, + Easing, + CubicBezier, + Render, + Interpolate, + Process, + Internals, + Selector, + Version, +}; diff --git a/src/index-legacy.js b/src/index-legacy.js new file mode 100644 index 0000000..b472c71 --- /dev/null +++ b/src/index-legacy.js @@ -0,0 +1,72 @@ +import Render from './core/render'; +import Interpolate from './objects/interpolate'; +import Objects from './objects/objects'; +import Util from './objects/util'; +import Internals from './core/internals'; +import Process from './process/process'; +import Easing from './easing/easing'; +import Selector from './util/selector'; + +// TweenConstructor +import Tween from './tween/tween'; +import TweenCollection from './tween/tweenCollection'; +// interface +import to from './interface/to'; +import fromTo from './interface/fromTo'; +import allTo from './interface/allTo'; +import allFromTo from './interface/allFromTo'; +import Animation from './animation/animation'; + +// components +import BoxModel from './components/boxModelEssential'; +import ColorProperties from './components/colorProperties'; +import HTMLAttributes from './components/htmlAttributes'; +import OpacityProperty from './components/opacityProperty'; +import TextWriteProp from './components/textWrite'; +import TransformLegacy from './components/transformLegacy'; +import SVGDraw from './components/svgDraw'; +import SVGMorph from './components/svgMorph'; + +import Version from './util/version'; + +const Components = { + BoxModel, + ColorProperties, + HTMLAttributes, + OpacityProperty, + TextWriteProp, + TransformLegacy, + SVGDraw, + SVGMorph, +}; + +// init components +Object.keys(Components).forEach((component) => { + const compOps = Components[component]; + Components[component] = new Animation(compOps); +}); + +export default { + Animation, + Components, + + // Tween Interface + Tween, + fromTo, + to, + // Tween Collection + TweenCollection, + allFromTo, + allTo, + // Tween Interface + + Objects, + Util, + Easing, + Render, + Interpolate, + Process, + Internals, + Selector, + Version, +}; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..8cffa97 --- /dev/null +++ b/src/index.js @@ -0,0 +1,55 @@ +// KUTE.js standard distribution version +import CubicBezier from 'cubic-bezier-easing'; +import Render from './core/render'; +import Interpolate from './objects/interpolate'; +import Objects from './objects/objects'; +import Util from './objects/util'; +import Internals from './core/internals'; +import Process from './process/process'; +import Easing from './easing/easing-bezier'; +import Selector from './util/selector'; + +// TweenConstructor +import Tween from './tween/tween'; +import TweenCollection from './tween/tweenCollection'; +// interface +import to from './interface/to'; +import fromTo from './interface/fromTo'; +import allTo from './interface/allTo'; +import allFromTo from './interface/allFromTo'; + +// Animation +import Animation from './animation/animation'; + +// Default Components +import Components from './objects/componentsDefault'; + +import Version from './util/version'; + +const KUTE = { + Animation, + Components, + + // Tween Interface + Tween, + fromTo, + to, + // Tween Collection + TweenCollection, + allFromTo, + allTo, + // Tween Interface + + Objects, + Util, + Easing, + CubicBezier, + Render, + Interpolate, + Process, + Internals, + Selector, + Version, +}; + +export default KUTE; diff --git a/src/interface/allFromTo.js b/src/interface/allFromTo.js new file mode 100644 index 0000000..b40ea35 --- /dev/null +++ b/src/interface/allFromTo.js @@ -0,0 +1,18 @@ +import selector from '../util/selector'; +import TweenCollection from '../tween/tweenCollection'; + +/** + * The `KUTE.allFromTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at a given state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {TweenCollection} the Tween object collection + */ +export default function allFromTo(elements, startObject, endObject, optionsObj) { + const options = optionsObj || {}; + return new TweenCollection(selector(elements, true), startObject, endObject, options); +} diff --git a/src/interface/allTo.js b/src/interface/allTo.js new file mode 100644 index 0000000..6b450f7 --- /dev/null +++ b/src/interface/allTo.js @@ -0,0 +1,18 @@ +import selector from '../util/selector'; +import TweenCollection from '../tween/tweenCollection'; + +/** + * The `KUTE.allTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at their current state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenProps} optionsObj progress + * @returns {TweenCollection} the Tween object collection + */ +export default function allTo(elements, endObject, optionsObj) { + const options = optionsObj || {}; + options.resetStart = endObject; + return new TweenCollection(selector(elements, true), endObject, endObject, options); +} diff --git a/src/interface/fromTo.js b/src/interface/fromTo.js new file mode 100644 index 0000000..56cb09c --- /dev/null +++ b/src/interface/fromTo.js @@ -0,0 +1,19 @@ +import selector from '../util/selector'; +import connect from '../objects/connect'; + +const { tween: TweenConstructor } = connect; + +/** + * The `KUTE.fromTo()` static method returns a new Tween object + * for a single `HTMLElement` at a given state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ +export default function fromTo(element, startObject, endObject, optionsObj) { + const options = optionsObj || {}; + return new TweenConstructor(selector(element), startObject, endObject, options); +} diff --git a/src/interface/to.js b/src/interface/to.js new file mode 100644 index 0000000..d2cf5ab --- /dev/null +++ b/src/interface/to.js @@ -0,0 +1,19 @@ +import selector from '../util/selector'; +import connect from '../objects/connect'; + +const { tween: TweenConstructor } = connect; + +/** + * The `KUTE.to()` static method returns a new Tween object + * for a single `HTMLElement` at its current state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ +export default function to(element, endObject, optionsObj) { + const options = optionsObj || {}; + options.resetStart = endObject; + return new TweenConstructor(selector(element), endObject, endObject, options); +} diff --git a/src/interpolation/arrays.js b/src/interpolation/arrays.js new file mode 100644 index 0000000..a959b0a --- /dev/null +++ b/src/interpolation/arrays.js @@ -0,0 +1,16 @@ +/** + * Array Interpolation Function. + * + * @param {number[]} a start array + * @param {number[]} b end array + * @param {number} v progress + * @returns {number[]} the resulting array + */ +export default function arrays(a, b, v) { + const result = []; const { length } = b; + for (let i = 0; i < length; i += 1) { + // eslint-disable-next-line no-bitwise + result[i] = ((a[i] + (b[i] - a[i]) * v) * 1000 >> 0) / 1000; + } + return result; +} diff --git a/src/interpolation/colors.js b/src/interpolation/colors.js new file mode 100644 index 0000000..b9359aa --- /dev/null +++ b/src/interpolation/colors.js @@ -0,0 +1,28 @@ +import numbers from './numbers'; +/** + * Color Interpolation Function. + * + * @param {KUTE.colorObject} a start color + * @param {KUTE.colorObject} b end color + * @param {number} v progress + * @returns {string} the resulting color + */ +export default function colors(a, b, v) { + const _c = {}; + const ep = ')'; + const cm = ','; + const rgb = 'rgb('; + const rgba = 'rgba('; + + Object.keys(b).forEach((c) => { + if (c !== 'a') { + _c[c] = numbers(a[c], b[c], v) >> 0 || 0; // eslint-disable-line no-bitwise + } else if (a[c] && b[c]) { + _c[c] = (numbers(a[c], b[c], v) * 100 >> 0) / 100; // eslint-disable-line no-bitwise + } + }); + + return !_c.a + ? rgb + _c.r + cm + _c.g + cm + _c.b + ep + : rgba + _c.r + cm + _c.g + cm + _c.b + cm + _c.a + ep; +} diff --git a/src/interpolation/coords.js b/src/interpolation/coords.js new file mode 100644 index 0000000..35d3298 --- /dev/null +++ b/src/interpolation/coords.js @@ -0,0 +1,20 @@ +/** + * Coordinates Interpolation Function. + * + * @param {number[][]} a start coordinates + * @param {number[][]} b end coordinates + * @param {string} l amount of coordinates + * @param {number} v progress + * @returns {number[][]} the interpolated coordinates + */ +export default function coords(a, b, l, v) { + const points = []; + for (let i = 0; i < l; i += 1) { // for each point + points[i] = []; + for (let j = 0; j < 2; j += 1) { // each point coordinate + // eslint-disable-next-line no-bitwise + points[i].push(((a[i][j] + (b[i][j] - a[i][j]) * v) * 1000 >> 0) / 1000); + } + } + return points; +} diff --git a/src/interpolation/numbers.js b/src/interpolation/numbers.js new file mode 100644 index 0000000..175fdda --- /dev/null +++ b/src/interpolation/numbers.js @@ -0,0 +1,14 @@ +/** + * Numbers Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {number} v progress + * @returns {number} the interpolated number + */ +export default function numbers(a, b, v) { + const A = +a; + const B = b - a; + // a = +a; b -= a; + return A + B * v; +} diff --git a/src/interpolation/perspective.js b/src/interpolation/perspective.js new file mode 100644 index 0000000..cb108b9 --- /dev/null +++ b/src/interpolation/perspective.js @@ -0,0 +1,13 @@ +/** + * Perspective Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the perspective function in string format + */ +export default function perspective(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `perspective(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} diff --git a/src/interpolation/rotate.js b/src/interpolation/rotate.js new file mode 100644 index 0000000..d0fca7c --- /dev/null +++ b/src/interpolation/rotate.js @@ -0,0 +1,13 @@ +/** + * 2D Rotation Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated rotation + */ +export default function rotate(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `rotate(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} diff --git a/src/interpolation/rotate3d.js b/src/interpolation/rotate3d.js new file mode 100644 index 0000000..c69907f --- /dev/null +++ b/src/interpolation/rotate3d.js @@ -0,0 +1,19 @@ +/** + * 3D Rotation Interpolation Function. + * + * @param {number} a start [x,y,z] angles + * @param {number} b end [x,y,z] angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D rotation string + */ +export default function rotate3d(a, b, u, v) { + let rotateStr = ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[0] || b[0] ? `rotateX(${((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000}${u})` : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[1] || b[1] ? `rotateY(${((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000}${u})` : ''; + // eslint-disable-next-line no-bitwise + rotateStr += a[2] || b[2] ? `rotateZ(${((a[2] + (b[2] - a[2]) * v) * 1000 >> 0) / 1000}${u})` : ''; + return rotateStr; +} diff --git a/src/interpolation/scale.js b/src/interpolation/scale.js new file mode 100644 index 0000000..e4da74a --- /dev/null +++ b/src/interpolation/scale.js @@ -0,0 +1,12 @@ +/** + * Scale Interpolation Function. + * + * @param {number} a start scale + * @param {number} b end scale + * @param {number} v progress + * @returns {string} the interpolated scale + */ +export default function scale(a, b, v) { + // eslint-disable-next-line no-bitwise + return `scale(${((a + (b - a) * v) * 1000 >> 0) / 1000})`; +} diff --git a/src/interpolation/skew.js b/src/interpolation/skew.js new file mode 100644 index 0000000..46bbe56 --- /dev/null +++ b/src/interpolation/skew.js @@ -0,0 +1,17 @@ +/** + * Skew Interpolation Function. + * + * @param {number} a start {x,y} angles + * @param {number} b end {x,y} angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated string value of skew(s) + */ +export default function skew(a, b, u, v) { + const skewArray = []; + // eslint-disable-next-line no-bitwise + skewArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + skewArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return `skew(${skewArray.join(',')})`; +} diff --git a/src/interpolation/skewX.js b/src/interpolation/skewX.js new file mode 100644 index 0000000..172334d --- /dev/null +++ b/src/interpolation/skewX.js @@ -0,0 +1,13 @@ +/** + * SkewX Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated skewX + */ +export default function skewX(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `skewX(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} diff --git a/src/interpolation/skewY.js b/src/interpolation/skewY.js new file mode 100644 index 0000000..e7f3fc5 --- /dev/null +++ b/src/interpolation/skewY.js @@ -0,0 +1,13 @@ +/** + * SkewY Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated skewY + */ +export default function skewY(a, b, u, v) { + // eslint-disable-next-line no-bitwise + return `skewY(${((a + (b - a) * v) * 1000 >> 0) / 1000}${u})`; +} diff --git a/src/interpolation/translate.js b/src/interpolation/translate.js new file mode 100644 index 0000000..dacc327 --- /dev/null +++ b/src/interpolation/translate.js @@ -0,0 +1,17 @@ +/** + * Translate 2D Interpolation Function. + * + * @param {number[]} a start [x,y] position + * @param {number[]} b end [x,y] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 2D translation string + */ +export default function translate(a, b, u, v) { + const translateArray = []; + // eslint-disable-next-line no-bitwise + translateArray[0] = (a[0] === b[0] ? b[0] : ((a[0] + (b[0] - a[0]) * v) * 1000 >> 0) / 1000) + u; + // eslint-disable-next-line no-bitwise + translateArray[1] = a[1] || b[1] ? ((a[1] === b[1] ? b[1] : ((a[1] + (b[1] - a[1]) * v) * 1000 >> 0) / 1000) + u) : '0'; + return `translate(${translateArray.join(',')})`; +} diff --git a/src/interpolation/translate3d.js b/src/interpolation/translate3d.js new file mode 100644 index 0000000..c71ffff --- /dev/null +++ b/src/interpolation/translate3d.js @@ -0,0 +1,18 @@ +/** + * Translate 3D Interpolation Function. + * + * @param {number[]} a start [x,y,z] position + * @param {number[]} b end [x,y,z] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D translation string + */ +export default function translate3d(a, b, u, v) { + const translateArray = []; + for (let ax = 0; ax < 3; ax += 1) { + translateArray[ax] = (a[ax] || b[ax] + // eslint-disable-next-line no-bitwise + ? ((a[ax] + (b[ax] - a[ax]) * v) * 1000 >> 0) / 1000 : 0) + u; + } + return `translate3d(${translateArray.join(',')})`; +} diff --git a/src/interpolation/units.js b/src/interpolation/units.js new file mode 100644 index 0000000..8e37df5 --- /dev/null +++ b/src/interpolation/units.js @@ -0,0 +1,15 @@ +/** + * Units Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the interpolated value + unit string + */ +export default function units(a, b, u, v) { // number1, number2, unit, progress + const A = +a; + const B = b - a; + // a = +a; b -= a; + return (A + B * v) + u; +} diff --git a/src/objects/componentsBase.js b/src/objects/componentsBase.js new file mode 100644 index 0000000..a4b2175 --- /dev/null +++ b/src/objects/componentsBase.js @@ -0,0 +1,16 @@ +import Animation from '../animation/animationBase'; + +// kute-base supported components +import baseTransform from '../components/transformFunctionsBase'; +import baseBoxModel from '../components/boxModelBase'; +import baseOpacity from '../components/opacityPropertyBase'; +// import {baseCrossBrowserMove} from '../components/crossBrowserMove' +// support for kute-base ends here + +const Components = { + Transform: new Animation(baseTransform), + BoxModel: new Animation(baseBoxModel), + Opacity: new Animation(baseOpacity), +}; + +export default Components; diff --git a/src/objects/componentsDefault.js b/src/objects/componentsDefault.js new file mode 100644 index 0000000..32ef35b --- /dev/null +++ b/src/objects/componentsDefault.js @@ -0,0 +1,29 @@ +import Animation from '../animation/animation'; + +import EssentialBoxModel from '../components/boxModelEssential'; +import ColorsProperties from '../components/colorProperties'; +import HTMLAttributes from '../components/htmlAttributes'; +import OpacityProperty from '../components/opacityProperty'; +import TextWriteProp from '../components/textWrite'; +import TransformFunctions from '../components/transformFunctions'; +import SVGDraw from '../components/svgDraw'; +import SVGMorph from '../components/svgMorph'; + +const Components = { + EssentialBoxModel, + ColorsProperties, + HTMLAttributes, + OpacityProperty, + TextWriteProp, + TransformFunctions, + SVGDraw, + SVGMorph, +}; + +// init components +Object.keys(Components).forEach((component) => { + const compOps = Components[component]; + Components[component] = new Animation(compOps); +}); + +export default Components; diff --git a/src/objects/componentsExtra.js b/src/objects/componentsExtra.js new file mode 100644 index 0000000..6345540 --- /dev/null +++ b/src/objects/componentsExtra.js @@ -0,0 +1,45 @@ +import Animation from '../animation/animationDevelopment'; + +import BackgroundPosition from '../components/backgroundPosition'; +import BorderRadius from '../components/borderRadius'; +import BoxModel from '../components/boxModel'; +import ClipProperty from '../components/clipProperty'; +import ColorProperties from '../components/colorProperties'; +import FilterEffects from '../components/filterEffects'; +import HTMLAttributes from '../components/htmlAttributes'; +import OpacityProperty from '../components/opacityProperty'; +import SVGDraw from '../components/svgDraw'; +import SVGCubicMorph from '../components/svgCubicMorph'; +import SVGTransform from '../components/svgTransform'; +import ScrollProperty from '../components/scrollProperty'; +import ShadowProperties from '../components/shadowProperties'; +import TextProperties from '../components/textProperties'; +import TextWriteProperties from '../components/textWrite'; +import MatrixTransform from '../components/transformMatrix'; + +const Components = { + BackgroundPosition, + BorderRadius, + BoxModel, + ClipProperty, + ColorProperties, + FilterEffects, + HTMLAttributes, + OpacityProperty, + SVGDraw, + SVGCubicMorph, + SVGTransform, + ScrollProperty, + ShadowProperties, + TextProperties, + TextWriteProperties, + MatrixTransform, +}; + +// init components +Object.keys(Components).forEach((component) => { + const compOps = Components[component]; + Components[component] = new Animation(compOps); +}); + +export default Components; diff --git a/src/objects/connect.js b/src/objects/connect.js new file mode 100644 index 0000000..2d5f778 --- /dev/null +++ b/src/objects/connect.js @@ -0,0 +1,6 @@ +const connect = {}; +/** @type {KUTE.TweenBase | KUTE.Tween | KUTE.TweenExtra} */ +connect.tween = null; +connect.processEasing = null; + +export default connect; diff --git a/src/objects/crossCheck.js b/src/objects/crossCheck.js new file mode 100644 index 0000000..e58a764 --- /dev/null +++ b/src/objects/crossCheck.js @@ -0,0 +1,6 @@ +// checks for differences between the processed start and end values, +// can be set to make sure start unit and end unit are same, +// stack transforms, process SVG paths, +// any type of post processing the component needs +const crossCheck = {}; +export default crossCheck; diff --git a/src/objects/defaultOptions.js b/src/objects/defaultOptions.js new file mode 100644 index 0000000..bfb341f --- /dev/null +++ b/src/objects/defaultOptions.js @@ -0,0 +1,14 @@ +const defaultOptions = { + duration: 700, + delay: 0, + easing: 'linear', + repeat: 0, + repeatDelay: 0, + yoyo: false, + resetStart: false, + offset: 0, +}; +// no need to set defaults for callbacks +// defaultOptions.onPause = undefined +// defaultOptions.onResume = undefined +export default defaultOptions; diff --git a/src/objects/defaultValues.js b/src/objects/defaultValues.js new file mode 100644 index 0000000..aec2050 --- /dev/null +++ b/src/objects/defaultValues.js @@ -0,0 +1,2 @@ +const defaultValues = {}; +export default defaultValues; diff --git a/src/objects/globalObject.js b/src/objects/globalObject.js new file mode 100644 index 0000000..8961257 --- /dev/null +++ b/src/objects/globalObject.js @@ -0,0 +1,8 @@ +let gl0bal; + +if (typeof global !== 'undefined') gl0bal = global; +else if (typeof window !== 'undefined') gl0bal = window.self; +else gl0bal = {}; + +const globalObject = gl0bal; +export default globalObject; diff --git a/src/objects/interpolate.js b/src/objects/interpolate.js new file mode 100644 index 0000000..0f0a5e5 --- /dev/null +++ b/src/objects/interpolate.js @@ -0,0 +1,4 @@ +// KUTE.js INTERPOLATE FUNCTIONS +// ============================= +const interpolate = {}; +export default interpolate; diff --git a/src/objects/kute.js b/src/objects/kute.js new file mode 100644 index 0000000..7ed1d44 --- /dev/null +++ b/src/objects/kute.js @@ -0,0 +1,5 @@ +/** + * The KUTE.js Execution Context + */ +const KEC = {}; +export default KEC; diff --git a/src/objects/linkProperty.js b/src/objects/linkProperty.js new file mode 100644 index 0000000..e3586e1 --- /dev/null +++ b/src/objects/linkProperty.js @@ -0,0 +1,3 @@ +// link properties to interpolate functions +const linkProperty = {}; +export default linkProperty; diff --git a/src/objects/objects.js b/src/objects/objects.js new file mode 100644 index 0000000..88fef2a --- /dev/null +++ b/src/objects/objects.js @@ -0,0 +1,23 @@ +import supportedProperties from './supportedProperties'; +import defaultValues from './defaultValues'; +import defaultOptions from './defaultOptions'; +import prepareProperty from './prepareProperty'; +import prepareStart from './prepareStart'; +import crossCheck from './crossCheck'; +import onStart from './onStart'; +import onComplete from './onComplete'; +import linkProperty from './linkProperty'; + +const Objects = { + supportedProperties, + defaultValues, + defaultOptions, + prepareProperty, + prepareStart, + crossCheck, + onStart, + onComplete, + linkProperty, +}; + +export default Objects; diff --git a/src/objects/objectsBase.js b/src/objects/objectsBase.js new file mode 100644 index 0000000..b504275 --- /dev/null +++ b/src/objects/objectsBase.js @@ -0,0 +1,13 @@ +import defaultOptions from './defaultOptions'; +import linkProperty from './linkProperty'; +import onStart from './onStart'; +import onComplete from './onComplete'; + +const Objects = { + defaultOptions, + linkProperty, + onStart, + onComplete, +}; + +export default Objects; diff --git a/src/objects/onComplete.js b/src/objects/onComplete.js new file mode 100644 index 0000000..dbead27 --- /dev/null +++ b/src/objects/onComplete.js @@ -0,0 +1,3 @@ +// schedule property specific function on animation complete +const onComplete = {}; +export default onComplete; diff --git a/src/objects/onStart.js b/src/objects/onStart.js new file mode 100644 index 0000000..b6a4ef7 --- /dev/null +++ b/src/objects/onStart.js @@ -0,0 +1,4 @@ +// schedule property specific function on animation start +// link property update function to KUTE.js execution context +const onStart = {}; +export default onStart; diff --git a/src/objects/prepareProperty.js b/src/objects/prepareProperty.js new file mode 100644 index 0000000..8e86ee1 --- /dev/null +++ b/src/objects/prepareProperty.js @@ -0,0 +1,3 @@ +// used in preparePropertiesObject +const prepareProperty = {}; +export default prepareProperty; diff --git a/src/objects/prepareStart.js b/src/objects/prepareStart.js new file mode 100644 index 0000000..a946308 --- /dev/null +++ b/src/objects/prepareStart.js @@ -0,0 +1,3 @@ +// check current property value when .to() method is used +const prepareStart = {}; +export default prepareStart; diff --git a/src/objects/supportedProperties.js b/src/objects/supportedProperties.js new file mode 100644 index 0000000..b3d41c3 --- /dev/null +++ b/src/objects/supportedProperties.js @@ -0,0 +1,3 @@ +// all supported properties +const supportedProperties = {}; +export default supportedProperties; diff --git a/src/objects/tweens.js b/src/objects/tweens.js new file mode 100644 index 0000000..5a2f8ff --- /dev/null +++ b/src/objects/tweens.js @@ -0,0 +1,2 @@ +const Tweens = []; +export default Tweens; diff --git a/src/objects/util.js b/src/objects/util.js new file mode 100644 index 0000000..bffef7f --- /dev/null +++ b/src/objects/util.js @@ -0,0 +1,3 @@ +// util - a general object for utils like rgbToHex, processEasing +const Util = {}; +export default Util; diff --git a/src/process/getInlineStyle.js b/src/process/getInlineStyle.js new file mode 100644 index 0000000..8079267 --- /dev/null +++ b/src/process/getInlineStyle.js @@ -0,0 +1,34 @@ +/** + * getInlineStyle + * Returns the transform style for element from + * cssText. Used by for the `.to()` static method. + * + * @param {Element} el target element + * @returns {object} + */ +export default function getInlineStyle(el) { + // if the scroll applies to `window` it returns as it has no styling + if (!el.style) return false; + // the cssText | the resulting transform object + const css = el.style.cssText.replace(/\s/g, '').split(';'); + const transformObject = {}; + const arrayFn = ['translate3d', 'translate', 'scale3d', 'skew']; + + css.forEach((cs) => { + if (/transform/i.test(cs)) { + // all transform properties + const tps = cs.split(':')[1].split(')'); + tps.forEach((tpi) => { + const tpv = tpi.split('('); + const tp = tpv[0]; + // each transform property + const tv = tpv[1]; + if (!/matrix/.test(tp)) { + transformObject[tp] = arrayFn.includes(tp) ? tv.split(',') : tv; + } + }); + } + }); + + return transformObject; +} diff --git a/src/process/getInlineStyleLegacy.js b/src/process/getInlineStyleLegacy.js new file mode 100644 index 0000000..83e176b --- /dev/null +++ b/src/process/getInlineStyleLegacy.js @@ -0,0 +1,33 @@ +import transformProperty from '../util/transformProperty'; + +/** + * getInlineStyle + * + * Returns the transform style for element from cssText. + * Used by for the `.to()` static method on legacy browsers. + * + * @param {Element} el target element + * @returns {object} a transform object + */ +export default function getInlineStyleLegacy(el) { + if (!el.style) return false; // if the scroll applies to `window` it returns as it has no styling + const css = el.style.cssText.replace(/\s/g, '').split(';'); // the cssText | the resulting transform object + const transformObject = {}; + const arrayFn = ['translate3d', 'translate', 'scale3d', 'skew']; + + css.forEach((cs) => { + const csi = cs.split(':'); + if (csi[0] === transformProperty) { + const tps = csi[1].split(')'); // all transform properties + tps.forEach((tpi) => { + const tpv = tpi.split('('); const tp = tpv[0]; const + tv = tpv[1]; // each transform property + if (!/matrix/.test(tp)) { + transformObject[tp] = arrayFn.includes(tp) ? tv.split(',') : tv; + } + }); + } + }); + + return transformObject; +} diff --git a/src/process/getStartValues.js b/src/process/getStartValues.js new file mode 100644 index 0000000..230dcd6 --- /dev/null +++ b/src/process/getStartValues.js @@ -0,0 +1,48 @@ +import getInlineStyle from './getInlineStyle'; +import prepareObject from './prepareObject'; +import defaultValues from '../objects/defaultValues'; +import prepareStart from '../objects/prepareStart'; +import supportedProperties from '../objects/supportedProperties'; + +/** + * getStartValues + * + * Returns the start values for to() method. + * Used by for the `.to()` static method. + * + * @this {KUTE.Tween} the tween instance + */ +export default function getStartValues() { + const startValues = {}; + const currentStyle = getInlineStyle(this.element); + + Object.keys(this.valuesStart).forEach((tweenProp) => { + Object.keys(prepareStart).forEach((component) => { + const componentStart = prepareStart[component]; + + Object.keys(componentStart).forEach((tweenCategory) => { + // clip, opacity, scroll + if (tweenCategory === tweenProp && componentStart[tweenProp]) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this, tweenProp, this.valuesStart[tweenProp]); + // find in an array of properties + } else if (supportedProperties[component] + && supportedProperties[component].includes(tweenProp)) { + startValues[tweenProp] = componentStart[tweenCategory] + .call(this, tweenProp, this.valuesStart[tweenProp]); + } + }); + }); + }); + + // stack transformCSS props for .to() chains + // also add to startValues values from previous tweens + Object.keys(currentStyle).forEach((current) => { + if (!(current in this.valuesStart)) { + startValues[current] = currentStyle[current] || defaultValues[current]; + } + }); + + this.valuesStart = {}; + prepareObject.call(this, startValues, 'start'); +} diff --git a/src/process/getStyleForProperty.js b/src/process/getStyleForProperty.js new file mode 100644 index 0000000..b8e8b74 --- /dev/null +++ b/src/process/getStyleForProperty.js @@ -0,0 +1,26 @@ +import defaultValues from '../objects/defaultValues'; + +/** + * getStyleForProperty + * + * Returns the computed style property for element for .to() method. + * Used by for the `.to()` static method. + * + * @param {Element} elem + * @param {string} propertyName + * @returns {string} + */ +export default function getStyleForProperty(elem, propertyName) { + let result = defaultValues[propertyName]; + const styleAttribute = elem.style; + const computedStyle = getComputedStyle(elem) || elem.currentStyle; + const styleValue = styleAttribute[propertyName] && !/auto|initial|none|unset/.test(styleAttribute[propertyName]) + ? styleAttribute[propertyName] + : computedStyle[propertyName]; + + if (propertyName !== 'transform' && (propertyName in computedStyle || propertyName in styleAttribute)) { + result = styleValue; + } + + return result; +} diff --git a/src/process/prepareObject.js b/src/process/prepareObject.js new file mode 100644 index 0000000..ead2490 --- /dev/null +++ b/src/process/prepareObject.js @@ -0,0 +1,53 @@ +import prepareProperty from '../objects/prepareProperty'; +import supportedProperties from '../objects/supportedProperties'; +import defaultValues from '../objects/defaultValues'; + +/** + * prepareObject + * + * Returns all processed valuesStart / valuesEnd. + * + * @param {Element} obj the values start/end object + * @param {string} fn toggles between the two + */ +export default function prepareObject(obj, fn) { // this, props object, type: start/end + const propertiesObject = fn === 'start' ? this.valuesStart : this.valuesEnd; + + Object.keys(prepareProperty).forEach((component) => { + const prepareComponent = prepareProperty[component]; + const supportComponent = supportedProperties[component]; + + Object.keys(prepareComponent).forEach((tweenCategory) => { + const transformObject = {}; + + Object.keys(obj).forEach((tweenProp) => { + // scroll, opacity, other components + if (defaultValues[tweenProp] && prepareComponent[tweenProp]) { + propertiesObject[tweenProp] = prepareComponent[tweenProp] + .call(this, tweenProp, obj[tweenProp]); + + // transform + } else if (!defaultValues[tweenCategory] && tweenCategory === 'transform' + && supportComponent.includes(tweenProp)) { + transformObject[tweenProp] = obj[tweenProp]; + + // allow transformFunctions to work with preprocessed input values + } else if (!defaultValues[tweenProp] && tweenProp === 'transform') { + propertiesObject[tweenProp] = obj[tweenProp]; + + // colors, boxModel, category + } else if (!defaultValues[tweenCategory] + && supportComponent && supportComponent.includes(tweenProp)) { + propertiesObject[tweenProp] = prepareComponent[tweenCategory] + .call(this, tweenProp, obj[tweenProp]); + } + }); + + // we filter out older browsers by checking Object.keys + if (Object.keys(transformObject).length) { + propertiesObject[tweenCategory] = prepareComponent[tweenCategory] + .call(this, tweenCategory, transformObject); + } + }); + }); +} diff --git a/src/process/process.js b/src/process/process.js new file mode 100644 index 0000000..d92656d --- /dev/null +++ b/src/process/process.js @@ -0,0 +1,11 @@ +import getInlineStyle from './getInlineStyle'; +import getStyleForProperty from './getStyleForProperty'; +import getStartValues from './getStartValues'; +import prepareObject from './prepareObject'; + +export default { + getInlineStyle, + getStyleForProperty, + getStartValues, + prepareObject, +}; diff --git a/src/tween/tween.js b/src/tween/tween.js new file mode 100644 index 0000000..7ca6c34 --- /dev/null +++ b/src/tween/tween.js @@ -0,0 +1,271 @@ +import KEC from '../objects/kute'; +import TweenBase from './tweenBase'; +import connect from '../objects/connect'; +import add from '../core/add'; +import remove from '../core/remove'; +import defaultOptions from '../objects/defaultOptions'; +import crossCheck from '../objects/crossCheck'; +import prepareObject from '../process/prepareObject'; +import getStartValues from '../process/getStartValues'; +import { Tick, Ticker } from '../core/render'; +import queueStart from '../core/queueStart'; + +/** + * The `KUTE.Tween()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor adds additional functionality and is the default + * Tween object constructor in KUTE.js. + */ +export default class Tween extends TweenBase { + /** + * @param {KUTE.tweenParams} args (*target*, *startValues*, *endValues*, *options*) + * @returns {Tween} the resulting Tween object + */ + constructor(...args) { + super(...args); // this calls the constructor of TweenBase + + // reset interpolation values + this.valuesStart = {}; + this.valuesEnd = {}; + + // const startObject = args[1]; + // const endObject = args[2]; + const [startObject, endObject, options] = args.slice(1); + + // set valuesEnd + prepareObject.call(this, endObject, 'end'); + + // set valuesStart + if (this._resetStart) { + this.valuesStart = startObject; + } else { + prepareObject.call(this, startObject, 'start'); + } + + // ready for crossCheck + if (!this._resetStart) { + Object.keys(crossCheck).forEach((component) => { + Object.keys(crossCheck[component]).forEach((checkProp) => { + crossCheck[component][checkProp].call(this, checkProp); + }); + }); + } + + // set paused state + /** @type {boolean} */ + this.paused = false; + /** @type {number?} */ + this._pauseTime = null; + + // additional properties and options + /** @type {number?} */ + this._repeat = options.repeat || defaultOptions.repeat; + /** @type {number?} */ + this._repeatDelay = options.repeatDelay || defaultOptions.repeatDelay; + // we cache the number of repeats to be able to put it back after all cycles finish + /** @type {number?} */ + this._repeatOption = this._repeat; + + // yoyo needs at least repeat: 1 + /** @type {KUTE.tweenProps} */ + this.valuesRepeat = {}; // valuesRepeat + /** @type {boolean} */ + this._yoyo = options.yoyo || defaultOptions.yoyo; + /** @type {boolean} */ + this._reversed = false; + + // don't load extra callbacks + // this._onPause = options.onPause || defaultOptions.onPause + // this._onResume = options.onResume || defaultOptions.onResume + + // chained Tweens + // this._chain = options.chain || defaultOptions.chain; + return this; + } + + /** + * Starts tweening, extended method + * @param {number?} time the tween start time + * @returns {Tween} this instance + */ + start(time) { + // on start we reprocess the valuesStart for TO() method + if (this._resetStart) { + this.valuesStart = this._resetStart; + getStartValues.call(this); + + // this is where we do the valuesStart and valuesEnd check for fromTo() method + Object.keys(crossCheck).forEach((component) => { + Object.keys(crossCheck[component]).forEach((checkProp) => { + crossCheck[component][checkProp].call(this, checkProp); + }); + }); + } + // still not paused + this.paused = false; + + // set yoyo values + if (this._yoyo) { + Object.keys(this.valuesEnd).forEach((endProp) => { + this.valuesRepeat[endProp] = this.valuesStart[endProp]; + }); + } + + super.start(time); + + return this; + } + + /** + * Stops tweening, extended method + * @returns {Tween} this instance + */ + stop() { + super.stop(); + if (!this.paused && this.playing) { + this.paused = false; + this.stopChainedTweens(); + } + return this; + } + + /** + * Trigger internal completion callbacks. + */ + close() { + super.close(); + + if (this._repeatOption > 0) { + this._repeat = this._repeatOption; + } + if (this._yoyo && this._reversed === true) { + this.reverse(); + this._reversed = false; + } + + return this; + } + + /** + * Resume tweening + * @returns {Tween} this instance + */ + resume() { + if (this.paused && this.playing) { + this.paused = false; + if (this._onResume !== undefined) { + this._onResume.call(this); + } + // re-queue execution context + queueStart.call(this); + // update time and let it roll + this._startTime += KEC.Time() - this._pauseTime; + add(this); + // restart ticker if stopped + if (!Tick) Ticker(); + } + return this; + } + + /** + * Pause tweening + * @returns {Tween} this instance + */ + pause() { + if (!this.paused && this.playing) { + remove(this); + this.paused = true; + this._pauseTime = KEC.Time(); + if (this._onPause !== undefined) { + this._onPause.call(this); + } + } + return this; + } + + /** + * Reverses start values with end values + */ + reverse() { + Object.keys(this.valuesEnd).forEach((reverseProp) => { + const tmp = this.valuesRepeat[reverseProp]; + this.valuesRepeat[reverseProp] = this.valuesEnd[reverseProp]; + this.valuesEnd[reverseProp] = tmp; + this.valuesStart[reverseProp] = this.valuesRepeat[reverseProp]; + }); + } + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + update(time) { + const T = time !== undefined ? time : KEC.Time(); + + let elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + const progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach((tweenProp) => { + KEC[tweenProp](this.element, + this.valuesStart[tweenProp], + this.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + if (this._repeat > 0) { + if (Number.isFinite(this._repeat)) this._repeat -= 1; + + // set the right time for delay + this._startTime = T; + if (Number.isFinite(this._repeat) && this._yoyo && !this._reversed) { + this._startTime += this._repeatDelay; + } + + if (this._yoyo) { // handle yoyo + this._reversed = !this._reversed; + this.reverse(); + } + + return true; + } + + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.forEach((tw) => tw.start()); + } + + return false; + } + return true; + } +} + +// Update Tween Interface Update +connect.tween = Tween; diff --git a/src/tween/tweenBase.js b/src/tween/tweenBase.js new file mode 100644 index 0000000..8d070e5 --- /dev/null +++ b/src/tween/tweenBase.js @@ -0,0 +1,211 @@ +import KEC from '../objects/kute'; +import connect from '../objects/connect'; +import onStart from '../objects/onStart'; +import onComplete from '../objects/onComplete'; +import defaultOptions from '../objects/defaultOptions'; + +import { Tick, Ticker, stop } from '../core/render'; + +import add from '../core/add'; +import remove from '../core/remove'; +import queueStart from '../core/queueStart'; + +/** + * The `TweenBase` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * `TweenBase` is meant to be used with pre-processed values. + */ +export default class TweenBase { + /** + * @param {Element} targetElement the target element + * @param {KUTE.tweenProps} startObject the start values + * @param {KUTE.tweenProps} endObject the end values + * @param {KUTE.tweenOptions} opsObject the end values + * @returns {TweenBase} the resulting Tween object + */ + constructor(targetElement, startObject, endObject, opsObject) { + // element animation is applied to + this.element = targetElement; + + /** @type {boolean} */ + this.playing = false; + /** @type {number?} */ + this._startTime = null; + /** @type {boolean} */ + this._startFired = false; + + // type is set via KUTE.tweenProps + this.valuesEnd = endObject; + this.valuesStart = startObject; + + // OPTIONS + const options = opsObject || {}; + // internal option to process inline/computed style at start instead of init + // used by to() method and expects object : {} / false + this._resetStart = options.resetStart || 0; + // you can only set a core easing function as default + /** @type {KUTE.easingOption} */ + this._easing = typeof (options.easing) === 'function' ? options.easing : connect.processEasing(options.easing); + /** @type {number} */ + this._duration = options.duration || defaultOptions.duration; // duration option | default + /** @type {number} */ + this._delay = options.delay || defaultOptions.delay; // delay option | default + + // set other options + Object.keys(options).forEach((op) => { + const internalOption = `_${op}`; + if (!(internalOption in this)) this[internalOption] = options[op]; + }); + + // callbacks should not be set as undefined + // this._onStart = options.onStart + // this._onUpdate = options.onUpdate + // this._onStop = options.onStop + // this._onComplete = options.onComplete + + // queue the easing + const easingFnName = this._easing.name; + if (!onStart[easingFnName]) { + onStart[easingFnName] = function easingFn(prop) { + if (!KEC[prop] && prop === this._easing.name) KEC[prop] = this._easing; + }; + } + + return this; + } + + /** + * Starts tweening + * @param {number?} time the tween start time + * @returns {TweenBase} this instance + */ + start(time) { + // now it's a good time to start + add(this); + this.playing = true; + + this._startTime = typeof time !== 'undefined' ? time : KEC.Time(); + this._startTime += this._delay; + + if (!this._startFired) { + if (this._onStart) { + this._onStart.call(this); + } + + queueStart.call(this); + + this._startFired = true; + } + + if (!Tick) Ticker(); + return this; + } + + /** + * Stops tweening + * @returns {TweenBase} this instance + */ + stop() { + if (this.playing) { + remove(this); + this.playing = false; + + if (this._onStop) { + this._onStop.call(this); + } + this.close(); + } + return this; + } + + /** + * Trigger internal completion callbacks. + */ + close() { + // scroll|transformMatrix need this + Object.keys(onComplete).forEach((component) => { + Object.keys(onComplete[component]).forEach((toClose) => { + onComplete[component][toClose].call(this, toClose); + }); + }); + // when all animations are finished, stop ticking after ~3 frames + this._startFired = false; + stop.call(this); + } + + /** + * Schedule another tween instance to start once this one completes. + * @param {KUTE.chainOption} args the tween animation start time + * @returns {TweenBase} this instance + */ + chain(args) { + this._chain = []; + this._chain = args.length ? args : this._chain.concat(args); + return this; + } + + /** + * Stop tweening the chained tween instances. + */ + stopChainedTweens() { + if (this._chain && this._chain.length) this._chain.forEach((tw) => tw.stop()); + } + + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + update(time) { + const T = time !== undefined ? time : KEC.Time(); + + let elapsed; + + if (T < this._startTime && this.playing) { return true; } + + elapsed = (T - this._startTime) / this._duration; + elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; + + // calculate progress + const progress = this._easing(elapsed); + + // render the update + Object.keys(this.valuesEnd).forEach((tweenProp) => { + KEC[tweenProp](this.element, + this.valuesStart[tweenProp], + this.valuesEnd[tweenProp], + progress); + }); + + // fire the updateCallback + if (this._onUpdate) { + this._onUpdate.call(this); + } + + if (elapsed === 1) { + // fire the complete callback + if (this._onComplete) { + this._onComplete.call(this); + } + + // now we're sure no animation is running + this.playing = false; + + // stop ticking when finished + this.close(); + + // start animating chained tweens + if (this._chain !== undefined && this._chain.length) { + this._chain.map((tw) => tw.start()); + } + + return false; + } + + return true; + } +} + +// Update Tween Interface +connect.tween = TweenBase; diff --git a/src/tween/tweenCollection.js b/src/tween/tweenCollection.js new file mode 100644 index 0000000..88f94b3 --- /dev/null +++ b/src/tween/tweenCollection.js @@ -0,0 +1,128 @@ +import KEC from '../objects/kute'; +import defaultOptions from '../objects/defaultOptions'; +import connect from '../objects/connect'; + +/** + * The static method creates a new `Tween` object for each `HTMLElement` + * from and `Array`, `HTMLCollection` or `NodeList`. + */ +export default class TweenCollection { + /** + * + * @param {Element[] | HTMLCollection | NodeList} els target elements + * @param {KUTE.tweenProps} vS the start values + * @param {KUTE.tweenProps} vE the end values + * @param {KUTE.tweenOptions} Options tween options + * @returns {TweenCollection} the Tween object collection + */ + constructor(els, vS, vE, Options) { + const TweenConstructor = connect.tween; + /** @type {KUTE.twCollection[]} */ + this.tweens = []; + + const Ops = Options || {}; + /** @type {number?} */ + Ops.delay = Ops.delay || defaultOptions.delay; + + // set all options + const options = []; + + Array.from(els).forEach((el, i) => { + options[i] = Ops || {}; + options[i].delay = i > 0 ? Ops.delay + (Ops.offset || defaultOptions.offset) : Ops.delay; + if (el instanceof Element) { + this.tweens.push(new TweenConstructor(el, vS, vE, options[i])); + } else { + throw Error(`KUTE - ${el} is not instanceof Element`); + } + }); + + /** @type {number?} */ + this.length = this.tweens.length; + return this; + } + + /** + * Starts tweening, all targets + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + start(time) { + const T = time === undefined ? KEC.Time() : time; + this.tweens.map((tween) => tween.start(T)); + return this; + } + + /** + * Stops tweening, all targets and their chains + * @returns {TweenCollection} this instance + */ + stop() { + this.tweens.map((tween) => tween.stop()); + return this; + } + + /** + * Pause tweening, all targets + * @returns {TweenCollection} this instance + */ + pause() { + this.tweens.map((tween) => tween.pause()); + return this; + } + + /** + * Resume tweening, all targets + * @returns {TweenCollection} this instance + */ + resume() { + this.tweens.map((tween) => tween.resume()); + return this; + } + + /** + * Schedule another tween or collection to start after + * this one is complete. + * @param {number?} args the tween start time + * @returns {TweenCollection} this instance + */ + chain(args) { + const lastTween = this.tweens[this.length - 1]; + if (args instanceof TweenCollection) { + lastTween.chain(args.tweens); + } else if (args instanceof connect.tween) { + lastTween.chain(args); + } else { + throw new TypeError('KUTE.js - invalid chain value'); + } + return this; + } + + /** + * Check if any tween instance is playing + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + playing() { + return this.tweens.some((tw) => tw.playing); + } + + /** + * Remove all tweens in the collection + */ + removeTweens() { + this.tweens = []; + } + + /** + * Returns the maximum animation duration + * @returns {number} this instance + */ + getMaxDuration() { + const durations = []; + this.tweens.forEach((tw) => { + durations.push(tw._duration + tw._delay + tw._repeat * tw._repeatDelay); + }); + return Math.max(durations); + } +} diff --git a/src/tween/tweenExtra.js b/src/tween/tweenExtra.js new file mode 100644 index 0000000..7bd71f4 --- /dev/null +++ b/src/tween/tweenExtra.js @@ -0,0 +1,73 @@ +import connect from '../objects/connect'; +import Tween from './tween'; + +// to do +// * per property easing +// * per property duration +// * per property callback +// * per property delay/offset +// * new update method to work with the above +// * other cool ideas + +/** + * The `KUTE.TweenExtra()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor is intended for experiments or testing of new features. + */ +export default class TweenExtra extends Tween { + /** + * @param {KUTE.tweenParams} args (*target*, *startValues*, *endValues*, *options*) + * @returns {TweenExtra} the resulting Tween object + */ + constructor(...args) { + super(...args); // import constructor of TweenBase -> Tween + + return this; + } + + // additional methods + // set/override property + // to(property, value) { + // TO DO + // this.valuesEnd[property] = value // well that's not all + // } + + // fromTo(property, value) { + // TO DO + // this.valuesEnd[property] = value // well that's not all + // } + + // getTotalDuration() { + // to do + // } + + /** + * Method to add callbacks on the fly. + * @param {string} name callback name + * @param {Function} fn callback function + * @returns {TweenExtra} + */ + on(name, fn) { + if (['start', 'stop', 'update', 'complete', 'pause', 'resume'].indexOf(name) > -1) { + this[`_on${name.charAt(0).toUpperCase() + name.slice(1)}`] = fn; + } + return this; + } + + /** + * Method to set options on the fly. + * * accepting [repeat,yoyo,delay,repeatDelay,easing] + * + * @param {string} option the tick time + * @param {string | number | number[]} value the tick time + * @returns {TweenExtra} + */ + option(option, value) { + this[`_${option}`] = value; + return this; + } +} + +// Tween Interface +connect.tween = TweenExtra; diff --git a/src/util/degToRad.js b/src/util/degToRad.js new file mode 100644 index 0000000..263b0c3 --- /dev/null +++ b/src/util/degToRad.js @@ -0,0 +1,10 @@ +/** + * degToRad + * + * Returns the value of a degree angle in radian. + * + * @param {number} a the degree angle + * @returns {number} the radian angle + */ +const degToRad = (a) => (a * Math.PI) / 180; +export default degToRad; diff --git a/src/util/fromJSON.js b/src/util/fromJSON.js new file mode 100644 index 0000000..c91bce2 --- /dev/null +++ b/src/util/fromJSON.js @@ -0,0 +1,17 @@ +/** + * fromJSON + * + * Returns the {valuesStart, valuesEnd} objects + * from a Tween instance. + * + * @param {string} str the JSON string + * @returns {JSON} the JSON object + */ +const fromJSON = (str) => { + const obj = JSON.parse(str); + return { + valuesStart: obj.valuesStart, + valuesEnd: obj.valuesEnd, + }; +}; +export default fromJSON; diff --git a/src/util/getPrefix.js b/src/util/getPrefix.js new file mode 100644 index 0000000..cca35d3 --- /dev/null +++ b/src/util/getPrefix.js @@ -0,0 +1,19 @@ +/** + * getPrefix + * + * Returns browser CSS3 prefix. Keep `for()` + * for wider browser support. + * + * @returns {?string} the browser prefix + */ +const getPrefix = () => { + let thePrefix = null; + const prefixes = ['Moz', 'moz', 'Webkit', 'webkit', 'O', 'o', 'Ms', 'ms']; + for (let i = 0, pfl = prefixes.length; i < pfl; i += 1) { + if (`${prefixes[i]}Transform` in document.body.style) { + thePrefix = prefixes[i]; break; // !! BREAK + } + } + return thePrefix; +}; +export default getPrefix; diff --git a/src/util/hexToRGB.js b/src/util/hexToRGB.js new file mode 100644 index 0000000..8ce596c --- /dev/null +++ b/src/util/hexToRGB.js @@ -0,0 +1,22 @@ +/** + * hexToRGB + * + * Converts a #HEX color format into RGB + * and returns a color object {r,g,b}. + * + * @param {string} hex the degree angle + * @returns {KUTE.colorObject | null} the radian angle + */ +const hexToRGB = (hex) => { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + const hexShorthand = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + const HEX = hex.replace(hexShorthand, (_, r, g, b) => r + r + g + g + b + b); + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(HEX); + + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } : null; +}; +export default hexToRGB; diff --git a/src/util/now.js b/src/util/now.js new file mode 100644 index 0000000..27759c0 --- /dev/null +++ b/src/util/now.js @@ -0,0 +1,32 @@ +// Include a performance.now polyfill. +// source https://github.com/tweenjs/tween.js/blob/master/src/Now.ts +let performanceNow; + +// In node.js, use process.hrtime. +// eslint-disable-next-line +// @ts-ignore +if (typeof self === 'undefined' && typeof process !== 'undefined' && process.hrtime) { + performanceNow = () => { + // eslint-disable-next-line + // @ts-ignore + const time = process.hrtime(); + + // Convert [seconds, nanoseconds] to milliseconds. + return time[0] * 1000 + time[1] / 1000000; + }; +} else if (typeof self !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) { + // In a browser, use self.performance.now if it is available. + // This must be bound, because directly assigning this function + // leads to an invocation exception in Chrome. + performanceNow = self.performance.now.bind(self.performance); +} else if (typeof Date !== 'undefined' && Date.now) { + // Use Date.now if it is available. + performanceNow = Date.now; +} else { + // Otherwise, use 'new Date().getTime()'. + performanceNow = () => new Date().getTime(); +} + +const now = performanceNow; + +export default now; diff --git a/src/util/polyfill-legacy.js b/src/util/polyfill-legacy.js new file mode 100644 index 0000000..7833696 --- /dev/null +++ b/src/util/polyfill-legacy.js @@ -0,0 +1,23 @@ +/* + * build this polyfill for IE9+ browser support + */ +// import 'minifill/src/this.Window' +// import 'minifill/src/this.Document' +// import 'minifill/src/window.HTMLElement' + +// import 'minifill/src/Object.defineProperty' +// import 'minifill/src/Object.create' +import 'minifill/src/Function.prototype.bind'; + +import 'minifill/src/Array.from'; +import 'minifill/src/Array.prototype.map'; +import 'minifill/src/Array.prototype.some'; +import 'minifill/src/Array.prototype.every'; +import 'minifill/src/Array.prototype.includes'; +import 'minifill/src/Array.prototype.flat'; +import 'minifill/src/String.prototype.includes'; + +// IE9+ +import 'minifill/src/Date.now'; +import 'minifill/src/window.performance.now'; +import 'minifill/src/window.requestAnimationFrame'; diff --git a/src/util/polyfill.js b/src/util/polyfill.js new file mode 100644 index 0000000..2e2514a --- /dev/null +++ b/src/util/polyfill.js @@ -0,0 +1,8 @@ +// IE10+ +import 'minifill/src/Array.from'; +import 'minifill/src/Array.prototype.flat'; +import 'minifill/src/Array.prototype.includes'; +import 'minifill/src/String.prototype.includes'; +import 'minifill/src/Number.isFinite'; +import 'minifill/src/Number.isInteger'; +import 'minifill/src/Number.isNaN'; diff --git a/src/util/progressBar.js b/src/util/progressBar.js new file mode 100644 index 0000000..65fa8d0 --- /dev/null +++ b/src/util/progressBar.js @@ -0,0 +1,109 @@ +import KEC from '../objects/kute'; +import connect from '../objects/connect'; +import selector from './selector'; + +/** + * ProgressBar + * + * @class + * A progress bar utility for KUTE.js that will connect + * a target ``. with a Tween instance + * allowing it to control the progress of the Tween. + */ +export default class ProgressBar { + /** + * @constructor + * @param {HTMLElement} el target or string selector + * @param {KUTE.Tween} multi when true returns an array of elements + */ + constructor(element, tween) { + this.element = selector(element); + this.element.tween = tween; + this.element.tween.toolbar = this.element; + this.element.toolbar = this; + [this.element.output] = this.element.parentNode.getElementsByTagName('OUTPUT'); + + // invalidate + if (!(this.element instanceof HTMLInputElement)) throw TypeError('Target element is not [HTMLInputElement]'); + if (this.element.type !== 'range') throw TypeError('Target element is not a range input'); + if (!(tween instanceof connect.tween)) throw TypeError(`tween parameter is not [${connect.tween}]`); + + this.element.setAttribute('value', 0); + this.element.setAttribute('min', 0); + this.element.setAttribute('max', 1); + this.element.setAttribute('step', 0.0001); + + this.element.tween._onUpdate = this.updateBar; + + this.element.addEventListener('mousedown', this.downAction, false); + } + + updateBar() { + const tick = 0.0001; + const { output } = this.toolbar; + + // let progress = this.paused ? this.toolbar.value + // : (KEC.Time() - this._startTime) / this._duration; + // progress = progress > 1 - tick ? 1 : progress < 0.01 ? 0 : progress; + + let progress; + if (this.paused) { + progress = this.toolbar.value; + } else { + progress = (KEC.Time() - this._startTime) / this._duration; + } + + // progress = progress > 1 - tick ? 1 : progress < 0.01 ? 0 : progress; + if (progress > 1 - tick) progress = 1; + if (progress < 0.01) progress = 0; + + const value = !this._reversed ? progress : 1 - progress; + this.toolbar.value = value; + // eslint-disable-next-line no-bitwise + if (output) output.value = `${(value * 10000 >> 0) / 100}%`; + } + + toggleEvents(action) { + // add passive handler ? + this.element[`${action}EventListener`]('mousemove', this.moveAction, false); + this.element[`${action}EventListener`]('mouseup', this.upAction, false); + } + + updateTween() { + // make sure we never complete the tween + const progress = (!this.tween._reversed ? this.value : 1 - this.value) + * this.tween._duration - 0.0001; + + this.tween._startTime = 0; + this.tween.update(progress); + } + + moveAction() { + this.toolbar.updateTween.call(this); + } + + downAction() { + if (!this.tween.playing) { + this.tween.start(); + } + + if (!this.tween.paused) { + this.tween.pause(); + this.toolbar.toggleEvents('add'); + + KEC.Tick = cancelAnimationFrame(KEC.Ticker); + } + } + + upAction() { + if (this.tween.paused) { + if (this.tween.paused) this.tween.resume(); + + this.tween._startTime = KEC.Time() + - (!this.tween._reversed ? this.value : 1 - this.value) * this.tween._duration; + + this.toolbar.toggleEvents('remove'); + KEC.Tick = requestAnimationFrame(KEC.Ticker); + } + } +} diff --git a/src/util/radToDeg.js b/src/util/radToDeg.js new file mode 100644 index 0000000..d5de40c --- /dev/null +++ b/src/util/radToDeg.js @@ -0,0 +1,10 @@ +/** + * radToDeg + * + * Returns the value of a radian in degrees. + * + * @param {number} a the value in radian + * @returns {number} the value in degrees + */ +const radToDeg = (a) => (a * 180) / Math.PI; +export default radToDeg; diff --git a/src/util/rgbToHex.js b/src/util/rgbToHex.js new file mode 100644 index 0000000..66333e0 --- /dev/null +++ b/src/util/rgbToHex.js @@ -0,0 +1,14 @@ +/** + * rgbToHex + * + * Converts an {r,g,b} color `Object` into #HEX string color format. + * Webkit browsers ignore HEX, always use RGB/RGBA. + * + * @param {number} r the red value + * @param {number} g the green value + * @param {number} b the blue value + * @returns {string} the #HEX string + */ +// eslint-disable-next-line no-bitwise +const rgbToHex = (r, g, b) => `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; +export default rgbToHex; diff --git a/src/util/selector.js b/src/util/selector.js new file mode 100644 index 0000000..8c4d917 --- /dev/null +++ b/src/util/selector.js @@ -0,0 +1,26 @@ +/** + * selector + * + * A selector utility for KUTE.js. + * + * @param {KUTE.selectorType} el target(s) or string selector + * @param {boolean | number} multi when true returns an array/collection of elements + * @returns {Element | Element[] | null} + */ +export default function selector(el, multi) { + try { + let requestedElem; + let itemsArray; + if (multi) { + itemsArray = el instanceof Array && el.every((x) => x instanceof Element); + requestedElem = el instanceof HTMLCollection || el instanceof NodeList || itemsArray + ? el : document.querySelectorAll(el); + } else { + requestedElem = el instanceof Element || el === window // scroll + ? el : document.querySelector(el); + } + return requestedElem; + } catch (e) { + throw TypeError(`KUTE.js - Element(s) not found: ${el}.`); + } +} diff --git a/src/util/supportLegacyTransform.js b/src/util/supportLegacyTransform.js new file mode 100644 index 0000000..f9a0c56 --- /dev/null +++ b/src/util/supportLegacyTransform.js @@ -0,0 +1,5 @@ +import transformProperty from './transformProperty'; + +/** check if transform is supported via prefixed property */ +const supportTransform = transformProperty in document.head.style; +export default supportTransform; diff --git a/src/util/toJSON.js b/src/util/toJSON.js new file mode 100644 index 0000000..f350234 --- /dev/null +++ b/src/util/toJSON.js @@ -0,0 +1,17 @@ +/** + * toJSON + * + * Returns the {valuesStart, valuesEnd} objects + * from a Tween instance in JSON string format. + * + * @param {KUTE.Tween} tween the Tween instance + * @returns {string} the JSON string + */ +const toJSON = (tween) => { + const obj = { + valuesStart: tween.valuesStart, + valuesEnd: tween.valuesEnd, + }; + return JSON.stringify(obj); +}; +export default toJSON; diff --git a/src/util/transformProperty.js b/src/util/transformProperty.js new file mode 100644 index 0000000..ccf07e2 --- /dev/null +++ b/src/util/transformProperty.js @@ -0,0 +1,5 @@ +import trueProperty from './trueProperty'; + +/** the `transform` string for legacy browsers */ +const transformProperty = trueProperty('transform'); +export default transformProperty; diff --git a/src/util/trueColor.js b/src/util/trueColor.js new file mode 100644 index 0000000..03c2887 --- /dev/null +++ b/src/util/trueColor.js @@ -0,0 +1,49 @@ +import hexToRGB from './hexToRGB'; + +/** + * trueColor + * + * Transform any color to rgba()/rgb() and return a nice RGB(a) object. + * + * @param {string} colorString the color input + * @returns {KUTE.colorObject} the {r,g,b,a} color object + */ +const trueColor = (colorString) => { + let result; + if (/rgb|rgba/.test(colorString)) { // first check if it's a rgb string + const vrgb = colorString.replace(/\s|\)/, '').split('(')[1].split(','); + const colorAlpha = vrgb[3] ? vrgb[3] : null; + if (!colorAlpha) { + result = { r: parseInt(vrgb[0], 10), g: parseInt(vrgb[1], 10), b: parseInt(vrgb[2], 10) }; + } + result = { + r: parseInt(vrgb[0], 10), + g: parseInt(vrgb[1], 10), + b: parseInt(vrgb[2], 10), + a: parseFloat(colorAlpha), + }; + } if (/^#/.test(colorString)) { + const fromHex = hexToRGB(colorString); + result = { r: fromHex.r, g: fromHex.g, b: fromHex.b }; + } if (/transparent|none|initial|inherit/.test(colorString)) { + result = { + r: 0, g: 0, b: 0, a: 0, + }; + } + // maybe we can check for web safe colors + // only works in a browser + if (!/^#|^rgb/.test(colorString)) { + const siteHead = document.getElementsByTagName('head')[0]; + siteHead.style.color = colorString; + let webColor = getComputedStyle(siteHead, null).color; + webColor = /rgb/.test(webColor) ? webColor.replace(/[^\d,]/g, '').split(',') : [0, 0, 0]; + siteHead.style.color = ''; + result = { + r: parseInt(webColor[0], 10), + g: parseInt(webColor[1], 10), + b: parseInt(webColor[2], 10), + }; + } + return result; +}; +export default trueColor; diff --git a/src/util/trueDimension.js b/src/util/trueDimension.js new file mode 100644 index 0000000..4301b08 --- /dev/null +++ b/src/util/trueDimension.js @@ -0,0 +1,27 @@ +/** + * trueDimension + * + * Returns the string value of a specific CSS property converted into a nice + * { v = value, u = unit } object. + * + * @param {string} dimValue the property string value + * @param {boolean | number} isAngle sets the utility to investigate angles + * @returns {{v: number, u: string}} the true {value, unit} tuple + */ +const trueDimension = (dimValue, isAngle) => { + const intValue = parseInt(dimValue, 10) || 0; + const mUnits = ['px', '%', 'deg', 'rad', 'em', 'rem', 'vh', 'vw']; + let theUnit; + + for (let mIndex = 0; mIndex < mUnits.length; mIndex += 1) { + if (typeof dimValue === 'string' && dimValue.includes(mUnits[mIndex])) { + theUnit = mUnits[mIndex]; break; + } + } + if (theUnit === undefined) { + theUnit = isAngle ? 'deg' : 'px'; + } + + return { v: intValue, u: theUnit }; +}; +export default trueDimension; diff --git a/src/util/trueProperty.js b/src/util/trueProperty.js new file mode 100644 index 0000000..7bff726 --- /dev/null +++ b/src/util/trueProperty.js @@ -0,0 +1,19 @@ +import getPrefix from './getPrefix'; + +/** + * trueProperty + * + * Returns prefixed property name in a legacy browser + * or the regular name in modern browsers. + * + * @param {string} property the property name + * @returns {string} the right property name for every browser + */ +const trueProperty = (property) => { + const prop = !(property in document.head.style) + ? getPrefix() + (property.charAt(0).toUpperCase() + property.slice(1)) + : property; + return prop; +}; + +export default trueProperty; diff --git a/src/util/version.js b/src/util/version.js new file mode 100644 index 0000000..369fd70 --- /dev/null +++ b/src/util/version.js @@ -0,0 +1,9 @@ +// @ts-ignore +import { version } from '../../package.json'; + +/** + * A global namespace for library version. + * @type {string} + */ +const Version = version; +export default Version; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fdc8e92 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", + "declaration": true, + "resolveJsonModule": true, + "emitDeclarationOnly": true, + "maxNodeModuleJsDepth": 3, // allows to incorporate dependency utils + "strict": true, + "allowJs": true, + "rootDir": "../", + "outFile": "types/kute.d.ts", // UN-comment to generate + "outDir": "types", + }, + "files": [ + "types/index.d.ts", + // "types/kute.d.ts", // comment to re-generate, delete file + "types/more/kute.ts", + "types/more/types.d.ts", + ], +} diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..1b28421 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,155 @@ +export as namespace KUTE; + +// dependencies +export * as SVGPathCommander from "svg-path-commander"; + +import './kute'; +export { default as Animation } from "kute.js/src/animation/animation"; +export { default as AnimationBase } from "kute.js/src/animation/animationBase"; +export { default as AnimationDevelopment } from "kute.js/src/animation/animationDevelopment"; +export { default as backgroundPosition } from "kute.js/src/components/backgroundPosition"; +export { default as backgroundPositionBase } from "kute.js/src/components/backgroundPositionBase"; +export { default as borderRadius } from "kute.js/src/components/borderRadius"; +export { default as borderRadiusBase } from "kute.js/src/components/borderRadiusBase"; +export { default as boxModel } from "kute.js/src/components/boxModel"; +export { default as boxModelBase } from "kute.js/src/components/boxModelBase"; +export { default as boxModelEssential } from "kute.js/src/components/boxModelEssential"; +export { default as clipProperty } from "kute.js/src/components/clipProperty"; +export { default as clipPropertyBase } from "kute.js/src/components/clipPropertyBase"; +export { default as colorProperties } from "kute.js/src/components/colorProperties"; +export { default as colorPropertiesBase } from "kute.js/src/components/colorPropertiesBase"; +export { default as crossBrowserMove } from "kute.js/src/components/crossBrowserMove"; +export { default as filterEffects } from "kute.js/src/components/filterEffects"; +export { default as filterEffectsBase } from "kute.js/src/components/filterEffectsBase"; +export { default as htmlAttributes } from "kute.js/src/components/htmlAttributes"; +export { default as htmlAttributesBase } from "kute.js/src/components/htmlAttributesBase"; +export { default as opacityProperty } from "kute.js/src/components/opacityProperty"; +export { default as opacityPropertyBase } from "kute.js/src/components/opacityPropertyBase"; +export { default as scrollProperty } from "kute.js/src/components/scrollProperty"; +export { default as scrollPropertyBase } from "kute.js/src/components/scrollPropertyBase"; +export { default as shadowProperties } from "kute.js/src/components/shadowProperties"; +export { default as shadowPropertiesBase } from "kute.js/src/components/shadowPropertiesBase"; +export { default as svgCubicMorph } from "kute.js/src/components/svgCubicMorph"; +export { default as svgCubicMorphBase } from "kute.js/src/components/svgCubicMorphBase"; +export { default as svgDraw } from "kute.js/src/components/svgDraw"; +export { default as svgDrawBase } from "kute.js/src/components/svgDrawBase"; +export { default as svgMorph } from "kute.js/src/components/svgMorph"; +export { default as svgMorphBase } from "kute.js/src/components/svgMorphBase"; +export { default as svgTransform } from "kute.js/src/components/svgTransform"; +export { default as svgTransformBase } from "kute.js/src/components/svgTransformBase"; +export { default as textProperties } from "kute.js/src/components/textProperties"; +export { default as textPropertiesBase } from "kute.js/src/components/textPropertiesBase"; +export { default as textWrite } from "kute.js/src/components/textWrite"; +export { default as textWriteBase } from "kute.js/src/components/textWriteBase"; +export { default as transformFunctions } from "kute.js/src/components/transformFunctions"; +export { default as transformFunctionsBase } from "kute.js/src/components/transformFunctionsBase"; +export { default as transformLegacy } from "kute.js/src/components/transformLegacy"; +export { default as transformLegacyBase } from "kute.js/src/components/transformLegacyBase"; +export { default as transformMatrix } from "kute.js/src/components/transformMatrix"; +export { default as transformMatrixBase } from "kute.js/src/components/transformMatrixBase"; +export { default as add } from "kute.js/src/core/add"; +export { default as getAll } from "kute.js/src/core/getAll"; +export { default as Internals } from "kute.js/src/core/internals"; +export { default as linkInterpolation } from "kute.js/src/core/linkInterpolation"; +export { default as queueStart } from "kute.js/src/core/queueStart"; +export { default as remove } from "kute.js/src/core/remove"; +export { default as removeAll } from "kute.js/src/core/removeAll"; +export { default as Render } from "kute.js/src/core/render"; +export { default as EasingBase } from "kute.js/src/easing/easing-base"; +export { default as EasingBezier } from "kute.js/src/easing/easing-bezier"; +export { default as Easing } from "kute.js/src/easing/easing"; +export { default as allFromTo } from "kute.js/src/interface/allFromTo"; +export { default as allTo } from "kute.js/src/interface/allTo"; +export { default as fromTo } from "kute.js/src/interface/fromTo"; +export { default as to } from "kute.js/src/interface/to"; +export { default as arrays } from "kute.js/src/interpolation/arrays"; +export { default as colors } from "kute.js/src/interpolation/colors"; +export { default as coords } from "kute.js/src/interpolation/coords"; +export { default as numbers } from "kute.js/src/interpolation/numbers"; +export { default as perspective } from "kute.js/src/interpolation/perspective"; +export { default as rotate } from "kute.js/src/interpolation/rotate"; +export { default as rotate3d } from "kute.js/src/interpolation/rotate3d"; +export { default as scale } from "kute.js/src/interpolation/scale"; +export { default as skew } from "kute.js/src/interpolation/skew"; +export { default as skewX } from "kute.js/src/interpolation/skewX"; +export { default as skewY } from "kute.js/src/interpolation/skewY"; +export { default as translate } from "kute.js/src/interpolation/translate"; +export { default as translate3d } from "kute.js/src/interpolation/translate3d"; +export { default as units } from "kute.js/src/interpolation/units"; +export { default as ComponentsBase } from "kute.js/src/objects/componentsBase"; +export { default as ComponentsDefault } from "kute.js/src/objects/componentsDefault"; +export { default as ComponentsExtra } from "kute.js/src/objects/componentsExtra"; +export { default as connect } from "kute.js/src/objects/connect"; +export { default as crossCheck } from "kute.js/src/objects/crossCheck"; +export { default as defaultOptions } from "kute.js/src/objects/defaultOptions"; +export { default as defaultValues } from "kute.js/src/objects/defaultValues"; +export { default as globalObject } from "kute.js/src/objects/globalObject"; +export { default as Interpolate } from "kute.js/src/objects/interpolate"; +export { default as KEC } from "kute.js/src/objects/kute"; +export { default as linkProperty } from "kute.js/src/objects/linkProperty"; +export { default as Objects } from "kute.js/src/objects/objects"; +export { default as ObjectsBase } from "kute.js/src/objects/objectsBase"; +export { default as onComplete } from "kute.js/src/objects/onComplete"; +export { default as onStart } from "kute.js/src/objects/onStart"; +export { default as prepareProperty } from "kute.js/src/objects/prepareProperty"; +export { default as prepareStart } from "kute.js/src/objects/prepareStart"; +export { default as supportedProperties } from "kute.js/src/objects/supportedProperties"; +export { default as Tweens } from "kute.js/src/objects/tweens"; +export { default as Util } from "kute.js/src/objects/util"; +export { default as getInlineStyle } from "kute.js/src/process/getInlineStyle"; +export { default as getInlineStyleLegacy } from "kute.js/src/process/getInlineStyleLegacy"; +export { default as getStartValues } from "kute.js/src/process/getStartValues"; +export { default as getStyleForProperty } from "kute.js/src/process/getStyleForProperty"; +export { default as prepareObject } from "kute.js/src/process/prepareObject"; +export { default as Process } from "kute.js/src/process/process"; +export { default as Tween } from "kute.js/src/tween/tween"; +export { default as TweenBase } from "kute.js/src/tween/tweenBase"; +export { default as TweenCollection } from "kute.js/src/tween/tweenCollection"; +export { default as TweenExtra } from "kute.js/src/tween/tweenExtra"; +export { default as degToRad } from "kute.js/src/util/degToRad"; +export { default as fromJSON } from "kute.js/src/util/fromJSON"; +export { default as getPrefix } from "kute.js/src/util/getPrefix"; +export { default as hexToRGB } from "kute.js/src/util/hexToRGB"; +export { default as now } from "kute.js/src/util/now"; +export { default as ProgressBar } from "kute.js/src/util/progressBar"; +export { default as radToDeg } from "kute.js/src/util/radToDeg"; +export { default as rgbToHex } from "kute.js/src/util/rgbToHex"; +export { default as selector } from "kute.js/src/util/selector"; +export { default as supportLegacyTransform } from "kute.js/src/util/supportLegacyTransform"; +export { default as toJSON } from "kute.js/src/util/toJSON"; +export { default as transformProperty } from "kute.js/src/util/transformProperty"; +export { default as trueColor } from "kute.js/src/util/trueColor"; +export { default as trueDimension } from "kute.js/src/util/trueDimension"; +export { default as trueProperty } from "kute.js/src/util/trueProperty"; +export { default as Version } from "kute.js/src/util/version"; + +export { + easingFunction, + easingOption, + tweenOptions, + tweenProps, + tweenParams, + twCollection, + chainOption, + propValue, + rawValue, + interpolationFn, + preparePropFn, + prepareStartFn, + fullComponent, + baseComponent, + curveObject, + polygonMorph, + polygonObject, + transformMObject, + transformFObject, + transformSVGObject, + exactPolygon, + drawObject, + curveSpecs, + colorObject, + shadowObject, + filterList, + selectorType, +} from './more/types'; + diff --git a/types/kute.d.ts b/types/kute.d.ts new file mode 100644 index 0000000..acf3cc8 --- /dev/null +++ b/types/kute.d.ts @@ -0,0 +1,3054 @@ +declare module "kute.js/src/objects/supportedProperties" { + export default supportedProperties; + const supportedProperties: {}; +} +declare module "kute.js/src/objects/defaultValues" { + export default defaultValues; + const defaultValues: {}; +} +declare module "kute.js/src/objects/defaultOptions" { + export default defaultOptions; + namespace defaultOptions { + const duration: number; + const delay: number; + const easing: string; + const repeat: number; + const repeatDelay: number; + const yoyo: boolean; + const resetStart: boolean; + const offset: number; + } +} +declare module "kute.js/src/objects/prepareProperty" { + export default prepareProperty; + const prepareProperty: {}; +} +declare module "kute.js/src/objects/prepareStart" { + export default prepareStart; + const prepareStart: {}; +} +declare module "kute.js/src/objects/onStart" { + export default onStart; + const onStart: {}; +} +declare module "kute.js/src/objects/onComplete" { + export default onComplete; + const onComplete: {}; +} +declare module "kute.js/src/objects/crossCheck" { + export default crossCheck; + const crossCheck: {}; +} +declare module "kute.js/src/objects/linkProperty" { + export default linkProperty; + const linkProperty: {}; +} +declare module "kute.js/src/objects/util" { + export default Util; + const Util: {}; +} +declare module "kute.js/src/objects/interpolate" { + export default interpolate; + const interpolate: {}; +} +declare module "kute.js/src/animation/animation" { + /** + * 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: KUTE.fullComponent); + } +} +declare module "kute.js/src/animation/animationBase" { + /** + * 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: KUTE.baseComponent); + _: number; + } +} +declare module "kute.js/src/animation/animationDevelopment" { + /** + * 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: any); + } + import Animation from "kute.js/src/animation/animation"; +} +declare module "kute.js/src/process/getStyleForProperty" { + /** + * getStyleForProperty + * + * Returns the computed style property for element for .to() method. + * Used by for the `.to()` static method. + * + * @param {Element} elem + * @param {string} propertyName + * @returns {string} + */ + export default function getStyleForProperty(elem: Element, propertyName: string): string; +} +declare module "kute.js/src/interpolation/numbers" { + /** + * Numbers Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {number} v progress + * @returns {number} the interpolated number + */ + export default function numbers(a: number, b: number, v: number): number; +} +declare module "kute.js/src/util/trueDimension" { + export default trueDimension; + /** + * trueDimension + * + * Returns the string value of a specific CSS property converted into a nice + * { v = value, u = unit } object. + * + * @param {string} dimValue the property string value + * @param {boolean | number} isAngle sets the utility to investigate angles + * @returns {{v: number, u: string}} the true {value, unit} tuple + */ + function trueDimension(dimValue: string, isAngle: boolean | number): { + v: number; + u: string; + }; +} +declare module "kute.js/src/objects/kute" { + export default KEC; + /** + * The KUTE.js Execution Context + */ + const KEC: {}; +} +declare module "kute.js/src/components/backgroundPositionBase" { + /** + * Sets the property update function. + * @param {string} prop the property name + */ + export function onStartBgPos(prop: string): void; + export default BackgroundPositionBase; + namespace BackgroundPositionBase { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartBgPos as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/backgroundPosition" { + export default BackgroundPosition; + namespace BackgroundPosition { + export const component: string; + export const property: string; + export const defaultValue: number[]; + export namespace Interpolate { + export { numbers }; + } + export { bgPositionFunctions as functions }; + export namespace Util { + export { trueDimension }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace bgPositionFunctions { + export { getBgPos as prepareStart }; + export { prepareBgPos as prepareProperty }; + export { onStartBgPos as onStart }; + } + import trueDimension from "kute.js/src/util/trueDimension"; + /** + * Returns the property computed style. + * @param {string} prop the property + * @returns {string} the property computed style + */ + function getBgPos(prop: string): string; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {string} value the property value + * @returns {number[]} the property tween object + */ + function prepareBgPos(_: string, value: string): number[]; + import { onStartBgPos } from "kute.js/src/components/backgroundPositionBase"; +} +declare module "kute.js/src/interpolation/units" { + /** + * Units Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the interpolated value + unit string + */ + export default function units(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/components/borderRadiusBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function radiusOnStartFn(tweenProp: string): void; + export default BorderRadiusBase; + namespace BorderRadiusBase { + const component: string; + const category: string; + namespace Interpolate { + export { units }; + } + namespace functions { + export { radiusOnStart as onStart }; + } + } + import units from "kute.js/src/interpolation/units"; + const radiusOnStart: {}; +} +declare module "kute.js/src/components/borderRadius" { + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string} the property computed style + */ + export function getRadius(tweenProp: string): string; + /** + * Returns the property tween object. + * @param {string} value the property value + * @returns {{v: number, u: string}} the property tween object + */ + export function prepareRadius(_: any, value: string): { + v: number; + u: string; + }; + export namespace radiusFunctions { + export { getRadius as prepareStart }; + export { prepareRadius as prepareProperty }; + export { radiusOnStart as onStart }; + } + export default BorderRadius; + const radiusOnStart: {}; + namespace BorderRadius { + export const component: string; + export const category: string; + export { radiusProps as properties }; + export { radiusValues as defaultValues }; + export namespace Interpolate { + export { units }; + } + export { radiusFunctions as functions }; + export namespace Util { + export { trueDimension }; + } + } + const radiusProps: string[]; + const radiusValues: {}; + import units from "kute.js/src/interpolation/units"; + import trueDimension from "kute.js/src/util/trueDimension"; +} +declare module "kute.js/src/components/boxModelBase" { + /** + * Sets the update function for the property. + * @param {string} tweenProp the property name + */ + export function boxModelOnStart(tweenProp: string): void; + export default BoxModelBase; + namespace BoxModelBase { + export const component: string; + export const category: string; + export { baseBoxProps as properties }; + export namespace Interpolate { + export { numbers }; + } + export namespace functions { + export { baseBoxOnStart as onStart }; + } + } + const baseBoxProps: string[]; + import numbers from "kute.js/src/interpolation/numbers"; + const baseBoxOnStart: {}; +} +declare module "kute.js/src/components/boxModel" { + export default BoxModel; + namespace BoxModel { + export const component: string; + export const category: string; + export { boxModelProperties as properties }; + export { boxModelValues as defaultValues }; + export namespace Interpolate { + export { numbers }; + } + export { boxModelFunctions as functions }; + } + const boxModelProperties: string[]; + const boxModelValues: {}; + import numbers from "kute.js/src/interpolation/numbers"; + namespace boxModelFunctions { + export { getBoxModel as prepareStart }; + export { prepareBoxModel as prepareProperty }; + export { boxPropsOnStart as onStart }; + } + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string} computed style for property + */ + function getBoxModel(tweenProp: string): string; + /** + * 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: string, value: string): number; + const boxPropsOnStart: {}; +} +declare module "kute.js/src/components/boxModelEssential" { + export default BoxModelEssential; + namespace BoxModelEssential { + export const component: string; + export const category: string; + export { essentialBoxProps as properties }; + export { essentialBoxPropsValues as defaultValues }; + export namespace Interpolate { + export { numbers }; + } + export { essentialBoxModelFunctions as functions }; + export namespace Util { + export { trueDimension }; + } + } + const essentialBoxProps: string[]; + namespace essentialBoxPropsValues { + const top: number; + const left: number; + const width: number; + const height: number; + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace essentialBoxModelFunctions { + export { getBoxModel as prepareStart }; + export { prepareBoxModel as prepareProperty }; + export { essentialBoxOnStart as onStart }; + } + import trueDimension from "kute.js/src/util/trueDimension"; + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string} computed style for property + */ + function getBoxModel(tweenProp: string): string; + /** + * 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: string, value: string): number; + const essentialBoxOnStart: {}; +} +declare module "kute.js/src/components/clipPropertyBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartClip(tweenProp: string): void; + export default ClipPropertyBase; + namespace ClipPropertyBase { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartClip as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/clipProperty" { + export default ClipProperty; + namespace ClipProperty { + export const component: string; + export const property: string; + export const defaultValue: number[]; + export namespace Interpolate { + export { numbers }; + } + export { clipFunctions as functions }; + export namespace Util { + export { trueDimension }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace clipFunctions { + export { getClip as prepareStart }; + export { prepareClip as prepareProperty }; + export { onStartClip as onStart }; + } + import trueDimension from "kute.js/src/util/trueDimension"; + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string | number[]} computed style for property + */ + function getClip(tweenProp: string): string | number[]; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {string} value the property value + * @returns {number[]} the property tween object + */ + function prepareClip(_: string, value: string): number[]; + import { onStartClip } from "kute.js/src/components/clipPropertyBase"; +} +declare module "kute.js/src/util/hexToRGB" { + export default hexToRGB; + /** + * hexToRGB + * + * Converts a #HEX color format into RGB + * and returns a color object {r,g,b}. + * + * @param {string} hex the degree angle + * @returns {KUTE.colorObject | null} the radian angle + */ + function hexToRGB(hex: string): KUTE.colorObject | null; +} +declare module "kute.js/src/util/trueColor" { + export default trueColor; + /** + * trueColor + * + * Transform any color to rgba()/rgb() and return a nice RGB(a) object. + * + * @param {string} colorString the color input + * @returns {KUTE.colorObject} the {r,g,b,a} color object + */ + function trueColor(colorString: string): KUTE.colorObject; +} +declare module "kute.js/src/interpolation/colors" { + /** + * Color Interpolation Function. + * + * @param {KUTE.colorObject} a start color + * @param {KUTE.colorObject} b end color + * @param {number} v progress + * @returns {string} the resulting color + */ + export default function colors(a: KUTE.colorObject, b: KUTE.colorObject, v: number): string; +} +declare module "kute.js/src/components/colorPropertiesBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartColors(tweenProp: string): void; + export namespace baseColors { + const component: string; + const category: string; + namespace Interpolate { + export { numbers }; + export { colors }; + } + namespace functions { + export { colorsOnStart as onStart }; + } + } + export default baseColors; + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + const colorsOnStart: {}; +} +declare module "kute.js/src/components/colorProperties" { + export default colorProperties; + namespace colorProperties { + export const component: string; + export const category: string; + export { supportedColors as properties }; + export { defaultColors as defaultValues }; + export namespace Interpolate { + export { numbers }; + export { colors }; + } + export { colorFunctions as functions }; + export namespace Util { + export { trueColor }; + } + } + const supportedColors: string[]; + const defaultColors: {}; + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + namespace colorFunctions { + export { getColor as prepareStart }; + export { prepareColor as prepareProperty }; + export { colorsOnStart as onStart }; + } + import trueColor from "kute.js/src/util/trueColor"; + /** + * Returns the current property computed style. + * @param {string} prop the property name + * @returns {string} property computed style + */ + function getColor(prop: string): string; + /** + * 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(_: string, value: string): KUTE.colorObject; + const colorsOnStart: {}; +} +declare module "kute.js/src/process/getInlineStyle" { + /** + * getInlineStyle + * Returns the transform style for element from + * cssText. Used by for the `.to()` static method. + * + * @param {Element} el target element + * @returns {object} + */ + export default function getInlineStyle(el: Element): object; +} +declare module "kute.js/src/util/getPrefix" { + export default getPrefix; + /** + * getPrefix + * + * Returns browser CSS3 prefix. Keep `for()` + * for wider browser support. + * + * @returns {?string} the browser prefix + */ + function getPrefix(): string | null; +} +declare module "kute.js/src/util/trueProperty" { + export default trueProperty; + /** + * trueProperty + * + * Returns prefixed property name in a legacy browser + * or the regular name in modern browsers. + * + * @param {string} property the property name + * @returns {string} the right property name for every browser + */ + function trueProperty(property: string): string; +} +declare module "kute.js/src/components/crossBrowserMove" { + /** + * Sets the property update function. + * @param {string} tweenProp the `path` property + */ + export function onStartComponent(tweenProp: string): void; + export namespace baseCrossBrowserMove { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartComponent as onStart }; + } + } + export default crossBrowserMove; + import numbers from "kute.js/src/interpolation/numbers"; + namespace crossBrowserMove { + const component_1: string; + export { component_1 as component }; + const property_1: string; + export { property_1 as property }; + export const defaultValue: number[]; + export namespace Interpolate_1 { + export { numbers }; + } + export { Interpolate_1 as Interpolate }; + export { componentFunctions as functions }; + export namespace Util { + export { trueProperty }; + } + } + namespace componentFunctions { + export { getComponentCurrentValue as prepareStart }; + export { prepareComponentValue as prepareProperty }; + export { onStartComponent as onStart }; + } + import trueProperty from "kute.js/src/util/trueProperty"; + /** + * Returns the property current style. + */ + function getComponentCurrentValue(): number[]; + /** + * Returns the property tween object. + * @param {string} _ property name + * @param {string} value property value + * @returns {number[]} the property tween object + */ + function prepareComponentValue(_: string, value: string): number[]; +} +declare module "kute.js/src/components/filterEffectsBase" { + /** + * 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: any, b: any, v: any): string; + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartFilter(tweenProp: string): void; + export default baseFilter; + namespace baseFilter { + const component: string; + const property: string; + namespace Interpolate { + export { numbers as opacity }; + export { numbers as blur }; + export { numbers as saturate }; + export { numbers as grayscale }; + export { numbers as brightness }; + export { numbers as contrast }; + export { numbers as sepia }; + export { numbers as invert }; + export { numbers as hueRotate }; + export namespace dropShadow { + export { numbers }; + export { colors }; + export { dropshadow }; + } + } + namespace functions { + export { onStartFilter as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; +} +declare module "kute.js/src/components/filterEffects" { + export default filterEffects; + namespace filterEffects { + export const component: string; + export const property: string; + export namespace defaultValue { + const opacity: number; + const blur: number; + const saturate: number; + const grayscale: number; + const brightness: number; + const contrast: number; + const sepia: number; + const invert: number; + const hueRotate: number; + const dropShadow: (number | { + r: number; + g: number; + b: number; + })[]; + const url: string; + } + export namespace Interpolate { + export { numbers as opacity }; + export { numbers as blur }; + export { numbers as saturate }; + export { numbers as grayscale }; + export { numbers as brightness }; + export { numbers as contrast }; + export { numbers as sepia }; + export { numbers as invert }; + export { numbers as hueRotate }; + export namespace dropShadow_1 { + export { numbers }; + export { colors }; + export { dropshadow }; + } + export { dropShadow_1 as dropShadow }; + } + export { filterFunctions as functions }; + export namespace Util { + export { parseDropShadow }; + export { parseFilterString }; + export { replaceDashNamespace }; + export { trueColor }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + import { dropshadow } from "kute.js/src/components/filterEffectsBase"; + namespace filterFunctions { + export { getFilter as prepareStart }; + export { prepareFilter as prepareProperty }; + export { onStartFilter as onStart }; + export { crossCheckFilter as crossCheck }; + } + /** + * 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: (string | number)[]): KUTE.filterList['dropShadow']; + /** + * 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: string): { + [x: string]: number; + }; + /** + * Returns camelCase filter sub-property. + * @param {string} str source string + * @returns {string} camelCase property name + */ + function replaceDashNamespace(str: string): string; + import trueColor from "kute.js/src/util/trueColor"; + /** + * 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: string, value: string): string; + /** + * 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(_: string, value: string): KUTE.filterList; + import { onStartFilter } from "kute.js/src/components/filterEffectsBase"; + /** + * Adds missing sub-properties in `valuesEnd` from `valuesStart`. + * @param {string} tweenProp the property name + */ + function crossCheckFilter(tweenProp: string): void; +} +declare module "kute.js/src/components/htmlAttributesBase" { + export namespace onStartAttr { + /** + * onStartAttr.attr + * + * Sets the sub-property update function. + * @param {string} tweenProp the property name + */ + function attr(tweenProp: string): void; + /** + * onStartAttr.attr + * + * Sets the sub-property update function. + * @param {string} tweenProp the property name + */ + function attr(tweenProp: string): void; + /** + * onStartAttr.attributes + * + * Sets the update function for the property. + * @param {string} tweenProp the property name + */ + function attributes(tweenProp: string): void; + /** + * onStartAttr.attributes + * + * Sets the update function for the property. + * @param {string} tweenProp the property name + */ + function attributes(tweenProp: string): void; + } + export default baseAttributes; + export const attributes: {}; + namespace baseAttributes { + export { ComponentName as component }; + export const property: string; + export namespace Interpolate { + export { numbers }; + export { colors }; + } + export namespace functions { + export { onStartAttr as onStart }; + } + } + const ComponentName: "baseHTMLAttributes"; + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; +} +declare module "kute.js/src/components/htmlAttributes" { + /** + * 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(_: string, value: string): { + [x: string]: string; + }; + /** + * 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: string, attrObj: string): number; + export default htmlAttributes; + namespace htmlAttributes { + export { ComponentName as component }; + export const property: string; + export const subProperties: string[]; + export const defaultValue: { + fill: string; + stroke: string; + 'stop-color': string; + opacity: number; + 'stroke-opacity': number; + 'fill-opacity': number; + }; + export namespace Interpolate { + export { numbers }; + export { colors }; + } + export { attrFunctions as functions }; + export namespace Util { + export { replaceUppercase }; + export { trueColor }; + export { trueDimension }; + } + } + const ComponentName: "htmlAttributes"; + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + namespace attrFunctions { + export { getAttr as prepareStart }; + export { prepareAttr as prepareProperty }; + export { onStartAttr as onStart }; + } + /** + * Returns non-camelcase property name. + * @param {string} a the camelcase property name + * @returns {string} the non-camelcase property name + */ + function replaceUppercase(a: string): string; + import trueColor from "kute.js/src/util/trueColor"; + import trueDimension from "kute.js/src/util/trueDimension"; + import { onStartAttr } from "kute.js/src/components/htmlAttributesBase"; +} +declare module "kute.js/src/components/opacityPropertyBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartOpacity(tweenProp: string): void; + export default OpacityPropertyBase; + namespace OpacityPropertyBase { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartOpacity as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/opacityProperty" { + export default OpacityProperty; + namespace OpacityProperty { + export const component: string; + export const property: string; + export const defaultValue: number; + export namespace Interpolate { + export { numbers }; + } + export { opacityFunctions as functions }; + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace opacityFunctions { + export { getOpacity as prepareStart }; + export { prepareOpacity as prepareProperty }; + export { onStartOpacity as onStart }; + } + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string} computed style for property + */ + function getOpacity(tweenProp: string): string; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {string} value the property value + * @returns {number} the property tween object + */ + function prepareOpacity(_: string, value: string): number; + import { onStartOpacity } from "kute.js/src/components/opacityPropertyBase"; +} +declare module "kute.js/src/components/scrollPropertyBase" { + /** + * Prevent further scroll events until scroll animation is over. + * @param {Event} e event object + */ + export function preventScroll(e: Event): void; + /** + * Returns the scroll element / target. + * @returns {{el: Element, st: Element}} + */ + export function getScrollTargets(): { + el: Element; + st: Element; + }; + /** + * Toggles scroll prevention callback on scroll events. + * @param {string} action addEventListener / removeEventListener + * @param {Element} element target + */ + export function toggleScrollEvents(action: string, element: Element): void; + /** + * Action performed before scroll animation start. + */ + export function scrollIn(): void; + /** + * Action performed when scroll animation ends. + */ + export function scrollOut(): void; + /** + * * 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: string): void; + export class onStartScroll { + /** + * * Sets the scroll target. + * * Adds the scroll prevention event listener. + * * Sets the property update function. + * @param {string} tweenProp the property name + */ + constructor(tweenProp: string); + element: HTMLElement | undefined; + } + /** + * Removes the scroll prevention event listener. + */ + export function onCompleteScroll(): void; + export const scrollContainer: HTMLElement; + export default ScrollPropertyBase; + namespace ScrollPropertyBase { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartScroll as onStart }; + export { onCompleteScroll as onComplete }; + } + namespace Util { + export { preventScroll }; + export { scrollIn }; + export { scrollOut }; + export { getScrollTargets }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/scrollProperty" { + export default ScrollProperty; + namespace ScrollProperty { + export const component: string; + export const property: string; + export const defaultValue: number; + export namespace Interpolate { + export { numbers }; + } + export { scrollFunctions as functions }; + export namespace Util { + export { preventScroll }; + export { scrollIn }; + export { scrollOut }; + export { getScrollTargets }; + export { toggleScrollEvents }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace scrollFunctions { + export { getScroll as prepareStart }; + export { prepareScroll as prepareProperty }; + export { onStartScroll as onStart }; + export { onCompleteScroll as onComplete }; + } + import { preventScroll } from "kute.js/src/components/scrollPropertyBase"; + import { scrollIn } from "kute.js/src/components/scrollPropertyBase"; + import { scrollOut } from "kute.js/src/components/scrollPropertyBase"; + import { getScrollTargets } from "kute.js/src/components/scrollPropertyBase"; + import { toggleScrollEvents } from "kute.js/src/components/scrollPropertyBase"; + /** + * Returns the current property computed style. + * @returns {number} computed style for property + */ + function getScroll(): number; + class getScroll { + element: HTMLElement | undefined; + } + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {string} value the property value + * @returns {number} the property tween object + */ + function prepareScroll(_: string, value: string): number; + import { onStartScroll } from "kute.js/src/components/scrollPropertyBase"; + import { onCompleteScroll } from "kute.js/src/components/scrollPropertyBase"; +} +declare module "kute.js/src/components/shadowPropertiesBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartShadow(tweenProp: string): void; + export default ShadowPropertiesBase; + namespace ShadowPropertiesBase { + const component: string; + namespace Interpolate { + export { numbers }; + export { colors }; + } + namespace functions { + export { shadowPropOnStart as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + const shadowPropOnStart: {}; +} +declare module "kute.js/src/components/shadowProperties" { + /** + * Returns the current property computed style. + * @param {string} tweenProp the property name + * @returns {string} computed style for property + */ + export function getShadow(tweenProp: string): string; + /** + * 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: string, propValue: string): KUTE.shadowObject; + export default ShadowProperties; + namespace ShadowProperties { + export const component: string; + export { shadowProps as properties }; + export namespace defaultValues { + const boxShadow: string; + const textShadow: string; + } + export namespace Interpolate { + export { numbers }; + export { colors }; + } + export { shadowFunctions as functions }; + export namespace Util { + export { processShadowArray }; + export { trueColor }; + } + } + const shadowProps: string[]; + import numbers from "kute.js/src/interpolation/numbers"; + import colors from "kute.js/src/interpolation/colors"; + namespace shadowFunctions { + export { getShadow as prepareStart }; + export { prepareShadow as prepareProperty }; + export { shadowPropOnStart as onStart }; + } + /** + * 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: (number | string)[], tweenProp: string): KUTE.shadowObject; + import trueColor from "kute.js/src/util/trueColor"; + const shadowPropOnStart: {}; +} +declare module "kute.js/src/components/svgCubicMorphBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the `path` property + */ + export function onStartCubicMorph(tweenProp: string): void; + export default baseSvgCubicMorph; + namespace baseSvgCubicMorph { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + export { pathToString }; + } + namespace functions { + export { onStartCubicMorph as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + import pathToString from "svg-path-commander/src/convert/pathToString"; +} +declare module "kute.js/src/util/selector" { + /** + * selector + * + * A selector utility for KUTE.js. + * + * @param {KUTE.selectorType} el target(s) or string selector + * @param {boolean | number} multi when true returns an array/collection of elements + * @returns {Element | Element[] | null} + */ + export default function selector(el: KUTE.selectorType, multi: boolean | number): Element | Element[] | null; +} +declare module "kute.js/src/components/svgCubicMorph" { + export default svgCubicMorph; + namespace svgCubicMorph { + export const component: string; + export const property: string; + export const defaultValue: never[]; + export namespace Interpolate { + export { numbers }; + export { pathToString }; + } + export { svgCubicMorphFunctions as functions }; + export namespace Util { + export { pathToCurve }; + export { pathToAbsolute }; + export { pathToString }; + export { parsePathString }; + export { getRotatedCurve }; + export { getRotations }; + export { equalizeSegments }; + export { reverseCurve }; + export { clonePath }; + export { getDrawDirection }; + export { segmentCubicFactory }; + export { splitCubic }; + export { splitPath }; + export { fixPath }; + export { getCurveArray }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + import pathToString from "svg-path-commander/src/convert/pathToString"; + namespace svgCubicMorphFunctions { + export { getCubicMorph as prepareStart }; + export { prepareCubicMorph as prepareProperty }; + export { onStartCubicMorph as onStart }; + export { crossCheckCubicMorph as crossCheck }; + } + import pathToCurve from "svg-path-commander/src/convert/pathToCurve"; + import pathToAbsolute from "svg-path-commander/src/convert/pathToAbsolute"; + import parsePathString from "svg-path-commander/src/parser/parsePathString"; + /** + * 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: import("svg-path-commander").curveArray, b: import("svg-path-commander").curveArray): import("svg-path-commander").curveArray; + /** + * Returns all possible path rotations for `curveArray`. + * @param {SVGPathCommander.curveArray} a the source `curveArray` + * @returns {SVGPathCommander.curveArray[]} all rotations for source + */ + function getRotations(a: import("svg-path-commander").curveArray): import("svg-path-commander").curveArray[]; + /** + * 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: import("svg-path-commander").curveArray, path2: import("svg-path-commander").curveArray, TL: number): import("svg-path-commander").curveArray[]; + import reverseCurve from "svg-path-commander/src/process/reverseCurve"; + import clonePath from "svg-path-commander/src/process/clonePath"; + import getDrawDirection from "svg-path-commander/src/util/getDrawDirection"; + import segmentCubicFactory from "svg-path-commander/src/util/segmentCubicFactory"; + 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"; + /** + * 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: import("svg-path-commander").pathArray | string): KUTE.curveSpecs[]; + /** + * Returns the current `d` attribute value. + * @returns {string} + */ + function getCubicMorph(): string; + /** + * 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(_: string, value: string | KUTE.curveObject): KUTE.curveObject; + import { onStartCubicMorph } from "kute.js/src/components/svgCubicMorphBase"; + /** + * 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: string): void; +} +declare module "kute.js/src/components/svgDrawBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartDraw(tweenProp: string): void; + export default SvgDrawBase; + namespace SvgDrawBase { + const component: string; + const property: string; + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartDraw as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/svgDraw" { + export default SvgDrawProperty; + namespace SvgDrawProperty { + export const component: string; + export const property: string; + export const defaultValue: string; + export namespace Interpolate { + export { numbers }; + } + export { svgDrawFunctions as functions }; + export namespace Util { + export { getRectLength }; + export { getPolyLength }; + export { getLineLength }; + export { getCircleLength }; + export { getEllipseLength }; + export { getTotalLength }; + export { resetDraw }; + export { getDraw }; + export { percent }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; + namespace svgDrawFunctions { + export { getDrawValue as prepareStart }; + export { prepareDraw as prepareProperty }; + export { onStartDraw as onStart }; + } + /** + * Returns the `` 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 `` length + */ + function getRectLength(el: SVGRectElement): number; + /** + * Returns the `` / `` length. + * @param {SVGPolylineElement | SVGPolygonElement} el target element + * @returns {number} the element length + */ + function getPolyLength(el: SVGPolylineElement | SVGPolygonElement): number; + /** + * Returns the `` length. + * @param {SVGLineElement} el target element + * @returns {number} the element length + */ + function getLineLength(el: SVGLineElement): number; + /** + * Returns the `` length. + * @param {SVGCircleElement} el target element + * @returns {number} the element length + */ + function getCircleLength(el: SVGCircleElement): number; + /** + * Returns the `` length. + * @param {SVGEllipseElement} el target element + * @returns {number} the element length + */ + function getEllipseLength(el: SVGEllipseElement): number; + /** + * Returns the shape length. + * @param {SVGPathCommander.shapeTypes} el target element + * @returns {number} the element length + */ + function getTotalLength(el: SVGPathCommander.shapeTypes): number; + /** + * Reset CSS properties associated with the `draw` property. + * @param {SVGPathCommander.shapeTypes} element target + */ + function resetDraw(elem: any): void; + /** + * 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: SVGPathCommander.shapeTypes, value: string | KUTE.drawObject): KUTE.drawObject; + /** + * Convert a `` length percent value to absolute. + * @param {string} v raw value + * @param {number} l length value + * @returns {number} the absolute value + */ + function percent(v: string, l: number): number; + /** + * Returns the property tween object. + * @returns {KUTE.drawObject} the property tween object + */ + function getDrawValue(): KUTE.drawObject; + /** + * 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(_: string, value: string | KUTE.drawObject): KUTE.drawObject; + import { onStartDraw } from "kute.js/src/components/svgDrawBase"; +} +declare module "kute.js/src/interpolation/coords" { + /** + * Coordinates Interpolation Function. + * + * @param {number[][]} a start coordinates + * @param {number[][]} b end coordinates + * @param {string} l amount of coordinates + * @param {number} v progress + * @returns {number[][]} the interpolated coordinates + */ + export default function coords(a: number[][], b: number[][], l: string, v: number): number[][]; +} +declare module "kute.js/src/components/svgMorphBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartSVGMorph(tweenProp: string): void; + export default SVGMorphBase; + namespace SVGMorphBase { + export const component: string; + export const property: string; + export { coords as Interpolate }; + export namespace functions { + export { onStartSVGMorph as onStart }; + } + } + import coords from "kute.js/src/interpolation/coords"; +} +declare module "kute.js/src/components/svgMorph" { + export default SVGMorph; + namespace SVGMorph { + export const component: string; + export const property: string; + export const defaultValue: never[]; + export { coords as Interpolate }; + export namespace defaultOptions { + const morphPrecision: number; + } + export { svgMorphFunctions as functions }; + export namespace Util { + export { addPoints }; + export { bisect }; + export { getPolygon }; + export { validPolygon }; + export { getInterpolationPoints }; + export { pathStringToPolygon }; + export { distanceSquareRoot }; + export { midPoint }; + export { approximatePolygon }; + export { rotatePolygon }; + export { pathToString }; + export { pathToCurve }; + export { getTotalLength }; + export { getPointAtLength }; + export { polygonArea }; + export { roundPath }; + } + } + import coords from "kute.js/src/interpolation/coords"; + namespace svgMorphFunctions { + export { getSVGMorph as prepareStart }; + export { prepareSVGMorph as prepareProperty }; + export { onStartSVGMorph as onStart }; + export { crossCheckSVGMorph as crossCheck }; + } + /** + * 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: KUTE.polygonObject, numPoints: number): void; + /** + * 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: number[][], maxSegmentLength?: number): void; + /** + * 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: import("kute.js/types").polygonMorph | string, maxSegmentLength: number): import("kute.js/types").polygonMorph; + /** + * Checks the validity of a polygon. + * @param {KUTE.polygonMorph} polygon the target polygon + * @returns {boolean} the result of the check + */ + function validPolygon(polygon: import("kute.js/types").polygonMorph): boolean; + /** + * 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: string, path2: string, precision: number): import("kute.js/types").polygonMorph[]; + /** + * 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: string, maxLength: number): KUTE.exactPolygon; + import distanceSquareRoot from "svg-path-commander/src/math/distanceSquareRoot"; + import midPoint from "svg-path-commander/src/math/midPoint"; + /** + * 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: import("svg-path-commander").pathArray, maxLength: number): KUTE.exactPolygon; + /** + * 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: import("kute.js/types").polygonMorph, vs: import("kute.js/types").polygonMorph): void; + import pathToString from "svg-path-commander/src/convert/pathToString"; + import pathToCurve from "svg-path-commander/src/convert/pathToCurve"; + import getTotalLength from "svg-path-commander/src/util/getTotalLength"; + import getPointAtLength from "svg-path-commander/src/util/getPointAtLength"; + import polygonArea from "svg-path-commander/src/math/polygonArea"; + import roundPath from "svg-path-commander/src/process/roundPath"; + /** + * Returns the current `d` attribute value. + * @returns {string} the `d` attribute value + */ + function getSVGMorph(): string; + /** + * 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(_: string, value: string | KUTE.polygonObject): KUTE.polygonObject; + import { onStartSVGMorph } from "kute.js/src/components/svgMorphBase"; + /** + * Enables the `to()` method by preparing the tween object in advance. + * @param {string} prop the `path` property name + */ + function crossCheckSVGMorph(prop: string): void; + /** + * 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: import("svg-path-commander").pathArray): KUTE.exactPolygon | false; +} +declare module "kute.js/src/components/svgTransformBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function svgTransformOnStart(tweenProp: string): void; + export default baseSVGTransform; + namespace baseSVGTransform { + const component: string; + const property: string; + namespace defaultOptions { + const transformOrigin: string; + } + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { svgTransformOnStart as onStart }; + } + } + import numbers from "kute.js/src/interpolation/numbers"; +} +declare module "kute.js/src/components/svgTransform" { + export namespace svgTransformFunctions { + export { getStartSvgTransform as prepareStart }; + export { prepareSvgTransform as prepareProperty }; + export { svgTransformOnStart as onStart }; + export { svgTransformCrossCheck as crossCheck }; + } + export namespace svgTransform { + export const component: string; + export const property: string; + export namespace defaultOptions { + const transformOrigin: string; + } + export namespace defaultValue { + const translate: number; + const rotate: number; + const skewX: number; + const skewY: number; + const scale: number; + } + export namespace Interpolate { + export { numbers }; + } + export { svgTransformFunctions as functions }; + export namespace Util { + export { parseStringOrigin }; + export { parseTransformString }; + export { parseTransformSVG }; + } + } + export default svgTransform; + /** + * 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(_: string, value: string): string; + /** + * 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: string, value: string): KUTE.transformSVGObject; + import { svgTransformOnStart } from "kute.js/src/components/svgTransformBase"; + function svgTransformCrossCheck(prop: any): void; + import numbers from "kute.js/src/interpolation/numbers"; + /** + * 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: string, bbox: SVGPathCommander.pathBBox): number; + /** + * Parse SVG transform string and return an object. + * @param {string} a transform string + * @returns {Object} + */ + function parseTransformString(a: string): { + [x: string]: (string | number); + }; + /** + * Returns the SVG transform tween object. + * @param {string} _ property name + * @param {Object} v property value object + * @returns {KUTE.transformSVGObject} the SVG transform tween object + */ + function parseTransformSVG(_: string, v: { + [x: string]: (string | number); + }): KUTE.transformSVGObject; +} +declare module "kute.js/src/components/textPropertiesBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function textPropOnStart(tweenProp: string): void; + export default TextPropertiesBase; + namespace TextPropertiesBase { + const component: string; + const category: string; + namespace Interpolate { + export { units }; + } + namespace functions { + export { textOnStart as onStart }; + } + } + import units from "kute.js/src/interpolation/units"; + const textOnStart: {}; +} +declare module "kute.js/src/components/textProperties" { + /** + * Returns the current property computed style. + * @param {string} prop the property name + * @returns {string} computed style for property + */ + export function getTextProp(prop: string): string; + /** + * 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(_: string, value: string): number; + export default TextProperties; + namespace TextProperties { + export const component: string; + export const category: string; + export { textProps as properties }; + export namespace defaultValues { + const fontSize: number; + const lineHeight: number; + const letterSpacing: number; + const wordSpacing: number; + } + export namespace Interpolate { + export { units }; + } + export { textPropFunctions as functions }; + export namespace Util { + export { trueDimension }; + } + } + const textProps: string[]; + import units from "kute.js/src/interpolation/units"; + namespace textPropFunctions { + export { getTextProp as prepareStart }; + export { prepareTextProp as prepareProperty }; + export { textOnStart as onStart }; + } + import trueDimension from "kute.js/src/util/trueDimension"; + const textOnStart: {}; +} +declare module "kute.js/src/objects/connect" { + export default connect; + namespace connect { + const tween: KUTE.TweenBase | KUTE.Tween | KUTE.TweenExtra; + const processEasing: any; + } +} +declare module "kute.js/src/components/textWriteBase" { + export namespace onStartWrite { + /** + * onStartWrite.text + * + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function text(tweenProp: string): void; + /** + * onStartWrite.text + * + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function text(tweenProp: string): void; + /** + * onStartWrite.number + * + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function number(tweenProp: string): void; + /** + * onStartWrite.number + * + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function number(tweenProp: string): void; + } + export namespace TextWriteBase { + const component: string; + const category: string; + namespace defaultOptions { + const textChars: string; + } + namespace Interpolate { + export { numbers }; + } + namespace functions { + export { onStartWrite as onStart }; + } + namespace Util { + export { charSet }; + } + } + export default TextWriteBase; + export namespace charSet { + export { lowerCaseAlpha as alpha }; + export { upperCaseAlpha as upper }; + export { nonAlpha as symbols }; + export { numeric }; + export { alphaNumeric as alphanumeric }; + export { allTypes as all }; + } + import numbers from "kute.js/src/interpolation/numbers"; + const lowerCaseAlpha: string[]; + const upperCaseAlpha: string[]; + const nonAlpha: string[]; + const numeric: string[]; + const alphaNumeric: string[]; + const allTypes: string[]; +} +declare module "kute.js/src/components/textWrite" { + export function createTextTweens(target: any, newText: any, ops: any): false | any[]; + export namespace textWriteFunctions { + export { getWrite as prepareStart }; + export { prepareText as prepareProperty }; + export { onStartWrite as onStart }; + } + export namespace TextWrite { + export const component: string; + export const category: string; + export const properties: string[]; + export namespace defaultValues { + const text: string; + const number: string; + } + export namespace defaultOptions { + const textChars: string; + } + export namespace Interpolate { + export { numbers }; + } + export { textWriteFunctions as functions }; + export namespace Util { + export { charSet }; + export { createTextTweens }; + } + } + export default TextWrite; + /** + * Returns the current element `innerHTML`. + * @returns {string} computed style for property + */ + function getWrite(): string; + /** + * 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: string, value: string): number | string; + import { onStartWrite } from "kute.js/src/components/textWriteBase"; + import numbers from "kute.js/src/interpolation/numbers"; + import { charSet } from "kute.js/src/components/textWriteBase"; +} +declare module "kute.js/src/interpolation/perspective" { + /** + * Perspective Interpolation Function. + * + * @param {number} a start value + * @param {number} b end value + * @param {string} u unit + * @param {number} v progress + * @returns {string} the perspective function in string format + */ + export default function perspective(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/interpolation/translate3d" { + /** + * Translate 3D Interpolation Function. + * + * @param {number[]} a start [x,y,z] position + * @param {number[]} b end [x,y,z] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D translation string + */ + export default function translate3d(a: number[], b: number[], u: string, v: number): string; +} +declare module "kute.js/src/interpolation/rotate3d" { + /** + * 3D Rotation Interpolation Function. + * + * @param {number} a start [x,y,z] angles + * @param {number} b end [x,y,z] angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated 3D rotation string + */ + export default function rotate3d(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/interpolation/translate" { + /** + * Translate 2D Interpolation Function. + * + * @param {number[]} a start [x,y] position + * @param {number[]} b end [x,y] position + * @param {string} u unit, usually `px` degrees + * @param {number} v progress + * @returns {string} the interpolated 2D translation string + */ + export default function translate(a: number[], b: number[], u: string, v: number): string; +} +declare module "kute.js/src/interpolation/rotate" { + /** + * 2D Rotation Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated rotation + */ + export default function rotate(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/interpolation/scale" { + /** + * Scale Interpolation Function. + * + * @param {number} a start scale + * @param {number} b end scale + * @param {number} v progress + * @returns {string} the interpolated scale + */ + export default function scale(a: number, b: number, v: number): string; +} +declare module "kute.js/src/interpolation/skew" { + /** + * Skew Interpolation Function. + * + * @param {number} a start {x,y} angles + * @param {number} b end {x,y} angles + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated string value of skew(s) + */ + export default function skew(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/components/transformFunctionsBase" { + /** + * Sets the property update function. + * * same to svgTransform, htmlAttributes + * @param {string} tweenProp the property name + */ + export function onStartTransform(tweenProp: string): void; + export default TransformFunctionsBase; + namespace TransformFunctionsBase { + const component: string; + const property: string; + namespace functions { + export { onStartTransform as onStart }; + } + namespace Interpolate { + export { perspective }; + export { translate3d }; + export { rotate3d }; + export { translate }; + export { rotate }; + export { scale }; + export { skew }; + } + } + import perspective from "kute.js/src/interpolation/perspective"; + import translate3d from "kute.js/src/interpolation/translate3d"; + import rotate3d from "kute.js/src/interpolation/rotate3d"; + import translate from "kute.js/src/interpolation/translate"; + import rotate from "kute.js/src/interpolation/rotate"; + import scale from "kute.js/src/interpolation/scale"; + import skew from "kute.js/src/interpolation/skew"; +} +declare module "kute.js/src/components/transformFunctions" { + export default TransformFunctions; + namespace TransformFunctions { + export const component: string; + export const property: string; + export { supportedTransformProperties as subProperties }; + export { defaultTransformValues as defaultValues }; + export { transformFunctions as functions }; + export namespace Interpolate { + export { perspective }; + export { translate3d }; + export { rotate3d }; + export { translate }; + export { rotate }; + export { scale }; + export { skew }; + } + } + const supportedTransformProperties: string[]; + namespace defaultTransformValues { + const perspective_1: number; + export { perspective_1 as perspective }; + const translate3d_1: number[]; + export { translate3d_1 as translate3d }; + export const translateX: number; + export const translateY: number; + export const translateZ: number; + const translate_1: number[]; + export { translate_1 as translate }; + const rotate3d_1: number[]; + export { rotate3d_1 as rotate3d }; + export const rotateX: number; + export const rotateY: number; + export const rotateZ: number; + const rotate_1: number; + export { rotate_1 as rotate }; + export const skewX: number; + export const skewY: number; + const skew_1: number[]; + export { skew_1 as skew }; + const scale_1: number; + export { scale_1 as scale }; + } + namespace transformFunctions { + export { getTransform as prepareStart }; + export { prepareTransform as prepareProperty }; + export { onStartTransform as onStart }; + export { crossCheckTransform as crossCheck }; + } + import perspective from "kute.js/src/interpolation/perspective"; + import translate3d from "kute.js/src/interpolation/translate3d"; + import rotate3d from "kute.js/src/interpolation/rotate3d"; + import translate from "kute.js/src/interpolation/translate"; + import rotate from "kute.js/src/interpolation/rotate"; + import scale from "kute.js/src/interpolation/scale"; + import skew from "kute.js/src/interpolation/skew"; + /** + * Returns the current property inline style. + * @param {string} tweenProp the property name + * @returns {string} inline style for property + */ + function getTransform(tweenProp: string): string; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {Object} obj the property value + * @returns {KUTE.transformFObject} the property tween object + */ + function prepareTransform(_: string, obj: { + [x: string]: string | number | (string | number)[]; + }): KUTE.transformFObject; + import { onStartTransform } from "kute.js/src/components/transformFunctionsBase"; + /** + * Prepare tween object in advance for `to()` method. + * @param {string} tweenProp the property name + */ + function crossCheckTransform(tweenProp: string): void; +} +declare module "kute.js/src/util/transformProperty" { + export default transformProperty; + /** the `transform` string for legacy browsers */ + const transformProperty: string; +} +declare module "kute.js/src/process/getInlineStyleLegacy" { + /** + * getInlineStyle + * + * Returns the transform style for element from cssText. + * Used by for the `.to()` static method on legacy browsers. + * + * @param {Element} el target element + * @returns {object} a transform object + */ + export default function getInlineStyleLegacy(el: Element): object; +} +declare module "kute.js/src/util/supportLegacyTransform" { + export default supportTransform; + /** check if transform is supported via prefixed property */ + const supportTransform: boolean; +} +declare module "kute.js/src/components/transformLegacyBase" { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + export function onStartLegacyTransform(tweenProp: string): void; + export default BaseLegacyTransform; + namespace BaseLegacyTransform { + const component: string; + const property: string; + namespace functions { + export { onStartLegacyTransform as onStart }; + } + namespace Interpolate { + export { perspective }; + export { translate3d }; + export { rotate3d }; + export { translate }; + export { rotate }; + export { scale }; + export { skew }; + } + namespace Util { + export { transformProperty }; + } + } + import perspective from "kute.js/src/interpolation/perspective"; + import translate3d from "kute.js/src/interpolation/translate3d"; + import rotate3d from "kute.js/src/interpolation/rotate3d"; + import translate from "kute.js/src/interpolation/translate"; + import rotate from "kute.js/src/interpolation/rotate"; + import scale from "kute.js/src/interpolation/scale"; + import skew from "kute.js/src/interpolation/skew"; + import transformProperty from "kute.js/src/util/transformProperty"; +} +declare module "kute.js/src/components/transformLegacy" { + export default transformLegacyComponent; + namespace transformLegacyComponent { + export const component: string; + export const property: string; + export { legacyTransformProperties as subProperties }; + export { legacyTransformValues as defaultValues }; + export { transformLegacyFunctions as functions }; + export namespace Interpolate { + export { perspective }; + export { translate3d }; + export { rotate3d }; + export { translate }; + export { rotate }; + export { scale }; + export { skew }; + } + export const Util: string[]; + } + const legacyTransformProperties: string[]; + namespace legacyTransformValues { + const perspective_1: number; + export { perspective_1 as perspective }; + const translate3d_1: number[]; + export { translate3d_1 as translate3d }; + export const translateX: number; + export const translateY: number; + export const translateZ: number; + const translate_1: number[]; + export { translate_1 as translate }; + const rotate3d_1: number[]; + export { rotate3d_1 as rotate3d }; + export const rotateX: number; + export const rotateY: number; + export const rotateZ: number; + const rotate_1: number; + export { rotate_1 as rotate }; + export const skewX: number; + export const skewY: number; + const skew_1: number[]; + export { skew_1 as skew }; + const scale_1: number; + export { scale_1 as scale }; + } + namespace transformLegacyFunctions { + export { getLegacyTransform as prepareStart }; + export { prepareLegacyTransform as prepareProperty }; + export { onStartLegacyTransform as onStart }; + export { crossCheckLegacyTransform as crossCheck }; + } + import perspective from "kute.js/src/interpolation/perspective"; + import translate3d from "kute.js/src/interpolation/translate3d"; + import rotate3d from "kute.js/src/interpolation/rotate3d"; + import translate from "kute.js/src/interpolation/translate"; + import rotate from "kute.js/src/interpolation/rotate"; + import scale from "kute.js/src/interpolation/scale"; + import skew from "kute.js/src/interpolation/skew"; + /** + * Returns the current property inline style. + * @param {string} tweenProperty the property name + * @returns {string} inline style for property + */ + function getLegacyTransform(tweenProperty: string): string; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {Object} obj the property value + * @returns {KUTE.transformFObject} the property tween object + */ + function prepareLegacyTransform(_: string, obj: { + [x: string]: string | number | (string | number)[]; + }): KUTE.transformFObject; + import { onStartLegacyTransform } from "kute.js/src/components/transformLegacyBase"; + /** + * Prepare tween object in advance for `to()` method. + * @param {string} tweenProp the property name + */ + function crossCheckLegacyTransform(tweenProp: string): void; +} +declare module "kute.js/src/interpolation/arrays" { + /** + * Array Interpolation Function. + * + * @param {number[]} a start array + * @param {number[]} b end array + * @param {number} v progress + * @returns {number[]} the resulting array + */ + export default function arrays(a: number[], b: number[], v: number): number[]; +} +declare module "kute.js/src/components/transformMatrixBase" { + export namespace onStartTransform { + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function transform(tweenProp: string): void; + /** + * Sets the property update function. + * @param {string} tweenProp the property name + */ + function transform(tweenProp: string): void; + /** + * onStartTransform.CSS3Matrix + * + * Sets the update function for the property. + * @param {string} prop the property name + */ + function CSS3Matrix(prop: string): void; + /** + * onStartTransform.CSS3Matrix + * + * Sets the update function for the property. + * @param {string} prop the property name + */ + function CSS3Matrix(prop: string): void; + } + export namespace TransformMatrixBase { + export { matrixComponent as component }; + export const property: string; + export namespace functions { + export { onStartTransform as onStart }; + } + export namespace Interpolate { + export { numbers as perspective }; + export { arrays as translate3d }; + export { arrays as rotate3d }; + export { arrays as skew }; + export { arrays as scale3d }; + } + } + export default TransformMatrixBase; + const matrixComponent: "transformMatrixBase"; + import numbers from "kute.js/src/interpolation/numbers"; + import arrays from "kute.js/src/interpolation/arrays"; +} +declare module "kute.js/src/components/transformMatrix" { + export default matrixTransform; + namespace matrixTransform { + export { matrixComponent as component }; + export const property: string; + export namespace defaultValue { + const perspective: number; + const translate3d: number[]; + const translateX: number; + const translateY: number; + const translateZ: number; + const rotate3d: number[]; + const rotateX: number; + const rotateY: number; + const rotateZ: number; + const skew: number[]; + const skewX: number; + const skewY: number; + const scale3d: number[]; + const scaleX: number; + const scaleY: number; + const scaleZ: number; + } + export { matrixFunctions as functions }; + export namespace Interpolate { + export { numbers as perspective }; + export { arrays as translate3d }; + export { arrays as rotate3d }; + export { arrays as skew }; + export { arrays as scale3d }; + } + } + const matrixComponent: "transformMatrix"; + namespace matrixFunctions { + export { getTransform as prepareStart }; + export { prepareTransform as prepareProperty }; + export { onStartTransform as onStart }; + export { onCompleteTransform as onComplete }; + export { crossCheckTransform as crossCheck }; + } + import numbers from "kute.js/src/interpolation/numbers"; + import arrays from "kute.js/src/interpolation/arrays"; + /** + * Returns the current transform object. + * @param {string} _ the property name + * @param {string} value the property value + * @returns {KUTE.transformMObject} transform object + */ + function getTransform(_: string, value: string): KUTE.transformMObject; + /** + * Returns the property tween object. + * @param {string} _ the property name + * @param {Object} obj the property value + * @returns {KUTE.transformMObject} the property tween object + */ + function prepareTransform(_: string, value: any): KUTE.transformMObject; + import { onStartTransform } from "kute.js/src/components/transformMatrixBase"; + /** + * Sets the end values for the next `to()` method call. + * @param {string} tweenProp the property name + */ + function onCompleteTransform(tweenProp: string): void; + /** + * Prepare tween object in advance for `to()` method. + * @param {string} tweenProp the property name + */ + function crossCheckTransform(tweenProp: string): void; +} +declare module "kute.js/src/objects/tweens" { + export default Tweens; + const Tweens: any[]; +} +declare module "kute.js/src/core/add" { + export default add; + /** + * KUTE.add(Tween) + * + * @param {KUTE.Tween} tw a new tween to add + */ + function add(tw: KUTE.Tween): number; +} +declare module "kute.js/src/core/getAll" { + export default getAll; + /** + * KUTE.add(Tween) + * + * @return {KUTE.Tween[]} tw a new tween to add + */ + function getAll(): KUTE.Tween[]; +} +declare module "kute.js/src/core/remove" { + export default remove; + /** + * KUTE.remove(Tween) + * + * @param {KUTE.Tween} tw a new tween to add + */ + function remove(tw: KUTE.Tween): void; +} +declare module "kute.js/src/core/removeAll" { + export default removeAll; + /** + * KUTE.removeAll() + */ + function removeAll(): void; +} +declare module "kute.js/src/objects/globalObject" { + export default globalObject; + const globalObject: {}; +} +declare module "kute.js/src/util/now" { + export default now; + function now(): number; +} +declare module "kute.js/src/core/render" { + export function stop(): void; + export default Render; + export let Tick: number; + /** + * + * @param {number | Date} time + */ + export function Ticker(time: number | Date): void; + namespace Render { + export { Tick }; + export { Ticker }; + export { Tweens }; + export { Time }; + } + import Tweens from "kute.js/src/objects/tweens"; + namespace Time { + export { now }; + } + import now from "kute.js/src/util/now"; +} +declare module "kute.js/src/core/linkInterpolation" { + /** + * linkInterpolation + * @this {KUTE.Tween} + */ + export default function linkInterpolation(): void; +} +declare module "kute.js/src/core/internals" { + export default internals; + namespace internals { + export { add }; + export { remove }; + export { getAll }; + export { removeAll }; + export { stop }; + export { linkInterpolation }; + } + import add from "kute.js/src/core/add"; + import remove from "kute.js/src/core/remove"; + import getAll from "kute.js/src/core/getAll"; + import removeAll from "kute.js/src/core/removeAll"; + import { stop } from "kute.js/src/core/render"; + import linkInterpolation from "kute.js/src/core/linkInterpolation"; +} +declare module "kute.js/src/core/queueStart" { + export default function queueStart(): void; +} +declare module "kute.js/src/easing/easing-base" { + export default Easing; + namespace Easing { + const linear: KUTE.easingFunction; + const easingQuadraticIn: KUTE.easingFunction; + const easingQuadraticOut: KUTE.easingFunction; + const easingQuadraticInOut: KUTE.easingFunction; + const easingCubicIn: KUTE.easingFunction; + const easingCubicOut: KUTE.easingFunction; + const easingCubicInOut: KUTE.easingFunction; + const easingCircularIn: KUTE.easingFunction; + const easingCircularOut: KUTE.easingFunction; + const easingCircularInOut: KUTE.easingFunction; + const easingBackIn: KUTE.easingFunction; + const easingBackOut: KUTE.easingFunction; + const easingBackInOut: KUTE.easingFunction; + } +} +declare module "kute.js/src/easing/easing-bezier" { + export default Easing; + namespace Easing { + const linear: CubicBezier; + const easingSinusoidalIn: CubicBezier; + const easingSinusoidalOut: CubicBezier; + const easingSinusoidalInOut: CubicBezier; + const easingQuadraticIn: CubicBezier; + const easingQuadraticOut: CubicBezier; + const easingQuadraticInOut: CubicBezier; + const easingCubicIn: CubicBezier; + const easingCubicOut: CubicBezier; + const easingCubicInOut: CubicBezier; + const easingQuarticIn: CubicBezier; + const easingQuarticOut: CubicBezier; + const easingQuarticInOut: CubicBezier; + const easingQuinticIn: CubicBezier; + const easingQuinticOut: CubicBezier; + const easingQuinticInOut: CubicBezier; + const easingExponentialIn: CubicBezier; + const easingExponentialOut: CubicBezier; + const easingExponentialInOut: CubicBezier; + const easingCircularIn: CubicBezier; + const easingCircularOut: CubicBezier; + const easingCircularInOut: CubicBezier; + const easingBackIn: CubicBezier; + const easingBackOut: CubicBezier; + const easingBackInOut: CubicBezier; + } + import CubicBezier from "cubic-bezier-easing"; +} +declare module "kute.js/src/easing/easing" { + export default Easing; + namespace Easing { + const linear: KUTE.easingFunction; + const easingSinusoidalIn: KUTE.easingFunction; + const easingSinusoidalOut: KUTE.easingFunction; + const easingSinusoidalInOut: KUTE.easingFunction; + const easingQuadraticIn: KUTE.easingFunction; + const easingQuadraticOut: KUTE.easingFunction; + const easingQuadraticInOut: KUTE.easingFunction; + const easingCubicIn: KUTE.easingFunction; + const easingCubicOut: KUTE.easingFunction; + const easingCubicInOut: KUTE.easingFunction; + const easingQuarticIn: KUTE.easingFunction; + const easingQuarticOut: KUTE.easingFunction; + const easingQuarticInOut: KUTE.easingFunction; + const easingQuinticIn: KUTE.easingFunction; + const easingQuinticOut: KUTE.easingFunction; + const easingQuinticInOut: KUTE.easingFunction; + const easingCircularIn: KUTE.easingFunction; + const easingCircularOut: KUTE.easingFunction; + const easingCircularInOut: KUTE.easingFunction; + const easingExponentialIn: KUTE.easingFunction; + const easingExponentialOut: KUTE.easingFunction; + const easingExponentialInOut: KUTE.easingFunction; + const easingBackIn: KUTE.easingFunction; + const easingBackOut: KUTE.easingFunction; + const easingBackInOut: KUTE.easingFunction; + const easingElasticIn: KUTE.easingFunction; + const easingElasticOut: KUTE.easingFunction; + const easingElasticInOut: KUTE.easingFunction; + const easingBounceIn: KUTE.easingFunction; + const easingBounceOut: KUTE.easingFunction; + const easingBounceInOut: KUTE.easingFunction; + } +} +declare module "kute.js/src/tween/tweenCollection" { + /** + * The static method creates a new `Tween` object for each `HTMLElement` + * from and `Array`, `HTMLCollection` or `NodeList`. + */ + export default class TweenCollection { + /** + * + * @param {Element[] | HTMLCollection | NodeList} els target elements + * @param {KUTE.tweenProps} vS the start values + * @param {KUTE.tweenProps} vE the end values + * @param {KUTE.tweenOptions} Options tween options + * @returns {TweenCollection} the Tween object collection + */ + constructor(els: Element[] | HTMLCollection | NodeList, vS: import("kute.js/types").tweenProps, vE: import("kute.js/types").tweenProps, Options: KUTE.tweenOptions); + /** @type {KUTE.twCollection[]} */ + tweens: import("kute.js/types").twCollection[]; + /** @type {number?} */ + length: number | null; + /** + * Starts tweening, all targets + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + start(time: number | null): TweenCollection; + /** + * Stops tweening, all targets and their chains + * @returns {TweenCollection} this instance + */ + stop(): TweenCollection; + /** + * Pause tweening, all targets + * @returns {TweenCollection} this instance + */ + pause(): TweenCollection; + /** + * Resume tweening, all targets + * @returns {TweenCollection} this instance + */ + resume(): TweenCollection; + /** + * Schedule another tween or collection to start after + * this one is complete. + * @param {number?} args the tween start time + * @returns {TweenCollection} this instance + */ + chain(args: number | null): TweenCollection; + /** + * Check if any tween instance is playing + * @param {number?} time the tween start time + * @returns {TweenCollection} this instance + */ + playing(): TweenCollection; + /** + * Remove all tweens in the collection + */ + removeTweens(): void; + /** + * Returns the maximum animation duration + * @returns {number} this instance + */ + getMaxDuration(): number; + } +} +declare module "kute.js/src/interface/allFromTo" { + /** + * The `KUTE.allFromTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at a given state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {TweenCollection} the Tween object collection + */ + export default function allFromTo(elements: Element[] | HTMLCollection | NodeList, startObject: import("kute.js/types").tweenProps, endObject: import("kute.js/types").tweenProps, optionsObj: KUTE.tweenOptions): TweenCollection; + import TweenCollection from "kute.js/src/tween/tweenCollection"; +} +declare module "kute.js/src/interface/allTo" { + /** + * The `KUTE.allTo()` static method creates a new Tween object + * for multiple `HTMLElement`s, `HTMLCollection` or `NodeListat` + * at their current state. + * + * @param {Element[] | HTMLCollection | NodeList} elements target elements + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenProps} optionsObj progress + * @returns {TweenCollection} the Tween object collection + */ + export default function allTo(elements: Element[] | HTMLCollection | NodeList, endObject: import("kute.js/types").tweenProps, optionsObj: import("kute.js/types").tweenProps): TweenCollection; + import TweenCollection from "kute.js/src/tween/tweenCollection"; +} +declare module "kute.js/src/interface/fromTo" { + /** + * The `KUTE.fromTo()` static method returns a new Tween object + * for a single `HTMLElement` at a given state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} startObject + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ + export default function fromTo(element: Element, startObject: import("kute.js/types").tweenProps, endObject: import("kute.js/types").tweenProps, optionsObj: KUTE.tweenOptions): KUTE.Tween; +} +declare module "kute.js/src/interface/to" { + /** + * The `KUTE.to()` static method returns a new Tween object + * for a single `HTMLElement` at its current state. + * + * @param {Element} element target element + * @param {KUTE.tweenProps} endObject + * @param {KUTE.tweenOptions} optionsObj tween options + * @returns {KUTE.Tween} the resulting Tween object + */ + export default function to(element: Element, endObject: import("kute.js/types").tweenProps, optionsObj: KUTE.tweenOptions): KUTE.Tween; +} +declare module "kute.js/src/interpolation/skewX" { + /** + * SkewX Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated skewX + */ + export default function skewX(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/interpolation/skewY" { + /** + * SkewY Interpolation Function. + * + * @param {number} a start angle + * @param {number} b end angle + * @param {string} u unit, usually `deg` degrees + * @param {number} v progress + * @returns {string} the interpolated skewY + */ + export default function skewY(a: number, b: number, u: string, v: number): string; +} +declare module "kute.js/src/objects/componentsBase" { + export default Components; + namespace Components { + const Transform: Animation; + const BoxModel: Animation; + const Opacity: Animation; + } + import Animation from "kute.js/src/animation/animationBase"; +} +declare module "kute.js/src/objects/componentsDefault" { + export default Components; + namespace Components { + export { EssentialBoxModel }; + export { ColorsProperties }; + export { HTMLAttributes }; + export { OpacityProperty }; + export { TextWriteProp }; + export { TransformFunctions }; + export { SVGDraw }; + export { SVGMorph }; + } + import EssentialBoxModel from "kute.js/src/components/boxModelEssential"; + import ColorsProperties from "kute.js/src/components/colorProperties"; + import HTMLAttributes from "kute.js/src/components/htmlAttributes"; + import OpacityProperty from "kute.js/src/components/opacityProperty"; + import TextWriteProp from "kute.js/src/components/textWrite"; + import TransformFunctions from "kute.js/src/components/transformFunctions"; + import SVGDraw from "kute.js/src/components/svgDraw"; + import SVGMorph from "kute.js/src/components/svgMorph"; +} +declare module "kute.js/src/objects/componentsExtra" { + export default Components; + namespace Components { + export { BackgroundPosition }; + export { BorderRadius }; + export { BoxModel }; + export { ClipProperty }; + export { ColorProperties }; + export { FilterEffects }; + export { HTMLAttributes }; + export { OpacityProperty }; + export { SVGDraw }; + export { SVGCubicMorph }; + export { SVGTransform }; + export { ScrollProperty }; + export { ShadowProperties }; + export { TextProperties }; + export { TextWriteProperties }; + export { MatrixTransform }; + } + import BackgroundPosition from "kute.js/src/components/backgroundPosition"; + import BorderRadius from "kute.js/src/components/borderRadius"; + import BoxModel from "kute.js/src/components/boxModel"; + import ClipProperty from "kute.js/src/components/clipProperty"; + import ColorProperties from "kute.js/src/components/colorProperties"; + import FilterEffects from "kute.js/src/components/filterEffects"; + import HTMLAttributes from "kute.js/src/components/htmlAttributes"; + import OpacityProperty from "kute.js/src/components/opacityProperty"; + import SVGDraw from "kute.js/src/components/svgDraw"; + import SVGCubicMorph from "kute.js/src/components/svgCubicMorph"; + import SVGTransform from "kute.js/src/components/svgTransform"; + import ScrollProperty from "kute.js/src/components/scrollProperty"; + import ShadowProperties from "kute.js/src/components/shadowProperties"; + import TextProperties from "kute.js/src/components/textProperties"; + import TextWriteProperties from "kute.js/src/components/textWrite"; + import MatrixTransform from "kute.js/src/components/transformMatrix"; +} +declare module "kute.js/src/objects/objects" { + export default Objects; + namespace Objects { + export { supportedProperties }; + export { defaultValues }; + export { defaultOptions }; + export { prepareProperty }; + export { prepareStart }; + export { crossCheck }; + export { onStart }; + export { onComplete }; + export { linkProperty }; + } + import supportedProperties from "kute.js/src/objects/supportedProperties"; + import defaultValues from "kute.js/src/objects/defaultValues"; + import defaultOptions from "kute.js/src/objects/defaultOptions"; + import prepareProperty from "kute.js/src/objects/prepareProperty"; + import prepareStart from "kute.js/src/objects/prepareStart"; + import crossCheck from "kute.js/src/objects/crossCheck"; + import onStart from "kute.js/src/objects/onStart"; + import onComplete from "kute.js/src/objects/onComplete"; + import linkProperty from "kute.js/src/objects/linkProperty"; +} +declare module "kute.js/src/objects/objectsBase" { + export default Objects; + namespace Objects { + export { defaultOptions }; + export { linkProperty }; + export { onStart }; + export { onComplete }; + } + import defaultOptions from "kute.js/src/objects/defaultOptions"; + import linkProperty from "kute.js/src/objects/linkProperty"; + import onStart from "kute.js/src/objects/onStart"; + import onComplete from "kute.js/src/objects/onComplete"; +} +declare module "kute.js/src/process/prepareObject" { + /** + * prepareObject + * + * Returns all processed valuesStart / valuesEnd. + * + * @param {Element} obj the values start/end object + * @param {string} fn toggles between the two + */ + export default function prepareObject(obj: Element, fn: string): void; +} +declare module "kute.js/src/process/getStartValues" { + /** + * getStartValues + * + * Returns the start values for to() method. + * Used by for the `.to()` static method. + * + * @this {KUTE.Tween} the tween instance + */ + export default function getStartValues(): void; + export default class getStartValues { + valuesStart: {}; + } +} +declare module "kute.js/src/process/process" { + namespace _default { + export { getInlineStyle }; + export { getStyleForProperty }; + export { getStartValues }; + export { prepareObject }; + } + export default _default; + import getInlineStyle from "kute.js/src/process/getInlineStyle"; + import getStyleForProperty from "kute.js/src/process/getStyleForProperty"; + import getStartValues from "kute.js/src/process/getStartValues"; + import prepareObject from "kute.js/src/process/prepareObject"; +} +declare module "kute.js/src/tween/tweenBase" { + /** + * The `TweenBase` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * `TweenBase` is meant to be used with pre-processed values. + */ + export default class TweenBase { + /** + * @param {Element} targetElement the target element + * @param {KUTE.tweenProps} startObject the start values + * @param {KUTE.tweenProps} endObject the end values + * @param {KUTE.tweenOptions} opsObject the end values + * @returns {TweenBase} the resulting Tween object + */ + constructor(targetElement: Element, startObject: import("kute.js/types").tweenProps, endObject: import("kute.js/types").tweenProps, opsObject: KUTE.tweenOptions); + element: Element; + /** @type {boolean} */ + playing: boolean; + /** @type {number?} */ + _startTime: number | null; + /** @type {boolean} */ + _startFired: boolean; + valuesEnd: import("kute.js/types").tweenProps; + valuesStart: import("kute.js/types").tweenProps; + _resetStart: any; + /** @type {KUTE.easingOption} */ + _easing: KUTE.easingOption; + /** @type {number} */ + _duration: number; + /** @type {number} */ + _delay: number; + /** + * Starts tweening + * @param {number?} time the tween start time + * @returns {TweenBase} this instance + */ + start(time: number | null): TweenBase; + /** + * Stops tweening + * @returns {TweenBase} this instance + */ + stop(): TweenBase; + /** + * Trigger internal completion callbacks. + */ + close(): void; + /** + * Schedule another tween instance to start once this one completes. + * @param {KUTE.chainOption} args the tween animation start time + * @returns {TweenBase} this instance + */ + chain(args: KUTE.chainOption): TweenBase; + _chain: any; + /** + * Stop tweening the chained tween instances. + */ + stopChainedTweens(): void; + /** + * Update the tween on each tick. + * @param {number} time the tick time + * @returns {boolean} this instance + */ + update(time: number): boolean; + } +} +declare module "kute.js/src/tween/tween" { + /** + * The `KUTE.Tween()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor adds additional functionality and is the default + * Tween object constructor in KUTE.js. + */ + export default class Tween extends TweenBase { + /** @type {boolean} */ + paused: boolean; + /** @type {number?} */ + _pauseTime: number | null; + /** @type {number?} */ + _repeat: number | null; + /** @type {number?} */ + _repeatDelay: number | null; + /** @type {number?} */ + _repeatOption: number | null; + /** @type {KUTE.tweenProps} */ + valuesRepeat: import("kute.js/types").tweenProps; + /** @type {boolean} */ + _yoyo: boolean; + /** @type {boolean} */ + _reversed: boolean; + /** + * Resume tweening + * @returns {Tween} this instance + */ + resume(): Tween; + /** + * Pause tweening + * @returns {Tween} this instance + */ + pause(): Tween; + /** + * Reverses start values with end values + */ + reverse(): void; + } + import TweenBase from "kute.js/src/tween/tweenBase"; +} +declare module "kute.js/src/tween/tweenExtra" { + /** + * The `KUTE.TweenExtra()` constructor creates a new `Tween` object + * for a single `HTMLElement` and returns it. + * + * This constructor is intended for experiments or testing of new features. + */ + export default class TweenExtra extends Tween { + /** + * Method to add callbacks on the fly. + * @param {string} name callback name + * @param {Function} fn callback function + * @returns {TweenExtra} + */ + on(name: string, fn: Function): TweenExtra; + /** + * Method to set options on the fly. + * * accepting [repeat,yoyo,delay,repeatDelay,easing] + * + * @param {string} option the tick time + * @param {string | number | number[]} value the tick time + * @returns {TweenExtra} + */ + option(option: string, value: string | number | number[]): TweenExtra; + } + import Tween from "kute.js/src/tween/tween"; +} +declare module "kute.js/src/util/degToRad" { + export default degToRad; + /** + * degToRad + * + * Returns the value of a degree angle in radian. + * + * @param {number} a the degree angle + * @returns {number} the radian angle + */ + function degToRad(a: number): number; +} +declare module "kute.js/src/util/fromJSON" { + export default fromJSON; + /** + * fromJSON + * + * Returns the {valuesStart, valuesEnd} objects + * from a Tween instance. + * + * @param {string} str the JSON string + * @returns {JSON} the JSON object + */ + function fromJSON(str: string): JSON; +} +declare module "kute.js/src/util/progressBar" { + /** + * ProgressBar + * + * @class + * A progress bar utility for KUTE.js that will connect + * a target ``. with a Tween instance + * allowing it to control the progress of the Tween. + */ + export default class ProgressBar { + /** + * @constructor + * @param {HTMLElement} el target or string selector + * @param {KUTE.Tween} multi when true returns an array of elements + */ + constructor(element: any, tween: any); + element: HTMLInputElement; + updateBar(): void; + toggleEvents(action: any): void; + updateTween(): void; + moveAction(): void; + downAction(): void; + upAction(): void; + } +} +declare module "kute.js/src/util/radToDeg" { + export default radToDeg; + /** + * radToDeg + * + * Returns the value of a radian in degrees. + * + * @param {number} a the value in radian + * @returns {number} the value in degrees + */ + function radToDeg(a: number): number; +} +declare module "kute.js/src/util/rgbToHex" { + export default rgbToHex; + /** + * rgbToHex + * + * Converts an {r,g,b} color `Object` into #HEX string color format. + * Webkit browsers ignore HEX, always use RGB/RGBA. + * + * @param {number} r the red value + * @param {number} g the green value + * @param {number} b the blue value + * @returns {string} the #HEX string + */ + function rgbToHex(r: number, g: number, b: number): string; +} +declare module "kute.js/src/util/toJSON" { + export default toJSON; + /** + * toJSON + * + * Returns the {valuesStart, valuesEnd} objects + * from a Tween instance in JSON string format. + * + * @param {KUTE.Tween} tween the Tween instance + * @returns {string} the JSON string + */ + function toJSON(tween: KUTE.Tween): string; +} +declare module "kute.js/src/util/version" { + export default Version; + /** + * A global namespace for library version. + * @type {string} + */ + const Version: string; +} +declare module "kute.js/types/more/kute" { + export { default as Animation } from "kute.js/src/animation/animation"; + export { default as AnimationBase } from "kute.js/src/animation/animationBase"; + export { default as AnimationDevelopment } from "kute.js/src/animation/animationDevelopment"; + export { default as backgroundPosition } from "kute.js/src/components/backgroundPosition"; + export { default as backgroundPositionBase } from "kute.js/src/components/backgroundPositionBase"; + export { default as borderRadius } from "kute.js/src/components/borderRadius"; + export { default as borderRadiusBase } from "kute.js/src/components/borderRadiusBase"; + export { default as boxModel } from "kute.js/src/components/boxModel"; + export { default as boxModelBase } from "kute.js/src/components/boxModelBase"; + export { default as boxModelEssential } from "kute.js/src/components/boxModelEssential"; + export { default as clipProperty } from "kute.js/src/components/clipProperty"; + export { default as clipPropertyBase } from "kute.js/src/components/clipPropertyBase"; + export { default as colorProperties } from "kute.js/src/components/colorProperties"; + export { default as colorPropertiesBase } from "kute.js/src/components/colorPropertiesBase"; + export { default as crossBrowserMove } from "kute.js/src/components/crossBrowserMove"; + export { default as filterEffects } from "kute.js/src/components/filterEffects"; + export { default as filterEffectsBase } from "kute.js/src/components/filterEffectsBase"; + export { default as htmlAttributes } from "kute.js/src/components/htmlAttributes"; + export { default as htmlAttributesBase } from "kute.js/src/components/htmlAttributesBase"; + export { default as opacityProperty } from "kute.js/src/components/opacityProperty"; + export { default as opacityPropertyBase } from "kute.js/src/components/opacityPropertyBase"; + export { default as scrollProperty } from "kute.js/src/components/scrollProperty"; + export { default as scrollPropertyBase } from "kute.js/src/components/scrollPropertyBase"; + export { default as shadowProperties } from "kute.js/src/components/shadowProperties"; + export { default as shadowPropertiesBase } from "kute.js/src/components/shadowPropertiesBase"; + export { default as svgCubicMorph } from "kute.js/src/components/svgCubicMorph"; + export { default as svgCubicMorphBase } from "kute.js/src/components/svgCubicMorphBase"; + export { default as svgDraw } from "kute.js/src/components/svgDraw"; + export { default as svgDrawBase } from "kute.js/src/components/svgDrawBase"; + export { default as svgMorph } from "kute.js/src/components/svgMorph"; + export { default as svgMorphBase } from "kute.js/src/components/svgMorphBase"; + export { default as svgTransform } from "kute.js/src/components/svgTransform"; + export { default as svgTransformBase } from "kute.js/src/components/svgTransformBase"; + export { default as textProperties } from "kute.js/src/components/textProperties"; + export { default as textPropertiesBase } from "kute.js/src/components/textPropertiesBase"; + export { default as textWrite } from "kute.js/src/components/textWrite"; + export { default as textWriteBase } from "kute.js/src/components/textWriteBase"; + export { default as transformFunctions } from "kute.js/src/components/transformFunctions"; + export { default as transformFunctionsBase } from "kute.js/src/components/transformFunctionsBase"; + export { default as transformLegacy } from "kute.js/src/components/transformLegacy"; + export { default as transformLegacyBase } from "kute.js/src/components/transformLegacyBase"; + export { default as transformMatrix } from "kute.js/src/components/transformMatrix"; + export { default as transformMatrixBase } from "kute.js/src/components/transformMatrixBase"; + export { default as add } from "kute.js/src/core/add"; + export { default as getAll } from "kute.js/src/core/getAll"; + export { default as Internals } from "kute.js/src/core/internals"; + export { default as linkInterpolation } from "kute.js/src/core/linkInterpolation"; + export { default as queueStart } from "kute.js/src/core/queueStart"; + export { default as remove } from "kute.js/src/core/remove"; + export { default as removeAll } from "kute.js/src/core/removeAll"; + export { default as Render } from "kute.js/src/core/render"; + export { default as EasingBase } from "kute.js/src/easing/easing-base"; + export { default as EasingBezier } from "kute.js/src/easing/easing-bezier"; + export { default as Easing } from "kute.js/src/easing/easing"; + export { default as allFromTo } from "kute.js/src/interface/allFromTo"; + export { default as allTo } from "kute.js/src/interface/allTo"; + export { default as fromTo } from "kute.js/src/interface/fromTo"; + export { default as to } from "kute.js/src/interface/to"; + export { default as arrays } from "kute.js/src/interpolation/arrays"; + export { default as colors } from "kute.js/src/interpolation/colors"; + export { default as coords } from "kute.js/src/interpolation/coords"; + export { default as numbers } from "kute.js/src/interpolation/numbers"; + export { default as perspective } from "kute.js/src/interpolation/perspective"; + export { default as rotate } from "kute.js/src/interpolation/rotate"; + export { default as rotate3d } from "kute.js/src/interpolation/rotate3d"; + export { default as scale } from "kute.js/src/interpolation/scale"; + export { default as skew } from "kute.js/src/interpolation/skew"; + export { default as skewX } from "kute.js/src/interpolation/skewX"; + export { default as skewY } from "kute.js/src/interpolation/skewY"; + export { default as translate } from "kute.js/src/interpolation/translate"; + export { default as translate3d } from "kute.js/src/interpolation/translate3d"; + export { default as units } from "kute.js/src/interpolation/units"; + export { default as ComponentsBase } from "kute.js/src/objects/componentsBase"; + export { default as ComponentsDefault } from "kute.js/src/objects/componentsDefault"; + export { default as ComponentsExtra } from "kute.js/src/objects/componentsExtra"; + export { default as connect } from "kute.js/src/objects/connect"; + export { default as crossCheck } from "kute.js/src/objects/crossCheck"; + export { default as defaultOptions } from "kute.js/src/objects/defaultOptions"; + export { default as defaultValues } from "kute.js/src/objects/defaultValues"; + export { default as globalObject } from "kute.js/src/objects/globalObject"; + export { default as Interpolate } from "kute.js/src/objects/interpolate"; + export { default as KEC } from "kute.js/src/objects/kute"; + export { default as linkProperty } from "kute.js/src/objects/linkProperty"; + export { default as Objects } from "kute.js/src/objects/objects"; + export { default as ObjectsBase } from "kute.js/src/objects/objectsBase"; + export { default as onComplete } from "kute.js/src/objects/onComplete"; + export { default as onStart } from "kute.js/src/objects/onStart"; + export { default as prepareProperty } from "kute.js/src/objects/prepareProperty"; + export { default as prepareStart } from "kute.js/src/objects/prepareStart"; + export { default as supportedProperties } from "kute.js/src/objects/supportedProperties"; + export { default as Tweens } from "kute.js/src/objects/tweens"; + export { default as Util } from "kute.js/src/objects/util"; + export { default as getInlineStyle } from "kute.js/src/process/getInlineStyle"; + export { default as getInlineStyleLegacy } from "kute.js/src/process/getInlineStyleLegacy"; + export { default as getStartValues } from "kute.js/src/process/getStartValues"; + export { default as getStyleForProperty } from "kute.js/src/process/getStyleForProperty"; + export { default as prepareObject } from "kute.js/src/process/prepareObject"; + export { default as Process } from "kute.js/src/process/process"; + export { default as Tween } from "kute.js/src/tween/tween"; + export { default as TweenBase } from "kute.js/src/tween/tweenBase"; + export { default as TweenCollection } from "kute.js/src/tween/tweenCollection"; + export { default as TweenExtra } from "kute.js/src/tween/tweenExtra"; + export { default as degToRad } from "kute.js/src/util/degToRad"; + export { default as fromJSON } from "kute.js/src/util/fromJSON"; + export { default as getPrefix } from "kute.js/src/util/getPrefix"; + export { default as hexToRGB } from "kute.js/src/util/hexToRGB"; + export { default as now } from "kute.js/src/util/now"; + export { default as ProgressBar } from "kute.js/src/util/progressBar"; + export { default as radToDeg } from "kute.js/src/util/radToDeg"; + export { default as rgbToHex } from "kute.js/src/util/rgbToHex"; + export { default as selector } from "kute.js/src/util/selector"; + export { default as supportLegacyTransform } from "kute.js/src/util/supportLegacyTransform"; + export { default as toJSON } from "kute.js/src/util/toJSON"; + export { default as transformProperty } from "kute.js/src/util/transformProperty"; + export { default as trueColor } from "kute.js/src/util/trueColor"; + export { default as trueDimension } from "kute.js/src/util/trueDimension"; + export { default as trueProperty } from "kute.js/src/util/trueProperty"; + export { default as Version } from "kute.js/src/util/version"; +} diff --git a/types/more/kute.ts b/types/more/kute.ts new file mode 100644 index 0000000..185d333 --- /dev/null +++ b/types/more/kute.ts @@ -0,0 +1,127 @@ +export {default as Animation} from '../../src/animation/animation'; +export {default as AnimationBase} from '../../src/animation/animationBase'; +export {default as AnimationDevelopment} from '../../src/animation/animationDevelopment'; + +export {default as backgroundPosition} from '../../src/components/backgroundPosition'; +export {default as backgroundPositionBase} from '../../src/components/backgroundPositionBase'; +export {default as borderRadius} from '../../src/components/borderRadius'; +export {default as borderRadiusBase} from '../../src/components/borderRadiusBase'; +export {default as boxModel} from '../../src/components/boxModel'; +export {default as boxModelBase} from '../../src/components/boxModelBase'; +export {default as boxModelEssential} from '../../src/components/boxModelEssential'; +export {default as clipProperty} from '../../src/components/clipProperty'; +export {default as clipPropertyBase} from '../../src/components/clipPropertyBase'; +export {default as colorProperties} from '../../src/components/colorProperties'; +export {default as colorPropertiesBase} from '../../src/components/colorPropertiesBase'; +export {default as crossBrowserMove} from '../../src/components/crossBrowserMove'; +export {default as filterEffects} from '../../src/components/filterEffects'; +export {default as filterEffectsBase} from '../../src/components/filterEffectsBase'; +export {default as htmlAttributes} from '../../src/components/htmlAttributes'; +export {default as htmlAttributesBase} from '../../src/components/htmlAttributesBase'; +export {default as opacityProperty} from '../../src/components/opacityProperty'; +export {default as opacityPropertyBase} from '../../src/components/opacityPropertyBase'; +export {default as scrollProperty} from '../../src/components/scrollProperty'; +export {default as scrollPropertyBase} from '../../src/components/scrollPropertyBase'; +export {default as shadowProperties} from '../../src/components/shadowProperties'; +export {default as shadowPropertiesBase} from '../../src/components/shadowPropertiesBase'; +export {default as svgCubicMorph} from '../../src/components/svgCubicMorph'; +export {default as svgCubicMorphBase} from '../../src/components/svgCubicMorphBase'; +export {default as svgDraw} from '../../src/components/svgDraw'; +export {default as svgDrawBase} from '../../src/components/svgDrawBase'; +export {default as svgMorph} from '../../src/components/svgMorph'; +export {default as svgMorphBase} from '../../src/components/svgMorphBase'; +export {default as svgTransform} from '../../src/components/svgTransform'; +export {default as svgTransformBase} from '../../src/components/svgTransformBase'; +export {default as textProperties} from '../../src/components/textProperties'; +export {default as textPropertiesBase} from '../../src/components/textPropertiesBase'; +export {default as textWrite} from '../../src/components/textWrite'; +export {default as textWriteBase} from '../../src/components/textWriteBase'; +export {default as transformFunctions} from '../../src/components/transformFunctions'; +export {default as transformFunctionsBase} from '../../src/components/transformFunctionsBase'; +export {default as transformLegacy} from '../../src/components/transformLegacy'; +export {default as transformLegacyBase} from '../../src/components/transformLegacyBase'; +export {default as transformMatrix} from '../../src/components/transformMatrix'; +export {default as transformMatrixBase} from '../../src/components/transformMatrixBase'; + +export {default as add} from '../../src/core/add'; +export {default as getAll} from '../../src/core/getAll'; +export {default as Internals} from '../../src/core/internals'; +export {default as linkInterpolation} from '../../src/core/linkInterpolation'; +export {default as queueStart} from '../../src/core/queueStart'; +export {default as remove} from '../../src/core/remove'; +export {default as removeAll} from '../../src/core/removeAll'; +export {default as Render} from '../../src/core/render'; + +export {default as EasingBase} from '../../src/easing/easing-base'; +export {default as EasingBezier} from '../../src/easing/easing-bezier'; +export {default as Easing} from '../../src/easing/easing'; + +export {default as allFromTo} from '../../src/interface/allFromTo'; +export {default as allTo} from '../../src/interface/allTo'; +export {default as fromTo} from '../../src/interface/fromTo'; +export {default as to} from '../../src/interface/to'; + +export {default as arrays} from '../../src/interpolation/arrays'; +export {default as colors} from '../../src/interpolation/colors'; +export {default as coords} from '../../src/interpolation/coords'; +export {default as numbers} from '../../src/interpolation/numbers'; +export {default as perspective} from '../../src/interpolation/perspective'; +export {default as rotate} from '../../src/interpolation/rotate'; +export {default as rotate3d} from '../../src/interpolation/rotate3d'; +export {default as scale} from '../../src/interpolation/scale'; +export {default as skew} from '../../src/interpolation/skew'; +export {default as skewX} from '../../src/interpolation/skewX'; +export {default as skewY} from '../../src/interpolation/skewY'; +export {default as translate} from '../../src/interpolation/translate'; +export {default as translate3d} from '../../src/interpolation/translate3d'; +export {default as units} from '../../src/interpolation/units'; + +export {default as ComponentsBase} from '../../src/objects/componentsBase'; +export {default as ComponentsDefault} from '../../src/objects/componentsDefault'; +export {default as ComponentsExtra} from '../../src/objects/componentsExtra'; +export {default as connect} from '../../src/objects/connect'; +export {default as crossCheck} from '../../src/objects/crossCheck'; +export {default as defaultOptions} from '../../src/objects/defaultOptions'; +export {default as defaultValues} from '../../src/objects/defaultValues'; +export {default as globalObject} from '../../src/objects/globalObject'; +export {default as Interpolate} from '../../src/objects/interpolate'; +export {default as KEC} from '../../src/objects/kute'; +export {default as linkProperty} from '../../src/objects/linkProperty'; +export {default as Objects} from '../../src/objects/objects'; +export {default as ObjectsBase} from '../../src/objects/objectsBase'; +export {default as onComplete} from '../../src/objects/onComplete'; +export {default as onStart} from '../../src/objects/onStart'; +export {default as prepareProperty} from '../../src/objects/prepareProperty'; +export {default as prepareStart} from '../../src/objects/prepareStart'; +export {default as supportedProperties} from '../../src/objects/supportedProperties'; +export {default as Tweens} from '../../src/objects/tweens'; +export {default as Util} from '../../src/objects/util'; + +export {default as getInlineStyle} from '../../src/process/getInlineStyle'; +export {default as getInlineStyleLegacy} from '../../src/process/getInlineStyleLegacy'; +export {default as getStartValues} from '../../src/process/getStartValues'; +export {default as getStyleForProperty} from '../../src/process/getStyleForProperty'; +export {default as prepareObject} from '../../src/process/prepareObject'; +export {default as Process} from '../../src/process/process'; + +export {default as Tween} from '../../src/tween/tween'; +export {default as TweenBase} from '../../src/tween/tweenBase'; +export {default as TweenCollection} from '../../src/tween/tweenCollection'; +export {default as TweenExtra} from '../../src/tween/tweenExtra'; + +export {default as degToRad} from '../../src/util/degToRad'; +export {default as fromJSON} from '../../src/util/fromJSON'; +export {default as getPrefix} from '../../src/util/getPrefix'; +export {default as hexToRGB} from '../../src/util/hexToRGB'; +export {default as now} from '../../src/util/now'; +export {default as ProgressBar} from '../../src/util/progressBar'; +export {default as radToDeg} from '../../src/util/radToDeg'; +export {default as rgbToHex} from '../../src/util/rgbToHex'; +export {default as selector} from '../../src/util/selector'; +export {default as supportLegacyTransform} from '../../src/util/supportLegacyTransform'; +export {default as toJSON} from '../../src/util/toJSON'; +export {default as transformProperty} from '../../src/util/transformProperty'; +export {default as trueColor} from '../../src/util/trueColor'; +export {default as trueDimension} from '../../src/util/trueDimension'; +export {default as trueProperty} from '../../src/util/trueProperty'; +export {default as Version} from '../../src/util/version'; diff --git a/types/more/types.d.ts b/types/more/types.d.ts new file mode 100644 index 0000000..00258f9 --- /dev/null +++ b/types/more/types.d.ts @@ -0,0 +1,208 @@ +import CubicBezier from "cubic-bezier-easing"; +import Tween from "kute.js/src/tween/tween"; +import TweenBase from "kute.js/src/tween/tweenBase"; +import TweenExtra from "kute.js/src/tween/tweenExtra"; + +// custom types +export type selectorType = Element | Element[] | HTMLCollection | string; + +export type easingFunction = (fn: number) => number; +export type easingOption = string | easingFunction | CubicBezier; + +export declare interface tweenOptions { + /** @default 700 */ + duration?: number; + /** @default 0 */ + delay?: number; + /** @default 0 */ + offset?: number; + /** @default "linear" */ + easing?: easingOption; + /** @default 0 */ + repeat?: number; + /** @default 0 */ + repeatDelay?: number; + /** @default false */ + yoyo?: boolean; + /** @default null */ + resetStart?: any; +} + +export type tweenProps = [string, (string | number | number[])][]; +export type tweenParams = [Element, tweenProps, tweenProps, tweenOptions]; +export type twCollection = (Tween | TweenBase | TweenExtra)[]; +export type chainOption = Tween | TweenBase | twCollection; +export type propValue = number | number[] | [string, number] | [string, number][]; +export type rawValue = string | propValue; +export type interpolationFn = (a: propValue, b: propValue, t: number) => void; +export type prepareStartFn = (a?: string, b?: rawValue) => rawValue; +export type preparePropFn = (a?: string, b?: rawValue) => propValue; +export type onStartPropFn = (tweenProp?: string) => void; + +export interface fullComponent { + component: string; + category?: string; + property?: string; + properties?: string[]; + subProperties?: string[]; + defaultValues?: propValue[]; + defaultValue?: propValue; + defaultOptions?: [string, string | number | number[]][]; + Interpolate?: [string, interpolationFn][]; + functions: { + prepareStart: prepareStartFn; + prepareProperty: preparePropFn; + onStart: () => onStartPropFn; + onComplete?: () => void; + crossCheck?: () => void; + } +} +export interface baseComponent { + component: string; + category?: string; + property?: string; + properties?: string[]; + subProperties?: string[]; + defaultOptions?: [string, string | number | number[]][]; + Interpolate?: [string, interpolationFn][]; + functions: { + onStart: onStartPropFn; + } +} +export interface curveSpecs { + s: SVGPathCommander.CSegment | SVGPathCommander.MSegment, + ss: SVGPathCommander.curveArray, + l: number +} + +export interface curveObject { + curve: SVGPathCommander.curveArray, + original: string +} + +export type polygonMorph = [number, number][]; + +export type exactPolygon = { polygon: polygonMorph, skipBisect?: boolean } | false; + +export interface polygonObject { + polygon: polygonMorph, + original: string +} + +export declare interface transformFObject { + perspective?: number; + translate3d?: number[]; + rotate3d?: number[]; + skew?: number[]; + scale?: number; + } + +export declare interface transformMObject { + perspective?: number; + translate3d?: number[]; + rotate3d?: number[]; + scale3d?: number[]; + skew?: number[]; + } + + +export interface colorObject { + /** @default 0 */ + r: number, + /** @default 0 */ + g: number, + /** @default 0 */ + b: number, + /** @default 1 */ + a: number | null +} + +export interface drawObject { + s: number, + e: number, + l: number +} + +export interface transformSVGObject { + translate?: number | [number, number], + rotate?: number, + skewX?: number, + skewY?: number, + scale?: number +} + +// boxShadow: '0px 0px 0px 0px rgb(0,0,0)', +// h-shadow, v-shadow, blur, spread, color +export type boxShadowObject = [number, number, number, number, colorObject]; +// textShadow: '0px 0px 0px rgb(0,0,0)', +// h-shadow, v-shadow, blur, color +export type textShadowObject = [number, number, number, colorObject] +export type shadowObject = boxShadowObject | textShadowObject; + +// property: range | default +export interface filterList { + /** + * opacity range [0-100%] + * opacity unit % + * @default 100 + */ + opacity: number, + /** + * blur range [0-N] + * blur unit [em, px, rem] + * @default 0 + */ + blur: number, + /** + * saturate range [0-N] + * saturate unit % + * @default 100 + */ + saturate: number, + /** + * invert range [0-100] + * invert unit % + * @default 0 + */ + invert: number, + /** + * grayscale range [0-100] + * grayscale unit % + * @default 0 + */ + grayscale: number, + /** + * brightness range [0-100] + * brightness unit % + * @default 100 + */ + brightness: number, + /** + * contrast range [0-N] + * contrast unit % + * @default 100 + */ + contrast: number, + /** + * sepia range [0-N] + * sepia unit % + * @default 0 + */ + sepia: number, + /** + * hue-rotate range [0-N] + * hue-rotate unit deg + * @default 0 + */ + hueRotate: number, + /** + * drop-shadow [x,y,spread,color] + * @default [0,0,0,{r:0,g:0,b:0}] + */ + dropShadow: [number, number, number, colorObject], + /** + * "url(_URL_)" + * @default null + */ + url: string +} \ No newline at end of file