score:1
Accepted answer
While not perfect, this modified version of the code you were using adjusts the text of the currently selected node as it animates and makes it horizontal.
var width = 960,
height = 700,
radius = (Math.min(width, height) / 2) - 10;
var formatNumber = d3.format(",d");
var x = d3.scaleLinear()
.range([0, 2 * Math.PI]);
var y = d3.scaleLinear()
.range([0, radius]);
var color = d3.scaleOrdinal(d3.schemeCategory20);
var partition = d3.partition();
function startAngle(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x0))); }
function endAngle(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x1))); }
function innerRadius(d) { return Math.max(0, y(d.y0)); }
function outerRadius(d) { return Math.max(0, y(d.y1)); }
var arc = d3.arc()
.startAngle( function(d) { return startAngle(d); })
.endAngle( function(d) { return endAngle(d); })
.innerRadius(function(d) { return innerRadius(d); })
.outerRadius(function(d) { return outerRadius(d); })
var texttransform = function(d) {
var translation = y(d.y0);
var rotation = computeTextRotation(d);
if (rotation > 90 && rotation < 270) {
rotation = rotation + 180;
translation = -translation;
}
return (
"rotate(" + rotation + ")" +
"translate(" + translation + ",0)"
);
}
var transition = {};
function calcTransitionPercentage(){
var now = Date.now()-transition.clockNow;
if(!transition.delay || now > transition.delay){
return Math.min(1,(now-(transition.delay||0))/transition.duration);
}
return 0;
}
function computeTextRotation(d) {
if (d.depth === 0) {
return 0;
}
var current = x((d.x0 + d.x1)/2);
var angle = (current - Math.PI / 2) / Math.PI * 180;
if(transition.node === d){
angle -= 90 * calcTransitionPercentage();
}
return (angle > 90 || angle < 270) ? angle : 180 + angle ;
}
var textanchor = function(d) {
if (d.depth === 0) {
return "middle";
}
var rotation = computeTextRotation(d);
return (rotation > 90 && rotation < 270) ? "end" : "start";
}
var textdx = function(d) {
if (d.depth === 0) {
return 0;
}
var rotation = computeTextRotation(d);
return (rotation > 90 && rotation < 270) ? -6 : 6;
}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2) + ")");
function calcFontSize(d) {
const xFactor = 12, yFactor = 7.5 ; // stub
if (d.depth === 0) {
return "30px";
}
// use inner arc len as text height delimiter
var innerArc = (endAngle(d) - startAngle(d)) * 2 * Math.PI * innerRadius(d);
var len = (d.y1-d.y0) * radius;
return Math.min(innerArc / yFactor, len / d.data.textlen * xFactor) + "px";
}
function click(d = { x0: 0, x1: 1, y0: 0, y1: 1 }) {
transition = {clockNow: Date.now(), duration: 750, node: d }
var trans = svg.transition().duration(750);
trans.selectAll("path")
.attrTween("d", function(n) { return function() { return arc(n); }; })
.tween("scale", function() {
var xd = d3.interpolate(x.domain(), [d.x0, d.x1]),
yd = d3.interpolate(y.domain(), [d.y0, 1]),
yr = d3.interpolate(y.range(), [d.y0 ? 20 : 0, radius]);
return function(t) {
x.domain(xd(t));
y.domain(yd(t)).range(yr(t));
};
});
trans.selectAll("text")
.attrTween("transform", function(n) { return function() { return texttransform(n); }; })
.attrTween("text-anchor", function(n) { return function() { return textanchor(n); }; })
.attrTween("dx", function(n) { return function() { return textdx(n); }; })
.styleTween("font-size", function(n) { return function() { return calcFontSize(n); }; });
trans.selectAll("text")
.delay(400)
.attrTween("opacity", function(n) { return function() {
if (d === n || n.ancestors().includes(d)) {
return 1;
} else {
return 0;
}
}; });
}
d3.text('https://raw.githubusercontent.com/manooh/NVSee/master/data/feelings_EN.txt', function(error, raw){
if (error) throw error;
// replace two-space indentation with pipes
raw = raw.replace(new RegExp(' ', 'g'), '|');
//read pipe-delimited data
var dsv = d3.dsvFormat('|');
var flatData = dsv.parse(raw);
var rData = currentNode = tree(flatData);
rData = d3.hierarchy(rData);
var nodes = partition(rData
.sum(function(d) { return 1; }) // each leaf gets a size of 1
.sort(function(a, b) { d3.ascending(a.name, b.name) }) // not working?
)
.descendants();
g = svg.selectAll("path")
.data(nodes)
.enter().append("g");
path = g.append("path")
.attr("d", arc)
.style("fill", function(d, i) {
var c;
if (d.depth === 0) {
return "white";
} else if (d.depth === 1) {
c = color((d.children ? d : d.parent).data.name);
} else if (d.depth > 1) {
c = d3.color(d.parent.data.color).darker();
}
d.data.color = c;
return c;
})
.on("click", click)
.append("title")
.text(function(d) { return d.data.name });
text = g.append("text")
.style("fill", function(d) {
if (d.depth === 0) {
return "#CCC";
} else {
return "#FFF";
}})
.attr("class", "svglabel")
.attr("transform", texttransform)
.attr("text-anchor", textanchor)
.attr("dx", textdx)
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.data.name; })
.style("font-size", function(d) {
// hack. save text len as property to make accessible in transiton
d.data.textlen = this.getComputedTextLength();
return calcFontSize(d);
});
});
function tree(nodes) {
var curr, parent, root;
var lev = 1;
nodes.forEach(function(d) {
if (!root) {
// handle root (first node)
curr = {
name: d.d1,
children: []
};
root = curr;
parent = curr;
} else {
if (d['d' + (lev+1)]) {
// handle children
lev = lev+1;
parent = curr;
} else if (d['d' + (lev-1)]) {
// handle moving up the hierarchy
lev = lev-1;
parent = parent.parent;
} else if (!d['d' + lev]) {
// if it's neither child, nor moving up, nor a sibling, handle exception
throw "unhandled tree level";
}
curr = {
name: d['d' + lev],
children: []
};
curr.parent = parent;
parent.children.push(curr);
}
});
return root;
}
.svglabel {
font-family: sans-serif;
pointer-events: none;
}
body {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
Source: stackoverflow.com
Related Query
- Get visible root node in zoomable sunburst
- Does the d3 treemap layout get cached when a root node is passed to it?
- D3: Sunburst chart with root node on the outside ring
- How can I make last node in d3 zoomable sunburst as a hyperlink?
- How to get data of parent node in d3.js
- Unable to get node datum on mouseover in D3 v6
- Get arrowheads to point at outer edge of node in D3
- D3 force layout fix root node at the center
- Space out nodes evenly around root node in D3 force layout
- D3js V4 Center Node in Zoomable Tree
- Center force directed layout after tick using root node (return to center)
- How to get the same node positions in d3's force layout graph
- javascript zoomable tree map click the last node
- How can i get the startAngle and endAngle of each arc in the sunburst example using d3.js?
- How can I set an initial .focus() on a node in a d3.js sunburst chart?
- How to hide outer ring in zoomable sunburst
- How to create tooltip in D3 to get image on MouseOver on a node in a Graph
- Hiding Root node in d3 tree
- Hide root node and edges in D3 v4 Tree Diagram
- d3.js on-demand data loading to get the next node for a tree
- get the parent nodes to a given node in d3 dendogram
- How to get the boundaries of currently visible time scale (after panning and zooming)?
- How to center root node circle in a d3.layout.pack graph?
- Adding class to root node in d3js tree layout
- How to highlight path from root to selected node in d3 js?
- Get Clipped Line Visible Area Length d3
- Radial Reingold Tilford Tree remove root node
- D3 zoomable timeline, how to get actual extreme values?
- Root element is not showing its children in sunburst
- D3 data format like zoomable sunburst chart
More Query from same tag
- D3 how to call functions on event when inside a class?
- math to svg coordinate translation in javascript
- add custom elements based on css styles not images to chart D3.js
- How to add controls and buttons to map?
- How can I use a leaflet layer control to toggle a d3 svg overlay?
- D3 v4 chart with Bi directional chart
- d3js mask to show dots over bar chart
- Text Not Showing Over SVG Rects
- c3js : Custom region tooltips, hover effects, etc
- Passing a string to a template that has d3.js tree within a Django app
- trying to create a donut chart with labels inside the curve using d3.js
- D3.js and Knockout Force Diagram API Updates
- In D3 Bubble Layout, Is there a way to listen to the name of a bubble and add interaction via jQuery?
- JSON summing multiple objects where values contain a string
- D3 Chord Diagram Not Rendering Correctly
- d3: color by separate array
- How do I make my chart bars align with the chart axis?
- Rotate element thrown outside the SVG
- Qlik Sense change measure used on graph
- text align right relatively to parent G in SVG
- grouped category bar chart with different groups in d3?
- Why do equal-duration d3 transitions get out-of-sync?
- pan d3.js graph
- SVG path stroke-dasharray transition works backwards in some browsers -d3js
- How do I get parent's info from a child?
- What is the best way to hide elements with a certain ID that doesn't effect the performance
- Confusing paths when using D3 and topojson?
- d3 selection issue offsetParent is null
- Resolve Promises with D3
- Add Tooltip on Scatter points, error is generated for D3.js Version 4