Rendering D3 code that is not hard coded - reactjs

I notice that in much of the D3 documentation the charts, graphs, margins and so on are often hard coded. The xAxis is 500px, etc.. This isn't very helpful for me. So I'm trying to think of how I can accomplish a dynamic approach to rendering D3 content in React.
For example, in the following code I am simply rendering a line based on some time-series stock-price data. I have some D3 code in componentDidMount but given the way D3 works it wants concrete width and height values. But in componentDidMount I don't have those values yet. Lets say that this single line plot is one of 100 other plots each in a div in a grid layout.
So how can I get the width/height of the div/svg and only then compute my D3 code and render svgs?
componentDidMount() {
console.log("componentDidMount")
const data = this.props.data;
const selectX = this.props.selectX;
const selectY = this.props.selectY;
console.log(data)
const xScale = d3ScaleTime()
.domain(d3ArrayExtent(data, selectX))
.range([0, 1]);
const yScale = d3ScaleTime()
.domain(d3ArrayExtent(data, selectY))
.range([1, 0]);
const xAxis = d3AxisBottom()
.scale(xScale)
.ticks(data.length / 8);
const yAxis = d3AxisLeft()
.scale(yScale)
.ticks(3);
const selectScaledX = datum => xScale(selectX(datum));
const selectScaledY = datum => yScale(selectY(datum));
const sparkLine = d3Line()
.x(selectScaledX)
.y(selectScaledY);
const linePath = sparkLine(data);
console.log(linePath);
this.setState({
linePath: linePath
});
}

I tried to imitate your issue in the demo below.
class Chart extends React.Component {
componentDidMount() {
var data = this.props.data;
var containerDOMElementWidth = ReactDOM.findDOMNode(this).getBoundingClientRect().width
var chartHeight = containerDOMElementWidth / 2;
this.drawChart(data, containerDOMElementWidth, chartHeight);
}
drawChart(data, chartWidth, chartHeight) {
var margin = { top: 30, right: 20, bottom: 30, left: 50 };
var width = chartWidth - margin.left - margin.right;
var height = chartHeight - margin.top - margin.bottom;
var parseDate = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x)
.ticks(2);
var yAxis = d3.axisLeft().scale(y)
.ticks(2);
var valueline = d3.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.close);
});
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function (d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return d.date;
}));
y.domain([0, d3.max(data, function (d) {
return d.close;
})]);
svg.append("path").attr('class', 'line-chart') // Add the valueline path.
.attr("d", valueline(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
}
render() {
return <div></div>;
}
}
function getRandomData() {
return [{
date: "1-May-12",
close: Math.random() * 90
}, {
date: "30-Apr-12",
close: Math.random() * 90
}, {
date: "27-Apr-12",
close: Math.random() * 90
}, {
date: "26-Apr-12",
close: Math.random() * 90
}, {
date: "25-Apr-12",
close: Math.random() * 90
}];
}
ReactDOM.render(
<div className="charts-container">
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
</div>,
document.getElementById('container')
);
.line-chart {
fill: none;
stroke: blue
}
.charts-container {
display: flex;
}
.chart-wrapper {
width: 100%;
}
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<div id="container">
</div>
Here we draw two charts one by one and calculate their width and height this way:
componentDidMount() {
var data = this.props.data;
// gets the width of container div element with ReactDOM.findDOMNode
var containerDOMElementWidth = ReactDOM.findDOMNode(this).getBoundingClientRect().width
// chart height have to be a half of width
var chartHeight = containerDOMElementWidth / 2;
// pass width and height as an arguments
this.drawChart(data, containerDOMElementWidth, chartHeight);
}
Our drawChart method look like:
drawChart(data, chartWidth, chartHeight) {
var margin = { top: 30, right: 20, bottom: 30, left: 50 };
var width = chartWidth - margin.left - margin.right;
var height = chartHeight - margin.top - margin.bottom;
... // code for the chart drawing
render:
ReactDOM.render(
<div className="charts-container">
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
</div>,
document.getElementById('container')
);
If we will render only one chart it also works fine without any code changing because of we calculate the width of the chart as width of parent div element:
class Chart extends React.Component {
componentDidMount() {
var data = this.props.data;
var containerDOMElementWidth = ReactDOM.findDOMNode(this).getBoundingClientRect().width
var chartHeight = containerDOMElementWidth / 2;
this.drawChart(data, containerDOMElementWidth, chartHeight);
}
drawChart(data, chartWidth, chartHeight) {
var margin = { top: 30, right: 20, bottom: 30, left: 50 };
var width = chartWidth - margin.left - margin.right;
var height = chartHeight - margin.top - margin.bottom;
var parseDate = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x)
.ticks(2);
var yAxis = d3.axisLeft().scale(y)
.ticks(2);
var valueline = d3.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.close);
});
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function (d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return d.date;
}));
y.domain([0, d3.max(data, function (d) {
return d.close;
})]);
svg.append("path").attr('class', 'line-chart') // Add the valueline path.
.attr("d", valueline(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
}
render() {
return <div></div>;
}
}
function getRandomData() {
return [{
date: "1-May-12",
close: Math.random() * 90
}, {
date: "30-Apr-12",
close: Math.random() * 90
}, {
date: "27-Apr-12",
close: Math.random() * 90
}, {
date: "26-Apr-12",
close: Math.random() * 90
}, {
date: "25-Apr-12",
close: Math.random() * 90
}];
}
ReactDOM.render(
<div className="charts-container">
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
</div>,
document.getElementById('container')
);
.line-chart {
fill: none;
stroke: blue
}
.charts-container {
display: flex;
}
.chart-wrapper {
width: 100%;
}
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<div id="container">
</div>
The same thing for three charts:
class Chart extends React.Component {
componentDidMount() {
var data = this.props.data;
var containerDOMElementWidth = ReactDOM.findDOMNode(this).getBoundingClientRect().width
var chartHeight = containerDOMElementWidth / 2;
this.drawChart(data, containerDOMElementWidth, chartHeight);
}
drawChart(data, chartWidth, chartHeight) {
var margin = { top: 30, right: 20, bottom: 30, left: 50 };
var width = chartWidth - margin.left - margin.right;
var height = chartHeight - margin.top - margin.bottom;
var parseDate = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x)
.ticks(2);
var yAxis = d3.axisLeft().scale(y)
.ticks(2);
var valueline = d3.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.close);
});
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
data.forEach(function (d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return d.date;
}));
y.domain([0, d3.max(data, function (d) {
return d.close;
})]);
svg.append("path").attr('class', 'line-chart') // Add the valueline path.
.attr("d", valueline(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
}
render() {
return <div></div>;
}
}
function getRandomData() {
return [{
date: "1-May-12",
close: Math.random() * 90
}, {
date: "30-Apr-12",
close: Math.random() * 90
}, {
date: "27-Apr-12",
close: Math.random() * 90
}, {
date: "26-Apr-12",
close: Math.random() * 90
}, {
date: "25-Apr-12",
close: Math.random() * 90
}];
}
ReactDOM.render(
<div className="charts-container">
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
<div className="chart-wrapper">
<Chart data={getRandomData()} />
</div>
</div>,
document.getElementById('container')
);
.line-chart {
fill: none;
stroke: blue
}
.charts-container {
display: flex;
}
.chart-wrapper {
width: 100%;
}
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<div id="container">
</div>

Related

d3js get data from multidimensional array

I'm working on a d3js donut chart and I'm trying to feed data in from a multidimensional array: fiddle
Output of topHoldersArray:
{
"1":{"address":"0xd35a2d8c651f3eba4f0a044db961b5b0ccf68a2d","amount":"309953166.54621424","percent":"30.9953%"},
"2":{"address":"0xe17c20292b2f1b0ff887dc32a73c259fae25f03b","amount":"200000001","percent":"20.0000%"},
"3":{"address":"0x0000000000000000000000000000000000000000","amount":"129336426","percent":"12.9336%"}
}
With this array I get the error:
Uncaught TypeError: Cannot read property 'startAngle' of undefined
How can I feed this array into the graph? It seems the issue is that it's a multidimensional array but I"m not sure how to access it for the data points
Here's a snippet illustrating the problem:
var topHoldersArray = [
{
"1":{"address":"0xd35a2d8c651f3eba4f0a044db961b5b0ccf68a2d","amount":"309953166","percent":"30.9953%"},
"2":{"address":"0xe17c20292b2f1b0ff887dc32a73c259fae25f03b","amount":"200000001","percent":"20.0000%"},
"3":{"address":"0x0000000000000000000000000000000000000000","amount":"129336426","percent":"12.9336%"}
}
];
var data = topHoldersArray;
var text = "";
var width = 260;
var height = 260;
var thickness = 40;
var duration = 750;
var radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var svg = d3.select("#topHoldersChart")
.append('svg')
.attr('class', 'pie')
.attr('width', width)
.attr('height', height);
var g = svg.append('g')
.attr('transform', 'translate(' + (width/2) + ',' + (height/2) + ')');
var arc = d3.arc()
.innerRadius(radius - thickness)
.outerRadius(radius);
var pie = d3.pie()
.value(function(d) { return d.amount; })
.sort(null);
var path = g.selectAll('path')
.data(pie(data))
.enter()
.append("g")
.on("mouseover", function(d) {
let g = d3.select(this)
.style("cursor", "pointer")
.style("fill", "black")
.append("g")
.attr("class", "text-group");
g.append("text")
.attr("class", "name-text")
.text(`${d.data.address}`)
.attr('text-anchor', 'middle')
.attr('dy', '-1.2em');
g.append("text")
.attr("class", "value-text")
.text(`${d.data.amount}`)
.attr('text-anchor', 'middle')
.attr('dy', '.6em');
})
.on("mouseout", function(d) {
d3.select(this)
.style("cursor", "none")
.style("fill", color(this._current))
.select(".text-group").remove();
})
.append('path')
.attr('d', arc)
.attr('fill', (d,i) => color(i))
.on("mouseover", function(d) {
d3.select(this)
.style("cursor", "pointer")
.style("fill", "black");
})
.on("mouseout", function(d) {
d3.select(this)
.style("cursor", "none")
.style("fill", color(this._current));
})
.each(function(d, i) { this._current = i; });
g.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.text(text);
.pie {
margin: 20px;
}
.pie text {
font-family: "Verdana";
fill: #888;
}
.pie .name-text{
font-size: 1em;
}
.pie .value-text{
font-size: 3em;
}
<div class="token-chart">
<h6>Top Holders</h6>
<div class="chart" id="topHoldersChart"></div>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
Let's look at your d3.pie layout:
var pie = d3.pie()
.value(function(d) { return d.amount; })
.sort(null);
When we feed data to this (pie(data)), pie is expecting an array. But you are providing an object:
{
"1":{"address":"0xd35a2d8c651f3eba4f0a044db961b5b0ccf68a2d","amount":"309953166.54621424","percent":"30.9953%"},
"2":{"address":"0xe17c20292b2f1b0ff887dc32a73c259fae25f03b","amount":"200000001","percent":"20.0000%"},
"3":{"address":"0x0000000000000000000000000000000000000000","amount":"129336426","percent":"12.9336%"}
}
We need to convert this to an array to feed it to d3.pie(). For this we could use d3.entries() (though there are other ways to achieve this too).
d3.entries() takes an object, say:
{ a: value1, b: value2 }
And converts it to an array:
[ { key: "a", value: value1 }, {key: "b", value: value2 } ]
The values are now within a property called value. This requires us to look up the amount at d.value.amount. For example:
var topHoldersArray =
{
"1":{"address":"0xd35a2d8c651f3eba4f0a044db961b5b0ccf68a2d","amount":"309953166","percent":"30.9953%"},
"2":{"address":"0xe17c20292b2f1b0ff887dc32a73c259fae25f03b","amount":"200000001","percent":"20.0000%"},
"3":{"address":"0x0000000000000000000000000000000000000000","amount":"129336426","percent":"12.9336%"}
};
var data = d3.entries(topHoldersArray);
var text = "";
var width = 260;
var height = 260;
var thickness = 40;
var duration = 750;
var radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal(d3.schemeCategory20);
var svg = d3.select("#topHoldersChart")
.append('svg')
.attr('class', 'pie')
.attr('width', width)
.attr('height', height);
var g = svg.append('g')
.attr('transform', 'translate(' + (width/2) + ',' + (height/2) + ')');
var arc = d3.arc()
.innerRadius(radius - thickness)
.outerRadius(radius);
var pie = d3.pie()
.value(function(d) { return d.value.amount; })
.sort(null);
var path = g.selectAll('path')
.data(pie(data))
.enter()
.append("g")
.on("mouseover", function(d) {
let g = d3.select(this)
.style("cursor", "pointer")
.style("fill", "black")
.append("g")
.attr("class", "text-group");
g.append("text")
.attr("class", "name-text")
.text(`${d.data.value.address}`)
.attr('text-anchor', 'middle')
.attr('dy', '-1.2em')
g.append("text")
.attr("class", "value-text")
.text(`${d.data.value.amount}`)
.attr('text-anchor', 'middle')
.attr('dy', '.6em')
})
.on("mouseout", function(d) {
d3.select(this)
.style("cursor", "none")
.style("fill", color(this._current))
.select(".text-group").remove();
})
.append('path')
.attr('d', arc)
.attr('fill', (d,i) => color(i))
.on("mouseover", function(d) {
d3.select(this)
.style("cursor", "pointer")
.style("fill", "black");
})
.on("mouseout", function(d) {
d3.select(this)
.style("cursor", "none")
.style("fill", color(this._current));
})
.each(function(d, i) { this._current = i; });
g.append('text')
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.text(text);
.pie {
margin: 20px;
}
.pie text {
font-family: "Verdana";
fill: #888;
}
.pie .name-text{
font-size: 1em;
}
.pie .value-text{
font-size: 3em;
}
<div class="token-chart">
<h6>Top Holders</h6>
<div class="chart" id="topHoldersChart"></div>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>

How do i give ellipsis in axis labels in d3 v4?

Here is my code snippet for implementing the ellipsis on x axis labels in d3 v3.
Can someone help me figure out the changes needed to my code in v4??
//function for adding '...' if length is more than 50 px
var wrap = function () {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
svg.select('.x.axis')
.call(xAxis)
.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
You just need to save the group element containing x-axis into a variable and use as shown below.
var wrap = function() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
xAxis.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 250 - margin.left - margin.right,
height = 250 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleBand()
.range([0, width])
.padding(0.1);
var y = d3.scaleLinear()
.range([height, 0]);
// append the svg object to the body of the page
// append a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var data = [{
"salesperson": "Bob Patrickson",
"sales": 33
},
{
"salesperson": "Robin Dearden",
"sales": 12
},
{
"salesperson": "Anne Hathaway",
"sales": 41
},
{
"salesperson": "Mark Wahlberg",
"sales": 16
}
];
// format the data
data.forEach(function(d) {
d.sales = +d.sales;
});
// Scale the range of the data in the domains
x.domain(data.map(function(d) {
return d.salesperson;
}));
y.domain([0, d3.max(data, function(d) {
return d.sales;
})]);
// append the rectangles for the bar chart
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.salesperson);
})
.attr("width", x.bandwidth())
.attr("y", function(d) {
return y(d.sales);
})
.attr("height", function(d) {
return height - y(d.sales);
});
// add the x Axis
var xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// add the y Axis
svg.append("g")
.call(d3.axisLeft(y));
var wrap = function() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (50) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
};
//calling the function
xAxis.selectAll('text')
.style('text-anchor', 'end')
.attr('fill', '#8a9299')
.attr('transform', 'rotate(-60)')
.each(wrap);
.bar {
fill: steelblue;
}
<script src="//d3js.org/d3.v4.min.js"></script>

Elasticsearch- Nested Aggregations D3

I am trying to create D3 charts based on elasticsearch nested aggregation. While I can plot a chart based on the first aggregation, I am not sure why I cant plot a similar chart on the nested a subsequent aggregation. Can anyone suggest what I should do?
My code:
esClient.search({
index: 'vehicle',
body: {
query:{
match:{
_all:searchTerms
}
},
aggs: {
touchdowns: {
terms: {
field: "country",
size:5
},
aggs: {
corp: {
terms: {
field: "companyName",
size:5
}
}
},
}
},
sort: [sortObject],
from: resultsPage * 10,
}
}).then(function(es_return){
deferred.resolve(es_return);
//// Pie Chart first aggregation
var touchdowns = es_return.aggregations.touchdowns.buckets;
// d3 donut chart
var width = 600,
height = 300,
radius = Math.min(width, height) / 2;
var color = ['#ff7f0e', '#d62728', '#2ca02c', '#1f77b4'];
var arc = d3.svg.arc()
.outerRadius(radius - 60)
.innerRadius(120);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.doc_count; });
var svg = d3.select("#donut-chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/1.4 + "," + height/2 + ")");
var g = svg.selectAll(".arc")
.data(pie(touchdowns))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d, i) { return color[i]; });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("fill", "white")
.text(function (d) { return d.data.key; });
//// Pie Chart
var touchdowns = es_return.aggregations.touchdowns.buckets.corp.buckets;
// d3 donut chart
var width = 600,
height = 300,
radius = Math.min(width, height) / 2;
var color = ['#ff7f0e', '#d62728', '#2ca02c', '#1f77b4'];
var arc = d3.svg.arc()
.outerRadius(radius - 60)
.innerRadius(120);
var pie = d3.layout.pie()
.sort(null)
.value(function (d) { return d.doc_count; });
var svg = d3.select("#donut-chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width/1.4 + "," + height/2 + ")");
var g = svg.selectAll(".arc")
.data(pie(touchdowns))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d, i) { return color[i]; });
g.append("text")
.attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.style("fill", "white")
.text(function (d) { return d.assignee.key; });
}, function(error){
deferred.reject(error);
});
return deferred.promise;};

How to draw Zoomable Sunburst with angular directive?

I am new to d3.js, can anyone guide me about drawing zoomable sunburst.
Thanks in advance !
You might want to check out the D3 gallery of examples, specifically the zoomable sunburst:
http://bl.ocks.org/mbostock/4348373
Code from their example:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke: #fff;
fill-rule: evenodd;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 700,
radius = Math.min(width, height) / 2;
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var color = d3.scale.category20c();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.value(function(d) { return d.size; });
var arc = d3.svg.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
.innerRadius(function(d) { return Math.max(0, y(d.y)); })
.outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
d3.json("/mbostock/raw/4063550/flare.json", function(error, root) {
if (error) throw error;
var path = svg.selectAll("path")
.data(partition.nodes(root))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return color((d.children ? d : d.parent).name); })
.on("click", click);
function click(d) {
path.transition()
.duration(750)
.attrTween("d", arcTween(d));
}
});
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(d, i) {
return i
? function(t) { return arc(d); }
: function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
};
}
</script>

d3.js Help getting Y axis dynamically labeled on simple bar chart

The data is in an array of objects where the
Data = [object{name:"FIRST TECH", value:2477}];
The technology names change and I am trying to place them to the left of the bar they are associated with.
I'm not sure if I'm doing this in the best practice, but when I get the text appended to the side it is invisible. I've tried changing the class name, changing the color, z-index, position:absolute, it always remains hidden.
What do I need to do in order to get the label correctly on the side?
Code:
<style>
h2{
text-align:center;
margin-left: auto;
margin-right: auto;
}
.abcxyz{
fill:black;
color:#000;
text-anchor: end;
}
.chart {
width:800px;
display:block;
margin:auto;
background-color:#c7d9e8;
}
.chart rect {
fill: steelblue;
}
.chart rect:hover{
fill:brown;
}
.values {
fill: white;
font: 12px sans-serif;
text-anchor: end;
}
</style>
<script>
$(document).ready(function(){
var return_data;
$.ajax({
url: '<?php echo site_url('metrics/getTechDocs') ?>',
type: 'GET',
success: function(data){
data = JSON.parse(data);
set_return_data(data);
drawGraph(data);
},
error: function(data){
console.log("error");
}
});
});
function set_return_data(data){
return_data = data;
console.log (return_data);
}
function formatGraphData(data){
var newData = new Array();
for(x in data){
tmp = {name: x , value: data[x].length};
newData.push(tmp);
}
newData.sort(function(a,b){return b.value - a.value} );
return newData;
}
function drawGraph(rawData){
rawData = formatGraphData(rawData);
var width = 800,
barHeight = 30;
var x = d3.scale.linear()
.domain([0, rawData[0].value])
.range([10, width]);
var y = d3.scale.linear()
.domain(rawData.map(function(d){return d.name}))
.range([0, barHeight * rawData.length]);
var chart = d3.select(".chart")
.attr("height", barHeight * rawData.length);
var bar = chart.selectAll("g")
.data(rawData)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("text")
.attr("class", "abcxyz")
.attr("y", barHeight / 2 )
.text(function(d){return d.name});
bar.append("rect")
.attr("height", barHeight - 1)
.attr("width", function(d){return x(d.value);});
bar.append("text")
.attr("class", "values")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d){return d.value;});
}
</script>
<div>
<h2>Frequency of Technology Terms</h2>
<svg class="chart"></svg>
</div>
SVG doesn't know z-order or anything similar. The elements are displayed in the order they are added in. So to make the text appear on top of the bars, draw the bars first and then the text.

Resources