diff --git a/src/animation.js b/src/animation.js deleted file mode 100644 index 7eedfd7..0000000 --- a/src/animation.js +++ /dev/null @@ -1,212 +0,0 @@ -/** - * {} - * @author yutent - * @date 2024/03/07 15:46:18 - */ - -import eve from './eve.js' -import { SnapElement } from './svg.js' -import mina from './mina.js' -import { is } from './utils.js' - -let elproto = SnapElement.prototype, - Str = String, - has = 'hasOwnProperty' - -function slice(from, to, f) { - return function (arr) { - let res = arr.slice(from, to) - if (res.length == 1) { - res = res[0] - } - return f ? f(res) : res - } -} -export class Animation { - constructor(attr, ms, easing, callback) { - if (typeof easing === 'function' && !easing.length) { - callback = easing - easing = mina.linear - } - this.attr = attr - this.dur = ms - easing && (this.easing = easing) - callback && (this.callback = callback) - } -} -/** - * Creates an animation object - ** - * attr (object) attributes of final destination - * duration (number) duration of the animation, in milliseconds - * easing (function) #optional one of easing functions of @mina or custom one - * callback (function) #optional callback function that fires when animation ends - */ -export function createAnimation(attr, ms, easing, callback) { - return new Animation(attr, ms, easing, callback) -} -/** - * Returns a set of animations that may be able to manipulate the current element - ** -= (object) in format: - { - anim (object) animation object, - mina (object) @mina object, - curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, - status (function) gets or sets the status of the animation, - stop (function) stops the animation - } -*/ -elproto.inAnim = function () { - let el = this - let res = [] - - for (let id in el.anims) { - if (el.anims.hasOwnProperty(id)) { - let a = el.anims[id] - res.push({ - anim: new Animation(a._attrs, a.dur, a.easing, a._callback), - mina: a, - curStatus: a.status(), - status(val) { - return a.status(val) - }, - stop() { - a.stop() - } - }) - } - } - return res -} -/** - * Runs generic animation of one number into another with a caring function - ** - - from (number|array) number or array of numbers - - to (number|array) number or array of numbers - - setter (function) caring function that accepts one number argument - - duration (number) duration, in milliseconds - - easing (function) #optional easing function from @mina or custom - - callback (function) #optional callback function to execute when animation ends - = (object) animation object in @mina format - { - id (string) animation id, consider it read-only, - duration (function) gets or sets the duration of the animation, - easing (function) easing, - speed (function) gets or sets the speed of the animation, - status (function) gets or sets the status of the animation, - stop (function) stops the animation - } - let rect = new Snap().rect(0, 0, 10, 10); - animate(0, 10, function (val) { - rect.attr({ - x: val - }); - }, 1000); - // in given context is equivalent to - rect.animate({x: 10}, 1000); -*/ -export function animate(from, to, setter, ms, easing, callback) { - if (typeof easing == 'function' && !easing.length) { - callback = easing - easing = mina.linear - } - let now = mina.time(), - anim = mina(from, to, now, now + ms, mina.time, setter, easing) - callback && eve.once('mina.finish.' + anim.id, callback) - return anim -} -/*\ - * SnapElement.stop - [ method ] - ** - * Stops all the animations for the current element - ** - = (SnapElement) the current element - \*/ -elproto.stop = function () { - let anims = this.inAnim() - for (let i = 0, ii = anims.length; i < ii; i++) { - anims[i].stop() - } - return this -} -/*\ - * SnapElement.animate - [ method ] - ** - * Animates the given attributes of the element - ** - - attrs (object) key-value pairs of destination attributes - - duration (number) duration of the animation in milliseconds - - easing (function) #optional easing function from @mina or custom - - callback (function) #optional callback function that executes when the animation ends - = (SnapElement) the current element - \*/ -elproto.animate = function (attrs, ms, easing, callback) { - if (typeof easing == 'function' && !easing.length) { - callback = easing - easing = mina.linear - } - if (attrs instanceof Animation) { - callback = attrs.callback - easing = attrs.easing - ms = attrs.dur - attrs = attrs.attr - } - let fkeys = [], - tkeys = [], - keys = {}, - from, - to, - f, - eq, - el = this - for (let key in attrs) - if (attrs[has](key)) { - if (el.equal) { - eq = el.equal(key, Str(attrs[key])) - from = eq.from - to = eq.to - f = eq.f - } else { - from = +el.attr(key) - to = +attrs[key] - } - let len = is(from, 'array') ? from.length : 1 - keys[key] = slice(fkeys.length, fkeys.length + len, f) - fkeys = fkeys.concat(from) - tkeys = tkeys.concat(to) - } - let now = mina.time(), - anim = mina( - fkeys, - tkeys, - now, - now + ms, - mina.time, - function (val) { - let attr = {} - for (let key in keys) - if (keys[has](key)) { - attr[key] = keys[key](val) - } - el.attr(attr) - }, - easing - ) - el.anims[anim.id] = anim - anim._attrs = attrs - anim._callback = callback - eve('snap.animcreated.' + el.id, anim) - eve.once('mina.finish.' + anim.id, function () { - eve.off('mina.*.' + anim.id) - delete el.anims[anim.id] - callback && callback.call(el) - }) - eve.once('mina.stop.' + anim.id, function () { - eve.off('mina.*.' + anim.id) - delete el.anims[anim.id] - }) - return el -} diff --git a/src/attradd.js b/src/attradd.js deleted file mode 100644 index ca3c25b..0000000 --- a/src/attradd.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * {} - * @author yutent - * @date 2024/03/07 15:17:00 - */ - -import eve from './eve.js' - -let operators = { - '+': function (x, y) { - return x + y - }, - '-': function (x, y) { - return x - y - }, - '/': function (x, y) { - return x / y - }, - '*': function (x, y) { - return x * y - } - }, - reUnit = /[a-z]+$/i, - reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/ - -function getUnit(unit) { - return function (val) { - return +val.toFixed(3) + unit - } -} -eve.on('snap.util.attr', function (val) { - let plus = String(val).match(reAddon) - if (plus) { - let evnt = eve.nt(), - name = evnt.substring(evnt.lastIndexOf('.') + 1), - a = this.attr(name), - atr = {} - eve.stop() - let unit = plus[3] || '', - aUnit = a.match(reUnit), - op = operators[plus[1]] - if (aUnit && aUnit == unit) { - val = op(+a, +plus[2]) - } else { - a = this.asPX(name) - val = op(this.asPX(name), this.asPX(name, plus[2] + unit)) - } - if (isNaN(a) || isNaN(val)) { - return - } - atr[name] = val - this.attr(atr) - } -})(-10) - -eve.on('snap.util.equal', function (name, b) { - let a = String(this.attr(name) || '') - let bplus = String(b).match(reAddon) - - if (bplus) { - eve.stop() - let unit = bplus[3] || '', - aUnit = a.match(reUnit), - op = operators[bplus[1]] - if (aUnit && aUnit === unit) { - return { - from: +a, - to: op(+a, +bplus[2]), - f: getUnit(aUnit) - } - } else { - a = this.asPX(name) - return { - from: a, - to: op(a, this.asPX(name, bplus[2] + unit)), - f: _ => _ - } - } - } -})(-10) diff --git a/src/equal.js b/src/equal.js deleted file mode 100644 index ce9f51f..0000000 --- a/src/equal.js +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -import eve from './eve.js' -import { Snap } from './svg.js' -import { is } from './utils.js' -import { SEPARATOR } from './lib/constants.js' -import { parseColor } from './lib/color.js' -import { Matrix } from './matrix.js' - -let names = {}, - reUnit = /[%a-z]+$/i, - Str = String -names.stroke = names.fill = 'colour' -function getEmpty(item) { - let l = item[0] - switch (l.toLowerCase()) { - case 't': - return [l, 0, 0] - case 'm': - return [l, 1, 0, 0, 1, 0, 0] - case 'r': - if (item.length == 4) { - return [l, 0, item[2], item[3]] - } else { - return [l, 0] - } - case 's': - if (item.length == 5) { - return [l, 1, 1, item[3], item[4]] - } else if (item.length == 3) { - return [l, 1, 1] - } else { - return [l, 1] - } - } -} -function equaliseTransform(t1, t2, getBBox) { - t1 = t1 || new Matrix() - t2 = t2 || new Matrix() - t1 = Snap.parseTransformString(t1.toTransformString()) || [] - t2 = Snap.parseTransformString(t2.toTransformString()) || [] - let maxlength = Math.max(t1.length, t2.length), - from = [], - to = [], - i = 0, - j, - jj, - tt1, - tt2 - for (; i < maxlength; i++) { - tt1 = t1[i] || getEmpty(t2[i]) - tt2 = t2[i] || getEmpty(tt1) - if ( - tt1[0] != tt2[0] || - (tt1[0].toLowerCase() == 'r' && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || - (tt1[0].toLowerCase() == 's' && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) - ) { - t1 = Snap._.transform2matrix(t1, getBBox()) - t2 = Snap._.transform2matrix(t2, getBBox()) - from = [['m', t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]] - to = [['m', t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]] - break - } - from[i] = [] - to[i] = [] - for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { - j in tt1 && (from[i][j] = tt1[j]) - j in tt2 && (to[i][j] = tt2[j]) - } - } - return { - from: path2array(from), - to: path2array(to), - f: getPath(from) - } -} -function getNumber(val) { - return val -} -function getUnit(unit) { - return function (val) { - return +val.toFixed(3) + unit - } -} -function getViewBox(val) { - return val.join(' ') -} -function getColour(clr) { - return Snap.rgb(clr[0], clr[1], clr[2], clr[3]) -} -function getPath(path) { - let k = 0, - i, - ii, - j, - jj, - out, - a, - b = [] - for (i = 0, ii = path.length; i < ii; i++) { - out = '[' - a = ['"' + path[i][0] + '"'] - for (j = 1, jj = path[i].length; j < jj; j++) { - a[j] = 'val[' + k++ + ']' - } - out += a + ']' - b[i] = out - } - return Function('val', 'return Snap.path.toString.call([' + b + '])') -} -function path2array(path) { - let out = [] - for (let i = 0, ii = path.length; i < ii; i++) { - for (let j = 1, jj = path[i].length; j < jj; j++) { - out.push(path[i][j]) - } - } - return out -} -function isNumeric(obj) { - return isFinite(obj) -} -function arrayEqual(arr1, arr2) { - if (!is(arr1, 'array') || !is(arr2, 'array')) { - return false - } - return arr1.toString() == arr2.toString() -} - -eve.on('snap.util.equal', function (name, b) { - let A, - B, - a = Str(this.attr(name) || ''), - el = this - if (names[name] == 'colour') { - A = parseColor(a) - B = parseColor(b) - return { - from: [A.r, A.g, A.b, A.opacity], - to: [B.r, B.g, B.b, B.opacity], - f: getColour - } - } - if (name == 'viewBox') { - A = this.attr(name).vb.split(' ').map(Number) - B = b.split(' ').map(Number) - return { - from: A, - to: B, - f: getViewBox - } - } - if ( - name == 'transform' || - name == 'gradientTransform' || - name == 'patternTransform' - ) { - if (typeof b == 'string') { - b = Str(b).replace(/\.{3}|\u2026/g, a) - } - a = this.matrix - if (!Snap._.rgTransform.test(b)) { - b = Snap._.transform2matrix(Snap._.svgTransform2string(b), this.getBBox()) - } else { - b = Snap._.transform2matrix(b, this.getBBox()) - } - return equaliseTransform(a, b, function () { - return el.getBBox(1) - }) - } - if (name == 'd' || name == 'path') { - A = Snap.path.toCubic(a, b) - return { - from: path2array(A[0]), - to: path2array(A[1]), - f: getPath(A[0]) - } - } - if (name == 'points') { - A = Str(a).split(SEPARATOR) - B = Str(b).split(SEPARATOR) - return { - from: A, - to: B, - f: function (val) { - return val - } - } - } - if (isNumeric(a) && isNumeric(b)) { - return { - from: parseFloat(a), - to: parseFloat(b), - f: getNumber - } - } - let aUnit = a.match(reUnit), - bUnit = Str(b).match(reUnit) - if (aUnit && arrayEqual(aUnit, bUnit)) { - return { - from: parseFloat(a), - to: parseFloat(b), - f: getUnit(aUnit) - } - } else { - return { - from: this.asPX(name), - to: this.asPX(name, b), - f: getNumber - } - } -}) diff --git a/src/index.js b/src/index.js index 05f6954..478aab7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,8 @@ import { Snap } from './svg.js' import './paper.js' import './element.js' -import { createAnimation, animate } from './animation.js' import { Matrix } from './matrix.js' -import './attradd.js' import './path.js' -import './set.js' -import './equal.js' -import './mouse.js' import './filter.js' export default Snap @@ -15,5 +10,3 @@ export default Snap export function createSvg(...args) { return new Snap(...args) } - -export { Matrix, createAnimation, animate } diff --git a/src/mina.js b/src/mina.js deleted file mode 100644 index 66221e4..0000000 --- a/src/mina.js +++ /dev/null @@ -1,343 +0,0 @@ -/** - * {} - * @author yutent - * @date 2024/03/08 10:20:25 - */ - -import eve from './eve.js' -import { uuid } from './utils.js' - -let animations = {}, - requestAnimFrame = - window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame, - requestID, - isArray = Array.isArray, - diff = function (a, b, A, B) { - if (isArray(a)) { - res = [] - for (let i = 0, ii = a.length; i < ii; i++) { - res[i] = diff(a[i], b, A[i], B) - } - return res - } - let dif = (A - a) / (B - b) - return function (bb) { - return a + dif * (bb - b) - } - }, - timer = Date.now, - sta = function (val) { - let a = this - if (val == null) { - return a.s - } - let ds = a.s - val - a.b += a.dur * ds - a.B += a.dur * ds - a.s = val - }, - speed = function (val) { - if (val == null) { - return this.spd - } - this.spd = val - }, - duration = function (val) { - if (val == null) { - return this.dur - } - this.s = (this.s * val) / this.dur - this.dur = val - }, - stopit = function () { - delete animations[this.id] - this.update() - eve('mina.stop.' + this.id, a) - }, - pause = function () { - let a = this - if (a.pdif) { - return - } - delete animations[a.id] - a.update() - a.pdif = a.get() - a.b - }, - resume = function () { - let a = this - if (!a.pdif) { - return - } - a.b = a.get() - a.pdif - delete a.pdif - animations[a.id] = a - frame() - }, - update = function () { - let a = this, - res - if (isArray(a.start)) { - res = [] - for (let j = 0, jj = a.start.length; j < jj; j++) { - res[j] = +a.start[j] + (a.end[j] - a.start[j]) * a.easing(a.s) - } - } else { - res = +a.start + (a.end - a.start) * a.easing(a.s) - } - a.set(res) - }, - frame = function (timeStamp) { - // Manual invokation? - if (!timeStamp) { - // Frame loop stopped? - if (!requestID) { - // Start frame loop... - requestID = requestAnimFrame(frame) - } - return - } - let len = 0 - for (let i in animations) - if (animations.hasOwnProperty(i)) { - let a = animations[i], - b = a.get(), - res - len++ - a.s = (b - a.b) / (a.dur / a.spd) - if (a.s >= 1) { - delete animations[i] - a.s = 1 - len-- - ;(function (a) { - setTimeout(function () { - eve('mina.finish.' + a.id, a) - }) - })(a) - } - a.update() - } - requestID = len ? requestAnimFrame(frame) : false - } -/*** - * Generic animation of numbers - ** - * a (number) start _slave_ number - * A (number) end _slave_ number - * b (number) start _master_ number (start time in general case) - * B (number) end _master_ number (end time in general case) - * get (function) getter of _master_ number (see @mina.time) - * set (function) setter of _slave_ number - * easing (function) #optional easing function, default is @mina.linear - = (object) animation descriptor - { - id (string) animation id, - start (number) start _slave_ number, - end (number) end _slave_ number, - b (number) start _master_ number, - s (number) animation status (0..1), - dur (number) animation duration, - spd (number) animation speed, - get (function) getter of _master_ number (see @mina.time), - set (function) setter of _slave_ number, - easing (function) easing function, default is @mina.linear, - status (function) status getter/setter, - speed (function) speed getter/setter, - duration (function) duration getter/setter, - stop (function) animation stopper - pause (function) pauses the animation - resume (function) resumes the animation - update (function) calles setter with the right value of the animation - } - */ -export const mina = function (a, A, b, B, get, set, easing) { - let anim = { - id: uuid('M'), - start: a, - end: A, - b: b, - s: 0, - dur: B - b, - spd: 1, - get: get, - set: set, - easing: easing || mina.linear, - status: sta, - speed: speed, - duration: duration, - stop: stopit, - pause: pause, - resume: resume, - update: update - } - animations[anim.id] = anim - let len = 0, - i - for (i in animations) - if (animations.hasOwnProperty(i)) { - len++ - if (len == 2) { - break - } - } - len == 1 && frame() - return anim -} -/*\ - * mina.time - [ method ] - ** - * Returns the current time. Equivalent to: - | function () { - | return (new Date).getTime(); - | } - \*/ -mina.time = timer -/*\ - * mina.getById - [ method ] - ** - * Returns an animation by its id - - id (string) animation's id - = (object) See @mina - \*/ -mina.getById = function (id) { - return animations[id] || null -} - -/*\ - * mina.linear - [ method ] - ** - * Default linear easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.linear = function (n) { - return n -} -/*\ - * mina.easeout - [ method ] - ** - * Easeout easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.easeout = function (n) { - return Math.pow(n, 1.7) -} -/*\ - * mina.easein - [ method ] - ** - * Easein easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.easein = function (n) { - return Math.pow(n, 0.48) -} -/*\ - * mina.easeinout - [ method ] - ** - * Easeinout easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.easeinout = function (n) { - if (n == 1) { - return 1 - } - if (n == 0) { - return 0 - } - let q = 0.48 - n / 1.04, - Q = Math.sqrt(0.1734 + q * q), - x = Q - q, - X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), - y = -Q - q, - Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), - t = X + Y + 0.5 - return (1 - t) * 3 * t * t + t * t * t -} -/*\ - * mina.backin - [ method ] - ** - * Backin easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.backin = function (n) { - if (n == 1) { - return 1 - } - let s = 1.70158 - return n * n * ((s + 1) * n - s) -} -/*\ - * mina.backout - [ method ] - ** - * Backout easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.backout = function (n) { - if (n == 0) { - return 0 - } - n = n - 1 - let s = 1.70158 - return n * n * ((s + 1) * n + s) + 1 -} -/*\ - * mina.elastic - [ method ] - ** - * Elastic easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.elastic = function (n) { - if (n == !!n) { - return n - } - return ( - Math.pow(2, -10 * n) * Math.sin(((n - 0.075) * (2 * Math.PI)) / 0.3) + 1 - ) -} -/*\ - * mina.bounce - [ method ] - ** - * Bounce easing - - n (number) input 0..1 - = (number) output 0..1 - \*/ -mina.bounce = function (n) { - let s = 7.5625, - p = 2.75, - l - if (n < 1 / p) { - l = s * n * n - } else { - if (n < 2 / p) { - n -= 1.5 / p - l = s * n * n + 0.75 - } else { - if (n < 2.5 / p) { - n -= 2.25 / p - l = s * n * n + 0.9375 - } else { - n -= 2.625 / p - l = s * n * n + 0.984375 - } - } - } - return l -} -export default mina diff --git a/src/set.js b/src/set.js deleted file mode 100644 index 8b6131e..0000000 --- a/src/set.js +++ /dev/null @@ -1,321 +0,0 @@ -/** - * {} - * @author yutent - * @date 2024/03/07 15:33:05 - */ - -import eve from './eve.js' -import { Animation } from './animation.js' -import mina from './mina.js' -import { is } from './utils.js' - -let mmax = Math.max, - mmin = Math.min - -// Set -let Set = function (items) { - this.items = [] - this.bindings = {} - this.length = 0 - this.type = 'set' - if (items) { - for (let i = 0, ii = items.length; i < ii; i++) { - if (items[i]) { - this[this.items.length] = this.items[this.items.length] = items[i] - this.length++ - } - } - } - }, - setproto = Set.prototype -/*\ - * Set.push - [ method ] - ** - * Adds each argument to the current set - = (object) original element - \*/ -setproto.push = function () { - let item, len - for (let i = 0, ii = arguments.length; i < ii; i++) { - item = arguments[i] - if (item) { - len = this.items.length - this[len] = this.items[len] = item - this.length++ - } - } - return this -} -/*\ - * Set.pop - [ method ] - ** - * Removes last element and returns it - = (object) element - \*/ -setproto.pop = function () { - this.length && delete this[this.length--] - return this.items.pop() -} -/*\ - * Set.forEach - [ method ] - ** - * Executes given function for each element in the set - * - * If the function returns `false`, the loop stops running. - ** - - callback (function) function to run - - thisArg (object) context object for the callback - = (object) Set object - \*/ -setproto.forEach = function (callback, thisArg) { - for (let i = 0, ii = this.items.length; i < ii; i++) { - if (callback.call(thisArg, this.items[i], i) === false) { - return this - } - } - return this -} -/** - * Animates each element in set in sync. - * - ** - - attrs (object) key-value pairs of destination attributes - - duration (number) duration of the animation in milliseconds - - easing (function) #optional easing function from @mina or custom - - callback (function) #optional callback function that executes when the animation ends - * or - - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` - > Usage - | // animate all elements in set to radius 10 - | set.animate({r: 10}, 500, mina.easein); - | // or - | // animate first element to radius 10, but second to radius 20 and in different time - | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); - = (SnapElement) the current element -*/ -setproto.animate = function (attrs, ms, easing, callback) { - if (typeof easing == 'function' && !easing.length) { - callback = easing - easing = mina.linear - } - if (attrs instanceof Animation) { - callback = attrs.callback - easing = attrs.easing - ms = easing.dur - attrs = attrs.attr - } - let args = arguments - if (is(attrs, 'array') && is(args[args.length - 1], 'array')) { - let each = true - } - let begin, - handler = function () { - if (begin) { - this.b = begin - } else { - begin = this.b - } - }, - cb = 0, - set = this, - callbacker = - callback && - function () { - if (++cb == set.length) { - callback.call(this) - } - } - return this.forEach(function (el, i) { - eve.once('snap.animcreated.' + el.id, handler) - if (each) { - args[i] && el.animate.apply(el, args[i]) - } else { - el.animate(attrs, ms, easing, callbacker) - } - }) -} -/** - * Removes all children of the set. - * - */ -setproto.remove = function () { - while (this.length) { - this.pop().remove() - } - return this -} -/** - * Specifies how to handle a specific attribute when applied - * to a set. - * - ** - - attr (string) attribute name - - callback (function) function to run - * or - - attr (string) attribute name - - element (SnapElement) specific element in the set to apply the attribute to - * or - - attr (string) attribute name - - element (SnapElement) specific element in the set to apply the attribute to - - eattr (string) attribute on the element to bind the attribute to - = (object) Set object - */ -setproto.bind = function (attr, a, b) { - let data = {} - if (typeof a == 'function') { - this.bindings[attr] = a - } else { - let aname = b || attr - this.bindings[attr] = function (v) { - data[aname] = v - a.attr(data) - } - } - return this -} -/** - * Equivalent of @SnapElement.attr. - */ -setproto.attr = function (value) { - let unbound = {} - for (let k in value) { - if (this.bindings[k]) { - this.bindings[k](value[k]) - } else { - unbound[k] = value[k] - } - } - for (let i = 0, ii = this.items.length; i < ii; i++) { - this.items[i].attr(unbound) - } - return this -} -/** - * Removes all elements from the set - */ -setproto.clear = function () { - while (this.length) { - this.pop() - } -} -/** - * Removes range of elements from the set - ** - * index (number) position of the deletion - * count (number) number of element to remove - * insertion… (object) #optional elements to insert - */ -setproto.splice = function (index, count, insertion) { - index = index < 0 ? mmax(this.length + index, 0) : index - count = mmax(0, mmin(this.length - index, count)) - let tail = [], - todel = [], - args = [], - i - for (i = 2; i < arguments.length; i++) { - args.push(arguments[i]) - } - for (i = 0; i < count; i++) { - todel.push(this[index + i]) - } - for (; i < this.length - index; i++) { - tail.push(this[index + i]) - } - let arglen = args.length - for (i = 0; i < arglen + tail.length; i++) { - this.items[index + i] = this[index + i] = - i < arglen ? args[i] : tail[i - arglen] - } - i = this.items.length = this.length -= count - arglen - while (this[i]) { - delete this[i++] - } - return new Set(todel) -} -/** - * Removes given element from the set - ** - * element (object) element to remove - */ -setproto.exclude = function (el) { - for (let i = 0, ii = this.length; i < ii; i++) - if (this[i] == el) { - this.splice(i, 1) - return true - } - return false -} -/** - * Inserts set elements after given element. - ** - * element (object) set will be inserted after this element - */ -setproto.insertAfter = function (el) { - let i = this.items.length - while (i--) { - this.items[i].insertAfter(el) - } - return this -} -/** - * Union of all bboxes of the set. See @SnapElement.getBBox. - */ -setproto.getBBox = function () { - let x = [], - y = [], - x2 = [], - y2 = [] - for (let i = this.items.length; i--; ) - if (!this.items[i].removed) { - let box = this.items[i].getBBox() - x.push(box.x) - y.push(box.y) - x2.push(box.x + box.width) - y2.push(box.y + box.height) - } - x = mmin.apply(0, x) - y = mmin.apply(0, y) - x2 = mmax.apply(0, x2) - y2 = mmax.apply(0, y2) - return { - x: x, - y: y, - x2: x2, - y2: y2, - width: x2 - x, - height: y2 - y, - cx: x + (x2 - x) / 2, - cy: y + (y2 - y) / 2 - } -} -/** - * Creates a clone of the set. - */ -setproto.clone = function (s) { - s = new Set() - for (let i = 0, ii = this.items.length; i < ii; i++) { - s.push(this.items[i].clone()) - } - return s -} - -setproto.type = 'set' - -/** - * Creates a set and fills it with list of arguments. - ** - = (object) New Set object - | let r = paper.rect(0, 0, 10, 10), - | s1 = createSet(), // empty set - | s2 = createSet(r, paper.circle(100, 100, 20)); // prefilled set -*/ -export function createSet(...args) { - let set = new Set() - if (args.length) { - set.push.apply(set, args) - } - return set -}