Adding a way to specify how attributes are bound on Set objects

This commit is backward compatible with previous versions but adds a new option for handling
attribute applications on Set objects.  The normal behavior (of applying the attribute
to all elements in the set) is preserved unless the developer explicitly defines how
the attribute should be treated.  This relatively simply change allows three useful
cases.  First, the user can specify that an attribute to applied to a specific element.
Second, it allows pseudo-attributes to be defined and applied to a specific element.  Finally,
and most powerfully, it allows the user to specify a function to be called when a given
attribute is set.  That function can, of course, apply the attribute to a number of
different elements.

This commit includes test cases for all these cases.
master
Michael Tiller 2014-03-23 08:59:50 -04:00
parent f94872941f
commit b54624a11b
2 changed files with 86 additions and 3 deletions

View File

@ -18,6 +18,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
// Set // Set
var Set = function (items) { var Set = function (items) {
this.items = []; this.items = [];
this.bindings = {};
this.length = 0; this.length = 0;
this.type = "set"; this.type = "set";
if (items) { if (items) {
@ -87,9 +88,46 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
} }
return this; 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) { 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++) { for (var i = 0, ii = this.items.length; i < ii; i++) {
this.items[i].attr(value); this.items[i].attr(unbound);
} }
return this; return this;
}; };

View File

@ -82,6 +82,51 @@ describe("Set methods", function () {
expect(set[1]).to.be(rect2); expect(set[1]).to.be(rect2);
expect(set[2]).to.be(rect3); expect(set[2]).to.be(rect3);
}); });
it("Set.attr", function() {
var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40);
var set = Snap.set(rect1, rect2);
set.attr({"fill": "#ff0000"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#ff0000");
set.attr({"stroke": "#0000ff"});
expect(rect1.node.getAttribute("stroke")).to.be("#0000ff");
expect(rect2.node.getAttribute("stroke")).to.be("#0000ff");
});
it("Set.bind", function() {
var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40);
var set = Snap.set(rect1, rect2);
// Setting "stroke" on set only applies it to rect1
set.bind("stroke", rect1);
// Setting "fill1" on set maps to fill attribute on rect1
set.bind("fill1", rect1, "fill");
// Setting "fill2" on set maps to fill attribute on rect2
set.bind("fill2", function(v) { rect2.attr({"fill": v}); });
// Set everything to black
rect1.attr({"fill": "#000000", "stroke": "#000000"})
rect2.attr({"fill": "#000000", "stroke": "#000000"})
set.attr({"fill1": "#00ff00"});
expect(rect1.node.getAttribute("fill")).to.be("#00ff00");
expect(rect2.node.getAttribute("fill")).to.be("#000000");
// Will trigger the fallback implementation of attr which is
// to set that attribute on all elements in the set.
set.attr({"fill": "#ff0000"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#ff0000");
set.attr({"fill2": "#00ff00"});
expect(rect1.node.getAttribute("fill")).to.be("#ff0000");
expect(rect2.node.getAttribute("fill")).to.be("#00ff00");
set.attr({"stroke": "#0000ff"});
expect(rect1.node.getAttribute("stroke")).to.be("#0000ff");
expect(rect2.node.getAttribute("stroke")).to.be("#000000");
});
it("Set.splice - remove only", function() { it("Set.splice - remove only", function() {
var rect1 = s.rect(10, 20, 30, 40); var rect1 = s.rect(10, 20, 30, 40);
var rect2 = s.rect(10, 20, 30, 40); var rect2 = s.rect(10, 20, 30, 40);