Changes, lots of them:

* Updated SVGPathCommander to make use of the new features, the SVG morph components can now process paths in Node.js
* svgCubicMorph component now can morph lines properly, as shown in the updated demo
* svgMorph component also updated
* documentation updates for more clarity with the morph components
This commit is contained in:
thednp 2020-09-23 18:59:39 +00:00
parent 85d9c09ede
commit 0b7fd91bab
43 changed files with 4604 additions and 4335 deletions

View file

@ -1,5 +1,8 @@
# KUTE.js
A modern JavaScript animation engine built on ES6/ES7 standards with most essential features for web developers, designers and animators, delivering easy to use methods to set up high performance, cross-browser animations. The focus is code quality, flexibility, performance and size.
[![KUTE.js](demo/assets/img/apple-touch-icon.png)](https://thednp.github.io/kute.js/)
A modern JavaScript animation engine built on ES6+ standards with most essential features for the web, delivering easy to use methods to set up high performance, cross-browser animations. The focus is code quality, flexibility, performance and size.
[![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)

View file

@ -1,9 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle" class="st0" d="M559,597.4H302.1H43.6c-21,0-38-17-38-38V408.8V223.6V44c0-21,17-38,38-38h105.6H300h160.3H559
c21,0,38,17,38,38v184v331.4C597,580.4,580,597.4,559,597.4z"/>
<path id="star" d="M302.1,17.9c16,29,81.4,147.7,98.2,178.2c31.1,6,62.3,11.9,93.4,17.9c35.5,6.8,71,13.6,106.5,20.4
c-46.4,49.5-92.7,99-139.1,148.5c1.1,8.5,6.7,53.4,12.4,99.1c5.7,45.3,11.4,91.4,12.9,102.9c-36-16.9-158.8-74.5-184.2-86.4
c-28.5,13.4-151.3,71-184.2,86.4c0.4-3.2,13.3-106.6,13.3-106.6s10.1-81,11.9-95.3C96.8,333.5,50.4,284,4,234.5
c34.4-6.6,68.8-13.2,103.3-19.8c32.2-6.2,64.4-12.3,96.5-18.5C221,165.1,286.5,46.2,302.1,17.9z"/>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 600 600" style="enable-background:new 0 0 600 600;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
</style>
<path id="rectangle" class="st0" d="M559,597.4H302.1H43.6c-21,0-38-17-38-38V300V44c0-21,17-38,38-38H300h259c21,0,38,17,38,38
v257.7v257.7C597,580.4,580,597.4,559,597.4z"/>
<path id="star" d="M302.1,17.9c16,29,81.4,147.7,98.2,178.2c13.7,2.6,47.3,9.1,83.5,16c46.1,8.8,96.5,18.5,116.4,22.3
c-25.1,26.7-117.8,125.7-139.1,148.5c1.1,8.5,23.8,190.5,25.3,202c-36-16.9-158.8-74.5-184.2-86.4c-28.5,13.4-151.3,71-184.2,86.4
c0.4-3.2,23.4-187.6,25.2-201.9C122.8,361.3,30,262.3,4,234.5c17.3-3.3,59.5-11.4,101.3-19.4c41.4-7.9,82.5-15.8,98.5-18.9
C221,165.1,286.5,46.2,302.1,17.9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 997 B

View file

@ -1,29 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="complex-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 513 513">
<path id="symbol-left" d="M155.9,333.4h-55.6c-3.4,0-5.9-1.5-7.3-3.8c-1.5-2.4-1.5-5.5,0-8.5l59.1-104.3c0.1-0.1,0.1-0.2,0-0.3
l-37.6-65.1c-1.6-3.1-1.8-6.2-0.3-8.5c1.4-2.3,4.2-3.5,7.6-3.5h55.6c8.5,0,12.7,5.5,15.5,10.4c0,0,38,66.3,38.2,66.7
c-2.3,4-60.1,106.2-60.1,106.2C168.2,327.8,164.2,333.4,155.9,333.4z"/>
<path id="symbol-left-clone" class="st0" d="M155.9,333.4h-55.6c-3.4,0-5.9-1.5-7.3-3.8c-1.5-2.4-1.5-5.5,0-8.5l59.1-104.3
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="complex-morph-example" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 513 513" style="enable-background:new 0 0 513 513;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
</style>
<path id="symbol-left" class="st0" d="M155.9,333.4h-55.6c-3.4,0-5.9-1.5-7.3-3.8c-1.5-2.4-1.5-5.5,0-8.5l59.1-104.3
c0.1-0.1,0.1-0.2,0-0.3l-37.6-65.1c-1.6-3.1-1.8-6.2-0.3-8.5c1.4-2.3,4.2-3.5,7.6-3.5h55.6c8.5,0,12.7,5.5,15.5,10.4
c0,0,38,66.3,38.2,66.7c-2.3,4-60.1,106.2-60.1,106.2C168.2,327.8,164.2,333.4,155.9,333.4z"/>
<path id="symbol-right" class="st0" d="M419,75.3L295.8,293.1c-0.1,0.1-0.1,0.3,0,0.4l78.4,143.3c1.6,3.1,1.6,6.2,0.1,8.6
<path id="symbol-left-clone" class="st0" d="M155.9,333.4h-55.6c-3.4,0-5.9-1.5-7.3-3.8c-1.5-2.4-1.5-5.5,0-8.5l59.1-104.3
c0.1-0.1,0.1-0.2,0-0.3l-37.6-65.1c-1.6-3.1-1.8-6.2-0.3-8.5c1.4-2.3,4.2-3.5,7.6-3.5h55.6c8.5,0,12.7,5.5,15.5,10.4
c0,0,38,66.3,38.2,66.7c-2.3,4-60.1,106.2-60.1,106.2C168.2,327.8,164.2,333.4,155.9,333.4z"/>
<path id="symbol-right" class="st0" d="M419,75.3L295.8,293.1c-0.1,0.1-0.1,0.3,0,0.4l78.4,143.3c1.6,3.1,1.6,6.2,0.1,8.6
c-1.4,2.3-4,3.6-7.4,3.6h-55.6c-8.5,0-12.8-5.7-15.5-10.6c0,0-78.8-144.6-79.1-145c3.9-7,123.8-219.5,123.8-219.5
c3-5.4,6.6-10.6,14.9-10.6h56.2c3.4,0,6,1.3,7.4,3.6C420.5,69.1,420.5,72.2,419,75.3L419,75.3z"/>
<path id="eye-right" class="st0" d="M352,128c2.6,0,5,0.5,7.4,1.3c2.3,0.8,4.5,2,6.6,3.6c10.6,7.8,18,24.2,18,43.1
<path id="eye-right" class="st0" d="M352,128c2.6,0,5,0.5,7.4,1.3c2.3,0.8,4.5,2,6.6,3.6c10.6,7.8,18,24.2,18,43.1
c0,16.2-5.3,30.5-13.5,39.2c-3.1,3.3-6.6,5.8-10.5,7.3c-2.6,1-5.3,1.5-8,1.5c-4,0-7.8-1.1-11.3-3.1c-2.7-1.6-5.3-3.7-7.6-6.2
c-7.9-8.7-13-22.8-13-38.7c0-19.2,7.5-35.7,18.4-43.4c1.9-1.4,4-2.5,6.1-3.2C346.9,128.5,349.4,128,352,128z"/>
<path id="eye-left" class="st0" d="M176,156c10.4,0,19.7,1.4,27.5,3.9c14.5,4.7,23.5,13.4,23.5,24.8c0,3.7,1.9,21.5-0.1,24.8
<path id="eye-left" class="st0" d="M176,156c10.4,0,19.7,1.4,27.5,3.9c14.5,4.7,23.5,13.4,23.5,24.8c0,3.7,1.9,21.5-0.1,24.8
c-3.3-5.5-9.2-10.3-16.7-13.9c-5.6-2.7-12.2-4.8-19.4-6c-4.7-0.8-9.6-1.2-14.7-1.2c-8.9,0-17.3,1.3-24.7,3.5
c-12.2,3.7-21.6,10-26.3,17.6c-2-3.3-0.1-21.1-0.1-24.8c0-11.3,8.8-19.9,23-24.6c3.7-1.2,7.8-2.2,12.2-2.9
C165.1,156.4,170.4,156,176,156z"/>
<path id="mouth" d="M250.2,416c-42.9,0-82-16.6-111.5-43.9c-7-6.5-13.5-13.6-19.4-21.2c-3.8-4.9-7.3-10-10.6-15.4
<path id="mouth" class="st0" d="M250.2,416c-42.9,0-82-16.6-111.5-43.9c-7-6.5-13.5-13.6-19.4-21.2c-3.8-4.9-7.3-10-10.6-15.4
c5.6,4.4,11.9,8.2,18.7,11.5c7.1,3.4,14.8,6.2,23,8.4c33.9,9.2,76.7,8.9,120.9,0.1c47.2-9.3,87.3-26.8,114.5-50.3
c6-5.1,11.3-10.6,16-16.3c5.6-6.9,10.3-14.2,13.8-21.8c-1.2,9.2-3.1,18.2-5.7,26.9c-2.6,8.8-5.9,17.3-9.7,25.5
C373.1,376.7,316.1,416,250.2,416L250.2,416z"/>
<path id="rectangle-container" class="st2" d="M426.7,0H85.3C38.4,0,0,38.4,0,85.3v341.3c0,47,38.4,85.3,85.3,85.3h341.3
<path id="rectangle-container" class="st0" d="M426.7,0H85.3C38.4,0,0,38.4,0,85.3v341.3c0,47,38.4,85.3,85.3,85.3h341.3
c46.9,0,85.3-38.4,85.3-85.3V85.3C512,38.4,473.6,0,426.7,0z"/>
<path id="circle-container" class="st0" d="M0,256c0,100.9,59.8,165.3,72,177.9c11.2,11.6,77.7,78.1,184,78.1
c14.5,0,115.8-1.7,190.7-85.3C510.1,356,512,274.1,512,256c0-18.9-2.1-96.7-61-165.9C375.7,1.8,269.4,0,256,0
C241,0,141.3,1.7,66.6,83.7C1.9,154.8,0,237.9,0,256z"/>
<path id="circle-container" d="M0,256c0,100.9,59.8,165.3,72,177.9c9.1,9.4,34.7,34.4,75.6,53.5c50.6,23.7,95,24.6,108.4,24.6
c10.9,0,61.3-0.9,117.6-30c42.1-21.8,67.4-49,73.1-55.3c64-70.6,65.3-157,65.3-170.7c0-18.9-2.1-96.7-61-165.9
c-8.6-10.2-37.3-42-86-65C313.6,0.9,268.6,0,256,0c-11,0-61.8,0.8-118.2,30.1C97.1,51.3,72.4,77.3,66.6,83.7C1.3,154.7,0,243,0,256z
"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1,41 +1,53 @@
// general tween options
var morphOps = {
duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'
}
// basic morph
var morphTween = KUTE.to('#rectangle', { path: '#star' }, {
duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'
});
var morphTween1 = KUTE.to('#rectangle1', { path: '#star1' }, {
duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'
});
var morphTween = KUTE.to('#rectangle', { path: '#star' }, morphOps);
var morphTween1 = KUTE.to('#rectangle1', { path: '#star1' }, morphOps);
var morphTween2 = KUTE.to('#rectangle2', { path: '#star2' }, morphOps);
var morphBtn = document.getElementById('morphBtn');
morphBtn.addEventListener('click', function(){
!morphTween.playing && morphTween.start() && morphTween1.start()
!morphTween.playing && morphTween.start();
!morphTween1.playing && morphTween1.start();
!morphTween2.playing && morphTween2.start();
}, false);
// line to circle
var lineMorph = KUTE.to('#line',{path:'#circle'},{ yoyo:true, repeat:1, duration:2000, easing: 'easingCubicOut'}),
lineMorph1 = KUTE.to('#line1',{path:'#circle1'},{ yoyo:true, repeat:1, duration:2000, easing: 'easingCubicOut'}),
morphBtnClosed = document.getElementById('morphBtnClosed');
var lineMorph = KUTE.to('#line' ,{path:'#circle' }, morphOps);
var lineMorph1 = KUTE.to('#line1',{path:'#circle1'}, morphOps);
var lineMorph2 = KUTE.to('#line2',{path:'#circle2'}, morphOps);
var lineMorph3 = KUTE.to('#line3',{path:'#circle3'}, morphOps);
var morphBtnClosed = document.getElementById('morphBtnClosed')
morphBtnClosed.addEventListener('click', function(){
!lineMorph.playing && lineMorph.start()
!lineMorph1.playing && lineMorph1.start()
!lineMorph.playing && lineMorph.start();
!lineMorph1.playing && lineMorph1.start();
!lineMorph2.playing && lineMorph2.start();
!lineMorph3.playing && lineMorph3.start();
}, false);
var morphOps1 = {
duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'
}
// multishape morph
var multiMorphBtn = document.getElementById('multiMorphBtn');
var multiMorph1 = KUTE.fromTo('#w11', { path: '#w11', attr:{ fill: "rgb(233,27,31)" } }, { path: '#w21', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph2 = KUTE.fromTo('#w12', { path: '#w12', attr:{ fill: "rgb(255,87,34)" } }, { path: '#w22', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph3 = KUTE.fromTo('#w13', { path: '#w13', attr:{ fill: "rgb(76,175,80)" } }, { path: '#w23', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph4 = KUTE.fromTo('#w14', { path: '#w14', attr:{ fill: "rgb(33,150,243)" } }, { path: '#w24', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph1 = KUTE.fromTo('#w11', { path: '#w11', attr:{ fill: "rgb(233,27,31)" } }, { path: '#w21', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph2 = KUTE.fromTo('#w12', { path: '#w12', attr:{ fill: "rgb(255,87,34)" } }, { path: '#w22', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph3 = KUTE.fromTo('#w13', { path: '#w13', attr:{ fill: "rgb(76,175,80)" } }, { path: '#w23', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph4 = KUTE.fromTo('#w14', { path: '#w14', attr:{ fill: "rgb(33,150,243)" } }, { path: '#w24', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph11 = KUTE.fromTo('#w111', { path: '#w111', attr:{ fill: "rgb(233,27,31)" } }, { path: '#w211', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph21 = KUTE.fromTo('#w121', { path: '#w121', attr:{ fill: "rgb(255,87,34)" } }, { path: '#w221', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph31 = KUTE.fromTo('#w131', { path: '#w131', attr:{ fill: "rgb(76,175,80)" } }, { path: '#w231', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph41 = KUTE.fromTo('#w141', { path: '#w141', attr:{ fill: "rgb(33,150,243)" } }, { path: '#w241', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph11 = KUTE.fromTo('#w111', { path: '#w111', attr:{ fill: "rgb(233,27,31)" } }, { path: '#w211', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph21 = KUTE.fromTo('#w121', { path: '#w121', attr:{ fill: "rgb(255,87,34)" } }, { path: '#w221', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph31 = KUTE.fromTo('#w131', { path: '#w131', attr:{ fill: "rgb(76,175,80)" } }, { path: '#w231', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph41 = KUTE.fromTo('#w141', { path: '#w141', attr:{ fill: "rgb(33,150,243)" } }, { path: '#w241', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph1s = KUTE.fromTo('#s11', { path: '#s11', attr:{ fill: "rgb(233,27,31)" } }, { path: '#s23', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph2s = KUTE.fromTo('#s12', { path: '#s12', attr:{ fill: "rgb(255,87,34)" } }, { path: '#s21', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph3s = KUTE.fromTo('#s13', { path: '#s13', attr:{ fill: "rgb(76,175,80)" } }, { path: '#s24', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph4s = KUTE.fromTo('#s14', { path: '#s14', attr:{ fill: "rgb(33,150,243)" } }, { path: '#s22', attr:{ fill: "#56C5FF" } }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var multiMorph1s = KUTE.fromTo('#s11', { path: '#s11', attr:{ fill: "rgb(233,27,31)" } }, { path: '#s23', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph2s = KUTE.fromTo('#s12', { path: '#s12', attr:{ fill: "rgb(255,87,34)" } }, { path: '#s21', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph3s = KUTE.fromTo('#s13', { path: '#s13', attr:{ fill: "rgb(76,175,80)" } }, { path: '#s24', attr:{ fill: "#56C5FF" } }, morphOps1);
var multiMorph4s = KUTE.fromTo('#s14', { path: '#s14', attr:{ fill: "rgb(33,150,243)" } }, { path: '#s22', attr:{ fill: "#56C5FF" } }, morphOps1);
multiMorphBtn.addEventListener('click', function(){
!multiMorph1.playing && multiMorph1.start() && multiMorph11.start() && multiMorph1s.start();
@ -46,20 +58,20 @@ multiMorphBtn.addEventListener('click', function(){
// complex multi morph
var compliMorphBtn = document.getElementById('compliMorphBtn');
var compliMorph1 = KUTE.fromTo('#rectangle-container', {path: '#rectangle-container', attr:{ fill: "#2196F3"} }, { path: '#circle-container', attr:{ fill: "#FF5722"} }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph2 = KUTE.fromTo('#symbol-left', {path: '#symbol-left'}, { path: '#eye-left' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph3 = KUTE.fromTo('#symbol-left-clone', {path: '#symbol-left-clone'}, { path: '#mouth' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph4 = KUTE.fromTo('#symbol-right', {path: '#symbol-right'}, { path: '#eye-right' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph1 = KUTE.fromTo('#rectangle-container', {path: '#rectangle-container', attr:{ fill: "#2196F3"} }, { path: '#circle-container', attr:{ fill: "#FF5722"} }, morphOps1);
var compliMorph2 = KUTE.fromTo('#symbol-left', {path: '#symbol-left'}, { path: '#eye-left' }, morphOps1);
var compliMorph3 = KUTE.fromTo('#symbol-left-clone', {path: '#symbol-left-clone'}, { path: '#mouth' }, morphOps1);
var compliMorph4 = KUTE.fromTo('#symbol-right', {path: '#symbol-right'}, { path: '#eye-right' }, morphOps1);
var compliMorph11 = KUTE.fromTo('#rectangle-container1', {path: '#rectangle-container1', attr:{ fill: "#9C27B0"} }, { path: '#circle-container1', attr:{ fill: "#FF5722"} }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph21 = KUTE.fromTo('#symbol-left1', {path: '#symbol-left1'}, { path: '#eye-left1' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph31 = KUTE.fromTo('#symbol-left-clone1', {path: '#symbol-left-clone1'}, { path: '#mouth1' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph41 = KUTE.fromTo('#symbol-right1', {path: '#symbol-right1'}, { path: '#eye-right1' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph11 = KUTE.fromTo('#rectangle-container1', {path: '#rectangle-container1', attr:{ fill: "#9C27B0"} }, { path: '#circle-container1', attr:{ fill: "#FF5722"} }, morphOps1);
var compliMorph21 = KUTE.fromTo('#symbol-left1', {path: '#symbol-left1'}, { path: '#eye-left1' }, morphOps1);
var compliMorph31 = KUTE.fromTo('#symbol-left-clone1', {path: '#symbol-left-clone1'}, { path: '#mouth1' }, morphOps1);
var compliMorph41 = KUTE.fromTo('#symbol-right1', {path: '#symbol-right1'}, { path: '#eye-right1' }, morphOps1);
var compliMorph12 = KUTE.fromTo('#rectangle-container2', {path: '#rectangle-container2', attr:{ fill: "#e91b1f"} }, { path: '#circle-container2', attr:{ fill: "#FF5722"} }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph22 = KUTE.fromTo('#symbol-left2', {path: '#symbol-left2'}, { path: '#eye-left2' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph32 = KUTE.fromTo('#sample-shape2', {path: '#sample-shape2'}, { path: '#mouth2' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph42 = KUTE.fromTo('#symbol-right2', {path: '#symbol-right2'}, { path: '#eye-right2' }, { duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
var compliMorph12 = KUTE.fromTo('#rectangle-container2', {path: '#rectangle-container2', attr:{ fill: "#e91b1f"} }, { path: '#circle-container2', attr:{ fill: "#FF5722"} }, morphOps1);
var compliMorph22 = KUTE.fromTo('#symbol-left2', {path: '#symbol-left2'}, { path: '#eye-left2' }, morphOps1);
var compliMorph32 = KUTE.fromTo('#sample-shape2', {path: '#sample-shape2'}, { path: '#mouth2' }, morphOps1);
var compliMorph42 = KUTE.fromTo('#symbol-right2', {path: '#symbol-right2'}, { path: '#eye-right2' }, morphOps1);
compliMorphBtn.addEventListener('click', function(){
!compliMorph1.playing && compliMorph1.start() && compliMorph11.start() && compliMorph12.start();

View file

@ -10,7 +10,6 @@
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="apple-touch-icon" href="./assets/img/apple-touch-icon.png">
<link href="https://fonts.googleapis.com/css?family=Roboto:400,800|Roboto+Condensed:400,800" rel="stylesheet">
<!-- TO DO -->
<title>KUTE.js Background Position</title>

View file

@ -141,10 +141,10 @@
<div class="d-flex align-items-start align-items-md-center h-md-100">
<div class="w-100 flex-column"> <!-- IE9 fix -->
<div class="spicr-layer" data-translate="y:-150" data-duration="800" data-delay="550" data-easing="easingCircularOut">
<h1>ECMA Script 2015</h1>
<h1>ES6+ JavaScript</h1>
</div>
<div class="spicr-layer" data-translate="y:-150" data-duration="900" data-delay="650" data-easing="easingCircularOut">
<p>Inside the sources you will find fast &amp; modern JavaScript code with solid build tools. Everything and anything can be done with SVGElement,
<p>Inside the sources you will find fast &amp; modern JavaScript code with solid build tools. Everything and anything can be done with <b>SVGElement</b>,
HTML attributes, CSS transform, etc.</p>
</div>
</div>
@ -215,11 +215,10 @@
<p class="lead condensed">The JavaScript animation engine reimagined for the evolving modern web, the library that keeps track on the changing standards, the modular tool
to enable creativity.</p>
<p>Built on modern ES6/ES7 JavaScript Standard, packed with utilities, build tools and a wide range of supported properties, <b>KUTE</b>.js is now a fully featured animation engine
<p>Built on modern ES6+ JavaScript Standard, packed with utilities, build tools and a wide range of supported properties, <b>KUTE</b>.js is now a fully featured animation engine
you can use to create complex animations, with properties or elements that cannot be animated with CSS3 transitions or other animation engines, or attributes that aren't
even drafted in the specification yet.</p>
<p class="lead condensed">The JavaScript animation engine that never stops evolving just like we never stop learning. Instead of becoming more bloated, we make it more modular,
instead of compromising we chose innovating. </p>
<p>While <b>KUTE</b>.js doesn't activelly support legacy browsers, it provides a wide range of tools and utilities you can use to create a fallback animation for every browser
@ -237,8 +236,8 @@
<div class="columns">
<div class="col2">
<h3 class="border">ES6/ES7 JavaScript</h2>
<p class="condensed">The entire codebase reworked on the latest standards with flexible rollup based build tools. Most classes are extensible via the ES6 <code>extend</code>
<h3 class="border">ES6+ JavaScript</h2>
<p class="condensed">The entire codebase reworked on the latest standards with flexible <code>rollup</code> based build tools. Most classes are extensible via the ES6 <code>extend</code>
or your usual <code>prototype</code>, depending on the class.</p>
</div>
<div class="col2">

View file

@ -2,17 +2,17 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0">
<meta name="description" content="KUTE.js performance testing page, comparing basic transform to matrix transform.">
<meta name="keywords" content="kute,kute.js,Javascript,Native Javascript,vanilla javascript,jQuery">
<meta name="author" content="dnp_theme">
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="apple-touch-icon" href="./assets/img/apple-touch-icon.png">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0">
<meta name="description" content="KUTE.js performance testing page, comparing basic transform to matrix transform.">
<meta name="keywords" content="kute,kute.js,Javascript,Native Javascript,vanilla javascript,jQuery">
<meta name="author" content="dnp_theme">
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="apple-touch-icon" href="./assets/img/apple-touch-icon.png">
<title>KUTE.js | Regular Transform Performance Testing Page</title>
<style>
<title>KUTE.js | Regular Transform Performance Testing Page</title>
<style>
body {
background-color: #08263d;
color: #999;
@ -177,7 +177,7 @@
.cube .cube__side:nth-child(13) {transform: translateX(-25px) rotateY(90deg); }
.cube .cube__side:nth-child(14) {transform: rotateY(90deg); }
.cube .cube__side:nth-child(15) {transform: translateX(25px) rotateY(90deg); }
</style>
</style>
</head>
<body>

View file

@ -2,18 +2,18 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0">
<meta name="description" content="KUTE.js performance testing page, in comparison with GSAP and Tween.js">
<meta name="keywords" content="kute,kute.js,Javascript,Native Javascript,vanilla javascript,jQuery">
<meta name="author" content="dnp_theme">
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="apple-touch-icon" href="./assets/img/apple-touch-icon.png">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1.0">
<meta name="description" content="KUTE.js performance testing page, in comparison with GSAP and Tween.js">
<meta name="keywords" content="kute,kute.js,Javascript,Native Javascript,vanilla javascript,jQuery">
<meta name="author" content="dnp_theme">
<link rel="shortcut icon" href="./assets/img/favicon.ico">
<link rel="apple-touch-icon" href="./assets/img/apple-touch-icon.png">
<title>KUTE.js | Performance Testing Page</title>
<!-- <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"> -->
<style>
<title>KUTE.js | Performance Testing Page</title>
<!-- <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"> -->
<style>
body {
background-color: #08263d;
color: #999;
@ -152,7 +152,7 @@
padding-right: 5px;
padding-left: 5px;
}
</style>
</style>
</head>

View file

@ -170,7 +170,7 @@ var progressBar = new KUTE.ProgressBar(rangeSlider,morphTween)
// also start animation when Element is clicked
document.getElementById('rectangle').addEventListener('click',function(){
!morphTween.playing && morphTween.start()
!morphTween.playing && morphTween.start()
})
</code></pre>

View file

@ -116,17 +116,17 @@ var myBSTween1 = KUTE.to('selector', {boxShadow: '10px 10px #069'}).start();
// or a fromTo with string and array, hex and rgb
var myBSTween2 = KUTE.fromTo(
'selector', // target
{boxShadow: [0, 0, 0, '#069']}, // from
{boxShadow: '5px 5px rgb(0,0,0)'}) // to
.start();
'selector', // target
{boxShadow: [0, 0, 0, '#069']}, // from
{boxShadow: '5px 5px rgb(0,0,0)'}) // to
.start();
// maybe you want to animate an inset boxShadow?
var myBSTween3 = KUTE.fromTo(
'selector', // target
{boxShadow: [5, 5, 0, '#069', 'inset']}, // from
{boxShadow: '0px 0px rgb(0,0,0)'}) // to
.start();
'selector', // target
{boxShadow: [5, 5, 0, '#069', 'inset']}, // from
{boxShadow: '0px 0px rgb(0,0,0)'}) // to
.start();
</code></pre>
<div id="boxShadow" class="featurettes">
@ -143,10 +143,10 @@ var myTSTween1 = KUTE.to('selector', {textShadow: '10px 10px #069'}).start();
// or a fromTo with string and array, hex and rgb
var myTSTween2 = KUTE.fromTo(
'selector', // target
{textShadow: [0, 0, 0, '#069']}, // from
{textShadow: '5px 5px rgb(0,0,0)'}) // to
.start();
'selector', // target
{textShadow: [0, 0, 0, '#069']}, // from
{textShadow: '5px 5px rgb(0,0,0)'}) // to
.start();
</code></pre>
<div id="textShadow" class="featurettes">

View file

@ -1,5 +1,5 @@
/*!
* KUTE.js Base v2.0.15 (http://thednp.github.io/kute.js)
* KUTE.js Base v2.0.16 (http://thednp.github.io/kute.js)
* Copyright 2015-2020 © thednp
* Licensed under MIT (https://github.com/thednp/kute.js/blob/master/LICENSE)
*/
@ -9,7 +9,7 @@
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.KUTE = factory());
}(this, (function () { 'use strict';
var version = "2.0.15";
var version = "2.0.16";
var KUTE = {};
@ -452,7 +452,7 @@
BoxModel: BoxModel,
Opacity: Opacity,
},
TweenBase: TweenBase,
Tween: TweenBase,
fromTo: fromTo,
Objects: Objects,
Easing: Easing,

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -91,11 +91,12 @@
<div class="col9 border">
<p class="lead condensed">The KUTE.js <b>SVG Cubic Morph</b> component enables animation for the <b>d</b> (description) presentation attribute and is the latest in all the SVG
components.</p>
<p>The main difference with the other <a href="svgMorph.html">SVG Morph</a> component is the fact that this components is using some path processing scripts borrowed from
<a href="http://www.raphaeljs.com/">Raphael.js</a> and other libraries to convert all path commands to <i>cubicBezierTo</i> path commands.</p>
<p>The component will process paths and out of the box will provide the closest possible interpolation by default. It also implements a series of solutions from
<a href="https://github.com/paperjs/paper.js/">Paper.js</a> to determine paths draw direction and automatically reverse one of them for most accurate presentation and as a result
the previously featured options <kbd>reverseFirstPath</kbd> and <kbd>reverseSecondPath</kbd> have been deprecated.</p>
<p>The main difference with the <a href="svgMorph.html">SVG Morph</a> component is the fact that this components is converting all path commands to <i>cubicBezierTo</i>,
giving it the upper hand over the original morph component. While the other component will spend time to process the path data and create polygons, this component should deliver
the animation faster and using considerably less power.</p>
<p>All path processing is powered by our <a href="https://github.com/thednp/svg-path-commander">SVGPathCommander</a> starting KUTE.js version 2.0.14, which aims to modernize and
improve the path processing and enable transition from closed to and from un-closed shapes.</p>
</div>
@ -109,8 +110,8 @@
<p>The first morphing animation example is a transition from a rectangle into a star, just like for the other component.</p>
<pre><code class="language-markup">&lt;svg id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
&lt;path id="rectangle" class="bg-lime" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531 c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"/>
&lt;path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"/>
&lt;path id="rectangle" class="bg-lime" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531 c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"/>
&lt;path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"/>
&lt;/svg>
</code></pre>
@ -134,36 +135,47 @@ var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864
<path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011z"/>
</svg>
<svg class="example-box-model example-box" id="morph-example1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle1" class="bg-blue" d="M559,597.4H302.1H43.6c-21,0-38-17-38-38V408.8V223.6V44c0-21,17-38,38-38h105.6H300h160.3H559
c21,0,38,17,38,38v184v331.4C597,580.4,580,597.4,559,597.4z"/>
<path id="star1" style="visibility:hidden" d="M302.1,17.9c16,29,81.4,147.7,98.2,178.2c31.1,6,62.3,11.9,93.4,17.9c35.5,6.8,71,13.6,106.5,20.4
c-46.4,49.5-92.7,99-139.1,148.5c1.1,8.5,6.7,53.4,12.4,99.1c5.7,45.3,11.4,91.4,12.9,102.9c-36-16.9-158.8-74.5-184.2-86.4
c-28.5,13.4-151.3,71-184.2,86.4c0.4-3.2,13.3-106.6,13.3-106.6s10.1-81,11.9-95.3C96.8,333.5,50.4,284,4,234.5
c34.4-6.6,68.8-13.2,103.3-19.8c32.2-6.2,64.4-12.3,96.5-18.5C221,165.1,286.5,46.2,302.1,17.9z"/>
<path id="rectangle1" class="bg-olive" d="M559,597.4H43.6c-21,0-38-17-38-38V44c0-21,17-38,38-38H559c21,0,38,17,38,38v515.4 C597,580.4,580,597.4,559,597.4"/>
<path id="star1" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808 l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"/>
</svg>
<svg class="example-box-model example-box" id="morph-example2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle2" class="bg-blue" d="M559,597.4H302.1H43.6c-21,0-38-17-38-38V300V44c0-21,17-38,38-38H300h259c21,0,38,17,38,38
v257.7v257.7C597,580.4,580,597.4,559,597.4"/>
<path id="star2" style="visibility:hidden" d="M302.1,17.9c16,29,81.4,147.7,98.2,178.2c13.7,2.6,47.3,9.1,83.5,16c46.1,8.8,96.5,18.5,116.4,22.3
c-25.1,26.7-117.8,125.7-139.1,148.5c1.1,8.5,23.8,190.5,25.3,202c-36-16.9-158.8-74.5-184.2-86.4c-28.5,13.4-151.3,71-184.2,86.4
c0.4-3.2,23.4-187.6,25.2-201.9C122.8,361.3,30,262.3,4,234.5c17.3-3.3,59.5-11.4,101.3-19.4c41.4-7.9,82.5-15.8,98.5-18.9
C221,165.1,286.5,46.2,302.1,17.9"/>
</svg>
<div class="example-buttons">
<a id="morphBtn" class="btn btn-green" href="javascript:void(0)">Start</a>
</div>
</div>
<p>The second blue shape and its corresponding end shape have been edited by adding additional curve points using a vector graphics editor to match the amount of points in both shapes as well as to optimize their travel
distance during the animation. You can use the same technique on your shapes to control the animation to your style.</p>
<p>Chris Coyier wrote <a href="https://css-tricks.com/svg-shape-morphing-works/">an excelent article</a> in which he explains how SVG morphing animation works, from concept, terminology and workflow.</p>
<p><b>Some takeaways:</b></p>
<ul>
<li>The <b class="text-red">red shape</b> and its corresponding end shape are both the originals, un-edited shapes, both have the <code>Z</code> path command, notice a strange line at the bottom-right of the rectangle
during the animation. We'll have another example about that line.</li>
<li>The <b class="text-olive">olive shape</b> and its corresponding end shape both have been edited by removing the <code>Z</code> path command, notice the strange line during the animation is gone, also a different
presentation.</li>
<li>The <b class="text-blue">blue shape</b> and its corresponding end shape have been edited by removing their <code>Z</code> path commands and by adding additional curve points using a vector graphics editor to match
the amount of points in both shapes.</li>
</ul>
<p>In this example we focus on experimentation to discover ways to optimize the morph animation so that the points travel optimal distance. Keep in mind that the <code>Z</code> path command is actually a shorthand
for <code>L</code> (line path command), sometimes it's required to close the shape, our shapes here happen to be OK without it.</p>
<p>Each morph animation as well as each pair of shapes can have its own quirks. You can use the technique on your shapes to optimize the animation to your style. Chris Coyier wrote
<a href="https://css-tricks.com/svg-shape-morphing-works/">an excelent article</a> in which he explains the terminology and workflow on how SVG morphing animation works with simple examples.</p>
<h3>Morphing Unclosed Shapes To Closed Shapes</h3>
<p>The next morphing animation example is a transition from a line into a circle and this example is to showcase the component's behavior when one of the paths is not closed (it doesn't have the <i>Z</i> path command),
while the other path is closed.</p>
<p>The next set of morphing animations is a transition from a line into a circle and showcases the component's behavior when both shapes are closed (they have the <code>Z</code> path command) or one or another is not,
but first let's create the necessary markup and scripting:</p>
<pre><code class="language-markup">&lt;svg id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
&lt;path id="line" fill="transparent" stroke="orange" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300"/>
&lt;path id="star" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
&lt;path id="line" fill="transparent" stroke="orange" stroke-linejoin="round" stroke-width="10" d="M10 300 L580 300"/>
&lt;path id="star" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
&lt;/svg>
</code></pre>
<p>Now we can apply both <code>.to()</code> and <code>fromTo()</code> methods:</p>
<pre><code class="language-javascript">// the fromTo() method
var tween = KUTE.fromTo('#line', {path: '#line' }, { path: '#circle' }).start();
// OR
@ -173,31 +185,50 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
<div class="featurettes">
<svg class="example-box-model example-box" id="morph-example-closed" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line" fill="transparent" stroke="#FF5722" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300z"/>
<path id="circle" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
<path id="line" fill="transparent" stroke="#FF5722" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300z"/>
<path id="circle" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0z"/>
</svg>
<svg class="example-box-model example-box" id="morph-example-closed1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line1" fill="transparent" stroke="#4CAF50" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300"/>
<path id="circle1" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
<path id="line1" fill="transparent" stroke="#4CAF50" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300"/>
<path id="circle1" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0z"/>
</svg>
<svg class="example-box-model example-box" id="morph-example-closed2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line2" fill="transparent" stroke="#2196F3" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300z"/>
<path id="circle2" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0"/>
</svg>
<svg class="example-box-model example-box" id="morph-example-closed3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line3" fill="transparent" stroke="#e91b1f" stroke-linejoin="round" stroke-width="15" d="M10 300 L580 300"/>
<path id="circle3" style="visibility:hidden" d="M10,300a290,290 0 1,1 580,0a290,290 0 1,1 -580,0"/>
</svg>
<div class="example-buttons">
<a id="morphBtnClosed" class="btn btn-green" href="javascript:void(0)">Start</a>
</div>
</div>
<p>The functionality of this component is different from the <a href="svgMorph.html">svgMorph</a> component in the sense that it will animate shapes as authored. In the above example, the orange line is closed
while the green line is not, and the animation is different.</p>
<p>As you can see, the functionality of this component is very different from the <a href="svgMorph.html">svgMorph</a> component in the sense that it will
morph shapes as authored. If you replay the above animations, here are a few takeaways:</p>
<ul>
<li>the <b class="text-orange">orange</b> line and its corresponding shape are both closed, this makes the last <code>Z</code> path command behave like a regular
line, perhaps not the best visual presentation;</li>
<li>the <b class="text-green">green</b> line is not closed, but its corresponding shape is, still the <code>Z</code> path command seems to cause trouble, while
the presentation looks a bit different;</li>
<li>the <b class="text-blue">blue</b> line is now closed, but its corresponding shape isn't and with the <code>Z</code> path command missing from the second shape,
the animation looks significantly better;</li>
<li>the <b class="text-red">red</b> line and its corresponding shape are both not closed, another combination that delivers excellent outcome.</li>
</ul>
<p>As you can see, this is another case where easy steps can be made to optimize the visual presentation. Keep in mind that stroke attributes like
<code>stroke-linejoin</code> such can have a small impact on your animation, particularly on start and end.</p>
<h3>Subpath Example</h3>
<p>In other cases, you may want to morph paths that have subpaths. Let's have a look at the following SVG:</p>
<pre><code class="language-markup">&lt;svg id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
&lt;path id="w1" d="M412.23 511.914c-47.708-24.518-94.086-36.958-137.88-36.958-5.956 0-11.952 0.18-17.948 0.708-55.88 4.624-106.922 19.368-139.75 30.828-8.708 3.198-17.634 6.576-26.83 10.306l-89.822 311.394c61.702-22.832 116.292-33.938 166.27-33.938 80.846 0 139.528 30.208 187.992 61.304 22.962-77.918 78.044-266.09 94.482-322.324-11.95-7.284-24.076-14.57-36.514-21.32z
&lt;path id="w1" d="M412.23 511.914c-47.708-24.518-94.086-36.958-137.88-36.958-5.956 0-11.952 0.18-17.948 0.708-55.88 4.624-106.922 19.368-139.75 30.828-8.708 3.198-17.634 6.576-26.83 10.306l-89.822 311.394c61.702-22.832 116.292-33.938 166.27-33.938 80.846 0 139.528 30.208 187.992 61.304 22.962-77.918 78.044-266.09 94.482-322.324-11.95-7.284-24.076-14.57-36.514-21.32z
m116.118 79.156l-90.446 314.148c26.832 15.372 117.098 64.05 186.212 64.05 55.792 0 118.252-14.296 190.834-43.792l86.356-301.976c-58.632 18.922-114.876 28.52-167.464 28.52-95.95 0-163.114-31.098-205.492-60.95z
m-235.526-222.28c77.118 0.798 134.152 30.208 181.416 60.502l92.752-317.344c-19.546-11.196-70.806-39.094-107.858-48.6-24.386-5.684-50.02-8.616-77.204-8.616-51.796 0.976-108.388 13.946-172.888 39.8l-88.44 310.596c64.808-24.436 120.644-36.34 172.086-36.34 0.046 0.002 0.136 0.002 0.136 0.002z
m731.178-170.666c-58.814 22.832-116.208 34.466-171.028 34.466-91.686 0-159.292-31.802-203.094-62.366l-91.95 318.236c61.746 39.708 128.29 59.878 198.122 59.878 56.948 0 115.94-13.68 175.462-40.688l-0.182-2.222 3.734-0.886 88.936-306.418z"/>
&lt;path id="w2" d="M0 187.396l367.2-50.6v354.798h-367.2v-304.2z
&lt;path id="w2" d="M0 187.396l367.2-50.6v354.798h-367.2v-304.2z
m0 649.2v-299.798h367.2v350.398z
m407.6 56v-355.798h488.4v423.2z
m0-761.2l488.4-67.4v427.6h-488.4v-360.2z"/>
@ -308,23 +339,24 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
<defs>
<mask id="symbol2">
<rect width="100%" height="100%" fill="#fff"></rect>
<path id="symbol-left2" fill="#000" d="M155.889 333.394h-55.632c-3.351 0-5.854-1.504-7.271-3.792-1.467-2.379-1.542-5.464 0-8.534l59.11-104.313c0.063-0.114 0.063-0.19 0-0.316l-37.615-65.116c-1.556-3.098-1.783-6.157-0.316-8.534 1.417-2.301 4.235-3.477 7.586-3.477h55.632c8.535 0 12.72 5.499 15.489 10.431 0 0 38.020 66.33 38.249 66.696-2.252 3.97-60.059 106.21-60.059 106.21-2.844 5.131-6.852 10.745-15.173 10.745z"></path>
<path id="symbol-left2" fill="#000" d="M155.889 333.394h-55.632c-3.351 0-5.854-1.504-7.271-3.792-1.467-2.379-1.542-5.464 0-8.534l59.11-104.313c0.063-0.114 0.063-0.19 0-0.316l-37.615-65.116c-1.556-3.098-1.783-6.157-0.316-8.534 1.417-2.301 4.235-3.477 7.586-3.477h55.632c8.535 0 12.72 5.499 15.489 10.431 0 0 38.020 66.33 38.249 66.696-2.252 3.97-60.059 106.21-60.059 106.21-2.844 5.131-6.852 10.745-15.173 10.745"></path>
<path id="sample-shape2" fill="#000" d="M250 450 L250 450"></path>
<path id="symbol-right2" fill="#000" d="M418.956 75.269l-123.176 217.79c-0.075 0.115-0.075 0.255 0 0.367l78.431 143.295c1.556 3.084 1.593 6.221 0.113 8.597-1.415 2.288-4.033 3.552-7.383 3.552h-55.57c-8.522 0-12.783-5.663-15.54-10.596 0 0-78.848-144.646-79.050-145.023 3.944-6.98 123.797-219.523 123.797-219.523 2.984-5.362 6.587-10.596 14.894-10.596h56.203c3.351 0 5.981 1.265 7.396 3.553 1.466 2.376 1.428 5.511-0.115 8.584z"></path>
<path id="symbol-right2" fill="#000" d="M418.956 75.269l-123.176 217.79c-0.075 0.115-0.075 0.255 0 0.367l78.431 143.295c1.556 3.084 1.593 6.221 0.113 8.597-1.415 2.288-4.033 3.552-7.383 3.552h-55.57c-8.522 0-12.783-5.663-15.54-10.596 0 0-78.848-144.646-79.050-145.023 3.944-6.98 123.797-219.523 123.797-219.523 2.984-5.362 6.587-10.596 14.894-10.596h56.203c3.351 0 5.981 1.265 7.396 3.553 1.466 2.376 1.428 5.511-0.115 8.584"></path>
<path id="eye-right2" style="visibility: hidden;" d="M352,128c2.6,0,5,0.5,7.4,1.3c2.3,0.8,4.5,2,6.6,3.6c10.6,7.8,18,24.2,18,43.1c0,16.2-5.3,30.5-13.5,39.2
c-3.1,3.3-6.6,5.8-10.5,7.3c-2.6,1-5.3,1.5-8,1.5c-4,0-7.8-1.1-11.3-3.1c-2.7-1.6-5.3-3.7-7.6-6.2c-7.9-8.7-13-22.8-13-38.7
c0-19.2,7.5-35.7,18.4-43.4c1.9-1.4,4-2.5,6.1-3.2C346.9,128.5,349.4,128,352,128z"></path>
c0-19.2,7.5-35.7,18.4-43.4c1.9-1.4,4-2.5,6.1-3.2C346.9,128.5,349.4,128,352,128"></path>
<path id="eye-left2" style="visibility: hidden;" d="M176,156c10.4,0,19.7,1.4,27.5,3.9c14.5,4.7,23.5,13.4,23.5,24.8c0,3.7,1.9,21.5-0.1,24.8
c-3.3-5.5-9.2-10.3-16.7-13.9c-5.6-2.7-12.2-4.8-19.4-6c-4.7-0.8-9.6-1.2-14.7-1.2c-8.9,0-17.3,1.3-24.7,3.5
c-12.2,3.7-21.6,10-26.3,17.6c-2-3.3-0.1-21.1-0.1-24.8c0-11.3,8.8-19.9,23-24.6c3.7-1.2,7.8-2.2,12.2-2.9
C165.1,156.4,170.4,156,176,156z"></path>
<path id="mouth2" style="visibility: hidden;" d="M250.172 416c-59.621 0-111.929-32.14-141.446-80.476 35.205 27.53 97.267 32.905 162.644 19.989 70.124-13.853 124.555-45.771 144.227-88.297-10.827 83.98-80.759 148.784-165.425 148.784z"></path>
C165.1,156.4,170.4,156,176,156"></path>
<path id="mouth2" style="visibility: hidden;" d="M250.172 416c-59.621 0-111.929-32.14-141.446-80.476 35.205 27.53 97.267 32.905 162.644 19.989 70.124-13.853 124.555-45.771 144.227-88.297-10.827 83.98-80.759 148.784-165.425 148.784"></path>
</mask>
</defs>
<path id="rectangle-container2" fill="#e91b1f" mask="url(#symbol2)" d="M426.7,0H85.3C38.4,0,0,38.4,0,85.3v341.3c0,47,38.4,85.3,85.3,85.3h341.3
c46.9,0,85.3-38.4,85.3-85.3V85.3C512,38.4,473.6,0,426.7,0z"></path>
<path id="circle-container2" style="visibility: hidden;" d="M0,256c0,100.9,59.8,165.3,72,177.9c11.2,11.6,77.7,78.1,184,78.1c14.5,0,115.8-1.7,190.7-85.3
C510.1,356,512,274.1,512,256c0-18.9-2.1-96.7-61-165.9C375.7,1.8,269.4,0,256,0C241,0,141.3,1.7,66.6,83.7C1.9,154.8,0,237.9,0,256 z"></path>
c46.9,0,85.3-38.4,85.3-85.3V85.3C512,38.4,473.6,0,426.7,0"></path>
<path id="circle-container2" style="visibility: hidden;" d="M0,256c0,100.9,59.8,165.3,72,177.9c9.1,9.4,34.7,34.4,75.6,53.5c50.6,23.7,95,24.6,108.4,24.6
c10.9,0,61.3-0.9,117.6-30c42.1-21.8,67.4-49,73.1-55.3c64-70.6,65.3-157,65.3-170.7c0-18.9-2.1-96.7-61-165.9
c-8.6-10.2-37.3-42-86-65C313.6,0.9,268.6,0,256,0c-11,0-61.8,0.8-118.2,30.1C97.1,51.3,72.4,77.3,66.6,83.7C1.3,154.7,0,243,0,256"></path>
</svg>
<div class="example-buttons">
<a id="compliMorphBtn" class="btn btn-green" href="javascript:void(0)">Start</a>
@ -342,8 +374,8 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
path strings among other issues. You can try the <a href="https://thednp.github.io/svg-path-commander/">SVGPathCommander demo page</a> to prepare your path strings.</li>
<li>Since animation works only with <code>path</code> <b>SVGElement</b>s, you might need a <a href="https://github.com/Waest/SVGPathConverter" target="_blank">convertToPath</a> utility.</li>
<li>Both SVG morph components will always animate first sub-path from both starting and ending shapes, and for any case hopefully this demo will guide you in mastering the technique.</li>
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or something like <a href="https://github.com/fontello/svgpath">SVGPath</a> tools to
apply a scale transformation to your shapes' path commands.</li>
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or <a href="https://github.com/Waest/SVGPathConverter">SVGPathCommander</a>
to apply a scale transformation to your shapes' path commands.</li>
<li>The <b>SVG Cubic Morph</b> component WILL NOT animate paths with sub-paths as of KUTE.js version 2.0.14, hopefuly this guide will help you break the ice.</li>
<li>Compared to <a href="svgMorph.html">svgMorph</a>, this component can be more memory efficient, as we're dealing with significantly less interpolation points which translates directly
into better performance and the shapes never show any sign of "polygon artifacts".</li>
@ -373,10 +405,11 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
<!-- JavaScript =============================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="./src/polyfill.min.js"></script>
<!-- <script src="./src/kute-extra.js"></script> -->
<script src="./src/kute-extra.min.js"></script>
<script src="./assets/js/svgCubicMorph.js"></script>
<script src="./assets/js/prism.js"></script>
<script src="./assets/js/scripts.js"></script>
<script src="./assets/js/svgCubicMorph.js"></script>
</body>

View file

@ -89,8 +89,8 @@
<div class="col9 border">
<p class="lead condensed">The KUTE.js <b>SVG Morph</b> component enables animation for the <b>d</b> (description) presentation attribute and is one of the most important in all the
SVG components.</p>
<p>It only applies to inline <b>SVGPathElement</b> shapes and doesn't care if these shapes are closed (their <b>d</b> attribute ends with <b>Z</b> path command). On initialization
or animation start, depending on the chosen KUTE.js method, it will <a href="http://phrogz.net/SVG/convert_path_to_polygon.xhtml" target="_blank">sample a number of points</a>
<p>It only works with inline <b>SVGPathElement</b> shapes and the presentation is always the same when shapes are closed or not (their <b>d</b> attribute ends with <b>Z</b> path command).
On initialization or animation start, depending on the chosen KUTE.js method, it will <a href="http://phrogz.net/SVG/convert_path_to_polygon.xhtml" target="_blank">sample a number of points</a>
along the two paths based on a default / given sample size and will create two arrays of coordinates we need for interpolation.</p>
<p>This component was originally inspired by a <a href="http://bl.ocks.org/mbostock/3081153" target="_blank">D3.js path morphing example</a> and now implements a set of
<a href="https://github.com/d3/d3-polygon">D3 polygon</a> geometric operations and other functionalities from <a href="https://github.com/veltman/flubber">flubber</a> to
@ -98,7 +98,7 @@
<p>While in some cases you might be able to create SVG morphing animations via CSS3 <i>transition</i>, this component was developed to provide various solutions for working
with complex shapes, bringing convenience, resources and clarity to one of the most complex types of animation.</p>
<p>All path processing is powered by our <a href="https://github.com/thednp/svg-path-commander">SVGPathCommander</a> starting KUTE.js version 2.0.14, which aims to modernize and
improve the path processing and enable transition from closed to and from un-closed shapes.</p>
improve the path processing and enable you to prepare your path strings in Node.js.</p>
</div>
</div>
@ -166,7 +166,7 @@ var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864
<pre><code class="language-markup">&lt;svg id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
&lt;path id="line" fill="transparent" stroke="orange" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300"/>
&lt;path id="star" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
&lt;path id="circle" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
&lt;/svg>
</code></pre>
@ -181,12 +181,12 @@ var tween = KUTE.to('#line', { path: '#circle' }).start();
<div class="featurettes">
<svg class="example-box-model example-box" id="morph-example-closed" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line" fill="transparent" stroke="#FF5722" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300Z"/>
<path id="line" fill="transparent" stroke="#FF5722" stroke-linejoin="round" stroke-width="15" d="M10 300L590 300Z"/>
<path id="circle" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
</svg>
<svg class="example-box-model example-box" id="morph-example-closed1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="line1" fill="transparent" stroke="#4CAF50" stroke-linejoin="round" stroke-width="10" d="M10 300L590 300"/>
<path id="circle1" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0z"/>
<path id="line1" fill="transparent" stroke="#4CAF50" stroke-linejoin="round" stroke-width="15" d="M10 300L590 300"/>
<path id="circle1" style="visibility:hidden" d="M10,300a290,290 0 1,0 580,0a290,290 0 1,0 -580,0"/>
</svg>
<div class="example-buttons">
<a id="morphBtnClosed" class="btn btn-green" href="javascript:void(0)">Start</a>
@ -383,8 +383,8 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
<li>Since <b>SVG Morph</b> animation works only with <code>path</code> elements, you might need a <code>convertToPath</code> feature, so
<a href="https://github.com/Waest/SVGPathConverter" target="_blank">grab one here</a>.</li>
<li>Both SVG morph components will always animate first sub-path from both starting and ending shapes, and for any case hopefully this demo will guide you in mastering the technique.</li>
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or something like <a href="https://github.com/fontello/svgpath">SVGPath</a> tools to
apply a scale transformation to your shapes' path commands.</li>
<li>In some cases your start and end shapes don't have a very close size, you can use your vector graphics editor of choice or <a href="https://github.com/Waest/SVGPathConverter">SVGPathCommander</a>
to apply a scale transformation to your shapes' path commands.</li>
<li>The morphing animation is expensive so try to optimize the number of morph animations that run at the same time. When morphing sub-paths/multi-paths instead of cloning shapes to have same number
of shapes in both starting and ending shapes, you should also consider a fade and/or scale animation to improve the overal animation performance, mobile devices still don't do very much, regardless
of the advertising.</li>
@ -419,7 +419,8 @@ var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
<!-- Placed at the end of the document so the pages load faster -->
<script src="./src/polyfill.min.js"></script>
<script src="./src/kute.min.js"></script>
<!-- <script src="./src/kute.min.js"></script> -->
<script src="../dist/kute.js"></script>
<script src="./assets/js/prism.js"></script>
<script src="./assets/js/scripts.js"></script>
<script src="./assets/js/svgMorph.js"></script>

View file

@ -148,29 +148,29 @@
<pre><code class="language-javascript">// using the svgTransform property works in all SVG enabled browsers
var tween2 = KUTE.to(
'shape', // target
{ // to
'shape', // target
{ // to
svgTransform: {
translate: [150,100],
rotate: 45,
skewX: 15, skewY: 20,
scale: 1.5
}
}
}
);
// transformMatrix can animate SVGElement targets on modern browsers
// requires adding styling like `transform-origin:50% 50%` to the target element
var tween1 = KUTE.to(
'shape', // target
{ // to
'shape', // target
{ // to
transform: {
translate3d: [150,100,0],
rotate3d: [0,0,45],
skew: [15,20],
scale3d: [1.5,1.5,1]
}
}
}
);
</code></pre>

View file

@ -208,14 +208,14 @@ var tween2 = KUTE.fromTo('selector1',{skewY:0},{skewY:45}).start();
<p>If you check the <a href="http://codepen.io/thednp/pen/avZrYo" target="_blank">test here</a>, you will notice that only the <code>skewY</code> is going to work and no rotation. Now let's do this properly.</p>
<pre><code class="language-javascript">var tween1 = KUTE.fromTo(
'selector1', // element
{pespective:200,translateX:0, rotateX:0, rotateY:0, rotateZ:0}, // from
{pespective:200,translateX:250, rotateX:360, rotateY:15, rotateZ:5} // to
'selector1', // element
{pespective:200,translateX:0, rotateX:0, rotateY:0, rotateZ:0}, // from
{pespective:200,translateX:250, rotateX:360, rotateY:15, rotateZ:5} // to
);
var tween2 = KUTE.fromTo(
'selector2', // element
{translateX:0, rotateX:0, rotateY:0, rotateZ:0}, // from
{translateX:-250, rotateX:360, rotateY:15, rotateZ:5} // to
'selector2', // element
{translateX:0, rotateX:0, rotateY:0, rotateZ:0}, // from
{translateX:-250, rotateX:360, rotateY:15, rotateZ:5} // to
);
</code></pre>

800
dist/kute.esm.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

804
dist/kute.js vendored

File diff suppressed because it is too large Load diff

4
dist/kute.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{
"name": "kute.js",
"version": "2.0.15",
"version": "2.0.16",
"description": "JavaScript animation engine of the future is called KUTE.js.",
"main": "dist/kute.min.js",
"module": "dist/kute.esm.js",
@ -57,16 +57,15 @@
"cubic-bezier-easing": "^1.0.2",
"minifill": "^0.0.14",
"shorter-js": "^0.1.4",
"d3-polygon": "^2.0.0",
"svg-path-commander": "^0.0.6"
"svg-path-commander": "0.0.9"
},
"devDependencies": {
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"npm-run-all": "^4.1.5",
"rollup": "^2.26.9",
"rollup": "^2.28.1",
"rollup-plugin-cleanup": "^3.1.1",
"rollup-plugin-terser": "^7.0.1"
"rollup-plugin-terser": "^7.0.2"
}
}

View file

@ -18,28 +18,28 @@ function replaceUppercase (a) { return a.replace(/[A-Z]/g, "-$&").toLowerCase();
// Component Functions
export function getAttr(tweenProp,value){
const attrStartValues = {};
for (const attr in value){
const attribute = replaceUppercase(attr).replace(/_+[a-z]+/,''); // get the value for 'fill-opacity' not fillOpacity, also 'width' not the internal 'width_px'
const currentValue = this.element.getAttribute(attribute);
let attrStartValues = {};
for (let attr in value){
let attribute = replaceUppercase(attr).replace(/_+[a-z]+/,''), // get the value for 'fill-opacity' not fillOpacity, also 'width' not the internal 'width_px'
currentValue = this.element.getAttribute(attribute);
attrStartValues[attribute] = svgColors.includes(attribute) ? (currentValue || 'rgba(0,0,0,0)') : (currentValue || (/opacity/i.test(attr) ? 1 : 0));
}
return attrStartValues;
}
export function prepareAttr(tweenProp,attrObj){ // attr (string),attrObj (object)
const attributesObject = {};
for ( const p in attrObj ) {
const prop = replaceUppercase(p);
const regex = /(%|[a-z]+)$/;
const currentValue = this.element.getAttribute(prop.replace(/_+[a-z]+/,''));
let attributesObject = {};
for ( let p in attrObj ) {
let prop = replaceUppercase(p),
regex = /(%|[a-z]+)$/,
currentValue = this.element.getAttribute(prop.replace(/_+[a-z]+/,''));
if ( !svgColors.includes(prop)) {
if ( currentValue !== null && regex.test(currentValue) ) { // attributes set with unit suffixes
const unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u;
const suffix = /%/.test(unit) ? '_percent' : `_${unit}`;
let unit = trueDimension(currentValue).u || trueDimension(attrObj[p]).u,
suffix = /%/.test(unit) ? '_percent' : `_${unit}`;
onStart[ComponentName][prop+suffix] = function(tp) { // most "unknown" attributes cannot register into onStart, so we manually add them
if ( this.valuesEnd[tweenProp] && this.valuesEnd[tweenProp][tp] && !(tp in attributes) ) {
attributes[tp] = (elem, p, a, b, v) => {
const _p = p.replace(suffix,'');
let _p = p.replace(suffix,'');
elem.setAttribute(_p, ( (numbers(a.v,b.v,v)*1000>>0)/1000) + b.u );
}
}

View file

@ -9,24 +9,26 @@ import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute.js'
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve.js'
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
import reverseCurve from 'svg-path-commander/src/process/reverseCurve.js'
import createPath from 'svg-path-commander/src/util/createPath.js'
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection.js'
import clonePath from 'svg-path-commander/src/process/clonePath.js'
import splitCubic from 'svg-path-commander/src/process/splitCubic.js'
import splitPath from 'svg-path-commander/src/process/splitPath.js'
import getSegCubicLength from 'svg-path-commander/src/util/getSegCubicLength.js'
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot.js'
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
// Component Util
function getCurveArray(pathString){
return pathToCurve(splitPath(pathToString(pathToAbsolute(pathString)))[0]).map((x,i,pathArray)=>{
let curveToPath = i ? [['M'].concat(pathArray[i-1].slice(-2))].concat([x]) : [],
curveLength = i ? createPath(pathToString(clonePath(curveToPath))).getTotalLength() : 0,
subsegs = i ? (curveLength ? splitCubic( pathArray[i-1].slice(-2).concat(x.slice(1)) ) : [x,x]) : [x];
return pathToCurve(splitPath(pathToString(pathToAbsolute(pathString)))[0]).map((segment,i,pathArray)=>{
let segmentData = i && pathArray[i-1].slice(-2).concat(segment.slice(1)),
curveLength = i ? getSegCubicLength.apply(0, segmentData ) : 0,
subsegs = i ? (curveLength ? splitCubic( segmentData ) : [segment,segment]) : [segment]; // must be [segment,segment]
return {
seg: x,
subsegs: subsegs,
length: curveLength
s: segment,
ss: subsegs,
l: curveLength
}
})
}
@ -36,19 +38,19 @@ function equalizeSegments(path1,path2,TL){
c2 = getCurveArray(path2),
L1 = c1.length,
L2 = c2.length,
l1 = c1.filter(x=>x.length).length,
l2 = c2.filter(x=>x.length).length,
m1 = c1.filter(x=>x.length).reduce((a,{length})=>a+length,0) / l1 || 0,
m2 = c2.filter(x=>x.length).reduce((a,{length})=>a+length,0) / l2 || 0,
l1 = c1.filter(x=>x.l).length,
l2 = c2.filter(x=>x.l).length,
m1 = c1.filter(x=>x.l).reduce((a,{l})=>a+l,0) / l1 || 0,
m2 = c2.filter(x=>x.l).reduce((a,{l})=>a+l,0) / l2 || 0,
tl = TL || Math.max(L1,L2),
mm = [m1,m2],
dif = [tl-L1,tl-L2],
result = [c1,c2].map((x,i) => x.length === tl ? x.map(y=>y.seg)
canSplit = 0,
result = [c1,c2].map((x,i) => x.l === tl ? x.map(y=>y.s)
: x.map((y,j) => {
let canSplit = j && dif[i] && y.length >= mm[i],
segResult = canSplit ? y.subsegs : [y.seg]
canSplit = j && dif[i] && y.l >= mm[i]
dif[i] -= canSplit ? 1 : 0
return segResult
return canSplit ? y.ss : [y.s]
}).flat())
return result[0].length === result[1].length ? result : equalizeSegments(result[0],result[1],tl)
@ -73,30 +75,20 @@ function getRotations(a) {
function getRotatedCurve(a,b) {
let segCount = a.length - 1,
linePaths = [],
lineLengths = [],
computedIndex = 0,
sumLensSqrd = 0,
rotations = getRotations(a);
rotations.map((r,i)=>{
let sumLensSqrd = 0,
linePath = createPath('M0,0L0,0'),
linePt1, ll1,
linePt2, ll2,
linePathStr
for (let j = 0; j < segCount; j++) {
linePt1 = a[(i + j) % segCount]; ll1 = linePt1.length
linePt2 = b[ j % segCount]; ll2 = linePt2.length
linePathStr = `M${linePt1[ll1-2]},${linePt1[ll1-1]}L${linePt2[ll2-2]},${linePt2[ll2-1]}`
linePath.setAttribute('d',linePathStr);
sumLensSqrd += Math.pow(linePath.getTotalLength(),2);
linePaths[j] = linePath;
}
a.slice(1).map((s,j) => {
sumLensSqrd += distanceSquareRoot(a[(i+j) % segCount].slice(-2),b[j % segCount].slice(-2))
})
lineLengths[i] = sumLensSqrd
sumLensSqrd = 0
})
let computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths))
computedIndex = lineLengths.indexOf(Math.min.apply(null,lineLengths))
return rotations[computedIndex]
}
@ -131,6 +123,7 @@ function crossCheckCubicMorph(tweenProp){
path2 = this.valuesEnd[tweenProp].original,
curves = equalizeSegments(path1,path2),
curve0 = getDrawDirection(curves[0]) !== getDrawDirection(curves[1]) ? reverseCurve(curves[0]) : clonePath(curves[0])
this.valuesStart[tweenProp].curve = curve0;
this.valuesEnd[tweenProp].curve = getRotatedCurve(curves[1],curve0)
}
@ -156,7 +149,7 @@ const svgCubicMorph = {
Util: {
pathToCurve, pathToAbsolute, pathToString, parsePathString,
getRotatedCurve, getRotations, equalizeSegments,
reverseCurve, createPath, clonePath, getDrawDirection,
reverseCurve, clonePath, getDrawDirection,
splitCubic, getCurveArray
}
}

View file

@ -66,15 +66,15 @@ function getEllipseLength(el) { // returns the length of an ellipse
}
function getTotalLength(el) { // returns the result of any of the below functions
if (/rect/.test(el.tagName)) {
if ('rect'===el.tagName) {
return getRectLength(el);
} else if (/circle/.test(el.tagName)) {
} else if ('circle'===el.tagName) {
return getCircleLength(el);
} else if (/ellipse/.test(el.tagName)) {
} else if ('ellipse'===el.tagName) {
return getEllipseLength(el);
} else if (/polygon|polyline/.test(el.tagName)) {
} else if (['polygon,polyline'].indexOf(el.tagName)>-1) {
return getPolyLength(el);
} else if (/line/.test(el.tagName)) {
} else if ('line'===el.tagName) {
return getLineLength(el);
}
}

View file

@ -4,14 +4,18 @@ import Components from '../objects/components.js'
import coords from '../interpolation/coords.js'
import {onStartSVGMorph} from './svgMorphBase.js'
import pathToAbsolute from 'svg-path-commander/src/convert/pathToAbsolute.js'
import pathToCurve from 'svg-path-commander/src/convert/pathToCurve.js'
import pathToString from 'svg-path-commander/src/convert/pathToString.js'
import normalizePath from 'svg-path-commander/src/process/normalizePath.js'
import splitPath from 'svg-path-commander/src/process/splitPath.js'
import roundPath from 'svg-path-commander/src/process/roundPath.js'
import invalidPathValue from 'svg-path-commander/src/util/invalidPathValue.js'
import createPath from 'svg-path-commander/src/util/createPath.js'
import polygonArea from 'd3-polygon/src/area.js'
import polygonLength from 'd3-polygon/src/length.js'
import getPathLength from 'svg-path-commander/src/util/getPathLength.js'
import getPointAtLength from 'svg-path-commander/src/util/getPointAtLength.js'
import getDrawDirection from 'svg-path-commander/src/util/getDrawDirection.js'
import epsilon from 'svg-path-commander/src/math/epsilon.js'
import midPoint from 'svg-path-commander/src/math/midPoint.js'
import distanceSquareRoot from 'svg-path-commander/src/math/distanceSquareRoot.js'
// const SVGMorph = { property : 'path', defaultValue: [], interpolators: {numbers,coords} }, functions = { prepareStart, prepareProperty, onStart, crossCheck }
@ -22,73 +26,65 @@ import polygonLength from 'd3-polygon/src/length.js'
// original script flubber
// https://github.com/veltman/flubber
function isFiniteNumber(number) {
return typeof number === "number" && isFinite(number);
}
function distanceSquareRoot(a, b) {
return Math.sqrt(
(a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])
);
}
function pointAlong(a, b, pct) {
return [a[0] + (b[0] - a[0]) * pct, a[1] + (b[1] - a[1]) * pct];
}
function samePoint(a, b) {
return distanceSquareRoot(a, b) < 1e-9;
function polygonLength(ring){
return ring.reduce((length, point, i) =>
i ? length + distanceSquareRoot(ring[i-1],point) : 0, 0 )
}
function pathStringToRing(str, maxSegmentLength) {
let parsed = pathToAbsolute(str);
let parsed = normalizePath(str,0)
return exactRing(parsed) || approximateRing(parsed, maxSegmentLength);
}
function exactRing(segments) {
let ring = [];
function exactRing(pathArray) {
let ring = [],
segment = [], pathCommand = '',
pathlen = pathArray.length,
pathLength = 0;
if (!segments.length || segments[0][0] !== "M") {
if (!pathArray.length || pathArray[0][0] !== "M") {
return false;
}
for (let i = 0; i < segments.length; i++) {
let [command, x, y] = segments[i];
if ((command === "M" && i) || command === "Z") {
for (let i = 0; i < pathlen; i++) {
segment = pathArray[i]
pathCommand = segment[0]
if (pathCommand === "M" && i || pathCommand === "Z") {
break; // !!
} else if (command === "M" || command === "L") {
ring.push([x, y]);
} else if (command === "H") {
ring.push([x, ring[ring.length - 1][1]]);
} else if (command === "V") {
ring.push([ring[ring.length - 1][0], x]);
} else if ('ML'.indexOf( pathCommand) > -1) {
ring.push([segment[1], segment[2]]);
} else {
return false;
}
}
return ring.length ? { ring } : false;
pathLength = polygonLength(ring)
return pathlen ? { ring, pathLength } : false;
}
function approximateRing(parsed, maxSegmentLength) {
let ringPath = splitPath(pathToString(parsed))[0],
ring = [], len, testPath, numPoints = 3;
curvePath = pathToCurve(ringPath,4),
pathLength = getPathLength(curvePath),
ring = [], numPoints = 3, point;
if (!ringPath) {
throw (invalidPathValue);
}
testPath = createPath(ringPath);
len = testPath.getTotalLength();
if (
maxSegmentLength &&
isFiniteNumber(maxSegmentLength) &&
maxSegmentLength > 0
) {
numPoints = Math.max(numPoints, Math.ceil(len / maxSegmentLength));
if ( maxSegmentLength && !isNaN(maxSegmentLength) && +maxSegmentLength > 0 ) {
numPoints = Math.max(numPoints, Math.ceil(pathLength / maxSegmentLength));
}
for (let i = 0; i < numPoints; i++) {
let p = testPath.getPointAtLength((len * i) / numPoints);
ring.push([p.x, p.y]);
point = getPointAtLength(curvePath,pathLength * i / numPoints)
ring.push([point.x, point.y]);
}
// Make all rings clockwise
if (!getDrawDirection(curvePath)) {
ring.reverse();
}
return {
pathLength,
ring,
skipBisect: true
};
@ -116,16 +112,20 @@ function rotateRing(ring, vs) {
}
}
function addPoints(ring, numPoints) {
const desiredLength = ring.length + numPoints,
let desiredLength = ring.length + numPoints,
// step = ring.pathLength / numPoints;
step = polygonLength(ring) / numPoints;
let i = 0, cursor = 0, insertAt = step / 2;
let i = 0, cursor = 0, insertAt = step / 2, a, b, segment;
while (ring.length < desiredLength) {
let a = ring[i], b = ring[(i + 1) % ring.length], segment = distanceSquareRoot(a, b);
a = ring[i]
b = ring[(i + 1) % ring.length]
// console.log(step,a,b)
segment = distanceSquareRoot(a, b)
if (insertAt <= cursor + segment) {
ring.splice( i + 1, 0, segment ? pointAlong(a, b, (insertAt - cursor) / segment) : a.slice(0) );
ring.splice( i + 1, 0, segment ? midPoint(a, b, (insertAt - cursor) / segment) : a.slice(0) );
insertAt += step;
continue;
}
@ -135,67 +135,52 @@ function addPoints(ring, numPoints) {
}
}
function bisect(ring, maxSegmentLength = Infinity) {
let a = [], b = []
for (let i = 0; i < ring.length; i++) {
let a = ring[i], b = i === ring.length - 1 ? ring[0] : ring[i + 1];
a = ring[i], b = i === ring.length - 1 ? ring[0] : ring[i + 1];
// Could splice the whole set for a segment instead, but a bit messy
while (distanceSquareRoot(a, b) > maxSegmentLength) {
b = pointAlong(a, b, 0.5);
b = midPoint(a, b, 0.5);
ring.splice(i + 1, 0, b);
}
}
}
function normalizeRing(ring, maxSegmentLength) {
let points, area, skipBisect;
let points, skipBisect, pathLength;
if (typeof ring === "string") {
let converted = pathStringToRing(ring, maxSegmentLength);
ring = converted.ring;
skipBisect = converted.skipBisect;
let converted = pathStringToRing(ring, maxSegmentLength)
ring = converted.ring
skipBisect = converted.skipBisect
pathLength = converted.pathLength
} else if (!Array.isArray(ring)) {
throw (invalidPathValue);
throw (invalidPathValue)
}
points = ring.slice(0);
points = ring.slice(0)
points.pathLength = pathLength
if (!validRing(points)) {
throw (invalidPathValue);
throw (invalidPathValue)
}
// TODO skip this test to avoid scale issues?
// Chosen epsilon (1e-6) is problematic for small coordinate range
if (points.length > 1 && samePoint(points[0], points[points.length - 1])) {
points.pop();
// 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()
}
area = polygonArea(points);
// Make all rings clockwise
if (area > 0) {
points.reverse();
if ( !skipBisect && maxSegmentLength && !isNaN(maxSegmentLength) && (+maxSegmentLength) > 0 ) {
bisect(points, maxSegmentLength)
}
if (
!skipBisect &&
maxSegmentLength &&
isFiniteNumber(maxSegmentLength) &&
maxSegmentLength > 0
) {
bisect(points, maxSegmentLength);
}
return points;
return points
}
function validRing(ring) {
return ring.every(function(point) {
return (
Array.isArray(point) &&
point.length >= 2 &&
isFiniteNumber(point[0]) &&
isFiniteNumber(point[1])
);
});
return Array.isArray(ring) && ring.every( point =>
Array.isArray(point) && point.length === 2 && !isNaN(point[0]) && !isNaN(point[1]))
}
function getInterpolationPoints(pathArray1, pathArray2, morphPrecision) {
@ -207,8 +192,9 @@ function getInterpolationPoints(pathArray1, pathArray2, morphPrecision) {
addPoints(fromRing, diff < 0 ? diff * -1 : 0);
addPoints(toRing, diff > 0 ? diff : 0);
rotateRing(fromRing, toRing);
return [fromRing,toRing]
rotateRing(fromRing,toRing);
return [roundPath(fromRing),roundPath(toRing)]
}
@ -242,7 +228,6 @@ function crossCheckSVGMorph(prop){
// process morphPrecision
morphPrecision = this._morphPrecision ? parseInt(this._morphPrecision) : defaultOptions.morphPrecision,
paths = getInterpolationPoints(p1,p2,morphPrecision);
this.valuesStart[prop].pathArray = paths[0];
this.valuesEnd[prop].pathArray = paths[1];
}
@ -270,10 +255,10 @@ const svgMorph = {
Util: {
addPoints,bisect,normalizeRing,validRing, // component
getInterpolationPoints,pathStringToRing,
isFiniteNumber,distanceSquareRoot,pointAlong,samePoint,
exactRing,approximateRing,createPath,rotateRing,
pathToAbsolute,pathToString, // svg-path-commander
polygonLength,polygonArea // d3-polygon
distanceSquareRoot,midPoint,
approximateRing,rotateRing,
pathToString,pathToCurve,// svg-path-commander
getPathLength,getPointAtLength,getDrawDirection,roundPath
}
}

View file

@ -10,7 +10,7 @@ import Selector from './util/selector.js'
import Animation from './animation/animationBase.js'
// TweenConstructor
import TweenBase from './tween/tweenBase.js'
import Tween from './tween/tweenBase.js'
// Interface only fromTo
import fromTo from './interface/fromTo.js'
@ -36,7 +36,7 @@ export default {
// Move
},
TweenBase,
Tween,
fromTo,
Objects,

View file

@ -11,7 +11,7 @@ import Easing from './easing/easing-bezier.js'
import Selector from './util/selector.js'
// TweenConstructor
import TweenExtra from './tween/tweenExtra.js'
import Tween from './tween/tweenExtra.js'
import TweenCollection from './tween/tweenCollection.js'
import ProgressBar from './util/progressBar.js'
// interface
@ -28,8 +28,8 @@ import BorderRadius from './components/borderRadius.js'
import BoxModel from './components/boxModel.js'
import ClipProperty from './components/clipProperty.js'
import ColorProperties from './components/colorProperties.js'
import HTMLAttributes from './components/htmlAttributes.js'
import FilterEffects from './components/filterEffects'
import HTMLAttributes from './components/htmlAttributes.js'
import OpacityProperty from './components/opacityProperty.js'
import SVGDraw from './components/svgDraw.js'
import SVGCubicMorph from './components/svgCubicMorph.js'
@ -38,7 +38,7 @@ import ScrollProperty from './components/scrollProperty.js'
import ShadowProperties from './components/shadowProperties.js'
import TextProperties from './components/textProperties.js'
import TextWriteProperties from './components/textWrite.js'
import matrixTransform from './components/transformMatrix.js'
import MatrixTransform from './components/transformMatrix.js'
for (let component in Components) {
let compOps = Components[component]
@ -50,7 +50,7 @@ export default {
Components,
// Tween Interface
TweenExtra,
Tween,
fromTo,
to,
// Tween Collection

View file

@ -23,15 +23,24 @@ import allFromTo from './interface/allFromTo.js'
import Animation from './animation/animation.js'
// components
import EssentialBoxModel from './components/boxModelEssential.js'
import ColorsProperties from './components/colorProperties.js'
import HTMLAttributes from './components/htmlAttributes.js'
import OpacityProperty from './components/opacityProperty.js'
import TextWrite from './components/textWrite.js'
import TransformFunctions from './components/transformFunctions.js'
// import TransformFunctions from './components/transformLegacy.js'
import SVGDraw from './components/svgDraw.js'
import SVGMorph from './components/svgMorph.js'
// import EssentialBoxModel from './components/boxModelEssential.js'
// import ColorsProperties from './components/colorProperties.js'
// import HTMLAttributes from './components/htmlAttributes.js'
// import OpacityProperty from './components/opacityProperty.js'
// import TextWrite from './components/textWrite.js'
// import TransformFunctions from './components/transformFunctions.js'
// // import TransformFunctions from './components/transformLegacy.js'
// import SVGDraw from './components/svgDraw.js'
// import SVGMorph from './components/svgMorph.js'
import './components/boxModelEssential.js'
import './components/colorProperties.js'
import './components/htmlAttributes.js'
import './components/opacityProperty.js'
import './components/textWrite.js'
import './components/transformFunctions.js'
// import './components/transformLegacy.js'
import './components/svgDraw.js'
import './components/svgMorph.js'
// init components
for (let component in Components) {

View file

@ -4,15 +4,15 @@ import defaultValues from '../objects/defaultValues.js'
// prepareObject - returns all processed valuesStart / valuesEnd
export default function (obj, fn) { // this, props object, type: start/end
const propertiesObject = fn === 'start' ? this.valuesStart : this.valuesEnd
let propertiesObject = fn === 'start' ? this.valuesStart : this.valuesEnd
for ( const component in prepareProperty ) {
for ( let component in prepareProperty ) {
let prepareComponent = prepareProperty[component],
supportComponent = supportedProperties[component]
for ( const tweenCategory in prepareComponent ) {
for ( let tweenCategory in prepareComponent ) {
let transformObject = {}
for (const tweenProp in obj) {
for (let tweenProp in obj) {
if ( defaultValues[tweenProp] && prepareComponent[tweenProp] ) { // scroll, opacity, other components
propertiesObject[tweenProp] = prepareComponent[tweenProp].call(this,tweenProp,obj[tweenProp]);