Snap之Set - bobby169/Snap.svgDoc GitHub Wiki
[TOC]
Set
Set本质是一个数组,可以对添加到数组中的svg批量执行push、pop、forEach、animate、remove、bind、attr、clear、splice、exclude、insertAfter、getBBox、clone等批量操作。
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]) {
// 以下标的形式,复制数组数据作为Set类的属性,且让Set具有类又具有数组的特性。因为有数组下标又有length
this[this.items.length] = this.items[this.items.length] = items[i];
this.length++;
}
}
}
},
setproto = Set.prototype;
Set与Paper.g或Paper.group的区别
Set更像createjs中的Container,本质是一个数组,是虚拟的。但可以对整个数组批量操作。而Paper.group是Svg中的<g>标签,是实体的标签。因为createjs中只有canvas一个标签,所以Container是一个数组。而Svg本身有<g>标签,添加Set的支持,在不用<g>标签的情况下可以灵活批量处理svg中的元素。
Set本身是一个类,以下标的形式,复制数组数据作为Set类的属性,且让Set具有类又具有数组的特性。因为有数组下标又有length。但Set终旧是一个类,且是一个伪数组,所以后面的操作就是模拟数组的push、pop、forEach、splice等方法。
es6 Set本身是一个构造函数,集成了数组和类的于一身
let svg = Snap("#svg");
let c1 = svg.paper.circle(50,50,40);
let c2 = svg.paper.circle(150,50,40);
let set = Snap.set(c1, c2) // 注意set为小写
set.exclude(c1)
set.attr({
fill: "#f00",
stroke: "#0f0",
strokeWidth: 5
})
下面我们用es6原生的Set构造函数
Set.prototype.attr = function (value) {
this.forEach((v) => {
v.attr(value)
})
}
let svg = Snap("#svg");
let c1 = svg.paper.circle(50,50,40);
let c2 = svg.paper.circle(150,50,40);
let set = new Set([c1,c2])
set.delete(c1)
set.attr({
fill: "#f00",
stroke: "#0f0",
strokeWidth: 5
});
Set.push() 相当于es6 Set.prototype.add()方法
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.exclude(element) 相当于es6 Set.prototype.delete()方法
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;
};
Set.pop()
Removes last element and returns it
setproto.pop = function () {
this.length && delete this[this.length--];
return this.items.pop();
};
Set.clear() 相当于es6 Set.prototype.clear()方法
Removes all elements from the set
setproto.clear = function () {
while (this.length) {
this.pop();
}
};
Set.remove()
Removes all children of the set.
setproto.remove = function () {
while (this.length) {
this.pop().remove();
}
return this;
};
Set.forEach() 相当于es6 Set.prototype.forEach()方法
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.insertAfter(el)
Inserts set elements after given element.
setproto.insertAfter = function (el) {
var i = this.items.length;
while (i--) {
this.items[i].insertAfter(el);
}
return this;
};
Set.attr(value)
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;
};
es6 Set实现
Set.prototype.attr = function (value) {
this.forEach((v) => {
v.attr(value)
})
}
Set.animate(attrs, ms, easing, callback)
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);
}
});
};
用es6实现
Set.prototype.animate = setproto.animate
示例:
let s = Snap('#svg')
let circle = s.circle(10, 20, 30);
let square = s.rect(60, 60, 30, 30);
// let set = new Set([circle, square]);
let set = Snap.set(circle, square);
let result = set.animate({opacity: .5}, 1000, function() {
result.forEach(function (el) {
var o = el.attr("opacity");
console.info(o)
});
});
Set.getBBox()
返回集合中元素的边界框bounding box描述
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 = Math.min.apply(0, x);
y = Math.min.apply(0, y);
x2 = Math.max.apply(0, x2);
y2 = Math.max.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
};
};
es6 Set实现
Set.prototype.getBBox = function () {
let x = [],
y = [],
x2 = [],
y2 = [];
this.forEach((v) => {
if(!v.removed) {
let box = v.getBBox();
x.push(box.x);
y.push(box.y);
x2.push(box.x + box.width);
y2.push(box.y + box.height);
}
})
x = Math.min.apply(0, x);
y = Math.min.apply(0, y);
x2 = Math.max.apply(0, x2);
y2 = Math.max.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
};
}
示例:
let svg = Snap("#svg");
let c1 = svg.paper.circle(50,50,40);
let c2 = svg.paper.circle(150,50,40);
let set = Snap.set(c1, c2) // 注意set为小写
// let set = new Set([c1, c2])
set.attr({
fill: "#f00",
stroke: "#0f0",
strokeWidth: 5
})
let bbox = set.getBBox()
console.info(bbox)
let rect = svg.paper.rect(bbox.x, bbox.y, bbox.width, bbox.height).attr({
opacity: 0.2,
fill: '#00f'
})