316 lines
9.3 KiB
JavaScript
316 lines
9.3 KiB
JavaScript
// 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.
|
|
Snap.plugin(function (Snap, Element, Paper, glob) {
|
|
var mmax = Math.max,
|
|
mmin = Math.min;
|
|
|
|
// Set
|
|
var Set = function (items) {
|
|
this.items = [];
|
|
this.bindings = {};
|
|
this.length = 0;
|
|
this.type = "set";
|
|
if (items) {
|
|
for (var 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 () {
|
|
var item,
|
|
len;
|
|
for (var 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 (var i = 0, ii = this.items.length; i < ii; i++) {
|
|
if (callback.call(thisArg, this.items[i], i) === false) {
|
|
return this;
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
/*\
|
|
* Set.animate
|
|
[ method ]
|
|
**
|
|
* 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]);
|
|
= (Element) the current element
|
|
\*/
|
|
setproto.animate = function (attrs, ms, easing, callback) {
|
|
if (typeof easing == "function" && !easing.length) {
|
|
callback = easing;
|
|
easing = mina.linear;
|
|
}
|
|
if (attrs instanceof Snap._.Animation) {
|
|
callback = attrs.callback;
|
|
easing = attrs.easing;
|
|
ms = easing.dur;
|
|
attrs = attrs.attr;
|
|
}
|
|
var args = arguments;
|
|
if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) {
|
|
var each = true;
|
|
}
|
|
var 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);
|
|
}
|
|
});
|
|
};
|
|
setproto.remove = function () {
|
|
while (this.length) {
|
|
this.pop().remove();
|
|
}
|
|
return this;
|
|
};
|
|
/*\
|
|
* Set.bind
|
|
[ method ]
|
|
**
|
|
* 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 (Element) specific element in the set to apply the attribute to
|
|
* or
|
|
- attr (string) attribute name
|
|
- element (Element) 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) {
|
|
var data = {};
|
|
if (typeof a == "function") {
|
|
this.bindings[attr] = a;
|
|
} else {
|
|
var aname = b || attr;
|
|
this.bindings[attr] = function (v) {
|
|
data[aname] = v;
|
|
a.attr(data);
|
|
};
|
|
}
|
|
return this;
|
|
};
|
|
setproto.attr = function (value) {
|
|
var unbound = {};
|
|
for (var k in value) {
|
|
if (this.bindings[k]) {
|
|
this.bindings[k](value[k]);
|
|
} else {
|
|
unbound[k] = value[k];
|
|
}
|
|
}
|
|
for (var i = 0, ii = this.items.length; i < ii; i++) {
|
|
this.items[i].attr(unbound);
|
|
}
|
|
return this;
|
|
};
|
|
/*\
|
|
* Set.clear
|
|
[ method ]
|
|
**
|
|
* Removes all elements from the set
|
|
\*/
|
|
setproto.clear = function () {
|
|
while (this.length) {
|
|
this.pop();
|
|
}
|
|
};
|
|
/*\
|
|
* Set.splice
|
|
[ method ]
|
|
**
|
|
* 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
|
|
= (object) set elements that were deleted
|
|
\*/
|
|
setproto.splice = function (index, count, insertion) {
|
|
index = index < 0 ? mmax(this.length + index, 0) : index;
|
|
count = mmax(0, mmin(this.length - index, count));
|
|
var 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]);
|
|
}
|
|
var 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);
|
|
};
|
|
/*\
|
|
* Set.exclude
|
|
[ method ]
|
|
**
|
|
* Removes given element from the set
|
|
**
|
|
- element (object) element to remove
|
|
= (boolean) `true` if object was found and removed from the set
|
|
\*/
|
|
setproto.exclude = function (el) {
|
|
for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) {
|
|
this.splice(i, 1);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
setproto.insertAfter = function (el) {
|
|
var i = this.items.length;
|
|
while (i--) {
|
|
this.items[i].insertAfter(el);
|
|
}
|
|
return this;
|
|
};
|
|
setproto.getBBox = function () {
|
|
var x = [],
|
|
y = [],
|
|
x2 = [],
|
|
y2 = [];
|
|
for (var i = this.items.length; i--;) if (!this.items[i].removed) {
|
|
var 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
|
|
};
|
|
};
|
|
setproto.clone = function (s) {
|
|
s = new Set;
|
|
for (var i = 0, ii = this.items.length; i < ii; i++) {
|
|
s.push(this.items[i].clone());
|
|
}
|
|
return s;
|
|
};
|
|
setproto.toString = function () {
|
|
return "Snap\u2018s set";
|
|
};
|
|
setproto.type = "set";
|
|
// export
|
|
Snap.Set = Set;
|
|
Snap.set = function () {
|
|
var set = new Set;
|
|
if (arguments.length) {
|
|
set.push.apply(set, Array.prototype.slice.call(arguments, 0));
|
|
}
|
|
return set;
|
|
};
|
|
});
|