Reputation: 13686
I would like to associate a d3.js
created SVG element to a javascript object - such that when the SVG element is made available on an event listener, I can trace back to the javascript object directly from it. This however does not seem to work out in my case as explained below.
I have lots of SVG elements each logically associated to one object that contains structured data relevant to it. That data determines what to do when the event fires for any of those SVG elements, and is different for each of them
I simply add the object as a new property for the SVG element. I can see it's been added okay.
I then attach the event listener using d3's .on
function.
And I obtain what I believe to be the SVG element on which the event is being fired by d3.select(this)
. Indeed, I can modify the SVG attributes of it this way, as you can see when hovering the small rectangle in my codepen given below.
Although I can confirm that my object was added to the SVG object, when I retrieve the SVG element inside the event handler, it has everything but that object reference.
I reduced this problem into the code in this codepen - where logging demonstrates the problem - hover the rectangle to check it out.
What am I doing wrong that results in this non-availability of the added object reference? How should I correctly accomplish using an object reference inside the SVG element, or work-around this?
rectangle = main.append('rect')
.style('fill', '#0000FF')
.style('stroke-width', '0px')
.style('fill-opacity', '1')
.attr('height',30)
.attr('width',30)
.attr('id', '1')
rectangle.__test__ = 'test'
rectangle.on('mouseover', function(){
console.dir(d3.select(this))
/* __test__ is absent.... */
})
Upvotes: 1
Views: 769
Reputation: 27544
The reason that your sample code doesn't work as you expect is because rectangle
is not a reference to the rectangle element, it is a reference to a d3 selection which just happens to only contain a single element. Creating a different selection of the same element later will not give you access to a property of the initial selection.
(To get your head around it: think of the actual SVGRectElement
object as a library book. That book is inside your backpack (the d3 selection referenced by rectangle
). You create some notes about the book (__test__
), and also add them to your backpack. Then you do other things, and later someone gets the same library book out and puts it in a different backpack. For many uses, the effect is the same: a backpack containing a specific book. If you wanted to read the book or take it to a specific class, it wouldn't matter which backpack it was inside of. However, that person isn't going to be able to magically find your notes in their backpack!)
If you had done
rectangle.node().__test__ = "test";
//use .node() to extract the first element from the d3 selection
//and then assign a new property value to it
and then
console.dir(this.__test__);
//`this` directly references the rectangle element,
// which has the test property added above
in the event handler, it would work.
But you can do this much more easily by using d3 data functions to associate a data object with each element and then access it directly as the first parameter of your event handling function. Spend some time with the tutorials to figure out how to get the most out of d3.
Upvotes: 1