score:1
Nodes don't have to be grouped together physically to be able to group them to apply a label or highlight them. At present, the code you are using produces a g
element for each parent node, with a rect
that provides the colour fill and a blank text
element. The child nodes are then overlaid on this parent node with a black stroke
along the edges and a text
node with the country name.
If you want to be able to highlight all the elements that have the same parent and put a header on the element, you can do it a couple of ways:
alter existing elements to show a header
create an overlay with the same dimensions as the parent node to display a header
Altering existing elements
To be able to do this, we first need to be able to identify parent nodes and their children. One way to do this is by giving nodes classes according to their position in the hierarchy and their data content. Here's one possible way to do this:
var cells = innercanvas
.selectAll(".newcell")
.data(treemap)
.enter()
.append("g")
.attr("class", function (d,i) {
return 'newcell _' + i // i provides a unique identifier for each node
+ ' cell-level-' + d.depth // cell-level-0 for root, cell-level-1, cell-level-2, etc
+ ( d.name ? ' ' + safe_name(d.name) : '' ) // if d.name exists, use the 'safe' version
+ ( ! d.children
? ' leaf' // d has no children => it's a leaf node
: (d.depth === 0
? ' root' // d.depth = 0 => it's the root node
: ' internal ')); // has children, depth > 0 => internal node
})
// strips non-alphanumeric characters out of `name` strings, replaces with _
function safe_name (txt) {
return txt.replace(/\W/g, '_');
}
The SVG g
elements now look like this:
Now we can easily access the parent node for any country name c.name
by using
d3.select('.internal.' + safe_name(c.name))
or (e.g.) the text
elements of the leaf nodes for the country using
d3.selectAll('.leaf.' + safe_name(c.name) + ' text')
We can then use CSS to show or hide text elements, rect
strokes, etc.; e.g.
var bool = false;
var toggle = d3.select('#toggle')
.on('click', toggleSvg);
function toggleSvg() {
bool = !bool;
d3.selectAll('.Cyprus')
.classed('highlightAll', bool);
}
.newcell text {
font-family: Arial, sans-serif;
font-size: 10px;
}
.newcell.leaf rect {
stroke: #000;
stroke-width: 0.5px;
}
.oversize {
display: none;
}
.internal text {
opacity: 0
}
.internal.highlightAll text {
opacity: 1
}
.highlightAll.leaf rect {
opacity: 0.1
}
.highlightAll.leaf text {
opacity: 0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<p><a id="toggle" href='#'>Toggle Cyprus highlighting</a></p>
<svg width="186" height="77">
<g transform="translate(-30.1234, -258.33)">
<g class="newcell _2331 cell-level-1 Cyprus internal ">
<rect x="30.123480134121516" y="258.33086334171067" width="185.81893466750355" height="76.6094615363257" style="fill: rgb(100, 200, 75);"></rect>
<title>Cyprus</title>
<text x="123.0329474678733" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2332 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="268.33086334171067" width="31.51365155392795" height="23.97574841366901" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="280.3187375485452" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2333 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="292.30661175537968" width="31.51365155392795" height="32.633713122656687" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="308.62346831670802" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2334 cell-level-2 Cyprus leaf">
<rect x="71.637131688049465" y="268.33086334171067" width="55.48181226963859" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="99.37803782286876" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2335 cell-level-2 Cyprus leaf">
<rect x="127.11894395768805" y="268.33086334171067" width="78.823470843937" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="166.53067937965655" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
</g>
</svg>
Creating an overlay
This will duplicate an existing parent node on top of the treemap.
Add a new g
element to the treemap with rect
and text
nodes as children:
var highlightG = canvas.append('g')
.attr("transform", "translate(" + cfg.margin.left + "," + cfg.margin.top + ")")
.append('g')
.classed('highlighter', true)
.attr('opacity',0);
highlightG.append('rect');
highlightG.append('text');
We can use the data from an existing parent node to set the appropriate position and size for the rect
element and the content for the text
element.
var d = d3.select('.internal.Cyprus').datum();
highlightG.select('rect')
.attr("x", d.x)
.attr("y", d.y)
.attr("width", d.dx)
.attr("height", d.dy)
highlightG
.select("text")
.attr("x", d.x + d.dx / 2 )
.attr("y", d.y + d.dy / 2 )
.attr('dy', '.35em')
.attr("text-anchor", "middle")
.text(function () {
return d.name;
})
d3.select('.internal.Cyprus').property('__data__', {
depth: 1,
dx: 185.81893466750355,
dy: 76.6094615363257,
name: "Cyprus",
value: 446770,
x: 30.123480134121516,
y: 258.33086334171067
});
var opacity = 1;
var highlightG = d3.select('svg')
.append('g')
.attr("transform", "translate(-30.1234, -258.33)")
.append('g')
.classed('highlighter', true)
.attr('opacity', 0);
highlightG.append('rect');
highlightG.append('text');
d3.select('#toggle')
.on('click', function() {
var d = d3.select('.internal.Cyprus').datum();
highlightG.attr('opacity', opacity);
highlightG.select('rect')
.attr("x", d.x)
.attr("y", d.y)
.attr("width", d.dx)
.attr("height", d.dy)
highlightG
.select("text")
.attr("x", d.x + d.dx / 2)
.attr("y", d.y + d.dy / 2)
.attr('dy', '.35em')
.attr("text-anchor", "middle")
.text(function() {
return d.name;
})
opacity = opacity ? 0 : 1;
});
.newcell text {
font-family: Arial, sans-serif;
font-size: 10px;
}
.newcell.leaf rect {
stroke: #000;
stroke-width: 0.5px;
}
.oversize {
display: none;
}
.internal text {
opacity: 0
}
.highlighter rect {
fill: #000;
fill-opacity: 0.7;
stroke: deepskyblue;
stroke-width: 5px;
}
.highlighter text {
fill: deepskyblue;
opacity: 1
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<p><a id="toggle" href='#'>Activate Cyprus overlay</a></p>
<svg width="186" height="77">
<g transform="translate(-30.1234, -258.33)">
<g class="newcell _2331 cell-level-1 Cyprus internal ">
<rect x="30.123480134121516" y="258.33086334171067" width="185.81893466750355" height="76.6094615363257" style="fill: rgb(100, 200, 75);"></rect>
<title>Cyprus</title>
<text x="123.0329474678733" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2332 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="268.33086334171067" width="31.51365155392795" height="23.97574841366901" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="280.3187375485452" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2333 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="292.30661175537968" width="31.51365155392795" height="32.633713122656687" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="308.62346831670802" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2334 cell-level-2 Cyprus leaf">
<rect x="71.637131688049465" y="268.33086334171067" width="55.48181226963859" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="99.37803782286876" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2335 cell-level-2 Cyprus leaf">
<rect x="127.11894395768805" y="268.33086334171067" width="78.823470843937" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="166.53067937965655" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
</g>
</svg>
I've created a .block with more comprehensive versions of these options.
You should be able to find some combination of these that you can use for your purposes.
Source: stackoverflow.com
Related Query
- How to move elements along with svg group
- How to rotate a group of text elements
- How to group svg elements
- How to drag drop elements into svg group
- How can I make 2 different elements in a SVG group have different drag behaviours?
- How to display different column elements on X-Axis and Group in different column for xScale in D3.js Version 5
- How to clone a group of elements in svg and show the clone in specified coordinate?
- How can i group elements that are bound to different data (to be used with forcesimulatoin) in D3 so that I can sort them
- How to group elements by row?
- How to group g elements in D3?
- How to use brush to select circles that are contained in multiple group elements in D3.js?
- How do I group d3 elements generated from external data?
- How do I remove all children elements from a node and then apply them again with different color and size?
- How to add border/outline/stroke to SVG elements in CSS?
- How to create elements depending on data in D3?
- d3.js - how to insert new sibling elements
- d3.js - How can I set the cursor to hand when mouseover these elements on SVG container?
- D3: update data with multiple elements in a group
- How to update elements of D3 force layout when the underlying data changes
- How to drag an svg group using d3.js drag behavior?
- How to update the fill color on existing svg elements with d3.js?
- How to change text elements in d3?
- How to determine nearby SVG elements on a mouse event?
- How can I toggle the class of all elements in a selection?
- How do I associate SVG elements generated by graphviz to elements in the DOT source code
- How to avoid the overlapping of text elements on the TreeMap when child elements are opened in D3.js?
- D3 (v4): update pattern multiple elements in group
- How to get reference to SVG (child) elements nested in another SVG element (parent) using D3?
- In d3 for javascript, how do you create different elements for your data?
- How to control the group node distance in Hierarchical Edge Bundling in D3.js
More Query from same tag
- D3.js - why is this histogram generating a negative width and throwing an error?
- d3.geo buffer around a feature
- D3.js: Accessing the element's previous datum inside of .attrTween()
- How is it possible to sort a D3 generated HTML table with no "transition()" call?
- How to create group on drag drop
- How do I define a value accessor for a stacked bar graph?
- D3 Sorting Bar Chart Error n.each
- ReferenceError: event is not defined firefox d3.js
- D3 js click triggering for all the past clicks together
- DS.js JSON file format from CSV
- Array elements representation in data table
- Single on event for multiple transitions
- d3 version 4 drag and zoom update
- Drop-down list's design is crashed with too many elements
- Apply binding once in knockout component
- d3 dragging event does not terminate in Firefox
- What is the difference between .append and .join in D3.js
- Filter JavaScript Array Based on Multiple Values
- React Synthetic Event strange behavior
- D3 force simulation in Angular
- D3 mercator function NaN
- Newline characters disappear after uploading a txt to a server
- Getting data for d3 from ArangoDB using AQL (or arangojs)
- Plotting zeros with dimple/d3 js results NaN
- d3.js force directed graph sphere
- d3 Area graph fill issue
- d3 line and area charts not updating with new data array
- D3.js : Loading js file after html
- Change node colour onclick react-d3-graph
- How can I change default tick values on a d3.js