aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaivan <savian@me.com>2018-11-25 16:21:53 +1300
committerSaivan <savian@me.com>2018-11-25 16:21:53 +1300
commit62de7d0a1b994b69032a759b796b486e6bc382e3 (patch)
tree112b19f2903b4dc5b4cf61ebef0d021c6ca2f14d
parent2b37d7ba5b4267b39c86f9aba5fb14a1b376e846 (diff)
downloadsvg.js-62de7d0a1b994b69032a759b796b486e6bc382e3.tar.gz
svg.js-62de7d0a1b994b69032a759b796b486e6bc382e3.zip
Changed the esLint rules to avoid silly ternary operators, and to let code breathe!
This commit modifies some of the eslint rules, to allow our code to be a little bit more readable. This came about because we had a particularly pesky problem, where the code was indenting ternary operators. This fixes that, and makes it easy to add new rules to eslint as we please in the future. Changes ======= - Rebuilt the library with new eslint rules - Changed the eslintrc file to a yaml file by default
-rw-r--r--.eslintrc3
-rw-r--r--.eslintrc.yaml10
-rw-r--r--dist/svg.js658
-rw-r--r--package-lock.json2
-rw-r--r--src/animation/Animator.js70
-rw-r--r--src/animation/Controller.js252
-rw-r--r--src/animation/Queue.js36
-rw-r--r--src/animation/Runner.js842
-rw-r--r--src/animation/Timeline.js194
-rw-r--r--src/elements/A.js50
-rw-r--r--src/elements/Bare.js34
-rw-r--r--src/elements/Circle.js52
-rw-r--r--src/elements/ClipPath.js50
-rw-r--r--src/elements/Container.js30
-rw-r--r--src/elements/Defs.js22
-rw-r--r--src/elements/Dom.js268
-rw-r--r--src/elements/Element.js142
-rw-r--r--src/elements/Ellipse.js34
-rw-r--r--src/elements/G.js22
-rw-r--r--src/elements/Gradient.js66
-rw-r--r--src/elements/HtmlNode.js2
-rw-r--r--src/elements/Image.js96
-rw-r--r--src/elements/Line.js68
-rw-r--r--src/elements/Marker.js82
-rw-r--r--src/elements/Mask.js50
-rw-r--r--src/elements/Path.js78
-rw-r--r--src/elements/Pattern.js58
-rw-r--r--src/elements/Polygon.js26
-rw-r--r--src/elements/Polyline.js26
-rw-r--r--src/elements/Rect.js24
-rw-r--r--src/elements/Shape.js2
-rw-r--r--src/elements/Stop.js24
-rw-r--r--src/elements/Style.js64
-rw-r--r--src/elements/Svg.js72
-rw-r--r--src/elements/Symbol.js22
-rw-r--r--src/elements/Text.js174
-rw-r--r--src/elements/TextPath.js78
-rw-r--r--src/elements/Tspan.js56
-rw-r--r--src/elements/Use.js28
-rw-r--r--src/main.js40
-rw-r--r--src/modules/core/attr.js104
-rw-r--r--src/modules/core/circled.js52
-rw-r--r--src/modules/core/event.js160
-rw-r--r--src/modules/core/gradiented.js20
-rw-r--r--src/modules/core/parser.js16
-rw-r--r--src/modules/core/pointed.js24
-rw-r--r--src/modules/core/poly.js30
-rw-r--r--src/modules/core/selector.js18
-rw-r--r--src/modules/core/textable.js12
-rw-r--r--src/modules/optional/arrange.js82
-rw-r--r--src/modules/optional/class.js48
-rw-r--r--src/modules/optional/css.js80
-rw-r--r--src/modules/optional/data.js38
-rw-r--r--src/modules/optional/memory.js38
-rw-r--r--src/modules/optional/sugar.js240
-rw-r--r--src/modules/optional/transform.js78
-rw-r--r--src/svg.js8
-rw-r--r--src/types/ArrayPolyfill.js34
-rw-r--r--src/types/Box.js152
-rw-r--r--src/types/EventTarget.js50
-rw-r--r--src/types/List.js58
-rw-r--r--src/types/Matrix.js382
-rw-r--r--src/types/Morphable.js232
-rw-r--r--src/types/PathArray.js338
-rw-r--r--src/types/Point.js36
-rw-r--r--src/types/PointArray.js104
-rw-r--r--src/types/SVGArray.js48
-rw-r--r--src/types/SVGNumber.js94
-rw-r--r--src/utils/adopter.js156
-rw-r--r--src/utils/methods.js50
-rw-r--r--src/utils/utils.js98
-rw-r--r--src/utils/window.js4
72 files changed, 4684 insertions, 2107 deletions
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index e3578aa..0000000
--- a/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "standard"
-}
diff --git a/.eslintrc.yaml b/.eslintrc.yaml
new file mode 100644
index 0000000..6243075
--- /dev/null
+++ b/.eslintrc.yaml
@@ -0,0 +1,10 @@
+
+extends: standard
+rules:
+ operator-linebreak: [ error, before ]
+ object-curly-spacing: [ error, always ]
+ indent: [ error, 2, {
+ flatTernaryExpressions: true
+ }]
+ padded-blocks: off
+ space-in-parens: [ error, always ]
diff --git a/dist/svg.js b/dist/svg.js
index 7b311f9..2072971 100644
--- a/dist/svg.js
+++ b/dist/svg.js
@@ -6,7 +6,7 @@
* @copyright Wout Fierens <wout@mick-wout.com>
* @license MIT
*
-* BUILT: Mon Nov 19 2018 21:40:15 GMT+0100 (GMT+01:00)
+* BUILT: Sun Nov 25 2018 16:17:19 GMT+1300 (New Zealand Daylight Time)
*/;
var SVG = (function () {
'use strict';
@@ -112,6 +112,36 @@ var SVG = (function () {
return _setPrototypeOf(o, p);
}
+ function isNativeReflectConstruct() {
+ if (typeof Reflect === "undefined" || !Reflect.construct) return false;
+ if (Reflect.construct.sham) return false;
+ if (typeof Proxy === "function") return true;
+
+ try {
+ Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ function _construct(Parent, args, Class) {
+ if (isNativeReflectConstruct()) {
+ _construct = Reflect.construct;
+ } else {
+ _construct = function _construct(Parent, args, Class) {
+ var a = [null];
+ a.push.apply(a, args);
+ var Constructor = Function.bind.apply(Parent, a);
+ var instance = new Constructor();
+ if (Class) _setPrototypeOf(instance, Class.prototype);
+ return instance;
+ };
+ }
+
+ return _construct.apply(null, arguments);
+ }
+
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
@@ -974,99 +1004,599 @@ var SVG = (function () {
return event;
}
- function fullHex(hex$$1) {
+ function sixDigitHex(hex$$1) {
return hex$$1.length === 4 ? ['#', hex$$1.substring(1, 2), hex$$1.substring(1, 2), hex$$1.substring(2, 3), hex$$1.substring(2, 3), hex$$1.substring(3, 4), hex$$1.substring(3, 4)].join('') : hex$$1;
- } // Component to hex value
-
+ }
- function compToHex(comp) {
- var hex$$1 = comp.toString(16);
+ function componentHex(component) {
+ var integer = Math.round(component);
+ var hex$$1 = integer.toString(16);
return hex$$1.length === 1 ? '0' + hex$$1 : hex$$1;
}
+ function is(object, space) {
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = space[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var key = _step.value;
+
+ if (object[key] == null) {
+ return false;
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function getParameters(a) {
+ var params = is(a, 'rgb') ? {
+ _a: a.r,
+ _b: a.g,
+ _c: a.b,
+ space: 'rgb'
+ } : is(a, 'xyz') ? {
+ _a: a.x,
+ _b: a.y,
+ _c: a.z,
+ space: 'xyz'
+ } : is(a, 'hsl') ? {
+ _a: a.h,
+ _b: a.s,
+ _c: a.l,
+ space: 'hsl'
+ } : is(a, 'lab') ? {
+ _a: a.l,
+ _b: a.a,
+ _c: a.b,
+ space: 'lab'
+ } : is(a, 'lch') ? {
+ _a: a.l,
+ _b: a.c,
+ _c: a.h,
+ space: 'lch'
+ } : is(a, 'cmyk') ? {
+ _a: a.c,
+ _b: a.m,
+ _c: a.y,
+ _d: a.k,
+ space: 'cmyk'
+ } : {
+ _a: 0,
+ _b: 0,
+ _c: 0,
+ space: 'rgb'
+ };
+ return params;
+ }
+
+ function cieSpace(space) {
+ if (space === 'lab' || space === 'xyz' || space === 'lch') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function hueToRgb(p, q, t) {
+ if (t < 0) t += 1;
+ if (t > 1) t -= 1;
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
+ if (t < 1 / 2) return q;
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
+ return p;
+ }
+
var Color =
/*#__PURE__*/
function () {
function Color() {
+ var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
+ var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+ var c = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+ var d = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+ var space = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'rgb';
+
_classCallCheck(this, Color);
- this.init.apply(this, arguments);
+ // If the user gave us an array, make the color from it
+ if (typeof a === 'number') {
+ // Allow for the case that we don't need d...
+ space = typeof d === 'string' ? d : space;
+ d = typeof d === 'string' ? undefined : d; // Assign the values straight to the color
+
+ Object.assign(this, {
+ _a: a,
+ _b: b,
+ _c: c,
+ _d: d,
+ space: space
+ });
+ } else if (a instanceof Array) {
+ this.space = b || 'rgb';
+ Object.assign(this, {
+ _a: a[0],
+ _b: a[1],
+ _c: a[2],
+ _d: a[3]
+ });
+ } else if (a instanceof Object) {
+ // Set the object up and assign its values directly
+ var values = getParameters(a);
+ Object.assign(this, values);
+ } else if (typeof a === 'string') {
+ if (isRgb.test(a)) {
+ var noWhitespace = a.replace(whitespace, '');
+
+ var _rgb$exec$slice$map = rgb.exec(noWhitespace).slice(1, 4).map(function (v) {
+ return parseInt(v);
+ }),
+ _rgb$exec$slice$map2 = _slicedToArray(_rgb$exec$slice$map, 3),
+ _a2 = _rgb$exec$slice$map2[0],
+ _b2 = _rgb$exec$slice$map2[1],
+ _c2 = _rgb$exec$slice$map2[2];
+
+ Object.assign(this, {
+ _a: _a2,
+ _b: _b2,
+ _c: _c2,
+ space: 'rgb'
+ });
+ } else if (isHex.test(a)) {
+ var hexParse = function hexParse(v) {
+ return parseInt(v, 16);
+ };
+
+ var _hex$exec$map = hex.exec(sixDigitHex(a)).map(hexParse),
+ _hex$exec$map2 = _slicedToArray(_hex$exec$map, 4),
+ _a3 = _hex$exec$map2[1],
+ _b3 = _hex$exec$map2[2],
+ _c3 = _hex$exec$map2[3];
+
+ Object.assign(this, {
+ _a: _a3,
+ _b: _b3,
+ _c: _c3,
+ space: 'rgb'
+ });
+ } else throw Error("Unsupported string format, can't construct Color");
+ } // Now add the components as a convenience
+
+
+ var _a = this._a,
+ _b = this._b,
+ _c = this._c,
+ _d = this._d;
+ var components = this.space === 'rgb' ? {
+ r: _a,
+ g: _b,
+ b: _c
+ } : this.space === 'xyz' ? {
+ x: _a,
+ y: _b,
+ z: _c
+ } : this.space === 'hsl' ? {
+ h: _a,
+ s: _b,
+ l: _c
+ } : this.space === 'lab' ? {
+ l: _a,
+ a: _b,
+ b: _c
+ } : this.space === 'lch' ? {
+ l: _a,
+ c: _b,
+ h: _c
+ } : this.space === 'cmyk' ? {
+ c: _a,
+ y: _b,
+ m: _c,
+ k: _d
+ } : {};
+ Object.assign(this, components);
}
_createClass(Color, [{
- key: "init",
- value: function init(color, g, b) {
- var match; // initialize defaults
-
- this.r = 0;
- this.g = 0;
- this.b = 0;
- if (!color) return; // parse color
-
- if (typeof color === 'string') {
- if (isRgb.test(color)) {
- // get rgb values
- match = rgb.exec(color.replace(whitespace, '')); // parse numeric values
-
- this.r = parseInt(match[1]);
- this.g = parseInt(match[2]);
- this.b = parseInt(match[3]);
- } else if (isHex.test(color)) {
- // get hex values
- match = hex.exec(fullHex(color)); // parse numeric values
-
- this.r = parseInt(match[1], 16);
- this.g = parseInt(match[2], 16);
- this.b = parseInt(match[3], 16);
- }
- } else if (Array.isArray(color)) {
- this.r = color[0];
- this.g = color[1];
- this.b = color[2];
- } else if (_typeof(color) === 'object') {
- this.r = color.r;
- this.g = color.g;
- this.b = color.b;
- } else if (arguments.length === 3) {
- this.r = color;
- this.g = g;
- this.b = b;
+ key: "opacity",
+ value: function opacity() {
+ var _opacity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
+
+ this.opacity = _opacity;
+ }
+ /*
+ */
+
+ }, {
+ key: "brightness",
+ value: function brightness() {
+ var _this$rgb = this.rgb(),
+ r = _this$rgb._a,
+ g = _this$rgb._b,
+ b = _this$rgb._c;
+
+ var value = r / 255 * 0.30 + g / 255 * 0.59 + b / 255 * 0.11;
+ return value;
+ }
+ /*
+ Conversion Methods
+ */
+
+ }, {
+ key: "rgb",
+ value: function rgb$$1() {
+ if (this.space === 'rgb') {
+ return this;
+ } else if (cieSpace(this.space)) {
+ // Convert to the xyz color space
+ var x = this.x,
+ y = this.y,
+ z = this.z;
+
+ if (this.space === 'lab' || this.space === 'lch') {
+ // Get the values in the lab space
+ var l = this.l,
+ a = this.a,
+ _b4 = this.b;
+
+ if (this.space === 'lch') {
+ var c = this.c,
+ h = this.h;
+ var dToR = Math.PI / 180;
+ a = c * Math.cos(dToR * h);
+ _b4 = c * Math.sin(dToR * h);
+ } // Undo the nonlinear function
+
+
+ var yL = (l + 16) / 116;
+ var xL = a / 500 + y;
+ var zL = y - _b4 / 200; // Get the xyz values
+
+ var ct = 16 / 116;
+ var mx = 0.008856;
+ var nm = 7.787;
+ x = 0.95047 * (Math.pow(xL, 3) > mx ? Math.pow(xL, 3) : (xL - ct) / nm);
+ y = 1.00000 * (Math.pow(yL, 3) > mx ? Math.pow(yL, 3) : (yL - ct) / nm);
+ z = 1.08883 * (Math.pow(zL, 3) > mx ? Math.pow(zL, 3) : (zL - ct) / nm);
+ } // Convert xyz to unbounded rgb values
+
+
+ var rU = x * 3.2406 + y * -1.5372 + z * -0.4986;
+ var gU = x * -0.9689 + y * 1.8758 + z * 0.0415;
+ var bU = x * 0.0557 + y * -0.2040 + z * 1.0570; // Convert the values to true rgb values
+
+ var pow = Math.pow;
+ var bd = 0.0031308;
+ var r = rU > bd ? 1.055 * pow(rU, 1 / 2.4) - 0.055 : 12.92 * rU;
+ var g = gU > bd ? 1.055 * pow(gU, 1 / 2.4) - 0.055 : 12.92 * gU;
+ var b = bU > bd ? 1.055 * pow(bU, 1 / 2.4) - 0.055 : 12.92 * bU; // Make and return the color
+
+ var color = new Color(r, g, b);
+ return color;
+ } else if (this.space === 'hsl') {
+ // stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
+ // Get the current hsl values
+ var _h = this.h,
+ s = this.s,
+ _l = this.l; // If we are grey, then just make the color directly
+
+ if (s === 0) {
+ var _color2 = new Color(_l, _l, _l);
+
+ return _color2;
+ } // TODO I have no idea what this does :D If you figure it out, tell me!
+
+
+ var q = _l < 0.5 ? _l * (1 + s) : _l + s - _l * s;
+ var p = 2 * _l - q; // Get the rgb values
+
+ var _r = hueToRgb(p, q, _h + 1 / 3);
+
+ var _g = hueToRgb(p, q, _h);
+
+ var _b5 = hueToRgb(p, q, _h - 1 / 3); // Make a new color
+
+
+ var _color = new Color(_r, _g, _b5);
+
+ return _color;
+ } else if (this.space === 'cmyk') {
+ // https://gist.github.com/felipesabino/5066336
+ // Get the normalised cmyk values
+ var _a = this._a,
+ _b = this._b,
+ _c = this._c,
+ _d = this._d;
+
+ var _map = [_a, _b, _c, _d].map(function (v) {
+ return v / 100;
+ }),
+ _map2 = _slicedToArray(_map, 4),
+ _c4 = _map2[0],
+ m = _map2[1],
+ _y = _map2[2],
+ k = _map2[3]; // Get the rgb values
+
+
+ var _r2 = 1 - Math.min(1, _c4 * (1 - k) + k);
+
+ var _g2 = 1 - Math.min(1, m * (1 - k) + k);
+
+ var _b6 = 1 - Math.min(1, _y * (1 - k) + k); // Form the color and return it
+
+
+ var _color3 = new Color(_r2, _g2, _b6);
+
+ return _color3;
+ } else {
+ return this;
}
+ }
+ }, {
+ key: "lab",
+ value: function lab() {
+ // Get the xyz color
+ var _this$xyz = this.xyz(),
+ x = _this$xyz.x,
+ y = _this$xyz.y,
+ z = _this$xyz.z; // Get the lab components
- return this;
- } // Default to hex conversion
+ var l = 116 * y - 16;
+ var a = 500 * (x - y);
+ var b = 200 * (y - z); // Construct and return a new color
+
+ var color = new Color(l, a, b, 'lab');
+ return color;
+ }
+ }, {
+ key: "xyz",
+ value: function xyz() {
+ // Normalise the red, green and blue values
+ var _this$rgb2 = this.rgb(),
+ r255 = _this$rgb2._a,
+ g255 = _this$rgb2._b,
+ b255 = _this$rgb2._c;
+
+ var _map3 = [r255, g255, b255].map(function (v) {
+ return v / 255;
+ }),
+ _map4 = _slicedToArray(_map3, 3),
+ r = _map4[0],
+ g = _map4[1],
+ b = _map4[2]; // Convert to the lab rgb space
+
+
+ var rL = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
+ var gL = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
+ var bL = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; // Convert to the xyz color space without bounding the values
+
+ var xU = (rL * 0.4124 + gL * 0.3576 + bL * 0.1805) / 0.95047;
+ var yU = (rL * 0.2126 + gL * 0.7152 + bL * 0.0722) / 1.00000;
+ var zU = (rL * 0.0193 + gL * 0.1192 + bL * 0.9505) / 1.08883; // Get the proper xyz values by applying the bounding
+
+ var x = xU > 0.008856 ? Math.pow(xU, 1 / 3) : 7.787 * xU + 16 / 116;
+ var y = yU > 0.008856 ? Math.pow(yU, 1 / 3) : 7.787 * yU + 16 / 116;
+ var z = zU > 0.008856 ? Math.pow(zU, 1 / 3) : 7.787 * zU + 16 / 116; // Make and return the color
+
+ var color = new Color(x, y, z, 'xyz');
+ return color;
+ }
+ }, {
+ key: "lch",
+ value: function lch() {
+ // Get the lab color directly
+ var _this$lab = this.lab(),
+ l = _this$lab.l,
+ a = _this$lab.a,
+ b = _this$lab.b; // Get the chromaticity and the hue using polar coordinates
+
+
+ var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
+ var h = 180 * Math.atan2(b, a) / Math.PI;
+
+ if (h < 0) {
+ h *= -1;
+ h = 360 - h;
+ } // Make a new color and return it
+
+
+ var color = new Color(l, c, h, 'lch');
+ return color;
+ }
+ }, {
+ key: "hsl",
+ value: function hsl() {
+ // Get the rgb values
+ var _this$rgb3 = this.rgb(),
+ _a = _this$rgb3._a,
+ _b = _this$rgb3._b,
+ _c = _this$rgb3._c;
+
+ var _map5 = [_a, _b, _c].map(function (v) {
+ return v / 255;
+ }),
+ _map6 = _slicedToArray(_map5, 3),
+ r = _map6[0],
+ g = _map6[1],
+ b = _map6[2]; // Find the maximum and minimum values to get the lightness
+
+
+ var max = Math.max(r, g, b);
+ var min = Math.min(r, g, b);
+ var l = (max + min) / 2; // If the r, g, v values are identical then we are grey
+
+ var isGrey = max === min; // Calculate the hue and saturation
+
+ var delta = max - min;
+ var s = isGrey ? 0 : l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
+ var h = isGrey ? 0 : max === r ? ((g - b) / delta + (g < b ? 6 : 0)) / 6 : max === g ? ((b - r) / delta + 2) / 6 : max === b ? ((r - g) / delta + 4) / 6 : 0; // Construct and return the new color
+
+ var color = new Color(h, s, l, 'hsl');
+ return color;
+ }
+ }, {
+ key: "cmyk",
+ value: function cmyk() {
+ // Get the rgb values for the current color
+ var _this$rgb4 = this.rgb(),
+ _a = _this$rgb4._a,
+ _b = _this$rgb4._b,
+ _c = _this$rgb4._c;
+
+ var _map7 = [_a, _b, _c].map(function (v) {
+ return v / 255;
+ }),
+ _map8 = _slicedToArray(_map7, 3),
+ r = _map8[0],
+ g = _map8[1],
+ b = _map8[2]; // Get the cmyk values in an unbounded format
+
+
+ var k = 100 * Math.min(1 - r, 1 - g, 1 - b);
+ var c = 100 * (1 - r - k) / (1 - k);
+ var m = 100 * (1 - g - k) / (1 - k);
+ var y = 100 * (1 - b - k) / (1 - k); // Construct the new color
+
+ var color = new Color(c, m, y, k, 'cmyk');
+ return color;
+ }
+ /*
+ Modifying the color
+ */
+
+ }, {
+ key: "brighten",
+ value: function brighten() {
+ }
+ }, {
+ key: "darken",
+ value: function darken() {
+ }
+ /*
+ Mixing methods
+ */
+
+ }, {
+ key: "to",
+ value: function to(otherColor, space) {
+ // Force both colors to the color of this space (or let the user decide)
+ space = space || this.space; // Get the starting and ending colors
+ // let start = this[ space ]()
+ // let end = otherColor[ space ]()
+ // Return a function that blends between the two colors
+
+ return function (t) {};
+ }
+ }, {
+ key: "avearge",
+ value: function avearge(otherColor, space) {}
+ /*
+ Input and Output methods
+ */
+
+ }, {
+ key: "hex",
+ value: function hex$$1() {
+ var _this$rgb5 = this.rgb(),
+ _a = _this$rgb5._a,
+ _b = _this$rgb5._b,
+ _c = _this$rgb5._c;
+
+ var _map9 = [_a, _b, _c].map(componentHex),
+ _map10 = _slicedToArray(_map9, 3),
+ r = _map10[0],
+ g = _map10[1],
+ b = _map10[2];
+
+ return "#".concat(r).concat(g).concat(b);
+ }
}, {
key: "toString",
value: function toString() {
- return this.toHex();
+ return this.hex();
+ }
+ }, {
+ key: "toRgb",
+ value: function toRgb() {
+ var _this$rgb6 = this.rgb(),
+ r = _this$rgb6.r,
+ g = _this$rgb6.g,
+ b = _this$rgb6.b;
+
+ var max = Math.max,
+ min = Math.min,
+ round = Math.round;
+
+ var format = function format(v) {
+ return max(0, min(round(v), 255));
+ };
+
+ var _map11 = [r, g, b].map(format),
+ _map12 = _slicedToArray(_map11, 3),
+ rV = _map12[0],
+ gV = _map12[1],
+ bV = _map12[2];
+
+ var string = "rgb(".concat(rV, ",").concat(gV, ",").concat(bV, ")");
+ return string;
}
}, {
key: "toArray",
value: function toArray() {
- return [this.r, this.g, this.b];
- } // Build hex value
+ var _a = this._a,
+ _b = this._b,
+ _c = this._c,
+ _d = this._d,
+ space = this.space;
+ return [_a, _b, _c, _d, space];
+ }
+ }], [{
+ key: "fromArray",
+ value: function fromArray(array) {
+ var newColor = _construct(Color, _toConsumableArray(array));
- }, {
- key: "toHex",
- value: function toHex() {
- return '#' + compToHex(Math.round(this.r)) + compToHex(Math.round(this.g)) + compToHex(Math.round(this.b));
- } // Build rgb value
+ return newColor;
+ }
+ /*
+ Generating random colors
+ */
}, {
- key: "toRgb",
- value: function toRgb() {
- return 'rgb(' + [this.r, this.g, this.b].join() + ')';
- } // Calculate true brightness
+ key: "random",
+ value: function random() {
+ 'sine';
+ 'pastel';
+ 'vibrant';
+ 'dark';
+ 'rgb';
+ 'lab';
+ 'grey';
+ }
+ /*
+ Constructing colors
+ */
}, {
- key: "brightness",
- value: function brightness() {
- return this.r / 255 * 0.30 + this.g / 255 * 0.59 + this.b / 255 * 0.11;
- } // Testers
- // Test if given value is a color string
+ key: "temperature",
+ value: function temperature(kelvin) {} // Test if given value is a color string
- }], [{
+ }, {
key: "test",
value: function test(color) {
color += '';
diff --git a/package-lock.json b/package-lock.json
index 3ba3ab7..c5f923e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5268,7 +5268,7 @@
},
"media-typer": {
"version": "0.3.0",
- "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
diff --git a/src/animation/Animator.js b/src/animation/Animator.js
index 9b460f5..e9d5797 100644
--- a/src/animation/Animator.js
+++ b/src/animation/Animator.js
@@ -8,78 +8,106 @@ const Animator = {
timer: globals.window.performance || globals.window.Date,
transforms: [],
- frame (fn) {
+ frame ( fn ) {
+
// Store the node
- var node = Animator.frames.push({ run: fn })
+ var node = Animator.frames.push( { run: fn } )
// Request an animation frame if we don't have one
- if (Animator.nextDraw === null) {
- Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw)
+ if ( Animator.nextDraw === null ) {
+
+ Animator.nextDraw = globals.window.requestAnimationFrame( Animator._draw )
+
}
// Return the node so we can remove it easily
return node
+
},
- transform_frame (fn, id) {
+ transform_frame ( fn, id ) {
+
Animator.transforms[id] = fn
+
},
- timeout (fn, delay) {
+ timeout ( fn, delay ) {
+
delay = delay || 0
// Work out when the event should fire
var time = Animator.timer.now() + delay
// Add the timeout to the end of the queue
- var node = Animator.timeouts.push({ run: fn, time: time })
+ var node = Animator.timeouts.push( { run: fn, time: time } )
// Request another animation frame if we need one
- if (Animator.nextDraw === null) {
- Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw)
+ if ( Animator.nextDraw === null ) {
+
+ Animator.nextDraw = globals.window.requestAnimationFrame( Animator._draw )
+
}
return node
+
},
- cancelFrame (node) {
- Animator.frames.remove(node)
+ cancelFrame ( node ) {
+
+ Animator.frames.remove( node )
+
},
- clearTimeout (node) {
- Animator.timeouts.remove(node)
+ clearTimeout ( node ) {
+
+ Animator.timeouts.remove( node )
+
},
- _draw (now) {
+ _draw ( now ) {
+
// Run all the timeouts we can run, if they are not ready yet, add them
// to the end of the queue immediately! (bad timeouts!!! [sarcasm])
var nextTimeout = null
var lastTimeout = Animator.timeouts.last()
- while ((nextTimeout = Animator.timeouts.shift())) {
+ while ( ( nextTimeout = Animator.timeouts.shift() ) ) {
+
// Run the timeout if its time, or push it to the end
- if (now >= nextTimeout.time) {
+ if ( now >= nextTimeout.time ) {
+
nextTimeout.run()
+
} else {
- Animator.timeouts.push(nextTimeout)
+
+ Animator.timeouts.push( nextTimeout )
+
}
// If we hit the last item, we should stop shifting out more items
- if (nextTimeout === lastTimeout) break
+ if ( nextTimeout === lastTimeout ) break
+
}
// Run all of the animation frames
var nextFrame = null
var lastFrame = Animator.frames.last()
- while ((nextFrame !== lastFrame) && (nextFrame = Animator.frames.shift())) {
+ while ( ( nextFrame !== lastFrame ) && ( nextFrame = Animator.frames.shift() ) ) {
+
nextFrame.run()
+
}
- Animator.transforms.forEach(function (el) { el() })
+ Animator.transforms.forEach( function ( el ) {
+
+ el()
+
+ } )
// If we have remaining timeouts or frames, draw until we don't anymore
Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first()
- ? globals.window.requestAnimationFrame(Animator._draw)
+ ? globals.window.requestAnimationFrame( Animator._draw )
: null
+
}
}
diff --git a/src/animation/Controller.js b/src/animation/Controller.js
index cee7115..9efe87e 100644
--- a/src/animation/Controller.js
+++ b/src/animation/Controller.js
@@ -7,85 +7,149 @@ Base Class
The base stepper class that will be
***/
-function makeSetterGetter (k, f) {
- return function (v) {
- if (v == null) return this[v]
+function makeSetterGetter ( k, f ) {
+
+ return function ( v ) {
+
+ if ( v == null ) return this[v]
this[k] = v
- if (f) f.call(this)
+ if ( f ) f.call( this )
return this
+
}
+
}
export let easing = {
- '-': function (pos) { return pos },
- '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
- '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
- '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 },
- bezier: function (x1, y1, x2, y2) {
+ '-': function ( pos ) {
+
+ return pos
+
+ },
+ '<>': function ( pos ) {
+
+ return -Math.cos( pos * Math.PI ) / 2 + 0.5
+
+ },
+ '>': function ( pos ) {
+
+ return Math.sin( pos * Math.PI / 2 )
+
+ },
+ '<': function ( pos ) {
+
+ return -Math.cos( pos * Math.PI / 2 ) + 1
+
+ },
+ bezier: function ( x1, y1, x2, y2 ) {
+
// see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo
- return function (t) {
- if (t < 0) {
- if (x1 > 0) {
+ return function ( t ) {
+
+ if ( t < 0 ) {
+
+ if ( x1 > 0 ) {
+
return y1 / x1 * t
- } else if (x2 > 0) {
+
+ } else if ( x2 > 0 ) {
+
return y2 / x2 * t
+
} else {
+
return 0
+
}
- } else if (t > 1) {
- if (x2 < 1) {
- return (1 - y2) / (1 - x2) * t + (y2 - x2) / (1 - x2)
- } else if (x1 < 1) {
- return (1 - y1) / (1 - x1) * t + (y1 - x1) / (1 - x1)
+
+ } else if ( t > 1 ) {
+
+ if ( x2 < 1 ) {
+
+ return ( 1 - y2 ) / ( 1 - x2 ) * t + ( y2 - x2 ) / ( 1 - x2 )
+
+ } else if ( x1 < 1 ) {
+
+ return ( 1 - y1 ) / ( 1 - x1 ) * t + ( y1 - x1 ) / ( 1 - x1 )
+
} else {
+
return 1
+
}
+
} else {
- return 3 * t * (1 - t) ** 2 * y1 + 3 * t ** 2 * (1 - t) * y2 + t ** 3
+
+ return 3 * t * ( 1 - t ) ** 2 * y1 + 3 * t ** 2 * ( 1 - t ) * y2 + t ** 3
+
}
+
}
+
},
// see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo
- steps: function (steps, stepPosition = 'end') {
+ steps: function ( steps, stepPosition = 'end' ) {
+
// deal with "jump-" prefix
- stepPosition = stepPosition.split('-').reverse()[0]
+ stepPosition = stepPosition.split( '-' ).reverse()[0]
let jumps = steps
- if (stepPosition === 'none') {
+ if ( stepPosition === 'none' ) {
+
--jumps
- } else if (stepPosition === 'both') {
+
+ } else if ( stepPosition === 'both' ) {
+
++jumps
+
}
// The beforeFlag is essentially useless
- return (t, beforeFlag = false) => {
+ return ( t, beforeFlag = false ) => {
+
// Step is called currentStep in referenced url
- let step = Math.floor(t * steps)
- const jumping = (t * step) % 1 === 0
+ let step = Math.floor( t * steps )
+ const jumping = ( t * step ) % 1 === 0
+
+ if ( stepPosition === 'start' || stepPosition === 'both' ) {
- if (stepPosition === 'start' || stepPosition === 'both') {
++step
+
}
- if (beforeFlag && jumping) {
+ if ( beforeFlag && jumping ) {
+
--step
+
}
- if (t >= 0 && step < 0) {
+ if ( t >= 0 && step < 0 ) {
+
step = 0
+
}
- if (t <= 1 && step > jumps) {
+ if ( t <= 1 && step > jumps ) {
+
step = jumps
+
}
return step / jumps
+
}
+
}
}
export class Stepper {
- done () { return false }
+
+ done () {
+
+ return false
+
+ }
+
}
/***
@@ -94,17 +158,25 @@ Easing Functions
***/
export class Ease extends Stepper {
- constructor (fn) {
+
+ constructor ( fn ) {
+
super()
this.ease = easing[fn || timeline.ease] || fn
+
}
- step (from, to, pos) {
- if (typeof from !== 'number') {
+ step ( from, to, pos ) {
+
+ if ( typeof from !== 'number' ) {
+
return pos < 1 ? from : to
+
}
- return from + (to - from) * this.ease(pos)
+ return from + ( to - from ) * this.ease( pos )
+
}
+
}
/***
@@ -113,51 +185,65 @@ Controller Types
***/
export class Controller extends Stepper {
- constructor (fn) {
+
+ constructor ( fn ) {
+
super()
this.stepper = fn
+
}
- step (current, target, dt, c) {
- return this.stepper(current, target, dt, c)
+ step ( current, target, dt, c ) {
+
+ return this.stepper( current, target, dt, c )
+
}
- done (c) {
+ done ( c ) {
+
return c.done
+
}
+
}
function recalculate () {
+
// Apply the default parameters
- var duration = (this._duration || 500) / 1000
+ var duration = ( this._duration || 500 ) / 1000
var overshoot = this._overshoot || 0
// Calculate the PID natural response
var eps = 1e-10
var pi = Math.PI
- var os = Math.log(overshoot / 100 + eps)
- var zeta = -os / Math.sqrt(pi * pi + os * os)
- var wn = 3.9 / (zeta * duration)
+ var os = Math.log( overshoot / 100 + eps )
+ var zeta = -os / Math.sqrt( pi * pi + os * os )
+ var wn = 3.9 / ( zeta * duration )
// Calculate the Spring values
this.d = 2 * zeta * wn
this.k = wn * wn
+
}
export class Spring extends Controller {
- constructor (duration, overshoot) {
+
+ constructor ( duration, overshoot ) {
+
super()
- this.duration(duration || 500)
- .overshoot(overshoot || 0)
+ this.duration( duration || 500 )
+ .overshoot( overshoot || 0 )
+
}
- step (current, target, dt, c) {
- if (typeof current === 'string') return current
+ step ( current, target, dt, c ) {
+
+ if ( typeof current === 'string' ) return current
c.done = dt === Infinity
- if (dt === Infinity) return target
- if (dt === 0) return current
+ if ( dt === Infinity ) return target
+ if ( dt === 0 ) return current
- if (dt > 100) dt = 16
+ if ( dt > 100 ) dt = 16
dt /= 1000
@@ -165,65 +251,75 @@ export class Spring extends Controller {
var velocity = c.velocity || 0
// Apply the control to get the new position and store it
- var acceleration = -this.d * velocity - this.k * (current - target)
- var newPosition = current +
- velocity * dt +
- acceleration * dt * dt / 2
+ var acceleration = -this.d * velocity - this.k * ( current - target )
+ var newPosition = current
+ + velocity * dt
+ + acceleration * dt * dt / 2
// Store the velocity
c.velocity = velocity + acceleration * dt
// Figure out if we have converged, and if so, pass the value
- c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002
+ c.done = Math.abs( target - newPosition ) + Math.abs( velocity ) < 0.002
return c.done ? target : newPosition
+
}
+
}
-extend(Spring, {
- duration: makeSetterGetter('_duration', recalculate),
- overshoot: makeSetterGetter('_overshoot', recalculate)
-})
+extend( Spring, {
+ duration: makeSetterGetter( '_duration', recalculate ),
+ overshoot: makeSetterGetter( '_overshoot', recalculate )
+} )
export class PID extends Controller {
- constructor (p, i, d, windup) {
+
+ constructor ( p, i, d, windup ) {
+
super()
p = p == null ? 0.1 : p
i = i == null ? 0.01 : i
d = d == null ? 0 : d
windup = windup == null ? 1000 : windup
- this.p(p).i(i).d(d).windup(windup)
+ this.p( p ).i( i ).d( d ).windup( windup )
+
}
- step (current, target, dt, c) {
- if (typeof current === 'string') return current
+ step ( current, target, dt, c ) {
+
+ if ( typeof current === 'string' ) return current
c.done = dt === Infinity
- if (dt === Infinity) return target
- if (dt === 0) return current
+ if ( dt === Infinity ) return target
+ if ( dt === 0 ) return current
var p = target - current
- var i = (c.integral || 0) + p * dt
- var d = (p - (c.error || 0)) / dt
+ var i = ( c.integral || 0 ) + p * dt
+ var d = ( p - ( c.error || 0 ) ) / dt
var windup = this.windup
// antiwindup
- if (windup !== false) {
- i = Math.max(-windup, Math.min(i, windup))
+ if ( windup !== false ) {
+
+ i = Math.max( -windup, Math.min( i, windup ) )
+
}
c.error = p
c.integral = i
- c.done = Math.abs(p) < 0.001
+ c.done = Math.abs( p ) < 0.001
+
+ return c.done ? target : current + ( this.P * p + this.I * i + this.D * d )
- return c.done ? target : current + (this.P * p + this.I * i + this.D * d)
}
+
}
-extend(PID, {
- windup: makeSetterGetter('windup'),
- p: makeSetterGetter('P'),
- i: makeSetterGetter('I'),
- d: makeSetterGetter('D')
-})
+extend( PID, {
+ windup: makeSetterGetter( 'windup' ),
+ p: makeSetterGetter( 'P' ),
+ i: makeSetterGetter( 'I' ),
+ d: makeSetterGetter( 'D' )
+} )
diff --git a/src/animation/Queue.js b/src/animation/Queue.js
index 14b92b4..b4e2722 100644
--- a/src/animation/Queue.js
+++ b/src/animation/Queue.js
@@ -1,59 +1,77 @@
export default class Queue {
+
constructor () {
+
this._first = null
this._last = null
+
}
- push (value) {
+ push ( value ) {
+
// An item stores an id and the provided value
var item = value.next ? value : { value: value, next: null, prev: null }
// Deal with the queue being empty or populated
- if (this._last) {
+ if ( this._last ) {
+
item.prev = this._last
this._last.next = item
this._last = item
+
} else {
+
this._last = item
this._first = item
+
}
// Update the length and return the current item
return item
+
}
shift () {
+
// Check if we have a value
var remove = this._first
- if (!remove) return null
+ if ( !remove ) return null
// If we do, remove it and relink things
this._first = remove.next
- if (this._first) this._first.prev = null
+ if ( this._first ) this._first.prev = null
this._last = this._first ? this._last : null
return remove.value
+
}
// Shows us the first item in the list
first () {
+
return this._first && this._first.value
+
}
// Shows us the last item in the list
last () {
+
return this._last && this._last.value
+
}
// Removes the item that was returned from the push
- remove (item) {
+ remove ( item ) {
+
// Relink the previous item
- if (item.prev) item.prev.next = item.next
- if (item.next) item.next.prev = item.prev
- if (item === this._last) this._last = item.prev
- if (item === this._first) this._first = item.next
+ if ( item.prev ) item.prev.next = item.next
+ if ( item.next ) item.next.prev = item.prev
+ if ( item === this._last ) this._last = item.prev
+ if ( item === this._first ) this._first = item.next
// Invalidate item
item.prev = null
item.next = null
+
}
+
}
diff --git a/src/animation/Runner.js b/src/animation/Runner.js
index 47929fd..d2c7bdf 100644
--- a/src/animation/Runner.js
+++ b/src/animation/Runner.js
@@ -15,7 +15,9 @@ import SVGNumber from '../types/SVGNumber.js'
import Timeline from './Timeline.js'
export default class Runner extends EventTarget {
- constructor (options) {
+
+ constructor ( options ) {
+
super()
// Store a unique id on the runner, so that we can identify it later
@@ -28,7 +30,7 @@ export default class Runner extends EventTarget {
// Ensure that we get a controller
options = typeof options === 'function'
- ? new Controller(options)
+ ? new Controller( options )
: options
// Declare all of the variables
@@ -61,6 +63,7 @@ export default class Runner extends EventTarget {
this._swing = false
this._wait = 0
this._times = 1
+
}
/*
@@ -70,58 +73,75 @@ export default class Runner extends EventTarget {
help us make new runners from the current runner
*/
- element (element) {
- if (element == null) return this._element
+ element ( element ) {
+
+ if ( element == null ) return this._element
this._element = element
element._prepareRunner()
return this
+
}
- timeline (timeline) {
+ timeline ( timeline ) {
+
// check explicitly for undefined so we can set the timeline to null
- if (typeof timeline === 'undefined') return this._timeline
+ if ( typeof timeline === 'undefined' ) return this._timeline
this._timeline = timeline
return this
+
}
- animate (duration, delay, when) {
- var o = Runner.sanitise(duration, delay, when)
- var runner = new Runner(o.duration)
- if (this._timeline) runner.timeline(this._timeline)
- if (this._element) runner.element(this._element)
- return runner.loop(o).schedule(delay, when)
+ animate ( duration, delay, when ) {
+
+ var o = Runner.sanitise( duration, delay, when )
+ var runner = new Runner( o.duration )
+ if ( this._timeline ) runner.timeline( this._timeline )
+ if ( this._element ) runner.element( this._element )
+ return runner.loop( o ).schedule( delay, when )
+
}
- schedule (timeline, delay, when) {
+ schedule ( timeline, delay, when ) {
+
// The user doesn't need to pass a timeline if we already have one
- if (!(timeline instanceof Timeline)) {
+ if ( !( timeline instanceof Timeline ) ) {
+
when = delay
delay = timeline
timeline = this.timeline()
+
}
// If there is no timeline, yell at the user...
- if (!timeline) {
- throw Error('Runner cannot be scheduled without timeline')
+ if ( !timeline ) {
+
+ throw Error( 'Runner cannot be scheduled without timeline' )
+
}
// Schedule the runner on the timeline provided
- timeline.schedule(this, delay, when)
+ timeline.schedule( this, delay, when )
return this
+
}
unschedule () {
+
var timeline = this.timeline()
- timeline && timeline.unschedule(this)
+ timeline && timeline.unschedule( this )
return this
+
}
- loop (times, swing, wait) {
+ loop ( times, swing, wait ) {
+
// Deal with the user passing in an object
- if (typeof times === 'object') {
+ if ( typeof times === 'object' ) {
+
swing = times.swing
wait = times.wait
times = times.times
+
}
// Sanitise the values and store them
@@ -129,10 +149,13 @@ export default class Runner extends EventTarget {
this._swing = swing || false
this._wait = wait || 0
return this
+
}
- delay (delay) {
- return this.animate(0, delay)
+ delay ( delay ) {
+
+ return this.animate( 0, delay )
+
}
/*
@@ -141,26 +164,32 @@ export default class Runner extends EventTarget {
These methods allow us to attach basic functions to the runner directly
*/
- queue (initFn, runFn, retargetFn, isTransform) {
- this._queue.push({
+ queue ( initFn, runFn, retargetFn, isTransform ) {
+
+ this._queue.push( {
initialiser: initFn || noop,
runner: runFn || noop,
retarget: retargetFn,
isTransform: isTransform,
initialised: false,
finished: false
- })
+ } )
var timeline = this.timeline()
timeline && this.timeline()._continue()
return this
+
}
- during (fn) {
- return this.queue(null, fn)
+ during ( fn ) {
+
+ return this.queue( null, fn )
+
}
- after (fn) {
- return this.on('finish', fn)
+ after ( fn ) {
+
+ return this.on( 'finish', fn )
+
}
/*
@@ -169,34 +198,45 @@ export default class Runner extends EventTarget {
Control how the animation plays
*/
- time (time) {
- if (time == null) {
+ time ( time ) {
+
+ if ( time == null ) {
+
return this._time
+
}
let dt = time - this._time
- this.step(dt)
+ this.step( dt )
return this
+
}
duration () {
- return this._times * (this._wait + this._duration) - this._wait
+
+ return this._times * ( this._wait + this._duration ) - this._wait
+
}
- loops (p) {
+ loops ( p ) {
+
var loopDuration = this._duration + this._wait
- if (p == null) {
- var loopsDone = Math.floor(this._time / loopDuration)
- var relativeTime = (this._time - loopsDone * loopDuration)
+ if ( p == null ) {
+
+ var loopsDone = Math.floor( this._time / loopDuration )
+ var relativeTime = ( this._time - loopsDone * loopDuration )
var position = relativeTime / this._duration
- return Math.min(loopsDone + position, this._times)
+ return Math.min( loopsDone + position, this._times )
+
}
- var whole = Math.floor(p)
+ var whole = Math.floor( p )
var partial = p % 1
var time = loopDuration * whole + this._duration * partial
- return this.time(time)
+ return this.time( time )
+
}
- position (p) {
+ position ( p ) {
+
// Get all of the variables we need
var x = this._time
var d = this._duration
@@ -206,7 +246,8 @@ export default class Runner extends EventTarget {
var r = this._reverse
var position
- if (p == null) {
+ if ( p == null ) {
+
/*
This function converts a time to a position in the range [0, 1]
The full explanation can be found in this desmos demonstration
@@ -215,40 +256,49 @@ export default class Runner extends EventTarget {
*/
// Figure out the value without thinking about the start or end time
- const f = function (x) {
- var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d))
- var backwards = (swinging && !r) || (!swinging && r)
- var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards
- var clipped = Math.max(Math.min(uncliped, 1), 0)
+ const f = function ( x ) {
+
+ var swinging = s * Math.floor( x % ( 2 * ( w + d ) ) / ( w + d ) )
+ var backwards = ( swinging && !r ) || ( !swinging && r )
+ var uncliped = Math.pow( -1, backwards ) * ( x % ( w + d ) ) / d + backwards
+ var clipped = Math.max( Math.min( uncliped, 1 ), 0 )
return clipped
+
}
// Figure out the value by incorporating the start time
- var endTime = t * (w + d) - w
- position = x <= 0 ? Math.round(f(1e-5))
- : x < endTime ? f(x)
- : Math.round(f(endTime - 1e-5))
+ var endTime = t * ( w + d ) - w
+ position = x <= 0 ? Math.round( f( 1e-5 ) )
+ : x < endTime ? f( x )
+ : Math.round( f( endTime - 1e-5 ) )
return position
+
}
// Work out the loops done and add the position to the loops done
- var loopsDone = Math.floor(this.loops())
- var swingForward = s && (loopsDone % 2 === 0)
- var forwards = (swingForward && !r) || (r && swingForward)
- position = loopsDone + (forwards ? p : 1 - p)
- return this.loops(position)
+ var loopsDone = Math.floor( this.loops() )
+ var swingForward = s && ( loopsDone % 2 === 0 )
+ var forwards = ( swingForward && !r ) || ( r && swingForward )
+ position = loopsDone + ( forwards ? p : 1 - p )
+ return this.loops( position )
+
}
- progress (p) {
- if (p == null) {
- return Math.min(1, this._time / this.duration())
+ progress ( p ) {
+
+ if ( p == null ) {
+
+ return Math.min( 1, this._time / this.duration() )
+
}
- return this.time(p * this.duration())
+ return this.time( p * this.duration() )
+
}
- step (dt) {
+ step ( dt ) {
+
// If we are inactive, this stepper just gets skipped
- if (!this.enabled) return this
+ if ( !this.enabled ) return this
// Update the time and get the new position
dt = dt == null ? 16 : dt
@@ -264,8 +314,10 @@ export default class Runner extends EventTarget {
var justStarted = this._lastTime < 0 && this._time > 0
var justFinished = this._lastTime < this._time && this.time > duration
this._lastTime = this._time
- if (justStarted) {
- this.fire('start', this)
+ if ( justStarted ) {
+
+ this.fire( 'start', this )
+
}
// Work out if the runner is finished set the done flag here so animations
@@ -275,41 +327,54 @@ export default class Runner extends EventTarget {
this.done = !declarative && !justFinished && this._time >= duration
// Call initialise and the run function
- if (running || declarative) {
- this._initialise(running)
+ if ( running || declarative ) {
+
+ this._initialise( running )
// clear the transforms on this runner so they dont get added again and again
this.transforms = new Matrix()
- var converged = this._run(declarative ? dt : position)
- this.fire('step', this)
+ var converged = this._run( declarative ? dt : position )
+ this.fire( 'step', this )
+
}
// correct the done flag here
// declaritive animations itself know when they converged
- this.done = this.done || (converged && declarative)
- if (this.done) {
- this.fire('finish', this)
+ this.done = this.done || ( converged && declarative )
+ if ( this.done ) {
+
+ this.fire( 'finish', this )
+
}
return this
+
}
finish () {
- return this.step(Infinity)
+
+ return this.step( Infinity )
+
}
- reverse (reverse) {
+ reverse ( reverse ) {
+
this._reverse = reverse == null ? !this._reverse : reverse
return this
+
}
- ease (fn) {
- this._stepper = new Ease(fn)
+ ease ( fn ) {
+
+ this._stepper = new Ease( fn )
return this
+
}
- active (enabled) {
- if (enabled == null) return this.enabled
+ active ( enabled ) {
+
+ if ( enabled == null ) return this.enabled
this.enabled = enabled
return this
+
}
/*
@@ -319,102 +384,135 @@ export default class Runner extends EventTarget {
*/
// Save a morpher to the morpher list so that we can retarget it later
- _rememberMorpher (method, morpher) {
+ _rememberMorpher ( method, morpher ) {
+
this._history[method] = {
morpher: morpher,
caller: this._queue[this._queue.length - 1]
}
+
}
// Try to set the target for a morpher if the morpher exists, otherwise
// do nothing and return false
- _tryRetarget (method, target) {
- if (this._history[method]) {
+ _tryRetarget ( method, target ) {
+
+ if ( this._history[method] ) {
+
// if the last method wasnt even initialised, throw it away
- if (!this._history[method].caller.initialised) {
- let index = this._queue.indexOf(this._history[method].caller)
- this._queue.splice(index, 1)
+ if ( !this._history[method].caller.initialised ) {
+
+ let index = this._queue.indexOf( this._history[method].caller )
+ this._queue.splice( index, 1 )
return false
+
}
// for the case of transformations, we use the special retarget function
// which has access to the outer scope
- if (this._history[method].caller.retarget) {
- this._history[method].caller.retarget(target)
- // for everything else a simple morpher change is sufficient
+ if ( this._history[method].caller.retarget ) {
+
+ this._history[method].caller.retarget( target )
+ // for everything else a simple morpher change is sufficient
+
} else {
- this._history[method].morpher.to(target)
+
+ this._history[method].morpher.to( target )
+
}
this._history[method].caller.finished = false
var timeline = this.timeline()
timeline && timeline._continue()
return true
+
}
return false
+
}
// Run each initialise function in the runner if required
- _initialise (running) {
+ _initialise ( running ) {
+
// If we aren't running, we shouldn't initialise when not declarative
- if (!running && !this._isDeclarative) return
+ if ( !running && !this._isDeclarative ) return
// Loop through all of the initialisers
- for (var i = 0, len = this._queue.length; i < len; ++i) {
+ for ( var i = 0, len = this._queue.length; i < len; ++i ) {
+
// Get the current initialiser
var current = this._queue[i]
// Determine whether we need to initialise
- var needsIt = this._isDeclarative || (!current.initialised && running)
+ var needsIt = this._isDeclarative || ( !current.initialised && running )
running = !current.finished
// Call the initialiser if we need to
- if (needsIt && running) {
- current.initialiser.call(this)
+ if ( needsIt && running ) {
+
+ current.initialiser.call( this )
current.initialised = true
+
}
+
}
+
}
// Run each run function for the position or dt given
- _run (positionOrDt) {
+ _run ( positionOrDt ) {
+
// Run all of the _queue directly
var allfinished = true
- for (var i = 0, len = this._queue.length; i < len; ++i) {
+ for ( var i = 0, len = this._queue.length; i < len; ++i ) {
+
// Get the current function to run
var current = this._queue[i]
// Run the function if its not finished, we keep track of the finished
// flag for the sake of declarative _queue
- var converged = current.runner.call(this, positionOrDt)
- current.finished = current.finished || (converged === true)
+ var converged = current.runner.call( this, positionOrDt )
+ current.finished = current.finished || ( converged === true )
allfinished = allfinished && current.finished
+
}
// We report when all of the constructors are finished
return allfinished
+
}
- addTransform (transform, index) {
- this.transforms.lmultiplyO(transform)
+ addTransform ( transform, index ) {
+
+ this.transforms.lmultiplyO( transform )
return this
+
}
clearTransform () {
+
this.transforms = new Matrix()
return this
+
}
// TODO: Keep track of all transformations so that deletion is faster
clearTransformsFromQueue () {
- if (!this.done) {
- this._queue = this._queue.filter((item) => {
+
+ if ( !this.done ) {
+
+ this._queue = this._queue.filter( ( item ) => {
+
return !item.isTransform
- })
+
+ } )
+
}
+
}
- static sanitise (duration, delay, when) {
+ static sanitise ( duration, delay, when ) {
+
// Initialise the default parameters
var times = 1
var swing = false
@@ -424,13 +522,15 @@ export default class Runner extends EventTarget {
when = when || 'last'
// If we have an object, unpack the values
- if (typeof duration === 'object' && !(duration instanceof Stepper)) {
+ if ( typeof duration === 'object' && !( duration instanceof Stepper ) ) {
+
delay = duration.delay || delay
when = duration.when || when
swing = duration.swing || swing
times = duration.times || times
wait = duration.wait || wait
duration = duration.duration || timeline.duration
+
}
return {
@@ -441,215 +541,285 @@ export default class Runner extends EventTarget {
wait: wait,
when: when
}
+
}
+
}
Runner.id = 0
class FakeRunner {
- constructor (transforms = new Matrix(), id = -1, done = true) {
+
+ constructor ( transforms = new Matrix(), id = -1, done = true ) {
+
this.transforms = transforms
this.id = id
this.done = done
+
}
clearTransformsFromQueue () { }
+
}
-extend([Runner, FakeRunner], {
- mergeWith (runner) {
+extend( [ Runner, FakeRunner ], {
+ mergeWith ( runner ) {
+
return new FakeRunner(
- runner.transforms.lmultiply(this.transforms),
+ runner.transforms.lmultiply( this.transforms ),
runner.id
)
+
}
-})
+} )
// FakeRunner.emptyRunner = new FakeRunner()
-const lmultiply = (last, curr) => last.lmultiplyO(curr)
-const getRunnerTransform = (runner) => runner.transforms
+const lmultiply = ( last, curr ) => last.lmultiplyO( curr )
+const getRunnerTransform = ( runner ) => runner.transforms
function mergeTransforms () {
+
// Find the matrix to apply to the element and apply it
let runners = this._transformationRunners.runners
let netTransform = runners
- .map(getRunnerTransform)
- .reduce(lmultiply, new Matrix())
+ .map( getRunnerTransform )
+ .reduce( lmultiply, new Matrix() )
- this.transform(netTransform)
+ this.transform( netTransform )
this._transformationRunners.merge()
- if (this._transformationRunners.length() === 1) {
+ if ( this._transformationRunners.length() === 1 ) {
+
this._frameId = null
+
}
+
}
class RunnerArray {
+
constructor () {
+
this.runners = []
this.ids = []
+
}
- add (runner) {
- if (this.runners.includes(runner)) return
+ add ( runner ) {
+
+ if ( this.runners.includes( runner ) ) return
let id = runner.id + 1
- let leftSibling = this.ids.reduce((last, curr) => {
- if (curr > last && curr < id) return curr
+ let leftSibling = this.ids.reduce( ( last, curr ) => {
+
+ if ( curr > last && curr < id ) return curr
return last
- }, 0)
- let index = this.ids.indexOf(leftSibling) + 1
+ }, 0 )
- this.ids.splice(index, 0, id)
- this.runners.splice(index, 0, runner)
+ let index = this.ids.indexOf( leftSibling ) + 1
+
+ this.ids.splice( index, 0, id )
+ this.runners.splice( index, 0, runner )
return this
+
}
- getByID (id) {
- return this.runners[this.ids.indexOf(id + 1)]
+ getByID ( id ) {
+
+ return this.runners[this.ids.indexOf( id + 1 )]
+
}
- remove (id) {
- let index = this.ids.indexOf(id + 1)
- this.ids.splice(index, 1)
- this.runners.splice(index, 1)
+ remove ( id ) {
+
+ let index = this.ids.indexOf( id + 1 )
+ this.ids.splice( index, 1 )
+ this.runners.splice( index, 1 )
return this
+
}
merge () {
+
let lastRunner = null
- this.runners.forEach((runner, i) => {
- if (lastRunner && runner.done && lastRunner.done) {
- this.remove(runner.id)
- this.edit(lastRunner.id, runner.mergeWith(lastRunner))
+ this.runners.forEach( ( runner, i ) => {
+
+ if ( lastRunner && runner.done && lastRunner.done ) {
+
+ this.remove( runner.id )
+ this.edit( lastRunner.id, runner.mergeWith( lastRunner ) )
+
}
lastRunner = runner
- })
+
+ } )
return this
+
}
- edit (id, newRunner) {
- let index = this.ids.indexOf(id + 1)
- this.ids.splice(index, 1, id)
- this.runners.splice(index, 1, newRunner)
+ edit ( id, newRunner ) {
+
+ let index = this.ids.indexOf( id + 1 )
+ this.ids.splice( index, 1, id )
+ this.runners.splice( index, 1, newRunner )
return this
+
}
length () {
+
return this.ids.length
+
}
- clearBefore (id) {
- let deleteCnt = this.ids.indexOf(id + 1) || 1
- this.ids.splice(0, deleteCnt, 0)
- this.runners.splice(0, deleteCnt, new FakeRunner())
- .forEach((r) => r.clearTransformsFromQueue())
+ clearBefore ( id ) {
+
+ let deleteCnt = this.ids.indexOf( id + 1 ) || 1
+ this.ids.splice( 0, deleteCnt, 0 )
+ this.runners.splice( 0, deleteCnt, new FakeRunner() )
+ .forEach( ( r ) => r.clearTransformsFromQueue() )
return this
+
}
+
}
let frameId = 0
-registerMethods({
+registerMethods( {
Element: {
- animate (duration, delay, when) {
- var o = Runner.sanitise(duration, delay, when)
+ animate ( duration, delay, when ) {
+
+ var o = Runner.sanitise( duration, delay, when )
var timeline = this.timeline()
- return new Runner(o.duration)
- .loop(o)
- .element(this)
- .timeline(timeline)
- .schedule(delay, when)
+ return new Runner( o.duration )
+ .loop( o )
+ .element( this )
+ .timeline( timeline )
+ .schedule( delay, when )
+
},
- delay (by, when) {
- return this.animate(0, by, when)
+ delay ( by, when ) {
+
+ return this.animate( 0, by, when )
+
},
// this function searches for all runners on the element and deletes the ones
// which run before the current one. This is because absolute transformations
// overwfrite anything anyway so there is no need to waste time computing
// other runners
- _clearTransformRunnersBefore (currentRunner) {
- this._transformationRunners.clearBefore(currentRunner.id)
+ _clearTransformRunnersBefore ( currentRunner ) {
+
+ this._transformationRunners.clearBefore( currentRunner.id )
+
},
- _currentTransform (current) {
+ _currentTransform ( current ) {
+
return this._transformationRunners.runners
// we need the equal sign here to make sure, that also transformations
// on the same runner which execute before the current transformation are
// taken into account
- .filter((runner) => runner.id <= current.id)
- .map(getRunnerTransform)
- .reduce(lmultiply, new Matrix())
+ .filter( ( runner ) => runner.id <= current.id )
+ .map( getRunnerTransform )
+ .reduce( lmultiply, new Matrix() )
+
},
- addRunner (runner) {
- this._transformationRunners.add(runner)
+ addRunner ( runner ) {
+
+ this._transformationRunners.add( runner )
Animator.transform_frame(
- mergeTransforms.bind(this), this._frameId
+ mergeTransforms.bind( this ), this._frameId
)
+
},
_prepareRunner () {
- if (this._frameId == null) {
+
+ if ( this._frameId == null ) {
+
this._transformationRunners = new RunnerArray()
- .add(new FakeRunner(new Matrix(this)))
+ .add( new FakeRunner( new Matrix( this ) ) )
this._frameId = frameId++
+
}
+
}
}
-})
+} )
+
+extend( Runner, {
+ attr ( a, v ) {
+
+ return this.styleAttr( 'attr', a, v )
-extend(Runner, {
- attr (a, v) {
- return this.styleAttr('attr', a, v)
},
// Add animatable styles
- css (s, v) {
- return this.styleAttr('css', s, v)
+ css ( s, v ) {
+
+ return this.styleAttr( 'css', s, v )
+
},
- styleAttr (type, name, val) {
+ styleAttr ( type, name, val ) {
+
// apply attributes individually
- if (typeof name === 'object') {
- for (var key in val) {
- this.styleAttr(type, key, val[key])
+ if ( typeof name === 'object' ) {
+
+ for ( var key in val ) {
+
+ this.styleAttr( type, key, val[key] )
+
}
+
}
- var morpher = new Morphable(this._stepper).to(val)
+ var morpher = new Morphable( this._stepper ).to( val )
+
+ this.queue( function () {
+
+ morpher = morpher.from( this.element()[type]( name ) )
+
+ }, function ( pos ) {
- this.queue(function () {
- morpher = morpher.from(this.element()[type](name))
- }, function (pos) {
- this.element()[type](name, morpher.at(pos))
+ this.element()[type]( name, morpher.at( pos ) )
return morpher.done()
- })
+
+ } )
return this
+
},
- zoom (level, point) {
- var morpher = new Morphable(this._stepper).to(new SVGNumber(level))
+ zoom ( level, point ) {
+
+ var morpher = new Morphable( this._stepper ).to( new SVGNumber( level ) )
+
+ this.queue( function () {
- this.queue(function () {
- morpher = morpher.from(this.zoom())
- }, function (pos) {
- this.element().zoom(morpher.at(pos), point)
+ morpher = morpher.from( this.zoom() )
+
+ }, function ( pos ) {
+
+ this.element().zoom( morpher.at( pos ), point )
return morpher.done()
- })
+
+ } )
return this
+
},
/**
@@ -669,22 +839,25 @@ extend(Runner, {
// - Note F(1) = T
// 4. Now you get the delta matrix as a result: D = F * inv(M)
- transform (transforms, relative, affine) {
+ transform ( transforms, relative, affine ) {
+
// If we have a declarative function, we should retarget it if possible
relative = transforms.relative || relative
- if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
+ if ( this._isDeclarative && !relative && this._tryRetarget( 'transform', transforms ) ) {
+
return this
+
}
// Parse the parameters
- var isMatrix = Matrix.isMatrixLike(transforms)
+ var isMatrix = Matrix.isMatrixLike( transforms )
affine = transforms.affine != null
? transforms.affine
- : (affine != null ? affine : !isMatrix)
+ : ( affine != null ? affine : !isMatrix )
// Create a morepher and set its type
- const morpher = new Morphable(this._stepper)
- .type(affine ? TransformBag : Matrix)
+ const morpher = new Morphable( this._stepper )
+ .type( affine ? TransformBag : Matrix )
let origin
let element
@@ -693,249 +866,328 @@ extend(Runner, {
let startTransform
function setup () {
+
// make sure element and origin is defined
element = element || this.element()
- origin = origin || getOrigin(transforms, element)
+ origin = origin || getOrigin( transforms, element )
- startTransform = new Matrix(relative ? undefined : element)
+ startTransform = new Matrix( relative ? undefined : element )
// add the runner to the element so it can merge transformations
- element.addRunner(this)
+ element.addRunner( this )
// Deactivate all transforms that have run so far if we are absolute
- if (!relative) {
- element._clearTransformRunnersBefore(this)
+ if ( !relative ) {
+
+ element._clearTransformRunnersBefore( this )
+
}
+
}
- function run (pos) {
+ function run ( pos ) {
+
// clear all other transforms before this in case something is saved
// on this runner. We are absolute. We dont need these!
- if (!relative) this.clearTransform()
+ if ( !relative ) this.clearTransform()
- let { x, y } = new Point(origin).transform(element._currentTransform(this))
+ let { x, y } = new Point( origin ).transform( element._currentTransform( this ) )
- let target = new Matrix({ ...transforms, origin: [x, y] })
+ let target = new Matrix( { ...transforms, origin: [ x, y ] } )
let start = this._isDeclarative && current
? current
: startTransform
- if (affine) {
- target = target.decompose(x, y)
- start = start.decompose(x, y)
+ if ( affine ) {
+
+ target = target.decompose( x, y )
+ start = start.decompose( x, y )
// Get the current and target angle as it was set
const rTarget = target.rotate
const rCurrent = start.rotate
// Figure out the shortest path to rotate directly
- const possibilities = [rTarget - 360, rTarget, rTarget + 360]
- const distances = possibilities.map(a => Math.abs(a - rCurrent))
- const shortest = Math.min(...distances)
- const index = distances.indexOf(shortest)
+ const possibilities = [ rTarget - 360, rTarget, rTarget + 360 ]
+ const distances = possibilities.map( a => Math.abs( a - rCurrent ) )
+ const shortest = Math.min( ...distances )
+ const index = distances.indexOf( shortest )
target.rotate = possibilities[index]
+
}
- if (relative) {
+ if ( relative ) {
+
// we have to be careful here not to overwrite the rotation
// with the rotate method of Matrix
- if (!isMatrix) {
+ if ( !isMatrix ) {
+
target.rotate = transforms.rotate || 0
+
}
- if (this._isDeclarative && currentAngle) {
+ if ( this._isDeclarative && currentAngle ) {
+
start.rotate = currentAngle
+
}
+
}
- morpher.from(start)
- morpher.to(target)
+ morpher.from( start )
+ morpher.to( target )
- let affineParameters = morpher.at(pos)
+ let affineParameters = morpher.at( pos )
currentAngle = affineParameters.rotate
- current = new Matrix(affineParameters)
+ current = new Matrix( affineParameters )
- this.addTransform(current)
+ this.addTransform( current )
return morpher.done()
+
}
- function retarget (newTransforms) {
+ function retarget ( newTransforms ) {
+
// only get a new origin if it changed since the last call
if (
- (newTransforms.origin || 'center').toString() !==
- (transforms.origin || 'center').toString()
+ ( newTransforms.origin || 'center' ).toString()
+ !== ( transforms.origin || 'center' ).toString()
) {
- origin = getOrigin(transforms, element)
+
+ origin = getOrigin( transforms, element )
+
}
// overwrite the old transformations with the new ones
transforms = { ...newTransforms, origin }
+
}
- this.queue(setup, run, retarget, true)
- this._isDeclarative && this._rememberMorpher('transform', morpher)
+ this.queue( setup, run, retarget, true )
+ this._isDeclarative && this._rememberMorpher( 'transform', morpher )
return this
+
},
// Animatable x-axis
- x (x, relative) {
- return this._queueNumber('x', x)
+ x ( x, relative ) {
+
+ return this._queueNumber( 'x', x )
+
},
// Animatable y-axis
- y (y) {
- return this._queueNumber('y', y)
+ y ( y ) {
+
+ return this._queueNumber( 'y', y )
+
},
- dx (x) {
- return this._queueNumberDelta('x', x)
+ dx ( x ) {
+
+ return this._queueNumberDelta( 'x', x )
+
},
- dy (y) {
- return this._queueNumberDelta('y', y)
+ dy ( y ) {
+
+ return this._queueNumberDelta( 'y', y )
+
},
- _queueNumberDelta (method, to) {
- to = new SVGNumber(to)
+ _queueNumberDelta ( method, to ) {
+
+ to = new SVGNumber( to )
// Try to change the target if we have this method already registerd
- if (this._tryRetarget(method, to)) return this
+ if ( this._tryRetarget( method, to ) ) return this
// Make a morpher and queue the animation
- var morpher = new Morphable(this._stepper).to(to)
+ var morpher = new Morphable( this._stepper ).to( to )
var from = null
- this.queue(function () {
+ this.queue( function () {
+
from = this.element()[method]()
- morpher.from(from)
- morpher.to(from + to)
- }, function (pos) {
- this.element()[method](morpher.at(pos))
+ morpher.from( from )
+ morpher.to( from + to )
+
+ }, function ( pos ) {
+
+ this.element()[method]( morpher.at( pos ) )
return morpher.done()
- }, function (newTo) {
- morpher.to(from + new SVGNumber(newTo))
- })
+
+ }, function ( newTo ) {
+
+ morpher.to( from + new SVGNumber( newTo ) )
+
+ } )
// Register the morpher so that if it is changed again, we can retarget it
- this._rememberMorpher(method, morpher)
+ this._rememberMorpher( method, morpher )
return this
+
},
- _queueObject (method, to) {
+ _queueObject ( method, to ) {
+
// Try to change the target if we have this method already registerd
- if (this._tryRetarget(method, to)) return this
+ if ( this._tryRetarget( method, to ) ) return this
// Make a morpher and queue the animation
- var morpher = new Morphable(this._stepper).to(to)
- this.queue(function () {
- morpher.from(this.element()[method]())
- }, function (pos) {
- this.element()[method](morpher.at(pos))
+ var morpher = new Morphable( this._stepper ).to( to )
+ this.queue( function () {
+
+ morpher.from( this.element()[method]() )
+
+ }, function ( pos ) {
+
+ this.element()[method]( morpher.at( pos ) )
return morpher.done()
- })
+
+ } )
// Register the morpher so that if it is changed again, we can retarget it
- this._rememberMorpher(method, morpher)
+ this._rememberMorpher( method, morpher )
return this
+
},
- _queueNumber (method, value) {
- return this._queueObject(method, new SVGNumber(value))
+ _queueNumber ( method, value ) {
+
+ return this._queueObject( method, new SVGNumber( value ) )
+
},
// Animatable center x-axis
- cx (x) {
- return this._queueNumber('cx', x)
+ cx ( x ) {
+
+ return this._queueNumber( 'cx', x )
+
},
// Animatable center y-axis
- cy (y) {
- return this._queueNumber('cy', y)
+ cy ( y ) {
+
+ return this._queueNumber( 'cy', y )
+
},
// Add animatable move
- move (x, y) {
- return this.x(x).y(y)
+ move ( x, y ) {
+
+ return this.x( x ).y( y )
+
},
// Add animatable center
- center (x, y) {
- return this.cx(x).cy(y)
+ center ( x, y ) {
+
+ return this.cx( x ).cy( y )
+
},
// Add animatable size
- size (width, height) {
+ size ( width, height ) {
+
// animate bbox based size for all other elements
var box
- if (!width || !height) {
+ if ( !width || !height ) {
+
box = this._element.bbox()
+
}
- if (!width) {
+ if ( !width ) {
+
width = box.width / box.height * height
+
}
- if (!height) {
+ if ( !height ) {
+
height = box.height / box.width * width
+
}
return this
- .width(width)
- .height(height)
+ .width( width )
+ .height( height )
+
},
// Add animatable width
- width (width) {
- return this._queueNumber('width', width)
+ width ( width ) {
+
+ return this._queueNumber( 'width', width )
+
},
// Add animatable height
- height (height) {
- return this._queueNumber('height', height)
+ height ( height ) {
+
+ return this._queueNumber( 'height', height )
+
},
// Add animatable plot
- plot (a, b, c, d) {
+ plot ( a, b, c, d ) {
+
// Lines can be plotted with 4 arguments
- if (arguments.length === 4) {
- return this.plot([a, b, c, d])
+ if ( arguments.length === 4 ) {
+
+ return this.plot( [ a, b, c, d ] )
+
}
- var morpher = this._element.MorphArray().to(a)
+ var morpher = this._element.MorphArray().to( a )
+
+ this.queue( function () {
+
+ morpher.from( this._element.array() )
- this.queue(function () {
- morpher.from(this._element.array())
- }, function (pos) {
- this._element.plot(morpher.at(pos))
- })
+ }, function ( pos ) {
+
+ this._element.plot( morpher.at( pos ) )
+
+ } )
return this
+
},
// Add leading method
- leading (value) {
- return this._queueNumber('leading', value)
+ leading ( value ) {
+
+ return this._queueNumber( 'leading', value )
+
},
// Add animatable viewbox
- viewbox (x, y, width, height) {
- return this._queueObject('viewbox', new Box(x, y, width, height))
+ viewbox ( x, y, width, height ) {
+
+ return this._queueObject( 'viewbox', new Box( x, y, width, height ) )
+
},
- update (o) {
- if (typeof o !== 'object') {
- return this.update({
+ update ( o ) {
+
+ if ( typeof o !== 'object' ) {
+
+ return this.update( {
offset: arguments[0],
color: arguments[1],
opacity: arguments[2]
- })
+ } )
+
}
- if (o.opacity != null) this.attr('stop-opacity', o.opacity)
- if (o.color != null) this.attr('stop-color', o.color)
- if (o.offset != null) this.attr('offset', o.offset)
+ if ( o.opacity != null ) this.attr( 'stop-opacity', o.opacity )
+ if ( o.color != null ) this.attr( 'stop-color', o.color )
+ if ( o.offset != null ) this.attr( 'offset', o.offset )
return this
+
}
-})
+} )
-extend(Runner, { rx, ry, from, to })
+extend( Runner, { rx, ry, from, to } )
diff --git a/src/animation/Timeline.js b/src/animation/Timeline.js
index 6abcb80..2fa281c 100644
--- a/src/animation/Timeline.js
+++ b/src/animation/Timeline.js
@@ -3,21 +3,27 @@ import { registerMethods } from '../utils/methods.js'
import Animator from './Animator.js'
import EventTarget from '../types/EventTarget.js'
-var makeSchedule = function (runnerInfo) {
+var makeSchedule = function ( runnerInfo ) {
+
var start = runnerInfo.start
var duration = runnerInfo.runner.duration()
var end = start + duration
return { start: start, duration: duration, end: end, runner: runnerInfo.runner }
+
}
export default class Timeline extends EventTarget {
+
// Construct a new timeline on the given element
constructor () {
+
super()
this._timeSource = function () {
+
let w = globals.window
- return (w.performance || w.Date).now()
+ return ( w.performance || w.Date ).now()
+
}
// Store the timing variables
@@ -36,6 +42,7 @@ export default class Timeline extends EventTarget {
this._time = 0
this._lastSourceTime = 0
this._lastStepTime = 0
+
}
/**
@@ -43,19 +50,28 @@ export default class Timeline extends EventTarget {
*/
// schedules a runner on the timeline
- schedule (runner, delay, when) {
+ schedule ( runner, delay, when ) {
+
// FIXME: how to sort? maybe by runner id?
- if (runner == null) {
- return this._runners.map(makeSchedule).sort(function (a, b) {
- return (a.start - b.start) || (a.duration - b.duration)
- })
+ if ( runner == null ) {
+
+ return this._runners.map( makeSchedule ).sort( function ( a, b ) {
+
+ return ( a.start - b.start ) || ( a.duration - b.duration )
+
+ } )
+
}
- if (!this.active()) {
+ if ( !this.active() ) {
+
this._step()
- if (when == null) {
+ if ( when == null ) {
+
when = 'now'
+
}
+
}
// The start time for the next animation can either be given explicitly,
@@ -65,28 +81,40 @@ export default class Timeline extends EventTarget {
delay = delay || 0
// Work out when to start the animation
- if (when == null || when === 'last' || when === 'after') {
+ if ( when == null || when === 'last' || when === 'after' ) {
+
// Take the last time and increment
absoluteStartTime = this._startTime
- } else if (when === 'absolute' || when === 'start') {
+
+ } else if ( when === 'absolute' || when === 'start' ) {
+
absoluteStartTime = delay
delay = 0
- } else if (when === 'now') {
+
+ } else if ( when === 'now' ) {
+
absoluteStartTime = this._time
- } else if (when === 'relative') {
+
+ } else if ( when === 'relative' ) {
+
let runnerInfo = this._runners[runner.id]
- if (runnerInfo) {
+ if ( runnerInfo ) {
+
absoluteStartTime = runnerInfo.start + delay
delay = 0
+
}
+
} else {
- throw new Error('Invalid value for the "when" parameter')
+
+ throw new Error( 'Invalid value for the "when" parameter' )
+
}
// Manage runner
runner.unschedule()
- runner.timeline(this)
- runner.time(-delay)
+ runner.timeline( this )
+ runner.time( -delay )
// Save startTime for next runner
this._startTime = absoluteStartTime + runner.duration() + delay
@@ -99,91 +127,115 @@ export default class Timeline extends EventTarget {
}
// Save order and continue
- this._order.push(runner.id)
+ this._order.push( runner.id )
this._continue()
return this
+
}
// Remove the runner from this timeline
- unschedule (runner) {
- var index = this._order.indexOf(runner.id)
- if (index < 0) return this
+ unschedule ( runner ) {
+
+ var index = this._order.indexOf( runner.id )
+ if ( index < 0 ) return this
delete this._runners[runner.id]
- this._order.splice(index, 1)
- runner.timeline(null)
+ this._order.splice( index, 1 )
+ runner.timeline( null )
return this
+
}
play () {
+
// Now make sure we are not paused and continue the animation
this._paused = false
return this._continue()
+
}
pause () {
+
// Cancel the next animation frame and pause
this._nextFrame = null
this._paused = true
return this
+
}
stop () {
+
// Cancel the next animation frame and go to start
- this.seek(-this._time)
+ this.seek( -this._time )
return this.pause()
+
}
finish () {
- this.seek(Infinity)
+
+ this.seek( Infinity )
return this.pause()
+
}
- speed (speed) {
- if (speed == null) return this._speed
+ speed ( speed ) {
+
+ if ( speed == null ) return this._speed
this._speed = speed
return this
+
}
- reverse (yes) {
+ reverse ( yes ) {
+
var currentSpeed = this.speed()
- if (yes == null) return this.speed(-currentSpeed)
+ if ( yes == null ) return this.speed( -currentSpeed )
+
+ var positive = Math.abs( currentSpeed )
+ return this.speed( yes ? positive : -positive )
- var positive = Math.abs(currentSpeed)
- return this.speed(yes ? positive : -positive)
}
- seek (dt) {
+ seek ( dt ) {
+
this._time += dt
return this._continue()
+
}
- time (time) {
- if (time == null) return this._time
+ time ( time ) {
+
+ if ( time == null ) return this._time
this._time = time
return this
+
}
- persist (dtOrForever) {
- if (dtOrForever == null) return this._persist
+ persist ( dtOrForever ) {
+
+ if ( dtOrForever == null ) return this._persist
this._persist = dtOrForever
return this
+
}
- source (fn) {
- if (fn == null) return this._timeSource
+ source ( fn ) {
+
+ if ( fn == null ) return this._timeSource
this._timeSource = fn
return this
+
}
_step () {
+
// If the timeline is paused, just do nothing
- if (this._paused) return
+ if ( this._paused ) return
// Get the time delta from the last time and update the time
var time = this._timeSource()
var dtSource = time - this._lastSourceTime
- var dtTime = this._speed * dtSource + (this._time - this._lastStepTime)
+ var dtTime = this._speed * dtSource + ( this._time - this._lastStepTime )
this._lastSourceTime = time
// Update the time
@@ -193,7 +245,8 @@ export default class Timeline extends EventTarget {
// Run all of the runners directly
var runnersLeft = false
- for (var i = 0, len = this._order.length; i < len; i++) {
+ for ( var i = 0, len = this._order.length; i < len; i++ ) {
+
// Get and run the current runner and ignore it if its inactive
var runnerInfo = this._runners[this._order[i]]
var runner = runnerInfo.runner
@@ -204,64 +257,89 @@ export default class Timeline extends EventTarget {
let dtToStart = this._time - runnerInfo.start
// Dont run runner if not started yet
- if (dtToStart < 0) {
+ if ( dtToStart < 0 ) {
+
runnersLeft = true
continue
- } else if (dtToStart < dt) {
+
+ } else if ( dtToStart < dt ) {
+
// Adjust dt to make sure that animation is on point
dt = dtToStart
+
}
- if (!runner.active()) continue
+ if ( !runner.active() ) continue
// If this runner is still going, signal that we need another animation
// frame, otherwise, remove the completed runner
- var finished = runner.step(dt).done
- if (!finished) {
+ var finished = runner.step( dt ).done
+ if ( !finished ) {
+
runnersLeft = true
// continue
- } else if (runnerInfo.persist !== true) {
+
+ } else if ( runnerInfo.persist !== true ) {
+
// runner is finished. And runner might get removed
var endTime = runner.duration() - runner.time() + this._time
- if (endTime + this._persist < this._time) {
+ if ( endTime + this._persist < this._time ) {
+
// Delete runner and correct index
delete this._runners[this._order[i]]
- this._order.splice(i--, 1) && --len
- runner.timeline(null)
+ this._order.splice( i--, 1 ) && --len
+ runner.timeline( null )
+
}
+
}
+
}
// Get the next animation frame to keep the simulation going
- if (runnersLeft) {
- this._nextFrame = Animator.frame(this._step.bind(this))
+ if ( runnersLeft ) {
+
+ this._nextFrame = Animator.frame( this._step.bind( this ) )
+
} else {
+
this._nextFrame = null
+
}
return this
+
}
// Checks if we are running and continues the animation
_continue () {
- if (this._paused) return this
- if (!this._nextFrame) {
- this._nextFrame = Animator.frame(this._step.bind(this))
+
+ if ( this._paused ) return this
+ if ( !this._nextFrame ) {
+
+ this._nextFrame = Animator.frame( this._step.bind( this ) )
+
}
return this
+
}
active () {
+
return !!this._nextFrame
+
}
+
}
-registerMethods({
+registerMethods( {
Element: {
timeline: function () {
- this._timeline = (this._timeline || new Timeline())
+
+ this._timeline = ( this._timeline || new Timeline() )
return this._timeline
+
}
}
-})
+} )
diff --git a/src/elements/A.js b/src/elements/A.js
index 722deed..ee81975 100644
--- a/src/elements/A.js
+++ b/src/elements/A.js
@@ -4,40 +4,58 @@ import { xlink } from '../modules/core/namespaces.js'
import Container from './Container.js'
export default class A extends Container {
- constructor (node) {
- super(nodeOrNew('a', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'a', node ), node )
+
}
// Link url
- to (url) {
- return this.attr('href', url, xlink)
+ to ( url ) {
+
+ return this.attr( 'href', url, xlink )
+
}
// Link target attribute
- target (target) {
- return this.attr('target', target)
+ target ( target ) {
+
+ return this.attr( 'target', target )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create a hyperlink element
- link: wrapWithAttrCheck(function (url) {
- return this.put(new A()).to(url)
- })
+ link: wrapWithAttrCheck( function ( url ) {
+
+ return this.put( new A() ).to( url )
+
+ } )
},
Element: {
// Create a hyperlink element
- linkTo: function (url) {
+ linkTo: function ( url ) {
+
var link = new A()
- if (typeof url === 'function') { url.call(link, link) } else {
- link.to(url)
+ if ( typeof url === 'function' ) {
+
+ url.call( link, link )
+
+ } else {
+
+ link.to( url )
+
}
- return this.parent().put(link).put(this)
+ return this.parent().put( link ).put( this )
+
}
}
-})
+} )
-register(A)
+register( A )
diff --git a/src/elements/Bare.js b/src/elements/Bare.js
index a057634..190aa1f 100644
--- a/src/elements/Bare.js
+++ b/src/elements/Bare.js
@@ -4,28 +4,38 @@ import Container from './Container.js'
import { globals } from '../utils/window.js'
export default class Bare extends Container {
- constructor (node, attrs) {
- super(nodeOrNew(node, typeof node === 'string' ? null : node), attrs)
+
+ constructor ( node, attrs ) {
+
+ super( nodeOrNew( node, typeof node === 'string' ? null : node ), attrs )
+
}
- words (text) {
+ words ( text ) {
+
// remove contents
- while (this.node.hasChildNodes()) {
- this.node.removeChild(this.node.lastChild)
+ while ( this.node.hasChildNodes() ) {
+
+ this.node.removeChild( this.node.lastChild )
+
}
// create text node
- this.node.appendChild(globals.document.createTextNode(text))
+ this.node.appendChild( globals.document.createTextNode( text ) )
return this
+
}
+
}
-register(Bare)
+register( Bare )
-registerMethods('Container', {
+registerMethods( 'Container', {
// Create an element that is not described by SVG.js
- element: wrapWithAttrCheck(function (node) {
- return this.put(new Bare(node))
- })
-})
+ element: wrapWithAttrCheck( function ( node ) {
+
+ return this.put( new Bare( node ) )
+
+ } )
+} )
diff --git a/src/elements/Circle.js b/src/elements/Circle.js
index 3135ada..5aa969a 100644
--- a/src/elements/Circle.js
+++ b/src/elements/Circle.js
@@ -10,40 +10,54 @@ import SVGNumber from '../types/SVGNumber.js'
import Shape from './Shape.js'
export default class Circle extends Shape {
- constructor (node) {
- super(nodeOrNew('circle', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'circle', node ), node )
+
}
- radius (r) {
- return this.attr('r', r)
+ radius ( r ) {
+
+ return this.attr( 'r', r )
+
}
// Radius x value
- rx (rx) {
- return this.attr('r', rx)
+ rx ( rx ) {
+
+ return this.attr( 'r', rx )
+
}
// Alias radius x value
- ry (ry) {
- return this.rx(ry)
+ ry ( ry ) {
+
+ return this.rx( ry )
+
}
- size (size) {
- return this.radius(new SVGNumber(size).divide(2))
+ size ( size ) {
+
+ return this.radius( new SVGNumber( size ).divide( 2 ) )
+
}
+
}
-extend(Circle, { x, y, cx, cy, width, height })
+extend( Circle, { x, y, cx, cy, width, height } )
-registerMethods({
+registerMethods( {
Element: {
// Create circle element
- circle: wrapWithAttrCheck(function (size) {
- return this.put(new Circle())
- .size(size)
- .move(0, 0)
- })
+ circle: wrapWithAttrCheck( function ( size ) {
+
+ return this.put( new Circle() )
+ .size( size )
+ .move( 0, 0 )
+
+ } )
}
-})
+} )
-register(Circle)
+register( Circle )
diff --git a/src/elements/ClipPath.js b/src/elements/ClipPath.js
index e545baa..199ee5b 100644
--- a/src/elements/ClipPath.js
+++ b/src/elements/ClipPath.js
@@ -4,54 +4,72 @@ import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class ClipPath extends Container {
- constructor (node) {
- super(nodeOrNew('clipPath', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'clipPath', node ), node )
+
}
// Unclip all clipped elements and remove itself
remove () {
+
// unclip all targets
- this.targets().forEach(function (el) {
+ this.targets().forEach( function ( el ) {
+
el.unclip()
- })
+
+ } )
// remove clipPath from parent
return super.remove()
+
}
targets () {
- return baseFind('svg [clip-path*="' + this.id() + '"]')
+
+ return baseFind( 'svg [clip-path*="' + this.id() + '"]' )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create clipping element
- clip: wrapWithAttrCheck(function () {
- return this.defs().put(new ClipPath())
- })
+ clip: wrapWithAttrCheck( function () {
+
+ return this.defs().put( new ClipPath() )
+
+ } )
},
Element: {
// Distribute clipPath to svg element
- clipWith (element) {
+ clipWith ( element ) {
+
// use given clip or create a new one
let clipper = element instanceof ClipPath
? element
- : this.parent().clip().add(element)
+ : this.parent().clip().add( element )
// apply mask
- return this.attr('clip-path', 'url("#' + clipper.id() + '")')
+ return this.attr( 'clip-path', 'url("#' + clipper.id() + '")' )
+
},
// Unclip element
unclip () {
- return this.attr('clip-path', null)
+
+ return this.attr( 'clip-path', null )
+
},
clipper () {
- return this.reference('clip-path')
+
+ return this.reference( 'clip-path' )
+
}
}
-})
+} )
-register(ClipPath)
+register( ClipPath )
diff --git a/src/elements/Container.js b/src/elements/Container.js
index b47972e..82ee0ae 100644
--- a/src/elements/Container.js
+++ b/src/elements/Container.js
@@ -2,29 +2,39 @@ import { register } from '../utils/adopter.js'
import Element from './Element.js'
export default class Container extends Element {
- flatten (parent) {
- this.each(function () {
- if (this instanceof Container) return this.flatten(parent).ungroup(parent)
- return this.toParent(parent)
- })
+
+ flatten ( parent ) {
+
+ this.each( function () {
+
+ if ( this instanceof Container ) return this.flatten( parent ).ungroup( parent )
+ return this.toParent( parent )
+
+ } )
// we need this so that the root does not get removed
this.node.firstElementChild || this.remove()
return this
+
}
- ungroup (parent) {
+ ungroup ( parent ) {
+
parent = parent || this.parent()
- this.each(function () {
- return this.toParent(parent)
- })
+ this.each( function () {
+
+ return this.toParent( parent )
+
+ } )
this.remove()
return this
+
}
+
}
-register(Container)
+register( Container )
diff --git a/src/elements/Defs.js b/src/elements/Defs.js
index 2826611..bcbea01 100644
--- a/src/elements/Defs.js
+++ b/src/elements/Defs.js
@@ -2,12 +2,24 @@ import { nodeOrNew, register } from '../utils/adopter.js'
import Container from './Container.js'
export default class Defs extends Container {
- constructor (node) {
- super(nodeOrNew('defs', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'defs', node ), node )
+
+ }
+
+ flatten () {
+
+ return this
+
+ }
+ ungroup () {
+
+ return this
+
}
- flatten () { return this }
- ungroup () { return this }
}
-register(Defs)
+register( Defs )
diff --git a/src/elements/Dom.js b/src/elements/Dom.js
index 2fcedce..f3ea467 100644
--- a/src/elements/Dom.js
+++ b/src/elements/Dom.js
@@ -15,217 +15,294 @@ import List from '../types/List.js'
import attr from '../modules/core/attr.js'
export default class Dom extends EventTarget {
- constructor (node, attrs) {
- super(node)
+
+ constructor ( node, attrs ) {
+
+ super( node )
this.node = node
this.type = node.nodeName
- if (attrs && node !== attrs) {
- this.attr(attrs)
+ if ( attrs && node !== attrs ) {
+
+ this.attr( attrs )
+
}
+
}
// Add given element at a position
- add (element, i) {
- element = makeInstance(element)
+ add ( element, i ) {
+
+ element = makeInstance( element )
+
+ if ( i == null ) {
+
+ this.node.appendChild( element.node )
+
+ } else if ( element.node !== this.node.childNodes[i] ) {
+
+ this.node.insertBefore( element.node, this.node.childNodes[i] )
- if (i == null) {
- this.node.appendChild(element.node)
- } else if (element.node !== this.node.childNodes[i]) {
- this.node.insertBefore(element.node, this.node.childNodes[i])
}
return this
+
}
// Add element to given container and return self
- addTo (parent) {
- return makeInstance(parent).put(this)
+ addTo ( parent ) {
+
+ return makeInstance( parent ).put( this )
+
}
// Returns all child elements
children () {
- return new List(map(this.node.children, function (node) {
- return adopt(node)
- }))
+
+ return new List( map( this.node.children, function ( node ) {
+
+ return adopt( node )
+
+ } ) )
+
}
// Remove all elements in this container
clear () {
+
// remove children
- while (this.node.hasChildNodes()) {
- this.node.removeChild(this.node.lastChild)
+ while ( this.node.hasChildNodes() ) {
+
+ this.node.removeChild( this.node.lastChild )
+
}
// remove defs reference
delete this._defs
return this
+
}
// Clone element
clone () {
+
// write dom data to the dom so the clone can pickup the data
this.writeDataToDom()
// clone element and assign new id
- return assignNewId(this.node.cloneNode(true))
+ return assignNewId( this.node.cloneNode( true ) )
+
}
// Iterates over all children and invokes a given block
- each (block, deep) {
+ each ( block, deep ) {
+
var children = this.children()
var i, il
- for (i = 0, il = children.length; i < il; i++) {
- block.apply(children[i], [i, children])
+ for ( i = 0, il = children.length; i < il; i++ ) {
+
+ block.apply( children[i], [ i, children ] )
+
+ if ( deep ) {
+
+ children[i].each( block, deep )
- if (deep) {
- children[i].each(block, deep)
}
+
}
return this
+
}
// Get first child
first () {
- return adopt(this.node.firstChild)
+
+ return adopt( this.node.firstChild )
+
}
// Get a element at the given index
- get (i) {
- return adopt(this.node.childNodes[i])
+ get ( i ) {
+
+ return adopt( this.node.childNodes[i] )
+
}
getEventHolder () {
+
return this.node
+
}
getEventTarget () {
+
return this.node
+
}
// Checks if the given element is a child
- has (element) {
- return this.index(element) >= 0
+ has ( element ) {
+
+ return this.index( element ) >= 0
+
}
// Get / set id
- id (id) {
+ id ( id ) {
+
// generate new id if no id set
- if (typeof id === 'undefined' && !this.node.id) {
- this.node.id = eid(this.type)
+ if ( typeof id === 'undefined' && !this.node.id ) {
+
+ this.node.id = eid( this.type )
+
}
// dont't set directly width this.node.id to make `null` work correctly
- return this.attr('id', id)
+ return this.attr( 'id', id )
+
}
// Gets index of given element
- index (element) {
- return [].slice.call(this.node.childNodes).indexOf(element.node)
+ index ( element ) {
+
+ return [].slice.call( this.node.childNodes ).indexOf( element.node )
+
}
// Get the last child
last () {
- return adopt(this.node.lastChild)
+
+ return adopt( this.node.lastChild )
+
}
// matches the element vs a css selector
- matches (selector) {
+ matches ( selector ) {
+
const el = this.node
- return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector)
+ return ( el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector ).call( el, selector )
+
}
// Returns the parent element instance
- parent (type) {
+ parent ( type ) {
+
var parent = this
// check for parent
- if (!parent.node.parentNode) return null
+ if ( !parent.node.parentNode ) return null
// get parent element
- parent = adopt(parent.node.parentNode)
+ parent = adopt( parent.node.parentNode )
- if (!type) return parent
+ if ( !type ) return parent
// loop trough ancestors if type is given
- while (parent && parent.node instanceof globals.window.SVGElement) { // FIXME: That shouldnt be neccessary
- if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
- parent = adopt(parent.node.parentNode)
+ while ( parent && parent.node instanceof globals.window.SVGElement ) { // FIXME: That shouldnt be neccessary
+
+ if ( typeof type === 'string' ? parent.matches( type ) : parent instanceof type ) return parent
+ parent = adopt( parent.node.parentNode )
+
}
+
}
// Basically does the same as `add()` but returns the added element instead
- put (element, i) {
- this.add(element, i)
+ put ( element, i ) {
+
+ this.add( element, i )
return element
+
}
// Add element to given container and return container
- putIn (parent) {
- return makeInstance(parent).add(this)
+ putIn ( parent ) {
+
+ return makeInstance( parent ).add( this )
+
}
// Remove element
remove () {
- if (this.parent()) {
- this.parent().removeElement(this)
+
+ if ( this.parent() ) {
+
+ this.parent().removeElement( this )
+
}
return this
+
}
// Remove a given child
- removeElement (element) {
- this.node.removeChild(element.node)
+ removeElement ( element ) {
+
+ this.node.removeChild( element.node )
return this
+
}
// Replace this with element
- replace (element) {
- element = makeInstance(element)
- this.node.parentNode.replaceChild(element.node, this.node)
+ replace ( element ) {
+
+ element = makeInstance( element )
+ this.node.parentNode.replaceChild( element.node, this.node )
return element
+
}
- round (precision = 2, map) {
+ round ( precision = 2, map ) {
+
const factor = 10 ** precision
const attrs = this.attr()
// If we have no map, build one from attrs
- if (!map) {
- map = Object.keys(attrs)
+ if ( !map ) {
+
+ map = Object.keys( attrs )
+
}
// Holds rounded attributes
const newAttrs = {}
- map.forEach((key) => {
- newAttrs[key] = Math.round(attrs[key] * factor) / factor
- })
+ map.forEach( ( key ) => {
+
+ newAttrs[key] = Math.round( attrs[key] * factor ) / factor
- this.attr(newAttrs)
+ } )
+
+ this.attr( newAttrs )
return this
+
}
// Return id on string conversion
toString () {
+
return this.id()
+
}
// Import raw svg
- svg (svgOrFn, outerHTML) {
+ svg ( svgOrFn, outerHTML ) {
+
var well, len, fragment
- if (svgOrFn === false) {
+ if ( svgOrFn === false ) {
+
outerHTML = false
svgOrFn = null
+
}
// act as getter if no svg string is given
- if (svgOrFn == null || typeof svgOrFn === 'function') {
+ if ( svgOrFn == null || typeof svgOrFn === 'function' ) {
+
// The default for exports is, that the outerNode is included
outerHTML = outerHTML == null ? true : outerHTML
@@ -234,38 +311,49 @@ export default class Dom extends EventTarget {
let current = this
// An export modifier was passed
- if (svgOrFn != null) {
- current = adopt(current.node.cloneNode(true))
+ if ( svgOrFn != null ) {
+
+ current = adopt( current.node.cloneNode( true ) )
// If the user wants outerHTML we need to process this node, too
- if (outerHTML) {
- let result = svgOrFn(current)
+ if ( outerHTML ) {
+
+ let result = svgOrFn( current )
current = result || current
// The user does not want this node? Well, then he gets nothing
- if (result === false) return ''
+ if ( result === false ) return ''
+
}
// Deep loop through all children and apply modifier
- current.each(function () {
- let result = svgOrFn(this)
+ current.each( function () {
+
+ let result = svgOrFn( this )
let _this = result || this
// If modifier returns false, discard node
- if (result === false) {
+ if ( result === false ) {
+
this.remove()
- // If modifier returns new node, use it
- } else if (result && this !== _this) {
- this.replace(_this)
+ // If modifier returns new node, use it
+
+ } else if ( result && this !== _this ) {
+
+ this.replace( _this )
+
}
- }, true)
+
+ }, true )
+
}
// Return outer or inner content
return outerHTML
? current.node.outerHTML
: current.node.innerHTML
+
}
// Act as setter if we got a string
@@ -274,33 +362,41 @@ export default class Dom extends EventTarget {
outerHTML = outerHTML == null ? false : outerHTML
// Create temporary holder
- well = globals.document.createElementNS(ns, 'svg')
+ well = globals.document.createElementNS( ns, 'svg' )
fragment = globals.document.createDocumentFragment()
// Dump raw svg
well.innerHTML = svgOrFn
// Transplant nodes into the fragment
- for (len = well.children.length; len--;) {
- fragment.appendChild(well.firstElementChild)
+ for ( len = well.children.length; len--; ) {
+
+ fragment.appendChild( well.firstElementChild )
+
}
// Add the whole fragment at once
return outerHTML
- ? this.replace(fragment)
- : this.add(fragment)
+ ? this.replace( fragment )
+ : this.add( fragment )
+
}
// write svgjs data to the dom
writeDataToDom () {
+
// dump variables recursively
- this.each(function () {
+ this.each( function () {
+
this.writeDataToDom()
- })
+
+ } )
return this
+
}
+
}
-extend(Dom, { attr, find })
-register(Dom)
+extend( Dom, { attr, find } )
+register( Dom )
diff --git a/src/elements/Element.js b/src/elements/Element.js
index 91aa3e0..169c872 100644
--- a/src/elements/Element.js
+++ b/src/elements/Element.js
@@ -15,11 +15,13 @@ import Dom from './Dom.js'
import List from '../types/List.js'
import SVGNumber from '../types/SVGNumber.js'
-const Svg = getClass(root)
+const Svg = getClass( root )
export default class Element extends Dom {
- constructor (node, attrs) {
- super(node, attrs)
+
+ constructor ( node, attrs ) {
+
+ super( node, attrs )
// initialize data object
this.dom = {}
@@ -27,135 +29,177 @@ export default class Element extends Dom {
// create circular reference
this.node.instance = this
- if (node.hasAttribute('svgjs:data')) {
+ if ( node.hasAttribute( 'svgjs:data' ) ) {
+
// pull svgjs data from the dom (getAttributeNS doesn't work in html5)
- this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {})
+ this.setData( JSON.parse( node.getAttribute( 'svgjs:data' ) ) || {} )
+
}
+
}
// Move element by its center
- center (x, y) {
- return this.cx(x).cy(y)
+ center ( x, y ) {
+
+ return this.cx( x ).cy( y )
+
}
// Move by center over x-axis
- cx (x) {
- return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
+ cx ( x ) {
+
+ return x == null ? this.x() + this.width() / 2 : this.x( x - this.width() / 2 )
+
}
// Move by center over y-axis
- cy (y) {
+ cy ( y ) {
+
return y == null
? this.y() + this.height() / 2
- : this.y(y - this.height() / 2)
+ : this.y( y - this.height() / 2 )
+
}
// Get defs
defs () {
+
return this.root().defs()
+
}
// Get parent document
root () {
- let p = this.parent(Svg)
+
+ let p = this.parent( Svg )
return p && p.root()
+
}
getEventHolder () {
+
return this
+
}
// Set height of element
- height (height) {
- return this.attr('height', height)
+ height ( height ) {
+
+ return this.attr( 'height', height )
+
}
// Checks whether the given point inside the bounding box of the element
- inside (x, y) {
+ inside ( x, y ) {
+
let box = this.bbox()
- return x > box.x &&
- y > box.y &&
- x < box.x + box.width &&
- y < box.y + box.height
+ return x > box.x
+ && y > box.y
+ && x < box.x + box.width
+ && y < box.y + box.height
+
}
// Move element to given x and y values
- move (x, y) {
- return this.x(x).y(y)
+ move ( x, y ) {
+
+ return this.x( x ).y( y )
+
}
// return array of all ancestors of given type up to the root svg
- parents (until = globals.document) {
- until = makeInstance(until)
+ parents ( until = globals.document ) {
+
+ until = makeInstance( until )
let parents = new List()
let parent = this
while (
- (parent = parent.parent()) &&
- parent.node !== until.node &&
- parent.node !== globals.document
+ ( parent = parent.parent() )
+ && parent.node !== until.node
+ && parent.node !== globals.document
) {
- parents.push(parent)
+
+ parents.push( parent )
+
}
return parents
+
}
// Get referenced element form attribute value
- reference (attr) {
- attr = this.attr(attr)
- if (!attr) return null
+ reference ( attr ) {
+
+ attr = this.attr( attr )
+ if ( !attr ) return null
+
+ const m = attr.match( reference )
+ return m ? makeInstance( m[1] ) : null
- const m = attr.match(reference)
- return m ? makeInstance(m[1]) : null
}
// set given data to the elements data property
- setData (o) {
+ setData ( o ) {
+
this.dom = o
return this
+
}
// Set element size to given width and height
- size (width, height) {
- let p = proportionalSize(this, width, height)
+ size ( width, height ) {
+
+ let p = proportionalSize( this, width, height )
return this
- .width(new SVGNumber(p.width))
- .height(new SVGNumber(p.height))
+ .width( new SVGNumber( p.width ) )
+ .height( new SVGNumber( p.height ) )
+
}
// Set width of element
- width (width) {
- return this.attr('width', width)
+ width ( width ) {
+
+ return this.attr( 'width', width )
+
}
// write svgjs data to the dom
writeDataToDom () {
+
// remove previously set data
- this.node.removeAttribute('svgjs:data')
+ this.node.removeAttribute( 'svgjs:data' )
+
+ if ( Object.keys( this.dom ).length ) {
+
+ this.node.setAttribute( 'svgjs:data', JSON.stringify( this.dom ) ) // see #428
- if (Object.keys(this.dom).length) {
- this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
}
return super.writeDataToDom()
+
}
// Move over x-axis
- x (x) {
- return this.attr('x', x)
+ x ( x ) {
+
+ return this.attr( 'x', x )
+
}
// Move over y-axis
- y (y) {
- return this.attr('y', y)
+ y ( y ) {
+
+ return this.attr( 'y', y )
+
}
+
}
-extend(Element, {
+extend( Element, {
bbox, rbox, point, ctm, screenCTM
-})
+} )
-register(Element)
+register( Element )
diff --git a/src/elements/Ellipse.js b/src/elements/Ellipse.js
index 0350f1f..e1e1fe0 100644
--- a/src/elements/Ellipse.js
+++ b/src/elements/Ellipse.js
@@ -11,26 +11,34 @@ import Shape from './Shape.js'
import * as circled from '../modules/core/circled.js'
export default class Ellipse extends Shape {
- constructor (node) {
- super(nodeOrNew('ellipse', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'ellipse', node ), node )
+
}
- size (width, height) {
- var p = proportionalSize(this, width, height)
+ size ( width, height ) {
+
+ var p = proportionalSize( this, width, height )
return this
- .rx(new SVGNumber(p.width).divide(2))
- .ry(new SVGNumber(p.height).divide(2))
+ .rx( new SVGNumber( p.width ).divide( 2 ) )
+ .ry( new SVGNumber( p.height ).divide( 2 ) )
+
}
+
}
-extend(Ellipse, circled)
+extend( Ellipse, circled )
-registerMethods('Container', {
+registerMethods( 'Container', {
// Create an ellipse
- ellipse: wrapWithAttrCheck(function (width, height) {
- return this.put(new Ellipse()).size(width, height).move(0, 0)
- })
-})
+ ellipse: wrapWithAttrCheck( function ( width, height ) {
+
+ return this.put( new Ellipse() ).size( width, height ).move( 0, 0 )
+
+ } )
+} )
-register(Ellipse)
+register( Ellipse )
diff --git a/src/elements/G.js b/src/elements/G.js
index 6a93a3f..a72f1fb 100644
--- a/src/elements/G.js
+++ b/src/elements/G.js
@@ -3,18 +3,24 @@ import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
export default class G extends Container {
- constructor (node) {
- super(nodeOrNew('g', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'g', node ), node )
+
}
+
}
-registerMethods({
+registerMethods( {
Element: {
// Create a group element
- group: wrapWithAttrCheck(function () {
- return this.put(new G())
- })
+ group: wrapWithAttrCheck( function () {
+
+ return this.put( new G() )
+
+ } )
}
-})
+} )
-register(G)
+register( G )
diff --git a/src/elements/Gradient.js b/src/elements/Gradient.js
index 23de97d..7116fc8 100644
--- a/src/elements/Gradient.js
+++ b/src/elements/Gradient.js
@@ -12,71 +12,95 @@ import baseFind from '../modules/core/selector.js'
import * as gradiented from '../modules/core/gradiented.js'
export default class Gradient extends Container {
- constructor (type, attrs) {
+
+ constructor ( type, attrs ) {
+
super(
- nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type),
+ nodeOrNew( type + 'Gradient', typeof type === 'string' ? null : type ),
attrs
)
+
}
// Add a color stop
- stop (offset, color, opacity) {
- return this.put(new Stop()).update(offset, color, opacity)
+ stop ( offset, color, opacity ) {
+
+ return this.put( new Stop() ).update( offset, color, opacity )
+
}
// Update gradient
- update (block) {
+ update ( block ) {
+
// remove all stops
this.clear()
// invoke passed block
- if (typeof block === 'function') {
- block.call(this, this)
+ if ( typeof block === 'function' ) {
+
+ block.call( this, this )
+
}
return this
+
}
// Return the fill id
url () {
+
return 'url(#' + this.id() + ')'
+
}
// Alias string convertion to fill
toString () {
+
return this.url()
+
}
// custom attr to handle transform
- attr (a, b, c) {
- if (a === 'transform') a = 'gradientTransform'
- return super.attr(a, b, c)
+ attr ( a, b, c ) {
+
+ if ( a === 'transform' ) a = 'gradientTransform'
+ return super.attr( a, b, c )
+
}
targets () {
- return baseFind('svg [fill*="' + this.id() + '"]')
+
+ return baseFind( 'svg [fill*="' + this.id() + '"]' )
+
}
bbox () {
+
return new Box()
+
}
+
}
-extend(Gradient, gradiented)
+extend( Gradient, gradiented )
-registerMethods({
+registerMethods( {
Container: {
// Create gradient element in defs
- gradient: wrapWithAttrCheck(function (type, block) {
- return this.defs().gradient(type, block)
- })
+ gradient: wrapWithAttrCheck( function ( type, block ) {
+
+ return this.defs().gradient( type, block )
+
+ } )
},
// define gradient
Defs: {
- gradient: wrapWithAttrCheck(function (type, block) {
- return this.put(new Gradient(type)).update(block)
- })
+ gradient: wrapWithAttrCheck( function ( type, block ) {
+
+ return this.put( new Gradient( type ) ).update( block )
+
+ } )
}
-})
+} )
-register(Gradient)
+register( Gradient )
diff --git a/src/elements/HtmlNode.js b/src/elements/HtmlNode.js
index 009b122..d2299ed 100644
--- a/src/elements/HtmlNode.js
+++ b/src/elements/HtmlNode.js
@@ -3,4 +3,4 @@ import Dom from './Dom.js'
export default class HtmlNode extends Dom {}
-register(HtmlNode)
+register( HtmlNode )
diff --git a/src/elements/Image.js b/src/elements/Image.js
index 8f27470..4945271 100644
--- a/src/elements/Image.js
+++ b/src/elements/Image.js
@@ -9,69 +9,99 @@ import Shape from './Shape.js'
import { globals } from '../utils/window.js'
export default class Image extends Shape {
- constructor (node) {
- super(nodeOrNew('image', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'image', node ), node )
+
}
// (re)load image
- load (url, callback) {
- if (!url) return this
+ load ( url, callback ) {
+
+ if ( !url ) return this
var img = new globals.window.Image()
- on(img, 'load', function (e) {
- var p = this.parent(Pattern)
+ on( img, 'load', function ( e ) {
+
+ var p = this.parent( Pattern )
// ensure image size
- if (this.width() === 0 && this.height() === 0) {
- this.size(img.width, img.height)
+ if ( this.width() === 0 && this.height() === 0 ) {
+
+ this.size( img.width, img.height )
+
}
- if (p instanceof Pattern) {
+ if ( p instanceof Pattern ) {
+
// ensure pattern size if not set
- if (p.width() === 0 && p.height() === 0) {
- p.size(this.width(), this.height())
+ if ( p.width() === 0 && p.height() === 0 ) {
+
+ p.size( this.width(), this.height() )
+
}
+
}
- if (typeof callback === 'function') {
- callback.call(this, e)
+ if ( typeof callback === 'function' ) {
+
+ callback.call( this, e )
+
}
- }, this)
- on(img, 'load error', function () {
+ }, this )
+
+ on( img, 'load error', function () {
+
// dont forget to unbind memory leaking events
- off(img)
- })
+ off( img )
+
+ } )
+
+ return this.attr( 'href', ( img.src = url ), xlink )
- return this.attr('href', (img.src = url), xlink)
}
+
}
-registerAttrHook(function (attr, val, _this) {
+registerAttrHook( function ( attr, val, _this ) {
+
// convert image fill and stroke to patterns
- if (attr === 'fill' || attr === 'stroke') {
- if (isImage.test(val)) {
- val = _this.root().defs().image(val)
+ if ( attr === 'fill' || attr === 'stroke' ) {
+
+ if ( isImage.test( val ) ) {
+
+ val = _this.root().defs().image( val )
+
}
+
}
- if (val instanceof Image) {
- val = _this.root().defs().pattern(0, 0, (pattern) => {
- pattern.add(val)
- })
+ if ( val instanceof Image ) {
+
+ val = _this.root().defs().pattern( 0, 0, ( pattern ) => {
+
+ pattern.add( val )
+
+ } )
+
}
return val
-})
-registerMethods({
+} )
+
+registerMethods( {
Container: {
// create image element, load image and set its size
- image: wrapWithAttrCheck(function (source, callback) {
- return this.put(new Image()).size(0, 0).load(source, callback)
- })
+ image: wrapWithAttrCheck( function ( source, callback ) {
+
+ return this.put( new Image() ).size( 0, 0 ).load( source, callback )
+
+ } )
}
-})
+} )
-register(Image)
+register( Image )
diff --git a/src/elements/Line.js b/src/elements/Line.js
index 99e7497..123f2bb 100644
--- a/src/elements/Line.js
+++ b/src/elements/Line.js
@@ -11,58 +11,78 @@ import Shape from './Shape.js'
import * as pointed from '../modules/core/pointed.js'
export default class Line extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('line', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'line', node ), node )
+
}
// Get array
array () {
- return new PointArray([
- [ this.attr('x1'), this.attr('y1') ],
- [ this.attr('x2'), this.attr('y2') ]
- ])
+
+ return new PointArray( [
+ [ this.attr( 'x1' ), this.attr( 'y1' ) ],
+ [ this.attr( 'x2' ), this.attr( 'y2' ) ]
+ ] )
+
}
// Overwrite native plot() method
- plot (x1, y1, x2, y2) {
- if (x1 == null) {
+ plot ( x1, y1, x2, y2 ) {
+
+ if ( x1 == null ) {
+
return this.array()
- } else if (typeof y1 !== 'undefined') {
+
+ } else if ( typeof y1 !== 'undefined' ) {
+
x1 = { x1: x1, y1: y1, x2: x2, y2: y2 }
+
} else {
- x1 = new PointArray(x1).toLine()
+
+ x1 = new PointArray( x1 ).toLine()
+
}
- return this.attr(x1)
+ return this.attr( x1 )
+
}
// Move by left top corner
- move (x, y) {
- return this.attr(this.array().move(x, y).toLine())
+ move ( x, y ) {
+
+ return this.attr( this.array().move( x, y ).toLine() )
+
}
// Set element size to given width and height
- size (width, height) {
- var p = proportionalSize(this, width, height)
- return this.attr(this.array().size(p.width, p.height).toLine())
+ size ( width, height ) {
+
+ var p = proportionalSize( this, width, height )
+ return this.attr( this.array().size( p.width, p.height ).toLine() )
+
}
+
}
-extend(Line, pointed)
+extend( Line, pointed )
-registerMethods({
+registerMethods( {
Container: {
// Create a line element
- line: wrapWithAttrCheck(function (...args) {
+ line: wrapWithAttrCheck( function ( ...args ) {
+
// make sure plot is called as a setter
// x1 is not necessarily a number, it can also be an array, a string and a PointArray
return Line.prototype.plot.apply(
- this.put(new Line())
- , args[0] != null ? args : [0, 0, 0, 0]
+ this.put( new Line() )
+ , args[0] != null ? args : [ 0, 0, 0, 0 ]
)
- })
+
+ } )
}
-})
+} )
-register(Line)
+register( Line )
diff --git a/src/elements/Marker.js b/src/elements/Marker.js
index d40d13b..1054987 100644
--- a/src/elements/Marker.js
+++ b/src/elements/Marker.js
@@ -3,79 +3,103 @@ import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
export default class Marker extends Container {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('marker', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'marker', node ), node )
+
}
// Set width of element
- width (width) {
- return this.attr('markerWidth', width)
+ width ( width ) {
+
+ return this.attr( 'markerWidth', width )
+
}
// Set height of element
- height (height) {
- return this.attr('markerHeight', height)
+ height ( height ) {
+
+ return this.attr( 'markerHeight', height )
+
}
// Set marker refX and refY
- ref (x, y) {
- return this.attr('refX', x).attr('refY', y)
+ ref ( x, y ) {
+
+ return this.attr( 'refX', x ).attr( 'refY', y )
+
}
// Update marker
- update (block) {
+ update ( block ) {
+
// remove all content
this.clear()
// invoke passed block
- if (typeof block === 'function') { block.call(this, this) }
+ if ( typeof block === 'function' ) {
+
+ block.call( this, this )
+
+ }
return this
+
}
// Return the fill id
toString () {
+
return 'url(#' + this.id() + ')'
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
- marker (...args) {
+ marker ( ...args ) {
+
// Create marker element in defs
- return this.defs().marker(...args)
+ return this.defs().marker( ...args )
+
}
},
Defs: {
// Create marker
- marker: wrapWithAttrCheck(function (width, height, block) {
+ marker: wrapWithAttrCheck( function ( width, height, block ) {
+
// Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
- return this.put(new Marker())
- .size(width, height)
- .ref(width / 2, height / 2)
- .viewbox(0, 0, width, height)
- .attr('orient', 'auto')
- .update(block)
- })
+ return this.put( new Marker() )
+ .size( width, height )
+ .ref( width / 2, height / 2 )
+ .viewbox( 0, 0, width, height )
+ .attr( 'orient', 'auto' )
+ .update( block )
+
+ } )
},
marker: {
// Create and attach markers
- marker (marker, width, height, block) {
- var attr = ['marker']
+ marker ( marker, width, height, block ) {
+
+ var attr = [ 'marker' ]
// Build attribute name
- if (marker !== 'all') attr.push(marker)
- attr = attr.join('-')
+ if ( marker !== 'all' ) attr.push( marker )
+ attr = attr.join( '-' )
// Set marker attribute
marker = arguments[1] instanceof Marker
? arguments[1]
- : this.defs().marker(width, height, block)
+ : this.defs().marker( width, height, block )
+
+ return this.attr( attr, marker )
- return this.attr(attr, marker)
}
}
-})
+} )
-register(Marker)
+register( Marker )
diff --git a/src/elements/Mask.js b/src/elements/Mask.js
index 8dfffd6..523b9de 100644
--- a/src/elements/Mask.js
+++ b/src/elements/Mask.js
@@ -4,54 +4,72 @@ import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class Mask extends Container {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('mask', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'mask', node ), node )
+
}
// Unmask all masked elements and remove itself
remove () {
+
// unmask all targets
- this.targets().forEach(function (el) {
+ this.targets().forEach( function ( el ) {
+
el.unmask()
- })
+
+ } )
// remove mask from parent
return super.remove()
+
}
targets () {
- return baseFind('svg [mask*="' + this.id() + '"]')
+
+ return baseFind( 'svg [mask*="' + this.id() + '"]' )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
- mask: wrapWithAttrCheck(function () {
- return this.defs().put(new Mask())
- })
+ mask: wrapWithAttrCheck( function () {
+
+ return this.defs().put( new Mask() )
+
+ } )
},
Element: {
// Distribute mask to svg element
- maskWith (element) {
+ maskWith ( element ) {
+
// use given mask or create a new one
var masker = element instanceof Mask
? element
- : this.parent().mask().add(element)
+ : this.parent().mask().add( element )
// apply mask
- return this.attr('mask', 'url("#' + masker.id() + '")')
+ return this.attr( 'mask', 'url("#' + masker.id() + '")' )
+
},
// Unmask element
unmask () {
- return this.attr('mask', null)
+
+ return this.attr( 'mask', null )
+
},
masker () {
- return this.reference('mask')
+
+ return this.reference( 'mask' )
+
}
}
-})
+} )
-register(Mask)
+register( Mask )
diff --git a/src/elements/Path.js b/src/elements/Path.js
index dc27320..1fe5661 100644
--- a/src/elements/Path.js
+++ b/src/elements/Path.js
@@ -6,76 +6,102 @@ import Shape from './Shape.js'
import baseFind from '../modules/core/selector.js'
export default class Path extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('path', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'path', node ), node )
+
}
// Get array
array () {
- return this._array || (this._array = new PathArray(this.attr('d')))
+
+ return this._array || ( this._array = new PathArray( this.attr( 'd' ) ) )
+
}
// Plot new path
- plot (d) {
- return (d == null) ? this.array()
- : this.clear().attr('d', typeof d === 'string' ? d : (this._array = new PathArray(d)))
+ plot ( d ) {
+
+ return ( d == null ) ? this.array()
+ : this.clear().attr( 'd', typeof d === 'string' ? d : ( this._array = new PathArray( d ) ) )
+
}
// Clear array cache
clear () {
+
delete this._array
return this
+
}
// Move by left top corner
- move (x, y) {
- return this.attr('d', this.array().move(x, y))
+ move ( x, y ) {
+
+ return this.attr( 'd', this.array().move( x, y ) )
+
}
// Move by left top corner over x-axis
- x (x) {
- return x == null ? this.bbox().x : this.move(x, this.bbox().y)
+ x ( x ) {
+
+ return x == null ? this.bbox().x : this.move( x, this.bbox().y )
+
}
// Move by left top corner over y-axis
- y (y) {
- return y == null ? this.bbox().y : this.move(this.bbox().x, y)
+ y ( y ) {
+
+ return y == null ? this.bbox().y : this.move( this.bbox().x, y )
+
}
// Set element size to given width and height
- size (width, height) {
- var p = proportionalSize(this, width, height)
- return this.attr('d', this.array().size(p.width, p.height))
+ size ( width, height ) {
+
+ var p = proportionalSize( this, width, height )
+ return this.attr( 'd', this.array().size( p.width, p.height ) )
+
}
// Set width of element
- width (width) {
- return width == null ? this.bbox().width : this.size(width, this.bbox().height)
+ width ( width ) {
+
+ return width == null ? this.bbox().width : this.size( width, this.bbox().height )
+
}
// Set height of element
- height (height) {
- return height == null ? this.bbox().height : this.size(this.bbox().width, height)
+ height ( height ) {
+
+ return height == null ? this.bbox().height : this.size( this.bbox().width, height )
+
}
targets () {
- return baseFind('svg textpath [href*="' + this.id() + '"]')
+
+ return baseFind( 'svg textpath [href*="' + this.id() + '"]' )
+
}
+
}
// Define morphable array
Path.prototype.MorphArray = PathArray
// Add parent method
-registerMethods({
+registerMethods( {
Container: {
// Create a wrapped path element
- path: wrapWithAttrCheck(function (d) {
+ path: wrapWithAttrCheck( function ( d ) {
+
// make sure plot is called as a setter
- return this.put(new Path()).plot(d || new PathArray())
- })
+ return this.put( new Path() ).plot( d || new PathArray() )
+
+ } )
}
-})
+} )
-register(Path)
+register( Path )
diff --git a/src/elements/Pattern.js b/src/elements/Pattern.js
index 6dd4e01..6f7897b 100644
--- a/src/elements/Pattern.js
+++ b/src/elements/Pattern.js
@@ -5,67 +5,89 @@ import Container from './Container.js'
import baseFind from '../modules/core/selector.js'
export default class Pattern extends Container {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('pattern', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'pattern', node ), node )
+
}
// Return the fill id
url () {
+
return 'url(#' + this.id() + ')'
+
}
// Update pattern by rebuilding
- update (block) {
+ update ( block ) {
+
// remove content
this.clear()
// invoke passed block
- if (typeof block === 'function') {
- block.call(this, this)
+ if ( typeof block === 'function' ) {
+
+ block.call( this, this )
+
}
return this
+
}
// Alias string convertion to fill
toString () {
+
return this.url()
+
}
// custom attr to handle transform
- attr (a, b, c) {
- if (a === 'transform') a = 'patternTransform'
- return super.attr(a, b, c)
+ attr ( a, b, c ) {
+
+ if ( a === 'transform' ) a = 'patternTransform'
+ return super.attr( a, b, c )
+
}
targets () {
- return baseFind('svg [fill*="' + this.id() + '"]')
+
+ return baseFind( 'svg [fill*="' + this.id() + '"]' )
+
}
bbox () {
+
return new Box()
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create pattern element in defs
- pattern (...args) {
- return this.defs().pattern(...args)
+ pattern ( ...args ) {
+
+ return this.defs().pattern( ...args )
+
}
},
Defs: {
- pattern: wrapWithAttrCheck(function (width, height, block) {
- return this.put(new Pattern()).update(block).attr({
+ pattern: wrapWithAttrCheck( function ( width, height, block ) {
+
+ return this.put( new Pattern() ).update( block ).attr( {
x: 0,
y: 0,
width: width,
height: height,
patternUnits: 'userSpaceOnUse'
- })
- })
+ } )
+
+ } )
}
-})
+} )
-register(Pattern)
+register( Pattern )
diff --git a/src/elements/Polygon.js b/src/elements/Polygon.js
index afa5f31..2288b75 100644
--- a/src/elements/Polygon.js
+++ b/src/elements/Polygon.js
@@ -11,22 +11,28 @@ import * as pointed from '../modules/core/pointed.js'
import * as poly from '../modules/core/poly.js'
export default class Polygon extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('polygon', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'polygon', node ), node )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create a wrapped polygon element
- polygon: wrapWithAttrCheck(function (p) {
+ polygon: wrapWithAttrCheck( function ( p ) {
+
// make sure plot is called as a setter
- return this.put(new Polygon()).plot(p || new PointArray())
- })
+ return this.put( new Polygon() ).plot( p || new PointArray() )
+
+ } )
}
-})
+} )
-extend(Polygon, pointed)
-extend(Polygon, poly)
-register(Polygon)
+extend( Polygon, pointed )
+extend( Polygon, poly )
+register( Polygon )
diff --git a/src/elements/Polyline.js b/src/elements/Polyline.js
index 5897295..3749c93 100644
--- a/src/elements/Polyline.js
+++ b/src/elements/Polyline.js
@@ -11,22 +11,28 @@ import * as pointed from '../modules/core/pointed.js'
import * as poly from '../modules/core/poly.js'
export default class Polyline extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('polyline', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'polyline', node ), node )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create a wrapped polygon element
- polyline: wrapWithAttrCheck(function (p) {
+ polyline: wrapWithAttrCheck( function ( p ) {
+
// make sure plot is called as a setter
- return this.put(new Polyline()).plot(p || new PointArray())
- })
+ return this.put( new Polyline() ).plot( p || new PointArray() )
+
+ } )
}
-})
+} )
-extend(Polyline, pointed)
-extend(Polyline, poly)
-register(Polyline)
+extend( Polyline, pointed )
+extend( Polyline, poly )
+register( Polyline )
diff --git a/src/elements/Rect.js b/src/elements/Rect.js
index 6e161c9..465b52b 100644
--- a/src/elements/Rect.js
+++ b/src/elements/Rect.js
@@ -9,21 +9,27 @@ import { rx, ry } from '../modules/core/circled.js'
import Shape from './Shape.js'
export default class Rect extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('rect', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'rect', node ), node )
+
}
+
}
-extend(Rect, { rx, ry })
+extend( Rect, { rx, ry } )
-registerMethods({
+registerMethods( {
Container: {
// Create a rect element
- rect: wrapWithAttrCheck(function (width, height) {
- return this.put(new Rect()).size(width, height)
- })
+ rect: wrapWithAttrCheck( function ( width, height ) {
+
+ return this.put( new Rect() ).size( width, height )
+
+ } )
}
-})
+} )
-register(Rect)
+register( Rect )
diff --git a/src/elements/Shape.js b/src/elements/Shape.js
index cdddc60..0d5a5b0 100644
--- a/src/elements/Shape.js
+++ b/src/elements/Shape.js
@@ -3,4 +3,4 @@ import Element from './Element.js'
export default class Shape extends Element {}
-register(Shape)
+register( Shape )
diff --git a/src/elements/Stop.js b/src/elements/Stop.js
index 9a5acaa..8838923 100644
--- a/src/elements/Stop.js
+++ b/src/elements/Stop.js
@@ -3,27 +3,35 @@ import Element from './Element.js'
import SVGNumber from '../types/SVGNumber.js'
export default class Stop extends Element {
- constructor (node) {
- super(nodeOrNew('stop', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'stop', node ), node )
+
}
// add color stops
- update (o) {
- if (typeof o === 'number' || o instanceof SVGNumber) {
+ update ( o ) {
+
+ if ( typeof o === 'number' || o instanceof SVGNumber ) {
+
o = {
offset: arguments[0],
color: arguments[1],
opacity: arguments[2]
}
+
}
// set attributes
- if (o.opacity != null) this.attr('stop-opacity', o.opacity)
- if (o.color != null) this.attr('stop-color', o.color)
- if (o.offset != null) this.attr('offset', new SVGNumber(o.offset))
+ if ( o.opacity != null ) this.attr( 'stop-opacity', o.opacity )
+ if ( o.color != null ) this.attr( 'stop-color', o.color )
+ if ( o.offset != null ) this.attr( 'offset', new SVGNumber( o.offset ) )
return this
+
}
+
}
-register(Stop)
+register( Stop )
diff --git a/src/elements/Style.js b/src/elements/Style.js
index 50ec50e..643f356 100644
--- a/src/elements/Style.js
+++ b/src/elements/Style.js
@@ -3,51 +3,69 @@ import { registerMethods } from '../utils/methods.js'
import { unCamelCase } from '../utils/utils.js'
import Element from './Element.js'
-function cssRule (selector, rule) {
- if (!selector) return ''
- if (!rule) return selector
+function cssRule ( selector, rule ) {
+
+ if ( !selector ) return ''
+ if ( !rule ) return selector
var ret = selector + '{'
- for (var i in rule) {
- ret += unCamelCase(i) + ':' + rule[i] + ';'
+ for ( var i in rule ) {
+
+ ret += unCamelCase( i ) + ':' + rule[i] + ';'
+
}
ret += '}'
return ret
+
}
export default class Style extends Element {
- constructor (node) {
- super(nodeOrNew('style', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'style', node ), node )
+
}
- words (w) {
- this.node.textContent += (w || '')
+ words ( w ) {
+
+ this.node.textContent += ( w || '' )
return this
+
}
- font (name, src, params = {}) {
- return this.rule('@font-face', {
+ font ( name, src, params = {} ) {
+
+ return this.rule( '@font-face', {
fontFamily: name,
src: src,
...params
- })
+ } )
+
}
- rule (selector, obj) {
- return this.words(cssRule(selector, obj))
+ rule ( selector, obj ) {
+
+ return this.words( cssRule( selector, obj ) )
+
}
+
}
-registerMethods('Dom', {
- style: wrapWithAttrCheck(function (selector, obj) {
- return this.put(new Style()).rule(selector, obj)
- }),
- fontface: wrapWithAttrCheck(function (name, src, params) {
- return this.put(new Style()).font(name, src, params)
- })
-})
+registerMethods( 'Dom', {
+ style: wrapWithAttrCheck( function ( selector, obj ) {
+
+ return this.put( new Style() ).rule( selector, obj )
+
+ } ),
+ fontface: wrapWithAttrCheck( function ( name, src, params ) {
+
+ return this.put( new Style() ).font( name, src, params )
+
+ } )
+} )
-register(Style)
+register( Style )
diff --git a/src/elements/Svg.js b/src/elements/Svg.js
index 6172454..1326900 100644
--- a/src/elements/Svg.js
+++ b/src/elements/Svg.js
@@ -11,68 +11,90 @@ import Defs from './Defs.js'
import { globals } from '../utils/window.js'
export default class Svg extends Container {
- constructor (node) {
- super(nodeOrNew('svg', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'svg', node ), node )
this.namespace()
+
}
isRoot () {
- return !this.node.parentNode ||
- !(this.node.parentNode instanceof globals.window.SVGElement) ||
- this.node.parentNode.nodeName === '#document'
+
+ return !this.node.parentNode
+ || !( this.node.parentNode instanceof globals.window.SVGElement )
+ || this.node.parentNode.nodeName === '#document'
+
}
// Check if this is a root svg
// If not, call docs from this element
root () {
- if (this.isRoot()) return this
+
+ if ( this.isRoot() ) return this
return super.root()
+
}
// Add namespaces
namespace () {
- if (!this.isRoot()) return this.root().namespace()
+
+ if ( !this.isRoot() ) return this.root().namespace()
return this
- .attr({ xmlns: ns, version: '1.1' })
- .attr('xmlns:xlink', xlink, xmlns)
- .attr('xmlns:svgjs', svgjs, xmlns)
+ .attr( { xmlns: ns, version: '1.1' } )
+ .attr( 'xmlns:xlink', xlink, xmlns )
+ .attr( 'xmlns:svgjs', svgjs, xmlns )
+
}
// Creates and returns defs element
defs () {
- if (!this.isRoot()) return this.root().defs()
- return adopt(this.node.getElementsByTagName('defs')[0]) ||
- this.put(new Defs())
+ if ( !this.isRoot() ) return this.root().defs()
+
+ return adopt( this.node.getElementsByTagName( 'defs' )[0] )
+ || this.put( new Defs() )
+
}
// custom parent method
- parent (type) {
- if (this.isRoot()) {
+ parent ( type ) {
+
+ if ( this.isRoot() ) {
+
return this.node.parentNode.nodeName === '#document'
? null
- : adopt(this.node.parentNode)
+ : adopt( this.node.parentNode )
+
}
- return super.parent(type)
+ return super.parent( type )
+
}
clear () {
+
// remove children
- while (this.node.hasChildNodes()) {
- this.node.removeChild(this.node.lastChild)
+ while ( this.node.hasChildNodes() ) {
+
+ this.node.removeChild( this.node.lastChild )
+
}
return this
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create nested svg document
- nested: wrapWithAttrCheck(function () {
- return this.put(new Svg())
- })
+ nested: wrapWithAttrCheck( function () {
+
+ return this.put( new Svg() )
+
+ } )
}
-})
+} )
-register(Svg, 'Svg', true)
+register( Svg, 'Svg', true )
diff --git a/src/elements/Symbol.js b/src/elements/Symbol.js
index f44125c..577d1f1 100644
--- a/src/elements/Symbol.js
+++ b/src/elements/Symbol.js
@@ -3,18 +3,24 @@ import { registerMethods } from '../utils/methods.js'
import Container from './Container.js'
export default class Symbol extends Container {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('symbol', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'symbol', node ), node )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
- symbol: wrapWithAttrCheck(function () {
- return this.put(new Symbol())
- })
+ symbol: wrapWithAttrCheck( function () {
+
+ return this.put( new Symbol() )
+
+ } )
}
-})
+} )
-register(Symbol)
+register( Symbol )
diff --git a/src/elements/Text.js b/src/elements/Text.js
index db9c2ee..a981d73 100644
--- a/src/elements/Text.js
+++ b/src/elements/Text.js
@@ -13,175 +13,233 @@ import { globals } from '../utils/window.js'
import * as textable from '../modules/core/textable.js'
export default class Text extends Shape {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('text', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'text', node ), node )
- this.dom.leading = new SVGNumber(1.3) // store leading value for rebuilding
+ this.dom.leading = new SVGNumber( 1.3 ) // store leading value for rebuilding
this._rebuild = true // enable automatic updating of dy values
this._build = false // disable build mode for adding multiple lines
// set default font
- this.attr('font-family', attrs['font-family'])
+ this.attr( 'font-family', attrs['font-family'] )
+
}
// Move over x-axis
- x (x) {
+ x ( x ) {
+
// act as getter
- if (x == null) {
- return this.attr('x')
+ if ( x == null ) {
+
+ return this.attr( 'x' )
+
}
- return this.attr('x', x)
+ return this.attr( 'x', x )
+
}
// Move over y-axis
- y (y) {
- var oy = this.attr('y')
+ y ( y ) {
+
+ var oy = this.attr( 'y' )
var o = typeof oy === 'number' ? oy - this.bbox().y : 0
// act as getter
- if (y == null) {
+ if ( y == null ) {
+
return typeof oy === 'number' ? oy - o : oy
+
}
- return this.attr('y', typeof y === 'number' ? y + o : y)
+ return this.attr( 'y', typeof y === 'number' ? y + o : y )
+
}
// Move center over x-axis
- cx (x) {
- return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
+ cx ( x ) {
+
+ return x == null ? this.bbox().cx : this.x( x - this.bbox().width / 2 )
+
}
// Move center over y-axis
- cy (y) {
- return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
+ cy ( y ) {
+
+ return y == null ? this.bbox().cy : this.y( y - this.bbox().height / 2 )
+
}
// Set the text content
- text (text) {
+ text ( text ) {
+
// act as getter
- if (text === undefined) {
+ if ( text === undefined ) {
+
var children = this.node.childNodes
var firstLine = 0
text = ''
- for (var i = 0, len = children.length; i < len; ++i) {
+ for ( var i = 0, len = children.length; i < len; ++i ) {
+
// skip textPaths - they are no lines
- if (children[i].nodeName === 'textPath') {
- if (i === 0) firstLine = 1
+ if ( children[i].nodeName === 'textPath' ) {
+
+ if ( i === 0 ) firstLine = 1
continue
+
}
// add newline if its not the first child and newLined is set to true
- if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
+ if ( i !== firstLine && children[i].nodeType !== 3 && adopt( children[i] ).dom.newLined === true ) {
+
text += '\n'
+
}
// add content of this node
text += children[i].textContent
+
}
return text
+
}
// remove existing content
- this.clear().build(true)
+ this.clear().build( true )
+
+ if ( typeof text === 'function' ) {
- if (typeof text === 'function') {
// call block
- text.call(this, this)
+ text.call( this, this )
+
} else {
+
// store text and make sure text is not blank
- text = text.split('\n')
+ text = text.split( '\n' )
// build new lines
- for (var j = 0, jl = text.length; j < jl; j++) {
- this.tspan(text[j]).newLine()
+ for ( var j = 0, jl = text.length; j < jl; j++ ) {
+
+ this.tspan( text[j] ).newLine()
+
}
+
}
// disable build mode and rebuild lines
- return this.build(false).rebuild()
+ return this.build( false ).rebuild()
+
}
// Set / get leading
- leading (value) {
+ leading ( value ) {
+
// act as getter
- if (value == null) {
+ if ( value == null ) {
+
return this.dom.leading
+
}
// act as setter
- this.dom.leading = new SVGNumber(value)
+ this.dom.leading = new SVGNumber( value )
return this.rebuild()
+
}
// Rebuild appearance type
- rebuild (rebuild) {
+ rebuild ( rebuild ) {
+
// store new rebuild flag if given
- if (typeof rebuild === 'boolean') {
+ if ( typeof rebuild === 'boolean' ) {
+
this._rebuild = rebuild
+
}
// define position of all lines
- if (this._rebuild) {
+ if ( this._rebuild ) {
+
var self = this
var blankLineOffset = 0
var leading = this.dom.leading
- this.each(function () {
- var fontSize = globals.window.getComputedStyle(this.node)
- .getPropertyValue('font-size')
- var dy = leading * new SVGNumber(fontSize)
+ this.each( function () {
+
+ var fontSize = globals.window.getComputedStyle( this.node )
+ .getPropertyValue( 'font-size' )
+ var dy = leading * new SVGNumber( fontSize )
+
+ if ( this.dom.newLined ) {
- if (this.dom.newLined) {
- this.attr('x', self.attr('x'))
+ this.attr( 'x', self.attr( 'x' ) )
+
+ if ( this.text() === '\n' ) {
- if (this.text() === '\n') {
blankLineOffset += dy
+
} else {
- this.attr('dy', dy + blankLineOffset)
+
+ this.attr( 'dy', dy + blankLineOffset )
blankLineOffset = 0
+
}
+
}
- })
- this.fire('rebuild')
+ } )
+
+ this.fire( 'rebuild' )
+
}
return this
+
}
// Enable / disable build mode
- build (build) {
+ build ( build ) {
+
this._build = !!build
return this
+
}
// overwrite method from parent to set data properly
- setData (o) {
+ setData ( o ) {
+
this.dom = o
- this.dom.leading = new SVGNumber(o.leading || 1.3)
+ this.dom.leading = new SVGNumber( o.leading || 1.3 )
return this
+
}
+
}
-extend(Text, textable)
+extend( Text, textable )
-registerMethods({
+registerMethods( {
Container: {
// Create text element
- text: wrapWithAttrCheck(function (text) {
- return this.put(new Text()).text(text)
- }),
+ text: wrapWithAttrCheck( function ( text ) {
+
+ return this.put( new Text() ).text( text )
+
+ } ),
// Create plain text element
- plain: wrapWithAttrCheck(function (text) {
- return this.put(new Text()).plain(text)
- })
+ plain: wrapWithAttrCheck( function ( text ) {
+
+ return this.put( new Text() ).plain( text )
+
+ } )
}
-})
+} )
-register(Text)
+register( Text )
diff --git a/src/elements/TextPath.js b/src/elements/TextPath.js
index 91c48ae..af89ef7 100644
--- a/src/elements/TextPath.js
+++ b/src/elements/TextPath.js
@@ -7,80 +7,106 @@ import Text from './Text.js'
import baseFind from '../modules/core/selector.js'
export default class TextPath extends Text {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('textPath', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'textPath', node ), node )
+
}
// return the array of the path track element
array () {
+
var track = this.track()
return track ? track.array() : null
+
}
// Plot path if any
- plot (d) {
+ plot ( d ) {
+
var track = this.track()
var pathArray = null
- if (track) {
- pathArray = track.plot(d)
+ if ( track ) {
+
+ pathArray = track.plot( d )
+
}
- return (d == null) ? pathArray : this
+ return ( d == null ) ? pathArray : this
+
}
// Get the path element
track () {
- return this.reference('href')
+
+ return this.reference( 'href' )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
- textPath: wrapWithAttrCheck(function (text, path) {
- return this.defs().path(path).text(text).addTo(this)
- })
+ textPath: wrapWithAttrCheck( function ( text, path ) {
+
+ return this.defs().path( path ).text( text ).addTo( this )
+
+ } )
},
Text: {
// Create path for text to run on
- path: wrapWithAttrCheck(function (track) {
+ path: wrapWithAttrCheck( function ( track ) {
+
var path = new TextPath()
// if track is a path, reuse it
- if (!(track instanceof Path)) {
+ if ( !( track instanceof Path ) ) {
+
// create path element
- track = this.root().defs().path(track)
+ track = this.root().defs().path( track )
+
}
// link textPath to path and add content
- path.attr('href', '#' + track, xlink)
+ path.attr( 'href', '#' + track, xlink )
// add textPath element as child node and return textPath
- return this.put(path)
- }),
+ return this.put( path )
+
+ } ),
// Get the textPath children
textPath () {
- return this.find('textPath')[0]
+
+ return this.find( 'textPath' )[0]
+
}
},
Path: {
// creates a textPath from this path
- text: wrapWithAttrCheck(function (text) {
- if (text instanceof Text) {
+ text: wrapWithAttrCheck( function ( text ) {
+
+ if ( text instanceof Text ) {
+
var txt = text.text()
- return text.clear().path(this).text(txt)
+ return text.clear().path( this ).text( txt )
+
}
- return this.parent().put(new Text()).path(this).text(text)
- }),
+ return this.parent().put( new Text() ).path( this ).text( text )
+
+ } ),
targets () {
- return baseFind('svg [href*="' + this.id() + '"]')
+
+ return baseFind( 'svg [href*="' + this.id() + '"]' )
+
}
}
-})
+} )
TextPath.prototype.MorphArray = PathArray
-register(TextPath)
+register( TextPath )
diff --git a/src/elements/Tspan.js b/src/elements/Tspan.js
index abd032f..fcf8cf5 100644
--- a/src/elements/Tspan.js
+++ b/src/elements/Tspan.js
@@ -9,61 +9,77 @@ import Text from './Text.js'
import * as textable from '../modules/core/textable.js'
export default class Tspan extends Text {
+
// Initialize node
- constructor (node) {
- super(nodeOrNew('tspan', node), node)
+ constructor ( node ) {
+
+ super( nodeOrNew( 'tspan', node ), node )
+
}
// Set text content
- text (text) {
- if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '')
+ text ( text ) {
+
+ if ( text == null ) return this.node.textContent + ( this.dom.newLined ? '\n' : '' )
- typeof text === 'function' ? text.call(this, this) : this.plain(text)
+ typeof text === 'function' ? text.call( this, this ) : this.plain( text )
return this
+
}
// Shortcut dx
- dx (dx) {
- return this.attr('dx', dx)
+ dx ( dx ) {
+
+ return this.attr( 'dx', dx )
+
}
// Shortcut dy
- dy (dy) {
- return this.attr('dy', dy)
+ dy ( dy ) {
+
+ return this.attr( 'dy', dy )
+
}
// Create new line
newLine () {
+
// fetch text parent
- var t = this.parent(Text)
+ var t = this.parent( Text )
// mark new line
this.dom.newLined = true
// apply new position
- return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())
+ return this.dy( t.dom.leading * t.attr( 'font-size' ) ).attr( 'x', t.x() )
+
}
+
}
-extend(Tspan, textable)
+extend( Tspan, textable )
-registerMethods({
+registerMethods( {
Tspan: {
- tspan: wrapWithAttrCheck(function (text) {
+ tspan: wrapWithAttrCheck( function ( text ) {
+
var tspan = new Tspan()
// clear if build mode is disabled
- if (!this._build) {
+ if ( !this._build ) {
+
this.clear()
+
}
// add new tspan
- this.node.appendChild(tspan.node)
+ this.node.appendChild( tspan.node )
+
+ return tspan.text( text )
- return tspan.text(text)
- })
+ } )
}
-})
+} )
-register(Tspan)
+register( Tspan )
diff --git a/src/elements/Use.js b/src/elements/Use.js
index 7921461..9237e08 100644
--- a/src/elements/Use.js
+++ b/src/elements/Use.js
@@ -4,24 +4,32 @@ import { xlink } from '../modules/core/namespaces.js'
import Shape from './Shape.js'
export default class Use extends Shape {
- constructor (node) {
- super(nodeOrNew('use', node), node)
+
+ constructor ( node ) {
+
+ super( nodeOrNew( 'use', node ), node )
+
}
// Use element as a reference
- element (element, file) {
+ element ( element, file ) {
+
// Set lined element
- return this.attr('href', (file || '') + '#' + element, xlink)
+ return this.attr( 'href', ( file || '' ) + '#' + element, xlink )
+
}
+
}
-registerMethods({
+registerMethods( {
Container: {
// Create a use element
- use: wrapWithAttrCheck(function (element, file) {
- return this.put(new Use()).element(element, file)
- })
+ use: wrapWithAttrCheck( function ( element, file ) {
+
+ return this.put( new Use() ).element( element, file )
+
+ } )
}
-})
+} )
-register(Use)
+register( Use )
diff --git a/src/main.js b/src/main.js
index 919fb25..951cc69 100644
--- a/src/main.js
+++ b/src/main.js
@@ -116,50 +116,50 @@ export { default as TextPath } from './elements/TextPath.js'
export { default as Tspan } from './elements/Tspan.js'
export { default as Use } from './elements/Use.js'
-extend([
+extend( [
Svg,
Symbol,
Image,
Pattern,
Marker
-], getMethodsFor('viewbox'))
+], getMethodsFor( 'viewbox' ) )
-extend([
+extend( [
Line,
Polyline,
Polygon,
Path
-], getMethodsFor('marker'))
+], getMethodsFor( 'marker' ) )
-extend(Text, getMethodsFor('Text'))
-extend(Path, getMethodsFor('Path'))
+extend( Text, getMethodsFor( 'Text' ) )
+extend( Path, getMethodsFor( 'Path' ) )
-extend(Defs, getMethodsFor('Defs'))
+extend( Defs, getMethodsFor( 'Defs' ) )
-extend([
+extend( [
Text,
Tspan
-], getMethodsFor('Tspan'))
+], getMethodsFor( 'Tspan' ) )
-extend([
+extend( [
Rect,
Ellipse,
Circle,
Gradient
-], getMethodsFor('radius'))
+], getMethodsFor( 'radius' ) )
-extend(EventTarget, getMethodsFor('EventTarget'))
-extend(Dom, getMethodsFor('Dom'))
-extend(Element, getMethodsFor('Element'))
-extend(Shape, getMethodsFor('Shape'))
+extend( EventTarget, getMethodsFor( 'EventTarget' ) )
+extend( Dom, getMethodsFor( 'Dom' ) )
+extend( Element, getMethodsFor( 'Element' ) )
+extend( Shape, getMethodsFor( 'Shape' ) )
// extend(Element, getConstructor('Memory'))
-extend(Container, getMethodsFor('Container'))
+extend( Container, getMethodsFor( 'Container' ) )
-extend(Runner, getMethodsFor('Runner'))
+extend( Runner, getMethodsFor( 'Runner' ) )
-List.extend(getMethodNames())
+List.extend( getMethodNames() )
-registerMorphableType([
+registerMorphableType( [
SVGNumber,
Color,
Box,
@@ -167,6 +167,6 @@ registerMorphableType([
SVGArray,
PointArray,
PathArray
-])
+] )
makeMorphable()
diff --git a/src/modules/core/attr.js b/src/modules/core/attr.js
index f90dcb9..7cb9e2a 100644
--- a/src/modules/core/attr.js
+++ b/src/modules/core/attr.js
@@ -5,77 +5,113 @@ import SVGArray from '../../types/SVGArray.js'
import SVGNumber from '../../types/SVGNumber.js'
const hooks = []
-export function registerAttrHook (fn) {
- hooks.push(fn)
+export function registerAttrHook ( fn ) {
+
+ hooks.push( fn )
+
}
// Set svg element attribute
-export default function attr (attr, val, ns) {
+export default function attr ( attr, val, ns ) {
+
// act as full getter
- if (attr == null) {
+ if ( attr == null ) {
+
// get an object of attributes
attr = {}
val = this.node.attributes
- for (let node of val) {
- attr[node.nodeName] = isNumber.test(node.nodeValue)
- ? parseFloat(node.nodeValue)
+ for ( let node of val ) {
+
+ attr[node.nodeName] = isNumber.test( node.nodeValue )
+ ? parseFloat( node.nodeValue )
: node.nodeValue
+
}
return attr
- } else if (attr instanceof Array) {
+
+ } else if ( attr instanceof Array ) {
+
// loop through array and get all values
- return attr.reduce((last, curr) => {
- last[curr] = this.attr(curr)
+ return attr.reduce( ( last, curr ) => {
+
+ last[curr] = this.attr( curr )
return last
- }, {})
- } else if (typeof attr === 'object') {
+
+ }, {} )
+
+ } else if ( typeof attr === 'object' ) {
+
// apply every attribute individually if an object is passed
- for (val in attr) this.attr(val, attr[val])
- } else if (val === null) {
+ for ( val in attr ) this.attr( val, attr[val] )
+
+ } else if ( val === null ) {
+
// remove value
- this.node.removeAttribute(attr)
- } else if (val == null) {
+ this.node.removeAttribute( attr )
+
+ } else if ( val == null ) {
+
// act as a getter if the first and only argument is not an object
- val = this.node.getAttribute(attr)
+ val = this.node.getAttribute( attr )
return val == null ? defaults[attr]
- : isNumber.test(val) ? parseFloat(val)
- : val
+ : isNumber.test( val ) ? parseFloat( val )
+ : val
+
} else {
+
// Loop through hooks and execute them to convert value
- val = hooks.reduce((_val, hook) => {
- return hook(attr, _val, this)
- }, val)
+ val = hooks.reduce( ( _val, hook ) => {
+
+ return hook( attr, _val, this )
+
+ }, val )
// ensure correct numeric values (also accepts NaN and Infinity)
- if (typeof val === 'number') {
- val = new SVGNumber(val)
- } else if (Color.isColor(val)) {
+ if ( typeof val === 'number' ) {
+
+ val = new SVGNumber( val )
+
+ } else if ( Color.isColor( val ) ) {
+
// ensure full hex color
- val = new Color(val)
- } else if (val.constructor === Array) {
+ val = new Color( val )
+
+ } else if ( val.constructor === Array ) {
+
// Check for plain arrays and parse array values
- val = new SVGArray(val)
+ val = new SVGArray( val )
+
}
// if the passed attribute is leading...
- if (attr === 'leading') {
+ if ( attr === 'leading' ) {
+
// ... call the leading method instead
- if (this.leading) {
- this.leading(val)
+ if ( this.leading ) {
+
+ this.leading( val )
+
}
+
} else {
+
// set given attribute on node
- typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString())
- : this.node.setAttribute(attr, val.toString())
+ typeof ns === 'string' ? this.node.setAttributeNS( ns, attr, val.toString() )
+ : this.node.setAttribute( attr, val.toString() )
+
}
// rebuild if required
- if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
+ if ( this.rebuild && ( attr === 'font-size' || attr === 'x' ) ) {
+
this.rebuild()
+
}
+
}
return this
+
}
diff --git a/src/modules/core/circled.js b/src/modules/core/circled.js
index 597d252..ad901b9 100644
--- a/src/modules/core/circled.js
+++ b/src/modules/core/circled.js
@@ -1,53 +1,69 @@
import SVGNumber from '../../types/SVGNumber.js'
// Radius x value
-export function rx (rx) {
- return this.attr('rx', rx)
+export function rx ( rx ) {
+
+ return this.attr( 'rx', rx )
+
}
// Radius y value
-export function ry (ry) {
- return this.attr('ry', ry)
+export function ry ( ry ) {
+
+ return this.attr( 'ry', ry )
+
}
// Move over x-axis
-export function x (x) {
+export function x ( x ) {
+
return x == null
? this.cx() - this.rx()
- : this.cx(x + this.rx())
+ : this.cx( x + this.rx() )
+
}
// Move over y-axis
-export function y (y) {
+export function y ( y ) {
+
return y == null
? this.cy() - this.ry()
- : this.cy(y + this.ry())
+ : this.cy( y + this.ry() )
+
}
// Move by center over x-axis
-export function cx (x) {
+export function cx ( x ) {
+
return x == null
- ? this.attr('cx')
- : this.attr('cx', x)
+ ? this.attr( 'cx' )
+ : this.attr( 'cx', x )
+
}
// Move by center over y-axis
-export function cy (y) {
+export function cy ( y ) {
+
return y == null
- ? this.attr('cy')
- : this.attr('cy', y)
+ ? this.attr( 'cy' )
+ : this.attr( 'cy', y )
+
}
// Set width of element
-export function width (width) {
+export function width ( width ) {
+
return width == null
? this.rx() * 2
- : this.rx(new SVGNumber(width).divide(2))
+ : this.rx( new SVGNumber( width ).divide( 2 ) )
+
}
// Set height of element
-export function height (height) {
+export function height ( height ) {
+
return height == null
? this.ry() * 2
- : this.ry(new SVGNumber(height).divide(2))
+ : this.ry( new SVGNumber( height ).divide( 2 ) )
+
}
diff --git a/src/modules/core/event.js b/src/modules/core/event.js
index a52a744..23459fb 100644
--- a/src/modules/core/event.js
+++ b/src/modules/core/event.js
@@ -4,38 +4,48 @@ import { globals } from '../../utils/window.js'
let listenerId = 0
-function getEvents (node) {
- const n = makeInstance(node).getEventHolder()
- if (!n.events) n.events = {}
+function getEvents ( node ) {
+
+ const n = makeInstance( node ).getEventHolder()
+ if ( !n.events ) n.events = {}
return n.events
+
}
-function getEventTarget (node) {
- return makeInstance(node).getEventTarget()
+function getEventTarget ( node ) {
+
+ return makeInstance( node ).getEventTarget()
+
}
-function clearEvents (node) {
- const n = makeInstance(node).getEventHolder()
- if (n.events) n.events = {}
+function clearEvents ( node ) {
+
+ const n = makeInstance( node ).getEventHolder()
+ if ( n.events ) n.events = {}
+
}
// Add event binder in the SVG namespace
-export function on (node, events, listener, binding, options) {
- var l = listener.bind(binding || node)
- var bag = getEvents(node)
- var n = getEventTarget(node)
+export function on ( node, events, listener, binding, options ) {
+
+ var l = listener.bind( binding || node )
+ var bag = getEvents( node )
+ var n = getEventTarget( node )
// events can be an array of events or a string of events
- events = Array.isArray(events) ? events : events.split(delimiter)
+ events = Array.isArray( events ) ? events : events.split( delimiter )
// add id to listener
- if (!listener._svgjsListenerId) {
+ if ( !listener._svgjsListenerId ) {
+
listener._svgjsListenerId = ++listenerId
+
}
- events.forEach(function (event) {
- var ev = event.split('.')[0]
- var ns = event.split('.')[1] || '*'
+ events.forEach( function ( event ) {
+
+ var ev = event.split( '.' )[0]
+ var ns = event.split( '.' )[1] || '*'
// ensure valid object
bag[ev] = bag[ev] || {}
@@ -45,76 +55,126 @@ export function on (node, events, listener, binding, options) {
bag[ev][ns][listener._svgjsListenerId] = l
// add listener
- n.addEventListener(ev, l, options || false)
- })
+ n.addEventListener( ev, l, options || false )
+
+ } )
+
}
// Add event unbinder in the SVG namespace
-export function off (node, events, listener, options) {
- var bag = getEvents(node)
- var n = getEventTarget(node)
+export function off ( node, events, listener, options ) {
+
+ var bag = getEvents( node )
+ var n = getEventTarget( node )
// listener can be a function or a number
- if (typeof listener === 'function') {
+ if ( typeof listener === 'function' ) {
+
listener = listener._svgjsListenerId
- if (!listener) return
+ if ( !listener ) return
+
}
// events can be an array of events or a string or undefined
- events = Array.isArray(events) ? events : (events || '').split(delimiter)
+ events = Array.isArray( events ) ? events : ( events || '' ).split( delimiter )
+
+ events.forEach( function ( event ) {
- events.forEach(function (event) {
- var ev = event && event.split('.')[0]
- var ns = event && event.split('.')[1]
+ var ev = event && event.split( '.' )[0]
+ var ns = event && event.split( '.' )[1]
var namespace, l
- if (listener) {
+ if ( listener ) {
+
// remove listener reference
- if (bag[ev] && bag[ev][ns || '*']) {
+ if ( bag[ev] && bag[ev][ns || '*'] ) {
+
// removeListener
- n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false)
+ n.removeEventListener( ev, bag[ev][ns || '*'][listener], options || false )
delete bag[ev][ns || '*'][listener]
+
}
- } else if (ev && ns) {
+
+ } else if ( ev && ns ) {
+
// remove all listeners for a namespaced event
- if (bag[ev] && bag[ev][ns]) {
- for (l in bag[ev][ns]) { off(n, [ev, ns].join('.'), l) }
+ if ( bag[ev] && bag[ev][ns] ) {
+
+ for ( l in bag[ev][ns] ) {
+
+ off( n, [ ev, ns ].join( '.' ), l )
+
+ }
delete bag[ev][ns]
+
}
- } else if (ns) {
+
+ } else if ( ns ) {
+
// remove all listeners for a specific namespace
- for (event in bag) {
- for (namespace in bag[event]) {
- if (ns === namespace) { off(n, [event, ns].join('.')) }
+ for ( event in bag ) {
+
+ for ( namespace in bag[event] ) {
+
+ if ( ns === namespace ) {
+
+ off( n, [ event, ns ].join( '.' ) )
+
+ }
+
}
+
}
- } else if (ev) {
+
+ } else if ( ev ) {
+
// remove all listeners for the event
- if (bag[ev]) {
- for (namespace in bag[ev]) { off(n, [ev, namespace].join('.')) }
+ if ( bag[ev] ) {
+
+ for ( namespace in bag[ev] ) {
+
+ off( n, [ ev, namespace ].join( '.' ) )
+
+ }
delete bag[ev]
+
}
+
} else {
+
// remove all listeners on a given node
- for (event in bag) { off(n, event) }
+ for ( event in bag ) {
+
+ off( n, event )
+
+ }
+
+ clearEvents( node )
- clearEvents(node)
}
- })
+
+ } )
+
}
-export function dispatch (node, event, data) {
- var n = getEventTarget(node)
+export function dispatch ( node, event, data ) {
+
+ var n = getEventTarget( node )
// Dispatch event
- if (event instanceof globals.window.Event) {
- n.dispatchEvent(event)
+ if ( event instanceof globals.window.Event ) {
+
+ n.dispatchEvent( event )
+
} else {
- event = new globals.window.CustomEvent(event, { detail: data, cancelable: true })
- n.dispatchEvent(event)
+
+ event = new globals.window.CustomEvent( event, { detail: data, cancelable: true } )
+ n.dispatchEvent( event )
+
}
return event
+
}
diff --git a/src/modules/core/gradiented.js b/src/modules/core/gradiented.js
index 6c744e4..dd9c46f 100644
--- a/src/modules/core/gradiented.js
+++ b/src/modules/core/gradiented.js
@@ -1,13 +1,17 @@
import SVGNumber from '../../types/SVGNumber.js'
-export function from (x, y) {
- return (this._element || this).type === 'radialGradient'
- ? this.attr({ fx: new SVGNumber(x), fy: new SVGNumber(y) })
- : this.attr({ x1: new SVGNumber(x), y1: new SVGNumber(y) })
+export function from ( x, y ) {
+
+ return ( this._element || this ).type === 'radialGradient'
+ ? this.attr( { fx: new SVGNumber( x ), fy: new SVGNumber( y ) } )
+ : this.attr( { x1: new SVGNumber( x ), y1: new SVGNumber( y ) } )
+
}
-export function to (x, y) {
- return (this._element || this).type === 'radialGradient'
- ? this.attr({ cx: new SVGNumber(x), cy: new SVGNumber(y) })
- : this.attr({ x2: new SVGNumber(x), y2: new SVGNumber(y) })
+export function to ( x, y ) {
+
+ return ( this._element || this ).type === 'radialGradient'
+ ? this.attr( { cx: new SVGNumber( x ), cy: new SVGNumber( y ) } )
+ : this.attr( { x2: new SVGNumber( x ), y2: new SVGNumber( y ) } )
+
}
diff --git a/src/modules/core/parser.js b/src/modules/core/parser.js
index 1ff2380..12c9728 100644
--- a/src/modules/core/parser.js
+++ b/src/modules/core/parser.js
@@ -2,26 +2,32 @@ import { globals } from '../../utils/window.js'
import { makeInstance } from '../../utils/adopter.js'
export default function parser () {
+
// Reuse cached element if possible
- if (!parser.nodes) {
- let svg = makeInstance().size(2, 0)
+ if ( !parser.nodes ) {
+
+ let svg = makeInstance().size( 2, 0 )
svg.node.cssText = [
'opacity: 0',
'position: absolute',
'left: -100%',
'top: -100%',
'overflow: hidden'
- ].join(';')
+ ].join( ';' )
let path = svg.path().node
parser.nodes = { svg, path }
+
}
- if (!parser.nodes.svg.node.parentNode) {
+ if ( !parser.nodes.svg.node.parentNode ) {
+
let b = globals.document.body || globals.document.documentElement
- parser.nodes.svg.addTo(b)
+ parser.nodes.svg.addTo( b )
+
}
return parser.nodes
+
}
diff --git a/src/modules/core/pointed.js b/src/modules/core/pointed.js
index 95e6819..813b0e3 100644
--- a/src/modules/core/pointed.js
+++ b/src/modules/core/pointed.js
@@ -3,23 +3,31 @@ import PointArray from '../../types/PointArray.js'
export let MorphArray = PointArray
// Move by left top corner over x-axis
-export function x (x) {
- return x == null ? this.bbox().x : this.move(x, this.bbox().y)
+export function x ( x ) {
+
+ return x == null ? this.bbox().x : this.move( x, this.bbox().y )
+
}
// Move by left top corner over y-axis
-export function y (y) {
- return y == null ? this.bbox().y : this.move(this.bbox().x, y)
+export function y ( y ) {
+
+ return y == null ? this.bbox().y : this.move( this.bbox().x, y )
+
}
// Set width of element
-export function width (width) {
+export function width ( width ) {
+
let b = this.bbox()
- return width == null ? b.width : this.size(width, b.height)
+ return width == null ? b.width : this.size( width, b.height )
+
}
// Set height of element
-export function height (height) {
+export function height ( height ) {
+
let b = this.bbox()
- return height == null ? b.height : this.size(b.width, height)
+ return height == null ? b.height : this.size( b.width, height )
+
}
diff --git a/src/modules/core/poly.js b/src/modules/core/poly.js
index ad12020..56703a5 100644
--- a/src/modules/core/poly.js
+++ b/src/modules/core/poly.js
@@ -3,29 +3,39 @@ import PointArray from '../../types/PointArray.js'
// Get array
export function array () {
- return this._array || (this._array = new PointArray(this.attr('points')))
+
+ return this._array || ( this._array = new PointArray( this.attr( 'points' ) ) )
+
}
// Plot new path
-export function plot (p) {
- return (p == null) ? this.array()
- : this.clear().attr('points', typeof p === 'string' ? p
- : (this._array = new PointArray(p)))
+export function plot ( p ) {
+
+ return ( p == null ) ? this.array()
+ : this.clear().attr( 'points', typeof p === 'string' ? p
+ : ( this._array = new PointArray( p ) ) )
+
}
// Clear array cache
export function clear () {
+
delete this._array
return this
+
}
// Move by left top corner
-export function move (x, y) {
- return this.attr('points', this.array().move(x, y))
+export function move ( x, y ) {
+
+ return this.attr( 'points', this.array().move( x, y ) )
+
}
// Set element size to given width and height
-export function size (width, height) {
- let p = proportionalSize(this, width, height)
- return this.attr('points', this.array().size(p.width, p.height))
+export function size ( width, height ) {
+
+ let p = proportionalSize( this, width, height )
+ return this.attr( 'points', this.array().size( p.width, p.height ) )
+
}
diff --git a/src/modules/core/selector.js b/src/modules/core/selector.js
index 24841c5..a60df02 100644
--- a/src/modules/core/selector.js
+++ b/src/modules/core/selector.js
@@ -3,13 +3,19 @@ import { globals } from '../../utils/window.js'
import { map } from '../../utils/utils.js'
import List from '../../types/List.js'
-export default function baseFind (query, parent) {
- return new List(map((parent || globals.document).querySelectorAll(query), function (node) {
- return adopt(node)
- }))
+export default function baseFind ( query, parent ) {
+
+ return new List( map( ( parent || globals.document ).querySelectorAll( query ), function ( node ) {
+
+ return adopt( node )
+
+ } ) )
+
}
// Scoped find method
-export function find (query) {
- return baseFind(query, this.node)
+export function find ( query ) {
+
+ return baseFind( query, this.node )
+
}
diff --git a/src/modules/core/textable.js b/src/modules/core/textable.js
index 55df7c6..b0a0993 100644
--- a/src/modules/core/textable.js
+++ b/src/modules/core/textable.js
@@ -1,19 +1,25 @@
import { globals } from '../../utils/window.js'
// Create plain text node
-export function plain (text) {
+export function plain ( text ) {
+
// clear if build mode is disabled
- if (this._build === false) {
+ if ( this._build === false ) {
+
this.clear()
+
}
// create text node
- this.node.appendChild(globals.document.createTextNode(text))
+ this.node.appendChild( globals.document.createTextNode( text ) )
return this
+
}
// Get length of text element
export function length () {
+
return this.node.getComputedTextLength()
+
}
diff --git a/src/modules/optional/arrange.js b/src/modules/optional/arrange.js
index 6ce2eea..51e8605 100644
--- a/src/modules/optional/arrange.js
+++ b/src/modules/optional/arrange.js
@@ -3,109 +3,141 @@ import { registerMethods } from '../../utils/methods.js'
// Get all siblings, including myself
export function siblings () {
+
return this.parent().children()
+
}
// Get the curent position siblings
export function position () {
- return this.parent().index(this)
+
+ return this.parent().index( this )
+
}
// Get the next element (will return null if there is none)
export function next () {
+
return this.siblings()[this.position() + 1]
+
}
// Get the next element (will return null if there is none)
export function prev () {
+
return this.siblings()[this.position() - 1]
+
}
// Send given element one step forward
export function forward () {
+
var i = this.position() + 1
var p = this.parent()
// move node one step forward
- p.removeElement(this).add(this, i)
+ p.removeElement( this ).add( this, i )
// make sure defs node is always at the top
- if (typeof p.isRoot === 'function' && p.isRoot()) {
- p.node.appendChild(p.defs().node)
+ if ( typeof p.isRoot === 'function' && p.isRoot() ) {
+
+ p.node.appendChild( p.defs().node )
+
}
return this
+
}
// Send given element one step backward
export function backward () {
+
var i = this.position()
- if (i > 0) {
- this.parent().removeElement(this).add(this, i - 1)
+ if ( i > 0 ) {
+
+ this.parent().removeElement( this ).add( this, i - 1 )
+
}
return this
+
}
// Send given element all the way to the front
export function front () {
+
var p = this.parent()
// Move node forward
- p.node.appendChild(this.node)
+ p.node.appendChild( this.node )
// Make sure defs node is always at the top
- if (typeof p.isRoot === 'function' && p.isRoot()) {
- p.node.appendChild(p.defs().node)
+ if ( typeof p.isRoot === 'function' && p.isRoot() ) {
+
+ p.node.appendChild( p.defs().node )
+
}
return this
+
}
// Send given element all the way to the back
export function back () {
- if (this.position() > 0) {
- this.parent().removeElement(this).add(this, 0)
+
+ if ( this.position() > 0 ) {
+
+ this.parent().removeElement( this ).add( this, 0 )
+
}
return this
+
}
// Inserts a given element before the targeted element
-export function before (element) {
- element = makeInstance(element)
+export function before ( element ) {
+
+ element = makeInstance( element )
element.remove()
var i = this.position()
- this.parent().add(element, i)
+ this.parent().add( element, i )
return this
+
}
// Inserts a given element after the targeted element
-export function after (element) {
- element = makeInstance(element)
+export function after ( element ) {
+
+ element = makeInstance( element )
element.remove()
var i = this.position()
- this.parent().add(element, i + 1)
+ this.parent().add( element, i + 1 )
return this
+
}
-export function insertBefore (element) {
- element = makeInstance(element)
- element.before(this)
+export function insertBefore ( element ) {
+
+ element = makeInstance( element )
+ element.before( this )
+
}
-export function insertAfter (element) {
- element = makeInstance(element)
- element.after(this)
+export function insertAfter ( element ) {
+
+ element = makeInstance( element )
+ element.after( this )
+
}
-registerMethods('Dom', {
+registerMethods( 'Dom', {
siblings, position, next, prev, forward, backward, front, back, before, after
-})
+} )
diff --git a/src/modules/optional/class.js b/src/modules/optional/class.js
index b08c82b..93ccd0e 100644
--- a/src/modules/optional/class.js
+++ b/src/modules/optional/class.js
@@ -3,42 +3,58 @@ import { registerMethods } from '../../utils/methods.js'
// Return array of classes on the node
export function classes () {
- var attr = this.attr('class')
- return attr == null ? [] : attr.trim().split(delimiter)
+
+ var attr = this.attr( 'class' )
+ return attr == null ? [] : attr.trim().split( delimiter )
+
}
// Return true if class exists on the node, false otherwise
-export function hasClass (name) {
- return this.classes().indexOf(name) !== -1
+export function hasClass ( name ) {
+
+ return this.classes().indexOf( name ) !== -1
+
}
// Add class to the node
-export function addClass (name) {
- if (!this.hasClass(name)) {
+export function addClass ( name ) {
+
+ if ( !this.hasClass( name ) ) {
+
var array = this.classes()
- array.push(name)
- this.attr('class', array.join(' '))
+ array.push( name )
+ this.attr( 'class', array.join( ' ' ) )
+
}
return this
+
}
// Remove class from the node
-export function removeClass (name) {
- if (this.hasClass(name)) {
- this.attr('class', this.classes().filter(function (c) {
+export function removeClass ( name ) {
+
+ if ( this.hasClass( name ) ) {
+
+ this.attr( 'class', this.classes().filter( function ( c ) {
+
return c !== name
- }).join(' '))
+
+ } ).join( ' ' ) )
+
}
return this
+
}
// Toggle the presence of a class on the node
-export function toggleClass (name) {
- return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
+export function toggleClass ( name ) {
+
+ return this.hasClass( name ) ? this.removeClass( name ) : this.addClass( name )
+
}
-registerMethods('Dom', {
+registerMethods( 'Dom', {
classes, hasClass, addClass, removeClass, toggleClass
-})
+} )
diff --git a/src/modules/optional/css.js b/src/modules/optional/css.js
index babee7a..d5378f4 100644
--- a/src/modules/optional/css.js
+++ b/src/modules/optional/css.js
@@ -3,68 +3,98 @@ import { isBlank } from '../core/regex.js'
import { registerMethods } from '../../utils/methods.js'
// Dynamic style generator
-export function css (style, val) {
+export function css ( style, val ) {
+
let ret = {}
- if (arguments.length === 0) {
+ if ( arguments.length === 0 ) {
+
// get full style as object
- this.node.style.cssText.split(/\s*;\s*/)
- .filter(function (el) { return !!el.length })
- .forEach(function (el) {
- let t = el.split(/\s*:\s*/)
+ this.node.style.cssText.split( /\s*;\s*/ )
+ .filter( function ( el ) {
+
+ return !!el.length
+
+ } )
+ .forEach( function ( el ) {
+
+ let t = el.split( /\s*:\s*/ )
ret[t[0]] = t[1]
- })
+
+ } )
return ret
+
}
- if (arguments.length < 2) {
+ if ( arguments.length < 2 ) {
+
// get style properties in the array
- if (Array.isArray(style)) {
- for (let name of style) {
- let cased = camelCase(name)
+ if ( Array.isArray( style ) ) {
+
+ for ( let name of style ) {
+
+ let cased = camelCase( name )
ret[cased] = this.node.style[cased]
+
}
return ret
+
}
// get style for property
- if (typeof style === 'string') {
- return this.node.style[camelCase(style)]
+ if ( typeof style === 'string' ) {
+
+ return this.node.style[camelCase( style )]
+
}
// set styles in object
- if (typeof style === 'object') {
- for (let name in style) {
+ if ( typeof style === 'object' ) {
+
+ for ( let name in style ) {
+
// set empty string if null/undefined/'' was given
- this.node.style[camelCase(name)] =
- (style[name] == null || isBlank.test(style[name])) ? '' : style[name]
+ this.node.style[camelCase( name )]
+ = ( style[name] == null || isBlank.test( style[name] ) ) ? '' : style[name]
+
}
+
}
+
}
// set style for property
- if (arguments.length === 2) {
- this.node.style[camelCase(style)] =
- (val == null || isBlank.test(val)) ? '' : val
+ if ( arguments.length === 2 ) {
+
+ this.node.style[camelCase( style )]
+ = ( val == null || isBlank.test( val ) ) ? '' : val
+
}
return this
+
}
// Show element
export function show () {
- return this.css('display', '')
+
+ return this.css( 'display', '' )
+
}
// Hide element
export function hide () {
- return this.css('display', 'none')
+
+ return this.css( 'display', 'none' )
+
}
// Is element visible?
export function visible () {
- return this.css('display') !== 'none'
+
+ return this.css( 'display' ) !== 'none'
+
}
-registerMethods('Dom', {
+registerMethods( 'Dom', {
css, show, hide, visible
-})
+} )
diff --git a/src/modules/optional/data.js b/src/modules/optional/data.js
index 341d129..498e65a 100644
--- a/src/modules/optional/data.js
+++ b/src/modules/optional/data.js
@@ -1,26 +1,40 @@
import { registerMethods } from '../../utils/methods.js'
// Store data values on svg nodes
-export function data (a, v, r) {
- if (typeof a === 'object') {
- for (v in a) {
- this.data(v, a[v])
+export function data ( a, v, r ) {
+
+ if ( typeof a === 'object' ) {
+
+ for ( v in a ) {
+
+ this.data( v, a[v] )
+
}
- } else if (arguments.length < 2) {
+
+ } else if ( arguments.length < 2 ) {
+
try {
- return JSON.parse(this.attr('data-' + a))
- } catch (e) {
- return this.attr('data-' + a)
+
+ return JSON.parse( this.attr( 'data-' + a ) )
+
+ } catch ( e ) {
+
+ return this.attr( 'data-' + a )
+
}
+
} else {
- this.attr('data-' + a,
+
+ this.attr( 'data-' + a,
v === null ? null
- : r === true || typeof v === 'string' || typeof v === 'number' ? v
- : JSON.stringify(v)
+ : r === true || typeof v === 'string' || typeof v === 'number' ? v
+ : JSON.stringify( v )
)
+
}
return this
+
}
-registerMethods('Dom', { data })
+registerMethods( 'Dom', { data } )
diff --git a/src/modules/optional/memory.js b/src/modules/optional/memory.js
index 6478367..7c599f0 100644
--- a/src/modules/optional/memory.js
+++ b/src/modules/optional/memory.js
@@ -1,40 +1,60 @@
import { registerMethods } from '../../utils/methods.js'
// Remember arbitrary data
-export function remember (k, v) {
+export function remember ( k, v ) {
+
// remember every item in an object individually
- if (typeof arguments[0] === 'object') {
- for (var key in k) {
- this.remember(key, k[key])
+ if ( typeof arguments[0] === 'object' ) {
+
+ for ( var key in k ) {
+
+ this.remember( key, k[key] )
+
}
- } else if (arguments.length === 1) {
+
+ } else if ( arguments.length === 1 ) {
+
// retrieve memory
return this.memory()[k]
+
} else {
+
// store memory
this.memory()[k] = v
+
}
return this
+
}
// Erase a given memory
export function forget () {
- if (arguments.length === 0) {
+
+ if ( arguments.length === 0 ) {
+
this._memory = {}
+
} else {
- for (var i = arguments.length - 1; i >= 0; i--) {
+
+ for ( var i = arguments.length - 1; i >= 0; i-- ) {
+
delete this.memory()[arguments[i]]
+
}
+
}
return this
+
}
// This triggers creation of a new hidden class which is not performant
// However, this function is not rarely used so it will not happen frequently
// Return local memory object
export function memory () {
- return (this._memory = this._memory || {})
+
+ return ( this._memory = this._memory || {} )
+
}
-registerMethods('Dom', { remember, forget, memory })
+registerMethods( 'Dom', { remember, forget, memory } )
diff --git a/src/modules/optional/sugar.js b/src/modules/optional/sugar.js
index 6001631..4b6e6f3 100644
--- a/src/modules/optional/sugar.js
+++ b/src/modules/optional/sugar.js
@@ -8,169 +8,227 @@ import SVGNumber from '../../types/SVGNumber.js'
// Define list of available attributes for stroke and fill
var sugar = {
- stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],
- fill: ['color', 'opacity', 'rule'],
- prefix: function (t, a) {
+ stroke: [ 'color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset' ],
+ fill: [ 'color', 'opacity', 'rule' ],
+ prefix: function ( t, a ) {
+
return a === 'color' ? t : t + '-' + a
+
}
}
// Add sugar for fill and stroke
-;['fill', 'stroke'].forEach(function (m) {
+;[ 'fill', 'stroke' ].forEach( function ( m ) {
+
var extension = {}
var i
- extension[m] = function (o) {
- if (typeof o === 'undefined') {
- return this.attr(m)
+ extension[m] = function ( o ) {
+
+ if ( typeof o === 'undefined' ) {
+
+ return this.attr( m )
+
}
- if (typeof o === 'string' || Color.isRgb(o) || (o instanceof Element)) {
- this.attr(m, o)
+ if ( typeof o === 'string' || Color.isRgb( o ) || ( o instanceof Element ) ) {
+
+ this.attr( m, o )
+
} else {
+
// set all attributes from sugar.fill and sugar.stroke list
- for (i = sugar[m].length - 1; i >= 0; i--) {
- if (o[sugar[m][i]] != null) {
- this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]])
+ for ( i = sugar[m].length - 1; i >= 0; i-- ) {
+
+ if ( o[sugar[m][i]] != null ) {
+
+ this.attr( sugar.prefix( m, sugar[m][i] ), o[sugar[m][i]] )
+
}
+
}
+
}
return this
+
}
- registerMethods(['Shape', 'Runner'], extension)
-})
+ registerMethods( [ 'Shape', 'Runner' ], extension )
-registerMethods(['Element', 'Runner'], {
+} )
+
+registerMethods( [ 'Element', 'Runner' ], {
// Let the user set the matrix directly
- matrix: function (mat, b, c, d, e, f) {
+ matrix: function ( mat, b, c, d, e, f ) {
+
// Act as a getter
- if (mat == null) {
- return new Matrix(this)
+ if ( mat == null ) {
+
+ return new Matrix( this )
+
}
// Act as a setter, the user can pass a matrix or a set of numbers
- return this.attr('transform', new Matrix(mat, b, c, d, e, f))
+ return this.attr( 'transform', new Matrix( mat, b, c, d, e, f ) )
+
},
// Map rotation to transform
- rotate: function (angle, cx, cy) {
- return this.transform({ rotate: angle, ox: cx, oy: cy }, true)
+ rotate: function ( angle, cx, cy ) {
+
+ return this.transform( { rotate: angle, ox: cx, oy: cy }, true )
+
},
// Map skew to transform
- skew: function (x, y, cx, cy) {
+ skew: function ( x, y, cx, cy ) {
+
return arguments.length === 1 || arguments.length === 3
- ? this.transform({ skew: x, ox: y, oy: cx }, true)
- : this.transform({ skew: [x, y], ox: cx, oy: cy }, true)
+ ? this.transform( { skew: x, ox: y, oy: cx }, true )
+ : this.transform( { skew: [ x, y ], ox: cx, oy: cy }, true )
+
},
- shear: function (lam, cx, cy) {
- return this.transform({ shear: lam, ox: cx, oy: cy }, true)
+ shear: function ( lam, cx, cy ) {
+
+ return this.transform( { shear: lam, ox: cx, oy: cy }, true )
+
},
// Map scale to transform
- scale: function (x, y, cx, cy) {
+ scale: function ( x, y, cx, cy ) {
+
return arguments.length === 1 || arguments.length === 3
- ? this.transform({ scale: x, ox: y, oy: cx }, true)
- : this.transform({ scale: [x, y], ox: cx, oy: cy }, true)
+ ? this.transform( { scale: x, ox: y, oy: cx }, true )
+ : this.transform( { scale: [ x, y ], ox: cx, oy: cy }, true )
+
},
// Map translate to transform
- translate: function (x, y) {
- return this.transform({ translate: [x, y] }, true)
+ translate: function ( x, y ) {
+
+ return this.transform( { translate: [ x, y ] }, true )
+
},
// Map relative translations to transform
- relative: function (x, y) {
- return this.transform({ relative: [x, y] }, true)
+ relative: function ( x, y ) {
+
+ return this.transform( { relative: [ x, y ] }, true )
+
},
// Map flip to transform
- flip: function (direction, around) {
+ flip: function ( direction, around ) {
+
var directionString = typeof direction === 'string' ? direction
- : isFinite(direction) ? 'both'
- : 'both'
- var origin = (direction === 'both' && isFinite(around)) ? [around, around]
- : (direction === 'x') ? [around, 0]
- : (direction === 'y') ? [0, around]
- : isFinite(direction) ? [direction, direction]
- : [0, 0]
- this.transform({ flip: directionString, origin: origin }, true)
+ : isFinite( direction ) ? 'both'
+ : 'both'
+ var origin = ( direction === 'both' && isFinite( around ) ) ? [ around, around ]
+ : ( direction === 'x' ) ? [ around, 0 ]
+ : ( direction === 'y' ) ? [ 0, around ]
+ : isFinite( direction ) ? [ direction, direction ]
+ : [ 0, 0 ]
+ this.transform( { flip: directionString, origin: origin }, true )
+
},
// Opacity
- opacity: function (value) {
- return this.attr('opacity', value)
+ opacity: function ( value ) {
+
+ return this.attr( 'opacity', value )
+
},
// Relative move over x and y axes
- dmove: function (x, y) {
- return this.dx(x).dy(y)
+ dmove: function ( x, y ) {
+
+ return this.dx( x ).dy( y )
+
}
-})
+} )
-registerMethods('Element', {
+registerMethods( 'Element', {
// Relative move over x axis
- dx: function (x) {
- return this.x(new SVGNumber(x).plus(this.x()))
+ dx: function ( x ) {
+
+ return this.x( new SVGNumber( x ).plus( this.x() ) )
+
},
// Relative move over y axis
- dy: function (y) {
- return this.y(new SVGNumber(y).plus(this.y()))
+ dy: function ( y ) {
+
+ return this.y( new SVGNumber( y ).plus( this.y() ) )
+
}
-})
+} )
-registerMethods('radius', {
+registerMethods( 'radius', {
// Add x and y radius
- radius: function (x, y) {
- var type = (this._element || this).type
+ radius: function ( x, y ) {
+
+ var type = ( this._element || this ).type
return type === 'radialGradient' || type === 'radialGradient'
- ? this.attr('r', new SVGNumber(x))
- : this.rx(x).ry(y == null ? x : y)
+ ? this.attr( 'r', new SVGNumber( x ) )
+ : this.rx( x ).ry( y == null ? x : y )
+
}
-})
+} )
-registerMethods('Path', {
+registerMethods( 'Path', {
// Get path length
length: function () {
+
return this.node.getTotalLength()
+
},
// Get point at length
- pointAt: function (length) {
- return new Point(this.node.getPointAtLength(length))
+ pointAt: function ( length ) {
+
+ return new Point( this.node.getPointAtLength( length ) )
+
}
-})
+} )
-registerMethods(['Element', 'Runner'], {
+registerMethods( [ 'Element', 'Runner' ], {
// Set font
- font: function (a, v) {
- if (typeof a === 'object') {
- for (v in a) this.font(v, a[v])
+ font: function ( a, v ) {
+
+ if ( typeof a === 'object' ) {
+
+ for ( v in a ) this.font( v, a[v] )
+
}
return a === 'leading'
- ? this.leading(v)
+ ? this.leading( v )
: a === 'anchor'
- ? this.attr('text-anchor', v)
+ ? this.attr( 'text-anchor', v )
: a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style'
- ? this.attr('font-' + a, v)
- : this.attr(a, v)
+ ? this.attr( 'font-' + a, v )
+ : this.attr( a, v )
+
}
-})
+} )
+
+registerMethods( 'Text', {
+ ax ( x ) {
+
+ return this.attr( 'x', x )
-registerMethods('Text', {
- ax (x) {
- return this.attr('x', x)
},
- ay (y) {
- return this.attr('y', y)
+ ay ( y ) {
+
+ return this.attr( 'y', y )
+
},
- amove (x, y) {
- return this.ax(x).ay(y)
+ amove ( x, y ) {
+
+ return this.ax( x ).ay( y )
+
}
-})
+} )
// Add events to elements
const methods = [ 'click',
@@ -186,19 +244,27 @@ const methods = [ 'click',
'touchmove',
'touchleave',
'touchend',
- 'touchcancel' ].reduce(function (last, event) {
+ 'touchcancel' ].reduce( function ( last, event ) {
+
// add event to Element
- const fn = function (f) {
- if (f === null) {
- off(this, event)
+ const fn = function ( f ) {
+
+ if ( f === null ) {
+
+ off( this, event )
+
} else {
- on(this, event, f)
+
+ on( this, event, f )
+
}
return this
+
}
last[event] = fn
return last
-}, {})
-registerMethods('Element', methods)
+}, {} )
+
+registerMethods( 'Element', methods )
diff --git a/src/modules/optional/transform.js b/src/modules/optional/transform.js
index b8f4c74..717fbf3 100644
--- a/src/modules/optional/transform.js
+++ b/src/modules/optional/transform.js
@@ -5,68 +5,92 @@ import Matrix from '../../types/Matrix.js'
// Reset all transformations
export function untransform () {
- return this.attr('transform', null)
+
+ return this.attr( 'transform', null )
+
}
// merge the whole transformation chain into one matrix and returns it
export function matrixify () {
- var matrix = (this.attr('transform') || '')
+
+ var matrix = ( this.attr( 'transform' ) || '' )
// split transformations
- .split(transforms).slice(0, -1).map(function (str) {
+ .split( transforms ).slice( 0, -1 ).map( function ( str ) {
+
// generate key => value pairs
- var kv = str.trim().split('(')
- return [kv[0],
- kv[1].split(delimiter)
- .map(function (str) { return parseFloat(str) })
+ var kv = str.trim().split( '(' )
+ return [ kv[0],
+ kv[1].split( delimiter )
+ .map( function ( str ) {
+
+ return parseFloat( str )
+
+ } )
]
- })
+
+ } )
.reverse()
// merge every transformation into one matrix
- .reduce(function (matrix, transform) {
- if (transform[0] === 'matrix') {
- return matrix.lmultiply(Matrix.fromArray(transform[1]))
+ .reduce( function ( matrix, transform ) {
+
+ if ( transform[0] === 'matrix' ) {
+
+ return matrix.lmultiply( Matrix.fromArray( transform[1] ) )
+
}
- return matrix[transform[0]].apply(matrix, transform[1])
- }, new Matrix())
+ return matrix[transform[0]].apply( matrix, transform[1] )
+
+ }, new Matrix() )
return matrix
+
}
// add an element to another parent without changing the visual representation on the screen
-export function toParent (parent) {
- if (this === parent) return this
+export function toParent ( parent ) {
+
+ if ( this === parent ) return this
var ctm = this.screenCTM()
var pCtm = parent.screenCTM().inverse()
- this.addTo(parent).untransform().transform(pCtm.multiply(ctm))
+ this.addTo( parent ).untransform().transform( pCtm.multiply( ctm ) )
return this
+
}
// same as above with parent equals root-svg
export function toRoot () {
- return this.toParent(this.root())
+
+ return this.toParent( this.root() )
+
}
// Add transformations
-export function transform (o, relative) {
+export function transform ( o, relative ) {
+
// Act as a getter if no object was passed
- if (o == null || typeof o === 'string') {
- var decomposed = new Matrix(this).decompose()
+ if ( o == null || typeof o === 'string' ) {
+
+ var decomposed = new Matrix( this ).decompose()
return decomposed[o] || decomposed
+
}
- if (!Matrix.isMatrixLike(o)) {
+ if ( !Matrix.isMatrixLike( o ) ) {
+
// Set the origin according to the defined transform
- o = { ...o, origin: getOrigin(o, this) }
+ o = { ...o, origin: getOrigin( o, this ) }
+
}
// The user can pass a boolean, an Element or an Matrix or nothing
- var cleanRelative = relative === true ? this : (relative || false)
- var result = new Matrix(cleanRelative).transform(o)
- return this.attr('transform', result)
+ var cleanRelative = relative === true ? this : ( relative || false )
+ var result = new Matrix( cleanRelative ).transform( o )
+ return this.attr( 'transform', result )
+
}
-registerMethods('Element', {
+registerMethods( 'Element', {
untransform, matrixify, toParent, toRoot, transform
-})
+} )
diff --git a/src/svg.js b/src/svg.js
index 4026598..7b79af9 100644
--- a/src/svg.js
+++ b/src/svg.js
@@ -3,11 +3,13 @@ import * as regex from './modules/core/regex.js'
import { makeInstance } from './utils/adopter'
// The main wrapping element
-export default function SVG (element) {
- return makeInstance(element)
+export default function SVG ( element ) {
+
+ return makeInstance( element )
+
}
-Object.assign(SVG, svgMembers)
+Object.assign( SVG, svgMembers )
SVG.utils = SVG
SVG.regex = regex
diff --git a/src/types/ArrayPolyfill.js b/src/types/ArrayPolyfill.js
index 4d2309f..0ee29a5 100644
--- a/src/types/ArrayPolyfill.js
+++ b/src/types/ArrayPolyfill.js
@@ -1,8 +1,10 @@
/* eslint no-new-func: "off" */
-export const subClassArray = (function () {
+export const subClassArray = ( function () {
+
try {
+
// try es6 subclassing
- return Function('name', 'baseClass', '_constructor', [
+ return Function( 'name', 'baseClass', '_constructor', [
'baseClass = baseClass || Array',
'return {',
' [name]: class extends baseClass {',
@@ -12,25 +14,35 @@ export const subClassArray = (function () {
' }',
' }',
'}[name]'
- ].join('\n'))
- } catch (e) {
+ ].join( '\n' ) )
+
+ } catch ( e ) {
+
// Use es5 approach
- return (name, baseClass = Array, _constructor) => {
+ return ( name, baseClass = Array, _constructor ) => {
+
const Arr = function () {
- baseClass.apply(this, arguments)
- _constructor && _constructor.apply(this, arguments)
+
+ baseClass.apply( this, arguments )
+ _constructor && _constructor.apply( this, arguments )
+
}
- Arr.prototype = Object.create(baseClass.prototype)
+ Arr.prototype = Object.create( baseClass.prototype )
Arr.prototype.constructor = Arr
- Arr.prototype.map = function (fn) {
+ Arr.prototype.map = function ( fn ) {
+
const arr = new Arr()
- arr.push.apply(arr, Array.prototype.map.call(this, fn))
+ arr.push.apply( arr, Array.prototype.map.call( this, fn ) )
return arr
+
}
return Arr
+
}
+
}
-})()
+
+} )()
diff --git a/src/types/Box.js b/src/types/Box.js
index e55f114..2fcb923 100644
--- a/src/types/Box.js
+++ b/src/types/Box.js
@@ -4,33 +4,45 @@ import { globals } from '../utils/window.js'
import Point from './Point.js'
import parser from '../modules/core/parser.js'
-function isNulledBox (box) {
+function isNulledBox ( box ) {
+
return !box.w && !box.h && !box.x && !box.y
+
}
-function domContains (node) {
- return (globals.document.documentElement.contains || function (node) {
+function domContains ( node ) {
+
+ return ( globals.document.documentElement.contains || function ( node ) {
+
// This is IE - it does not support contains() for top-level SVGs
- while (node.parentNode) {
+ while ( node.parentNode ) {
+
node = node.parentNode
+
}
return node === document
- }).call(globals.document.documentElement, node)
+
+ } ).call( globals.document.documentElement, node )
+
}
export default class Box {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (source) {
- var base = [0, 0, 0, 0]
- source = typeof source === 'string' ? source.split(delimiter).map(parseFloat)
- : Array.isArray(source) ? source
- : typeof source === 'object' ? [source.left != null ? source.left
- : source.x, source.top != null ? source.top : source.y, source.width, source.height]
- : arguments.length === 4 ? [].slice.call(arguments)
- : base
+ init ( source ) {
+
+ var base = [ 0, 0, 0, 0 ]
+ source = typeof source === 'string' ? source.split( delimiter ).map( parseFloat )
+ : Array.isArray( source ) ? source
+ : typeof source === 'object' ? [ source.left != null ? source.left
+ : source.x, source.top != null ? source.top : source.y, source.width, source.height ]
+ : arguments.length === 4 ? [].slice.call( arguments )
+ : base
this.x = source[0] || 0
this.y = source[1] || 0
@@ -44,105 +56,139 @@ export default class Box {
this.cy = this.y + this.h / 2
return this
+
}
// Merge rect box with another, return a new instance
- merge (box) {
- let x = Math.min(this.x, box.x)
- let y = Math.min(this.y, box.y)
- let width = Math.max(this.x + this.width, box.x + box.width) - x
- let height = Math.max(this.y + this.height, box.y + box.height) - y
+ merge ( box ) {
+
+ let x = Math.min( this.x, box.x )
+ let y = Math.min( this.y, box.y )
+ let width = Math.max( this.x + this.width, box.x + box.width ) - x
+ let height = Math.max( this.y + this.height, box.y + box.height ) - y
+
+ return new Box( x, y, width, height )
- return new Box(x, y, width, height)
}
- transform (m) {
+ transform ( m ) {
+
let xMin = Infinity
let xMax = -Infinity
let yMin = Infinity
let yMax = -Infinity
let pts = [
- new Point(this.x, this.y),
- new Point(this.x2, this.y),
- new Point(this.x, this.y2),
- new Point(this.x2, this.y2)
+ new Point( this.x, this.y ),
+ new Point( this.x2, this.y ),
+ new Point( this.x, this.y2 ),
+ new Point( this.x2, this.y2 )
]
- pts.forEach(function (p) {
- p = p.transform(m)
- xMin = Math.min(xMin, p.x)
- xMax = Math.max(xMax, p.x)
- yMin = Math.min(yMin, p.y)
- yMax = Math.max(yMax, p.y)
- })
+ pts.forEach( function ( p ) {
+
+ p = p.transform( m )
+ xMin = Math.min( xMin, p.x )
+ xMax = Math.max( xMax, p.x )
+ yMin = Math.min( yMin, p.y )
+ yMax = Math.max( yMax, p.y )
+
+ } )
return new Box(
xMin, yMin,
xMax - xMin,
yMax - yMin
)
+
}
addOffset () {
+
// offset by window scroll position, because getBoundingClientRect changes when window is scrolled
this.x += globals.window.pageXOffset
this.y += globals.window.pageYOffset
return this
+
}
toString () {
+
return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
+
}
toArray () {
- return [this.x, this.y, this.width, this.height]
+
+ return [ this.x, this.y, this.width, this.height ]
+
}
isNulled () {
- return isNulledBox(this)
+
+ return isNulledBox( this )
+
}
+
}
-function getBox (cb) {
+function getBox ( cb ) {
+
let box
try {
- box = cb(this.node)
- if (isNulledBox(box) && !domContains(this.node)) {
- throw new Error('Element not in the dom')
+ box = cb( this.node )
+
+ if ( isNulledBox( box ) && !domContains( this.node ) ) {
+
+ throw new Error( 'Element not in the dom' )
+
}
- } catch (e) {
+
+ } catch ( e ) {
+
try {
- let clone = this.clone().addTo(parser().svg).show()
- box = cb(clone.node)
+
+ let clone = this.clone().addTo( parser().svg ).show()
+ box = cb( clone.node )
clone.remove()
- } catch (e) {
- throw new Error('Getting a bounding box of element "' + this.node.nodeName + '" is not possible')
+
+ } catch ( e ) {
+
+ throw new Error( 'Getting a bounding box of element "' + this.node.nodeName + '" is not possible' )
+
}
+
}
return box
+
}
export function bbox () {
- return new Box(getBox.call(this, (node) => node.getBBox()))
+
+ return new Box( getBox.call( this, ( node ) => node.getBBox() ) )
+
}
-export function rbox (el) {
- let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect()))
- if (el) return box.transform(el.screenCTM().inverse())
+export function rbox ( el ) {
+
+ let box = new Box( getBox.call( this, ( node ) => node.getBoundingClientRect() ) )
+ if ( el ) return box.transform( el.screenCTM().inverse() )
return box.addOffset()
+
}
-registerMethods({
+registerMethods( {
viewbox: {
- viewbox (x, y, width, height) {
+ viewbox ( x, y, width, height ) {
+
// act as getter
- if (x == null) return new Box(this.attr('viewBox'))
+ if ( x == null ) return new Box( this.attr( 'viewBox' ) )
// act as setter
- return this.attr('viewBox', new Box(x, y, width, height))
+ return this.attr( 'viewBox', new Box( x, y, width, height ) )
+
}
}
-})
+} )
diff --git a/src/types/EventTarget.js b/src/types/EventTarget.js
index 5a005fd..3d755bf 100644
--- a/src/types/EventTarget.js
+++ b/src/types/EventTarget.js
@@ -2,57 +2,79 @@ import { dispatch, off, on } from '../modules/core/event.js'
import Base from './Base.js'
export default class EventTarget extends Base {
- constructor ({ events = {} } = {}) {
+
+ constructor ( { events = {} } = {} ) {
+
super()
this.events = events
+
}
addEventListener () {}
- dispatch (event, data) {
- return dispatch(this, event, data)
+ dispatch ( event, data ) {
+
+ return dispatch( this, event, data )
+
}
- dispatchEvent (event) {
+ dispatchEvent ( event ) {
+
const bag = this.getEventHolder().events
- if (!bag) return true
+ if ( !bag ) return true
const events = bag[event.type]
- for (let i in events) {
- for (let j in events[i]) {
- events[i][j](event)
+ for ( let i in events ) {
+
+ for ( let j in events[i] ) {
+
+ events[i][j]( event )
+
}
+
}
return !event.defaultPrevented
+
}
// Fire given event
- fire (event, data) {
- this.dispatch(event, data)
+ fire ( event, data ) {
+
+ this.dispatch( event, data )
return this
+
}
getEventHolder () {
+
return this
+
}
getEventTarget () {
+
return this
+
}
// Unbind event from listener
- off (event, listener) {
- off(this, event, listener)
+ off ( event, listener ) {
+
+ off( this, event, listener )
return this
+
}
// Bind given event to listener
- on (event, listener, binding, options) {
- on(this, event, listener, binding, options)
+ on ( event, listener, binding, options ) {
+
+ on( this, event, listener, binding, options )
return this
+
}
removeEventListener () {}
+
}
diff --git a/src/types/List.js b/src/types/List.js
index 8bd3985..a2d2226 100644
--- a/src/types/List.js
+++ b/src/types/List.js
@@ -1,38 +1,62 @@
import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
-const List = subClassArray('List', Array, function (arr = []) {
+const List = subClassArray( 'List', Array, function ( arr = [] ) {
+
// This catches the case, that native map tries to create an array with new Array(1)
- if (typeof arr === 'number') return this
+ if ( typeof arr === 'number' ) return this
this.length = 0
- this.push(...arr)
-})
+ this.push( ...arr )
+
+} )
export default List
-extend(List, {
- each (fnOrMethodName, ...args) {
- if (typeof fnOrMethodName === 'function') {
- this.forEach((el) => { fnOrMethodName.call(el, el) })
+extend( List, {
+ each ( fnOrMethodName, ...args ) {
+
+ if ( typeof fnOrMethodName === 'function' ) {
+
+ this.forEach( ( el ) => {
+
+ fnOrMethodName.call( el, el )
+
+ } )
+
} else {
- return this.map(el => { return el[fnOrMethodName](...args) })
+
+ return this.map( el => {
+
+ return el[fnOrMethodName]( ...args )
+
+ } )
+
}
return this
+
},
toArray () {
- return Array.prototype.concat.apply([], this)
+
+ return Array.prototype.concat.apply( [], this )
+
}
-})
+} )
+
+List.extend = function ( methods ) {
+
+ methods = methods.reduce( ( obj, name ) => {
+
+ obj[name] = function ( ...attrs ) {
+
+ return this.each( name, ...attrs )
-List.extend = function (methods) {
- methods = methods.reduce((obj, name) => {
- obj[name] = function (...attrs) {
- return this.each(name, ...attrs)
}
return obj
- }, {})
- extend(List, methods)
+ }, {} )
+
+ extend( List, methods )
+
}
diff --git a/src/types/Matrix.js b/src/types/Matrix.js
index a1eb317..a9a311e 100644
--- a/src/types/Matrix.js
+++ b/src/types/Matrix.js
@@ -3,27 +3,33 @@ import { radians } from '../utils/utils.js'
import Element from '../elements/Element.js'
import Point from './Point.js'
-function closeEnough (a, b, threshold) {
- return Math.abs(b - a) < (threshold || 1e-6)
+function closeEnough ( a, b, threshold ) {
+
+ return Math.abs( b - a ) < ( threshold || 1e-6 )
+
}
export default class Matrix {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
// Initialize
- init (source) {
- var base = Matrix.fromArray([1, 0, 0, 1, 0, 0])
+ init ( source ) {
+
+ var base = Matrix.fromArray( [ 1, 0, 0, 1, 0, 0 ] )
// ensure source as object
source = source instanceof Element ? source.matrixify()
- : typeof source === 'string' ? Matrix.fromArray(source.split(delimiter).map(parseFloat))
- : Array.isArray(source) ? Matrix.fromArray(source)
- : (typeof source === 'object' && Matrix.isMatrixLike(source)) ? source
- : (typeof source === 'object') ? new Matrix().transform(source)
- : arguments.length === 6 ? Matrix.fromArray([].slice.call(arguments))
- : base
+ : typeof source === 'string' ? Matrix.fromArray( source.split( delimiter ).map( parseFloat ) )
+ : Array.isArray( source ) ? Matrix.fromArray( source )
+ : ( typeof source === 'object' && Matrix.isMatrixLike( source ) ) ? source
+ : ( typeof source === 'object' ) ? new Matrix().transform( source )
+ : arguments.length === 6 ? Matrix.fromArray( [].slice.call( arguments ) )
+ : base
// Merge the source matrix with the base matrix
this.a = source.a != null ? source.a : base.a
@@ -34,56 +40,68 @@ export default class Matrix {
this.f = source.f != null ? source.f : base.f
return this
+
}
// Clones this matrix
clone () {
- return new Matrix(this)
+
+ return new Matrix( this )
+
}
// Transform a matrix into another matrix by manipulating the space
- transform (o) {
+ transform ( o ) {
+
// Check if o is a matrix and then left multiply it directly
- if (Matrix.isMatrixLike(o)) {
- var matrix = new Matrix(o)
- return matrix.multiplyO(this)
+ if ( Matrix.isMatrixLike( o ) ) {
+
+ var matrix = new Matrix( o )
+ return matrix.multiplyO( this )
+
}
// Get the proposed transformations and the current transformations
- var t = Matrix.formatTransforms(o)
+ var t = Matrix.formatTransforms( o )
var current = this
- let { x: ox, y: oy } = new Point(t.ox, t.oy).transform(current)
+ let { x: ox, y: oy } = new Point( t.ox, t.oy ).transform( current )
// Construct the resulting matrix
var transformer = new Matrix()
- .translateO(t.rx, t.ry)
- .lmultiplyO(current)
- .translateO(-ox, -oy)
- .scaleO(t.scaleX, t.scaleY)
- .skewO(t.skewX, t.skewY)
- .shearO(t.shear)
- .rotateO(t.theta)
- .translateO(ox, oy)
+ .translateO( t.rx, t.ry )
+ .lmultiplyO( current )
+ .translateO( -ox, -oy )
+ .scaleO( t.scaleX, t.scaleY )
+ .skewO( t.skewX, t.skewY )
+ .shearO( t.shear )
+ .rotateO( t.theta )
+ .translateO( ox, oy )
// If we want the origin at a particular place, we force it there
- if (isFinite(t.px) || isFinite(t.py)) {
- const origin = new Point(ox, oy).transform(transformer)
+ if ( isFinite( t.px ) || isFinite( t.py ) ) {
+
+ const origin = new Point( ox, oy ).transform( transformer )
// TODO: Replace t.px with isFinite(t.px)
const dx = t.px ? t.px - origin.x : 0
const dy = t.py ? t.py - origin.y : 0
- transformer.translateO(dx, dy)
+ transformer.translateO( dx, dy )
+
}
// Translate now after positioning
- transformer.translateO(t.tx, t.ty)
+ transformer.translateO( t.tx, t.ty )
return transformer
+
}
// Applies a matrix defined by its affine parameters
- compose (o) {
- if (o.origin) {
+ compose ( o ) {
+
+ if ( o.origin ) {
+
o.originX = o.origin[0]
o.originY = o.origin[1]
+
}
// Get the parameters
var ox = o.originX || 0
@@ -97,18 +115,20 @@ export default class Matrix {
// Apply the standard matrix
var result = new Matrix()
- .translateO(-ox, -oy)
- .scaleO(sx, sy)
- .shearO(lam)
- .rotateO(theta)
- .translateO(tx, ty)
- .lmultiplyO(this)
- .translateO(ox, oy)
+ .translateO( -ox, -oy )
+ .scaleO( sx, sy )
+ .shearO( lam )
+ .rotateO( theta )
+ .translateO( tx, ty )
+ .lmultiplyO( this )
+ .translateO( ox, oy )
return result
+
}
// Decomposes this matrix into its affine parameters
- decompose (cx = 0, cy = 0) {
+ decompose ( cx = 0, cy = 0 ) {
+
// Get the parameters from the matrix
var a = this.a
var b = this.b
@@ -123,20 +143,20 @@ export default class Matrix {
// Since we only shear in x, we can use the x basis to get the x scale
// and the rotation of the resulting matrix
- var sx = ccw * Math.sqrt(a * a + b * b)
- var thetaRad = Math.atan2(ccw * b, ccw * a)
+ var sx = ccw * Math.sqrt( a * a + b * b )
+ var thetaRad = Math.atan2( ccw * b, ccw * a )
var theta = 180 / Math.PI * thetaRad
- var ct = Math.cos(thetaRad)
- var st = Math.sin(thetaRad)
+ var ct = Math.cos( thetaRad )
+ var st = Math.sin( thetaRad )
// We can then solve the y basis vector simultaneously to get the other
// two affine parameters directly from these parameters
- var lam = (a * c + b * d) / determinant
- var sy = ((c * sx) / (lam * a - b)) || ((d * sx) / (lam * b + a))
+ var lam = ( a * c + b * d ) / determinant
+ var sy = ( ( c * sx ) / ( lam * a - b ) ) || ( ( d * sx ) / ( lam * b + a ) )
// Use the translations
- let tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy)
- let ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy)
+ let tx = e - cx + cx * ct * sx + cy * ( lam * ct * sx - st * sy )
+ let ty = f - cy + cx * st * sx + cy * ( lam * st * sx + ct * sy )
// Construct the decomposition and return it
return {
@@ -158,38 +178,48 @@ export default class Matrix {
e: this.e,
f: this.f
}
+
}
// Left multiplies by the given matrix
- multiply (matrix) {
- return this.clone().multiplyO(matrix)
+ multiply ( matrix ) {
+
+ return this.clone().multiplyO( matrix )
+
}
- multiplyO (matrix) {
+ multiplyO ( matrix ) {
+
// Get the matrices
var l = this
var r = matrix instanceof Matrix
? matrix
- : new Matrix(matrix)
+ : new Matrix( matrix )
+
+ return Matrix.matrixMultiply( l, r, this )
- return Matrix.matrixMultiply(l, r, this)
}
- lmultiply (matrix) {
- return this.clone().lmultiplyO(matrix)
+ lmultiply ( matrix ) {
+
+ return this.clone().lmultiplyO( matrix )
+
}
- lmultiplyO (matrix) {
+ lmultiplyO ( matrix ) {
+
var r = this
var l = matrix instanceof Matrix
? matrix
- : new Matrix(matrix)
+ : new Matrix( matrix )
+
+ return Matrix.matrixMultiply( l, r, this )
- return Matrix.matrixMultiply(l, r, this)
}
// Inverses matrix
inverseO () {
+
// Get the current parameters out of the matrix
var a = this.a
var b = this.b
@@ -200,7 +230,7 @@ export default class Matrix {
// Invert the 2x2 matrix in the top left
var det = a * d - b * c
- if (!det) throw new Error('Cannot invert ' + this)
+ if ( !det ) throw new Error( 'Cannot invert ' + this )
// Calculate the top 2x2 matrix
var na = d / det
@@ -209,8 +239,8 @@ export default class Matrix {
var nd = a / det
// Apply the inverted matrix to the top right
- var ne = -(na * e + nc * f)
- var nf = -(nb * e + nd * f)
+ var ne = -( na * e + nc * f )
+ var nf = -( nb * e + nd * f )
// Construct the inverted matrix
this.a = na
@@ -221,34 +251,46 @@ export default class Matrix {
this.f = nf
return this
+
}
inverse () {
+
return this.clone().inverseO()
+
}
// Translate matrix
- translate (x, y) {
- return this.clone().translateO(x, y)
+ translate ( x, y ) {
+
+ return this.clone().translateO( x, y )
+
}
- translateO (x, y) {
+ translateO ( x, y ) {
+
this.e += x || 0
this.f += y || 0
return this
+
}
// Scale matrix
- scale (x, y, cx, cy) {
- return this.clone().scaleO(...arguments)
+ scale ( x, y, cx, cy ) {
+
+ return this.clone().scaleO( ...arguments )
+
}
- scaleO (x, y = x, cx = 0, cy = 0) {
+ scaleO ( x, y = x, cx = 0, cy = 0 ) {
+
// Support uniform scaling
- if (arguments.length === 3) {
+ if ( arguments.length === 3 ) {
+
cy = cx
cx = y
y = x
+
}
let { a, b, c, d, e, f } = this
@@ -261,19 +303,23 @@ export default class Matrix {
this.f = f * y - cy * y + cy
return this
+
}
// Rotate matrix
- rotate (r, cx, cy) {
- return this.clone().rotateO(r, cx, cy)
+ rotate ( r, cx, cy ) {
+
+ return this.clone().rotateO( r, cx, cy )
+
}
- rotateO (r, cx = 0, cy = 0) {
+ rotateO ( r, cx = 0, cy = 0 ) {
+
// Convert degrees to radians
- r = radians(r)
+ r = radians( r )
- let cos = Math.cos(r)
- let sin = Math.sin(r)
+ let cos = Math.cos( r )
+ let sin = Math.sin( r )
let { a, b, c, d, e, f } = this
@@ -285,25 +331,33 @@ export default class Matrix {
this.f = f * cos + e * sin - cx * sin - cy * cos + cy
return this
+
}
// Flip matrix on x or y, at a given offset
- flip (axis, around) {
- return this.clone().flipO(axis, around)
+ flip ( axis, around ) {
+
+ return this.clone().flipO( axis, around )
+
}
- flipO (axis, around) {
- return axis === 'x' ? this.scaleO(-1, 1, around, 0)
- : axis === 'y' ? this.scaleO(1, -1, 0, around)
- : this.scaleO(-1, -1, axis, around || axis) // Define an x, y flip point
+ flipO ( axis, around ) {
+
+ return axis === 'x' ? this.scaleO( -1, 1, around, 0 )
+ : axis === 'y' ? this.scaleO( 1, -1, 0, around )
+ : this.scaleO( -1, -1, axis, around || axis ) // Define an x, y flip point
+
}
// Shear matrix
- shear (a, cx, cy) {
- return this.clone().shearO(a, cx, cy)
+ shear ( a, cx, cy ) {
+
+ return this.clone().shearO( a, cx, cy )
+
}
- shearO (lx, cx = 0, cy = 0) {
+ shearO ( lx, cx = 0, cy = 0 ) {
+
let { a, b, c, d, e, f } = this
this.a = a + b * lx
@@ -311,27 +365,33 @@ export default class Matrix {
this.e = e + f * lx - cy * lx
return this
+
}
// Skew Matrix
- skew (x, y, cx, cy) {
- return this.clone().skewO(...arguments)
+ skew ( x, y, cx, cy ) {
+
+ return this.clone().skewO( ...arguments )
+
}
- skewO (x, y = x, cx = 0, cy = 0) {
+ skewO ( x, y = x, cx = 0, cy = 0 ) {
+
// support uniformal skew
- if (arguments.length === 3) {
+ if ( arguments.length === 3 ) {
+
cy = cx
cx = y
y = x
+
}
// Convert degrees to radians
- x = radians(x)
- y = radians(y)
+ x = radians( x )
+ y = radians( y )
- let lx = Math.tan(x)
- let ly = Math.tan(y)
+ let lx = Math.tan( x )
+ let ly = Math.tan( y )
let { a, b, c, d, e, f } = this
@@ -343,55 +403,75 @@ export default class Matrix {
this.f = f + e * ly - cx * ly
return this
+
}
// SkewX
- skewX (x, cx, cy) {
- return this.skew(x, 0, cx, cy)
+ skewX ( x, cx, cy ) {
+
+ return this.skew( x, 0, cx, cy )
+
}
- skewXO (x, cx, cy) {
- return this.skewO(x, 0, cx, cy)
+ skewXO ( x, cx, cy ) {
+
+ return this.skewO( x, 0, cx, cy )
+
}
// SkewY
- skewY (y, cx, cy) {
- return this.skew(0, y, cx, cy)
+ skewY ( y, cx, cy ) {
+
+ return this.skew( 0, y, cx, cy )
+
}
- skewYO (y, cx, cy) {
- return this.skewO(0, y, cx, cy)
+ skewYO ( y, cx, cy ) {
+
+ return this.skewO( 0, y, cx, cy )
+
}
// Transform around a center point
- aroundO (cx, cy, matrix) {
+ aroundO ( cx, cy, matrix ) {
+
var dx = cx || 0
var dy = cy || 0
- return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy)
+ return this.translateO( -dx, -dy ).lmultiplyO( matrix ).translateO( dx, dy )
+
}
- around (cx, cy, matrix) {
- return this.clone().aroundO(cx, cy, matrix)
+ around ( cx, cy, matrix ) {
+
+ return this.clone().aroundO( cx, cy, matrix )
+
}
// Check if two matrices are equal
- equals (other) {
- var comp = new Matrix(other)
- return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) &&
- closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) &&
- closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f)
+ equals ( other ) {
+
+ var comp = new Matrix( other )
+ return closeEnough( this.a, comp.a ) && closeEnough( this.b, comp.b )
+ && closeEnough( this.c, comp.c ) && closeEnough( this.d, comp.d )
+ && closeEnough( this.e, comp.e ) && closeEnough( this.f, comp.f )
+
}
// Convert matrix to string
toString () {
+
return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'
+
}
toArray () {
- return [this.a, this.b, this.c, this.d, this.e, this.f]
+
+ return [ this.a, this.b, this.c, this.d, this.e, this.f ]
+
}
valueOf () {
+
return {
a: this.a,
b: this.b,
@@ -400,56 +480,62 @@ export default class Matrix {
e: this.e,
f: this.f
}
+
}
- static fromArray (a) {
+ static fromArray ( a ) {
+
return { a: a[0], b: a[1], c: a[2], d: a[3], e: a[4], f: a[5] }
+
}
- static isMatrixLike (o) {
+ static isMatrixLike ( o ) {
+
return (
- o.a != null ||
- o.b != null ||
- o.c != null ||
- o.d != null ||
- o.e != null ||
- o.f != null
+ o.a != null
+ || o.b != null
+ || o.c != null
+ || o.d != null
+ || o.e != null
+ || o.f != null
)
+
}
- static formatTransforms (o) {
+ static formatTransforms ( o ) {
+
// Get all of the parameters required to form the matrix
var flipBoth = o.flip === 'both' || o.flip === true
- var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1
- var flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1
+ var flipX = o.flip && ( flipBoth || o.flip === 'x' ) ? -1 : 1
+ var flipY = o.flip && ( flipBoth || o.flip === 'y' ) ? -1 : 1
var skewX = o.skew && o.skew.length ? o.skew[0]
- : isFinite(o.skew) ? o.skew
- : isFinite(o.skewX) ? o.skewX
- : 0
+ : isFinite( o.skew ) ? o.skew
+ : isFinite( o.skewX ) ? o.skewX
+ : 0
var skewY = o.skew && o.skew.length ? o.skew[1]
- : isFinite(o.skew) ? o.skew
- : isFinite(o.skewY) ? o.skewY
- : 0
+ : isFinite( o.skew ) ? o.skew
+ : isFinite( o.skewY ) ? o.skewY
+ : 0
var scaleX = o.scale && o.scale.length ? o.scale[0] * flipX
- : isFinite(o.scale) ? o.scale * flipX
- : isFinite(o.scaleX) ? o.scaleX * flipX
- : flipX
+ : isFinite( o.scale ) ? o.scale * flipX
+ : isFinite( o.scaleX ) ? o.scaleX * flipX
+ : flipX
var scaleY = o.scale && o.scale.length ? o.scale[1] * flipY
- : isFinite(o.scale) ? o.scale * flipY
- : isFinite(o.scaleY) ? o.scaleY * flipY
- : flipY
+ : isFinite( o.scale ) ? o.scale * flipY
+ : isFinite( o.scaleY ) ? o.scaleY * flipY
+ : flipY
var shear = o.shear || 0
var theta = o.rotate || o.theta || 0
- var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY)
+ var origin = new Point( o.origin || o.around || o.ox || o.originX, o.oy || o.originY )
var ox = origin.x
var oy = origin.y
- var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY)
+ var position = new Point( o.position || o.px || o.positionX, o.py || o.positionY )
var px = position.x
var py = position.y
- var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY)
+ var translate = new Point( o.translate || o.tx || o.translateX, o.ty || o.translateY )
var tx = translate.x
var ty = translate.y
- var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY)
+ var relative = new Point( o.relative || o.rx || o.relativeX, o.ry || o.relativeY )
var rx = relative.x
var ry = relative.y
@@ -457,10 +543,12 @@ export default class Matrix {
return {
scaleX, scaleY, skewX, skewY, shear, theta, rx, ry, tx, ty, ox, oy, px, py
}
+
}
// left matrix, right matrix, target matrix which is overwritten
- static matrixMultiply (l, r, o) {
+ static matrixMultiply ( l, r, o ) {
+
// Work out the product directly
var a = l.a * r.a + l.c * r.b
var b = l.b * r.a + l.d * r.b
@@ -478,23 +566,31 @@ export default class Matrix {
o.f = f
return o
+
}
+
}
export function ctm () {
- return new Matrix(this.node.getCTM())
+
+ return new Matrix( this.node.getCTM() )
+
}
export function screenCTM () {
+
/* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
This is needed because FF does not return the transformation matrix
for the inner coordinate system when getScreenCTM() is called on nested svgs.
However all other Browsers do that */
- if (typeof this.isRoot === 'function' && !this.isRoot()) {
- var rect = this.rect(1, 1)
+ if ( typeof this.isRoot === 'function' && !this.isRoot() ) {
+
+ var rect = this.rect( 1, 1 )
var m = rect.node.getScreenCTM()
rect.remove()
- return new Matrix(m)
+ return new Matrix( m )
+
}
- return new Matrix(this.node.getScreenCTM())
+ return new Matrix( this.node.getScreenCTM() )
+
}
diff --git a/src/types/Morphable.js b/src/types/Morphable.js
index 703cc00..87fa800 100644
--- a/src/types/Morphable.js
+++ b/src/types/Morphable.js
@@ -11,135 +11,200 @@ import SVGArray from './SVGArray.js'
import SVGNumber from './SVGNumber.js'
export default class Morphable {
- constructor (stepper) {
- this._stepper = stepper || new Ease('-')
+
+ constructor ( stepper ) {
+
+ this._stepper = stepper || new Ease( '-' )
this._from = null
this._to = null
this._type = null
this._context = null
this._morphObj = null
+
}
- from (val) {
- if (val == null) {
+ from ( val ) {
+
+ if ( val == null ) {
+
return this._from
+
}
- this._from = this._set(val)
+ this._from = this._set( val )
return this
+
}
- to (val) {
- if (val == null) {
+ to ( val ) {
+
+ if ( val == null ) {
+
return this._to
+
}
- this._to = this._set(val)
+ this._to = this._set( val )
return this
+
}
- type (type) {
+ type ( type ) {
+
// getter
- if (type == null) {
+ if ( type == null ) {
+
return this._type
+
}
// setter
this._type = type
return this
+
}
- _set (value) {
- if (!this._type) {
+ _set ( value ) {
+
+ if ( !this._type ) {
+
var type = typeof value
- if (type === 'number') {
- this.type(SVGNumber)
- } else if (type === 'string') {
- if (Color.isColor(value)) {
- this.type(Color)
- } else if (delimiter.test(value)) {
- this.type(pathLetters.test(value)
+ if ( type === 'number' ) {
+
+ this.type( SVGNumber )
+
+ } else if ( type === 'string' ) {
+
+ if ( Color.isColor( value ) ) {
+
+ this.type( Color )
+
+ } else if ( delimiter.test( value ) ) {
+
+ this.type( pathLetters.test( value )
? PathArray
: SVGArray
)
- } else if (numberAndUnit.test(value)) {
- this.type(SVGNumber)
+
+ } else if ( numberAndUnit.test( value ) ) {
+
+ this.type( SVGNumber )
+
} else {
- this.type(NonMorphable)
+
+ this.type( NonMorphable )
+
}
- } else if (morphableTypes.indexOf(value.constructor) > -1) {
- this.type(value.constructor)
- } else if (Array.isArray(value)) {
- this.type(SVGArray)
- } else if (type === 'object') {
- this.type(ObjectBag)
+
+ } else if ( morphableTypes.indexOf( value.constructor ) > -1 ) {
+
+ this.type( value.constructor )
+
+ } else if ( Array.isArray( value ) ) {
+
+ this.type( SVGArray )
+
+ } else if ( type === 'object' ) {
+
+ this.type( ObjectBag )
+
} else {
- this.type(NonMorphable)
+
+ this.type( NonMorphable )
+
}
+
}
- var result = (new this._type(value)).toArray()
+ var result = ( new this._type( value ) ).toArray()
this._morphObj = this._morphObj || new this._type()
- this._context = this._context ||
- Array.apply(null, Array(result.length)).map(Object)
+ this._context = this._context
+ || Array.apply( null, Array( result.length ) ).map( Object )
return result
+
}
- stepper (stepper) {
- if (stepper == null) return this._stepper
+ stepper ( stepper ) {
+
+ if ( stepper == null ) return this._stepper
this._stepper = stepper
return this
+
}
done () {
+
var complete = this._context
- .map(this._stepper.done)
- .reduce(function (last, curr) {
+ .map( this._stepper.done )
+ .reduce( function ( last, curr ) {
+
return last && curr
- }, true)
+
+ }, true )
return complete
+
}
- at (pos) {
+ at ( pos ) {
+
var _this = this
return this._morphObj.fromArray(
- this._from.map(function (i, index) {
- return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context)
- })
+ this._from.map( function ( i, index ) {
+
+ return _this._stepper.step( i, _this._to[index], pos, _this._context[index], _this._context )
+
+ } )
)
+
}
+
}
export class NonMorphable {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (val) {
- val = Array.isArray(val) ? val[0] : val
+ init ( val ) {
+
+ val = Array.isArray( val ) ? val[0] : val
this.value = val
return this
+
}
valueOf () {
+
return this.value
+
}
toArray () {
- return [this.value]
+
+ return [ this.value ]
+
}
+
}
export class TransformBag {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (obj) {
- if (Array.isArray(obj)) {
+ init ( obj ) {
+
+ if ( Array.isArray( obj ) ) {
+
obj = {
scaleX: obj[0],
scaleY: obj[1],
@@ -150,13 +215,16 @@ export class TransformBag {
originX: obj[6],
originY: obj[7]
}
+
}
- Object.assign(this, TransformBag.defaults, obj)
+ Object.assign( this, TransformBag.defaults, obj )
return this
+
}
toArray () {
+
var v = this
return [
@@ -169,7 +237,9 @@ export class TransformBag {
v.originX,
v.originY
]
+
}
+
}
TransformBag.defaults = {
@@ -184,40 +254,56 @@ TransformBag.defaults = {
}
export class ObjectBag {
- constructor (...args) {
- this.init(...args)
+
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (objOrArr) {
+ init ( objOrArr ) {
+
this.values = []
- if (Array.isArray(objOrArr)) {
+ if ( Array.isArray( objOrArr ) ) {
+
this.values = objOrArr
return
+
}
- var entries = Object.entries(objOrArr || {}).sort((a, b) => {
+ var entries = Object.entries( objOrArr || {} ).sort( ( a, b ) => {
+
return a[0] - b[0]
- })
- this.values = entries.reduce((last, curr) => last.concat(curr), [])
+ } )
+
+ this.values = entries.reduce( ( last, curr ) => last.concat( curr ), [] )
return this
+
}
valueOf () {
+
var obj = {}
var arr = this.values
- for (var i = 0, len = arr.length; i < len; i += 2) {
+ for ( var i = 0, len = arr.length; i < len; i += 2 ) {
+
obj[arr[i]] = arr[i + 1]
+
}
return obj
+
}
toArray () {
+
return this.values
+
}
+
}
const morphableTypes = [
@@ -226,21 +312,29 @@ const morphableTypes = [
ObjectBag
]
-export function registerMorphableType (type = []) {
- morphableTypes.push(...[].concat(type))
+export function registerMorphableType ( type = [] ) {
+
+ morphableTypes.push( ...[].concat( type ) )
+
}
export function makeMorphable () {
- extend(morphableTypes, {
- to (val) {
+
+ extend( morphableTypes, {
+ to ( val ) {
+
return new Morphable()
- .type(this.constructor)
- .from(this.valueOf())
- .to(val)
+ .type( this.constructor )
+ .from( this.valueOf() )
+ .to( val )
+
},
- fromArray (arr) {
- this.init(arr)
+ fromArray ( arr ) {
+
+ this.init( arr )
return this
+
}
- })
+ } )
+
}
diff --git a/src/types/PathArray.js b/src/types/PathArray.js
index 989cd8f..739218d 100644
--- a/src/types/PathArray.js
+++ b/src/types/PathArray.js
@@ -12,131 +12,182 @@ import Point from './Point.js'
import SVGArray from './SVGArray.js'
import parser from '../modules/core/parser.js'
-const PathArray = subClassArray('PathArray', SVGArray)
+const PathArray = subClassArray( 'PathArray', SVGArray )
export default PathArray
-export function pathRegReplace (a, b, c, d) {
- return c + d.replace(dots, ' .')
+export function pathRegReplace ( a, b, c, d ) {
+
+ return c + d.replace( dots, ' .' )
+
}
-function arrayToString (a) {
- for (var i = 0, il = a.length, s = ''; i < il; i++) {
+function arrayToString ( a ) {
+
+ for ( var i = 0, il = a.length, s = ''; i < il; i++ ) {
+
s += a[i][0]
- if (a[i][1] != null) {
+ if ( a[i][1] != null ) {
+
s += a[i][1]
- if (a[i][2] != null) {
+ if ( a[i][2] != null ) {
+
s += ' '
s += a[i][2]
- if (a[i][3] != null) {
+ if ( a[i][3] != null ) {
+
s += ' '
s += a[i][3]
s += ' '
s += a[i][4]
- if (a[i][5] != null) {
+ if ( a[i][5] != null ) {
+
s += ' '
s += a[i][5]
s += ' '
s += a[i][6]
- if (a[i][7] != null) {
+ if ( a[i][7] != null ) {
+
s += ' '
s += a[i][7]
+
}
+
}
+
}
+
}
+
}
+
}
return s + ' '
+
}
const pathHandlers = {
- M: function (c, p, p0) {
+ M: function ( c, p, p0 ) {
+
p.x = p0.x = c[0]
p.y = p0.y = c[1]
- return ['M', p.x, p.y]
+ return [ 'M', p.x, p.y ]
+
},
- L: function (c, p) {
+ L: function ( c, p ) {
+
p.x = c[0]
p.y = c[1]
- return ['L', c[0], c[1]]
+ return [ 'L', c[0], c[1] ]
+
},
- H: function (c, p) {
+ H: function ( c, p ) {
+
p.x = c[0]
- return ['H', c[0]]
+ return [ 'H', c[0] ]
+
},
- V: function (c, p) {
+ V: function ( c, p ) {
+
p.y = c[0]
- return ['V', c[0]]
+ return [ 'V', c[0] ]
+
},
- C: function (c, p) {
+ C: function ( c, p ) {
+
p.x = c[4]
p.y = c[5]
- return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]
+ return [ 'C', c[0], c[1], c[2], c[3], c[4], c[5] ]
+
},
- S: function (c, p) {
+ S: function ( c, p ) {
+
p.x = c[2]
p.y = c[3]
- return ['S', c[0], c[1], c[2], c[3]]
+ return [ 'S', c[0], c[1], c[2], c[3] ]
+
},
- Q: function (c, p) {
+ Q: function ( c, p ) {
+
p.x = c[2]
p.y = c[3]
- return ['Q', c[0], c[1], c[2], c[3]]
+ return [ 'Q', c[0], c[1], c[2], c[3] ]
+
},
- T: function (c, p) {
+ T: function ( c, p ) {
+
p.x = c[0]
p.y = c[1]
- return ['T', c[0], c[1]]
+ return [ 'T', c[0], c[1] ]
+
},
- Z: function (c, p, p0) {
+ Z: function ( c, p, p0 ) {
+
p.x = p0.x
p.y = p0.y
- return ['Z']
+ return [ 'Z' ]
+
},
- A: function (c, p) {
+ A: function ( c, p ) {
+
p.x = c[5]
p.y = c[6]
- return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]
+ return [ 'A', c[0], c[1], c[2], c[3], c[4], c[5], c[6] ]
+
}
}
-let mlhvqtcsaz = 'mlhvqtcsaz'.split('')
+let mlhvqtcsaz = 'mlhvqtcsaz'.split( '' )
+
+for ( var i = 0, il = mlhvqtcsaz.length; i < il; ++i ) {
+
+ pathHandlers[mlhvqtcsaz[i]] = ( function ( i ) {
+
+ return function ( c, p, p0 ) {
+
+ if ( i === 'H' ) c[0] = c[0] + p.x
+ else if ( i === 'V' ) c[0] = c[0] + p.y
+ else if ( i === 'A' ) {
-for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
- pathHandlers[mlhvqtcsaz[i]] = (function (i) {
- return function (c, p, p0) {
- if (i === 'H') c[0] = c[0] + p.x
- else if (i === 'V') c[0] = c[0] + p.y
- else if (i === 'A') {
c[5] = c[5] + p.x
c[6] = c[6] + p.y
+
} else {
- for (var j = 0, jl = c.length; j < jl; ++j) {
- c[j] = c[j] + (j % 2 ? p.y : p.x)
+
+ for ( var j = 0, jl = c.length; j < jl; ++j ) {
+
+ c[j] = c[j] + ( j % 2 ? p.y : p.x )
+
}
+
}
- return pathHandlers[i](c, p, p0)
+ return pathHandlers[i]( c, p, p0 )
+
}
- })(mlhvqtcsaz[i].toUpperCase())
+
+ } )( mlhvqtcsaz[i].toUpperCase() )
+
}
-extend(PathArray, {
+extend( PathArray, {
// Convert array to string
toString () {
- return arrayToString(this)
+
+ return arrayToString( this )
+
},
// Move path string
- move (x, y) {
+ move ( x, y ) {
+
// get bounding box of current situation
var box = this.bbox()
@@ -144,110 +195,154 @@ extend(PathArray, {
x -= box.x
y -= box.y
- if (!isNaN(x) && !isNaN(y)) {
+ if ( !isNaN( x ) && !isNaN( y ) ) {
+
// move every point
- for (var l, i = this.length - 1; i >= 0; i--) {
+ for ( var l, i = this.length - 1; i >= 0; i-- ) {
+
l = this[i][0]
- if (l === 'M' || l === 'L' || l === 'T') {
+ if ( l === 'M' || l === 'L' || l === 'T' ) {
+
this[i][1] += x
this[i][2] += y
- } else if (l === 'H') {
+
+ } else if ( l === 'H' ) {
+
this[i][1] += x
- } else if (l === 'V') {
+
+ } else if ( l === 'V' ) {
+
this[i][1] += y
- } else if (l === 'C' || l === 'S' || l === 'Q') {
+
+ } else if ( l === 'C' || l === 'S' || l === 'Q' ) {
+
this[i][1] += x
this[i][2] += y
this[i][3] += x
this[i][4] += y
- if (l === 'C') {
+ if ( l === 'C' ) {
+
this[i][5] += x
this[i][6] += y
+
}
- } else if (l === 'A') {
+
+ } else if ( l === 'A' ) {
+
this[i][6] += x
this[i][7] += y
+
}
+
}
+
}
return this
+
},
// Resize path string
- size (width, height) {
+ size ( width, height ) {
+
// get bounding box of current situation
var box = this.bbox()
var i, l
// recalculate position of all points according to new size
- for (i = this.length - 1; i >= 0; i--) {
+ for ( i = this.length - 1; i >= 0; i-- ) {
+
l = this[i][0]
- if (l === 'M' || l === 'L' || l === 'T') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- this[i][2] = ((this[i][2] - box.y) * height) / box.height + box.y
- } else if (l === 'H') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- } else if (l === 'V') {
- this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y
- } else if (l === 'C' || l === 'S' || l === 'Q') {
- this[i][1] = ((this[i][1] - box.x) * width) / box.width + box.x
- this[i][2] = ((this[i][2] - box.y) * height) / box.height + box.y
- this[i][3] = ((this[i][3] - box.x) * width) / box.width + box.x
- this[i][4] = ((this[i][4] - box.y) * height) / box.height + box.y
-
- if (l === 'C') {
- this[i][5] = ((this[i][5] - box.x) * width) / box.width + box.x
- this[i][6] = ((this[i][6] - box.y) * height) / box.height + box.y
+ if ( l === 'M' || l === 'L' || l === 'T' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+ this[i][2] = ( ( this[i][2] - box.y ) * height ) / box.height + box.y
+
+ } else if ( l === 'H' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+
+ } else if ( l === 'V' ) {
+
+ this[i][1] = ( ( this[i][1] - box.y ) * height ) / box.height + box.y
+
+ } else if ( l === 'C' || l === 'S' || l === 'Q' ) {
+
+ this[i][1] = ( ( this[i][1] - box.x ) * width ) / box.width + box.x
+ this[i][2] = ( ( this[i][2] - box.y ) * height ) / box.height + box.y
+ this[i][3] = ( ( this[i][3] - box.x ) * width ) / box.width + box.x
+ this[i][4] = ( ( this[i][4] - box.y ) * height ) / box.height + box.y
+
+ if ( l === 'C' ) {
+
+ this[i][5] = ( ( this[i][5] - box.x ) * width ) / box.width + box.x
+ this[i][6] = ( ( this[i][6] - box.y ) * height ) / box.height + box.y
+
}
- } else if (l === 'A') {
+
+ } else if ( l === 'A' ) {
+
// resize radii
- this[i][1] = (this[i][1] * width) / box.width
- this[i][2] = (this[i][2] * height) / box.height
+ this[i][1] = ( this[i][1] * width ) / box.width
+ this[i][2] = ( this[i][2] * height ) / box.height
// move position values
- this[i][6] = ((this[i][6] - box.x) * width) / box.width + box.x
- this[i][7] = ((this[i][7] - box.y) * height) / box.height + box.y
+ this[i][6] = ( ( this[i][6] - box.x ) * width ) / box.width + box.x
+ this[i][7] = ( ( this[i][7] - box.y ) * height ) / box.height + box.y
+
}
+
}
return this
+
},
// Test if the passed path array use the same path data commands as this path array
- equalCommands (pathArray) {
+ equalCommands ( pathArray ) {
+
var i, il, equalCommands
- pathArray = new PathArray(pathArray)
+ pathArray = new PathArray( pathArray )
equalCommands = this.length === pathArray.length
- for (i = 0, il = this.length; equalCommands && i < il; i++) {
+ for ( i = 0, il = this.length; equalCommands && i < il; i++ ) {
+
equalCommands = this[i][0] === pathArray[i][0]
+
}
return equalCommands
+
},
// Make path array morphable
- morph (pathArray) {
- pathArray = new PathArray(pathArray)
+ morph ( pathArray ) {
+
+ pathArray = new PathArray( pathArray )
+
+ if ( this.equalCommands( pathArray ) ) {
- if (this.equalCommands(pathArray)) {
this.destination = pathArray
+
} else {
+
this.destination = null
+
}
return this
+
},
// Get morphed path array at given position
- at (pos) {
+ at ( pos ) {
+
// make sure a destination is defined
- if (!this.destination) return this
+ if ( !this.destination ) return this
var sourceArray = this
var destinationArray = this.destination.value
@@ -257,47 +352,61 @@ extend(PathArray, {
// Animate has specified in the SVG spec
// See: https://www.w3.org/TR/SVG11/paths.html#PathElement
- for (i = 0, il = sourceArray.length; i < il; i++) {
- array[i] = [sourceArray[i][0]]
- for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
- array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
+ for ( i = 0, il = sourceArray.length; i < il; i++ ) {
+
+ array[i] = [ sourceArray[i][0] ]
+ for ( j = 1, jl = sourceArray[i].length; j < jl; j++ ) {
+
+ array[i][j] = sourceArray[i][j] + ( destinationArray[i][j] - sourceArray[i][j] ) * pos
+
}
// For the two flags of the elliptical arc command, the SVG spec say:
// Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
// Elliptical arc command as an array followed by corresponding indexes:
// ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
// 0 1 2 3 4 5 6 7
- if (array[i][0] === 'A') {
- array[i][4] = +(array[i][4] !== 0)
- array[i][5] = +(array[i][5] !== 0)
+ if ( array[i][0] === 'A' ) {
+
+ array[i][4] = +( array[i][4] !== 0 )
+ array[i][5] = +( array[i][5] !== 0 )
+
}
+
}
// Directly modify the value of a path array, this is done this way for performance
pathArray.value = array
return pathArray
+
},
// Absolutize and parse path to array
- parse (array = [['M', 0, 0]]) {
+ parse ( array = [ [ 'M', 0, 0 ] ] ) {
+
// if it's already a patharray, no need to parse it
- if (array instanceof PathArray) return array
+ if ( array instanceof PathArray ) return array
// prepare for parsing
var s
var paramCnt = { 'M': 2, 'L': 2, 'H': 1, 'V': 1, 'C': 6, 'S': 4, 'Q': 4, 'T': 2, 'A': 7, 'Z': 0 }
- if (typeof array === 'string') {
+ if ( typeof array === 'string' ) {
+
array = array
- .replace(numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
- .replace(pathLetters, ' $& ') // put some room between letters and numbers
- .replace(hyphen, '$1 -') // add space before hyphen
+ .replace( numbersWithDots, pathRegReplace ) // convert 45.123.123 to 45.123 .123
+ .replace( pathLetters, ' $& ' ) // put some room between letters and numbers
+ .replace( hyphen, '$1 -' ) // add space before hyphen
.trim() // trim
- .split(delimiter) // split into array
+ .split( delimiter ) // split into array
+
} else {
- array = array.reduce(function (prev, curr) {
- return [].concat.call(prev, curr)
- }, [])
+
+ array = array.reduce( function ( prev, curr ) {
+
+ return [].concat.call( prev, curr )
+
+ }, [] )
+
}
// array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
@@ -308,30 +417,41 @@ extend(PathArray, {
var len = array.length
do {
+
// Test if we have a path letter
- if (isPathLetter.test(array[index])) {
+ if ( isPathLetter.test( array[index] ) ) {
+
s = array[index]
++index
- // If last letter was a move command and we got no new, it defaults to [L]ine
- } else if (s === 'M') {
+ // If last letter was a move command and we got no new, it defaults to [L]ine
+
+ } else if ( s === 'M' ) {
+
s = 'L'
- } else if (s === 'm') {
+
+ } else if ( s === 'm' ) {
+
s = 'l'
+
}
- result.push(pathHandlers[s].call(null,
- array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat),
+ result.push( pathHandlers[s].call( null,
+ array.slice( index, ( index = index + paramCnt[s.toUpperCase()] ) ).map( parseFloat ),
p, p0
)
)
- } while (len > index)
+
+ } while ( len > index )
return result
+
},
// Get bounding box of path
bbox () {
- parser().path.setAttribute('d', this.toString())
+
+ parser().path.setAttribute( 'd', this.toString() )
return parser.nodes.path.getBBox()
+
}
-})
+} )
diff --git a/src/types/Point.js b/src/types/Point.js
index 27d81ea..16ae44d 100644
--- a/src/types/Point.js
+++ b/src/types/Point.js
@@ -1,45 +1,59 @@
export default class Point {
+
// Initialize
- constructor (...args) {
- this.init(...args)
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (x, y) {
+ init ( x, y ) {
+
let source
let base = { x: 0, y: 0 }
// ensure source as object
- source = Array.isArray(x) ? { x: x[0], y: x[1] }
+ source = Array.isArray( x ) ? { x: x[0], y: x[1] }
: typeof x === 'object' ? { x: x.x, y: x.y }
- : { x: x, y: y }
+ : { x: x, y: y }
// merge source
this.x = source.x == null ? base.x : source.x
this.y = source.y == null ? base.y : source.y
return this
+
}
// Clone point
clone () {
- return new Point(this)
+
+ return new Point( this )
+
}
// transform point with matrix
- transform (m) {
+ transform ( m ) {
+
// Perform the matrix multiplication
var x = m.a * this.x + m.c * this.y + m.e
var y = m.b * this.x + m.d * this.y + m.f
// Return the required point
- return new Point(x, y)
+ return new Point( x, y )
+
}
toArray () {
- return [this.x, this.y]
+
+ return [ this.x, this.y ]
+
}
+
}
-export function point (x, y) {
- return new Point(x, y).transform(this.screenCTM().inverse())
+export function point ( x, y ) {
+
+ return new Point( x, y ).transform( this.screenCTM().inverse() )
+
}
diff --git a/src/types/PointArray.js b/src/types/PointArray.js
index b246b2f..581b7dc 100644
--- a/src/types/PointArray.js
+++ b/src/types/PointArray.js
@@ -3,76 +3,97 @@ import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
import SVGArray from './SVGArray.js'
-const PointArray = subClassArray('PointArray', SVGArray)
+const PointArray = subClassArray( 'PointArray', SVGArray )
export default PointArray
-extend(PointArray, {
+extend( PointArray, {
// Convert array to string
toString () {
+
// convert to a poly point string
- for (var i = 0, il = this.length, array = []; i < il; i++) {
- array.push(this[i].join(','))
+ for ( var i = 0, il = this.length, array = []; i < il; i++ ) {
+
+ array.push( this[i].join( ',' ) )
+
}
- return array.join(' ')
+ return array.join( ' ' )
+
},
// Convert array to line object
toLine () {
+
return {
x1: this[0][0],
y1: this[0][1],
x2: this[1][0],
y2: this[1][1]
}
+
},
// Get morphed array at given position
- at (pos) {
+ at ( pos ) {
+
// make sure a destination is defined
- if (!this.destination) return this
+ if ( !this.destination ) return this
// generate morphed point string
- for (var i = 0, il = this.length, array = []; i < il; i++) {
- array.push([
- this[i][0] + (this.destination[i][0] - this[i][0]) * pos,
- this[i][1] + (this.destination[i][1] - this[i][1]) * pos
- ])
+ for ( var i = 0, il = this.length, array = []; i < il; i++ ) {
+
+ array.push( [
+ this[i][0] + ( this.destination[i][0] - this[i][0] ) * pos,
+ this[i][1] + ( this.destination[i][1] - this[i][1] ) * pos
+ ] )
+
}
- return new PointArray(array)
+ return new PointArray( array )
+
},
// Parse point string and flat array
- parse (array = [[0, 0]]) {
+ parse ( array = [ [ 0, 0 ] ] ) {
+
var points = []
// if it is an array
- if (array instanceof Array) {
+ if ( array instanceof Array ) {
+
// and it is not flat, there is no need to parse it
- if (array[0] instanceof Array) {
+ if ( array[0] instanceof Array ) {
+
return array
+
}
+
} else { // Else, it is considered as a string
+
// parse points
- array = array.trim().split(delimiter).map(parseFloat)
+ array = array.trim().split( delimiter ).map( parseFloat )
+
}
// validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
// Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
- if (array.length % 2 !== 0) array.pop()
+ if ( array.length % 2 !== 0 ) array.pop()
// wrap points in two-tuples and parse points as floats
- for (var i = 0, len = array.length; i < len; i = i + 2) {
- points.push([ array[i], array[i + 1] ])
+ for ( var i = 0, len = array.length; i < len; i = i + 2 ) {
+
+ points.push( [ array[i], array[i + 1] ] )
+
}
return points
+
},
// Move point string
- move (x, y) {
+ move ( x, y ) {
+
var box = this.bbox()
// get relative offset
@@ -80,41 +101,54 @@ extend(PointArray, {
y -= box.y
// move every point
- if (!isNaN(x) && !isNaN(y)) {
- for (var i = this.length - 1; i >= 0; i--) {
- this[i] = [this[i][0] + x, this[i][1] + y]
+ if ( !isNaN( x ) && !isNaN( y ) ) {
+
+ for ( var i = this.length - 1; i >= 0; i-- ) {
+
+ this[i] = [ this[i][0] + x, this[i][1] + y ]
+
}
+
}
return this
+
},
// Resize poly string
- size (width, height) {
+ size ( width, height ) {
+
var i
var box = this.bbox()
// recalculate position of all points according to new size
- for (i = this.length - 1; i >= 0; i--) {
- if (box.width) this[i][0] = ((this[i][0] - box.x) * width) / box.width + box.x
- if (box.height) this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y
+ for ( i = this.length - 1; i >= 0; i-- ) {
+
+ if ( box.width ) this[i][0] = ( ( this[i][0] - box.x ) * width ) / box.width + box.x
+ if ( box.height ) this[i][1] = ( ( this[i][1] - box.y ) * height ) / box.height + box.y
+
}
return this
+
},
// Get bounding box of points
bbox () {
+
var maxX = -Infinity
var maxY = -Infinity
var minX = Infinity
var minY = Infinity
- this.forEach(function (el) {
- maxX = Math.max(el[0], maxX)
- maxY = Math.max(el[1], maxY)
- minX = Math.min(el[0], minX)
- minY = Math.min(el[1], minY)
- })
+ this.forEach( function ( el ) {
+
+ maxX = Math.max( el[0], maxX )
+ maxY = Math.max( el[1], maxY )
+ minX = Math.min( el[0], minX )
+ minY = Math.min( el[1], minY )
+
+ } )
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
+
}
-})
+} )
diff --git a/src/types/SVGArray.js b/src/types/SVGArray.js
index 7f27ec4..7d59af1 100644
--- a/src/types/SVGArray.js
+++ b/src/types/SVGArray.js
@@ -2,49 +2,65 @@ import { delimiter } from '../modules/core/regex.js'
import { extend } from '../utils/adopter.js'
import { subClassArray } from './ArrayPolyfill.js'
-const SVGArray = subClassArray('SVGArray', Array, function (arr) {
- this.init(arr)
-})
+const SVGArray = subClassArray( 'SVGArray', Array, function ( arr ) {
+
+ this.init( arr )
+
+} )
export default SVGArray
-extend(SVGArray, {
- init (arr) {
+extend( SVGArray, {
+ init ( arr ) {
+
// This catches the case, that native map tries to create an array with new Array(1)
- if (typeof arr === 'number') return this
+ if ( typeof arr === 'number' ) return this
this.length = 0
- this.push(...this.parse(arr))
+ this.push( ...this.parse( arr ) )
return this
+
},
toArray () {
- return Array.prototype.concat.apply([], this)
+
+ return Array.prototype.concat.apply( [], this )
+
},
toString () {
- return this.join(' ')
+
+ return this.join( ' ' )
+
},
// Flattens the array if needed
valueOf () {
+
const ret = []
- ret.push(...this)
+ ret.push( ...this )
return ret
+
},
// Parse whitespace separated string
- parse (array = []) {
+ parse ( array = [] ) {
+
// If already is an array, no need to parse it
- if (array instanceof Array) return array
+ if ( array instanceof Array ) return array
+
+ return array.trim().split( delimiter ).map( parseFloat )
- return array.trim().split(delimiter).map(parseFloat)
},
clone () {
- return new this.constructor(this)
+
+ return new this.constructor( this )
+
},
toSet () {
- return new Set(this)
+
+ return new Set( this )
+
}
-})
+} )
diff --git a/src/types/SVGNumber.js b/src/types/SVGNumber.js
index ea21cbd..a35ed66 100644
--- a/src/types/SVGNumber.js
+++ b/src/types/SVGNumber.js
@@ -2,88 +2,126 @@ import { numberAndUnit } from '../modules/core/regex.js'
// Module for unit convertions
export default class SVGNumber {
+
// Initialize
- constructor (...args) {
- this.init(...args)
+ constructor ( ...args ) {
+
+ this.init( ...args )
+
}
- init (value, unit) {
- unit = Array.isArray(value) ? value[1] : unit
- value = Array.isArray(value) ? value[0] : value
+ init ( value, unit ) {
+
+ unit = Array.isArray( value ) ? value[1] : unit
+ value = Array.isArray( value ) ? value[0] : value
// initialize defaults
this.value = 0
this.unit = unit || ''
// parse value
- if (typeof value === 'number') {
+ if ( typeof value === 'number' ) {
+
// ensure a valid numeric value
- this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
- } else if (typeof value === 'string') {
- unit = value.match(numberAndUnit)
+ this.value = isNaN( value ) ? 0 : !isFinite( value ) ? ( value < 0 ? -3.4e+38 : +3.4e+38 ) : value
+
+ } else if ( typeof value === 'string' ) {
+
+ unit = value.match( numberAndUnit )
+
+ if ( unit ) {
- if (unit) {
// make value numeric
- this.value = parseFloat(unit[1])
+ this.value = parseFloat( unit[1] )
// normalize
- if (unit[5] === '%') { this.value /= 100 } else if (unit[5] === 's') {
+ if ( unit[5] === '%' ) {
+
+ this.value /= 100
+
+ } else if ( unit[5] === 's' ) {
+
this.value *= 1000
+
}
// store unit
this.unit = unit[5]
+
}
+
} else {
- if (value instanceof SVGNumber) {
+
+ if ( value instanceof SVGNumber ) {
+
this.value = value.valueOf()
this.unit = value.unit
+
}
+
}
return this
+
}
toString () {
- return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6
+
+ return ( this.unit === '%' ? ~~( this.value * 1e8 ) / 1e6
: this.unit === 's' ? this.value / 1e3
- : this.value
+ : this.value
) + this.unit
+
}
toJSON () {
+
return this.toString()
+
}
toArray () {
- return [this.value, this.unit]
+
+ return [ this.value, this.unit ]
+
}
valueOf () {
+
return this.value
+
}
// Add number
- plus (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this + number, this.unit || number.unit)
+ plus ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this + number, this.unit || number.unit )
+
}
// Subtract number
- minus (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this - number, this.unit || number.unit)
+ minus ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this - number, this.unit || number.unit )
+
}
// Multiply number
- times (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this * number, this.unit || number.unit)
+ times ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this * number, this.unit || number.unit )
+
}
// Divide number
- divide (number) {
- number = new SVGNumber(number)
- return new SVGNumber(this / number, this.unit || number.unit)
+ divide ( number ) {
+
+ number = new SVGNumber( number )
+ return new SVGNumber( this / number, this.unit || number.unit )
+
}
+
}
diff --git a/src/utils/adopter.js b/src/utils/adopter.js
index 80bfd8a..6e526e3 100644
--- a/src/utils/adopter.js
+++ b/src/utils/adopter.js
@@ -5,136 +5,190 @@ import { globals } from '../utils/window.js'
import Base from '../types/Base.js'
const elements = {}
-export const root = Symbol('root')
+export const root = Symbol( 'root' )
// Method for element creation
-export function makeNode (name) {
+export function makeNode ( name ) {
+
// create element
- return globals.document.createElementNS(ns, name)
+ return globals.document.createElementNS( ns, name )
+
}
-export function makeInstance (element) {
- if (element instanceof Base) return element
+export function makeInstance ( element ) {
+
+ if ( element instanceof Base ) return element
+
+ if ( typeof element === 'object' ) {
+
+ return adopt( element )
- if (typeof element === 'object') {
- return adopt(element)
}
- if (element == null) {
+ if ( element == null ) {
+
return new elements[root]()
+
}
- if (typeof element === 'string' && element.charAt(0) !== '<') {
- return adopt(globals.document.querySelector(element))
+ if ( typeof element === 'string' && element.charAt( 0 ) !== '<' ) {
+
+ return adopt( globals.document.querySelector( element ) )
+
}
- var node = makeNode('svg')
+ var node = makeNode( 'svg' )
node.innerHTML = element
// We can use firstChild here because we know,
// that the first char is < and thus an element
- element = adopt(node.firstChild)
+ element = adopt( node.firstChild )
return element
+
}
-export function nodeOrNew (name, node) {
- return node instanceof globals.window.Node ? node : makeNode(name)
+export function nodeOrNew ( name, node ) {
+
+ return node instanceof globals.window.Node ? node : makeNode( name )
+
}
// Adopt existing svg elements
-export function adopt (node) {
+export function adopt ( node ) {
+
// check for presence of node
- if (!node) return null
+ if ( !node ) return null
// make sure a node isn't already adopted
- if (node.instance instanceof Base) return node.instance
+ if ( node.instance instanceof Base ) return node.instance
+
+ if ( !( node instanceof globals.window.SVGElement ) ) {
+
+ return new elements.HtmlNode( node )
- if (!(node instanceof globals.window.SVGElement)) {
- return new elements.HtmlNode(node)
}
// initialize variables
var element
// adopt with element-specific settings
- if (node.nodeName === 'svg') {
- element = new elements[root](node)
- } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
- element = new elements.Gradient(node)
- } else if (elements[capitalize(node.nodeName)]) {
- element = new elements[capitalize(node.nodeName)](node)
+ if ( node.nodeName === 'svg' ) {
+
+ element = new elements[root]( node )
+
+ } else if ( node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient' ) {
+
+ element = new elements.Gradient( node )
+
+ } else if ( elements[capitalize( node.nodeName )] ) {
+
+ element = new elements[capitalize( node.nodeName )]( node )
+
} else {
- element = new elements.Bare(node)
+
+ element = new elements.Bare( node )
+
}
return element
+
}
-export function register (element, name = element.name, asRoot = false) {
+export function register ( element, name = element.name, asRoot = false ) {
+
elements[name] = element
- if (asRoot) elements[root] = element
+ if ( asRoot ) elements[root] = element
- addMethodNames(Object.keys(element.prototype))
+ addMethodNames( Object.keys( element.prototype ) )
return element
+
}
-export function getClass (name) {
+export function getClass ( name ) {
+
return elements[name]
+
}
// Element id sequence
let did = 1000
// Get next named element id
-export function eid (name) {
- return 'Svgjs' + capitalize(name) + (did++)
+export function eid ( name ) {
+
+ return 'Svgjs' + capitalize( name ) + ( did++ )
+
}
// Deep new id assignment
-export function assignNewId (node) {
+export function assignNewId ( node ) {
+
// do the same for SVG child nodes as well
- for (var i = node.children.length - 1; i >= 0; i--) {
- assignNewId(node.children[i])
+ for ( var i = node.children.length - 1; i >= 0; i-- ) {
+
+ assignNewId( node.children[i] )
+
}
- if (node.id) {
- return adopt(node).id(eid(node.nodeName))
+ if ( node.id ) {
+
+ return adopt( node ).id( eid( node.nodeName ) )
+
}
- return adopt(node)
+ return adopt( node )
+
}
// Method for extending objects
-export function extend (modules, methods, attrCheck) {
+export function extend ( modules, methods, attrCheck ) {
+
var key, i
- modules = Array.isArray(modules) ? modules : [modules]
+ modules = Array.isArray( modules ) ? modules : [ modules ]
+
+ for ( i = modules.length - 1; i >= 0; i-- ) {
+
+ for ( key in methods ) {
- for (i = modules.length - 1; i >= 0; i--) {
- for (key in methods) {
let method = methods[key]
- if (attrCheck) {
- method = wrapWithAttrCheck(methods[key])
+ if ( attrCheck ) {
+
+ method = wrapWithAttrCheck( methods[key] )
+
}
modules[i].prototype[key] = method
+
}
+
}
+
}
-export function extendWithAttrCheck (...args) {
- extend(...args, true)
+export function extendWithAttrCheck ( ...args ) {
+
+ extend( ...args, true )
+
}
-export function wrapWithAttrCheck (fn) {
- return function (...args) {
+export function wrapWithAttrCheck ( fn ) {
+
+ return function ( ...args ) {
+
let o = args[args.length - 1]
- if (o && o.constructor === Object && !(o instanceof Array)) {
- return fn.apply(this, args.slice(0, -1)).attr(o)
+ if ( o && o.constructor === Object && !( o instanceof Array ) ) {
+
+ return fn.apply( this, args.slice( 0, -1 ) ).attr( o )
+
} else {
- return fn.apply(this, args)
+
+ return fn.apply( this, args )
+
}
+
}
+
}
diff --git a/src/utils/methods.js b/src/utils/methods.js
index 70f9329..4973d13 100644
--- a/src/utils/methods.js
+++ b/src/utils/methods.js
@@ -2,41 +2,61 @@ const methods = {}
const constructors = {}
const names = []
-export function registerMethods (name, m) {
- if (Array.isArray(name)) {
- for (let _name of name) {
- registerMethods(_name, m)
+export function registerMethods ( name, m ) {
+
+ if ( Array.isArray( name ) ) {
+
+ for ( let _name of name ) {
+
+ registerMethods( _name, m )
+
}
return
+
}
- if (typeof name === 'object') {
- for (let [_name, _m] of Object.entries(name)) {
- registerMethods(_name, _m)
+ if ( typeof name === 'object' ) {
+
+ for ( let [ _name, _m ] of Object.entries( name ) ) {
+
+ registerMethods( _name, _m )
+
}
return
+
}
- addMethodNames(Object.keys(m))
- methods[name] = Object.assign(methods[name] || {}, m)
+ addMethodNames( Object.keys( m ) )
+ methods[name] = Object.assign( methods[name] || {}, m )
+
}
-export function getMethodsFor (name) {
+export function getMethodsFor ( name ) {
+
return methods[name] || {}
+
}
export function getMethodNames () {
- return [...new Set(names)]
+
+ return [ ...new Set( names ) ]
+
}
-export function addMethodNames (_names) {
- names.push(..._names)
+export function addMethodNames ( _names ) {
+
+ names.push( ..._names )
+
}
-export function registerConstructor (name, setup) {
+export function registerConstructor ( name, setup ) {
+
constructors[name] = setup
+
}
-export function getConstructor (name) {
+export function getConstructor ( name ) {
+
return constructors[name] ? { setup: constructors[name], name } : {}
+
}
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 64c0eed..01cd49f 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -1,103 +1,143 @@
// Map function
-export function map (array, block) {
+export function map ( array, block ) {
+
var i
var il = array.length
var result = []
- for (i = 0; i < il; i++) {
- result.push(block(array[i]))
+ for ( i = 0; i < il; i++ ) {
+
+ result.push( block( array[i] ) )
+
}
return result
+
}
// Filter function
-export function filter (array, block) {
+export function filter ( array, block ) {
+
var i
var il = array.length
var result = []
- for (i = 0; i < il; i++) {
- if (block(array[i])) { result.push(array[i]) }
+ for ( i = 0; i < il; i++ ) {
+
+ if ( block( array[i] ) ) {
+
+ result.push( array[i] )
+
+ }
+
}
return result
+
}
// Degrees to radians
-export function radians (d) {
+export function radians ( d ) {
+
return d % 360 * Math.PI / 180
+
}
// Radians to degrees
-export function degrees (r) {
+export function degrees ( r ) {
+
return r * 180 / Math.PI % 360
+
}
// Convert dash-separated-string to camelCase
-export function camelCase (s) {
- return s.toLowerCase().replace(/-(.)/g, function (m, g) {
+export function camelCase ( s ) {
+
+ return s.toLowerCase().replace( /-(.)/g, function ( m, g ) {
+
return g.toUpperCase()
- })
+
+ } )
+
}
// Convert camel cased string to string seperated
-export function unCamelCase (s) {
- return s.replace(/([A-Z])/g, function (m, g) {
+export function unCamelCase ( s ) {
+
+ return s.replace( /([A-Z])/g, function ( m, g ) {
+
return '-' + g.toLowerCase()
- })
+
+ } )
+
}
// Capitalize first letter of a string
-export function capitalize (s) {
- return s.charAt(0).toUpperCase() + s.slice(1)
+export function capitalize ( s ) {
+
+ return s.charAt( 0 ).toUpperCase() + s.slice( 1 )
+
}
// Calculate proportional width and height values when necessary
-export function proportionalSize (element, width, height) {
- if (width == null || height == null) {
+export function proportionalSize ( element, width, height ) {
+
+ if ( width == null || height == null ) {
+
var box = element.bbox()
- if (width == null) {
+ if ( width == null ) {
+
width = box.width / box.height * height
- } else if (height == null) {
+
+ } else if ( height == null ) {
+
height = box.height / box.width * width
+
}
+
}
return {
width: width,
height: height
}
+
}
-export function getOrigin (o, element) {
+export function getOrigin ( o, element ) {
+
// Allow origin or around as the names
let origin = o.origin // o.around == null ? o.origin : o.around
let ox, oy
// Allow the user to pass a string to rotate around a given point
- if (typeof origin === 'string' || origin == null) {
+ if ( typeof origin === 'string' || origin == null ) {
+
// Get the bounding box of the element with no transformations applied
- const string = (origin || 'center').toLowerCase().trim()
+ const string = ( origin || 'center' ).toLowerCase().trim()
const { height, width, x, y } = element.bbox()
// Calculate the transformed x and y coordinates
- let bx = string.includes('left') ? x
- : string.includes('right') ? x + width
- : x + width / 2
- let by = string.includes('top') ? y
- : string.includes('bottom') ? y + height
- : y + height / 2
+ let bx = string.includes( 'left' ) ? x
+ : string.includes( 'right' ) ? x + width
+ : x + width / 2
+ let by = string.includes( 'top' ) ? y
+ : string.includes( 'bottom' ) ? y + height
+ : y + height / 2
// Set the bounds eg : "bottom-left", "Top right", "middle" etc...
ox = o.ox != null ? o.ox : bx
oy = o.oy != null ? o.oy : by
+
} else {
+
ox = origin[0]
oy = origin[1]
+
}
// Return the origin as it is if it wasn't a string
return [ ox, oy ]
+
}
diff --git a/src/utils/window.js b/src/utils/window.js
index 9e51339..55f0bb6 100644
--- a/src/utils/window.js
+++ b/src/utils/window.js
@@ -3,7 +3,9 @@ export const globals = {
document: typeof document === 'undefined' ? null : document
}
-export function registerWindow (win = null, doc = null) {
+export function registerWindow ( win = null, doc = null ) {
+
globals.window = win
globals.document = doc
+
}