How can I animate the opacity on a bunch of Raphael objects as one object while maintaining the individual elements opacity states? I can't animate on sets without affecting each individual element, so how do I create one object to handle—I'm thinking in a jQuery mindset if that helps answer.
2 Answers
A general solution that works for any number of elements, any number of changes and any number of sets is to use .customAttributes
which calculate and store the correct opacity level for each element in the set based on a value attached to that individual element and a value for the set.
For example (in the demo, click multiple times to see the opacity of the set of three circles change one way and the individual circle clicked on change the other way):
http://jsbin.com/oxeyih/9/edit
Using something like this, which essentially adds this feature to all existing and future sets and elements in this Raphael paper instance:
// apply this using .attr or .animate to sets or each in a set
// to set the opacity of the set as a whole, maintaining relative opacity
paper.customAttributes.setOpacity = function( setOpacity ){
// elemOpacity might not be set yet
if (typeof this.attr('elemOpacity') == 'undefined') {
this.attr('elemOpacity', this.attr('opacity'));
}
return {opacity: setOpacity * this.attr('elemOpacity')};
}
// apply this using .attr or .animate to indiviual elements
// to set that element's opacity, factoring in the opacity of the set
paper.customAttributes.elemOpacity = function( elemOpacity ){
// setOpacity might not be set yet; setting it could create infinite loop
var setOpacity = this.attr('setOpacity');
setOpacity = typeof setOpacity == 'undefined' ? 1 : setOpacity;
return {opacity: setOpacity * elemOpacity };
}
You may want to add some kind of validation if your code could go wrong if either of the custom attributes go below 0.0 or above 1.0.
Any time you set the opacity of an element, use animate({elemOpacity: xx}, time);
(or .attr()
) and it'll take the set opacity into account, and any time you want to set the opacity of a set, call animate({setOpacity: xx}, time);
on a set, and it'll take each element's opacity into account.
In some cases with complex sets, rather than animating many elements which can be slow in many browsers, it's much better for performance, and simpler, to just plonk an overlay on top... This is a good idea if the elements in question can be safely sent .toBack()
and you don't need to interact (click, hover) with them further.
Just add an overlay rectangle, set to match the inherited colour of the container element (here's a way to get inherited background colour dynamically), send it then the set .toBack()
, and animate the opacity of that overlay.

- 1
- 1

- 32,576
- 21
- 101
- 125
If you keep global variable, then you can do this. Look at the DEMO.
var p = new Raphael(10,10, 500, 500);
var x = 0.5;
var r = p.rect(20, 20, 100, 80, 5).attr({fill: 'red', opacity: x}),
c = p.circle(200, 200, 80).attr({fill: 'orange'}),
s = p.set(r, c);
s.click(function() {
s[0].attr({opacity: x - 0.3});
s[1].attr({opacity: 0.3});
});

- 4,958
- 8
- 40
- 56
-
No, I think the problem is, changing the opacity **of a set** while maintaining the **relative** opacity of each item in the set - which isn't so easy! *...animate the opacity on **a bunch of Raphael objects as one object** while **maintaining the individual elements opacity states*** – user56reinstatemonica8 Jul 26 '13 at 17:47
-
I edited and I think it does the job, thanks for clarification @user568458 – Brian Jul 26 '13 at 18:41