score:22
D3 selections are arrays of arrays of DOM elements. (They are nested arrays so they can implement nested selections, while keeping separate index counts and properties for each sub-selection.)
So when you run a statement like:
var selectedArray = d3.select(this);
The selectedArray
is of the structure [[ {SVGGElement} ]]
. That much you seem to understand.
But your selectedArray
isn't just an array containing an array containing a single DOM element. It is also a d3.selection
object, with all the special functions that selections have, including the .style()
function.
However, when you extract the sub-array in the next line:
var selectGroup = selectedArray[0];
You now just have an ordinary array containing an SVG <g>
element node. It has no special functions from d3. And finally, when you extract the element from that array:
var selectedLine = selectGroup[0];
You just return the DOM element node itself. Which is the exact same object as the this
that you originally selected. That node has a .style
property, but not a .style()
function.
Sometimes, you do want to extract a node from a d3 selection in order to use the properties or methods that are part of the DOM interface. If you did want to do this, the approach above would work, or you could access it all in one line with
var svgNode = d3.select("svg")[0][0];
Or, you could use the selection.node()
method which does the exact same thing (grabs the first node in the first nest in the selection):
var svgNode = d3.select("svg").node();
But, if you want to use d3 selection methods on a single DOM element, you select that element and then call the methods on the selection. It doesn't matter whether the selection contains one element or 1000, your code is just the same. (It won't even throw an error if your selection is completely empty -- it just won't do anything!) If you want to use d3 methods on a child of your original selection, you need to use a subselection method (either selection.select()
or selection.selectAll()
).
svg.selectAll("g.team")
.on("mouseover",function(){
var lineName;
svg.selectAll("path.team.line").style("stroke","#C0C0C0");
//set all to gray
var selectedGroup = d3.select(this);
var selectedLine = selectedGroup.select("path.team.line");
//this only selects the (first) path that is a child
//of the selected group
selectedLine.style("color",function(d){ //let active keep color
lineName = abbrDict[d.name]; //full name to be at end of line
return color(d.name);
});
/* ...etc... */
By the way, when you add an event handler to an element with d3's selection.on()
method, d3 will automatically pass that element's data object as the first parameter to your event handling function. Which means you can simplify your code to avoid the secondary function call:
svg.selectAll("g.team")
.on("mouseover",function(d){ //d as a function parameter
var lineName;
svg.selectAll("path.team.line").style("stroke","#C0C0C0");
//set all to gray
var selectedLine = d3.select(this);
selectedLine.style("color", color(d.name) );
//already have the `d` for this element available
lineName = abbrDict[d.name];
/* ...etc... */
To continue with your code: For positioning your text element, you are trying to use the .getTotalLength()
and .getPointAtLength()
methods of the <path>
element. Now, these methods are DOM interface methods, not d3 methods, so you need the actual {SVGPathElement}
node, not a d3 selection. However, you're mixing up your d3 selections with your DOM methods currently.
To access the node using pure Javascript from the this
element (which is it's parent <g>
element):
var pathNode = this.children[0]; //assuming the <path> is the first child of <g>
var len = pathNode.getTotalLength();
var pos = pathNode.getPointAtLength( len );
Alternatively, you can access the <path>
element from the d3 selection you created above:
var pathNode = selectedLine.node(); //grab the node from the selection
var len = pathNode.getTotalLength();
var pos = pathNode.getPointAtLength( len );
Finally, this line:
this.parentNode.parentNode.appendChild(this.parentNode);
//brings team to front, must select the path's g parent
//to reorder it
I think should be just:
this.parentNode.appendChild(this);
//brings team to front, must select the path's g parent
//to reorder it
(since this
is the <g>
element already).
Source: stackoverflow.com
Related Query
- Selecting path within G element and change style
- Updating style of path within svg and d3
- D3.js change x-axis path line style
- change the style with 'selectAll' and 'select' problems
- How do I change color of path element when its value is selected from dropdown
- how to change style for a particular path in partition chart (D3.js)
- Select specific elements and change style of one
- Change style after a d3 path has been clicked
- How to dynamically alter point radius and style of JSON path in d3?
- How to get element on mouse position within d3.xhr and async queue?
- Change height and width of the path tag in SVG Image
- Style a d3 element with jQuery and CSS
- SVG element — handling and selecting text
- d3.js select nodes and change their style
- How to select a particular element in g elements and change its status in D3.js
- d3.js - update axis and change width of path
- D3.js cluster rollover - how to select and change another element
- D3 Differentiate between click and drag for an element which has a drag behavior
- How to use d3.min and d3.max within a d3.json command
- D3 Selecting an element inside an SVG
- D3 how to change the width and length of SVG
- Change and transition dataset in chord diagram with D3
- d3.js change color and size on line graph dot on mouseover
- StopPropagation() with SVG element and G
- Modifying SVG path opacity and it's marker
- How can I change the radius and opacity of a circle in d3?
- mouseout/mouseleave gets fired when mouse moves INSIDE the svg path element
- D3, retrieve the x position of a <g> element and apply multiple transform
- How to change speed of translate and scale when zooming in and out in D3 (using zoom.on & d3.event.translate, d3.event.zoom)?
- D3 v4 Brush and Zoom on the same element (without mouse events conflicting)
More Query from same tag
- Exit() is not working for d3 group bar chart
- d3 drag when elements are on top of each other
- visjs.org library : display only event dates
- Creating map of Africa using d3.js and topoJSON
- d3 v4 wrap text field (not axis)
- D3 how to find the height of the last point in a line graph
- d3.js: grouping with <g> (with the data join enter/update/exit cycle)
- d3's .call() passes incorrect selection when the current selection is div
- bisectLeft function does not work if the second parameter is numerical
- d3.js: Text too sharp
- D3.js tooltips not displaying correctlty when generated with Highcharts
- D3 click event returning null attribute
- Phoenix: How to load a static tsv file for d3 graph
- How to add a link to each node of d3 radar chart?
- Remove Text from Nodes in d3
- n3-line-chart: Inconsistent values for dates on x axis
- Data processing with Dimple.js
- D3.js Time series graph with epoch time
- ng-repeat not updating after change in nestled data
- D3-legend color always stays black
- Making multiple rectangles in SVG by D3 error
- Can I animate D3 pie arcs if I'm not updating data?
- D3.js - Date string comparion fails ( minimum and maximum dates are not found)
- D3JS - Combining "rect" functions
- d3 geojson works in v2, but not in v4
- Point along path interpolation translate function
- Leaflet Choropleth Map and D3 Line Graph Interference
- Rescale an SVG in CSS
- d3 force directed graph moving away on the svg, separating into group of nodes
- D3 V4 setting initial zoom level