Final version 1.5 commit.
This commit is contained in:
parent
b7b82afb6c
commit
d972e26f59
|
@ -9,7 +9,7 @@ morphBtn.addEventListener('click', function(){
|
|||
}, false);
|
||||
|
||||
var morphTween1 = KUTE.to('#rectangle1', { path: '#star1' }, {
|
||||
showMorphInfo: true, morphIndex: 79,
|
||||
showMorphInfo: true, morphIndex: 73,
|
||||
duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'
|
||||
});
|
||||
|
||||
|
@ -18,6 +18,37 @@ morphBtn1.addEventListener('click', function(){
|
|||
!morphTween1.playing && morphTween1.start();
|
||||
}, false);
|
||||
|
||||
// polygon morph
|
||||
var morphTween21 = KUTE.fromTo('#triangle', {path: '#triangle', fill: '#673AB7'}, { path: '#square', fill: '#2196F3' }, {
|
||||
duration: 1500, easing: 'easingCubicOut',
|
||||
});
|
||||
var morphTween22 = KUTE.fromTo('#triangle', {path: '#square', fill: '#2196F3'}, { path: '#star2', fill: 'deeppink' }, {
|
||||
morphIndex: 9,
|
||||
delay: 500, duration: 1500, easing: 'easingCubicOut'
|
||||
});
|
||||
var morphTween23 = KUTE.fromTo('#triangle', {path: '#star2', fill: 'deeppink'}, { path: '#triangle', fill: '#673AB7' }, {
|
||||
delay: 500, duration: 1500, easing: 'easingCubicOut'
|
||||
});
|
||||
|
||||
morphTween21.chain(morphTween22);
|
||||
morphTween22.chain(morphTween23);
|
||||
morphTween23.chain(morphTween21);
|
||||
|
||||
var morphBtn2 = document.getElementById('morphBtn2');
|
||||
morphBtn2.addEventListener('click', function(){
|
||||
if ( !morphTween21.playing && !morphTween22.playing && !morphTween23.playing ) {
|
||||
morphTween21.start(); morphTween21._dl = 500;
|
||||
morphBtn2.innerHTML = 'Stop';
|
||||
morphBtn2.className = 'btn btn-pink';
|
||||
} else {
|
||||
morphTween21.playing && morphTween21.stop(); morphTween21._dl = 0;
|
||||
morphTween22.playing && morphTween22.stop();
|
||||
morphTween23.playing && morphTween23.stop();
|
||||
morphBtn2.innerHTML = 'Start';
|
||||
morphBtn2.className = 'btn btn-green';
|
||||
}
|
||||
}, false);
|
||||
|
||||
|
||||
// simple multi morph
|
||||
var multiMorphBtn = document.getElementById('multiMorphBtn');
|
||||
|
@ -36,10 +67,10 @@ multiMorphBtn.addEventListener('click', function(){
|
|||
|
||||
// complex multi morph
|
||||
var compliMorphBtn = document.getElementById('compliMorphBtn');
|
||||
var compliMorph1 = KUTE.to('#rectangle-container', { path: '#circle-container', fill: "#FF5722" }, { morphPrecision: 10, morphIndex: 161, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph2 = KUTE.to('#symbol-left', { path: '#eye-left', fill: "#fff" }, { morphPrecision: 10, morphIndex: 20, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph3 = KUTE.to('#symbol-left-clone', { path: '#mouth', fill: "#fff" }, { morphPrecision: 10, morphIndex: 8, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph4 = KUTE.to('#symbol-right', { path: '#eye-right', fill: "#fff" }, { morphPrecision: 10, morphIndex: 55, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph1 = KUTE.fromTo('#rectangle-container', {path: '#rectangle-container', fill: "#2196F3"}, { path: '#circle-container', fill: "#FF5722" }, { morphPrecision: 10, morphIndex: 161, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph2 = KUTE.fromTo('#symbol-left', {path: '#symbol-left', fill: "#fff"}, { path: '#eye-left', fill: "#fff" }, { morphPrecision: 10, morphIndex: 20, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph3 = KUTE.fromTo('#symbol-left-clone', {path: '#symbol-left-clone', fill: "#fff"}, { path: '#mouth', fill: "#fff" }, { morphPrecision: 10, morphIndex: 8, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
var compliMorph4 = KUTE.fromTo('#symbol-right', {path: '#symbol-right', fill: "#CDDC39"}, { path: '#eye-right', fill: "#fff" }, { morphPrecision: 10, morphIndex: 55, duration: 2000, repeat: 1, yoyo: true, easing: 'easingCubicOut'});
|
||||
|
||||
compliMorphBtn.addEventListener('click', function(){
|
||||
!compliMorph1.playing && compliMorph1.start();
|
||||
|
@ -56,11 +87,6 @@ var draw2 = KUTE.fromTo('#drawSVG',{draw:'0% 10%'}, {draw:'90% 100%'}, {duration
|
|||
var draw3 = KUTE.fromTo('#drawSVG',{draw:'90% 100%'}, {draw:'100% 100%'}, {duration: 1500, easing: "easingCubicIn"});
|
||||
var draw4 = KUTE.fromTo('#drawSVG',{draw:'0% 0%'}, {draw:'0% 100%'}, {duration: 3500, easing: "easingBounceOut"});
|
||||
var draw5 = KUTE.fromTo('#drawSVG',{draw:'0% 100%'}, {draw:'50% 50%'}, {duration: 2500, easing: "easingExponentialInOut"});
|
||||
// var draw1 = KUTE.to('#drawSVG', {draw:'0% 10%'}, {duration: 1500, easing: "easingCubicIn"});
|
||||
// var draw2 = KUTE.to('#drawSVG', {draw:'90% 100%'}, {duration: 2500, easing: "easingCubicOut"});
|
||||
// var draw3 = KUTE.to('#drawSVG', {draw:'100% 100%'}, {duration: 1500, easing: "easingCubicIn"});
|
||||
// var draw4 = KUTE.to('#drawSVG', {draw:'0% 100%'}, {duration: 3500, easing: "easingBounceOut"});
|
||||
// var draw5 = KUTE.to('#drawSVG', {draw:'50% 50%'}, {duration: 2500, easing: "easingExponentialInOut"});
|
||||
|
||||
draw1.chain(draw2); draw2.chain(draw3); draw3.chain(draw4); draw4.chain(draw5);
|
||||
|
||||
|
|
2
css.html
2
css.html
|
@ -152,7 +152,7 @@ var tween3 = KUTE.to('selector1',{wordSpacing:50});
|
|||
<pre><code class="language-javascript">KUTE.to('selector1',{borderColor:'rgb(25,25,25)'}).start();
|
||||
KUTE.to('selector1',{borderTopColor:'#069'}).start();
|
||||
KUTE.to('selector1',{borderRightColor:'rgba(25,25,25,0.25)'}).start();
|
||||
KUTE.to('selector1',{borderBottomColor:'#069'}).start();
|
||||
KUTE.to('selector1',{borderBottomColor:'red'}).start(); // IE9+ browsers
|
||||
KUTE.to('selector1',{borderLeftColor:'#069'}).start();
|
||||
KUTE.to('selector1',{outlineColor:'#069'}).start();
|
||||
</code></pre>
|
||||
|
|
|
@ -153,6 +153,14 @@ K.Tween.prototype.restart = function(){
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// methods to queue callbacks with ease
|
||||
K.Tween.prototype.onUpdate = function(){
|
||||
this._uC = arguments;
|
||||
return this;
|
||||
}
|
||||
// _sC = startCallback | _cC = completeCallback | _stC = stopCallback
|
||||
// _pC = pauseCallback | _rC = resumeCallback
|
||||
</code></pre>
|
||||
<p>For some reasons these methods aren't included into the core/plugins by default, but let you decide what you need and how to customize the animation engine for your very secific need.</p>
|
||||
|
||||
|
|
|
@ -92,8 +92,8 @@
|
|||
<li><kbd class="bg-blue">rotate</kbd> is a property used to rotate an element on the Z axis or the plain document. Eg. <code>rotate:250</code> will rotate an element clockwise by 250 degrees. Supported on IE9.</li>
|
||||
<li><kbd class="bg-blue">skewX</kbd> is a property used to apply a skew transformation on the X axis. Eg. <code>skewX:25</code> will skew an element by 25 degrees. Supported on IE9.</li>
|
||||
<li><kbd class="bg-blue">skewY</kbd> is a property used to apply a skew transformation on the Y axis. Eg. <code>skewY:25</code> will skew an element by 25 degrees. Supported on IE9.</li>
|
||||
<li><kbd class="bg-blue">scale</kbd> is a property used to apply a size transformation. Eg. <code>scale:2</code> will enlarge an element by a degree of 2. Supported on IE9.</li>
|
||||
<li><kbd class="bg-red">matrix</kbd> property is not supported.</li>
|
||||
<li><kbd class="bg-blue">scale</kbd> is a property used to apply a single value size transformation. Eg. <code>scale:2</code> will enlarge an element by a degree of 2. Supported on IE9.</li>
|
||||
<li><kbd class="bg-red">matrix</kbd>, double axis <kbd class="bg-red">skew</kbd> and double axis <kbd class="bg-red">scale</kbd> properties are not supported.</li>
|
||||
</ul>
|
||||
|
||||
<h3>3D Transform Properties</h3>
|
||||
|
@ -106,7 +106,7 @@
|
|||
<li><kbd class="bg-blue">rotateX</kbd> property rotates an element on the X axis in a given 3D field. Eg. <code>rotateX:250</code> will rotate an element clockwise by 250 degrees. Modern browsers only and requires perspective.</li>
|
||||
<li><kbd class="bg-blue">rotateY</kbd> property rotates an element on the Y axis in a given 3D field. Eg. <code>rotateY:-150</code> will rotate an element counter-clockwise by 150 degrees. Modern browsers only and also requires perspective.</li>
|
||||
<li><kbd class="bg-blue">rotateZ</kbd> property rotates an element on the Z axis and is the equivalent of the 2D rotation. Eg. <code>rotateZ:-150</code> will rotate an element counter-clockwise by 150 degrees. Modern browsers only and doesn't require perspective.</li>
|
||||
<li><kbd class="bg-red">rotate3d</kbd> and <kbd class="bg-red">matrix3d</kbd> properties are not supported.</li>
|
||||
<li><kbd class="bg-red">matrix3d</kbd>, <kbd class="bg-red">rotate3d</kbd>, and <kbd class="bg-red">scale3d</kbd> properties are not supported.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Box Model Properties</h3>
|
||||
|
@ -196,7 +196,7 @@
|
|||
</ul>
|
||||
|
||||
<h3>Did We Miss Any Important Property?</h3>
|
||||
<p>Make sure you go to <a href="https://github.com/thednp/kute.js/issues" target="_blank">the issues tracker</a> and report the missing property ASAP.</p>
|
||||
<p>Make sure you go to <a href="https://github.com/thednp/kute.js/issues" target="_blank">the issues tracker</a> and report the missing property ASAP, or you can check the <a href="extend.html">extend</a> guide and learn how to develop a plugin to support a new property yourself.</p>
|
||||
</div>
|
||||
|
||||
<div class="content-wrap">
|
||||
|
@ -210,12 +210,12 @@
|
|||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer>
|
||||
<footer>
|
||||
<div class="content-wrap">
|
||||
<p class="pull-right"><a id="toTop" href="#">Back to top</a></p>
|
||||
<p>© 2007 - 2016 · <a href="http://themeforest.net/user/dnp_theme?ref=dnp_theme">dnp_theme</a>.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
||||
|
||||
</div><!-- /.site-wrapper -->
|
||||
|
||||
|
|
186
src/kute-svg.js
186
src/kute-svg.js
|
@ -23,31 +23,31 @@
|
|||
'use strict';
|
||||
|
||||
var K = window.KUTE, S = S || {}, p,
|
||||
_svg = document.getElementsByTagName('path')[0],
|
||||
_svg = K.selector('path') || K.selector('svg'),
|
||||
_ns = _svg && _svg.ownerSVGElement && _svg.ownerSVGElement.namespaceURI || 'http://www.w3.org/2000/svg',
|
||||
_nm = ['strokeWidth', 'strokeOpacity', 'fillOpacity', 'stopOpacity'], // numeric SVG CSS props
|
||||
_cls = ['fill', 'stroke', 'stopColor'], // colors 'hex', 'rgb', 'rgba' -- #fff / rgb(0,0,0) / rgba(0,0,0,0)
|
||||
trm = function(s){ if (!String.prototype.trim) { return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); } else { return s.trim(); }};
|
||||
pathReg = /(m[^(h|v|l)]*|[vhl][^(v|h|l|z)]*)/gmi;
|
||||
|
||||
if (_svg && !_svg.ownerSVGElement) {return;} // if SVG API is not supported, return
|
||||
|
||||
// SVG MORPH
|
||||
// get path d attribute or create a path with string value
|
||||
S.getPath = function(e){
|
||||
// get path d attribute or create a path from string value
|
||||
S.gPt = function(e){
|
||||
var p = {}, el = typeof e === 'object' ? e : /^\.|^\#/.test(e) ? document.querySelector(e) : null;
|
||||
if ( el && /path|glyph/.test(el.tagName) ) {
|
||||
p.e = S.forcePath(el);
|
||||
p.e = S.fPt(el);
|
||||
p.o = el.getAttribute('d');
|
||||
|
||||
} else if (!el && /[a-z][^a-z]*/ig.test(e)) { // maybe it's a string path already
|
||||
var np = S.createPath(trm(e));
|
||||
var np = S.cP(e.trim());
|
||||
p.e = np;
|
||||
p.o = e;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
S.pathCross = function(w){
|
||||
S.pCr = function(w){ // pathCross
|
||||
// path tween options
|
||||
this._mpr = w.morphPrecision || 25;
|
||||
this._midx = w.morphIndex;
|
||||
|
@ -55,24 +55,45 @@
|
|||
this._rv1 = w.reverseFirstPath;
|
||||
this._rv2 = w.reverseSecondPath;
|
||||
|
||||
var p1 = S.getOnePath(w._vS.path.o), p2 = S.getOnePath(w._vE.path.o), arr;
|
||||
var p1 = S.gOp(w._vS.path.o), p2 = S.gOp(w._vE.path.o), arr;
|
||||
this._isp = !/[CSQTA]/i.test(p1) && !/[CSQTA]/i.test(p2); // both shapes are polygons
|
||||
|
||||
arr = S._pathCross(p1,p2);
|
||||
arr = S._pCr(p1,p2,w._el.parentNode);
|
||||
|
||||
w._vS.path.d = arr[0];
|
||||
w._vE.path.d = arr[1];
|
||||
}
|
||||
|
||||
S._pathCross = function(s,e){
|
||||
s = S.createPath(s); e = S.createPath(e);
|
||||
var arr = S.getSegments(s,e,this._mpr), s1 = arr[0], e1 = arr[1], arL = e1.length, idx;
|
||||
S._pCr = function(s,e,svg){ // _pathCross
|
||||
var s1, e1, arr, idx, arL, sm, lg, smp, lgp, nsm = [], sml, cl = [], len, tl, cs;
|
||||
this._sp = false;
|
||||
|
||||
if (!this._isp) {
|
||||
s = S.cP(s); e = S.cP(e);
|
||||
arr = S.gSegs(s,e,this._mpr);
|
||||
s1 = arr[0]; e1 = arr[1]; arL = e1.length;
|
||||
} else {
|
||||
s = S.pTA(s); e = S.pTA(e);
|
||||
arL = Math.max(s.length,e.length);
|
||||
if ( arL === e.length) { sm = s; lg = e; } else { sm = e; lg = s; }
|
||||
sml = sm.length;
|
||||
|
||||
smp = S.cP('M'+sm.join('L')+'z'); len = smp.getTotalLength() / arL;
|
||||
for (var i=0; i<arL; i++){
|
||||
tl = smp.getPointAtLength(len*i);
|
||||
cs = S.gCP(len,tl,sm);
|
||||
nsm.push( [ cs[0], cs[1] ] );
|
||||
}
|
||||
|
||||
if (arL === e.length) { e1 = lg; s1 = nsm; } else { s1 = lg; e1 = nsm; }
|
||||
}
|
||||
|
||||
// reverse arrays
|
||||
if (this._rv1) { s1.reverse(); }
|
||||
if (this._rv2) { e1.reverse(); }
|
||||
|
||||
// determine index for best/minimum distance between points
|
||||
if (this._smi) { idx = S.getBestIndex(s1,e1); }
|
||||
if (this._smi) { idx = S.gBi(s1,e1); }
|
||||
|
||||
// shift second array to for smallest tween distance
|
||||
if (this._midx) {
|
||||
|
@ -82,7 +103,10 @@
|
|||
|
||||
// the console.log helper utility
|
||||
if (this._smi) {
|
||||
console.log( 'KUTE.js Path Morph Log\nThe morph used ' + arL + ' points to draw both paths based on '+this._mpr+' morphPrecision value.\n'
|
||||
// also show the points
|
||||
S.shP(s1,e1,svg);
|
||||
var mpi = this._isp ? 'the polygon with the most points.\n' : (this._mpr === 25 ? 'the default' : 'your') +' morphPrecision value of '+this._mpr+'.\n';
|
||||
console.log( 'KUTE.js Path Morph Log\nThe morph used ' + arL + ' points to draw both paths based on '+mpi
|
||||
+ (this._midx ? 'You\'ve configured the morphIndex to ' + this._midx + ' while the recommended is ' + idx+ '.\n' : 'You may also consider a morphIndex for the second path. Currently the best index seems to be ' + idx + '.\n')
|
||||
+ (
|
||||
!this._rv1 && !this._rv2 ? 'If the current animation is not satisfactory, consider reversing one of the paths. Maybe the paths do not intersect or they really have different draw directions.' :
|
||||
|
@ -95,93 +119,137 @@
|
|||
return [s1,e1]
|
||||
}
|
||||
|
||||
S.getSegments = function(s,e,r){
|
||||
S.gSegs = function(s,e,r){ // getSegments returns an array of points based on a sample size morphPrecision
|
||||
var s1 = [], e1 = [], le1 = s.getTotalLength(), le2 = e.getTotalLength(), ml = Math.max(le1,le2),
|
||||
d = r, ar = ml / r, j = 0, sl = ar*r; // sl = sample length
|
||||
|
||||
// populate the points arrays based on morphPrecision as sample size
|
||||
while ( (j += r) < sl ) {
|
||||
while ( (j += r) < sl ) { // populate the points arrays based on morphPrecision as sample size
|
||||
s1.push( [s.getPointAtLength(j).x, s.getPointAtLength(j).y]);
|
||||
e1.push( [e.getPointAtLength(j).x, e.getPointAtLength(j).y]);
|
||||
}
|
||||
return [s1,e1];
|
||||
}
|
||||
}
|
||||
|
||||
S.getBestIndex = function(s,e){
|
||||
var s1 = S.clone(s), e1 = S.clone(e), d = [], i, r = [], l = s1.length, t, ax, ay;
|
||||
S.gCP = function(p,t,s){ // getClosestPoint for polygon paths it returns a close point from the original path (length,pointAtLength,smallest); // intervalLength
|
||||
var x, y, a = [], l = s.length, dx, nx, pr;
|
||||
for (i=0; i<l; i++){
|
||||
x = Math.abs(s[i][0] - t.x);
|
||||
y = Math.abs(s[i][1] - t.y);
|
||||
a.push( Math.sqrt( x * x + y * y ) );
|
||||
}
|
||||
dx = a.indexOf(Math.min.apply(null,a));
|
||||
pr = !!s[dx-1] ? dx-1 : l-1;
|
||||
nx = !!s[dx+1] ? dx+1 : 0;
|
||||
return Math.abs(s[pr][0] - t.x) < p && Math.abs(s[pr][1] - t.y) < p ? s[pr]
|
||||
: Math.abs(s[nx][0] - t.x) < p && Math.abs(s[nx][1] - t.y) < p ? s[nx]
|
||||
: Math.abs(s[dx][0] - t.x) < p && Math.abs(s[dx][1] - t.y) < p ? s[dx]
|
||||
: [t.x,t.y];
|
||||
}
|
||||
|
||||
S.shP = function(s,e,v){// showPoints helper function to visualize the points on the path
|
||||
if (!this._sp){
|
||||
var c, a = arguments, cl, p, l;
|
||||
for (var i=0; i<2; i++){
|
||||
p = a[i]; l = p.length; cl = i=== 0 ? { f: 'DeepPink', o: 'HotPink' } : { f: 'Lime', o: 'LimeGreen' };
|
||||
for (var j=0; j<l; j++) {
|
||||
c = document.createElementNS(_ns,'circle');
|
||||
c.setAttribute('cx',p[j][0]); c.setAttribute('cy',p[j][1]);
|
||||
c.setAttribute('r', j===0 ? 20 : 10 ); c.setAttribute('fill', j===0 ? cl.f : cl.o);
|
||||
if (this._isp) { v.appendChild(c); } else if (!this._isp && j===0 ) { v.appendChild(c);}
|
||||
}
|
||||
}
|
||||
this._sp = true; c = null;
|
||||
}
|
||||
}
|
||||
|
||||
S.gBi = function(s,e){ // getBestIndex for shape rotation
|
||||
var s1 = S.clone(s), e1 = S.clone(e), d = [], i, l = e.length, t, ax, ay;
|
||||
for (i=0; i<l; i++){
|
||||
t = e1.splice(i,l-i); e1 = t.concat(e1);
|
||||
ax = Math.abs(s1[i][0] - e1[i][0]);
|
||||
ay = Math.abs(s1[i][1] - e1[i][1]);
|
||||
d.push( Math.sqrt( ax * ax + ay * ay ) );
|
||||
r.push( e1 );
|
||||
e1 = []; e1 = S.clone(e); t = null;
|
||||
}
|
||||
return d.indexOf(Math.min.apply(null,d));
|
||||
}
|
||||
|
||||
S.getOnePath = function(p){
|
||||
S.gOp = function(p){ // getOnePath, first path only
|
||||
var a = p.split(/z/i);
|
||||
if (a.length > 2) {
|
||||
return trm(a[0]) + 'z';
|
||||
} else { return trm(p); }
|
||||
return a[0].trim() + 'z';
|
||||
} else { return p.trim(); }
|
||||
}
|
||||
|
||||
S.createPath = function (p){
|
||||
S.cP = function (p){ // createPath
|
||||
var c = document.createElementNS(_ns,'path'), d = typeof p === 'object' ? p.getAttribute('d') : p;
|
||||
c.setAttribute('d',d); return c;
|
||||
}
|
||||
|
||||
S.forcePath = function(p){
|
||||
S.fPt = function(p){ // forcePath for glyph elements
|
||||
if (p.tagName === 'glyph') { // perhaps we can also change other SVG tags in the future
|
||||
var c = S.createPath(p); p.parentNode.appendChild(c); return c;
|
||||
var c = S.cP(p); p.parentNode.appendChild(c); return c;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
S.clone = function(obj) {
|
||||
S.clone = function(a) {
|
||||
var copy;
|
||||
|
||||
// Handle Array
|
||||
if (obj instanceof Array) {
|
||||
if (a instanceof Array) {
|
||||
copy = [];
|
||||
for (var i = 0, len = obj.length; i < len; i++) {
|
||||
copy[i] = S.clone(obj[i]);
|
||||
for (var i = 0, len = a.length; i < len; i++) {
|
||||
copy[i] = S.clone(a[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Handle Object
|
||||
if (obj instanceof Object) {
|
||||
copy = {};
|
||||
for (var attr in obj) {
|
||||
if (obj.hasOwnProperty(attr)) {
|
||||
copy[attr] = S.clone(obj[attr]);
|
||||
return a;
|
||||
}
|
||||
|
||||
S.pTA = function(p) { // simple pathToAbsolute for polygons
|
||||
var np = p.match(pathReg), wp = [], l = np.length, s, c, r, x = 0, y = 0;
|
||||
for (var i = 0; i<l; i++){
|
||||
np[i] = np[i]; c = np[i][0]; r = new RegExp(c+'[^\\d|\\-]*','i');
|
||||
np[i] = np[i].replace(/(^|[^,])\s*-/g, '$1,-').replace(/(\s+\,|\s|\,)/g,',').replace(r,'').split(',');
|
||||
np[i][0] = parseFloat(np[i][0]);
|
||||
np[i][1] = parseFloat(np[i][1]);
|
||||
if (i === 0) { x+=np[i][0]; y +=np[i][1]; }
|
||||
else {
|
||||
x = np[i-1][0];
|
||||
y = np[i-1][1];
|
||||
if (/l/i.test(c)) {
|
||||
np[i][0] = c === 'l' ? np[i][0] + x : np[i][0];
|
||||
np[i][1] = c === 'l' ? np[i][1] + y : np[i][1];
|
||||
} else if (/h/i.test(c)) {
|
||||
np[i][0] = c === 'h' ? np[i][0] + x : np[i][0];
|
||||
np[i][1] = y;
|
||||
} else if (/v/i.test(c)) {
|
||||
np[i][0] = x;
|
||||
np[i][1] = c === 'v' ? np[i][0] + y : np[i][0];
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
return np;
|
||||
}
|
||||
|
||||
// a shortHand pathCross
|
||||
K.svq = function(w){ if ( w._vE.path ) S.pCr(w); }
|
||||
|
||||
// register the render SVG path object
|
||||
// process path object and also register the render function
|
||||
K.pp['path'] = function(a,o,l) {
|
||||
K.pp['path'] = function(a,o,l) { // K.pp['path']('path',value,element);
|
||||
if (!('path' in K.dom)) {
|
||||
K.dom['path'] = function(w,p,v){
|
||||
var curve =[], i, l;
|
||||
|
||||
K.dom['path'] = function(w,p,v){
|
||||
var points =[], i, l;
|
||||
for(i=0,l=w._vE.path.d.length;i<l;i++) { // for each point
|
||||
curve[i] = [];
|
||||
points[i] = [];
|
||||
for(var j=0;j<2;j++) { // each point coordinate
|
||||
curve[i].push(w._vS.path.d[i][j]+(w._vE.path.d[i][j]-w._vS.path.d[i][j])*v);
|
||||
points[i].push(w._vS.path.d[i][j]+(w._vE.path.d[i][j]-w._vS.path.d[i][j])*v);
|
||||
}
|
||||
}
|
||||
w._el.setAttribute("d", v === 1 ? w._vE.path.o : 'M' + curve.join('L') + 'Z' );
|
||||
w._el.setAttribute("d", v === 1 ? w._vE.path.o : 'M' + points.join('L') + 'Z' );
|
||||
}
|
||||
}
|
||||
return S.getPath(o);
|
||||
return S.gPt(o);
|
||||
};
|
||||
|
||||
K.prS['path'] = function(el,p,v){
|
||||
|
@ -189,14 +257,14 @@
|
|||
};
|
||||
|
||||
// SVG DRAW
|
||||
S.getDraw = function(e,v){
|
||||
S.gDr = function(e,v){
|
||||
var l = e.getTotalLength(), start, end, d, o;
|
||||
if ( v instanceof Object ) {
|
||||
return v;
|
||||
} else if (typeof v === 'string') {
|
||||
v = v.split(/\,|\s/);
|
||||
start = /%/.test(v[0]) ? S.percent(trm(v[0]),l) : parseFloat(v[0]);
|
||||
end = /%/.test(v[1]) ? S.percent(trm(v[1]),l) : parseFloat(v[1]);
|
||||
start = /%/.test(v[0]) ? S.pc(v[0].trim(),l) : parseFloat(v[0]);
|
||||
end = /%/.test(v[1]) ? S.pc(v[1].trim(),l) : parseFloat(v[1]);
|
||||
} else if (typeof v === 'undefined') {
|
||||
o = parseFloat(K.gCS(e,'strokeDashoffset'));
|
||||
d = K.gCS(e,'strokeDasharray').split(/\,/);
|
||||
|
@ -208,7 +276,7 @@
|
|||
return { s: start, e: end, l: l }
|
||||
};
|
||||
|
||||
S.percent = function(v,l){
|
||||
S.pc = function(v,l){
|
||||
return parseFloat(v) / 100 * l;
|
||||
};
|
||||
|
||||
|
@ -226,11 +294,11 @@
|
|||
w._el.style.strokeDasharray = e+o<1 ? '0px, ' + l + 'px' : (e+o) + 'px, ' + l + 'px';
|
||||
}
|
||||
}
|
||||
return S.getDraw(l,o);
|
||||
return S.gDr(l,o);
|
||||
}
|
||||
|
||||
K.prS['draw'] = function(el,p,v){
|
||||
return S.getDraw(el)
|
||||
return S.gDr(el)
|
||||
}
|
||||
|
||||
// SVG CSS Properties
|
||||
|
@ -262,7 +330,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
for ( var i = 0, l = _nm.length; i< l; i++) { // for numeric CSS props SVG related
|
||||
for ( var i = 0, l = _nm.length; i< l; i++) { // for numeric CSS props for SVG elements
|
||||
p = _nm[i];
|
||||
if (p === 'strokeWidth'){
|
||||
K.pp[p] = function(p,v){
|
||||
|
|
234
src/kute.js
234
src/kute.js
|
@ -27,14 +27,15 @@
|
|||
return r ? f + (p.charAt(0).toUpperCase() + p.slice(1)) : p;
|
||||
};
|
||||
|
||||
K.selector = function(el,multi){
|
||||
K.selector = function(el,multi){ // a selector utility
|
||||
var nl;
|
||||
if (multi){
|
||||
nl = typeof el === 'object' && el.length ? el : document.querySelectorAll(el);
|
||||
} else {
|
||||
nl = typeof el === 'object' ? el : /^#/.test(el) ? document.getElementById(el.replace('#','')) : document.querySelector(el);
|
||||
}
|
||||
if (nl === null && el !== 'window') throw new TypeError('Element not found or incorrect selector: '+el); else return nl;
|
||||
if (nl === null && el !== 'window') throw new TypeError('Element not found or incorrect selector: '+el);
|
||||
return nl;
|
||||
};
|
||||
|
||||
var _tch = ('ontouchstart' in window || navigator.msMaxTouchPoints) || false, // support Touch?
|
||||
|
@ -89,9 +90,9 @@
|
|||
};
|
||||
|
||||
K.fromTo = function (el, f, to, o) {
|
||||
var _el = K.selector(el), ft = K.prP(f, to, _el),
|
||||
_vS = ft[0], _vE = ft[1]; o = o || {};
|
||||
return new K.Tween(_el, _vS, _vE, o);
|
||||
var _el = K.selector(el), ft = K.prP(f, to, _el), _vS = ft[0], _vE = ft[1]; o = o || {};
|
||||
var tw = new K.Tween(_el, _vS, _vE, o); K.svg && K.svq(tw); // on init we process the SVG paths
|
||||
return tw;
|
||||
};
|
||||
|
||||
// multiple elements tweening
|
||||
|
@ -173,111 +174,9 @@
|
|||
K.add = function (tw) { _tws.push(tw); };
|
||||
K.remove = function (tw) {
|
||||
var i = _tws.indexOf(tw);
|
||||
if (i !== -1) {
|
||||
_tws.splice(i, 1);
|
||||
}
|
||||
if (i !== -1) { _tws.splice(i, 1); }
|
||||
};
|
||||
K.s = function () { _caf(_t); _t = null; };
|
||||
|
||||
// register functions for the render object K.dom(w, p, w._e(e));
|
||||
K._queue = function (w) {
|
||||
for ( var p in w._vE ) {
|
||||
var cls = _cls.indexOf(p) !== -1,
|
||||
bm = _bm.indexOf(p) !== -1,
|
||||
sc = _sc.indexOf(p) !== -1,
|
||||
op = _op.indexOf(p) !== -1,
|
||||
tf = p === 'transform';
|
||||
if ( bm && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style[p] = (w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v ) + w._vE[p].unit;
|
||||
};
|
||||
} else if (tf && (!(p in K.dom)) ) {
|
||||
|
||||
K.dom[p] = function(w,p,v) {
|
||||
var _tS = '', tP, rps, pps = 'perspective('+w._pp+'px) ';
|
||||
for (tP in w._vE[p]) {
|
||||
var t1 = w._vS[p][tP], t2 = w._vE[p][tP];
|
||||
rps = rps || _3d.indexOf(tP) !== -1 && !_isIE;
|
||||
|
||||
if ( tP === 'translate' ) {
|
||||
var tls = '', ts = {}, ax;
|
||||
|
||||
for (ax in t2){
|
||||
var x1 = t1[ax].value || 0, x2 = t2[ax].value || 0, xu = t2[ax].unit || 'px';
|
||||
ts[ax] = x1===x2 ? x2+xu : (x1 + ( x2 - x1 ) * v) + xu;
|
||||
}
|
||||
tls = t2.x ? 'translate(' + ts.x + ',' + ts.y + ')' :
|
||||
'translate3d(' + ts.translateX + ',' + ts.translateY + ',' + ts.translateZ + ')';
|
||||
|
||||
_tS = (_tS === '') ? tls : (tls + ' ' + _tS);
|
||||
} else if ( tP === 'rotate' ) {
|
||||
var rt = '', rS = {}, rx;
|
||||
|
||||
for ( rx in t2 ){
|
||||
if ( t1[rx] ) {
|
||||
var a1 = t1[rx].value, a2 = t2[rx].value, au = t2[rx].unit||'deg',
|
||||
av = a1 + (a2 - a1) * v;
|
||||
rS[rx] = rx ==='z' ? 'rotate('+av+au+')' : rx + '(' + av + au + ') ';
|
||||
}
|
||||
}
|
||||
rt = t2.z ? rS.z : (rS.rotateX||'') + (rS.rotateY||'') + (rS.rotateZ||'');
|
||||
|
||||
_tS = (_tS === '') ? rt : (_tS + ' ' + rt);
|
||||
} else if (tP==='skew') {
|
||||
var sk = '', sS = {};
|
||||
for ( var sx in t2 ){
|
||||
if ( t1[sx] ) {
|
||||
var s1 = t1[sx].value, s2 = t2[sx].value, su = t2[sx].unit||'deg',
|
||||
sv = s1 + (s2 - s1) * v;
|
||||
sS[sx] = sx + '(' + sv + su + ') ';
|
||||
}
|
||||
}
|
||||
sk = (sS.skewX||'') + (sS.skewY||'');
|
||||
_tS = (_tS === '') ? sk : (_tS + ' ' + sk);
|
||||
} else if (tP === 'scale') {
|
||||
var sc1 = t1.value, sc2 = t2.value,
|
||||
s = sc1 + (sc2 - sc1) * v, scS = tP + '(' + s + ')';
|
||||
_tS = (_tS === '') ? scS : (_tS + ' ' + scS);
|
||||
}
|
||||
}
|
||||
w._el.style[_tr] = rps || ( w._pp !== undefined && w._pp !== 0 ) ? pps + _tS : _tS;
|
||||
};
|
||||
|
||||
} else if ( cls && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
var _c = {};
|
||||
for (var c in w._vE[p].value) {
|
||||
if ( c !== 'a' ){
|
||||
_c[c] = parseInt(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v )||0;
|
||||
} else {
|
||||
_c[c] = (w._vS[p].value[c] && w._vE[p].value[c]) ? parseFloat(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v) : null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( w._hex ) {
|
||||
w._el.style[p] = K.rth( _c.r, _c.g, _c.b );
|
||||
} else {
|
||||
w._el.style[p] = !_c.a || _isIE8 ? 'rgb(' + _c.r + ',' + _c.g + ',' + _c.b + ')' : 'rgba(' + _c.r + ',' + _c.g + ',' + _c.b + ',' + _c.a + ')';
|
||||
}
|
||||
};
|
||||
} else if ( sc && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el = (w._el === undefined || w._el === null) ? _sct : w._el;
|
||||
w._el.scrollTop = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
} else if ( op && (!(p in K.dom)) ) {
|
||||
if (_isIE8) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.filter = "alpha(opacity=" + ( w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v) * 100 + ")";
|
||||
};
|
||||
} else {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.opacity = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
K.s = function () { _caf(_t); _t = null; };
|
||||
|
||||
// process properties for _vE and _vS or one of them
|
||||
K.prP = function (e, s, l) {
|
||||
|
@ -330,6 +229,57 @@
|
|||
// process properties object | registers the plugins prepareStart functions
|
||||
K.pp = {}; K.prS = {};
|
||||
K.pp.tf = function(p,v){ // transform prop / value
|
||||
if (!('transform' in K.dom)) {
|
||||
K.dom['transform'] = function(w,p,v) {
|
||||
var _tS = '', tP, rps, pps = 'perspective('+w._pp+'px) ';
|
||||
for (tP in w._vE[p]) {
|
||||
var t1 = w._vS[p][tP], t2 = w._vE[p][tP];
|
||||
rps = rps || _3d.indexOf(tP) !== -1 && !_isIE;
|
||||
|
||||
if ( tP === 'translate' ) {
|
||||
var tls = '', ts = {}, ax;
|
||||
|
||||
for (ax in t2){
|
||||
var x1 = t1[ax].value || 0, x2 = t2[ax].value || 0, xu = t2[ax].unit || 'px';
|
||||
ts[ax] = x1===x2 ? x2+xu : (x1 + ( x2 - x1 ) * v) + xu;
|
||||
}
|
||||
tls = t2.x ? 'translate(' + ts.x + ',' + ts.y + ')' :
|
||||
'translate3d(' + ts.translateX + ',' + ts.translateY + ',' + ts.translateZ + ')';
|
||||
|
||||
_tS = (_tS === '') ? tls : (tls + ' ' + _tS);
|
||||
} else if ( tP === 'rotate' ) {
|
||||
var rt = '', rS = {}, rx;
|
||||
|
||||
for ( rx in t2 ){
|
||||
if ( t1[rx] ) {
|
||||
var a1 = t1[rx].value, a2 = t2[rx].value, au = t2[rx].unit||'deg',
|
||||
av = a1 + (a2 - a1) * v;
|
||||
rS[rx] = rx ==='z' ? 'rotate('+av+au+')' : rx + '(' + av + au + ') ';
|
||||
}
|
||||
}
|
||||
rt = t2.z ? rS.z : (rS.rotateX||'') + (rS.rotateY||'') + (rS.rotateZ||'');
|
||||
|
||||
_tS = (_tS === '') ? rt : (_tS + ' ' + rt);
|
||||
} else if (tP==='skew') {
|
||||
var sk = '', sS = {};
|
||||
for ( var sx in t2 ){
|
||||
if ( t1[sx] ) {
|
||||
var s1 = t1[sx].value, s2 = t2[sx].value, su = t2[sx].unit||'deg',
|
||||
sv = s1 + (s2 - s1) * v;
|
||||
sS[sx] = sx + '(' + sv + su + ') ';
|
||||
}
|
||||
}
|
||||
sk = (sS.skewX||'') + (sS.skewY||'');
|
||||
_tS = (_tS === '') ? sk : (_tS + ' ' + sk);
|
||||
} else if (tP === 'scale') {
|
||||
var sc1 = t1.value, sc2 = t2.value,
|
||||
s = sc1 + (sc2 - sc1) * v, scS = tP + '(' + s + ')';
|
||||
_tS = (_tS === '') ? scS : (_tS + ' ' + scS);
|
||||
}
|
||||
}
|
||||
w._el.style[_tr] = rps || ( w._pp !== undefined && w._pp !== 0 ) ? pps + _tS : _tS;
|
||||
};
|
||||
}
|
||||
var t = p.replace(/X|Y|Z/, ''), tv;
|
||||
if (p === 'translate3d') {
|
||||
tv = v.split(',');
|
||||
|
@ -360,9 +310,57 @@
|
|||
return { value: K.truD(v,p).v };
|
||||
}
|
||||
};
|
||||
K.pp.unl = function(p,v){ return { value: K.truD(v).v }; } // scroll | opacity | unitless
|
||||
K.pp.box = function(p,v){ return { value: K.truD(v).v, unit: K.truD(v).u }; } // box model | text props | radius props
|
||||
K.pp.cls = function(p,v){ return { value: K.truC(v) }; } // colors
|
||||
K.pp.unl = function(p,v){ // scroll | opacity | unitless
|
||||
if (/scroll/.test(p)){
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el = (w._el === undefined || w._el === null) ? _sct : w._el;
|
||||
w._el.scrollTop = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
} else if (p === 'opacity') {
|
||||
if (!(p in K.dom)) {
|
||||
if (_isIE8) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.filter = "alpha(opacity=" + ( w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v) * 100 + ")";
|
||||
};
|
||||
} else {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.opacity = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return { value: K.truD(v).v };
|
||||
}
|
||||
K.pp.box = function(p,v){
|
||||
if (!(p in K.dom)) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style[p] = (w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v ) + w._vE[p].unit;
|
||||
};
|
||||
}
|
||||
return { value: K.truD(v).v, unit: K.truD(v).u };
|
||||
}
|
||||
// box model | text props | radius props
|
||||
K.pp.cls = function(p,v){ // colors
|
||||
if (!(p in K.dom)) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
var _c = {};
|
||||
for (var c in w._vE[p].value) {
|
||||
if ( c !== 'a' ){
|
||||
_c[c] = parseInt(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v )||0;
|
||||
} else {
|
||||
_c[c] = (w._vS[p].value[c] && w._vE[p].value[c]) ? parseFloat(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v) : null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( w._hex ) {
|
||||
w._el.style[p] = K.rth( _c.r, _c.g, _c.b );
|
||||
} else {
|
||||
w._el.style[p] = !_c.a || _isIE8 ? 'rgb(' + _c.r + ',' + _c.g + ',' + _c.b + ')' : 'rgba(' + _c.r + ',' + _c.g + ',' + _c.b + ',' + _c.a + ')';
|
||||
}
|
||||
};
|
||||
}
|
||||
return { value: K.truC(v) };
|
||||
}
|
||||
|
||||
K.truD = function (d,p) { //true dimension returns { v = value, u = unit }
|
||||
var x = parseInt(d) || 0, mu = ['px','%','deg','rad','em','rem','vh','vw'], l = mu.length,
|
||||
|
@ -453,7 +451,7 @@
|
|||
}
|
||||
} else {
|
||||
return _d[p];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -569,8 +567,6 @@
|
|||
|
||||
//also add plugins options
|
||||
for (var o in _o) { if (!(o in this) && !/perspective|delay|duration|repeat|origin|start|stop|update|complete|pause|play|yoyo|easing/i.test(o) ) { this[o] = _o[o]; } }
|
||||
|
||||
K._queue(this);
|
||||
};
|
||||
|
||||
var w = K.Tween.prototype;
|
||||
|
@ -580,10 +576,7 @@
|
|||
|
||||
K.perspective(this._el,this); // apply the perspective and transform origin
|
||||
if ( this._rpr ) { this.stack(); } // on start we reprocess the valuesStart for TO() method
|
||||
|
||||
// SVG Plugin
|
||||
if (K.svg && this._vE.path) K.svg.pathCross(this); // on start we process the SVG paths
|
||||
|
||||
|
||||
for ( var e in this._vE ) {
|
||||
this._vSR[e] = this._vS[e];
|
||||
}
|
||||
|
@ -716,7 +709,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
K.svg && K.svq(this); // SVG Plugin | on start we process the SVG paths
|
||||
};
|
||||
|
||||
//prepare valuesStart for .to() method
|
||||
|
|
|
@ -1,859 +0,0 @@
|
|||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(["./kute.js"], function(KUTE){ factory(KUTE); return KUTE; });
|
||||
} else if(typeof module == "object" && typeof require == "function") {
|
||||
// We assume, that require() is sync.
|
||||
var KUTE = require("./kute.js");
|
||||
// Export the modified one. Not really required, but convenient.
|
||||
module.exports = factory(KUTE);
|
||||
} else if ( typeof window.KUTE !== 'undefined' ) {
|
||||
// Browser globals
|
||||
window.KUTE.svg = window.KUTE.svg || factory(KUTE);
|
||||
} else {
|
||||
throw new Error("SVG Plugin require KUTE.js.");
|
||||
}
|
||||
}( function (KUTE) {
|
||||
'use strict';
|
||||
var K = window.KUTE, S = S || {},
|
||||
p2s=/,?([a-z]),?/gi,
|
||||
_unl = ['strokeWidth', 'strokeOpacity', 'fillOpacity', 'stopOpacity'], // unitless SVG props;
|
||||
_cls = ['fill', 'stroke', 'stopColor']; // colors 'hex', 'rgb', 'rgba' -- #fff / rgb(0,0,0) / rgba(0,0,0,0)
|
||||
|
||||
// get path
|
||||
S.getPath = function(e){
|
||||
var p = {}, el = typeof e === 'object' ? e : /^\.|^\#/.test(e) ? document.querySelector(e) : null;
|
||||
if ( el && /path|glyph/.test(el.tagName) ) {
|
||||
p.e = el;
|
||||
p.o = el.getAttribute('d');
|
||||
|
||||
} else if (!el && /m|z|c|l|v|q|[0-9]|\,/gi.test(e)) { // maybe it's a string path already
|
||||
el = document.querySelector('[d="'+e+'"]');
|
||||
var newp = document.createElement('path');
|
||||
newp.setAttribute('d',e);
|
||||
p.e = el || newp;
|
||||
p.o = e;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
// process path now
|
||||
S.pathCross = function(w){
|
||||
var o1 = w._vS.path.o, o2 = w._vE.path.o,
|
||||
p1 = pathMulti(o1), p2 = pathMulti(o2), t, b1, b2;
|
||||
|
||||
w._vS.path.d = {}; w._vE.path.d = {};
|
||||
if ( typeof p1 === 'object' || typeof p2 === 'object' ) {
|
||||
if (typeof p1 === 'object' && typeof p2 === 'string') {
|
||||
|
||||
t = clone(p2); p2 = {}; b2 = curvePathBBox(path2curve(t));
|
||||
for (var i in p1) {
|
||||
// if (i*1 === 0) {
|
||||
p2[i] = t;
|
||||
// } else {
|
||||
// p2[i] = (i*1) % 2 ? 'M'+b2.cx+' '+b2.cy+ +'l0 0' : 'M'+b2.x+' '+b2.y +'l0 0';
|
||||
// }
|
||||
}
|
||||
|
||||
} else if (typeof p1 === 'string' && typeof p2 === 'object') {
|
||||
t = clone(p1); p1 = {}; b1 = curvePathBBox(path2curve(t));
|
||||
for (var i in p2) {
|
||||
// if (i*1 === 0) {
|
||||
p1[i] = t; // perhaps in the future do something about the corresponding shape
|
||||
// } else {
|
||||
// p1[i] = (i*1) % 2 ? 'M'+b1.cx+' '+b1.cy+ +'l0 0' : 'M'+b1.x+' '+b1.y +'l0 0';
|
||||
// }
|
||||
}
|
||||
|
||||
} else if (typeof p1 === 'object' && typeof p2 === 'object') {
|
||||
var pl1 = oKeys(p1).length, pl2 = oKeys(p2).length, s1, s2;
|
||||
|
||||
if (pl1 > pl2) {
|
||||
for (var i in p1){
|
||||
if (!(i in p2)) {
|
||||
s2 = getBSBox(p2,i);
|
||||
b2 = curvePathBBox(path2curve(p2[s2]));
|
||||
// p2[i] = p2[s2]; // or get the biggest/smalles shape
|
||||
p2[i] = (i*1) % 2 ? 'M'+b2.cx+' '+b2.cy+ +'l0 0' : 'M'+b2.x+' '+b2.y +'l0 0';
|
||||
}
|
||||
}
|
||||
|
||||
} else if (pl1<pl2) {
|
||||
for (var i in p2){
|
||||
if (!(i in p1)) {
|
||||
s1 = getBSBox(p1,i);
|
||||
b1 = curvePathBBox(path2curve(p1[s1]));
|
||||
// p1[i] = p1[s1]; // or get the biggest/smallest shape
|
||||
p1[i] = (i*1) % 2 ? 'M'+b1.cx+' '+b1.cy+ +'l0 0' : 'M'+b1.x+' '+b1.y +'l0 0';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (var j in p1) {
|
||||
w._vS.path.d[j] = path2curve(p1[j],p2[j])[0];
|
||||
w._vE.path.d[j] = path2curve(p1[j],p2[j])[1];
|
||||
}
|
||||
} else { // we do some single path shapes
|
||||
// w._vS.path = w._vE.path = [];
|
||||
w._vS.path.d = path2curve(p1,p2)[0];
|
||||
w._vE.path.d = path2curve(p1,p2)[1];
|
||||
}
|
||||
}
|
||||
|
||||
function getBSBox(c,i) {
|
||||
if (typeof c === 'object'){
|
||||
var s = [];
|
||||
for (var i in c){
|
||||
var bb = curvePathBBox(path2curve(c[i]));
|
||||
s.push(bb.w+bb.h);
|
||||
}
|
||||
if ( i*1 % 2 ) {
|
||||
return s.indexOf(Math.min.apply(null, s)).toString();
|
||||
} else {
|
||||
return s.indexOf(Math.max.apply(null, s)).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function oKeys(o){
|
||||
var k = [], p;
|
||||
if (!Object.keys) {
|
||||
for (p in o) { k.push(p); }
|
||||
return k;
|
||||
} else {
|
||||
return Object.keys(o);
|
||||
}
|
||||
}
|
||||
|
||||
function random(m,M) {
|
||||
return Math.floor(Math.random() * (M - m + 1)) + m;
|
||||
}
|
||||
|
||||
function pathMulti(p){
|
||||
var a = p.split(/z/i), path;
|
||||
if (a.length > 2) {
|
||||
for (var i = 0; i< a.length; i++) { trm(a[i].replace(/\n/,'')); if ( !/[0-9a-z]/gi.test(a[i]) ) { a.splice(i,1) } }
|
||||
path = {};
|
||||
for (var i=0, l=a.length; i<l; i++) { path[i] = a[i] + 'z'; }
|
||||
} else { path = trm(p); }
|
||||
return path;
|
||||
}
|
||||
|
||||
function trm(s){
|
||||
if (!String.prototype.trim) {
|
||||
return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
||||
} else { return s.trim(); }
|
||||
}
|
||||
|
||||
|
||||
// register the render SVG path object
|
||||
// process attributes object K.pa(t[x]) and also register their render functions
|
||||
K.pp.path = function(a,o){
|
||||
if (!('path' in K.dom)) {
|
||||
K.dom['path'] = function(w,p,v){
|
||||
var curves = [], curve =[], i, l, str='', tp = tp || typeof w._vE.path.d[0][0] === 'object';
|
||||
if (tp){ // we process multipath first
|
||||
for(i in w._vE.path.d) { // each parent path
|
||||
curves[i] = [];
|
||||
for ( var k = 0, l2 = w._vE.path.d[i].length; k < l2; k++){ // each path
|
||||
curves[i][k] = [];
|
||||
curves[i][k].push([w._vS.path.d[i][k][0]]);
|
||||
for(var j=1,l3=w._vE.path.d[i][k].length;j<l3;j++) { // each point
|
||||
curves[i][k].push(w._vS.path.d[i][k][j]+(w._vE.path.d[i][k][j]-w._vS.path.d[i][k][j])*v);
|
||||
}
|
||||
curves[i].push('z');
|
||||
}
|
||||
str += S.path2string(curves[i]);
|
||||
}
|
||||
w._el.setAttribute("d", v === 1 ? w._vE.path.o : str);
|
||||
} else {
|
||||
for(i=0,l=w._vE.path.d.length;i<l;i++) { //
|
||||
curve.push([w._vS.path.d[i][0]]);
|
||||
for(var j=1,l2=w._vS.path.d[i].length;j<l2;j++) { // each point
|
||||
curve[i].push(w._vS.path.d[i][j]+(w._vE.path.d[i][j]-w._vS.path.d[i][j])*v);
|
||||
}
|
||||
}
|
||||
curve.push('z');
|
||||
w._el.setAttribute("d", v === 1 ? w._vE.path.o : S.path2string(curve) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return S.getPath(o);
|
||||
}
|
||||
|
||||
|
||||
function closestPoint(pathNode, point) {
|
||||
var pathLength = pathNode.getTotalLength(),
|
||||
precision = pathLength / pathNode.pathSegList.numberOfItems * .125,
|
||||
best,
|
||||
bestLength,
|
||||
bestDistance = Infinity;
|
||||
// linear scan for coarse approximation
|
||||
for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
|
||||
if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) {
|
||||
best = scan, bestLength = scanLength, bestDistance = scanDistance;
|
||||
}
|
||||
}
|
||||
// binary search for precise estimate
|
||||
precision *= .5;
|
||||
while (precision > .5) {
|
||||
var before,
|
||||
after,
|
||||
beforeLength,
|
||||
afterLength,
|
||||
beforeDistance,
|
||||
afterDistance;
|
||||
if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) {
|
||||
best = before, bestLength = beforeLength, bestDistance = beforeDistance;
|
||||
} else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) {
|
||||
best = after, bestLength = afterLength, bestDistance = afterDistance;
|
||||
} else {
|
||||
precision *= .5;
|
||||
}
|
||||
}
|
||||
best = [best.x, best.y];
|
||||
best.distance = Math.sqrt(bestDistance);
|
||||
return best;
|
||||
function distance2(p) {
|
||||
var dx = p.x - point[0],
|
||||
dy = p.y - point[1];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
}
|
||||
|
||||
// K.dom[p] = function(w,p,v) { // for SVG unitless related CSS props
|
||||
// w._el.style[p] = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
// };
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Paths
|
||||
*/
|
||||
|
||||
var spaces = "\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029";
|
||||
var pathCommand = new RegExp("([a-z])[" + spaces + ",]*((-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?[" + spaces + "]*,?[" + spaces + "]*)+)", "ig");
|
||||
var pathValues = new RegExp("(-?\\d*\\.?\\d*(?:e[\\-+]?\\d+)?)[" + spaces + "]*,?[" + spaces + "]*", "ig");
|
||||
|
||||
|
||||
// Parses given path string into an array of arrays of path segments
|
||||
function parsePathString(pathString) {
|
||||
if (!pathString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if( pathString instanceof Array ) {
|
||||
return pathString;
|
||||
} else {
|
||||
var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0},
|
||||
data = [];
|
||||
|
||||
String(pathString).replace(pathCommand, function(a, b, c) {
|
||||
var params = [],
|
||||
name = b.toLowerCase();
|
||||
c.replace(pathValues, function (a, b) {
|
||||
b && params.push(+b);
|
||||
});
|
||||
if (name == "m" && params.length > 2) {
|
||||
data.push([b].concat(params.splice(0, 2)));
|
||||
name = "l";
|
||||
b = b == "m" ? "l" : "L";
|
||||
}
|
||||
if (name == "o" && params.length == 1) {
|
||||
data.push([b, params[0]]);
|
||||
}
|
||||
if (name == "r") {
|
||||
data.push([b].concat(params));
|
||||
} else while (params.length >= paramCounts[name]) {
|
||||
data.push([b].concat(params.splice(0, paramCounts[name])));
|
||||
if (!paramCounts[name]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// http://schepers.cc/getting-to-the-point
|
||||
function catmullRom2bezier(crp, z) {
|
||||
var d = [];
|
||||
for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
|
||||
var p = [
|
||||
{x: +crp[i - 2], y: +crp[i - 1]},
|
||||
{x: +crp[i], y: +crp[i + 1]},
|
||||
{x: +crp[i + 2], y: +crp[i + 3]},
|
||||
{x: +crp[i + 4], y: +crp[i + 5]}
|
||||
];
|
||||
if (z) {
|
||||
if (!i) {
|
||||
p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]};
|
||||
} else if (iLen - 4 == i) {
|
||||
p[3] = {x: +crp[0], y: +crp[1]};
|
||||
} else if (iLen - 2 == i) {
|
||||
p[2] = {x: +crp[0], y: +crp[1]};
|
||||
p[3] = {x: +crp[2], y: +crp[3]};
|
||||
}
|
||||
} else {
|
||||
if (iLen - 4 == i) {
|
||||
p[3] = p[2];
|
||||
} else if (!i) {
|
||||
p[0] = {x: +crp[i], y: +crp[i + 1]};
|
||||
}
|
||||
}
|
||||
d.push(["C",
|
||||
(-p[0].x + 6 * p[1].x + p[2].x) / 6,
|
||||
(-p[0].y + 6 * p[1].y + p[2].y) / 6,
|
||||
(p[1].x + 6 * p[2].x - p[3].x) / 6,
|
||||
(p[1].y + 6*p[2].y - p[3].y) / 6,
|
||||
p[2].x,
|
||||
p[2].y
|
||||
]);
|
||||
}
|
||||
|
||||
return d;
|
||||
|
||||
};
|
||||
|
||||
function ellipsePath(x, y, rx, ry, a) {
|
||||
if (a == null && ry == null) {
|
||||
ry = rx;
|
||||
}
|
||||
x = +x;
|
||||
y = +y;
|
||||
rx = +rx;
|
||||
ry = +ry;
|
||||
if (a != null) {
|
||||
var rad = Math.PI / 180,
|
||||
x1 = x + rx * Math.cos(-ry * rad),
|
||||
x2 = x + rx * Math.cos(-a * rad),
|
||||
y1 = y + rx * Math.sin(-ry * rad),
|
||||
y2 = y + rx * Math.sin(-a * rad),
|
||||
res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]];
|
||||
} else {
|
||||
res = [
|
||||
["M", x, y],
|
||||
["m", 0, -ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, 2 * ry],
|
||||
["a", rx, ry, 0, 1, 1, 0, -2 * ry],
|
||||
["z"]
|
||||
];
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
function pathToAbsolute(pathArray) {
|
||||
pathArray = parsePathString(pathArray);
|
||||
|
||||
if (!pathArray || !pathArray.length) {
|
||||
return [["M", 0, 0]];
|
||||
}
|
||||
var res = [],
|
||||
x = 0,
|
||||
y = 0,
|
||||
mx = 0,
|
||||
my = 0,
|
||||
start = 0,
|
||||
pa0;
|
||||
if (pathArray[0][0] == "M") {
|
||||
x = +pathArray[0][1];
|
||||
y = +pathArray[0][2];
|
||||
mx = x;
|
||||
my = y;
|
||||
start++;
|
||||
res[0] = ["M", x, y];
|
||||
}
|
||||
var crz = pathArray.length == 3 &&
|
||||
pathArray[0][0] == "M" &&
|
||||
pathArray[1][0].toUpperCase() == "R" &&
|
||||
pathArray[2][0].toUpperCase() == "Z";
|
||||
for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) {
|
||||
res.push(r = []);
|
||||
pa = pathArray[i];
|
||||
pa0 = pa[0];
|
||||
if (pa0 != pa0.toUpperCase()) {
|
||||
r[0] = pa0.toUpperCase();
|
||||
switch (r[0]) {
|
||||
case "A":
|
||||
r[1] = pa[1];
|
||||
r[2] = pa[2];
|
||||
r[3] = pa[3];
|
||||
r[4] = pa[4];
|
||||
r[5] = pa[5];
|
||||
r[6] = +pa[6] + x;
|
||||
r[7] = +pa[7] + y;
|
||||
break;
|
||||
case "V":
|
||||
r[1] = +pa[1] + y;
|
||||
break;
|
||||
case "H":
|
||||
r[1] = +pa[1] + x;
|
||||
break;
|
||||
case "R":
|
||||
var dots = [x, y].concat(pa.slice(1));
|
||||
for (var j = 2, jj = dots.length; j < jj; j++) {
|
||||
dots[j] = +dots[j] + x;
|
||||
dots[++j] = +dots[j] + y;
|
||||
}
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
break;
|
||||
case "O":
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
break;
|
||||
case "U":
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
break;
|
||||
case "M":
|
||||
mx = +pa[1] + x;
|
||||
my = +pa[2] + y;
|
||||
default:
|
||||
for (j = 1, jj = pa.length; j < jj; j++) {
|
||||
r[j] = +pa[j] + ((j % 2) ? x : y);
|
||||
}
|
||||
}
|
||||
} else if (pa0 == "R") {
|
||||
dots = [x, y].concat(pa.slice(1));
|
||||
res.pop();
|
||||
res = res.concat(catmullRom2bezier(dots, crz));
|
||||
r = ["R"].concat(pa.slice(-2));
|
||||
} else if (pa0 == "O") {
|
||||
res.pop();
|
||||
dots = ellipsePath(x, y, pa[1], pa[2]);
|
||||
dots.push(dots[0]);
|
||||
res = res.concat(dots);
|
||||
} else if (pa0 == "U") {
|
||||
res.pop();
|
||||
res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3]));
|
||||
r = ["U"].concat(res[res.length - 1].slice(-2));
|
||||
} else {
|
||||
for (var k = 0, kk = pa.length; k < kk; k++) {
|
||||
r[k] = pa[k];
|
||||
}
|
||||
}
|
||||
pa0 = pa0.toUpperCase();
|
||||
if (pa0 != "O") {
|
||||
switch (r[0]) {
|
||||
case "Z":
|
||||
x = +mx;
|
||||
y = +my;
|
||||
break;
|
||||
case "H":
|
||||
x = r[1];
|
||||
break;
|
||||
case "V":
|
||||
y = r[1];
|
||||
break;
|
||||
case "M":
|
||||
mx = r[r.length - 2];
|
||||
my = r[r.length - 1];
|
||||
default:
|
||||
x = r[r.length - 2];
|
||||
y = r[r.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
function l2c(x1, y1, x2, y2) {
|
||||
return [x1, y1, x2, y2, x2, y2];
|
||||
};
|
||||
function q2c(x1, y1, ax, ay, x2, y2) {
|
||||
var _13 = 1 / 3,
|
||||
_23 = 2 / 3;
|
||||
return [
|
||||
_13 * x1 + _23 * ax,
|
||||
_13 * y1 + _23 * ay,
|
||||
_13 * x2 + _23 * ax,
|
||||
_13 * y2 + _23 * ay,
|
||||
x2,
|
||||
y2
|
||||
];
|
||||
};
|
||||
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
|
||||
// for more information of where this math came from visit:
|
||||
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
||||
var _120 = Math.PI * 120 / 180,
|
||||
rad = Math.PI / 180 * (+angle || 0),
|
||||
res = [],
|
||||
xy,
|
||||
rotate = function (x, y, rad) {
|
||||
var X = x * Math.cos(rad) - y * Math.sin(rad),
|
||||
Y = x * Math.sin(rad) + y * Math.cos(rad);
|
||||
return {x: X, y: Y};
|
||||
};
|
||||
if (!recursive) {
|
||||
xy = rotate(x1, y1, -rad);
|
||||
x1 = xy.x;
|
||||
y1 = xy.y;
|
||||
xy = rotate(x2, y2, -rad);
|
||||
x2 = xy.x;
|
||||
y2 = xy.y;
|
||||
var cos = Math.cos(Math.PI / 180 * angle),
|
||||
sin = Math.sin(Math.PI / 180 * angle),
|
||||
x = (x1 - x2) / 2,
|
||||
y = (y1 - y2) / 2;
|
||||
var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
|
||||
if (h > 1) {
|
||||
h = Math.sqrt(h);
|
||||
rx = h * rx;
|
||||
ry = h * ry;
|
||||
}
|
||||
var rx2 = rx * rx,
|
||||
ry2 = ry * ry,
|
||||
k = (large_arc_flag == sweep_flag ? -1 : 1) *
|
||||
Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
|
||||
cx = k * rx * y / ry + (x1 + x2) / 2,
|
||||
cy = k * -ry * x / rx + (y1 + y2) / 2,
|
||||
f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
|
||||
f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
|
||||
|
||||
f1 = x1 < cx ? Math.PI - f1 : f1;
|
||||
f2 = x2 < cx ? Math.PI - f2 : f2;
|
||||
f1 < 0 && (f1 = Math.PI * 2 + f1);
|
||||
f2 < 0 && (f2 = Math.PI * 2 + f2);
|
||||
if (sweep_flag && f1 > f2) {
|
||||
f1 = f1 - Math.PI * 2;
|
||||
}
|
||||
if (!sweep_flag && f2 > f1) {
|
||||
f2 = f2 - Math.PI * 2;
|
||||
}
|
||||
} else {
|
||||
f1 = recursive[0];
|
||||
f2 = recursive[1];
|
||||
cx = recursive[2];
|
||||
cy = recursive[3];
|
||||
}
|
||||
var df = f2 - f1;
|
||||
if (Math.abs(df) > _120) {
|
||||
var f2old = f2,
|
||||
x2old = x2,
|
||||
y2old = y2;
|
||||
f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
|
||||
x2 = cx + rx * Math.cos(f2);
|
||||
y2 = cy + ry * Math.sin(f2);
|
||||
res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
|
||||
}
|
||||
df = f2 - f1;
|
||||
var c1 = Math.cos(f1),
|
||||
s1 = Math.sin(f1),
|
||||
c2 = Math.cos(f2),
|
||||
s2 = Math.sin(f2),
|
||||
t = Math.tan(df / 4),
|
||||
hx = 4 / 3 * rx * t,
|
||||
hy = 4 / 3 * ry * t,
|
||||
m1 = [x1, y1],
|
||||
m2 = [x1 + hx * s1, y1 - hy * c1],
|
||||
m3 = [x2 + hx * s2, y2 - hy * c2],
|
||||
m4 = [x2, y2];
|
||||
m2[0] = 2 * m1[0] - m2[0];
|
||||
m2[1] = 2 * m1[1] - m2[1];
|
||||
if (recursive) {
|
||||
return [m2, m3, m4].concat(res);
|
||||
} else {
|
||||
res = [m2, m3, m4].concat(res).join().split(",");
|
||||
var newres = [];
|
||||
for (var i = 0, ii = res.length; i < ii; i++) {
|
||||
newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
|
||||
}
|
||||
return newres;
|
||||
}
|
||||
};
|
||||
|
||||
function clone(obj) {
|
||||
var copy;
|
||||
|
||||
// Handle Array
|
||||
if (obj instanceof Array) {
|
||||
copy = [];
|
||||
for (var i = 0, len = obj.length; i < len; i++) {
|
||||
copy[i] = clone(obj[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Handle Object
|
||||
if (obj instanceof Object) {
|
||||
copy = {};
|
||||
for (var attr in obj) {
|
||||
if (obj.hasOwnProperty(attr)) {
|
||||
copy[attr] = clone(obj[attr]);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function path2curve(path, path2) {
|
||||
var p = pathToAbsolute(path),
|
||||
p2 = path2 && pathToAbsolute(path2),
|
||||
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
|
||||
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
|
||||
processPath = function (path, d, pcom) {
|
||||
var nx, ny;
|
||||
if (!path) {
|
||||
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
|
||||
}
|
||||
!(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
|
||||
switch (path[0]) {
|
||||
case "M":
|
||||
d.X = path[1];
|
||||
d.Y = path[2];
|
||||
break;
|
||||
case "A":
|
||||
path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
|
||||
break;
|
||||
case "S":
|
||||
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
|
||||
nx = d.x * 2 - d.bx; // And reflect the previous
|
||||
ny = d.y * 2 - d.by; // command's control point relative to the current point.
|
||||
}
|
||||
else { // or some else or nothing
|
||||
nx = d.x;
|
||||
ny = d.y;
|
||||
}
|
||||
path = ["C", nx, ny].concat(path.slice(1));
|
||||
break;
|
||||
case "T":
|
||||
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
|
||||
d.qx = d.x * 2 - d.qx; // And make a reflection similar
|
||||
d.qy = d.y * 2 - d.qy; // to case "S".
|
||||
}
|
||||
else { // or something else or nothing
|
||||
d.qx = d.x;
|
||||
d.qy = d.y;
|
||||
}
|
||||
path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
|
||||
break;
|
||||
case "Q":
|
||||
d.qx = path[1];
|
||||
d.qy = path[2];
|
||||
path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
|
||||
break;
|
||||
case "L":
|
||||
path = ["C"].concat(l2c(d.x, d.y, path[1], path[2]));
|
||||
break;
|
||||
case "H":
|
||||
path = ["C"].concat(l2c(d.x, d.y, path[1], d.y));
|
||||
break;
|
||||
case "V":
|
||||
path = ["C"].concat(l2c(d.x, d.y, d.x, path[1]));
|
||||
break;
|
||||
case "Z":
|
||||
path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y));
|
||||
break;
|
||||
}
|
||||
return path;
|
||||
},
|
||||
fixArc = function (pp, i) {
|
||||
if (pp[i].length > 7) {
|
||||
pp[i].shift();
|
||||
var pi = pp[i];
|
||||
while (pi.length) {
|
||||
pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
|
||||
p2 && (pcoms2[i] = "A"); // the same as above
|
||||
pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
|
||||
}
|
||||
pp.splice(i, 1);
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
}
|
||||
},
|
||||
fixM = function (path1, path2, a1, a2, i) {
|
||||
if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
|
||||
path2.splice(i, 0, ["M", a2.x, a2.y]);
|
||||
a1.bx = 0;
|
||||
a1.by = 0;
|
||||
a1.x = path1[i][1];
|
||||
a1.y = path1[i][2];
|
||||
ii = Math.max(p.length, p2 && p2.length || 0);
|
||||
}
|
||||
},
|
||||
pcoms1 = [], // path commands of original path p
|
||||
pcoms2 = [], // path commands of original path p2
|
||||
pfirst = "", // temporary holder for original path command
|
||||
pcom = ""; // holder for previous path command of original path
|
||||
for (var i = 0, ii = Math.max(p.length, p2 && p2.length || 0); i < ii; i++) {
|
||||
p[i] && (pfirst = p[i][0]); // save current path command
|
||||
|
||||
if (pfirst != "C") { // C is not saved yet, because it may be result of conversion
|
||||
pcoms1[i] = pfirst; // Save current path command
|
||||
i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
|
||||
}
|
||||
p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
|
||||
|
||||
if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
|
||||
// which may produce multiple C:s
|
||||
// so we have to make sure that C is also C in original path
|
||||
|
||||
fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
|
||||
|
||||
if (p2) { // the same procedures is done to p2
|
||||
p2[i] && (pfirst = p2[i][0]);
|
||||
if (pfirst != "C") {
|
||||
pcoms2[i] = pfirst;
|
||||
i && (pcom = pcoms2[i - 1]);
|
||||
}
|
||||
p2[i] = processPath(p2[i], attrs2, pcom);
|
||||
|
||||
if (pcoms2[i] != "A" && pfirst == "C") {
|
||||
pcoms2[i] = "C";
|
||||
}
|
||||
|
||||
fixArc(p2, i);
|
||||
}
|
||||
fixM(p, p2, attrs, attrs2, i);
|
||||
fixM(p2, p, attrs2, attrs, i);
|
||||
var seg = p[i],
|
||||
seg2 = p2 && p2[i],
|
||||
seglen = seg.length,
|
||||
seg2len = p2 && seg2.length;
|
||||
attrs.x = seg[seglen - 2];
|
||||
attrs.y = seg[seglen - 1];
|
||||
attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
|
||||
attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
|
||||
attrs2.bx = p2 && (parseFloat(seg2[seg2len - 4]) || attrs2.x);
|
||||
attrs2.by = p2 && (parseFloat(seg2[seg2len - 3]) || attrs2.y);
|
||||
attrs2.x = p2 && seg2[seg2len - 2];
|
||||
attrs2.y = p2 && seg2[seg2len - 1];
|
||||
}
|
||||
|
||||
return p2 ? [p, p2] : p;
|
||||
};
|
||||
|
||||
function box(x, y, width, height) {
|
||||
if (x == null) {
|
||||
x = y = width = height = 0;
|
||||
}
|
||||
if (y == null) {
|
||||
y = x.y;
|
||||
width = x.width;
|
||||
height = x.height;
|
||||
x = x.x;
|
||||
}
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
w: width,
|
||||
h: height,
|
||||
cx: x + width / 2,
|
||||
cy: y + height / 2
|
||||
};
|
||||
};
|
||||
|
||||
// Returns bounding box of cubic bezier curve.
|
||||
// Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
|
||||
// Original version: NISHIO Hirokazu
|
||||
// Modifications: https://github.com/timo22345
|
||||
function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
|
||||
var tvalues = [],
|
||||
bounds = [[], []],
|
||||
a, b, c, t, t1, t2, b2ac, sqrtb2ac;
|
||||
for (var i = 0; i < 2; ++i) {
|
||||
if (i == 0) {
|
||||
b = 6 * x0 - 12 * x1 + 6 * x2;
|
||||
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
|
||||
c = 3 * x1 - 3 * x0;
|
||||
} else {
|
||||
b = 6 * y0 - 12 * y1 + 6 * y2;
|
||||
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
|
||||
c = 3 * y1 - 3 * y0;
|
||||
}
|
||||
if (Math.abs(a) < 1e-12) {
|
||||
if (Math.abs(b) < 1e-12) {
|
||||
continue;
|
||||
}
|
||||
t = -c / b;
|
||||
if (0 < t && t < 1) {
|
||||
tvalues.push(t);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
b2ac = b * b - 4 * c * a;
|
||||
sqrtb2ac = Math.sqrt(b2ac);
|
||||
if (b2ac < 0) {
|
||||
continue;
|
||||
}
|
||||
t1 = (-b + sqrtb2ac) / (2 * a);
|
||||
if (0 < t1 && t1 < 1) {
|
||||
tvalues.push(t1);
|
||||
}
|
||||
t2 = (-b - sqrtb2ac) / (2 * a);
|
||||
if (0 < t2 && t2 < 1) {
|
||||
tvalues.push(t2);
|
||||
}
|
||||
}
|
||||
|
||||
var j = tvalues.length,
|
||||
jlen = j,
|
||||
mt;
|
||||
while (j--) {
|
||||
t = tvalues[j];
|
||||
mt = 1 - t;
|
||||
bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
|
||||
bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
|
||||
}
|
||||
|
||||
bounds[0][jlen] = x0;
|
||||
bounds[1][jlen] = y0;
|
||||
bounds[0][jlen + 1] = x3;
|
||||
bounds[1][jlen + 1] = y3;
|
||||
bounds[0].length = bounds[1].length = jlen + 2;
|
||||
|
||||
return {
|
||||
min: {x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1])},
|
||||
max: {x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1])}
|
||||
};
|
||||
};
|
||||
|
||||
function curvePathBBox(path) {
|
||||
var x = 0,
|
||||
y = 0,
|
||||
X = [],
|
||||
Y = [],
|
||||
p;
|
||||
for (var i = 0, ii = path.length; i < ii; i++) {
|
||||
p = path[i];
|
||||
if (p[0] == "M") {
|
||||
x = p[1];
|
||||
y = p[2];
|
||||
X.push(x);
|
||||
Y.push(y);
|
||||
} else {
|
||||
var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
|
||||
X = X.concat(dim.min.x, dim.max.x);
|
||||
Y = Y.concat(dim.min.y, dim.max.y);
|
||||
x = p[5];
|
||||
y = p[6];
|
||||
}
|
||||
}
|
||||
var xmin = Math.min.apply(0, X),
|
||||
ymin = Math.min.apply(0, Y),
|
||||
xmax = Math.max.apply(0, X),
|
||||
ymax = Math.max.apply(0, Y),
|
||||
bb = box(xmin, ymin, xmax - xmin, ymax - ymin);
|
||||
|
||||
return bb;
|
||||
};
|
||||
|
||||
|
||||
|
||||
S.path2string = function(path) {
|
||||
return path.join(',').replace(p2s, "$1");
|
||||
};
|
||||
|
||||
return S;
|
||||
}));
|
808
src/tmp/kute.js
808
src/tmp/kute.js
|
@ -1,808 +0,0 @@
|
|||
/* KUTE.js - The Light Tweening Engine
|
||||
* by dnp_theme
|
||||
* Licensed under MIT-License
|
||||
*/
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory); // AMD. Register as an anonymous module.
|
||||
} else if (typeof exports == 'object') {
|
||||
module.exports = factory(); // Node, not strict CommonJS
|
||||
} else {
|
||||
// Browser globals
|
||||
window.KUTE = window.KUTE || factory();
|
||||
}
|
||||
}( function () {
|
||||
"use strict";
|
||||
var K = K || {};
|
||||
K.getPrefix = function() { //returns browser prefix
|
||||
var div = document.createElement('div'), i = 0, pf = ['Moz', 'moz', 'Webkit', 'webkit', 'O', 'o', 'Ms', 'ms'], pl = pf.length,
|
||||
s = ['MozTransform', 'mozTransform', 'WebkitTransform', 'webkitTransform', 'OTransform', 'oTransform', 'MsTransform', 'msTransform'];
|
||||
|
||||
for (i; i < pl; i++) { if (s[i] in div.style) { return pf[i]; } }
|
||||
div = null;
|
||||
}
|
||||
|
||||
// prefix handling
|
||||
var _pf = K.getPrefix(), // prefix
|
||||
_rafR = (!('requestAnimationFrame' in window)) ? true : false, // is prefix required for requestAnimationFrame
|
||||
_pfT = (!('transform' in document.getElementsByTagName('div')[0].style)) ? true : false, // is prefix required for transform
|
||||
_tch = ('ontouchstart' in window || navigator.msMaxTouchPoints) || false, // support Touch?
|
||||
_ev = _tch ? 'touchstart' : 'mousewheel', //event to prevent on scroll
|
||||
//assign preffix to DOM properties
|
||||
_pfto = _pfT ? _pf + 'TransformOrigin' : 'transformOrigin',
|
||||
_pfp = _pfT ? _pf + 'Perspective' : 'perspective',
|
||||
_pfo = _pfT ? _pf + 'PerspectiveOrigin' : 'perspectiveOrigin',
|
||||
_tr = _pfT ? _pf + 'Transform' : 'transform',
|
||||
_raf = _rafR ? window[_pf + 'RequestAnimationFrame'] : window['requestAnimationFrame'],
|
||||
_caf = _rafR ? (window[_pf + 'CancelAnimationFrame'] || window[_pf + 'CancelRequestAnimationFrame']) : window['cancelAnimationFrame'],
|
||||
|
||||
//true scroll container
|
||||
_bd = document.body, _htm = document.getElementsByTagName('HTML')[0],
|
||||
_sct = (/webkit/i.test(navigator.userAgent) || document.compatMode == 'BackCompat' ? _bd : _htm),
|
||||
|
||||
_isIE = (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null) ? parseFloat( RegExp.$1 ) : false,
|
||||
_isIE8 = _isIE === 8, // check IE8/IE
|
||||
|
||||
//supported properties
|
||||
_cls = ['color', 'backgroundColor', 'borderColor', 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'], // colors 'hex', 'rgb', 'rgba' -- #fff / rgb(0,0,0) / rgba(0,0,0,0)
|
||||
_sc = ['scrollTop', 'scroll'], //scroll, it has no default value, it's calculated on tween start
|
||||
_op = ['opacity'], // opacity
|
||||
_bm = ['top', 'left', 'width', 'height'], // dimensions / box model
|
||||
_3d = ['rotateX', 'rotateY','translateZ'], // transform properties that require perspective
|
||||
_tf = ['translate3d', 'translateX', 'translateY', 'translateZ', 'rotate', 'translate', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY', 'scale'], // transform
|
||||
_all = _cls.concat(_sc, _op, _bm, _tf), al = _all.length,
|
||||
_d = _d || {}; //all properties default values
|
||||
|
||||
//populate default values object
|
||||
for ( var i=0; i< al; i++ ){
|
||||
var p = _all[i];
|
||||
if (_cls.indexOf(p) !== -1){
|
||||
_d[p] = 'rgba(0,0,0,0)'; // _d[p] = {r:0,g:0,b:0,a:1};
|
||||
} else if ( _bm.indexOf(p) !== -1 ) {
|
||||
_d[p] = 0;
|
||||
} else if ( p === 'translate3d' ){
|
||||
_d[p] = [0,0,0];
|
||||
} else if ( p === 'translate' ){
|
||||
_d[p] = [0,0];
|
||||
} else if ( p === 'rotate' || /X|Y|Z/.test(p) ){
|
||||
_d[p] = 0;
|
||||
} else if ( p === 'scale' || p === 'opacity' ){
|
||||
_d[p] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// main methods
|
||||
K.to = function (el, to, o) {
|
||||
var _el = typeof el === 'object' ? el : document.querySelector(el),
|
||||
_vS = to, _vE = K.prP(to)[0]; o = o || {}; o.rpr = true; // we're gonna have to build _vS object at start
|
||||
return new K.Tween(_el, _vS, _vE, o);
|
||||
};
|
||||
|
||||
K.fromTo = function (el, f, to, o) {
|
||||
var _el = typeof el === 'object' ? el : document.querySelector(el),
|
||||
_vS = K.prP(f, to)[0], _vE = K.prP(f, to)[1]; o = o || {};
|
||||
return new K.Tween(_el, _vS, _vE, o);
|
||||
};
|
||||
|
||||
// multiple elements tweening
|
||||
K.allTo = function (el, to, o) {
|
||||
var _els = typeof el === 'object' && el.length ? el : document.querySelectorAll(el);
|
||||
return new K.TweensTO(_els, to, o);
|
||||
};
|
||||
|
||||
K.allFromTo = function (el, f, to, o) {
|
||||
var _els = typeof el === 'object' && el.length ? el : document.querySelectorAll(el);
|
||||
return new K.TweensFT(_els, f, to, o);
|
||||
};
|
||||
|
||||
// the tweens array and tick ID
|
||||
K._tws = []; K._t = null;
|
||||
|
||||
// render functions
|
||||
K.dom = {};
|
||||
K._u = function(w,t) {
|
||||
t = t || window.performance.now();
|
||||
if (t < w._sT && w.playing && !w.paused) { return true; }
|
||||
|
||||
var p, e = Math.min(( t - w._sT ) / w._dr,1);
|
||||
|
||||
//render the CSS update
|
||||
for (p in w._vE){
|
||||
K.dom[p](w,p,w._e(e));
|
||||
}
|
||||
|
||||
if (w._uC) { w._uC.call(); }
|
||||
|
||||
if (e === 1) {
|
||||
if (w._r > 0) {
|
||||
if ( w._r < 9999 ) { w._r--; }
|
||||
|
||||
if (w._y) { w.reversed = !w.reversed; w.reverse(); } // handle yoyo
|
||||
|
||||
w._sT = (w._y && !w.reversed) ? t + w._rD : t; //set the right time for delay
|
||||
return true;
|
||||
} else {
|
||||
|
||||
if (w._cC) { w._cC.call(); }
|
||||
|
||||
//stop preventing scroll when scroll tween finished
|
||||
w.scrollOut();
|
||||
|
||||
// start animating chained tweens
|
||||
var i = 0, ctl = w._cT.length;
|
||||
for (i; i < ctl; i++) {
|
||||
w._cT[i].start(w._sT + w._dr);
|
||||
}
|
||||
|
||||
//stop ticking when finished
|
||||
w.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// internal ticker
|
||||
K._tk = function (t) {
|
||||
var i = 0, tl;
|
||||
K._t = _raf(K._tk);
|
||||
while ( i < (tl = K._tws.length) ) {
|
||||
if ( K._u(K._tws[i],t) ) {
|
||||
i++;
|
||||
} else {
|
||||
K._tws.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// aplies the transform origin and perspective
|
||||
K.perspective = function (l,w) {
|
||||
if ( w._to !== undefined ) { l.style[_pfto] = w._to; } // element transform origin
|
||||
if ( w._ppo !== undefined ) { l.style[_pfo] = w._ppo; } // element perspective origin
|
||||
if ( w._ppp !== undefined ) { l.parentNode.style[_pfp] = w._ppp + 'px'; } // parent perspective
|
||||
if ( w._pppo !== undefined ) { l.parentNode.style[_pfo] = w._pppo; } // parent perspective origin
|
||||
};
|
||||
|
||||
//more internals
|
||||
K.getAll = function () { return K._tws; };
|
||||
K.removeAll = function () { K._tws = []; };
|
||||
K.add = function (tw) { K._tws.push(tw); };
|
||||
K.remove = function (tw) {
|
||||
var i = K._tws.indexOf(tw);
|
||||
if (i !== -1) {
|
||||
K._tws.splice(i, 1);
|
||||
}
|
||||
};
|
||||
K.s = function () { _caf(K._t); K._t = null; };
|
||||
|
||||
// register functions for the render object K.dom(w, p, w._e(e));
|
||||
K._queue = function (w) {
|
||||
for ( var p in w._vE ) {
|
||||
// checking array on every frame takes time so let's cache these
|
||||
var cls = _cls.indexOf(p) !== -1,
|
||||
bm = _bm.indexOf(p) !== -1,
|
||||
sc = _sc.indexOf(p) !== -1,
|
||||
op = _op.indexOf(p) !== -1,
|
||||
tf = p === 'transform';
|
||||
|
||||
//process styles by property / property type
|
||||
if ( bm && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style[p] = (w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v ) + w._vE[p].unit;
|
||||
};
|
||||
} else if (tf && (!(p in K.dom)) ) {
|
||||
|
||||
K.dom[p] = function(w,p,v) {
|
||||
var _tS = '', tP, rps, pps = 'perspective('+w._pp+'px) ';
|
||||
for (tP in w._vE[p]) {
|
||||
var t1 = w._vS[p][tP], t2 = w._vE[p][tP];
|
||||
rps = rps || _3d.indexOf(tP) !== -1 && !_isIE;
|
||||
|
||||
if ( tP === 'translate' ) {
|
||||
var tls = '', ts = {}, ax;
|
||||
|
||||
for (ax in t2){
|
||||
var x1 = t1[ax].value || 0, x2 = t2[ax].value || 0, xu = t2[ax].unit || 'px';
|
||||
ts[ax] = x1===x2 ? x2+xu : (x1 + ( x2 - x1 ) * v) + xu;
|
||||
}
|
||||
tls = t2.x ? 'translate(' + ts.x + ',' + ts.y + ')' :
|
||||
'translate3d(' + ts.translateX + ',' + ts.translateY + ',' + ts.translateZ + ')';
|
||||
|
||||
_tS = (_tS === '') ? tls : (tls + ' ' + _tS);
|
||||
} else if ( tP === 'rotate' ) {
|
||||
var rt = '', rS = {}, rx;
|
||||
|
||||
for ( rx in t2 ){
|
||||
if ( t1[rx] ) {
|
||||
var a1 = t1[rx].value, a2 = t2[rx].value, au = t2[rx].unit||'deg',
|
||||
av = a1 + (a2 - a1) * v;
|
||||
rS[rx] = rx ==='z' ? 'rotate('+av+au+')' : rx + '(' + av + au + ') ';
|
||||
}
|
||||
}
|
||||
rt = t2.z ? rS.z : (rS.rotateX||'') + (rS.rotateY||'') + (rS.rotateZ||'');
|
||||
|
||||
_tS = (_tS === '') ? rt : (_tS + ' ' + rt);
|
||||
} else if (tP==='skew') {
|
||||
var sk = '', sS = {};
|
||||
for ( var sx in t2 ){
|
||||
if ( t1[sx] ) {
|
||||
var s1 = t1[sx].value, s2 = t2[sx].value, su = t2[sx].unit||'deg',
|
||||
sv = s1 + (s2 - s1) * v;
|
||||
sS[sx] = sx + '(' + sv + su + ') ';
|
||||
}
|
||||
}
|
||||
sk = (sS.skewX||'') + (sS.skewY||'');
|
||||
_tS = (_tS === '') ? sk : (_tS + ' ' + sk);
|
||||
} else if (tP === 'scale') {
|
||||
var sc1 = t1.value, sc2 = t2.value,
|
||||
s = sc1 + (sc2 - sc1) * v, scS = tP + '(' + s + ')';
|
||||
_tS = (_tS === '') ? scS : (_tS + ' ' + scS);
|
||||
}
|
||||
}
|
||||
w._el.style[_tr] = rps || ( w._pp !== undefined && w._pp !== 0 ) ? pps + _tS : _tS;
|
||||
};
|
||||
|
||||
} else if ( cls && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
var _c = {};
|
||||
for (var c in w._vE[p].value) {
|
||||
if ( c !== 'a' ){
|
||||
_c[c] = parseInt(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v )||0;
|
||||
} else {
|
||||
_c[c] = (w._vS[p].value[c] && w._vE[p].value[c]) ? parseFloat(w._vS[p].value[c] + (w._vE[p].value[c] - w._vS[p].value[c]) * v) : null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( w._hex ) {
|
||||
w._el.style[p] = K.rth( _c.r, _c.g, _c.b );
|
||||
} else {
|
||||
w._el.style[p] = !_c.a || _isIE8 ? 'rgb(' + _c.r + ',' + _c.g + ',' + _c.b + ')' : 'rgba(' + _c.r + ',' + _c.g + ',' + _c.b + ',' + _c.a + ')';
|
||||
}
|
||||
};
|
||||
} else if ( sc && (!(p in K.dom)) ) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el = (w._el === undefined || w._el === null) ? _sct : w._el;
|
||||
w._el.scrollTop = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
} else if ( op && (!(p in K.dom)) ) {
|
||||
if (_isIE8) {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.filter = "alpha(opacity=" + ( w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v) * 100 + ")";
|
||||
};
|
||||
} else {
|
||||
K.dom[p] = function(w,p,v) {
|
||||
w._el.style.opacity = w._vS[p].value + (w._vE[p].value - w._vS[p].value) * v;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// process properties for _vE and _vS or one of them
|
||||
K.prP = function (e, s) {
|
||||
var i, pl = arguments.length, _st = [], kp = K.pp;
|
||||
|
||||
for (i=0; i<pl; i++) {
|
||||
var t = arguments[i], x, sk = {}, rt = {}, tl = {}, tr = {}; _st[i] = {};
|
||||
for (x in t) {
|
||||
if (_tf.indexOf(x) !== -1) { // transform object gets built here
|
||||
if (x !== 'translate' && /translate/.test(x)) { //process translate3d
|
||||
var ta = ['X', 'Y', 'Z'], f = 0; //coordinates // translate[x] = pp(x, t[x]);
|
||||
|
||||
for (f; f < 3; f++) {
|
||||
var a = ta[f];
|
||||
if ( /3d/.test(x) ) {
|
||||
tl['translate' + a] = kp.tf('translate' + a, t[x][f]);
|
||||
} else {
|
||||
tl['translate' + a] = ('translate' + a in t) ? kp.tf('translate' + a, t['translate' + a]) : { value: 0, unit: 'px' };
|
||||
}
|
||||
}
|
||||
tr['translate'] = tl;
|
||||
} else if ( x !== 'rotate' && /rotate|skew/.test(x)) { //process rotation
|
||||
var ap = /rotate/.test(x) ? 'rotate' : 'skew', ra = ['X', 'Y', 'Z'], r = 0,
|
||||
rtp = ap === 'rotate' ? rt : sk;
|
||||
for (r; r < 3; r++) {
|
||||
var v = ra[r];
|
||||
if ( t[ap+v] !== undefined && x !== 'skewZ' ) {
|
||||
rtp[ap+v] = kp.tf(ap + v, t[ap+v]);
|
||||
}
|
||||
}
|
||||
tr[ap] = rtp;
|
||||
} else if ( x === 'translate' || x === 'rotate' || x === 'scale' ) { //process 2d translation / rotation
|
||||
tr[x] = kp.tf(x, t[x]);
|
||||
}
|
||||
_st[i]['transform'] = tr;
|
||||
} else {
|
||||
if ( _bm.indexOf(x) !== -1 ) {
|
||||
_st[i][x] = kp.box(x,t[x]);
|
||||
} else if (_op.indexOf(x) !== -1 || _sc.indexOf(x) !== -1) {
|
||||
_st[i][x] = kp.unl(x,t[x]);
|
||||
} else if (_cls.indexOf(x) !== -1) {
|
||||
_st[i][x] = kp.cls(x,t[x]);
|
||||
} else { _st[i][x] = kp[x](x,t[x]); } // or any other property from css/ attr / svg / third party plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
return _st;
|
||||
};
|
||||
|
||||
// process properties object
|
||||
K.pp = {};
|
||||
K.pp.tf = function(p,v){ // transform prop / value
|
||||
var t = p.replace(/X|Y|Z/, ''), tv;
|
||||
if (p === 'translate3d') {
|
||||
tv = v.split(',');
|
||||
return {
|
||||
translateX : { value: K.truD(tv[0]).v, unit: K.truD(tv[0]).u },
|
||||
translateY : { value: K.truD(tv[1]).v, unit: K.truD(tv[1]).u },
|
||||
translateZ : { value: K.truD(tv[2]).v, unit: K.truD(tv[2]).u }
|
||||
};
|
||||
} else if (p !== 'translate' && t === 'translate') {
|
||||
return { value: K.truD(v).v, unit: (K.truD(v).u||'px') };
|
||||
} else if (p !== 'rotate' && (t === 'skew' || t === 'rotate') && p !== 'skewZ' ) {
|
||||
return { value: K.truD(v).v, unit: (K.truD(v,p).u||'deg') };
|
||||
} else if (p === 'translate') {
|
||||
tv = typeof v === 'string' ? v.split(',') : v; var t2d = {};
|
||||
if (tv instanceof Array) {
|
||||
t2d.x = { value: K.truD(tv[0]).v, unit: K.truD(tv[0]).u },
|
||||
t2d.y = { value: K.truD(tv[1]).v, unit: K.truD(tv[1]).u }
|
||||
} else {
|
||||
t2d.x = { value: K.truD(tv).v, unit: K.truD(tv).u },
|
||||
t2d.y = { value: 0, unit: 'px' }
|
||||
}
|
||||
return t2d;
|
||||
} else if (p === 'rotate') {
|
||||
var r2d = {};
|
||||
r2d.z = { value: K.truD(v,p).v, unit: (K.truD(v,p).u||'deg') };
|
||||
return r2d;
|
||||
} else if (p === 'scale') {
|
||||
return { value: K.truD(v,p).v };
|
||||
}
|
||||
};
|
||||
K.pp.unl = function(p,v){ return { value: K.truD(v).v }; } // scroll | opacity | unitless
|
||||
K.pp.box = function(p,v){ return { value: K.truD(v).v, unit: K.truD(v).u }; } // box model | text props | radius props
|
||||
K.pp.cls = function(p,v){ return { value: K.truC(v) }; } // colors
|
||||
|
||||
K.truD = function (d,p) { //true dimension returns { v = value, u = unit }
|
||||
var x = parseInt(d) || 0, mu = ['px','%','deg','rad','em','rem','vh','vw'], l = mu.length,
|
||||
y = getU();
|
||||
function getU() {
|
||||
var u,i=0;
|
||||
for (i;i<l;i++) { if ( typeof d === 'string' && d.indexOf(mu[i]) !== -1 ) u = mu[i]; }
|
||||
u = u !== undefined ? u : (p ? 'deg' : 'px')
|
||||
return u;
|
||||
}
|
||||
return { v: x, u: y };
|
||||
};
|
||||
|
||||
K.preventScroll = function (e) { // prevent mousewheel or touch events while tweening scroll
|
||||
var data = document.body.getAttribute('data-tweening');
|
||||
if (data && data === 'scroll') { e.preventDefault(); }
|
||||
};
|
||||
|
||||
K.truC = function (v) { // replace transparent and transform any color to rgba()/rgb()
|
||||
var vrgb, y;
|
||||
if (/rgb|rgba/.test(v)) { //rgb will be fastest initialized
|
||||
vrgb = v.replace(/[^\d,]/g, '').split(','); y = vrgb[3] ? vrgb[3] : null;
|
||||
if (!y) {
|
||||
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]) };
|
||||
} else {
|
||||
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]), a: y*1 };
|
||||
}
|
||||
}
|
||||
if (/#/.test(v)) {
|
||||
return { r: K.htr(v).r, g: K.htr(v).g, b: K.htr(v).b };
|
||||
}
|
||||
if (/transparent|none|initial|inherit/.test(v)) {
|
||||
return { r: 0, g: 0, b: 0, a: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
K.rth = function (r, g, b) { // transform rgb to hex or vice-versa | webkit browsers ignore HEX, always use RGB/RGBA
|
||||
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
||||
};
|
||||
K.htr = function (hex) {
|
||||
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
||||
var shr = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
hex = hex.replace(shr, function (m, 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;
|
||||
};
|
||||
|
||||
K.pe = function (es) { //process easing
|
||||
if ( typeof es === 'function') {
|
||||
return es;
|
||||
} else if ( typeof es === 'string' ) {
|
||||
if ( /easing|linear/.test(es) ) {
|
||||
return K.Easing[es]; //regular Robert Penner Easing Functions
|
||||
} else if ( /bezier/.test(es) ) {
|
||||
var bz = es.replace(/bezier|\s|\(|\)/g,'').split(',');
|
||||
return K.Ease.Bezier( bz[0]*1,bz[1]*1,bz[2]*1,bz[3]*1 ); //bezier easing
|
||||
} else if ( /physics/.test(es) ) {
|
||||
return K.Physics[es](); // predefined physics bezier based easing functions
|
||||
} else {
|
||||
return K.Ease[es](); // predefined bezier based easing functions
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// core easing functions
|
||||
K.Easing = {};
|
||||
K.Easing.linear = function (t) { return t; };
|
||||
var _PI = Math.PI, _2PI = Math.PI * 2, _hPI = Math.PI / 2, _kea = 0.1, _kep = 0.4;
|
||||
|
||||
K.Easing.easingSinusoidalIn = function(t) { return -Math.cos(t * _hPI) + 1; };
|
||||
K.Easing.easingSinusoidalOut = function(t) { return Math.sin(t * _hPI); };
|
||||
K.Easing.easingSinusoidalInOut = function(t) { return -0.5 * (Math.cos(_PI * t) - 1); };
|
||||
K.Easing.easingQuadraticIn = function (t) { return t*t; };
|
||||
K.Easing.easingQuadraticOut = function (t) { return t*(2-t); };
|
||||
K.Easing.easingQuadraticInOut = function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; };
|
||||
K.Easing.easingCubicIn = function (t) { return t*t*t; };
|
||||
K.Easing.easingCubicOut = function (t) { return (--t)*t*t+1; };
|
||||
K.Easing.easingCubicInOut = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; };
|
||||
K.Easing.easingQuarticIn = function (t) { return t*t*t*t; };
|
||||
K.Easing.easingQuarticOut = function (t) { return 1-(--t)*t*t*t; };
|
||||
K.Easing.easingQuarticInOut = function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; };
|
||||
K.Easing.easingQuinticIn = function (t) { return t*t*t*t*t; };
|
||||
K.Easing.easingQuinticOut = function (t) { return 1+(--t)*t*t*t*t; };
|
||||
K.Easing.easingQuinticInOut = function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; };
|
||||
K.Easing.easingCircularIn = function(t) { return -(Math.sqrt(1 - (t * t)) - 1); };
|
||||
K.Easing.easingCircularOut = function(t) { return Math.sqrt(1 - (t = t - 1) * t); };
|
||||
K.Easing.easingCircularInOut = function(t) { return ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); };
|
||||
K.Easing.easingExponentialIn = function(t) { return Math.pow(2, 10 * (t - 1)) - 0.001; };
|
||||
K.Easing.easingExponentialOut = function(t) { return 1 - Math.pow(2, -10 * t); };
|
||||
K.Easing.easingExponentialInOut = function(t) { return (t *= 2) < 1 ? 0.5 * Math.pow(2, 10 * (t - 1)) : 0.5 * (2 - Math.pow(2, -10 * (t - 1))); };
|
||||
K.Easing.easingBackIn = function(t) { var s = 1.70158; return t * t * ((s + 1) * t - s); };
|
||||
K.Easing.easingBackOut = function(t) { var s = 1.70158; return --t * t * ((s + 1) * t + s) + 1; };
|
||||
K.Easing.easingBackInOut = function(t) { var s = 1.70158 * 1.525; if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s)); return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2); };
|
||||
K.Easing.easingElasticIn = function(t) {
|
||||
var s;
|
||||
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / _2PI;
|
||||
return - ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * _2PI / _kep ) );
|
||||
};
|
||||
K.Easing.easingElasticOut = function(t) {
|
||||
var s;
|
||||
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / _2PI ;
|
||||
return ( _kea * Math.pow( 2, - 10 * t) * Math.sin( ( t - s ) * _2PI / _kep ) + 1 );
|
||||
};
|
||||
K.Easing.easingElasticInOut = function(t) {
|
||||
var s;
|
||||
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
|
||||
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / _2PI ;
|
||||
if ( ( t *= 2 ) < 1 ) return - 0.5 * ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * _2PI / _kep ) );
|
||||
return _kea * Math.pow( 2, -10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * _2PI / _kep ) * 0.5 + 1;
|
||||
};
|
||||
K.Easing.easingBounceIn = function(t) { return 1 - K.Easing.easingBounceOut( 1 - t ); };
|
||||
K.Easing.easingBounceOut = function(t) {
|
||||
if ( t < ( 1 / 2.75 ) ) { return 7.5625 * t * t; }
|
||||
else if ( t < ( 2 / 2.75 ) ) { return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75; }
|
||||
else if ( t < ( 2.5 / 2.75 ) ) { return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375; }
|
||||
else {return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375; }
|
||||
};
|
||||
K.Easing.easingBounceInOut = function(t) { if ( t < 0.5 ) return K.Easing.easingBounceIn( t * 2 ) * 0.5; return K.Easing.easingBounceOut( t * 2 - 1 ) * 0.5 + 0.5;};
|
||||
|
||||
// single Tween object construct
|
||||
K.Tween = function (_el, _vS, _vE, _o) {
|
||||
this._el = _el; // element animation is applied to
|
||||
this._dr = _o&&_o.duration || 700; //duration
|
||||
this._r = _o&&_o.repeat || 0; // _repeat
|
||||
this._vSR = {}; // internal valuesStartRepeat
|
||||
this._vS = _vS; // valuesStart
|
||||
this._vE = _vE; // valuesEnd
|
||||
this._y = _o&&_o.yoyo || false; // _yoyo
|
||||
this.playing = false; // _isPlaying
|
||||
this.reversed = false; // _reversed
|
||||
this._rD = _o&&_o.repeatDelay || 0; // _repeatDelay
|
||||
this._dl = _o&&_o.delay || 0; //delay
|
||||
this._sT = null; // startTime
|
||||
this.paused = false; //_paused
|
||||
this._pST = null; //_pauseStartTime
|
||||
this._to = _o.transformOrigin; // transform-origin
|
||||
this._pp = _o.perspective; // perspective
|
||||
this._ppo = _o.perspectiveOrigin; // perspective origin
|
||||
this._ppp = _o.parentPerspective; // parent perspective
|
||||
this._pppo = _o.parentPerspectiveOrigin; // parent perspective origin
|
||||
this._rpr = _o.rpr || false; // internal option to process inline/computed style at start instead of init true/false
|
||||
this._hex = _o.keepHex || false; // option to keep hex for color tweens true/false
|
||||
this._e = _o && _o.easing ? K.pe(_o.easing) : K.Easing.linear; // _easing function
|
||||
this._cT = []; //_chainedTweens
|
||||
this._sC = _o&&_o.start || null; // _on StartCallback
|
||||
this._sCF = false; //_on StartCallbackFIRED
|
||||
this._uC = _o&&_o.update || null; // _on UpdateCallback
|
||||
this._cC = _o&&_o.complete || null; // _on CompleteCallback
|
||||
this._pC = _o&&_o.pause || null; // _on PauseCallback
|
||||
this._rC = _o&&_o.play || null; // _on ResumeCallback
|
||||
this._stC = _o&&_o.stop || null; // _on StopCallback
|
||||
this.repeat = this._r; // we cache the number of repeats to be able to put it back after all cycles finish
|
||||
|
||||
K._queue(this);
|
||||
};
|
||||
|
||||
var w = K.Tween.prototype;
|
||||
|
||||
w.start = function (t) {
|
||||
this.scrollIn();
|
||||
|
||||
K.perspective(this._el,this); // apply the perspective and transform origin
|
||||
|
||||
if ( this._rpr ) { this.stack(); } // on start we reprocess the valuesStart for TO() method
|
||||
|
||||
if (K.svg && this._vE.path) K.svg.pathCross(this); // on start we process the SVG paths
|
||||
|
||||
for ( var e in this._vE ) {
|
||||
this._vSR[e] = this._vS[e];
|
||||
}
|
||||
if (!this._sCF) {
|
||||
if (this._sC) { this._sC.call(); }
|
||||
this._sCF = true;
|
||||
}
|
||||
|
||||
// now it's a good time to start
|
||||
K._tws.push(this);
|
||||
this.playing = true;
|
||||
this.paused = false;
|
||||
this._sCF = false;
|
||||
this._sT = t || window.performance.now();
|
||||
this._sT += this._dl;
|
||||
|
||||
if (!K._t) K._tk();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
w.stop = function () {
|
||||
if (!this.paused && this.playing) {
|
||||
K.remove(this);
|
||||
this.playing = false;
|
||||
this.paused = false;
|
||||
this.scrollOut();
|
||||
|
||||
if (this._stC !== null) {
|
||||
this._stC.call();
|
||||
}
|
||||
this.stopChainedTweens();
|
||||
this.close();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
w.pause = function() {
|
||||
if (!this.paused && this.playing) {
|
||||
K.remove(this);
|
||||
this.paused = true;
|
||||
this._pST = window.performance.now();
|
||||
if (this._pC !== null) {
|
||||
this._pC.call();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
w.play = w.resume = function () {
|
||||
if (this.paused && this.playing) {
|
||||
this.paused = false;
|
||||
if (this._rC !== null) { this._rC.call(); }
|
||||
this._sT += window.performance.now() - this._pST;
|
||||
K.add(this);
|
||||
if (!K._t) K._tk(); // restart ticking if stopped
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
w.reverse = function () {
|
||||
if (this._y) {
|
||||
for (var p in this._vE) {
|
||||
var tmp = this._vSR[p];
|
||||
this._vSR[p] = this._vE[p];
|
||||
this._vE[p] = tmp;
|
||||
this._vS[p] = this._vSR[p];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
w.chain = function () { this._cT = arguments; return this; };
|
||||
|
||||
w.stopChainedTweens = function () {
|
||||
var i = 0, ctl =this._cT.length;
|
||||
for (i; i < ctl; i++) {
|
||||
this._cT[i].stop();
|
||||
}
|
||||
};
|
||||
|
||||
w.scrollOut = function(){ //prevent scroll when tweening scroll
|
||||
if ( 'scroll' in this._vE || 'scrollTop' in this._vE ) {
|
||||
this.removeListeners();
|
||||
document.body.removeAttribute('data-tweening');
|
||||
}
|
||||
};
|
||||
|
||||
w.scrollIn = function(){
|
||||
if ( 'scroll' in this._vE || 'scrollTop' in this._vE ) {
|
||||
if (!document.body.getAttribute('data-tweening') ) {
|
||||
document.body.setAttribute('data-tweening', 'scroll');
|
||||
this.addListeners();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
w.addListeners = function () {
|
||||
document.addEventListener(_ev, K.preventScroll, false);
|
||||
};
|
||||
|
||||
w.removeListeners = function () {
|
||||
document.removeEventListener(_ev, K.preventScroll, false);
|
||||
};
|
||||
|
||||
w.stack = function () { // stack transform props for .to() chains
|
||||
var f = this.prS();
|
||||
this._vS = {};
|
||||
this._vS = K.prP(f)[0];
|
||||
|
||||
for ( var p in this._vS ) {
|
||||
if ( p === 'transform' && (p in this._vE) ){
|
||||
for ( var sp in this._vS[p]) {
|
||||
if (!(sp in this._vE[p])) { this._vE[p][sp] = {}; }
|
||||
for ( var spp in this._vS[p][sp] ) { // 3rd level
|
||||
if ( this._vS[p][sp][spp].value !== undefined ) {
|
||||
if (!(spp in this._vE[p][sp])) { this._vE[p][sp][spp] = {}; }
|
||||
for ( var sppp in this._vS[p][sp][spp]) { // spp = translateX | rotateX | skewX | rotate2d
|
||||
if ( !(sppp in this._vE[p][sp][spp])) {
|
||||
this._vE[p][sp][spp][sppp] = this._vS[p][sp][spp][sppp]; // sppp = unit | value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( 'value' in this._vS[p][sp] && (!('value' in this._vE[p][sp])) ) { // 2nd level
|
||||
for ( var spp1 in this._vS[p][sp] ) { // scale
|
||||
if (!(spp1 in this._vE[p][sp])) {
|
||||
this._vE[p][sp][spp1] = this._vS[p][sp][spp1]; // spp = unit | value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//prepare valuesStart for .to() method
|
||||
w.prS = function () {
|
||||
var f = {}, el = this._el, to = this._vS, cs = this.gIS('transform'), deg = ['rotate','skew'], ax = ['X','Y','Z'];
|
||||
|
||||
for (var p in to){
|
||||
if ( _tf.indexOf(p) !== -1 ) {
|
||||
var r2d = (p === 'rotate' || p === 'translate' || p === 'scale');
|
||||
if ( /translate/.test(p) && p !== 'translate' ) {
|
||||
f['translate3d'] = cs['translate3d'] || _d[p];
|
||||
} else if ( r2d ) { // 2d transforms
|
||||
f[p] = cs[p] || _d[p];
|
||||
} else if ( !r2d && /rotate|skew/.test(p) ) { // all angles
|
||||
for (var d=0; d<2; d++) {
|
||||
for (var a = 0; a<3; a++) {
|
||||
var s = deg[d]+ax[a];
|
||||
if (_tf.indexOf(s) !== -1 && (s in to) ) { f[s] = cs[s] || _d[s]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( _sc.indexOf(p) === -1 ) {
|
||||
if (p === 'opacity' && _isIE8 ) { // handle IE8 opacity
|
||||
var co = this.gCS('filter');
|
||||
f['opacity'] = typeof co === 'number' ? co : _d['opacity'];
|
||||
} else {
|
||||
if (p==='attr') {
|
||||
f[p] = {};
|
||||
for (var p1 in to[p]){
|
||||
f[p][p1] = K.gCA(el,p1);
|
||||
}
|
||||
} else if (p==='path') {
|
||||
f[p] = el.getAttribute('d');
|
||||
} else {
|
||||
f[p] = this.gCS(p) || _d[p];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
f[p] = (el === null || el === undefined) ? (window.pageYOffset || _sct.scrollTop) : el.scrollTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( var p in cs ){ // also add to _vS values from previous tweens
|
||||
if ( _tf.indexOf(p) !== -1 && (!( p in to )) ) {
|
||||
f[p] = cs[p] || _d[p];
|
||||
}
|
||||
}
|
||||
return f;
|
||||
};
|
||||
|
||||
w.gIS = function(p) { // gIS = get transform style for element from cssText for .to() method, the sp is for transform property
|
||||
if (!this._el) return; // if the scroll applies to `window` it returns as it has no styling
|
||||
var l = this._el, cst = l.style.cssText,//the cssText
|
||||
trsf = {}; //the transform object
|
||||
// if we have any inline style in the cssText attribute, usually it has higher priority
|
||||
var css = cst.replace(/\s/g,'').split(';'), i=0, csl = css.length;
|
||||
for ( i; i<csl; i++ ){
|
||||
if ( /transform/.test(css[i])) {
|
||||
var tps = css[i].split(':')[1].split(')'), k=0, tpl = tps.length; //all transform properties
|
||||
for ( k; k< tpl; k++){
|
||||
var tp = tps[k].split('('); //each transform property
|
||||
if ( tp[0] !== '' && _tf.indexOf(tp) ){
|
||||
trsf[tp[0]] = /translate3d/.test(tp[0]) ? tp[1].split(',') : tp[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return trsf;
|
||||
};
|
||||
|
||||
w.gCS = function (p) { // gCS = get style property for element from computedStyle for .to() method
|
||||
var el = this._el, cs = window.getComputedStyle(el) || el.currentStyle, //the computed style
|
||||
ppp = ( !_isIE8 && _pfT && ( /transform|Radius/.test(p) ) ) ? ('-'+ _pf.toLowerCase()+'-'+p) : p, //prefixed property for CSS match
|
||||
s = ( (_pfT && p==='transform' ) || (_pfT && /radius/i.test(p) )) ? cs[ppp] : cs[p]; // s the property style value
|
||||
|
||||
if ( p !== 'transform' && (ppp in cs) ) {
|
||||
if ( s ){
|
||||
if (ppp==='filter') { // handle IE8 opacity
|
||||
var si1 = parseInt(s.split('=')[1].replace(')','')), si = parseFloat(si1/100);
|
||||
return si;
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
} else {
|
||||
return _d[p];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
w.close = function () {
|
||||
var self = this;
|
||||
setTimeout(function(){
|
||||
var i = K._tws.indexOf(self);
|
||||
if (i === K._tws.length-1) { K.s(); }
|
||||
if (self.repeat > 0) { self._r = self.repeat; }
|
||||
if (self._y && self.reversed===true) { self.reverse(); self.reversed = false; }
|
||||
self.playing = false;
|
||||
},64)
|
||||
};
|
||||
|
||||
// the multi elements Tween constructs
|
||||
K.TweensTO = function (els, vE, o) { // .to
|
||||
this.tweens = []; var i, tl = els.length, _o = [];
|
||||
for ( i = 0; i < tl; i++ ) {
|
||||
_o[i] = o || {}; o.delay = o.delay || 0;
|
||||
_o[i].delay = i>0 ? o.delay + (o.offset||0) : o.delay;
|
||||
this.tweens.push( K.to(els[i], vE, _o[i]) );
|
||||
}
|
||||
};
|
||||
K.TweensFT = function (els, vS, vE, o) { // .fromTo
|
||||
this.tweens = []; var i, tl = els.length, _o = [];
|
||||
for ( i = 0; i < tl; i++ ) {
|
||||
_o[i] = o || {}; o.delay = o.delay || 0;
|
||||
_o[i].delay = i>0 ? o.delay + (o.offset||0) : o.delay;
|
||||
this.tweens.push( K.fromTo(els[i], vS, vE, _o[i]) );
|
||||
}
|
||||
};
|
||||
var ws = K.TweensTO.prototype = K.TweensFT.prototype;
|
||||
ws.start = function(t){
|
||||
t = t || window.performance.now();
|
||||
var i, tl = this.tweens.length;
|
||||
for ( i = 0; i < tl; i++ ) {
|
||||
this.tweens[i].start(t);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
ws.stop = function(){ for ( var i = 0; i < this.tweens.length; i++ ) { this.tweens[i].stop(); } return this; }
|
||||
ws.pause = function(){ for ( var i = 0; i < this.tweens.length; i++ ) { this.tweens[i].pause(); } return this; }
|
||||
ws.chain = function(){ this.tweens[this.tweens.length-1]._cT = arguments; return this; }
|
||||
ws.play = ws.resume = function(){ for ( var i = 0; i < this.tweens.length; i++ ) { this.tweens[i].play(); } return this; }
|
||||
|
||||
return K;
|
||||
}));
|
158
svg.html
158
svg.html
|
@ -81,11 +81,11 @@
|
|||
<div class="content-wrap">
|
||||
<h2>SVG Plugin</h2>
|
||||
<p>The SVG Plugin for KUTE.js extends the core engine and enables animation for various CSS properties specific to SVG elements as well as morphing path shapes. We'll dig into this in great detail as well as provide valuable tips on how to configure your animation for best performance and visual aesthetics. The SVG Plugin is very light, maybe one of the lightest out there, still, you will find it to be very powerful and flexible.</p>
|
||||
<p>Keep in mind that older browsers like Internet Explorer 8 and below as well as stock browser from Android 4.3 and below <a href="http://caniuse.com/#search=svg" target="_blank">do not support inline SVG</a>.</p>
|
||||
<p>Keep in mind that older browsers like Internet Explorer 8 and below as well as stock browser from Android 4.3 and below <a href="http://caniuse.com/#search=svg" target="_blank">do not support inline SVG</a> so make sure to fiter out your SVG tweens.</p>
|
||||
<h3>Shape Morphing</h3>
|
||||
<p>One of the most important parts of the plugin is the shape morphing capability. It only applies to inline <code><path></code> and <code><glyph></code> SVG elements, with closed shapes (their <code>d</code> attribute ends with <code>z</code>). The plugin is packed with specific tween options to help you improve the morph animation:</p>
|
||||
<p>One of the most important parts of the plugin is the shape morphing capability. It only applies to inline <code><path></code> and <code><glyph></code> SVG elements, with closed shapes (their <code>d</code> attribute ends with <code>z</code>). 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 with these points, the arrays that we need for interpolation. Further more, with a set of options we can then rearrange / reverse these arrays to optimize and / or maximize the visual effect of the morph:</p>
|
||||
<ul>
|
||||
<li><kbd>showMorphInfo: true</kbd> when <code>true</code> the script will log valuable information about the morph such as default/current sample size, number of points based on sample size, the recommended index for points rotation, or if one of the shapes require to be reversed. By default this option is <code>false</code> for serious performance reasons.</li>
|
||||
<li><kbd>showMorphInfo: true</kbd> when <code>true</code> the script will log valuable information about the morph such as default/current sample size, number of points based on sample size, the recommended index for points rotation, or if one of the shapes require to be reversed. By default this option is <code>false</code> for serious performance reasons. This option will also show you the first point for both shapes so you can visualize</li>
|
||||
<li><kbd>morphPrecision: Number</kbd> option allows you to set the sampling size of the morph. The lesser value the better visual but the more power consumption and less performance. The default value is 25 but the <a href="http://bl.ocks.org/mbostock/3081153" target="_blank">D3.js example</a> uses 4.</li>
|
||||
<li><kbd>morphIndex: Number</kbd> option allows you to rotate the second/end path in a way that the points travel the least possible distance during morph, and as an effect the morph animation feel more "natural". By default, this option is not set.</li>
|
||||
<li><kbd>reverseFirstPath: true</kbd> when is <code>true</code> this option allows you to reverse the draw direction of the FIRST shape. By default this option is <code>false</code>.</li>
|
||||
|
@ -113,21 +113,21 @@ var tween = KUTE.to('#rectangle', { path: '#star' }).start();
|
|||
var tween = KUTE.to('#rectangle', { path: 'M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011' }).start();
|
||||
</code></pre>
|
||||
|
||||
<p>For all the above tween objects the animation should look like this:</p>
|
||||
<p>For all the above tween objects the animation should look like this:</p>
|
||||
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" >
|
||||
<path id="rectangle" class="bg-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"/>
|
||||
<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"/>
|
||||
</svg>
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtn" class="btn btn-green" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>As you can see, the animation could need some fine tunning. Let's open the console, and this time we'll pass in the <code>showMorphInfo: true</code> tween option that will help us find the best possible morph as performance and visual. Have a look:</p>
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" >
|
||||
<path id="rectangle" class="bg-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"/>
|
||||
<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"/>
|
||||
</svg>
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtn" class="btn btn-green" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>As you can see, the animation could need some fine tunning. Let's open the console, and this time we'll pass in the <code>showMorphInfo: true</code> tween option that will help us find the best possible morph as performance and visual. Have a look:</p>
|
||||
|
||||
<pre><code class="language-javascript">// let's check the morph info again
|
||||
var tween = KUTE.to('#rectangle', { path: '#star' }, {showMorphInfo: true}).start();
|
||||
|
@ -141,23 +141,54 @@ If the current animation is not satisfactory, consider reversing one of the path
|
|||
*/
|
||||
</code></pre>
|
||||
|
||||
<p>Next, we're going to set the <code>morphIndex: 79</code> and we will get an improved morph.</p>
|
||||
<div class="featurettes">
|
||||
<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="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"/>
|
||||
<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>
|
||||
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtn1" class="btn btn-orange" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>Much better! You can play with <code>morphIndex</code> value, maybe you can get an even better or more interesting morph.</p>
|
||||
<p>Next, we're going to set the <code>morphIndex: 79</code> option and we will get an improved morph.</p>
|
||||
<div class="featurettes">
|
||||
<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="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"/>
|
||||
<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>
|
||||
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtn1" class="btn btn-orange" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>Much better! You can play with the <code>morphIndex</code> value, maybe you can get an even better or more interesting morph. Also notice the above shapes have some points indicating the start for each shape, making it even easier for you to improve the morph, a nice addition to the <code>showMorphInfo</code> option.</p>
|
||||
|
||||
<h4>Morphing Polygon Paths</h4>
|
||||
<p>When your paths are only <code>lineto</code>, <code>vertical-lineto</code> and <code>horizontal-lineto</code> based shapes (the <code>d</code> attribute consists of <code>L</code>, <code>V</code> and <code>H</code> path commands), the SVG Plugin will work differently: it will use their points instead of sampling new ones. As a result, we boost the visual and maximize the performance. The <code>morphPrecision</code> option will not apply since the paths are already polygons, still you will have access to all the other options.</p>
|
||||
<pre><code class="language-javascript">// let's morph a triangle into a star
|
||||
var tween1 = KUTE.to('#triangle', { path: '#star' }).start();
|
||||
|
||||
// or same path into a square
|
||||
var tween2 = KUTE.to('#triangle', { path: '#square' }).start();
|
||||
</code></pre>
|
||||
|
||||
<p>In the example below the triangle shape will morph into a square, then the square will morph into a star, so 2 tweens chained with a third that will morph back to the original triangle shape. For each tween the morph will use the number of points from the shape with most points as a sample size for the other shape. Let's have a look at the demo.</p>
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="morph-example2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" >
|
||||
<path id="square" style="visibility:hidden" d="M25.508,12.011 L576.715,12.011 L576.715,584.766 L25.508,584.766 L25.508,12.011 z"/>
|
||||
|
||||
<path id="square2" style="visibility:hidden" d="M25.508,12.011 H576.715 V584.766 H25.508 V12.011z"/>
|
||||
<path id="square3" style="visibility:hidden" d="M25.508,12.011 L576.715,12.011 V584.766 L25.508,584.766 V12.011 z"/>
|
||||
|
||||
<path id="triangle" class="bg-indigo" d="M301.113,12.011L576.715,584.766L25.508,584.766L301.113,12.011z"/>
|
||||
|
||||
<path id="star2" 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>
|
||||
|
||||
|
||||
<div class="example-buttons">
|
||||
<a id="morphBtn2" class="btn btn-green" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>The morph for polygon paths is the best morph in terms of performance so it's worth keeping that in mind. Also using paths with only <code>L</code> path command will make sure to prevent value processing and allow the animation to start as fast as possible.</p>
|
||||
|
||||
<h4>Multi Path Example</h4>
|
||||
<p>In other cases, you may want to morph multiple paths at the same time. Let's have a look at the following paths:</p>
|
||||
<p>In other cases, you may want to morph paths that have subpaths. Let's have a look at the following paths:</p>
|
||||
<pre><code class="language-markup"><svg id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path d="M206.115,255.957c-23.854-12.259-47.043-18.479-68.94-18.479c-2.978,0-5.976,0.09-8.974,0.354 c-27.94,2.312-53.461,9.684-69.875,15.414c-4.354,1.599-8.817,3.288-13.415,5.152L0,414.096 c30.851-11.416,58.146-16.969,83.135-16.969c40.423,0,69.764,15.104,93.996,30.652c11.481-38.959,39.022-133.045,47.241-161.162 C218.397,262.975,212.334,259.332,206.115,255.957z
|
||||
M264.174,295.535l-45.223,157.074c13.416,7.686,58.549,32.024,93.105,32.024 c27.896,0,59.127-7.147,95.417-21.896l43.179-150.988c-29.316,9.461-57.438,14.26-83.732,14.26 C318.945,326.01,285.363,310.461,264.174,295.535z
|
||||
|
@ -169,7 +200,7 @@ If the current animation is not satisfactory, consider reversing one of the path
|
|||
M192 471.918l-191.844-26.297-0.010-157.621h191.854z"/>
|
||||
</svg>
|
||||
</code></pre>
|
||||
<p>As you can see, both these paths have additional subpaths, and KUTE.js will only animate the first of both in this case. To animate them all, we need to break them into multiple paths, so we can handle each path morph properly.</p>
|
||||
<p>As you can see, both these paths have subpaths, and KUTE.js will only animate the first of both in this case. To animate them all, we need to break them into multiple paths, so we can handle each path morph properly.</p>
|
||||
<pre><code class="language-markup"><svg id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
|
||||
<path id="w11" d="M206.115,255.957c-23.854-12.259-47.043-18.479-68.94-18.479c-2.978,0-5.976,0.09-8.974,0.354 c-27.94,2.312-53.461,9.684-69.875,15.414c-4.354,1.599-8.817,3.288-13.415,5.152L0,414.096 c30.851-11.416,58.146-16.969,83.135-16.969c40.423,0,69.764,15.104,93.996,30.652c11.481-38.959,39.022-133.045,47.241-161.162 C218.397,262.975,212.334,259.332,206.115,255.957z"/>
|
||||
<path id="w12" d="M264.174,295.535l-45.223,157.074c13.416,7.686,58.549,32.024,93.105,32.024 c27.896,0,59.127-7.147,95.417-21.896l43.179-150.988c-29.316,9.461-57.438,14.26-83.732,14.26 C318.945,326.01,285.363,310.461,264.174,295.535z"/>
|
||||
|
@ -182,7 +213,7 @@ If the current animation is not satisfactory, consider reversing one of the path
|
|||
<path id="w24" style="visibility:hidden" d="M192 471.918l-191.844-26.297-0.010-157.621h191.854z"/>
|
||||
</svg>
|
||||
</code></pre>
|
||||
<p>After a close inspection we determined that paths are not ordered the same so it seems we need to tween the paths in a way that their points travel the least possible distance, as follows: w11 to w24, w13 to w21, w14 to w22 and w12 to w23.</p>
|
||||
<p>After a close inspection we determined that paths are not ordered the same so it seems we need to tween the paths in a way that their points travel the least possible distance, as follows: <code>#w11</code> to <code>#w24</code>, <code>#w13</code> to <code>#w21</code>, <code>#w14</code> to <code>#w22</code> and <code>#w12</code> to <code>#w23</code>.</p>
|
||||
<p>Now we can write the tween objects and get to working:</p>
|
||||
<pre><code class="language-javascript">var multiMorph1 = KUTE.to('#w11', { path: '#w24' }).start();
|
||||
var multiMorph2 = KUTE.to('#w13', { path: '#w21' }).start();
|
||||
|
@ -190,30 +221,38 @@ var multiMorph3 = KUTE.to('#w14', { path: '#w22' }).start();
|
|||
var multiMorph3 = KUTE.to('#w12', { path: '#w23' }).start();
|
||||
</code></pre>
|
||||
|
||||
<p>As you can imagine, it's quite hard if not impossible to code something that would do all this work automatically, so after a few minutes of tweaking the options, here's what we should see:</p>
|
||||
<p>As you can imagine, it's quite hard if not impossible to code something that would do all this work automatically, so after a minute or two tweaking the options, here's what we should see:</p>
|
||||
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 550 550" >
|
||||
<path id="w11" class="bg-red" d="M206.115,255.957c-23.854-12.259-47.043-18.479-68.94-18.479c-2.978,0-5.976,0.09-8.974,0.354 c-27.94,2.312-53.461,9.684-69.875,15.414c-4.354,1.599-8.817,3.288-13.415,5.152L0,414.096 c30.851-11.416,58.146-16.969,83.135-16.969c40.423,0,69.764,15.104,93.996,30.652c11.481-38.959,39.022-133.045,47.241-161.162 C218.397,262.975,212.334,259.332,206.115,255.957z"/>
|
||||
<path id="w12" class="bg-orange" d="M264.174,295.535l-45.223,157.074c13.416,7.686,58.549,32.024,93.105,32.024 c27.896,0,59.127-7.147,95.417-21.896l43.179-150.988c-29.316,9.461-57.438,14.26-83.732,14.26 C318.945,326.01,285.363,310.461,264.174,295.535z"/>
|
||||
<path id="w13" class="bg-green" d="M146.411,184.395c38.559,0.399,67.076,15.104,90.708,30.251l46.376-158.672c-9.772-5.598-35.403-19.547-53.929-24.3c-12.193-2.842-25.01-4.308-38.602-4.308c-25.898,0.488-54.194,6.973-86.444,19.9 L60.3,202.564c32.404-12.218,60.322-18.17,86.043-18.17C146.366,184.395,146.411,184.395,146.411,184.395L146.411,184.395z"/>
|
||||
<path id="w14" class="bg-blue" d="M512,99.062c-29.407,11.416-58.104,17.233-85.514,17.233c-45.844,0-79.646-15.901-101.547-31.183L278.964,244.23 c30.873,19.854,64.146,29.939,99.062,29.939c28.474,0,57.97-6.84,87.73-20.344l-0.091-1.111l1.867-0.443L512,99.062z"/>
|
||||
|
||||
<path id="w21" style="visibility:hidden" d="M0.175 256l-0.175-156.037 192-26.072v182.109z"/>
|
||||
<path id="w22" style="visibility:hidden" d="M224 69.241l255.936-37.241v224h-255.936z"/>
|
||||
<path id="w23" style="visibility:hidden" d="M479.999 288l-0.063 224-255.936-36.008v-187.992z"/>
|
||||
<path id="w24" style="visibility:hidden" d="M192 471.918l-191.844-26.297-0.010-157.621h191.854z"/>
|
||||
</svg>
|
||||
|
||||
<div class="example-buttons">
|
||||
<a id="multiMorphBtn" class="btn btn-olive" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>This final touch required using <code>reverseSecondPath:true</code> option for all tweens because each shape have a slightly different position from its corresponding shape, so make sure to check the <a href="assets/js/svg.js" target="_blank">svg.js</a> for a full code review.</p>
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 550 550" >
|
||||
<path id="w11" class="bg-red" d="M206.115,255.957c-23.854-12.259-47.043-18.479-68.94-18.479c-2.978,0-5.976,0.09-8.974,0.354 c-27.94,2.312-53.461,9.684-69.875,15.414c-4.354,1.599-8.817,3.288-13.415,5.152L0,414.096 c30.851-11.416,58.146-16.969,83.135-16.969c40.423,0,69.764,15.104,93.996,30.652c11.481-38.959,39.022-133.045,47.241-161.162 C218.397,262.975,212.334,259.332,206.115,255.957z"/>
|
||||
<path id="w12" class="bg-orange" d="M264.174,295.535l-45.223,157.074c13.416,7.686,58.549,32.024,93.105,32.024 c27.896,0,59.127-7.147,95.417-21.896l43.179-150.988c-29.316,9.461-57.438,14.26-83.732,14.26 C318.945,326.01,285.363,310.461,264.174,295.535z"/>
|
||||
<path id="w13" class="bg-green" d="M146.411,184.395c38.559,0.399,67.076,15.104,90.708,30.251l46.376-158.672c-9.772-5.598-35.403-19.547-53.929-24.3c-12.193-2.842-25.01-4.308-38.602-4.308c-25.898,0.488-54.194,6.973-86.444,19.9 L60.3,202.564c32.404-12.218,60.322-18.17,86.043-18.17C146.366,184.395,146.411,184.395,146.411,184.395L146.411,184.395z"/>
|
||||
<path id="w14" class="bg-blue" d="M512,99.062c-29.407,11.416-58.104,17.233-85.514,17.233c-45.844,0-79.646-15.901-101.547-31.183L278.964,244.23 c30.873,19.854,64.146,29.939,99.062,29.939c28.474,0,57.97-6.84,87.73-20.344l-0.091-1.111l1.867-0.443L512,99.062z"/>
|
||||
|
||||
<path id="w21" style="visibility:hidden" d="M0.175 256l-0.175-156.037 192-26.072v182.109z"/>
|
||||
<path id="w22" style="visibility:hidden" d="M224 69.241l255.936-37.241v224h-255.936z"/>
|
||||
<path id="w23" style="visibility:hidden" d="M479.999 288l-0.063 224-255.936-36.008v-187.992z"/>
|
||||
<path id="w24" style="visibility:hidden" d="M192 471.918l-191.844-26.297-0.010-157.621h191.854z"/>
|
||||
</svg>
|
||||
|
||||
<div class="example-buttons">
|
||||
<a id="multiMorphBtn" class="btn btn-olive" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>Note that this final touch required using <code>reverseSecondPath:true</code> option for all tweens because each shape have a slightly different position from its corresponding shape, so make sure to check the <a href="assets/js/svg.js" target="_blank">svg.js</a> for a full code review.</p>
|
||||
|
||||
<h4>Complex Example</h4>
|
||||
<p>The last morph example is a bit more complex as the paths have subpaths with different positions and other important differences such as having different amounts of subpaths. In that case you have to manually clone one or more paths in a way that the number of starting shapes is equal to the number of ending shapes, as well as making sure the starting shapes are close to their corresponding end shapes; at this point you should be just like in the previous example. So without further talking, let's get into it:</p>
|
||||
<p>The last morph example is a bit more complex as the paths have subpaths with different positions and other important differences such as having different amounts of subpaths as well as significant differences of their positions. In this case you have to manually clone one or more paths in a way that the number of starting shapes is equal to the number of ending shapes, as well as making sure the starting shapes are close to their corresponding end shapes; at this point you should be just like in the previous example.</p>
|
||||
<p>An important aspect of multi path morph is syncronization: since the <code>.to()</code> method will prepare the paths for interpolation at animation start, and this usually takes a bit of time, the problem can be easily solved as always using the <code>.fromTo()</code> method. So, let's get into it:</p>
|
||||
|
||||
<pre><code class="language-javascript">// complex multi morph, the paths should be self explanatory
|
||||
var morph1 = KUTE.fromTo('#start-container', { path: '#start-container' }, { path: '#end-container' });
|
||||
var morph2 = KUTE.fromTo('#startpath1', { path: '#startpath1' }, { path: '#endpath1' });
|
||||
var morph3 = KUTE.fromTo('#startpath1-clone', { path: '#startpath1-clone' }, { path: '#endpath1' });
|
||||
var morph4 = KUTE.fromTo('#startpath2', { path: '#startpath2' }, { path: '#endpath2' });
|
||||
</code></pre>
|
||||
<p>As with the previous example, you should change which path will morph to which path so that their points travel the least possible distance and the morph animation looks visually appealing.</p>
|
||||
<div class="featurettes">
|
||||
<svg class="example-box-model example-box" id="multi-morph-example" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 513 513">
|
||||
<path id="rectangle-container" class="bg-blue" d="M426.671 0h-341.328c-46.937 0-85.343 38.405-85.343 85.345v341.311c0 46.969 38.406 85.344 85.343 85.344h341.328c46.938 0 85.329-38.375 85.329-85.345v-341.31c0-46.94-38.391-85.345-85.329-85.345z"/>
|
||||
|
@ -231,16 +270,17 @@ var multiMorph3 = KUTE.to('#w12', { path: '#w23' }).start();
|
|||
<a id="compliMorphBtn" class="btn btn-red" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>While there are other tools such as <a href="http://alexk111.github.io/SVG-Morpheus/" target="_blank">SVGMorpheus</a> to enable this kind of multi-path morph, they lack in options to improve the visual and performance. The demos look acceptable in most cases, but the SVGs were manually prepared/optimized which makes it pretty much unusable on a broader horizon. Again, the SVG Plugin for KUTE.js uses approximatelly the same algorithm as D3.js for determining the coordinates for tween, it's super light, it's a better solution.</p>
|
||||
<p>While there are other tools such as <a href="http://alexk111.github.io/SVG-Morpheus/" target="_blank">SVGMorpheus</a> to enable this kind of multi-path morph, they lack in options to improve the visual and performance. The demos look acceptable in most cases, but the SVGs were manually prepared/optimized which makes it pretty much unusable on a broader scope. The SVG Plugin for KUTE.js uses approximatelly the same algorithm as D3.js for determining the coordinates for tween, it's super light, it's a better solution.</p>
|
||||
|
||||
<h4>Recommendations</h4>
|
||||
<ul>
|
||||
<li>The SVG morph animation is very expensive so try to optimize the number of morph animations that run at the same time.</li>
|
||||
<li>When morphing subpaths/multipaths 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, don't forget about mobile devices.</li>
|
||||
<li>Large displays would need best resolution possible so a small <code>morphPrecision</code> value (1-10) would be required, assuming performant hardware are powering the displays. For small displays you can get quite comfortable with almost any value, including the default value.</li>
|
||||
<li>Polygons with only <code>lineto</code> path commands are best for performance.</li>
|
||||
<li>Faster animation speed could be a great trick to hide any polygonal "artefacts".</li>
|
||||
<li>Always use the <code>showMorphInfo:true</code> tween option to check how the values required for the morph change with every new option value, but <strong>never forget to disable it</strong> after you have optimized the morph to your liking, this option enables a function that detects the best index for points rotation that is very expensive and delays the animation for quite some time.</li>
|
||||
<li>The SVG morph performance is the same for both <code>.to()</code> and <code>.fromTo()</code> methods because the processing of the two paths happens on tween start delaying the animation, so keep that in mind when working with syncing multiple tweens, the morph will always start later.</li>
|
||||
<li>The SVG morph performance is the same for both <code>.to()</code> and <code>.fromTo()</code> methods, but the ones that use the second method will start faster, because the values have been prepared already and for the first method the processing of the two paths happens on tween start delaying the animation, so keep that in mind when working with syncing multiple tweens, the <code>.to()</code> based morph will always start later. Of course this assumes the you cache the tween objects first and start the animation later, if not (you start the animation on object creation), both methods will be delayed.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Drawing Stroke</h3>
|
||||
|
@ -342,7 +382,11 @@ var tween7 = KUTE.to('#myStopOpacity',{stopOpacity: 0.2});
|
|||
<a id="gradBtn" class="btn btn-yellow" href="javascript:void(0)">Start</a>
|
||||
</div>
|
||||
</div>
|
||||
<p>The SVG Plugin can be combined with the <a href="attr.html">Attributes Plugin</a> to enable even more advanced/complex animations for SVG elements.</p>
|
||||
<p>The SVG Plugin can be combined with the <a href="attr.html">Attributes Plugin</a> to enable even more advanced/complex animations for SVG elements.</p>
|
||||
|
||||
<h3>Future Plans</h3>
|
||||
<p>The future versions of the SVG Plugin might also feature improved cross browser transform animations, as currently the core engine only works and was tested with HTML elements of most types except SVG.</p>
|
||||
<p>Since most of this plugin scripting works with <code>path</code> or <code>glyph</code> elements, I'm also considering a very light <code>convertToPath</code> feature, but there are some <a href="https://github.com/Waest/SVGPathConverter" target="_blank">already out there</a>.</p>
|
||||
</div>
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
|
Loading…
Reference in a new issue