wilderness-core
Version:
The SVG animation engine behind Wilderness
1,794 lines (1,529 loc) • 146 kB
JavaScript
(function () {
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var toPoints = function toPoints(_ref) {
var type = _ref.type,
props = _objectWithoutProperties(_ref, ['type']);
switch (type) {
case 'circle':
return getPointsFromCircle(props);
case 'ellipse':
return getPointsFromEllipse(props);
case 'line':
return getPointsFromLine(props);
case 'path':
return getPointsFromPath(props);
case 'polygon':
return getPointsFromPolygon(props);
case 'polyline':
return getPointsFromPolyline(props);
case 'rect':
return getPointsFromRect(props);
case 'g':
return getPointsFromG(props);
default:
throw new Error('Not a valid shape type');
}
};
var getPointsFromCircle = function getPointsFromCircle(_ref2) {
var cx = _ref2.cx,
cy = _ref2.cy,
r = _ref2.r;
return [{ x: cx, y: cy - r, moveTo: true }, { x: cx, y: cy + r, curve: { type: 'arc', rx: r, ry: r, sweepFlag: 1 } }, { x: cx, y: cy - r, curve: { type: 'arc', rx: r, ry: r, sweepFlag: 1 } }];
};
var getPointsFromEllipse = function getPointsFromEllipse(_ref3) {
var cx = _ref3.cx,
cy = _ref3.cy,
rx = _ref3.rx,
ry = _ref3.ry;
return [{ x: cx, y: cy - ry, moveTo: true }, { x: cx, y: cy + ry, curve: { type: 'arc', rx: rx, ry: ry, sweepFlag: 1 } }, { x: cx, y: cy - ry, curve: { type: 'arc', rx: rx, ry: ry, sweepFlag: 1 } }];
};
var getPointsFromLine = function getPointsFromLine(_ref4) {
var x1 = _ref4.x1,
x2 = _ref4.x2,
y1 = _ref4.y1,
y2 = _ref4.y2;
return [{ x: x1, y: y1, moveTo: true }, { x: x2, y: y2 }];
};
var validCommands = /[MmLlHhVvCcSsQqTtAaZz]/g;
var commandLengths = {
A: 7,
C: 6,
H: 1,
L: 2,
M: 2,
Q: 4,
S: 4,
T: 2,
V: 1,
Z: 0
};
var relativeCommands = ['a', 'c', 'h', 'l', 'm', 'q', 's', 't', 'v'];
var isRelative = function isRelative(command) {
return relativeCommands.indexOf(command) !== -1;
};
var optionalArcKeys = ['xAxisRotation', 'largeArcFlag', 'sweepFlag'];
var getCommands = function getCommands(d) {
return d.match(validCommands);
};
var getParams = function getParams(d) {
return d.split(validCommands).map(function (v) {
return v.replace(/[0-9]+-/g, function (m) {
return m.slice(0, -1) + ' -';
});
}).map(function (v) {
return v.replace(/\.[0-9]+/g, function (m) {
return m + ' ';
});
}).map(function (v) {
return v.trim();
}).filter(function (v) {
return v.length > 0;
}).map(function (v) {
return v.split(/[ ,]+/).map(parseFloat).filter(function (n) {
return !isNaN(n);
});
});
};
var getPointsFromPath = function getPointsFromPath(_ref5) {
var d = _ref5.d;
var commands = getCommands(d);
var params = getParams(d);
var points = [];
var moveTo = void 0;
for (var i = 0, l = commands.length; i < l; i++) {
var command = commands[i];
var upperCaseCommand = command.toUpperCase();
var commandLength = commandLengths[upperCaseCommand];
var relative = isRelative(command);
var prevPoint = i === 0 ? null : points[points.length - 1];
if (commandLength > 0) {
var commandParams = params.shift();
var iterations = commandParams.length / commandLength;
for (var j = 0; j < iterations; j++) {
switch (upperCaseCommand) {
case 'M':
var x = (relative && prevPoint ? prevPoint.x : 0) + commandParams.shift();
var y = (relative && prevPoint ? prevPoint.y : 0) + commandParams.shift();
moveTo = { x: x, y: y };
points.push({ x: x, y: y, moveTo: true });
break;
case 'L':
points.push({
x: (relative ? prevPoint.x : 0) + commandParams.shift(),
y: (relative ? prevPoint.y : 0) + commandParams.shift()
});
break;
case 'H':
points.push({
x: (relative ? prevPoint.x : 0) + commandParams.shift(),
y: prevPoint.y
});
break;
case 'V':
points.push({
x: prevPoint.x,
y: (relative ? prevPoint.y : 0) + commandParams.shift()
});
break;
case 'A':
points.push({
curve: {
type: 'arc',
rx: commandParams.shift(),
ry: commandParams.shift(),
xAxisRotation: commandParams.shift(),
largeArcFlag: commandParams.shift(),
sweepFlag: commandParams.shift()
},
x: (relative ? prevPoint.x : 0) + commandParams.shift(),
y: (relative ? prevPoint.y : 0) + commandParams.shift()
});
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = optionalArcKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var k = _step.value;
if (points[points.length - 1]['curve'][k] === 0) {
delete points[points.length - 1]['curve'][k];
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
break;
case 'C':
points.push({
curve: {
type: 'cubic',
x1: (relative ? prevPoint.x : 0) + commandParams.shift(),
y1: (relative ? prevPoint.y : 0) + commandParams.shift(),
x2: (relative ? prevPoint.x : 0) + commandParams.shift(),
y2: (relative ? prevPoint.y : 0) + commandParams.shift()
},
x: (relative ? prevPoint.x : 0) + commandParams.shift(),
y: (relative ? prevPoint.y : 0) + commandParams.shift()
});
break;
case 'S':
var sx2 = (relative ? prevPoint.x : 0) + commandParams.shift();
var sy2 = (relative ? prevPoint.y : 0) + commandParams.shift();
var sx = (relative ? prevPoint.x : 0) + commandParams.shift();
var sy = (relative ? prevPoint.y : 0) + commandParams.shift();
var diff = {};
var sx1 = void 0;
var sy1 = void 0;
if (prevPoint.curve && prevPoint.curve.type === 'cubic') {
diff.x = Math.abs(prevPoint.x - prevPoint.curve.x2);
diff.y = Math.abs(prevPoint.y - prevPoint.curve.y2);
sx1 = prevPoint.x < prevPoint.curve.x2 ? prevPoint.x - diff.x : prevPoint.x + diff.x;
sy1 = prevPoint.y < prevPoint.curve.y2 ? prevPoint.y - diff.y : prevPoint.y + diff.y;
} else {
diff.x = Math.abs(sx - sx2);
diff.y = Math.abs(sy - sy2);
sx1 = prevPoint.x;
sy1 = prevPoint.y;
}
points.push({ curve: { type: 'cubic', x1: sx1, y1: sy1, x2: sx2, y2: sy2 }, x: sx, y: sy });
break;
case 'Q':
points.push({
curve: {
type: 'quadratic',
x1: (relative ? prevPoint.x : 0) + commandParams.shift(),
y1: (relative ? prevPoint.y : 0) + commandParams.shift()
},
x: (relative ? prevPoint.x : 0) + commandParams.shift(),
y: (relative ? prevPoint.y : 0) + commandParams.shift()
});
break;
case 'T':
var tx = (relative ? prevPoint.x : 0) + commandParams.shift();
var ty = (relative ? prevPoint.y : 0) + commandParams.shift();
var tx1 = void 0;
var ty1 = void 0;
if (prevPoint.curve && prevPoint.curve.type === 'quadratic') {
var _diff = {
x: Math.abs(prevPoint.x - prevPoint.curve.x1),
y: Math.abs(prevPoint.y - prevPoint.curve.y1)
};
tx1 = prevPoint.x < prevPoint.curve.x1 ? prevPoint.x - _diff.x : prevPoint.x + _diff.x;
ty1 = prevPoint.y < prevPoint.curve.y1 ? prevPoint.y - _diff.y : prevPoint.y + _diff.y;
} else {
tx1 = prevPoint.x;
ty1 = prevPoint.y;
}
points.push({ curve: { type: 'quadratic', x1: tx1, y1: ty1 }, x: tx, y: ty });
break;
}
}
} else {
if (prevPoint.x !== moveTo.x || prevPoint.y !== moveTo.y) {
points.push({ x: moveTo.x, y: moveTo.y });
}
}
}
return points;
};
var getPointsFromPolygon = function getPointsFromPolygon(_ref6) {
var points = _ref6.points;
return getPointsFromPoints({ closed: true, points: points });
};
var getPointsFromPolyline = function getPointsFromPolyline(_ref7) {
var points = _ref7.points;
return getPointsFromPoints({ closed: false, points: points });
};
var getPointsFromPoints = function getPointsFromPoints(_ref8) {
var closed = _ref8.closed,
points = _ref8.points;
var numbers = points.split(/[\s,]+/).map(function (n) {
return parseFloat(n);
});
var p = numbers.reduce(function (arr, point, i) {
if (i % 2 === 0) {
arr.push({ x: point });
} else {
arr[(i - 1) / 2].y = point;
}
return arr;
}, []);
if (closed) {
p.push(_extends({}, p[0]));
}
p[0].moveTo = true;
return p;
};
var getPointsFromRect = function getPointsFromRect(_ref9) {
var height = _ref9.height,
rx = _ref9.rx,
ry = _ref9.ry,
width = _ref9.width,
x = _ref9.x,
y = _ref9.y;
if (rx || ry) {
return getPointsFromRectWithCornerRadius({
height: height,
rx: rx || ry,
ry: ry || rx,
width: width,
x: x,
y: y
});
}
return getPointsFromBasicRect({ height: height, width: width, x: x, y: y });
};
var getPointsFromBasicRect = function getPointsFromBasicRect(_ref10) {
var height = _ref10.height,
width = _ref10.width,
x = _ref10.x,
y = _ref10.y;
return [{ x: x, y: y, moveTo: true }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }, { x: x, y: y }];
};
var getPointsFromRectWithCornerRadius = function getPointsFromRectWithCornerRadius(_ref11) {
var height = _ref11.height,
rx = _ref11.rx,
ry = _ref11.ry,
width = _ref11.width,
x = _ref11.x,
y = _ref11.y;
var curve = { type: 'arc', rx: rx, ry: ry, sweepFlag: 1 };
return [{ x: x + rx, y: y, moveTo: true }, { x: x + width - rx, y: y }, { x: x + width, y: y + ry, curve: curve }, { x: x + width, y: y + height - ry }, { x: x + width - rx, y: y + height, curve: curve }, { x: x + rx, y: y + height }, { x: x, y: y + height - ry, curve: curve }, { x: x, y: y + ry }, { x: x + rx, y: y, curve: curve }];
};
var getPointsFromG = function getPointsFromG(_ref12) {
var shapes = _ref12.shapes;
return shapes.map(function (s) {
return toPoints(s);
});
};
var pointsToD = function pointsToD(p) {
var d = '';
var i = 0;
var firstPoint = void 0;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = p[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var point = _step.value;
var _point$curve = point.curve,
curve = _point$curve === undefined ? false : _point$curve,
moveTo = point.moveTo,
x = point.x,
y = point.y;
var isFirstPoint = i === 0 || moveTo;
var isLastPoint = i === p.length - 1 || p[i + 1].moveTo;
var prevPoint = i === 0 ? null : p[i - 1];
if (isFirstPoint) {
firstPoint = point;
if (!isLastPoint) {
d += 'M' + x + ',' + y;
}
} else if (curve) {
switch (curve.type) {
case 'arc':
var _point$curve2 = point.curve,
_point$curve2$largeAr = _point$curve2.largeArcFlag,
largeArcFlag = _point$curve2$largeAr === undefined ? 0 : _point$curve2$largeAr,
rx = _point$curve2.rx,
ry = _point$curve2.ry,
_point$curve2$sweepFl = _point$curve2.sweepFlag,
sweepFlag = _point$curve2$sweepFl === undefined ? 0 : _point$curve2$sweepFl,
_point$curve2$xAxisRo = _point$curve2.xAxisRotation,
xAxisRotation = _point$curve2$xAxisRo === undefined ? 0 : _point$curve2$xAxisRo;
d += 'A' + rx + ',' + ry + ',' + xAxisRotation + ',' + largeArcFlag + ',' + sweepFlag + ',' + x + ',' + y;
break;
case 'cubic':
var _point$curve3 = point.curve,
cx1 = _point$curve3.x1,
cy1 = _point$curve3.y1,
cx2 = _point$curve3.x2,
cy2 = _point$curve3.y2;
d += 'C' + cx1 + ',' + cy1 + ',' + cx2 + ',' + cy2 + ',' + x + ',' + y;
break;
case 'quadratic':
var _point$curve4 = point.curve,
qx1 = _point$curve4.x1,
qy1 = _point$curve4.y1;
d += 'Q' + qx1 + ',' + qy1 + ',' + x + ',' + y;
break;
}
if (isLastPoint && x === firstPoint.x && y === firstPoint.y) {
d += 'Z';
}
} else if (isLastPoint && x === firstPoint.x && y === firstPoint.y) {
d += 'Z';
} else if (x !== prevPoint.x && y !== prevPoint.y) {
d += 'L' + x + ',' + y;
} else if (x !== prevPoint.x) {
d += 'H' + x;
} else if (y !== prevPoint.y) {
d += 'V' + y;
}
i++;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return d;
};
var toPath = function toPath(s) {
var isPoints = Array.isArray(s);
var isGroup = isPoints ? Array.isArray(s[0]) : s.type === 'g';
var points = isPoints ? s : isGroup ? s.shapes.map(function (shp) {
return toPoints(shp);
}) : toPoints(s);
if (isGroup) {
return points.map(function (p) {
return pointsToD(p);
});
}
return pointsToD(points);
};
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var getErrors = function getErrors(shape) {
var rules = getRules(shape);
var errors = [];
rules.map(function (_ref) {
var match = _ref.match,
prop = _ref.prop,
required = _ref.required,
type = _ref.type;
if (typeof shape[prop] === 'undefined') {
if (required) {
errors.push(prop + ' prop is required' + (prop === 'type' ? '' : ' on a ' + shape.type));
}
} else {
if (typeof type !== 'undefined') {
if (type === 'array') {
if (!Array.isArray(shape[prop])) {
errors.push(prop + ' prop must be of type array');
}
} else if (_typeof(shape[prop]) !== type) {
// eslint-disable-line valid-typeof
errors.push(prop + ' prop must be of type ' + type);
}
}
if (Array.isArray(match)) {
if (match.indexOf(shape[prop]) === -1) {
errors.push(prop + ' prop must be one of ' + match.join(', '));
}
}
}
});
if (shape.type === 'g' && Array.isArray(shape.shapes)) {
var childErrors = shape.shapes.map(function (s) {
return getErrors(s);
});
return [].concat.apply(errors, childErrors);
}
return errors;
};
var getRules = function getRules(shape) {
var rules = [{
match: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect', 'g'],
prop: 'type',
required: true,
type: 'string'
}];
switch (shape.type) {
case 'circle':
rules.push({ prop: 'cx', required: true, type: 'number' });
rules.push({ prop: 'cy', required: true, type: 'number' });
rules.push({ prop: 'r', required: true, type: 'number' });
break;
case 'ellipse':
rules.push({ prop: 'cx', required: true, type: 'number' });
rules.push({ prop: 'cy', required: true, type: 'number' });
rules.push({ prop: 'rx', required: true, type: 'number' });
rules.push({ prop: 'ry', required: true, type: 'number' });
break;
case 'line':
rules.push({ prop: 'x1', required: true, type: 'number' });
rules.push({ prop: 'x2', required: true, type: 'number' });
rules.push({ prop: 'y1', required: true, type: 'number' });
rules.push({ prop: 'y2', required: true, type: 'number' });
break;
case 'path':
rules.push({ prop: 'd', required: true, type: 'string' });
break;
case 'polygon':
case 'polyline':
rules.push({ prop: 'points', required: true, type: 'string' });
break;
case 'rect':
rules.push({ prop: 'height', required: true, type: 'number' });
rules.push({ prop: 'rx', type: 'number' });
rules.push({ prop: 'ry', type: 'number' });
rules.push({ prop: 'width', required: true, type: 'number' });
rules.push({ prop: 'x', required: true, type: 'number' });
rules.push({ prop: 'y', required: true, type: 'number' });
break;
case 'g':
rules.push({ prop: 'shapes', required: true, type: 'array' });
break;
}
return rules;
};
var valid = function valid(shape) {
var errors = getErrors(shape);
return {
errors: errors,
valid: errors.length === 0
};
};
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof$1 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* A tweenable color.
*
* @typedef {Object} Color
*
* @property {string} middleware - The name of this middleware.
* @property {number} r - The hexadecimal red value.
* @property {number} g - The hexadecimal green value.
* @property {number} b - The hexadecimal blue value.
* @property {number} a - The alpha value.
*/
var name = 'color';
var htmlColors = {
'aliceblue': '#F0F8FF',
'antiquewhite': '#FAEBD7',
'aqua': '#00FFFF',
'aquamarine': '#7FFFD4',
'azure': '#F0FFFF',
'beige': '#F5F5DC',
'bisque': '#FFE4C4',
'black': '#000000',
'blanchedalmond': '#FFEBCD',
'blue': '#0000FF',
'blueviolet': '#8A2BE2',
'brown': '#A52A2A',
'burlywood': '#DEB887',
'cadetblue': '#5F9EA0',
'chartreuse': '#7FFF00',
'chocolate': '#D2691E',
'coral': '#FF7F50',
'cornflowerblue': '#6495ED',
'cornsilk': '#FFF8DC',
'crimson': '#DC143C',
'cyan': '#00FFFF',
'darkblue': '#00008B',
'darkcyan': '#008B8B',
'darkgoldenrod': '#B8860B',
'darkgray': '#A9A9A9',
'darkgreen': '#006400',
'darkgrey': '#A9A9A9',
'darkkhaki': '#BDB76B',
'darkmagenta': '#8B008B',
'darkolivegreen': '#556B2F',
'darkorange': '#FF8C00',
'darkorchid': '#9932CC',
'darkred': '#8B0000',
'darksalmon': '#E9967A',
'darkseagreen': '#8FBC8F',
'darkslateblue': '#483D8B',
'darkslategray': '#2F4F4F',
'darkslategrey': '#2F4F4F',
'darkturquoise': '#00CED1',
'darkviolet': '#9400D3',
'deeppink': '#FF1493',
'deepskyblue': '#00BFFF',
'dimgray': '#696969',
'dimgrey': '#696969',
'dodgerblue': '#1E90FF',
'firebrick': '#B22222',
'floralwhite': '#FFFAF0',
'forestgreen': '#228B22',
'fuchsia': '#FF00FF',
'gainsboro': '#DCDCDC',
'ghostwhite': '#F8F8FF',
'gold': '#FFD700',
'goldenrod': '#DAA520',
'gray': '#808080',
'green': '#008000',
'greenyellow': '#ADFF2F',
'grey': '#808080',
'honeydew': '#F0FFF0',
'hotpink': '#FF69B4',
'indianred': '#CD5C5C',
'indigo': '#4B0082',
'ivory': '#FFFFF0',
'khaki': '#F0E68C',
'lavender': '#E6E6FA',
'lavenderblush': '#FFF0F5',
'lawngreen': '#7CFC00',
'lemonchiffon': '#FFFACD',
'lightblue': '#ADD8E6',
'lightcoral': '#F08080',
'lightcyan': '#E0FFFF',
'lightgoldenrodyellow': '#FAFAD2',
'lightgray': '#D3D3D3',
'lightgreen': '#90EE90',
'lightgrey': '#D3D3D3',
'lightpink': '#FFB6C1',
'lightsalmon': '#FFA07A',
'lightseagreen': '#20B2AA',
'lightskyblue': '#87CEFA',
'lightslategray': '#778899',
'lightslategrey': '#778899',
'lightsteelblue': '#B0C4DE',
'lightyellow': '#FFFFE0',
'lime': '#00FF00',
'limegreen': '#32CD32',
'linen': '#FAF0E6',
'magenta': '#FF00FF',
'maroon': '#800000',
'mediumaquamarine': '#66CDAA',
'mediumblue': '#0000CD',
'mediumorchid': '#BA55D3',
'mediumpurple': '#9370DB',
'mediumseagreen': '#3CB371',
'mediumslateblue': '#7B68EE',
'mediumspringgreen': '#00FA9A',
'mediumturquoise': '#48D1CC',
'mediumvioletred': '#C71585',
'midnightblue': '#191970',
'mintcream': '#F5FFFA',
'mistyrose': '#FFE4E1',
'moccasin': '#FFE4B5',
'navajowhite': '#FFDEAD',
'navy': '#000080',
'oldlace': '#FDF5E6',
'olive': '#808000',
'olivedrab': '#6B8E23',
'orange': '#FFA500',
'orangered': '#FF4500',
'orchid': '#DA70D6',
'palegoldenrod': '#EEE8AA',
'palegreen': '#98FB98',
'paleturquoise': '#AFEEEE',
'palevioletred': '#DB7093',
'papayawhip': '#FFEFD5',
'peachpuff': '#FFDAB9',
'peru': '#CD853F',
'pink': '#FFC0CB',
'plum': '#DDA0DD',
'powderblue': '#B0E0E6',
'purple': '#800080',
'rebeccapurple': '#663399',
'red': '#FF0000',
'rosybrown': '#BC8F8F',
'royalblue': '#4169E1',
'saddlebrown': '#8B4513',
'salmon': '#FA8072',
'sandybrown': '#F4A460',
'seagreen': '#2E8B57',
'seashell': '#FFF5EE',
'sienna': '#A0522D',
'silver': '#C0C0C0',
'skyblue': '#87CEEB',
'slateblue': '#6A5ACD',
'slategray': '#708090',
'slategrey': '#708090',
'snow': '#FFFAFA',
'springgreen': '#00FF7F',
'steelblue': '#4682B4',
'tan': '#D2B48C',
'teal': '#008080',
'thistle': '#D8BFD8',
'tomato': '#FF6347',
'turquoise': '#40E0D0',
'violet': '#EE82EE',
'wheat': '#F5DEB3',
'white': '#FFFFFF',
'whitesmoke': '#F5F5F5',
'yellow': '#FFFF00',
'yellowgreen': '#9ACD32'
};
var htmlColorKeys = Object.keys(htmlColors);
/**
* Converts a color string to a Color.
*
* @param {*} x - A potential color string.
*
* @returns {*}
*
* @example
* input('#FFFFFF')
*/
var input = function input(x) {
if (typeof x === 'string') {
if (hex(x)) {
return hexToColor(x);
} else if (rgb(x)) {
return rgbToColor(x);
} else if (rgba(x)) {
return rgbaToColor(x);
} else if (html(x)) {
return htmlToColor(x);
}
}
return x;
};
/**
* Converts a Color to a rgba color string.
*
* @param {*} x - A potential Color.
*
* @returns {*}
*
* @example
* output(color)
*/
var output = function output(x) {
if ((typeof x === 'undefined' ? 'undefined' : _typeof$1(x)) === 'object' && x.middleware === name) {
return colorToRgba(x);
}
return x;
};
/**
* Is string a hex color?
*
* @param {string} str - A potential hex color.
*
* @returns {boolean}
*
* @example
* hex('#FFFFFF')
*/
var hex = function hex(str) {
return str.match(/^#(?:[0-9a-f]{3}){1,2}$/i) !== null;
};
/**
* Is string a rgba color?
*
* @param {string} str - A potential rgba color.
*
* @returns {boolean}
*
* @example
* rgba('rgba(255,255,255,1)')
*/
var rgba = function rgba(str) {
return str.startsWith('rgba(');
};
/**
* Is string a rgb color?
*
* @param {string} str - A potential rgb color.
*
* @returns {boolean}
*
* @example
* rgb('rgb(255,255,255)')
*/
var rgb = function rgb(str) {
return str.startsWith('rgb(');
};
/**
* Is string a html color?
*
* @param {string} str - A potential html color.
*
* @returns {boolean}
*
* @example
* html('limegreen')
*/
var html = function html(str) {
return htmlColorKeys.indexOf(str) !== -1;
};
/**
* Converts a hex string to a Color.
*
* @param {string} hex - A hex color.
*
* @returns {Color}
*
* @example
* hexToColor('#FFFFFF')
*/
var hexToColor = function hexToColor(hex) {
var x = hex.replace('#', '');
if (x.length === 3) {
var y = '';
for (var i = 0; i < 3; i++) {
var v = x.charAt(i);
y += '' + v + v;
}
x = y;
}
return {
middleware: name,
r: parseInt(x.slice(0, 2), 16),
g: parseInt(x.slice(2, 4), 16),
b: parseInt(x.slice(4, 6), 16),
a: 1
};
};
/**
* Converts a rgb string to a Color.
*
* @param {string} rgb - A rgb color.
*
* @returns {Color}
*
* @example
* rgbToColor('rgb(255,255,255)')
*/
var rgbToColor = function rgbToColor(rgb) {
var x = rgb.replace(/\s/g, '');
var _x$substring$split = x.substring(4, x.length - 1).split(','),
_x$substring$split2 = _slicedToArray(_x$substring$split, 3),
r = _x$substring$split2[0],
g = _x$substring$split2[1],
b = _x$substring$split2[2];
return {
middleware: name,
r: parseFloat(r),
g: parseFloat(g),
b: parseFloat(b),
a: 1
};
};
/**
* Converts a rgba string to a Color.
*
* @param {string} rgba - A rgba color.
*
* @returns {Color}
*
* @example
* rgbaToColor('rgba(255,255,255,1)')
*/
var rgbaToColor = function rgbaToColor(rgba) {
var x = rgba.replace(/\s/g, '');
var _x$substring$split3 = x.substring(5, x.length - 1).split(','),
_x$substring$split4 = _slicedToArray(_x$substring$split3, 4),
r = _x$substring$split4[0],
g = _x$substring$split4[1],
b = _x$substring$split4[2],
a = _x$substring$split4[3];
return {
middleware: 'color',
r: parseFloat(r),
g: parseFloat(g),
b: parseFloat(b),
a: parseFloat(a)
};
};
/**
* Converts a html string to a Color.
*
* @param {string} html - An html color.
*
* @returns {Color}
*
* @example
* htmlToColor('limegreen')
*/
var htmlToColor = function htmlToColor(html) {
return hexToColor(htmlColors[html]);
};
/**
* Converts a Color to a rgba color string.
*
* @param {Color} color
*
* @returns {string}
*
* @example
* colorToRgba(color)
*/
var colorToRgba = function colorToRgba(_ref) {
var r = _ref.r,
g = _ref.g,
b = _ref.b,
a = _ref.a;
return 'rgba(' + parseInt(limit(r, 0, 255), 10) + ',' + parseInt(limit(g, 0, 255), 10) + ',' + parseInt(limit(b, 0, 255), 10) + ',' + limit(a, 0, 1) + ')';
};
/**
* Find the closest number within limits.
*
* @param {number} num - The desired number.
* @param {number} min - The minimum returned number.
* @param {number} max - the maximum returned number.
*
* @returns {number}
*
* @example
* limit(-1, 2, 5)
*/
var limit = function limit(num, min, max) {
return Math.max(min, Math.min(max, num));
};
var colorMiddleware = { name: name, input: input, output: output };
var _typeof$4 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* A naive, but small, clone function.
*
* @param {*} value
*
* @returns {*}
*
* @example
* clone('hello world')
*/
var clone = function clone(value) {
if ((typeof value === 'undefined' ? 'undefined' : _typeof$4(value)) !== 'object') {
return value;
} else if (Array.isArray(value)) {
var arr = [];
for (var i = 0, l = value.length; i < l; i++) {
arr.push(clone(value[i]));
}
return arr;
} else if (value !== null) {
var obj = {};
for (var key in value) {
obj[key] = clone(value[key]);
}
return obj;
}
return value;
};
var _typeof$5 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* A tweenable unit.
*
* @typedef {Object} Unit
*
* @property {string} middleware - The name of this middleware.
* @property {string} values - The type of color string to output.
*/
var name$1 = 'unit';
var units = ['ch', 'cm', 'em', 'ex', 'in', 'mm', 'pc', 'pt', 'px', 'rem', 'vh', 'vmax', 'vmin', 'vw', '%'];
/**
* Converts a unit string to a Unit.
*
* @param {*} x - A potential unit string.
*
* @returns {*}
*
* @example
* input('20px')
*/
var input$1 = function input(x) {
if (typeof x === 'string') {
var parts = x.split(' ');
var values = [];
for (var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
var number = parseFloat(part);
var unit = part.replace(number, '');
if (!isNaN(number) && (unit === '' || units.indexOf(unit) !== -1)) {
values.push([number, unit]);
} else {
values.push(part);
}
}
if (values.toString() !== parts.toString()) {
return { middleware: name$1, values: values };
}
}
return x;
};
/**
* Converts a Unit to a unit string.
*
* @param {*} x - A potential Unit.
*
* @returns {*}
*
* @example
* output(unit)
*/
var output$1 = function output(x) {
if ((typeof x === 'undefined' ? 'undefined' : _typeof$5(x)) === 'object' && x.middleware === name$1) {
var values = x.values;
var result = [];
for (var i = 0, l = values.length; i < l; i++) {
result.push(values[i].join(''));
}
return result.join(' ');
}
return x;
};
var unitMiddleware = { name: name$1, input: input$1, output: output$1 };
var config = {
defaults: {
keyframe: {
duration: 250,
easing: 'easeInOutQuad'
},
motionPath: {
easing: 'easeInOutQuad'
},
timeline: {
alternate: false,
initialIterations: 0,
iterations: 1,
middleware: [colorMiddleware, unitMiddleware],
queue: 0,
reverse: false
}
}
};
var _typeof$6 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* A group of functions to transform/untransform a value.
*
* @typedef {Object} Middleware
*
* @property {string} name - The name of the middleware.
* @property {function} input - Transform.
* @property {function} output - Untransform.
*/
/**
* Run every part of a value through a function.
*
* @param {*} value
* @param {function} func
*
* @returns {*}
*
* @example
* apply(2, n => n * 2)
*/
var apply$1 = function apply(value, func) {
var v = func(value);
if ((typeof v === 'undefined' ? 'undefined' : _typeof$6(v)) !== 'object') {
return v;
} else if (Array.isArray(v)) {
var arr = [];
for (var i = 0, l = v.length; i < l; i++) {
arr.push(apply(v[i], func));
}
return arr;
} else if (v !== null) {
var obj = {};
for (var k in v) {
obj[k] = apply(v[k], func);
}
return obj;
}
return v;
};
/**
* Runs each Middleware input function in turn on a value.
*
* @param {*} value
* @param {Middleware[]} middleware
*
* @returns {*}
*
* @example
* input({ foo: 1, bar: [ 2, 3 ] }, middleware)
*/
var input$2 = function input(value, middleware) {
var v = value;
for (var i = 0, l = middleware.length; i < l; i++) {
v = apply$1(v, middleware[i].input);
}
return v;
};
/**
* Runs each Middleware output function in reverse on a value.
*
* @param {*} value
* @param {Middleware[]} middleware
*
* @returns {*}
*
* @example
* output({ foo: 1, bar: [ 2, 3 ] }, middleware)
*/
var output$2 = function output(value, middleware) {
var v = value;
for (var i = middleware.length - 1; i >= 0; i--) {
v = apply$1(v, middleware[i].output);
}
return v;
};
var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof$3 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _slicedToArray$1 = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
/* globals true */
/**
* The position of an object on a Timeline
* where 0 is Timeline start and 1 is Timeline finish.
*
* @typedef {Object} TimelinePosition
*
* @property {Position} start
* @property {Position} finish
*/
/**
* A Shape positioned on a Timeline.
*
* @typedef {Object} TimelineShape
*
* @property {Shape} shape
* @property {TimelinePosition} timelinePosition
*/
/**
* The position of an object on a Timeline in milliseconds.
*
* @typedef {Object} MsTimelinePosition
*
* @property {number} start.
* @property {number} finish.
*/
/**
* A Shape positioned on a Timeline (position set in milliseconds).
*
* @typedef {Object} MsTimelineShape
*
* @property {Shape} shape
* @property {MsTimelinePosition} timelinePosition
*/
/**
* A TimelineShape array and their total duration.
*
* @typedef {Object} TimelineShapesAndDuration
*
* @property {TimelineShape[]} timelineShapes
* @property {number} duration
*/
/**
* The options required to calculate the current playback Position.
*
* @typedef {Object} PlaybackOptions
*
* @property {boolean} alternate - Should the next iteration reverse current direction?
* @property {number} duration - Milliseconds that each iteration lasts.
* @property {number} initialIterations - The starting number of iterations.
* @property {number} iterations - The number of playback interations (additional to initialIterations).
* @property {boolean} reverse - Should the first iteration start in a reverse direction?
* @property {number} [started] - The UNIX timestamp of playback start.
*/
/**
* PlaybackOptions and tween middleware.
*
* @typedef {Object} TimelineOptions
*
* @extends PlaybackOptions
* @property {Middleware[]} middleware
*/
/**
* A Shape and timeline related options.
*
* @typedef {Object} ShapeWithOptions
*
* @property {(string|number)} [after] - The name of the Shape to queue after (in sequence).
* @property {(string|number)} [at] - The name of the Shape to queue at (in parallel).
* @property {(string|number)} name - A unique reference.
* @property {number} offset - The offset in milliseconds to adjust the queuing of this shape.
* @property {Shape} shape
*/
/**
* An object containing Middlware, PlaybackOptions and ShapesWithOptions.
*
* @typedef {Object} SortedTimelineProps
*
* @property {Middleware[]} middleware
* @property {PlaybackOptions} playbackOptions
* @property {ShapeWithOptions[]} shapesWithOptions
*/
/**
* A sequence of Shapes.
*
* @typedef {Object} Timeline
*
* @property {Middleware[]} middleware
* @property {PlaybackOptions} playbackOptions
* @property {Object} state - Holds the last known state of the timeline.
* @property {TimelineShape[]} timelineShapes
*/
/**
* Runs each Middleware input function on every Keyframe's FrameShape.
*
* @param {Shape} shape
* @param {Middleware[]} middleware
*
* @example
* apply(shape, middleware)
*/
var apply = function apply(_ref, middleware) {
var keyframes = _ref.keyframes;
for (var i = 0, l = keyframes.length; i < l; i++) {
var keyframe = keyframes[i];
keyframe.frameShape = input$2(keyframe.frameShape, middleware);
}
};
/**
* Is playback currently in reverse?
*
* @param {PlaybackOptions} playbackOptions
* @param {number} complete - The number of iterations complete.
*
* @example
* currentReverse(playbackOptions, complete)
*/
var currentReverse = function currentReverse(playbackOptions, complete) {
var reverse = playbackOptions.reverse;
if (complete === 0) {
return reverse;
}
var alternate = playbackOptions.alternate;
var initialIterations = playbackOptions.initialIterations;
var initialReverse = sameDirection(alternate, initialIterations) ? reverse : !reverse;
return sameDirection(alternate, initialIterations + complete) ? initialReverse : !initialReverse;
};
/**
* The number of iterations a Timeline has completed.
*
* @param {PlaybackOptions} playbackOptions
* @param {number} opts.at
*
* @returns {number}
*
* @example
* iterationsComplete(playbackOptions, 1000)
*/
var iterationsComplete = function iterationsComplete(playbackOptions, at) {
var duration = playbackOptions.duration;
var iterations = playbackOptions.iterations;
var started = playbackOptions.started;
if (typeof started === 'undefined' || at <= started) {
return 0;
}
var ms = at - started;
var maxDuration = duration * iterations;
if (ms >= maxDuration) {
return iterations;
}
return ms / duration;
};
/**
* Starts playback of a Timeline.
*
* @param {Timeline} timeline
* @param {PlaybackOptions} playbackOptions
* @param {number} [at]
*
* @example
* play(timeline, { initialIterations: 0 })
*/
var play$1 = function play(timeline) {
var playbackOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var at = arguments[2];
timeline.playbackOptions = updatePlaybackOptions({ at: at, timeline: timeline, playbackOptions: playbackOptions });
updateState(timeline, at);
};
/**
* Calculate the Timeline Position.
*
* @param {number} totalIterations - initialIterations + iterationsComplete.
* @param {boolean} reverse - Is the Timeline currently in reverse?
*
* @returns {Position}
*
* @example
* position(5.43, true)
*/
var position = function position(totalIterations, reverse) {
var i = totalIterations >= 1 && totalIterations % 1 === 0 ? 1 : totalIterations % 1;
return reverse ? 1 - i : i;
};
/**
* Is the direction same as initial direction?
*
* @param {boolean} alternate - Is iteration direction alternating?
* @param {number} iterations - The number of iterations complete.
*
* @return {boolean}
*
* @example
* sameDirection(true, 3.25)
*/
var sameDirection = function sameDirection(alternate, iterations) {
var x = iterations % 2;
return !alternate || iterations === 0 || x <= 1 && x % 2 > 0;
};
/**
* Calculate the start position of a Shape on the Timeline.
*
* @param {Object} props
* @param {(string|number)} [props.after]
* @param {(string|number)} [props.at]
* @param {MsTimelineShape[]} props.msTimelineShapes
* @param {number} props.offset
* @param {number} props.timelineFinish - The current finish of the timeline.
*
* @returns {number}
*
* @example
* shapeStart({ 'foo', msTimelineShapes, 200, 2000 })
*/
var shapeStart = function shapeStart(_ref2) {
var after = _ref2.after,
at = _ref2.at,
msTimelineShapes = _ref2.msTimelineShapes,
offset = _ref2.offset,
timelineFinish = _ref2.timelineFinish;
if (typeof after !== 'undefined' || typeof at !== 'undefined') {
var reference = typeof after !== 'undefined' ? after : at;
for (var i = 0; i < msTimelineShapes.length; i++) {
var s = msTimelineShapes[i];
if (reference === s.shape.name) {
return (typeof at !== 'undefined' ? s.timelinePosition.start : s.timelinePosition.finish) + offset;
}
}
for (var _i = 0; _i < msTimelineShapes.length; _i++) {
var _s = msTimelineShapes[_i];
for (var j = 0; j < _s.shape.keyframes.length; j++) {
var keyframe = _s.shape.keyframes[j];
if (reference === keyframe.name) {
return _s.timelinePosition.start + _s.shape.duration * keyframe.position + offset;
}
}
}
{
throw new Error('No Shape or Keyframe matching name \'' + reference + '\'');
}
}
return timelineFinish + offset;
};
/**
* Create a ShapeWithOptions from an array.
*
* @param {Object[]} arr
* @param {Shape} arr.0
* @param {Object} arr.1
*
* @returns {ShapeWithOptions}
*
* @example
* shapeWithOptionsFromArray(arr, i)
*/
var shapeWithOptionsFromArray = function shapeWithOptionsFromArray(_ref3, i) {
var _ref4 = _slicedToArray$1(_ref3, 2),
shape = _ref4[0],
options = _ref4[1];
if (true && ((typeof shape === 'undefined' ? 'undefined' : _typeof$3(shape)) !== 'object' || !shape.keyframes)) {
throw new TypeError('When an array is passed to the timeline function the first item must be a Shape');
}
if (true && (typeof options === 'undefined' ? 'undefined' : _typeof$3(options)) !== 'object') {
throw new TypeError('When an array is passed to the timeline function the second item must be an object');
}
var _options$name = options.name,
name = _options$name === undefined ? i : _options$name,
_options$queue = options.queue,
queue = _options$queue === undefined ? config.defaults.timeline.queue : _options$queue;
if (true && typeof name !== 'string' && typeof name !== 'number') {
throw new TypeError('The name prop must be of type string or number');
}
if ((typeof queue === 'undefined' ? 'undefined' : _typeof$3(queue)) === 'object' && !Array.isArray(queue) && queue !== null) {
var after = queue.after,
at = queue.at,
_queue$offset = queue.offset,
offset = _queue$offset === undefined ? 0 : _queue$offset;
if (true && typeof offset !== 'undefined' && typeof offset !== 'number') {
throw new TypeError('The queue.offset prop must be of type number');
}
if (true && typeof at !== 'undefined' && typeof after !== 'undefined') {
throw new TypeError('You cannot pass both queue.at and queue.after props');
}
if (true && typeof at !== 'undefined' && typeof at !== 'string' && typeof at !== 'number') {
throw new TypeError('The queue.at prop must be of type string or number');
}
if (true && typeof after !== 'undefined' && typeof after !== 'string' && typeof after !== 'number') {
throw new TypeError('The queue.after prop must be of type string or number');
}
if (typeof at !== 'undefined') {
return { at: at, name: name, offset: offset, shape: shape };
}
if (typeof after !== 'undefined') {
return { after: after, name: name, offset: offset, shape: shape };
}
return { name: name, offset: offset, shape: shape };
} else if (typeof queue === 'number') {
return { name: name, offset: queue, shape: shape };
} else if (typeof queue === 'string') {
return { after: queue, name: name, offset: 0, shape: shape };
}
{
throw new TypeError('The queue prop must be of type number, string or object');
}
return { name: name, offset: 0, shape: shape };
};
/**
* Sorts an array of Shapes, ShapesWithOptions and TimelineOptions.
*
* @param {(Shape|Object[]|TimelineOptions)[]} props
*
* @returns {SortedTimelineProps}
*
* @example
* sort(props)
*/
var sort = function sort(props) {
if (true && props.length === 0) {
throw new TypeError('The timeline function must be passed at least one Shape');
}
var options = {};
var shapesWithOptions = [];
for (var i = 0, l = props.length; i < l; i++) {
var prop = props[i];
if (Array.isArray(prop)) {
shapesWithOptions.push(shapeWithOptionsFromArray(prop, i));
} else {
if (true && (typeof prop === 'undefined' ? 'undefined' : _typeof$3(prop)) !== 'object') {
throw new TypeError('The timeline function must only be passed objects and arrays');
}
if (prop.keyframes) {
shapesWithOptions.push({
name: i,
offset: config.defaults.timeline.queue,
shape: prop
});
} else {
{
if (i === 0) {
throw new TypeError('The timeline function must receive a Shape as the first argument');
} else if (i !== props.length - 1) {
throw new TypeError('The timeline function must receive options as the final argument');
}
}
options = clone(prop);
}
}
}
return {
middleware: validMiddleware(options),
playbackOptions: validPlaybackOptions(options),
shapesWithOptions: shapesWithOptions
};
};
/**
* Creates a Timeline from one or more Shape.
* Optionally can take an options object as the last argument,
* as well as options for each Shape if passed in as an array.
*
* @param {...(Shape|Object[]|TimelineOptions)} props
*
* @returns {Timeline}
*
* @example
* timeline(circle, [ square, { queue: -200 } ], { duration: 5000 })
*/
var timeline = function timeline() {
for (var _len = arguments.length, props = Array(_len), _key = 0; _key < _len; _key++) {
props[_key] = arguments[_key];
}
var _sort = sort(props),
middleware = _sort.middleware,
playbackOptions = _sort.playbackOptions,
shapesWithOptions = _sort.shapesWithOptions;
var _timelineShapesAndDur = timelineShapesAndDuration(shapesWithOptions, middleware),
duration = _timelineShapesAndDur.duration,
timelineShapes = _timelineShapesAndDur.timelineShapes;
if (typeof playbackOptions.duration === 'undefined') {
playbackOptions.duration = duration;
}
var t = { middleware: middleware, playbackOptions: playbackOptions, state: {}, timelineShapes: timelineShapes };
for (var i = 0, l = timelineShapes.length; i < l; i++) {
var shape = timelineShapes[i].shape;
shape.timeline = t;
shape.timelineIndex = i;
}
updateState(t);
t.event = event(t);
return t;
};
/**
* Converts a set of MsTimelineShapes to a set of TimelineShapes
* given the Timeline start and total duration values.
*
* @param {Object} props
* @param {number} props.duration
* @param {msTimelineShape[]} props.msTimelineShapes
* @param {number} props.start
*
* @returns {TimelineShape[]}
*
* @example
* timelineShapes()
*/
var timelineShapes = function timelineShapes(_ref5) {
var duration = _ref5.duration,
msTimelineShapes = _ref5.msTimelineShapes,
start = _ref5.start;
var s = [];
for (var i = 0, l = msTimelineShapes.length; i < l; i++) {
var msTimelineShape = msTimelineShapes[i];
var timelinePosition = msTimelineShape.timelinePosition;
s.push({
shape: msTimelineShape.shape,
timelinePosition: {
start: (timelinePosition.start - start) / duration,
finish: (timelinePosition.finish - start) / duration
}
});
}
return s;
};
/**
* Converts an array of ShapesWithOptions into TimelineShapes
* and their total duration.
*
* @param {ShapeWithOptions[]} shapesWithOptions
* @param {Middleware[]} middleware
*
* @returns {TimelineShapesAndDuration}
*
* @example
* timelineShapes(shapesWithOptions)
*/
var timelineShapesAndDuration = function timelineShapesAndDuration(shapesWithOptions, middleware) {
var timelineStart = 0;
var timelineFinish = 0;
var msTimelineShapes = [];
for (var i = 0, l = shapesWithOptions.length; i < l; i++) {
var _shapesWithOptions$i = shapesWithOptions[i],
after = _shapesWithOptions$i.after,
at = _shapesWithOptions$i.at,
name = _shapesWithOptions$i.name,
offset = _shapesWithOptions$i.offset,
shape = _shapesWithOptions$i.shape;
if (true && typeof shape.timeline !== 'undefined') {
throw new Error('A Shape can only be added to one timeline');
}
shape.name = name;
apply(shape, middleware);
var start = shapeStart({
after: after,
at: at,
msTimelineShapes: msTimelineShapes,
offset: offset,
timelineFinish: timelineFinish
});
var finish = start + shape.duration;
timelineStart = Math.min(timelineStart, start);
timelineFinish = Math.max(timelineFinish, finish);
msTimelineShapes.push({ shape: shape, timelinePosition: { start: start, finish: fini