I have this code that places a marker and on mouse-over this marker is scaled out and then back to the 'original' scale:
this.drawPerson = function () {
self.svg.append("path")
.attr("d", personPath)
.attr("transform", "translate(100,100)scale(0.1)")
.attr("class", "member")
.style("fill", "steelblue")
.on("mouseover", function(){
d3.select(this).transition()
.style("fill", "red")
.attr("transform", "translate(100,100)scale(0.2)")
})
.on("mouseout", function() {
d3.select(this).transition()
.style("fill", "steelblue")
.attr("transform", "translate(100,100)scale(0.1)")
});
}
The x and y are the coordinates for the position on the canvas.
Here is the example: http://jsfiddle.net/SuTZR/8/
-
1\$\begingroup\$ What's wrong with it as it stands? Performance? \$\endgroup\$Matt Gibson– Matt Gibson2012年07月24日 08:40:56 +00:00Commented Jul 24, 2012 at 8:40
-
\$\begingroup\$ i was thinking that the mouse out could just be reset as the original, rather then having to set it again. similar to the way is done with css \$\endgroup\$khinester– khinester2012年07月24日 09:28:46 +00:00Commented Jul 24, 2012 at 9:28
-
\$\begingroup\$ Like when you mouseout of an element with css hover set to something different? I think I see what you mean, but you are doing an animated transform, which is a lot more complex than simply switching from state to state. You could use CSS hover for this if the browser supported a transform like that natively, but until CSS3 is widely adopted, it's not going to be possible. Examples here: tympanus.net/codrops/2011/11/07/animated-buttons-with-css3 \$\endgroup\$Matt Gibson– Matt Gibson2012年07月24日 10:05:40 +00:00Commented Jul 24, 2012 at 10:05
-
\$\begingroup\$ As usual, IE spoils it for the rest of us: w3schools.com/cssref/css3_browsersupport.asp \$\endgroup\$Matt Gibson– Matt Gibson2012年07月24日 10:07:34 +00:00Commented Jul 24, 2012 at 10:07
-
\$\begingroup\$ @MattGibson Since IE<9 doesn't support SVG at all, I don't think that is a problem. \$\endgroup\$Inkbug– Inkbug2012年07月25日 09:17:57 +00:00Commented Jul 25, 2012 at 9:17
2 Answers 2
There does not seem to be a great way of solving this.
The best I can propose is to capture the style that you will re-set to into a function and use that function both during initialization and mouseout, this makes the code DRY'er, but not necessarily nicer:
this.drawPerson = function () {
function style( svg ){
return svg.style("fill", "steelblue")
.attr("transform", "translate(100,100)scale(0.1)");
}
style( self.svg.append("path")
.attr("d", personPath)
.attr("class", "member") )
.on("mouseover", function(){
d3.select(this).transition()
.style("fill", "red")
.attr("transform", "translate(100,100)scale(0.2)")
})
.on("mouseout", function() {
style( d3.select(this).transition() )
});
}
Okay so this answer does not try to change your code by functionalizing anything or what have you ... but it does optimize it:
function MyClient() {
var self = this,
personPath = "m 1.4194515,-160.64247 c 33.5874165,0 60.8159465,-25.97005 60.8159465,-58.00952 0,-32.0404 -27.22755,-58.0114 -60.8159465,-58.0114 -33.5883965,0 -60.8159415,25.971 -60.8159415,58.0114 0,32.0404 27.228527,58.00952 60.8159415,58.00952 z m 81.9575765,26.25762 C 70.531608,-146.64352 55.269688,-153.983 0.08110256,-153.983 c -55.19742156,0 -70.08915856,7.96609 -82.28062656,19.59815 -12.197359,11.62926 -8.081167,135.7024419 -8.081167,135.7024419 L -63.292733,-59.848397 -46.325227,122.37766 2.6291765,29.116913 48.308878,122.37766 64.467298,-59.848397 91.457218,1.3175919 c 0,-8e-4 4.76917,-123.4484419 -8.08019,-135.7024419 z",
fullCanvas = "100%",
w = $('#canvas').width(),
mapCanvasHeight = (w * 0.75),
transformVal = "translate(100,100)scale(0.";
this.init = function() {
self.drawCanvas();
self.drawRect();
self.drawPerson();
}
this.drawCanvas = function () {
self.svg = d3.select('#canvas')
.append('svg:svg')
.attr({
width:fullCanvas,
height:fullCanvas,
viewBox:("0 0 " + w + " " + mapCanvasHeight)
});
}
this.drawRect = function () {
self.svg
.append("rect")
.attr({
x:0,
y:0,
width:w,
height:mapCanvasHeight,
fill:"black"
});
}
this.drawPerson = function () {
self.svg
.append("path")
.attr({
d:personPath,
transform:transformVal+"1)",
class:"member",
fill:"steelblue"
})
.on({
mouseenter:function(){
d3.select(this).transition()
.style({
fill:"red"
})
.attr({
transform:transformVal+"2)"
});
},
mouseleave:function() {
d3.select(this).transition()
.style({
fill:"steelblue",
})
.attr({
transform:transformVal+"1)"
});
}
});
}
this.init();
};
var MyClient;
jQuery(function() {
MyClient = new MyClient();
});
The key here is the DOM object use of your methods:
- style
- attr
- on
This will be faster for three reasons, one major and two minor:
- Major = by consolidating your assignments of attributes and
mouseenter
/mouseleave
into a single bind you are applying to the object once instead of many times consecutively, and as we all know the most expensive action in jQuery is DOM querying - Minor = changing
mouseover
andmouseout
tomouseenter
andmouseleave
respectively prevents excessive firing (mouseover
will fire everytime you move the mouse and it is over the object) - Minor = use of the DOM object rather than string means less parsing and conversion efforts for the JS compiler to perform
I also did a couple of minor tweaks like consolidate the variables at the top, assign the "100%"
value to a variable, rename your width
variable (width
is a native DOM property for all elements, bad idea to use it as a variable name), and set your transform
value to a variable except for the 1
or 2
at the end, but these are more coding style than optimizations.