Goal
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.
(Motivation)
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
My Attempt
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.
The Problem
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?
Code description of the problem:
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.... */
})
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 byrectangle
). 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
and then
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.