greensock-rails 1.16.1.0 → 1.17.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * VERSION: 0.3.3
3
- * DATE: 2014-07-17
4
- * UPDATES AND DOCS AT: http://www.greensock.com
2
+ * VERSION: 0.4.0
3
+ * DATE: 2015-05-06
4
+ * UPDATES AND DOCS AT: http://greensock.com
5
5
  *
6
6
  * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
7
7
  * This work is subject to the terms at http://greensock.com/standard-license or for
@@ -14,14 +14,17 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
14
14
 
15
15
  "use strict";
16
16
 
17
+ var _numExp = /(?:\d|\-|\+|=|#|\.)*/g,
18
+ _suffixExp = /[A-Za-z%]/g;
19
+
17
20
  _gsScope._gsDefine.plugin({
18
21
  propName: "attr",
19
22
  API: 2,
20
- version: "0.3.3",
23
+ version: "0.4.0",
21
24
 
22
25
  //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
23
26
  init: function(target, value, tween) {
24
- var p, start, end;
27
+ var p, start, end, suffix, i;
25
28
  if (typeof(target.setAttribute) !== "function") {
26
29
  return false;
27
30
  }
@@ -29,10 +32,23 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
29
32
  this._proxy = {};
30
33
  this._start = {}; // we record start and end values exactly as they are in case they're strings (not numbers) - we need to be able to revert to them cleanly.
31
34
  this._end = {};
35
+ this._suffix = {};
32
36
  for (p in value) {
33
- this._start[p] = this._proxy[p] = start = target.getAttribute(p);
34
- end = this._addTween(this._proxy, p, parseFloat(start), value[p], p);
35
- this._end[p] = end ? end.s + end.c : value[p];
37
+ this._start[p] = this._proxy[p] = start = target.getAttribute(p) + "";
38
+ this._end[p] = end = value[p] + "";
39
+ this._suffix[p] = suffix = _suffixExp.test(end) ? end.replace(_numExp, "") : _suffixExp.test(start) ? start.replace(_numExp, "") : "";
40
+ if (suffix) {
41
+ i = end.indexOf(suffix);
42
+ if (i !== -1) {
43
+ end = end.substr(0, i);
44
+ }
45
+ }
46
+ if(!this._addTween(this._proxy, p, parseFloat(start), end, p)) {
47
+ this._suffix[p] = ""; //not a valid tween - perhaps something like an <img src=""> attribute.
48
+ }
49
+ if (end.charAt(1) === "=") {
50
+ this._end[p] = (this._firstPT.s + this._firstPT.c) + suffix;
51
+ }
36
52
  this._overwriteProps.push(p);
37
53
  }
38
54
  return true;
@@ -44,10 +60,11 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
44
60
  var props = this._overwriteProps,
45
61
  i = props.length,
46
62
  lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start,
63
+ useSuffix = (lookup === this._proxy),
47
64
  p;
48
65
  while (--i > -1) {
49
66
  p = props[i];
50
- this._target.setAttribute(p, lookup[p] + "");
67
+ this._target.setAttribute(p, lookup[p] + (useSuffix ? this._suffix[p] : ""));
51
68
  }
52
69
  }
53
70
 
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * VERSION: 1.16.1
3
- * DATE: 2015-03-13
4
- * UPDATES AND DOCS AT: http://www.greensock.com
2
+ * VERSION: 1.17.0
3
+ * DATE: 2015-05-27
4
+ * UPDATES AND DOCS AT: http://greensock.com
5
5
  *
6
6
  * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
7
7
  * This work is subject to the terms at http://greensock.com/standard-license or for
@@ -31,10 +31,11 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
31
31
  p = CSSPlugin.prototype = new TweenPlugin("css");
32
32
 
33
33
  p.constructor = CSSPlugin;
34
- CSSPlugin.version = "1.16.1";
34
+ CSSPlugin.version = "1.17.0";
35
35
  CSSPlugin.API = 2;
36
36
  CSSPlugin.defaultTransformPerspective = 0;
37
37
  CSSPlugin.defaultSkewType = "compensated";
38
+ CSSPlugin.defaultSmoothOrigin = true;
38
39
  p = "px"; //we'll reuse the "p" variable to keep file size down
39
40
  CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
40
41
 
@@ -731,6 +732,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
731
732
  }
732
733
  },
733
734
 
735
+ _addNonTweeningNumericPT = function(target, prop, start, end, next, overwriteProp) { //cleans up some code redundancies and helps minification. Just a fast way to add a NUMERIC non-tweening CSSPropTween
736
+ var pt = new CSSPropTween(target, prop, start, end - start, next, -1, overwriteProp);
737
+ pt.b = start;
738
+ pt.e = pt.xs0 = end;
739
+ return pt;
740
+ },
741
+
734
742
  /**
735
743
  * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
736
744
  * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
@@ -1060,7 +1068,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1060
1068
 
1061
1069
 
1062
1070
  //transform-related methods and properties
1063
- CSSPlugin.useSVGTransformAttr = _isSafari; //Safari has some rendering bugs when applying CSS transforms to SVG elements, so default to using the "transform" attribute instead.
1071
+ CSSPlugin.useSVGTransformAttr = _isSafari || _isFirefox; //Safari and Firefox both have some rendering bugs when applying CSS transforms to SVG elements, so default to using the "transform" attribute instead (users can override this).
1064
1072
  var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent").split(","),
1065
1073
  _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
1066
1074
  _transformPropCSS = _prefixCSS + "transform",
@@ -1100,18 +1108,94 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1100
1108
  }
1101
1109
  return force;
1102
1110
  })(),
1103
- _parseSVGOrigin = function(e, local, decoratee, absolute) {
1104
- var bbox, v;
1105
- if (!absolute || !(v = absolute.split(" ")).length) {
1106
- bbox = e.getBBox();
1111
+ _parseSVGOrigin = function(e, local, decoratee, absolute, smoothOrigin) {
1112
+ var tm = e._gsTransform,
1113
+ m = _getMatrix(e, true),
1114
+ v, x, y, xOrigin, yOrigin, a, b, c, d, tx, ty, determinant, xOriginOld, yOriginOld;
1115
+ if (tm) {
1116
+ xOriginOld = tm.xOrigin; //record the original values before we alter them.
1117
+ yOriginOld = tm.yOrigin;
1118
+ }
1119
+ if (!absolute || (v = absolute.split(" ")).length < 2) {
1120
+ b = e.getBBox();
1107
1121
  local = _parsePosition(local).split(" ");
1108
- v = [(local[0].indexOf("%") !== -1 ? parseFloat(local[0]) / 100 * bbox.width : parseFloat(local[0])) + bbox.x,
1109
- (local[1].indexOf("%") !== -1 ? parseFloat(local[1]) / 100 * bbox.height : parseFloat(local[1])) + bbox.y];
1122
+ v = [(local[0].indexOf("%") !== -1 ? parseFloat(local[0]) / 100 * b.width : parseFloat(local[0])) + b.x,
1123
+ (local[1].indexOf("%") !== -1 ? parseFloat(local[1]) / 100 * b.height : parseFloat(local[1])) + b.y];
1124
+ }
1125
+ decoratee.xOrigin = xOrigin = parseFloat(v[0]);
1126
+ decoratee.yOrigin = yOrigin = parseFloat(v[1]);
1127
+ if (absolute && m !== _identity2DMatrix) { //if svgOrigin is being set, we must invert the matrix and determine where the absolute point is, factoring in the current transforms. Otherwise, the svgOrigin would be based on the element's non-transformed position on the canvas.
1128
+ a = m[0];
1129
+ b = m[1];
1130
+ c = m[2];
1131
+ d = m[3];
1132
+ tx = m[4];
1133
+ ty = m[5];
1134
+ determinant = (a * d - b * c);
1135
+ x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + ((c * ty - d * tx) / determinant);
1136
+ y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - ((a * ty - b * tx) / determinant);
1137
+ xOrigin = decoratee.xOrigin = v[0] = x;
1138
+ yOrigin = decoratee.yOrigin = v[1] = y;
1139
+ }
1140
+ if (tm) { //avoid jump when transformOrigin is changed - adjust the x/y values accordingly
1141
+ if (smoothOrigin || (smoothOrigin !== false && CSSPlugin.defaultSmoothOrigin !== false)) {
1142
+ x = xOrigin - xOriginOld;
1143
+ y = yOrigin - yOriginOld;
1144
+ //originally, we simply adjusted the x and y values, but that would cause problems if, for example, you created a rotational tween part-way through an x/y tween. Managing the offset in a separate variable gives us ultimate flexibility.
1145
+ //tm.x -= x - (x * m[0] + y * m[2]);
1146
+ //tm.y -= y - (x * m[1] + y * m[3]);
1147
+ tm.xOffset += (x * m[0] + y * m[2]) - x;
1148
+ tm.yOffset += (x * m[1] + y * m[3]) - y;
1149
+ } else {
1150
+ tm.xOffset = tm.yOffset = 0;
1151
+ }
1110
1152
  }
1111
- decoratee.xOrigin = parseFloat(v[0]);
1112
- decoratee.yOrigin = parseFloat(v[1]);
1113
1153
  e.setAttribute("data-svg-origin", v.join(" "));
1114
1154
  },
1155
+ _isSVG = function(e) {
1156
+ return !!(_SVGElement && typeof(e.getBBox) === "function" && e.getCTM && (!e.parentNode || (e.parentNode.getBBox && e.parentNode.getCTM)));
1157
+ },
1158
+ _identity2DMatrix = [1,0,0,1,0,0],
1159
+ _getMatrix = function(e, force2D) {
1160
+ var tm = e._gsTransform || new Transform(),
1161
+ rnd = 100000,
1162
+ isDefault, s, m, n, dec;
1163
+ if (_transformProp) {
1164
+ s = _getStyle(e, _transformPropCSS, null, true);
1165
+ } else if (e.currentStyle) {
1166
+ //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
1167
+ s = e.currentStyle.filter.match(_ieGetMatrixExp);
1168
+ s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
1169
+ }
1170
+ isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
1171
+ if (tm.svg || (e.getBBox && _isSVG(e))) {
1172
+ if (isDefault && (e.style[_transformProp] + "").indexOf("matrix") !== -1) { //some browsers (like Chrome 40) don't correctly report transforms that are applied inline on an SVG element (they don't get included in the computed style), so we double-check here and accept matrix values
1173
+ s = e.style[_transformProp];
1174
+ isDefault = 0;
1175
+ }
1176
+ m = e.getAttribute("transform");
1177
+ if (isDefault && m) {
1178
+ if (m.indexOf("matrix") !== -1) { //just in case there's a "transform" value specified as an attribute instead of CSS style. Accept either a matrix() or simple translate() value though.
1179
+ s = m;
1180
+ isDefault = 0;
1181
+ } else if (m.indexOf("translate") !== -1) {
1182
+ s = "matrix(1,0,0,1," + m.match(/(?:\-|\b)[\d\-\.e]+\b/gi).join(",") + ")";
1183
+ isDefault = 0;
1184
+ }
1185
+ }
1186
+ }
1187
+ if (isDefault) {
1188
+ return _identity2DMatrix;
1189
+ }
1190
+ //split the matrix values out into an array (m for matrix)
1191
+ m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
1192
+ i = m.length;
1193
+ while (--i > -1) {
1194
+ n = Number(m[i]);
1195
+ m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
1196
+ }
1197
+ return (force2D && m.length > 6) ? [m[0], m[1], m[4], m[5], m[12], m[13]] : m;
1198
+ },
1115
1199
 
1116
1200
  /**
1117
1201
  * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
@@ -1131,37 +1215,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1131
1215
  rnd = 100000,
1132
1216
  zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0,
1133
1217
  defaultTransformPerspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0,
1134
- isDefault, s, m, i, n, dec, scaleX, scaleY, rotation, skewX;
1135
- if (_transformProp) {
1136
- s = _getStyle(t, _transformPropCSS, cs, true);
1137
- } else if (t.currentStyle) {
1138
- //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
1139
- s = t.currentStyle.filter.match(_ieGetMatrixExp);
1140
- s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
1141
- }
1142
- isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
1143
- tm.svg = !!(_SVGElement && typeof(t.getBBox) === "function" && t.getCTM && (!t.parentNode || (t.parentNode.getBBox && t.parentNode.getCTM))); //don't just rely on "instanceof _SVGElement" because if the SVG is embedded via an object tag, it won't work (SVGElement is mapped to a different object)
1218
+ m, i, scaleX, scaleY, rotation, skewX;
1219
+
1220
+ tm.svg = !!(t.getBBox && _isSVG(t));
1144
1221
  if (tm.svg) {
1145
- if (isDefault && (t.style[_transformProp] + "").indexOf("matrix") !== -1) { //some browsers (like Chrome 40) don't correctly report transforms that are applied inline on an SVG element (they don't get included in the computed style), so we double-check here and accept matrix values
1146
- s = t.style[_transformProp];
1147
- isDefault = false;
1148
- }
1149
1222
  _parseSVGOrigin(t, _getStyle(t, _transformOriginProp, _cs, false, "50% 50%") + "", tm, t.getAttribute("data-svg-origin"));
1150
1223
  _useSVGTransformAttr = CSSPlugin.useSVGTransformAttr || _forceSVGTransformAttr;
1151
- m = t.getAttribute("transform");
1152
- if (isDefault && m && m.indexOf("matrix") !== -1) { //just in case there's a "transform" value specified as an attribute instead of CSS style. Only accept a matrix, though.
1153
- s = m;
1154
- isDefault = 0;
1155
- }
1156
1224
  }
1157
- if (!isDefault) {
1158
- //split the matrix values out into an array (m for matrix)
1159
- m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
1160
- i = m.length;
1161
- while (--i > -1) {
1162
- n = Number(m[i]);
1163
- m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
1164
- }
1225
+ m = _getMatrix(t);
1226
+ if (m !== _identity2DMatrix) {
1227
+
1165
1228
  if (m.length === 16) {
1166
1229
  //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
1167
1230
  var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
@@ -1274,8 +1337,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1274
1337
  tm.scaleZ = 1;
1275
1338
  }
1276
1339
  if (tm.svg) {
1277
- tm.x -= tm.xOrigin - (tm.xOrigin * a - tm.yOrigin * b);
1278
- tm.y -= tm.yOrigin - (tm.yOrigin * d - tm.xOrigin * c);
1340
+ tm.x -= tm.xOrigin - (tm.xOrigin * a + tm.yOrigin * c);
1341
+ tm.y -= tm.yOrigin - (tm.xOrigin * b + tm.yOrigin * d);
1279
1342
  }
1280
1343
  }
1281
1344
  tm.zOrigin = zOrigin;
@@ -1286,14 +1349,18 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1286
1349
  }
1287
1350
  }
1288
1351
  }
1289
- //DEBUG: _log("parsed rotation of " + t.getAttribute("id")+": "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective);
1352
+ //DEBUG: _log("parsed rotation of " + t.getAttribute("id")+": "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective+ ", origin: "+ tm.xOrigin+ ","+ tm.yOrigin);
1290
1353
  if (rec) {
1291
1354
  t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
1292
1355
  if (tm.svg) { //if we're supposed to apply transforms to the SVG element's "transform" attribute, make sure there aren't any CSS transforms applied or they'll override the attribute ones. Also clear the transform attribute if we're using CSS, just to be clean.
1293
1356
  if (_useSVGTransformAttr && t.style[_transformProp]) {
1294
- _removeProp(t.style, _transformProp);
1357
+ TweenLite.delayedCall(0.001, function(){ //if we apply this right away (before anything has rendered), we risk there being no transforms for a brief moment and it also interferes with adjusting the transformOrigin in a tween with immediateRender:true (it'd try reading the matrix and it wouldn't have the appropriate data in place because we just removed it).
1358
+ _removeProp(t.style, _transformProp);
1359
+ });
1295
1360
  } else if (!_useSVGTransformAttr && t.getAttribute("transform")) {
1296
- t.removeAttribute("transform");
1361
+ TweenLite.delayedCall(0.001, function(){
1362
+ t.removeAttribute("transform");
1363
+ });
1297
1364
  }
1298
1365
  }
1299
1366
  }
@@ -1404,7 +1471,6 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1404
1471
  force3D = t.force3D,
1405
1472
  a11, a12, a13, a21, a22, a23, a31, a32, a33, a41, a42, a43,
1406
1473
  zOrigin, min, cos, sin, t1, t2, transform, comma, zero, skew, rnd;
1407
-
1408
1474
  //check to see if we should render as 2D (and SVGs must use 2D when _useSVGTransformAttr is true)
1409
1475
  if (((((v === 1 || v === 0) && force3D === "auto" && (this.tween._totalTime === this.tween._totalDuration || !this.tween._totalTime)) || !force3D) && !z && !perspective && !rotationY && !rotationX) || (_useSVGTransformAttr && isSVG) || !_supports3D) { //on the final render (which could be 0 for a from tween), if there are no 3D aspects, render in 2D to free up memory and improve performance especially on mobile devices. Check the tween's totalTime/totalDuration too in order to make sure it doesn't happen between repeats if it's a repeating tween.
1410
1476
 
@@ -1428,8 +1494,13 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1428
1494
  }
1429
1495
  }
1430
1496
  if (isSVG) {
1431
- x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12);
1432
- y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22);
1497
+ x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset;
1498
+ y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset;
1499
+ if (_useSVGTransformAttr && (t.xPercent || t.yPercent)) { //The SVG spec doesn't support percentage-based translation in the "transform" attribute, so we merge it into the matrix to simulate it.
1500
+ min = this.t.getBBox();
1501
+ x += t.xPercent * 0.01 * min.width;
1502
+ y += t.yPercent * 0.01 * min.height;
1503
+ }
1433
1504
  min = 0.000001;
1434
1505
  if (x < min) if (x > -min) {
1435
1506
  x = 0;
@@ -1573,8 +1644,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1573
1644
  z += a33*-zOrigin+zOrigin;
1574
1645
  }
1575
1646
  if (isSVG) { //due to bugs in some browsers, we need to manage the transform-origin of SVG manually
1576
- x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12);
1577
- y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22);
1647
+ x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset;
1648
+ y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset;
1578
1649
  }
1579
1650
  if (x < min && x > -min) {
1580
1651
  x = zero;
@@ -1603,19 +1674,21 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1603
1674
  };
1604
1675
 
1605
1676
  p = Transform.prototype;
1606
- p.x = p.y = p.z = p.skewX = p.skewY = p.rotation = p.rotationX = p.rotationY = p.zOrigin = p.xPercent = p.yPercent = 0;
1677
+ p.x = p.y = p.z = p.skewX = p.skewY = p.rotation = p.rotationX = p.rotationY = p.zOrigin = p.xPercent = p.yPercent = p.xOffset = p.yOffset = 0;
1607
1678
  p.scaleX = p.scaleY = p.scaleZ = 1;
1608
1679
 
1609
- _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent", {parser:function(t, e, p, cssp, pt, plugin, vars) {
1680
+ _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent,smoothOrigin", {parser:function(t, e, p, cssp, pt, plugin, vars) {
1610
1681
  if (cssp._lastParsedTransform === vars) { return pt; } //only need to parse the transform once, and only if the browser supports it.
1611
1682
  cssp._lastParsedTransform = vars;
1612
- var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
1683
+ var originalGSTransform = t._gsTransform,
1684
+ m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform),
1613
1685
  style = t.style,
1614
1686
  min = 0.000001,
1615
1687
  i = _transformProps.length,
1616
1688
  v = vars,
1617
1689
  endRotations = {},
1618
- m2, skewY, copy, orig, has3D, hasChange, dr;
1690
+ transformOriginString = "transformOrigin",
1691
+ m2, skewY, copy, orig, has3D, hasChange, dr, x, y;
1619
1692
  if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
1620
1693
  copy = _tempDiv.style; //don't use the original target because it might be SVG in which case some browsers don't report computed style correctly.
1621
1694
  copy[_transformProp] = v.transform;
@@ -1624,6 +1697,12 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1624
1697
  _doc.body.appendChild(_tempDiv);
1625
1698
  m2 = _getTransform(_tempDiv, null, false);
1626
1699
  _doc.body.removeChild(_tempDiv);
1700
+ if (v.xPercent != null) {
1701
+ m2.xPercent = _parseVal(v.xPercent, m1.xPercent);
1702
+ }
1703
+ if (v.yPercent != null) {
1704
+ m2.yPercent = _parseVal(v.yPercent, m1.yPercent);
1705
+ }
1627
1706
  } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
1628
1707
  m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
1629
1708
  scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
@@ -1696,13 +1775,15 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1696
1775
 
1697
1776
  orig = v.transformOrigin;
1698
1777
  if (m1.svg && (orig || v.svgOrigin)) {
1699
- _parseSVGOrigin(t, _parsePosition(orig), m2, v.svgOrigin);
1700
- pt = new CSSPropTween(m1, "xOrigin", m1.xOrigin, m2.xOrigin - m1.xOrigin, pt, -1, "transformOrigin");
1701
- pt.b = m1.xOrigin;
1702
- pt.e = pt.xs0 = m2.xOrigin;
1703
- pt = new CSSPropTween(m1, "yOrigin", m1.yOrigin, m2.yOrigin - m1.yOrigin, pt, -1, "transformOrigin");
1704
- pt.b = m1.yOrigin;
1705
- pt.e = pt.xs0 = m2.yOrigin;
1778
+ x = m1.xOffset; //when we change the origin, in order to prevent things from jumping we adjust the x/y so we must record those here so that we can create PropTweens for them and flip them at the same time as the origin
1779
+ y = m1.yOffset;
1780
+ _parseSVGOrigin(t, _parsePosition(orig), m2, v.svgOrigin, v.smoothOrigin);
1781
+ pt = _addNonTweeningNumericPT(m1, "xOrigin", (originalGSTransform ? m1 : m2).xOrigin, m2.xOrigin, pt, transformOriginString); //note: if there wasn't a transformOrigin defined yet, just start with the destination one; it's wasteful otherwise, and it causes problems with fromTo() tweens. For example, TweenLite.to("#wheel", 3, {rotation:180, transformOrigin:"50% 50%", delay:1}); TweenLite.fromTo("#wheel", 3, {scale:0.5, transformOrigin:"50% 50%"}, {scale:1, delay:2}); would cause a jump when the from values revert at the beginning of the 2nd tween.
1782
+ pt = _addNonTweeningNumericPT(m1, "yOrigin", (originalGSTransform ? m1 : m2).yOrigin, m2.yOrigin, pt, transformOriginString);
1783
+ if (x !== m1.xOffset || y !== m1.yOffset) {
1784
+ pt = _addNonTweeningNumericPT(m1, "xOffset", (originalGSTransform ? x : m1.xOffset), m1.xOffset, pt, transformOriginString);
1785
+ pt = _addNonTweeningNumericPT(m1, "yOffset", (originalGSTransform ? y : m1.yOffset), m1.yOffset, pt, transformOriginString);
1786
+ }
1706
1787
  orig = _useSVGTransformAttr ? null : "0px 0px"; //certain browsers (like firefox) completely botch transform-origin, so we must remove it to prevent it from contaminating transforms. We manage it ourselves with xOrigin and yOrigin
1707
1788
  }
1708
1789
  if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
@@ -1710,7 +1791,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1710
1791
  hasChange = true;
1711
1792
  p = _transformOriginProp;
1712
1793
  orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
1713
- pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin");
1794
+ pt = new CSSPropTween(style, p, 0, 0, pt, -1, transformOriginString);
1714
1795
  pt.b = style[p];
1715
1796
  pt.plugin = plugin;
1716
1797
  if (_supports3D) {
@@ -2260,7 +2341,21 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
2260
2341
  if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
2261
2342
  while (pt) {
2262
2343
  if (pt.type !== 2) {
2263
- pt.t[pt.p] = pt.e;
2344
+ if (pt.r && pt.type !== -1) {
2345
+ val = Math.round(pt.s + pt.c);
2346
+ if (!pt.type) {
2347
+ pt.t[pt.p] = val + pt.xs0;
2348
+ } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
2349
+ i = pt.l;
2350
+ str = pt.xs0 + val + pt.xs1;
2351
+ for (i = 1; i < pt.l; i++) {
2352
+ str += pt["xn"+i] + pt["xs"+(i+1)];
2353
+ }
2354
+ pt.t[pt.p] = str;
2355
+ }
2356
+ } else {
2357
+ pt.t[pt.p] = pt.e;
2358
+ }
2264
2359
  } else {
2265
2360
  pt.setRatio(v);
2266
2361
  }
@@ -1,9 +1,9 @@
1
1
  /*!
2
- * VERSION: 0.13.0
3
- * DATE: 2015-03-13
2
+ * VERSION: 0.14.0
3
+ * DATE: 2015-05-26
4
4
  * UPDATES AND DOCS AT: http://greensock.com
5
5
  *
6
- * Requires TweenLite and CSSPlugin version 1.16.1 or later (TweenMax contains both TweenLite and CSSPlugin). ThrowPropsPlugin is required for momentum-based continuation of movement after the mouse/touch is released (ThrowPropsPlugin is a membership benefit of Club GreenSock - http://greensock.com/club/).
6
+ * Requires TweenLite and CSSPlugin version 1.17.0 or later (TweenMax contains both TweenLite and CSSPlugin). ThrowPropsPlugin is required for momentum-based continuation of movement after the mouse/touch is released (ThrowPropsPlugin is a membership benefit of Club GreenSock - http://greensock.com/club/).
7
7
  *
8
8
  * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
9
9
  * This work is subject to the terms at http://greensock.com/standard-license or for
@@ -16,7 +16,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
16
16
 
17
17
  "use strict";
18
18
 
19
- _gsScope._gsDefine("utils.Draggable", ["events.EventDispatcher","TweenLite"], function(EventDispatcher, TweenLite) {
19
+ _gsScope._gsDefine("utils.Draggable", ["events.EventDispatcher","TweenLite","plugins.CSSPlugin"], function(EventDispatcher, TweenLite, CSSPlugin) {
20
20
 
21
21
  var _tempVarsXY = {css:{}}, //speed optimization - we reuse the same vars object for x/y TweenLite.set() calls to minimize garbage collection tasks and improve performance.
22
22
  _tempVarsX = {css:{}},
@@ -26,6 +26,10 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
26
26
  _tempEvent = {}, //for populating with pageX/pageY in old versions of IE
27
27
  _doc = document,
28
28
  _docElement = _doc.documentElement || {},
29
+ _createElement = function(type) {
30
+ return _doc.createElementNS ? _doc.createElementNS("http://www.w3.org/1999/xhtml", type) : _doc.createElement(type);
31
+ },
32
+ _tempDiv = _createElement("div"),
29
33
  _emptyArray = [],
30
34
  _emptyFunc = function() { return false; },
31
35
  _RAD2DEG = 180 / Math.PI,
@@ -42,6 +46,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
42
46
  _isMultiTouching,
43
47
  _isAndroid = (navigator.userAgent.toLowerCase().indexOf("android") !== -1), //Android handles touch events in an odd way and it's virtually impossible to "feature test" so we resort to UA sniffing
44
48
  _lastDragTime = 0,
49
+ _temp1 = {}, // a simple object we reuse and populate (usually x/y properties) to conserve memory and improve performance.
50
+ _temp2 = {},
45
51
  _windowProxy = {}, //memory/performance optimization - we reuse this object during autoScroll to store window-related bounds/offsets.
46
52
  _slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
47
53
  if (typeof(a) === "string") {
@@ -262,7 +268,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
262
268
  callback = vars[callbackName],
263
269
  listeners = instance._listeners[type];
264
270
  if (typeof(callback) === "function") {
265
- callback.apply(vars[callbackName + "Scope"] || instance, vars[callbackName + "Params"] || [instance.pointerEvent]);
271
+ callback.apply(vars[callbackName + "Scope"] || vars.callbackScope || instance, vars[callbackName + "Params"] || [instance.pointerEvent]);
266
272
  }
267
273
  if (listeners) {
268
274
  instance.dispatchEvent(type);
@@ -283,98 +289,169 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
283
289
  return _getElementBounds(e, context);
284
290
  },
285
291
 
286
- _tempDiv = _doc.createElement("div"),
287
- _supports3D = (_checkPrefix(_tempDiv, "perspective") !== ""),
292
+ _svgBorderFactor,
293
+ _svgBorderScales,
294
+ _svgScrollOffset,
295
+ _hasBorderBug,
296
+ _setEnvironmentVariables = function() { //some browsers factor the border into the SVG coordinate space, some don't (like Firefox). Some apply transforms to them, some don't. We feature-detect here so we know how to handle the border(s). We can't do this immediately - we must wait for the document.body to exist.
297
+ if (!_doc.createElementNS) {
298
+ _svgBorderFactor = 0;
299
+ _svgBorderScales = false;
300
+ return;
301
+ }
302
+ var div = _createElement("div"),
303
+ svg = _doc.createElementNS("http://www.w3.org/2000/svg", "svg"),
304
+ wrapper = _createElement("div"),
305
+ style = div.style,
306
+ parent = _doc.body || _docElement,
307
+ matrix, e1, point, oldValue;
308
+ if (_doc.body && _transformProp) {
309
+ style.position = wrapper.style.position = "absolute";
310
+ parent.appendChild(wrapper);
311
+ wrapper.appendChild(div);
312
+ style.height = "10px";
313
+ oldValue = div.offsetTop;
314
+ wrapper.style.border = "5px solid red";
315
+ _hasBorderBug = (oldValue !== div.offsetTop); //some browsers, like Firefox 38, cause the offsetTop/Left to be affected by a parent's border.
316
+ parent.removeChild(wrapper);
317
+ }
318
+ style = svg.style;
319
+ svg.setAttributeNS(null, "width", "400px");
320
+ svg.setAttributeNS(null, "height", "400px");
321
+ svg.setAttributeNS(null, "viewBox", "0 0 400 400");
322
+ style.display = "block";
323
+ style.boxSizing = "border-box";
324
+ style.border = "0px solid red";
325
+ style.transform = "none";
326
+ // in some browsers (like certain flavors of Android), the getScreenCTM() matrix is contaminated by the scroll position. We can run some logic here to detect that condition, but we ended up not needing this because we found another workaround using getBoundingClientRect().
327
+ div.style.cssText = "width:100px;height:100px;overflow:scroll";
328
+ parent.appendChild(div);
329
+ div.appendChild(svg);
330
+ point = svg.createSVGPoint().matrixTransform(svg.getScreenCTM());
331
+ e1 = point.y;
332
+ div.scrollTop = 100;
333
+ point.x = point.y = 0;
334
+ point = point.matrixTransform(svg.getScreenCTM());
335
+ _svgScrollOffset = (e1 - point.y < 100.1) ? 0 : e1 - point.y - 150;
336
+ div.removeChild(svg);
337
+ parent.removeChild(div);
338
+ // -- end _svgScrollOffset calculation.
339
+ parent.appendChild(svg);
340
+ matrix = svg.getScreenCTM();
341
+ e1 = matrix.e;
342
+ style.border = "50px solid red";
343
+ matrix = svg.getScreenCTM();
344
+ if (e1 === 0 && matrix.e === 0 && matrix.f === 0 && matrix.a === 1) { //Opera has a bunch of bugs - it doesn't adjust the x/y of the matrix, nor does it scale when box-sizing is border-box but it does so elsewhere; to get the correct behavior we set _svgBorderScales to true.
345
+ _svgBorderFactor = 1;
346
+ _svgBorderScales = true;
347
+ } else {
348
+ _svgBorderFactor = (e1 !== matrix.e) ? 1 : 0;
349
+ _svgBorderScales = (matrix.a !== 1);
350
+ }
351
+ parent.removeChild(svg);
352
+ },
288
353
 
354
+ _supports3D = (_checkPrefix(_tempDiv, "perspective") !== ""),
289
355
 
290
356
  // start matrix and point conversion methods...
291
- _originProp = _checkPrefix(_tempDiv, "transformOrigin").replace(/^ms/g, "Ms").replace(/([A-Z])/g, "-$1").toLowerCase(),
357
+ _transformOriginProp = _checkPrefix(_tempDiv, "transformOrigin").replace(/^ms/g, "Ms").replace(/([A-Z])/g, "-$1").toLowerCase(),
292
358
  _transformProp = _checkPrefix(_tempDiv, "transform"),
293
- _transformCSSProp = _transformProp.replace(/^ms/g, "Ms").replace(/([A-Z])/g, "-$1").toLowerCase(),
359
+ _transformPropCSS = _transformProp.replace(/^ms/g, "Ms").replace(/([A-Z])/g, "-$1").toLowerCase(),
294
360
  _point1 = {}, //we reuse _point1 and _point2 objects inside matrix and point conversion methods to conserve memory and minimize garbage collection tasks.
295
361
  _point2 = {},
296
- _hasReparentBug, //we'll set this inside the _getOffset2DMatrix() method after the body has loaded.
297
- _dummySVGRect = (function() {
298
- if (_isOldIE) {
299
- return;
300
- }
301
- var url = "http://www.w3.org/2000/svg",
302
- svg = _doc.createElementNS(url, "svg"),
303
- e = _doc.createElementNS(url, "rect");
304
- e.setAttributeNS(null, "width", "10");
305
- e.setAttributeNS(null, "height", "10");
306
- svg.appendChild(e);
307
- return svg;
308
- }()),
309
362
  _SVGElement = window.SVGElement,
310
363
  _isSVG = function(e) {
311
364
  return !!(_SVGElement && typeof(e.getBBox) === "function" && e.getCTM && (!e.parentNode || (e.parentNode.getBBox && e.parentNode.getCTM)));
312
365
  },
313
- _svgAttributes = ["class","viewBox","width","height","xml:space"],
314
- _getSVGOffsets = function(e) { //SVG elements don't always report offsetTop/offsetLeft/offsetParent at all (I'm looking at you, Firefox 29), so we have to do some work to manufacture those values. You can pass any SVG element and it'll spit back an object with offsetTop, offsetLeft, offsetParent, scaleX, and scaleY properties. We need the scaleX and scaleY to handle the way SVG can resize itself based on the container.
315
- if (!e.getBoundingClientRect || !e.parentNode) {
366
+ _isIE10orBelow = (((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(navigator.userAgent) || (/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/).exec(navigator.userAgent)) && parseFloat( RegExp.$1 ) < 11), //Ideally we'd avoid user agent sniffing, but there doesn't seem to be a way to feature-detect and sense a border-related bug that only affects IE10 and IE9.
367
+ _tempTransforms = [],
368
+ _tempElements = [],
369
+ _getSVGOffsets = function(e) { //SVG elements don't always report offsetTop/offsetLeft/offsetParent at all (I'm looking at you, Firefox 29 and Android), so we have to do some work to manufacture those values. You can pass any SVG element and it'll spit back an object with offsetTop, offsetLeft, offsetParent, scaleX, and scaleY properties. We need the scaleX and scaleY to handle the way SVG can resize itself based on the container.
370
+ if (!e.getBoundingClientRect || !e.parentNode || !_transformProp) {
316
371
  return {offsetTop:0, offsetLeft:0, scaleX:1, scaleY:1, offsetParent:_docElement};
317
372
  }
318
- if (e._gsSVGData && e._gsSVGData.lastUpdate === TweenLite.ticker.frame) {
319
- return e._gsSVGData;
373
+ if (Draggable.cacheSVGData !== false && e._gsCache && e._gsCache.lastUpdate === TweenLite.ticker.frame) { //performance optimization. Assume that if the offsets are requested again on the same tick, we can just feed back the values we already calculated (no need to keep recalculating until another tick elapses).
374
+ return e._gsCache;
320
375
  }
321
376
  var curElement = e,
322
- prevCSS = e.style.cssText,
323
- data = e._gsSVGData = e._gsSVGData || {},
324
- eRect, parentRect, offsetParent, rRect, i, a;
325
- if ((e.nodeName + "").toLowerCase() !== "svg" && e.getBBox) { //if it's a nested/child SVG element, we must find the parent SVG canvas and measure the offset from there.
377
+ cache = _cache(e),
378
+ eRect, parentRect, offsetParent, cs, m, i, point1, point2, borderWidth, borderHeight, width, height;
379
+ cache.lastUpdate = TweenLite.ticker.frame;
380
+ if (e.getBBox && !cache.isSVGRoot) { //if it's a nested/child SVG element, we must find the parent SVG canvas and measure the offset from there.
326
381
  curElement = e.parentNode;
327
382
  eRect = e.getBBox();
328
383
  while (curElement && (curElement.nodeName + "").toLowerCase() !== "svg") {
329
384
  curElement = curElement.parentNode;
330
385
  }
331
- data = _getSVGOffsets(curElement);
332
- return {offsetTop:eRect.y * data.scaleY, offsetLeft:eRect.x * data.scaleX, scaleX:data.scaleX, scaleY:data.scaleY, offsetParent:curElement || _docElement};
386
+ cs = _getSVGOffsets(curElement);
387
+ cache.offsetTop = eRect.y * cs.scaleY;
388
+ cache.offsetLeft = eRect.x * cs.scaleX;
389
+ cache.scaleX = cs.scaleX;
390
+ cache.scaleY = cs.scaleY;
391
+ cache.offsetParent = curElement || _docElement;
392
+ return cache;
333
393
  }
334
- while (!curElement.offsetParent && curElement.parentNode) {
335
- curElement = curElement.parentNode;
394
+ //only root SVG elements continue here...
395
+ offsetParent = cache.offsetParent;
396
+ if (offsetParent === _doc.body) {
397
+ offsetParent = _docElement; //avoids problems with margins/padding on the body
336
398
  }
337
- e.parentNode.insertBefore(_dummySVGRect, e); //Firefox measures things based NOT on the <svg> itself, but on the bounds of the child elements, so we add a dummy SVG object temporarily in the original one's spot which has a 10x10 <rect> in the upper left corner to make sure we're getting accurate results.
338
- e.parentNode.removeChild(e);
339
- _dummySVGRect.style.cssText = prevCSS;
340
- _dummySVGRect.style[_transformProp] = "none";
341
- i = _svgAttributes.length;
342
- while (--i > -1) {
343
- a = e.getAttribute(_svgAttributes[i]);
344
- if (a) {
345
- _dummySVGRect.setAttribute(_svgAttributes[i], a);
346
- } else {
347
- _dummySVGRect.removeAttribute(_svgAttributes[i]);
399
+ //walk up the ancestors and record any non-identity transforms (and reset them to "none") until we reach the offsetParent. We must do this so that the getBoundingClientRect() is accurate for measuring the offsetTop/offsetLeft. We'll revert the values later...
400
+ _tempElements.length = _tempTransforms.length = 0;
401
+ while (curElement) {
402
+ m = _getStyle(curElement, _transformProp, true);
403
+ if (m !== "matrix(1, 0, 0, 1, 0, 0)" && m !== "none" && m !== "translate3d(0px, 0px, 0px)") {
404
+ _tempElements.push(curElement);
405
+ _tempTransforms.push(curElement.style[_transformProp]);
406
+ curElement.style[_transformProp] = "none";
348
407
  }
349
- }
350
- eRect = _dummySVGRect.getBoundingClientRect();
351
- rRect = _dummySVGRect.firstChild.getBoundingClientRect();
352
- offsetParent = curElement.offsetParent;
353
- if (offsetParent) {
354
- if (offsetParent === _doc.body && _docElement) {
355
- offsetParent = _docElement; //to avoid problems with margins/padding on the <body>
408
+ if (curElement === offsetParent) {
409
+ break;
356
410
  }
357
- parentRect = offsetParent.getBoundingClientRect();
411
+ curElement = curElement.parentNode;
412
+ }
413
+ parentRect = offsetParent.getBoundingClientRect();
414
+ m = e.getScreenCTM();
415
+ point2 = e.createSVGPoint();
416
+ point1 = point2.matrixTransform(m);
417
+ point2.x = point2.y = 10;
418
+ point2 = point2.matrixTransform(m);
419
+ cache.scaleX = (point2.x - point1.x) / 10;
420
+ cache.scaleY = (point2.y - point1.y) / 10;
421
+ if (_svgBorderFactor === undefined) {
422
+ _setEnvironmentVariables();
423
+ }
424
+ if (cache.borderBox && !_svgBorderScales && e.getAttribute("width")) { //some browsers (like Safari) don't properly scale the matrix to accommodate the border when box-sizing is border-box, so we must calculate it here...
425
+ cs = _getComputedStyle(e) || {};
426
+ borderWidth = (parseFloat(cs.borderLeftWidth) + parseFloat(cs.borderRightWidth)) || 0;
427
+ borderHeight = (parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth)) || 0;
428
+ width = parseFloat(cs.width) || 0;
429
+ height = parseFloat(cs.height) || 0;
430
+ cache.scaleX *= (width - borderWidth) / width;
431
+ cache.scaleY *= (height - borderHeight) / height;
432
+ }
433
+ if (_svgScrollOffset) { //some browsers (like Chrome for Android) have bugs in the way getScreenCTM() is reported (it doesn't factor in scroll position), so we must revert to a more expensive technique for calculating offsetTop/Left.
434
+ eRect = e.getBoundingClientRect();
435
+ cache.offsetLeft = eRect.left - parentRect.left;
436
+ cache.offsetTop = eRect.top - parentRect.top;
358
437
  } else {
359
- parentRect = {top:-_getDocScrollTop(), left:-_getDocScrollLeft()};
360
- }
361
- _dummySVGRect.parentNode.insertBefore(e, _dummySVGRect);
362
- e.parentNode.removeChild(_dummySVGRect);
363
- data.scaleX = rRect.width / 10;
364
- data.scaleY = rRect.height / 10;
365
- data.offsetLeft = eRect.left - parentRect.left;
366
- data.offsetTop = eRect.top - parentRect.top;
367
- data.offsetParent = curElement.offsetParent || _docElement;
368
- data.lastUpdate = TweenLite.ticker.frame;
369
- return data;
438
+ cache.offsetLeft = point1.x - parentRect.left;
439
+ cache.offsetTop = point1.y - parentRect.top;
440
+ }
441
+ cache.offsetParent = offsetParent;
442
+ i = _tempElements.length;
443
+ while (--i > -1) {
444
+ _tempElements[i].style[_transformProp] = _tempTransforms[i];
445
+ }
446
+ return cache;
370
447
  },
371
- _getOffsetTransformOrigin = function(e, decoratee) {
448
+ _getOffsetTransformOrigin = function(e, decoratee) { //returns the x/y position of the transformOrigin of the element, in its own local coordinate system (pixels), offset from the top left corner.
372
449
  decoratee = decoratee || {};
373
- if (!e || e === _docElement || !e.parentNode) {
450
+ if (!e || e === _docElement || !e.parentNode || e === window) {
374
451
  return {x:0, y:0};
375
452
  }
376
453
  var cs = _getComputedStyle(e),
377
- v = (_originProp && cs) ? cs.getPropertyValue(_originProp) : "50% 50%",
454
+ v = (_transformOriginProp && cs) ? cs.getPropertyValue(_transformOriginProp) : "50% 50%",
378
455
  a = v.split(" "),
379
456
  x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
380
457
  y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
@@ -384,66 +461,141 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
384
461
  if (x === "center" || isNaN(parseFloat(x))) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it could be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
385
462
  x = "50%";
386
463
  }
387
- if (e.getBBox && _isSVG(e)) { //SVG elements must be handled in a special way because their origins are calculated from the parent SVG canvas origin
464
+ if (e.getBBox && _isSVG(e)) { //SVG elements must be handled in a special way because their origins are calculated from the top left.
388
465
  if (!e._gsTransform) {
389
466
  TweenLite.set(e, {x:"+=0", overwrite:false}); //forces creation of the _gsTransform where we store all the transform components including xOrigin and yOrigin for SVG elements, as of GSAP 1.15.0 which also takes care of calculating the origin from the upper left corner of the SVG canvas.
390
467
  if (e._gsTransform.xOrigin === undefined) {
391
- console.log("Draggable requires at least GSAP 1.16.1");
468
+ console.log("Draggable requires at least GSAP 1.17.0");
392
469
  }
393
470
  }
394
471
  v = e.getBBox();
395
- a = _getSVGOffsets(e);
396
- decoratee.x = (e._gsTransform.xOrigin - v.x) * a.scaleX;
397
- decoratee.y = (e._gsTransform.yOrigin - v.y) * a.scaleY;
472
+ decoratee.x = (e._gsTransform.xOrigin - v.x);
473
+ decoratee.y = (e._gsTransform.yOrigin - v.y);
398
474
  } else {
475
+ if (e.getBBox && !e.offsetWidth && (x + y).indexOf("%") !== -1) { //Firefox doesn't report offsetWidth/height on <svg> elements.
476
+ e = e.getBBox();
477
+ e = {offsetWidth: e.width, offsetHeight: e.height};
478
+ }
399
479
  decoratee.x = ((x.indexOf("%") !== -1) ? e.offsetWidth * parseFloat(x) / 100 : parseFloat(x));
400
480
  decoratee.y = ((y.indexOf("%") !== -1) ? e.offsetHeight * parseFloat(y) / 100 : parseFloat(y));
481
+
401
482
  }
402
483
  return decoratee;
403
484
  },
404
- _getOffset2DMatrix = function(e, offsetOrigin, parentOffsetOrigin) {
405
- var cs, m, parent, offsetParent, isRoot, offsets;
406
- if (e === window || !e || !e.parentNode) {
485
+ _cache = function(e) { //computes some important values and stores them in a _gsCache object attached to the element itself so that we can optimize performance
486
+ if (Draggable.cacheSVGData !== false && e._gsCache && e._gsCache.lastUpdate === TweenLite.ticker.frame) { //performance optimization. Assume that if the offsets are requested again on the same tick, we can just feed back the values we already calculated (no need to keep recalculating until another tick elapses).
487
+ return e._gsCache;
488
+ }
489
+ var cache = e._gsCache = e._gsCache || {},
490
+ cs = _getComputedStyle(e),
491
+ isSVG = (e.getBBox && _isSVG(e)),
492
+ isSVGRoot = ((e.nodeName + "").toLowerCase() === "svg"),
493
+ curSVG;
494
+ cache.isSVG = isSVG;
495
+ cache.isSVGRoot = isSVGRoot;
496
+ cache.borderBox = (cs.boxSizing === "border-box");
497
+ cache.computedStyle = cs;
498
+ if (isSVGRoot) {
499
+ if (!(cache.offsetParent = e.offsetParent)) { //some browsers don't report offsetParent for SVG elements.
500
+ e.parentNode.insertBefore(_tempDiv, e);
501
+ cache.offsetParent = _tempDiv.offsetParent;
502
+ e.parentNode.removeChild(_tempDiv);
503
+ }
504
+ } else if (isSVG) {
505
+ curSVG = e.parentNode;
506
+ while (curSVG && (curSVG.nodeName + "").toLowerCase() !== "svg") { //offsetParent is always the SVG canvas for SVG elements.
507
+ curSVG = curSVG.parentNode;
508
+ }
509
+ cache.offsetParent = curSVG;
510
+ }
511
+ return cache;
512
+ },
513
+ _getOffset2DMatrix = function(e, offsetOrigin, parentOffsetOrigin, zeroOrigin) {
514
+ if (e === window || !e || !e.style || !e.parentNode) {
407
515
  return [1,0,0,1,0,0];
408
516
  }
409
- cs = _getComputedStyle(e);
410
- m = cs ? cs.getPropertyValue(_transformCSSProp) : e.currentStyle ? e.currentStyle[_transformProp] : "1,0,0,1,0,0";
517
+ var cache = e._gsCache || _cache(e),
518
+ parent = e.parentNode,
519
+ parentCache = parent._gsCache || _cache(parent),
520
+ cs = cache.computedStyle,
521
+ parentOffsetParent = cache.isSVG ? parentCache.offsetParent : parent.offsetParent,
522
+ m, isRoot, offsets, rect, t, sx, sy, offsetX, offsetY, parentRect, borderTop, borderLeft, borderTranslateX, borderTranslateY;
523
+ m = (cache.isSVG && (e.style[_transformProp] + "").indexOf("matrix") !== -1) ? e.style[_transformProp] : cs ? cs.getPropertyValue(_transformPropCSS) : e.currentStyle ? e.currentStyle[_transformProp] : "1,0,0,1,0,0"; //some browsers (like Chrome 40) don't correctly report transforms that are applied inline on an SVG element (they don't get included in the computed style), so we double-check here and accept matrix values
524
+
525
+ if (e.getBBox && (e.getAttribute("transform") + "").indexOf("matrix") !== -1) { //SVG can store transform data in its "transform" attribute instead of the CSS, so look for that here (only accept matrix()).
526
+ m = e.getAttribute("transform");
527
+ }
411
528
  m = (m + "").match(/(?:\-|\b)[\d\-\.e]+\b/g) || [1,0,0,1,0,0];
412
529
  if (m.length > 6) {
413
530
  m = [m[0], m[1], m[4], m[5], m[12], m[13]];
414
531
  }
532
+ if (zeroOrigin) {
533
+ m[4] = m[5] = 0;
534
+ } else if (cache.isSVG && (t = e._gsTransform) && (t.xOrigin || t.yOrigin)) {
535
+ //SVGs handle origin very differently. Factor in GSAP's handling of origin values here:
536
+ m[0] = parseFloat(m[0]);
537
+ m[1] = parseFloat(m[1]);
538
+ m[2] = parseFloat(m[2]);
539
+ m[3] = parseFloat(m[3]);
540
+ m[4] = parseFloat(m[4]) - (t.xOrigin - (t.xOrigin * m[0] + t.yOrigin * m[2]));
541
+ m[5] = parseFloat(m[5]) - (t.yOrigin - (t.xOrigin * m[1] + t.yOrigin * m[3]));
542
+ }
415
543
  if (offsetOrigin) {
416
- parent = e.parentNode;
417
- offsets = ((e.getBBox && _isSVG(e)) || (e.offsetLeft === undefined && (e.nodeName + "").toLowerCase() === "svg")) ? _getSVGOffsets(e) : e;
418
- offsetParent = offsets.offsetParent;
419
- isRoot = (parent === _docElement || parent === _doc.body);
420
-
421
- //some browsers (like Chrome 31) have a bug that causes the offsetParent not to report correctly when a transform is applied to an element's parent, so the offsetTop and offsetLeft are measured from the parent instead of whatever the offsetParent reports as. For example, put an absolutely-positioned child div inside a position:static parent, then check the child's offsetTop before and after you apply a transform, like rotate(1deg). You'll see that it changes, but the offsetParent doesn't. So we must sense this condition here (and we can only do it after the body has loaded, as browsers don't accurately report offsets otherwise) and set a variable that we can easily reference later.
422
- if (_hasReparentBug === undefined && _doc.body && _transformProp) {
423
- _hasReparentBug = (function() {
424
- var parent = _doc.createElement("div"),
425
- child = _doc.createElement("div"),
426
- oldOffsetParent, value;
427
- child.style.position = "absolute";
428
- _doc.body.appendChild(parent);
429
- parent.appendChild(child);
430
- oldOffsetParent = child.offsetParent;
431
- parent.style[_transformProp] = "rotate(1deg)";
432
- value = (child.offsetParent === oldOffsetParent);
433
- _doc.body.removeChild(parent);
434
- return value;
435
- }());
544
+ if (_svgBorderFactor === undefined) {
545
+ _setEnvironmentVariables();
436
546
  }
437
- m[4] = Number(m[4]) + offsetOrigin.x + (offsets.offsetLeft || 0) - parentOffsetOrigin.x - (isRoot ? 0 : parent.scrollLeft) + (offsetParent ? parseInt(_getStyle(offsetParent, "borderLeftWidth"), 10) || 0 : 0);
438
- m[5] = Number(m[5]) + offsetOrigin.y + (offsets.offsetTop || 0) - parentOffsetOrigin.y - (isRoot ? 0 : parent.scrollTop) + (offsetParent ? parseInt(_getStyle(offsetParent, "borderTopWidth"), 10) || 0 : 0);
439
- if (parent && parent.offsetParent === offsetParent && (!_hasReparentBug || _getOffset2DMatrix(parent).join("") === "100100")) {
440
- m[4] -= parent.offsetLeft || 0;
441
- m[5] -= parent.offsetTop || 0;
547
+ offsets = (cache.isSVG || cache.isSVGRoot) ? _getSVGOffsets(e) : e;
548
+ if (cache.isSVG) { //don't just rely on "instanceof _SVGElement" because if the SVG is embedded via an object tag, it won't work (SVGElement is mapped to a different object))
549
+ rect = e.getBBox();
550
+ parentRect = (parentCache.isSVGRoot) ? {x:0, y:0} : parent.getBBox();
551
+ offsets = {offsetLeft:rect.x - parentRect.x, offsetTop:rect.y - parentRect.y, offsetParent:cache.offsetParent};
552
+ } else if (cache.isSVGRoot) {
553
+ borderTop = parseInt(cs.borderTopWidth, 10) || 0;
554
+ borderLeft = parseInt(cs.borderLeftWidth, 10) || 0;
555
+ borderTranslateX = ((m[0] - _svgBorderFactor) * borderLeft + m[2] * borderTop);
556
+ borderTranslateY = (m[1] * borderLeft + (m[3] - _svgBorderFactor) * borderTop);
557
+
558
+ sx = offsetOrigin.x;
559
+ sy = offsetOrigin.y;
560
+ offsetX = (sx - (sx * m[0] + sy * m[2])); //accommodate the SVG root's transforms when the origin isn't in the top left.
561
+ offsetY = (sy - (sx * m[1] + sy * m[3]));
562
+
563
+ m[4] = parseFloat(m[4]) + offsetX;
564
+ m[5] = parseFloat(m[5]) + offsetY;
565
+ offsetOrigin.x -= offsetX;
566
+ offsetOrigin.y -= offsetY;
567
+ sx = offsets.scaleX;
568
+ sy = offsets.scaleY;
569
+ offsetOrigin.x *= sx;
570
+ offsetOrigin.y *= sy;
571
+ m[0] *= sx;
572
+ m[1] *= sy;
573
+ m[2] *= sx;
574
+ m[3] *= sy;
575
+
576
+ if (!_isIE10orBelow) {
577
+ offsetOrigin.x += borderTranslateX;
578
+ offsetOrigin.y += borderTranslateY;
579
+ }
580
+ } else if (!_hasBorderBug && e.offsetParent) {
581
+ offsetOrigin.x += parseInt(_getStyle(e.offsetParent, "borderLeftWidth"), 10) || 0;
582
+ offsetOrigin.y += parseInt(_getStyle(e.offsetParent, "borderTopWidth"), 10) || 0;
442
583
  }
443
- if (parent && _getStyle(e, "position", true) === "fixed") { //fixed position elements should factor in the scroll position of the document.
584
+ isRoot = (parent === _docElement || parent === _doc.body);
585
+ m[4] = Number(m[4]) + offsetOrigin.x + (offsets.offsetLeft || 0) - parentOffsetOrigin.x - (isRoot ? 0 : parent.scrollLeft || 0);
586
+ m[5] = Number(m[5]) + offsetOrigin.y + (offsets.offsetTop || 0) - parentOffsetOrigin.y - (isRoot ? 0 : parent.scrollTop || 0);
587
+ if (parent && _getStyle(e, "position", cs) === "fixed") { //fixed position elements should factor in the scroll position of the document.
444
588
  m[4] += _getDocScrollLeft();
445
589
  m[5] += _getDocScrollTop();
446
590
  }
591
+ if (parent && parent !== _docElement && parentOffsetParent === offsets.offsetParent) {
592
+ m[4] -= parent.offsetLeft || 0;
593
+ m[5] -= parent.offsetTop || 0;
594
+ if (!_hasBorderBug && parent.offsetParent && !cache.isSVG && !cache.isSVGRoot) {
595
+ m[4] -= parseInt(_getStyle(parent.offsetParent, "borderLeftWidth"), 10) || 0;
596
+ m[5] -= parseInt(_getStyle(parent.offsetParent, "borderTopWidth"), 10) || 0;
597
+ }
598
+ }
447
599
  }
448
600
  return m;
449
601
  },
@@ -490,10 +642,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
490
642
  }
491
643
  return m;
492
644
  },
493
- _localToGlobal = function(e, p, decoratee) {
494
- var m = _getConcatenatedMatrix(e),
645
+ _localToGlobal = function(e, p, fromTopLeft, decoratee, zeroOrigin) {
646
+ e = _unwrapElement(e);
647
+ var m = _getConcatenatedMatrix(e, false, zeroOrigin),
495
648
  x = p.x,
496
649
  y = p.y;
650
+ if (fromTopLeft) {
651
+ _getOffsetTransformOrigin(e, p);
652
+ x -= p.x;
653
+ y -= p.y;
654
+ }
497
655
  decoratee = (decoratee === true) ? p : decoratee || {};
498
656
  decoratee.x = x * m[0] + y * m[2] + m[4];
499
657
  decoratee.y = x * m[1] + y * m[3] + m[5];
@@ -506,20 +664,56 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
506
664
  p.y = x * globalToLocal[1] + y * globalToLocal[3] + globalToLocal[5];
507
665
  return p;
508
666
  },
509
- _getElementBounds = function(e, context) {
510
- var origin, left, right, top, bottom, mLocalToGlobal, mGlobalToLocal, p1, p2, p3, p4;
667
+
668
+ _getElementBounds = function(e, context, fromTopLeft) {
669
+ if (!(e = _unwrapElement(e))) {
670
+ return null;
671
+ }
672
+ context = _unwrapElement(context);
673
+ var isSVG = (e.getBBox && _isSVG(e)),
674
+ origin, left, right, top, bottom, mLocalToGlobal, mGlobalToLocal, p1, p2, p3, p4, bbox, width, height, cache, borderLeft, borderTop, viewBox, viewBoxX, viewBoxY, computedDimensions, cs;
511
675
  if (e === window) {
512
676
  top = _getDocScrollTop();
513
677
  left = _getDocScrollLeft();
514
678
  right = left + (_docElement.clientWidth || e.innerWidth || _doc.body.clientWidth || 0);
515
-
516
- bottom = top + (((e.innerHeight || 0) - 20 < _docElement.clientHeight) ? _docElement.clientHeight : e.innerHeight || _doc.body.clientHeight || 0); //some browsers (like Firefox) ignore absolutely positioned elements, and collapse the height of the documentElement, so it could be 8px, for example, if you have just an absolutely positioned div. In that case, we use the innerHeight to resolve this. Also note that IE8 doesn't support window.innerHeight.
679
+ bottom = top + (((e.innerHeight || 0) - 20 < _docElement.clientHeight) ? _docElement.clientHeight : e.innerHeight || _doc.body.clientHeight || 0); //some browsers (like Firefox) ignore absolutely positioned elements, and collapse the height of the documentElement, so it could be 8px, for example, if you have just an absolutely positioned div. In that case, we use the innerHeight to resolve this.
680
+ } else if (context === undefined || context === window) {
681
+ return e.getBoundingClientRect();
517
682
  } else {
518
683
  origin = _getOffsetTransformOrigin(e);
519
684
  left = -origin.x;
520
- right = left + e.offsetWidth;
521
685
  top = -origin.y;
522
- bottom = top + e.offsetHeight;
686
+ if (isSVG) {
687
+ bbox = e.getBBox();
688
+ width = bbox.width;
689
+ height = bbox.height;
690
+ } else if (e.offsetWidth) {
691
+ width = e.offsetWidth;
692
+ height = e.offsetHeight;
693
+ } else {
694
+ computedDimensions = _getComputedStyle(e);
695
+ width = parseFloat(computedDimensions.width);
696
+ height = parseFloat(computedDimensions.height);
697
+ }
698
+ right = left + width;
699
+ bottom = top + height;
700
+ if (e.nodeName.toLowerCase() === "svg" && !_isOldIE) { //root SVG elements are a special beast because they have 2 types of scaling - transforms on themselves as well as the stretching of the SVG canvas itself based on the outer size and the viewBox. If, for example, the SVG's viewbox is "0 0 100 100" but the CSS is set to width:200px; height:200px, that'd make it appear at 2x scale even though the element itself has no CSS transforms but the offsetWidth/offsetHeight are based on that css, not the viewBox so we need to adjust them accordingly.
701
+ cache = _getSVGOffsets(e);
702
+ cs = cache.computedStyle || {};
703
+ viewBox = (e.getAttribute("viewBox") || "0 0").split(" ");
704
+ viewBoxX = parseFloat(viewBox[0]);
705
+ viewBoxY = parseFloat(viewBox[1]);
706
+ borderLeft = parseFloat(cs.borderLeftWidth) || 0;
707
+ borderTop = parseFloat(cs.borderTopWidth) || 0;
708
+ right -= width - ((width - borderLeft) / cache.scaleX) - viewBoxX;
709
+ bottom -= height - ((height - borderTop) / cache.scaleY) - viewBoxY;
710
+ left -= borderLeft / cache.scaleX - viewBoxX;
711
+ top -= borderTop / cache.scaleY - viewBoxY;
712
+ if (computedDimensions) { //when we had to use computed styles, factor in the border now.
713
+ right += (parseFloat(cs.borderRightWidth) + borderLeft) / cache.scaleX;
714
+ bottom += (borderTop + parseFloat(cs.borderBottomWidth)) / cache.scaleY;
715
+ }
716
+ }
523
717
  }
524
718
  if (e === context) {
525
719
  return {left:left, top:top, width: right - left, height: bottom - top};
@@ -532,7 +726,11 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
532
726
  p4 = _localizePoint({x:left, y:bottom}, mLocalToGlobal, mGlobalToLocal);
533
727
  left = Math.min(p1.x, p2.x, p3.x, p4.x);
534
728
  top = Math.min(p1.y, p2.y, p3.y, p4.y);
535
- return {left:left, top:top, width:Math.max(p1.x, p2.x, p3.x, p4.x) - left, height:Math.max(p1.y, p2.y, p3.y, p4.y) - top};
729
+ _temp1.x = _temp1.y = 0;
730
+ if (fromTopLeft) {
731
+ _getOffsetTransformOrigin(context, _temp1);
732
+ }
733
+ return {left:left + _temp1.x, top:top + _temp1.y, width:Math.max(p1.x, p2.x, p3.x, p4.x) - left, height:Math.max(p1.y, p2.y, p3.y, p4.y) - top};
536
734
  },
537
735
  // end matrix and point conversion methods
538
736
 
@@ -589,6 +787,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
589
787
  }
590
788
  },
591
789
 
790
+ _hasTouchID = function(list, ID) {
791
+ var i = list.length;
792
+ while (--i > -1) {
793
+ if (list[i].identifier === ID) {
794
+ return true;
795
+ }
796
+ }
797
+ return false;
798
+ },
799
+
592
800
  _onMultiTouchDocumentEnd = function(e) {
593
801
  _isMultiTouching = (e.touches && _dragCount < e.touches.length);
594
802
  _removeListener(e.target, "touchend", _onMultiTouchDocumentEnd);
@@ -1053,8 +1261,8 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1053
1261
  render(true);
1054
1262
  }
1055
1263
  }
1056
- if (vars.onThrowUpdate && !skipOnUpdate) {
1057
- vars.onThrowUpdate.apply(vars.onThrowUpdateScope || self, vars.onThrowUpdateParams || _emptyArray);
1264
+ if (!skipOnUpdate) {
1265
+ _dispatchEvent(self, "throwupdate", "onThrowUpdate");
1058
1266
  }
1059
1267
  },
1060
1268
 
@@ -1120,8 +1328,16 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1120
1328
 
1121
1329
  },
1122
1330
 
1331
+ onThrowComplete = function() {
1332
+ self.isThrowing = false;
1333
+ _dispatchEvent(self, "throwcomplete", "onThrowComplete");
1334
+ },
1335
+ onThrowOverwrite = function() {
1336
+ self.isThrowing = false;
1337
+ },
1338
+
1123
1339
  animate = function(throwProps, forceZeroVelocity) {
1124
- var snap, snapIsRaw, tween;
1340
+ var snap, snapIsRaw, tween, overshootTolerance;
1125
1341
  if (throwProps && ThrowPropsPlugin) {
1126
1342
  if (throwProps === true) {
1127
1343
  snap = vars.snap || {};
@@ -1138,7 +1354,9 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1138
1354
  }
1139
1355
  }
1140
1356
  }
1141
- self.tween = tween = ThrowPropsPlugin.to(scrollProxy || target, {throwProps:throwProps, ease:(vars.ease || _globals.Power3.easeOut), onComplete:vars.onThrowComplete, onCompleteParams:vars.onThrowCompleteParams, onCompleteScope:(vars.onThrowCompleteScope || self), onUpdate:(vars.fastMode ? vars.onThrowUpdate : syncXY), onUpdateParams:(vars.fastMode ? vars.onThrowUpdateParams : null), onUpdateScope:(vars.onThrowUpdateScope || self)}, (isNaN(vars.maxDuration) ? 2 : vars.maxDuration), (isNaN(vars.minDuration) ? 0.5 : vars.minDuration), (isNaN(vars.overshootTolerance) ? (1 - self.edgeResistance) + 0.2 : vars.overshootTolerance));
1357
+ self.isThrowing = true;
1358
+ overshootTolerance = (!isNaN(vars.overshootTolerance)) ? vars.overshootTolerance : (vars.edgeResistance === 1) ? 0 : (1 - self.edgeResistance) + 0.2;
1359
+ self.tween = tween = ThrowPropsPlugin.to(scrollProxy || target, {throwProps:throwProps, ease:(vars.ease || _globals.Power3.easeOut), onComplete:onThrowComplete, onOverwrite:onThrowOverwrite, onUpdate:(vars.fastMode ? _dispatchEvent : syncXY), onUpdateParams:(vars.fastMode ? [self, "onthrowupdate", "onThrowUpdate"] : _emptyArray)}, (isNaN(vars.maxDuration) ? 2 : vars.maxDuration), (!isNaN(vars.minDuration) ? vars.minDuration : (overshootTolerance === 0) ? 0 : 0.5), overshootTolerance);
1142
1360
  if (!vars.fastMode) {
1143
1361
  //to populate the end values, we just scrub the tween to the end, record the values, and then jump back to the beginning.
1144
1362
  if (scrollProxy) {
@@ -1291,7 +1509,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1291
1509
  } else if (e.pointerId) {
1292
1510
  touchID = e.pointerId; //for some Microsoft browsers
1293
1511
  } else {
1294
- touch = null;
1512
+ touch = touchID = null;
1295
1513
  }
1296
1514
  _dragCount++;
1297
1515
  _addToRenderQueue(render); //causes the Draggable to render on each "tick" of TweenLite.ticker (performance optimization - updating values in a mousemove can cause them to happen too frequently, like multiple times between frame redraws which is wasteful, and it also prevents values from updating properly in IE8)
@@ -1313,6 +1531,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1313
1531
  if (self.tween) {
1314
1532
  self.tween.kill();
1315
1533
  }
1534
+ self.isThrowing = false;
1316
1535
  TweenLite.killTweensOf(scrollProxy || target, true, killProps); //in case the user tries to drag it before the last tween is done.
1317
1536
  if (scrollProxy) {
1318
1537
  TweenLite.killTweensOf(target, true, {scrollTo:1}); //just in case the original target's scroll position is being tweened somewhere else.
@@ -1466,11 +1685,15 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1466
1685
  y = Math.round(y);
1467
1686
  }
1468
1687
  if (self.x !== x || (self.y !== y && !rotationMode)) {
1469
- self.x = self.endX = x;
1470
1688
  if (rotationMode) {
1471
- self.endRotation = x;
1689
+ self.endRotation = self.x = self.endX = x;
1472
1690
  } else {
1473
- self.y = self.endY = y;
1691
+ if (allowY) {
1692
+ self.y = self.endY = y;
1693
+ }
1694
+ if (allowX) {
1695
+ self.x = self.endX = x;
1696
+ }
1474
1697
  }
1475
1698
  dirty = true; //a flag that indicates we need to render the target next time the TweenLite.ticker dispatches a "tick" event (typically on a requestAnimationFrame) - this is a performance optimization (we shouldn't render on every move because sometimes many move events can get dispatched between screen refreshes, and that'd be wasteful to render every time)
1476
1699
  if (!self.isDragging) {
@@ -1482,7 +1705,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1482
1705
 
1483
1706
  //called when the mouse/touch is released
1484
1707
  onRelease = function(e, force) {
1485
- if (!enabled || !self.isPressed || e && touchID && !force && e.pointerId && e.pointerId !== touchID) { //for some Microsoft browsers, we must attach the listener to the doc rather than the trigger so that when the finger moves outside the bounds of the trigger, things still work. So if the event we're receiving has a pointerId that doesn't match the touchID, ignore it (for multi-touch)
1708
+ if (!enabled || !self.isPressed || (e && touchID != null && !force && ((e.pointerId && e.pointerId !== touchID) || (e.changedTouches && !_hasTouchID(e.changedTouches, touchID))))) { //for some Microsoft browsers, we must attach the listener to the doc rather than the trigger so that when the finger moves outside the bounds of the trigger, things still work. So if the event we're receiving has a pointerId that doesn't match the touchID, ignore it (for multi-touch)
1486
1709
  return;
1487
1710
  }
1488
1711
  self.isPressed = false;
@@ -1809,6 +2032,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1809
2032
  };
1810
2033
 
1811
2034
  this.kill = function() {
2035
+ self.isThrowing = false;
1812
2036
  TweenLite.killTweensOf(scrollProxy || target, true, killProps);
1813
2037
  self.disable();
1814
2038
  delete _lookup[target._gsDragID];
@@ -1856,7 +2080,7 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1856
2080
  p.constructor = Draggable;
1857
2081
  p.pointerX = p.pointerY = 0;
1858
2082
  p.isDragging = p.isPressed = false;
1859
- Draggable.version = "0.13.0";
2083
+ Draggable.version = "0.14.0";
1860
2084
  Draggable.zIndex = 1000;
1861
2085
 
1862
2086
  _addListener(_doc, "touchcancel", function() {
@@ -1891,16 +2115,23 @@ var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(globa
1891
2115
  return (_getTime() - _lastDragTime) / 1000;
1892
2116
  };
1893
2117
 
1894
- var _parseRect = function(e, undefined) { //accepts a DOM element, a mouse event, or a rectangle object and returns the corresponding rectangle with left, right, width, height, top, and bottom properties
1895
- var r = (e.pageX !== undefined) ? {left:e.pageX, top:e.pageY, right:e.pageX + 1, bottom:e.pageY + 1} : (!e.nodeType && e.left !== undefined && e.top !== undefined) ? e : _unwrapElement(e).getBoundingClientRect();
1896
- if (r.right === undefined && r.width !== undefined) {
1897
- r.right = r.left + r.width;
1898
- r.bottom = r.top + r.height;
1899
- } else if (r.width === undefined) { //some browsers don't include width and height properties. We can't just set them directly on r because some browsers throw errors, so create a new generic object.
1900
- r = {width: r.right - r.left, height: r.bottom - r.top, right: r.right, left: r.left, bottom: r.bottom, top: r.top};
1901
- }
1902
- return r;
1903
- };
2118
+ var _tempRect = {}, //reuse to reduce garbage collection tasks
2119
+ _parseRect = function(e, undefined) { //accepts a DOM element, a mouse event, or a rectangle object and returns the corresponding rectangle with left, right, width, height, top, and bottom properties
2120
+ if (e === window) {
2121
+ _tempRect.left = _tempRect.top = 0;
2122
+ _tempRect.width = _tempRect.right = _docElement.clientWidth || e.innerWidth || _doc.body.clientWidth || 0;
2123
+ _tempRect.height = _tempRect.bottom = ((e.innerHeight || 0) - 20 < _docElement.clientHeight) ? _docElement.clientHeight : e.innerHeight || _doc.body.clientHeight || 0;
2124
+ return _tempRect;
2125
+ }
2126
+ var r = (e.pageX !== undefined) ? {left:e.pageX, top:e.pageY, right:e.pageX + 1, bottom:e.pageY + 1} : (!e.nodeType && e.left !== undefined && e.top !== undefined) ? e : _unwrapElement(e).getBoundingClientRect();
2127
+ if (r.right === undefined && r.width !== undefined) {
2128
+ r.right = r.left + r.width;
2129
+ r.bottom = r.top + r.height;
2130
+ } else if (r.width === undefined) { //some browsers don't include width and height properties. We can't just set them directly on r because some browsers throw errors, so create a new generic object.
2131
+ r = {width: r.right - r.left, height: r.bottom - r.top, right: r.right, left: r.left, bottom: r.bottom, top: r.top};
2132
+ }
2133
+ return r;
2134
+ };
1904
2135
 
1905
2136
  Draggable.hitTest = function(obj1, obj2, threshold) {
1906
2137
  if (obj1 === obj2) {