From 985d3dec10e245ee4a53703e9fc71e7e3eced555 Mon Sep 17 00:00:00 2001 From: Michael Tiller Date: Sun, 23 Mar 2014 08:59:50 -0400 Subject: [PATCH] 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. --- src/set.js | 42 ++++++++++++++++++++++++++++++++++++++++-- test/set.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/set.js b/src/set.js index 5ba882e..542f7a8 100644 --- a/src/set.js +++ b/src/set.js @@ -18,6 +18,7 @@ Snap.plugin(function (Snap, Element, Paper, glob) { // Set var Set = function (items) { this.items = []; + this.bindings = {}; this.length = 0; this.type = "set"; if (items) { @@ -139,9 +140,46 @@ Snap.plugin(function (Snap, Element, Paper, glob) { } 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(value); + this.items[i].attr(unbound); } return this; }; @@ -262,4 +300,4 @@ Snap.plugin(function (Snap, Element, Paper, glob) { } return set; }; -}); \ No newline at end of file +}); diff --git a/test/set.js b/test/set.js index e91ddc8..43d82fb 100644 --- a/test/set.js +++ b/test/set.js @@ -82,6 +82,51 @@ describe("Set methods", function () { expect(set[1]).to.be(rect2); 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() { var rect1 = s.rect(10, 20, 30, 40); var rect2 = s.rect(10, 20, 30, 40); @@ -119,4 +164,4 @@ describe("Set methods", function () { expect(removedSet[1]).to.be(rect2); expect(removedSet[2]).to.be(rect4); }); -}); \ No newline at end of file +});