d3 is running in multiple times in react - javascript

I am using normal d3.js in my react application. problem is this code is being executing multiple times if I put my code in componentDidMount it is running only single time. but it is giving my value undefined. if I add componentDidUpdate it is giving value properly but running svg componenet multiple times. now don't know what to do?
below is my code
componentDidMount(){
this.processData(this.props);
}
componentDidUpdate(prevProps,prevState){
if(this.props.potentialBrandReturn== undefined)
this.processData(this.props);
return false;
}
processData(props){
var data = [
{
label: 'Return',
value: props.currentYearReturn,
potential: props.potentialComReturn,
color: '#aa3939'
},
{
label: 'Brand',
value: props.currentYearBrand,
potential: props.potentialBrandReturn,
color: '#2c4770'
}
];
var div = d3.select('body').append('div').attr('class', 'toolTip');
var axisMargin = 20,
margin = 40,
valueMargin = 4,
width = 550,
height = 250,
barHeight = 40,
barPadding = 30,
data,
bar,
svg,
scale,
scaleMark,
xAxis,
labelWidth = 0;
var max = d3.max(data, function(d) {
return d.potential;
});
svg = d3
.select('#customChart2')
.classed('svg-container1', true) //container class to make it responsive
.append('svg')
//responsive SVG needs these 2 attributes and no width and height attr
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('viewBox', '0 0 600 200')
//class to make it responsive
.classed('svg-content-responsive', true);
scale = d3.scale
.linear()
.domain([0, max])
.range([0, 400 - margin * 2 - labelWidth]);
bar = svg.selectAll('g').data(data).enter().append('g');
bar.attr('class', 'bar').attr('cx', 0).attr('transform', function(d, i) {
return (
'translate(' +
margin +
',' +
(i * (barHeight + barPadding) + barPadding) +
')'
);
});
//appending lable
bar
.append('text')
.attr('class', 'label')
.attr('y', barHeight / 2)
.attr('dy', '.35em') //vertical align middle
.text(function(d) {
return d.label;
})
.each(function() {
labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width)) + 5;
});
//appending Potential rect
bar
.append('rect')
.attr('transform', 'translate(' + labelWidth + ', 0)')
.attr('height', barHeight)
.style('fill', 'transparent')
.style('stroke', function(d) {
return d.color;
})
.attr('width', function(d) {
return scale(d.potential);
})
.on('mouseover', function() {
return tooltip.style('visibility', 'visible');
})
.on('mousemove', function(d) {
return tooltip
.style('top', d3.event.pageY - 10 + 'px')
.style('left', d3.event.pageX + 10 + 'px')
.text('Potential Value is $' + d.potential);
})
.on('mouseout', function() {
return tooltip.style('visibility', 'hidden');
});
//appending main bar for the chart
bar
.append('rect')
.attr('transform', 'translate(' + labelWidth + ', 0)')
.attr('height', barHeight)
.style('fill', function(d) {
return d.color;
})
.attr('width', function(d) {
return scale(d.value);
})
.on('mouseover', function() {
return tooltip.style('visibility', 'visible');
})
.on('mousemove', function(d) {
return tooltip
.style('top', d3.event.pageY - 10 + 'px')
.style('left', d3.event.pageX + 10 + 'px')
.text('Actual Value is $' + d.value);
})
.on('mouseout', function() {
return tooltip.style('visibility', 'hidden');
});
// appending text for rect Potential
bar
.append('text')
.attr('transform', 'translate(' + labelWidth + ', 0)')
.attr('y', barHeight / 2)
.attr('dy', '.35em') //vertical align middle
.attr('x', 10)
.attr('dx', function(d) {
return scale(d.potential);
})
.text(function(d) {
return '$' + d.potential + ' Potential';
});
//appending value in side the rectangle
bar
.append('text')
.attr('class', 'value')
.attr('y', barHeight / 2)
.attr('dx', function(d) {
var temp = scale(d.value) + labelWidth;
return temp - 10;
}) //margin right
//.attr("dx", valueMargin + labelWidth + margin) //margin right
.attr('dy', '.35em') //vertical align middle
.attr('text-anchor', 'start')
.text(function(d) {
return '$' + d.value;
});
// for tooltip message
var tooltip = d3
.select('body')
.append('div')
.attr('class', 'toolTip1')
.style('position', 'absolute')
.style('z-index', '10')
.style('visibility', 'hidden');
// appending the chart to html
svg
.insert('g', ':first-child')
.attr('class', 'axisHorizontal')
.attr(
'transform',
'translate(' +
(margin + labelWidth) +
',' +
(height - axisMargin - margin) +
')'
);
// .call(yAxis);

try this
constructor(props) {
super(props);
this.state = {
isDataPopulated: false
};
}
componentDidMount(){
// delte call to this.processData()
}
componentDidUpdate(prevProps,prevState){
let potentialBrandReturn = this.props.potentialBrandReturn === undefined;
if(!potentialBrandReturn && !this.state.isDataPopulated)
this.processData(this.props);
this.setState({isDataPopulated : true})
}else{
return false;
}
}

Related

Update a d3.js (v5) selection bound with double nested data

I have a double nested data set in d3. I want to create a scatter plot to be updated for each value of the first key ("time" variable), but the data of each point is bound to the values of he second key ("space" variable). So, to be clear, each point should be translated to new coordinates and its radius must be updated too.
Here is a data sample (in file "prosperLoanData.csv")
BorrowerState,LoanOriginationDate,LoanOriginalAmount,LenderYield
AK,2007-01-01 00:00:01,1000,0.1
AK,2007-01-01 00:00:01,2000,0.11
AK,2007-01-01 00:00:01,1500,0.09
AK,2007-01-01 00:00:01,500,0.1
AK,2008-01-01 00:00:01,2500,0.07
AK,2008-01-01 00:00:01,3000,0.06
AK,2008-01-01 00:00:01,3500,0.0652
OK,2007-01-01 00:00:01,4000,0.08
OK,2007-01-01 00:00:01,4100,0.081
OK,2007-01-01 00:00:01,4500,0.0812
OK,2007-01-01 00:00:01,4600,0.0799
OK,2007-01-01 00:00:01,3900,0.08
OK,2008-01-01 00:00:01,5000,0.05
And here is my code. I though that deleting the YearGroups1.exit().remove() was enough, but it is not. I can not properly select the circles and rebind them to the new dataset (at the second nested level). Can you help me?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
div.tooltip {
position: absolute;
text-align: center;
width: 180px;
height: 45px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<script type="text/javascript">
</script>
</head>
<body>
<script type="text/javascript">
/*
Use D3 to load the loan data
*/
var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S")
// load data
d3.csv("prosperLoanData.csv").then(function(data) {
// Setting global parameters
"use strict";
// ----> Margin & size
var margin = 75,
width = 1400 - margin,
height = 600 - margin,
op = 0.5,
years = [2007, 2008];
// ----> Format for strings
var formatDec = d3.format(".0f"),
formatper = d3.format(".2%"),
formatM = d3.format("\$.2s");
// change string (from CSV) into number format
data.forEach( function(d) {
d["Year"] = parseTime(d.LoanOriginationDate).getYear() + 1900;
d["LoanOriginalAmount"] = +d["LoanOriginalAmount"];
d["LenderYield"] = +d["LenderYield"];
// debugger
return d; });
// Function definition
// function update() {};
function key_func(d) {
return d['key'];
}
// FIXED PART
// Define the svg element
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin)
.attr("height", height + margin);
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Data preprocessing - grouping
var nested_year = d3.nest()
.key( function(d) { return d.Year } )
.key( function(d) { return d.BorrowerState })
.rollup( function(points) {
// debugger
var mean_loan = d3.mean(points, function(d) { return d.LoanOriginalAmount; } );
var mean_lenderyield = d3.mean(points, function(d) { return d.LenderYield; } );
// var std_loan = d3.deviation(points, function(d) { return d.LoanOriginalAmount; } );
var sum_loan = d3.sum(points, function(d) { return d.LoanOriginalAmount; } );
var max_loan = d3.max(points, function(d) { return d.LoanOriginalAmount; } );
var min_loan = d3.min(points, function(d) { return d.LoanOriginalAmount; } );
var max_ly = d3.max(points, function(d) { return d.LenderYield; } );
var min_ly = d3.min(points, function(d) { return d.LenderYield; } );
// debugger
return {
"meanLoan" : mean_loan,
"meanLenderyield" : mean_lenderyield,
// "stdLoan" : std_loan,
"sumLoan" : sum_loan,
};
}
)
.entries(data);
// Determining X/Y Max & Min
var LOA_E1 = d3.min(nested_year, function(d) {return d3.min(d.values, function(da) { return da.value.meanLoan; });})
var LOA_E2 = d3.max(nested_year, function(d) {return d3.max(d.values, function(da) { return da.value.meanLoan; });})
var LY_E1 = d3.min(nested_year, function(d) {return d3.min(d.values, function(da) { return da.value.meanLenderyield; });})
var LY_E2 = d3.max(nested_year, function(d) {return d3.max(d.values, function(da) { return da.value.meanLenderyield; });})
var LenderYield_Extent = [LY_E1 , LY_E2 ];
var LoanOriginalAmount_Extent = [LOA_E1 , LOA_E2];
// Creating a scale
var XScale = d3.scaleLinear()
.range([margin , width])
.domain([ 1.05 * LenderYield_Extent[0] - 0.05 * LenderYield_Extent[1] ,
1.05 * LenderYield_Extent[1] - 0.05 * LenderYield_Extent[0] ] );
// debugger
var YScale = d3.scaleLinear()
.range([height , margin])
.domain([ 0, 1.025 * LoanOriginalAmount_Extent[1]]);
var SUM_LOAN_Extent = [70E3 , 1.2E7]; // d3.extent(red_data.value, d => d.value.sumLoan);
var radius = d3.scaleSqrt()
.domain(SUM_LOAN_Extent)
.range([3,0.375 * margin/2]);
// Creating axis
var x_axis = d3.axisBottom()
.scale(XScale)
.tickFormat(d3.format(".2%"));
var y_axis = d3.axisLeft()
.scale(YScale)
.tickFormat(d3.format(".0f"));
svg.append('g')
.attr('transform', "translate(0," + height + ")")
.call(x_axis);
svg.append('g')
.attr('transform', "translate(" + margin + ",0)")
.call(y_axis);
// Text label for the x axis
svg.append("text")
.attr("transform",
"translate(" + (width/2 + margin) + " ," +
(height + margin/2) + ")")
.style("text-anchor", "middle")
.style("font-size", 20)
.text("Mean lender yield (percentage)");
// Text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.style("font-size", 20)
.text("Mean loan original amount [US dollars]");
// Creating gridlines
function make_x_gridlines() {
return d3.axisBottom(XScale)
.ticks(5);
};
function make_y_gridlines() {
return d3.axisLeft(YScale)
.ticks(5);
};
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-(height - 1 * margin ))
.tickFormat(""));
svg.append("g")
.attr("class", "grid")
.attr('transform', "translate(" + margin + ",0)")
.call(make_y_gridlines()
.tickSize(-(width - 1 * margin ))
.tickFormat(""));
// Add legend
var DELTA = SUM_LOAN_Extent[1] - SUM_LOAN_Extent[0];
var valuesToShow = [SUM_LOAN_Extent[0] + 0.00 * DELTA, SUM_LOAN_Extent[0] + 0.25 * DELTA ,
SUM_LOAN_Extent[0] + 0.50 * DELTA, SUM_LOAN_Extent[0] + 0.75 * DELTA ,
SUM_LOAN_Extent[0] + 1.00 * DELTA ];
var xCircle = width + 0.35 * margin;
var xLabel = 200;
var yCircle = 150;
var legend = svg.append("g")
.attr("class","legend")
.attr("trasform","translate(" + (width - 100) + "," + 20 + ")" )
.selectAll("g")
.data(valuesToShow)
.enter()
.append("g");
legend.append("circle")
.attr("cy", function(d,i) {
return (i+1)* 0.4 * yCircle + radius(d)/2; })
.attr("cx", xCircle)
.attr("r", function(d) {
return radius(d); })
.attr("stroke","black")
.attr("stroke-width",1.)
.attr("opacity", op);
// Add legend: labels
svg.selectAll("legend")
.data(valuesToShow)
.enter()
.append("text")
.attr('x', function(d,i){ return width + 0.55 * margin; } )
.attr('y', function(d,i){ return (i+1)* 0.4 * yCircle + radius(d)/2 } )
.text( function(d){ return formatM(d) } )
.style("font-size", 10)
.attr('alignment-baseline', 'middle');
svg.append("text")
.attr('x', 0.98 * xCircle )
.attr('y', 0.15 * yCircle )
.text( "Size = " )
.style("font-size", 12.5)
.attr('alignment-baseline', 'middle');
svg.append("text")
.attr('x', 0.98 * xCircle )
.attr('y', 0.15 * yCircle + 10 )
.text( "Total loan" )
.style("font-size", 12.5)
.attr('alignment-baseline', 'middle');
svg.append("text")
.attr('x', 0.98 * xCircle )
.attr('y', 0.15 * yCircle + 20)
.text( "amount (US \$)" )
.style("font-size", 12.5)
.attr('alignment-baseline', 'middle');
// Add color legend
var colors = d3.scaleOrdinal()
.domain([0, 1, 2])
.range(["blue", "green" , "black"]);
var stat = d3.scaleOrdinal()
.domain([0, 1, 2])
.range(["CA", "TX" , "Others"]);
var aaa = [ SUM_LOAN_Extent[0] + 1.00 * DELTA , SUM_LOAN_Extent[0] + 1.00 * DELTA, SUM_LOAN_Extent[0] + 1.00 * DELTA];
var legend1 = svg.append("g")
.attr("class","legend")
.attr("trasform","translate(" + (width - 100) + "," + 20 + ")" )
.selectAll("g")
.data(aaa)
.enter()
.append("g");
legend1.append("circle")
.attr("cy", function(d,i) { //debugger
return (6+i)* 0.4 * yCircle + radius(d)/2; })
.attr("cx", xCircle)
.attr("r", function(d) {
return radius(d); })
.attr("fill", function(d,i){ return colors(i)})
.attr("opacity", op);
// Add legend: labels
svg.selectAll(".legend1")
.data(aaa)
.enter()
.append("text")
.attr('x', function(d,i){ return width + 0.55 * margin; } )
.attr('y', function(d,i){ return (6+i)* 0.4 * yCircle + radius(d)/2 } )
.text( function(d,i){ return stat(i) } )
.style("font-size", 10)
.attr('alignment-baseline', 'middle');
// Appending first circles
// Accessing 1st group
var YearGroups = svg.selectAll(".YearGroups")
.data(nested_year, key_func)
.enter()
.append("g")
.attr("class", "YearGroups");
// Accessing 2nd group
var circles = YearGroups.selectAll("circle")
.data(function(d){
return d.values
})
.enter()
.append("circle")
.transition()
.duration(500)
.attr("cx", function(d) { return XScale(d.value.meanLenderyield) } )
.attr("cy", function(d) { return YScale(d.value.meanLoan ) } )
.attr("r" , function(d) { return radius(d.value.sumLoan ) } )
.attr("fill" , function(d) { if
(d.key == "CA") {return "blue"}
if (d.key == "TX") {return "green"}
else
{ return "black" }})
.attr("opacity" , op);
// debugger
// VARIABLE PART
function update(year) {
var filt = nested_year.filter(function(d) {return d.key == year;} );
var YearGroups1 = svg.selectAll(".YearGroups")
.data(filt, key_func);
YearGroups1.exit().remove();
var circles = YearGroups1.enter().append('g')
.attr("class", "YearGroups").selectAll('circle')
.data(function(d){ return d.values });
var CircPl = circles.enter()
.append("circle")
.transition()
.duration(500)
.attr("cx", function(d) { // debugger
return XScale(d.value.meanLenderyield); })
.attr("cy", function(d) { return YScale(d.value.meanLoan ); })
.attr("r" , function(d) { return radius(d.value.sumLoan ); })
.attr("fill" , function(d) { if
(d.key == "DC") {return "blue"}
if (d.key == "AR") {return "green"}
else
{ return "black" }})
.attr("opacity" , op)
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Lender yield : " + formatper(d.value.meanLenderyield) + "<br/>" +
"Loan original amount : " + formatDec(d.value.meanLoan) + " $ <br/>" +
"State : " + d.key)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
CircPl
// debugger
// Chart Title
svg.selectAll(".Title").remove()
svg
.append("text")
.attr("class","Title")
.attr("x", (margin + width) / 2)
.attr("y", margin / 2)
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.style("font-size", "32px")
.text("US Loans per State in " + year); // Title updated
}
var year_idx = 0;
var year_interval = setInterval(function() {
update(years[year_idx]);
year_idx++;
if(year_idx >= years.length) {
clearInterval(year_interval);
}
}, 1000);
});
</script>
</body>
</html>
I got the solution for the issue (thanks Myles C. from Udacity Mentor team).
In fact, the data to be accessed where easily stored in a dummy variable that has been used for data binding afterwards and the .merge() statement is used to update both to all circles.
function update_video(year) {
var filt = nested_year.filter(function(d) {
return d.key == year;
});
var data = filt[0].values
// Selection and Bind Data
const update = YearGroups.selectAll("circle")
.data(data);
var upd = update.enter()
.select("circle")
.merge(update)
.transition()
.duration(1500)
.attr("class", "node_circle")
.attr("cx", function(d) {
return XScale(d.value.meanLenderyield);
})
.attr("cy", function(d) {
return YScale(d.value.meanLoan);
})
.attr("r", function(d) {
return radius(d.value.sumLoan);
})
.attr("fill", function(d) {
if (d.key == "CA") { return "blue";}
if (d.key == "TX") { return "green";}
else { return "black"}
});
// Command necessary to remove States that are not available in the
// database for that year
update.exit().remove();
// Chart Title
svg.selectAll(".Title").remove();
svg.append("text")
.attr("class", "Title")
.attr("x", (margin + width) / 2)
.attr("y", margin / 2)
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.style("font-size", "32px")
.text("US Loans per State in " + year); // Title update
};
With this function, each circle is updated, regardless of the state (second key of nested data); the .exit().remove() command has been used to remove all points not bound to data.
Afterward, a second function is used to let the user choose a year and update the circles without transitions, but adding tooltips to get data information hoovering the points with the mouse.
function update_with_tooltip(year) {
var filt = nested_year.filter(function(d) {
return d.key == year;
});
var data = filt[0].values;
// Selection and Bind Data
const update = YearGroups.selectAll("circle")
.data(data);
// Update and merge
var upd = update.enter()
.select("circle")
.merge(update)
.attr("class", "node_circle")
.attr("cx", function(d) {
return XScale(d.value.meanLenderyield);
})
.attr("cy", function(d) {
return YScale(d.value.meanLoan);
})
.attr("r", function(d) {
return radius(d.value.sumLoan);
})
.attr("fill", function(d) {
if (d.key == "CA") { return "blue";}
if (d.key == "TX") { return "green";}
else { return "black"}
})
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Lender yield : " + formatper(d.value.meanLenderyield) +
"<br/>" + "Loan original amount : " + formatDec(d.value.meanLoan)
+ " $ <br/>" + "State : " + d.key)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
// Command necessary to remove States that are not available in the
// database for that year
update.exit().remove();
// Chart Title
svg.selectAll(".Title").remove();
svg.append("text")
.attr("class", "Title")
.attr("x", (margin + width) / 2)
.attr("y", margin / 2)
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.style("font-size", "32px")
.text("US Loans per State in " + year); // Title update
}

In d3.js treemap layout how to make the last child clickable and fill the entire treemap layout

Im using d3.js treemap layout . In the treemap , on clicking the parent segment with the children property it transitions into its respective child sub segments . But on clicking the last child without any children property it wont make the transition happens to fill only that child node in the entire layout . In the code that im working on I can redirect to a new window on click of the last child but not sure how to make the transition happening .
Find my code in the link https://codesandbox.io/s/affectionate-thunder-l024x
class TreemapChart extends React.Component {
componentDidMount() {
const self = this;
var margin = { top: 20, right: 0, bottom: 0, left: 0 },
width = 960,
height = 500 - margin.top - margin.bottom,
transitioning;
var x = d3.scale
.linear()
.domain([0, width])
.range([0, width]);
var y = d3.scale
.linear()
.domain([0, height])
.range([0, height]);
var treemap = d3.layout
.treemap()
.children(function(d, depth) {
return depth ? null : d._children;
})
.sort(function(a, b) {
return a.value - b.value;
})
.ratio((height / width) * 0.5 * (1 + Math.sqrt(5)))
.round(false);
var svg = d3
.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.bottom + margin.top)
.style("margin-left", -margin.left + "px")
.style("margin.right", -margin.right + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.style("shape-rendering", "crispEdges");
// .on("mousemove", function (d) {
// tool.style("left", d3.event.pageX + 10 + "px")
// tool.style("top", d3.event.pageY - 20 + "px")
// tool.style("display", "inline-block");
// tool.html(d.children ? null : d.name + "<br>" );
// }).on("mouseout", function (d) {
// tool.style("display", "none");
// });
var grandparent = svg.append("g").attr("class", "grandparent");
grandparent
.append("rect")
.attr("y", -margin.top)
.attr("width", width)
.attr("height", margin.top);
grandparent
.append("text")
.attr("x", 6)
.attr("y", 6 - margin.top)
.attr("dy", ".35em");
function dataMap(root) {
initialize(root);
accumulate(root);
accumulateCount(root);
layout(root);
display(root);
function initialize(root) {
root.x = root.y = 0;
root.dx = width;
root.dy = height;
root.depth = 0;
}
// Aggregate the values for internal nodes. This is normally done by the
// treemap layout, but not here because of our custom implementation.
// We also take a snapshot of the original children (_children) to avoid
// the children being overwritten when when layout is computed.
function accumulate(d) {
return (d._children = d.children)
? (d.value = d.children.reduce(function(p, v) {
return p + accumulate(v);
}, 0))
: d.value;
}
function accumulateCount(d) {
return (d._children = d.children)
? (d.count = d.children.reduce(function(p, v) {
return p + accumulateCount(v);
}, 0))
: d.count;
}
function layout(d) {
if (d._children) {
treemap.nodes({ _children: d._children });
d._children.forEach(function(c) {
c.x = d.x + c.x * d.dx;
c.y = d.y + c.y * d.dy;
c.dx *= d.dx;
c.dy *= d.dy;
c.parent = d;
layout(c);
});
}
}
function display(d) {
// console.log(d);
grandparent
.datum(d.parent)
.on("click", transition)
.select("text")
.text(name(d));
var g1 = svg
.insert("g", ".grandparent")
.datum(d)
.attr("class", "depth");
var g = g1
.selectAll("g")
.data(d._children)
.enter()
.append("g");
g.filter(function(d) {
return d._children;
})
.classed("children", true)
.on("click", transition);
g.selectAll(".child")
.data(function(d) {
return d._children || [d];
})
.enter()
.append("rect")
.attr("class", "child")
.call(rect);
g.append("rect")
.attr("class", "parent")
.call(rect)
.on("click", function(d) {
if (!d._children) {
window.open(d.url);
}
})
.append("title")
.text(function(d) {
return `${d.name} (${d.count})`;
});
g.append("text")
.attr("dx", "1rem")
.attr("dy", "2rem")
.text(function(d) {
return `${d.name}`;
})
.call(text);
function transition(d) {
self.props.onClickSegment(d.metricsValue);
if (transitioning || !d) return;
transitioning = true;
var g2 = display(d),
t1 = g1.transition().duration(750),
t2 = g2.transition().duration(750);
// Update the domain only after entering new elements.
x.domain([d.x, d.x + d.dx]);
y.domain([d.y, d.y + d.dy]);
// Enable anti-aliasing during the transition.
svg.style("shape-rendering", null);
// Draw child nodes on top of parent nodes.
svg.selectAll(".depth").sort(function(a, b) {
return a.depth - b.depth;
});
// Fade-in entering text.
g2.selectAll("text").style("fill-opacity", 0);
// Transition to the new view.
t1.selectAll("text")
.call(text)
.style("fill-opacity", 0);
t2.selectAll("text")
.call(text)
.style("fill-opacity", 1);
t1.selectAll("rect").call(rect);
t2.selectAll("rect").call(rect);
// Remove the old node when the transition is finished.
t1.remove().each("end", function() {
svg.style("shape-rendering", "crispEdges");
transitioning = false;
});
}
return g;
}
function text(text) {
text
.attr("x", function(d) {
return x(d.x) + 6;
})
.attr("y", function(d) {
return y(d.y) + 6;
});
}
function rect(rect) {
rect
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y);
})
.attr("width", function(d) {
return x(d.x + d.dx) - x(d.x);
})
.attr("height", function(d) {
return y(d.y + d.dy) - y(d.y);
});
}
function name(d) {
return d.parent ? name(d.parent) + " / " + d.name : d.name;
}
}
dataMap(dataObj);
}
handleClick = d => {
// this.props.onClickSegment(d.metricsValue);
console.log("The text", d.metricsValue);
};
render() {
return <p id="chart" />;
}
}
I need to click the last child and on clicking the last child should fill the layout with the respective breadcrumb like in the code.

D3 Legends Are not visible at bottom

I'm trying to push Legends at bottom of svg chart. but when I try to manipulate x and y position of legends complete graph is not appearing. D3 Js is giving an undefined error. Please find the code inline. Please explain to me how to put legends at the bottom of the chart. Thanks in advance.
var colorRange = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099",
"#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499", "#22aa99",
"#aaaa11", "#6633cc", "#e67300", "#8b0707", "#651067", "#329262", "#5574a6",
"#3b3eac"];
var data = [{"name" : "PQR", "percent" : "33.33"},..}]
// the D3 bits...
var color = d3.scale.category10();
var width = 300;
var height = 700;
var pie = d3.layout.pie().value(function(d) {
return d.percent
}).sort(null).padAngle(.03);
var arc = d3.svg.arc()
.outerRadius(width / 2 * 0.9)
.innerRadius(width / 2 * 0.5);
var svg = d3.select(element[0]).append('svg')
.attr({
width: width,
height: height
})
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
var path = svg.selectAll('path').data(pie(data)) // our data
.enter().append('path')
.style('stroke', 'white')
.attr('d', arc)
.attr('fill', function(d, i) {
return color(d.data.name)
});
path.transition()
.duration(1000)
.attrTween('d', function(d) {
var interpolate = d3.interpolate({
startAngle: 0,
endAngle: 0
}, d);
return function(t) {
return arc(interpolate(t));
};
});
var restOfTheData = function() {
var text = svg.selectAll('text')
.data(pie(data))
.enter()
.append("text")
.transition()
.duration(200)
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".4em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.data.percent + "%";
})
.style({
fill: '#fff',
'font-size': '12px'
});
var legendRectSize = 20;
var legendSpacing = 20;
var legend = d3.select('svg')
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
var height = legendRectSize;
var x = 0;
var y = i * height;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
}
setTimeout(restOfTheData, 1000);

D3 Bubble Chart - How to make width 100 % for svg element or all bubble cover whole width but height remain same

The bubble is taking specific width , I want it will take whole container width and spread in whole container but height reamin same
Here is my Angular2 Component code
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { bubbleData } from '../../shared/Mapstyles';
declare var d3: any;
#Component({
selector: 'app-bubble-graph',
templateUrl: './bubble-graph.component.html',
styleUrls: ['./bubble-graph.component.css'],
encapsulation: ViewEncapsulation.None
})
export class BubbleGraphComponent implements OnInit {
margin = 20;
diameter = 400;
color = d3.scale.linear()
.domain([-1, 5])
.range(['hsl(152,80%,80%)', 'hsl(228,30%,40%)'])
.interpolate(d3.interpolateHcl);
pack: any;
svg: any;
ngOnInit() {
this.initSvg();
this.drawSVG(bubbleData);
}
private initSvg() {
this.pack = d3.layout.pack()
.padding(150)
.size([this.diameter - this.margin, this.diameter - this.margin])
.value(function (d) { return d.size; });
this.svg = d3.select('svg').append('g')
.attr('transform', 'translate(' + this.diameter / 1.5 + ',' + this.diameter / 3 + ')');
}
private drawSVG(root) {
this.pack.nodes(root);
let view;
let tooltip = d3.select('body')
.append('div')
.style('position', 'absolute')
.style('z-index', '10')
.style('visibility', 'hidden');
let circle = this.svg.selectAll('circle')
.data(root.children)
.enter().append('circle')
.attr('class', 'node')
.style('fill', 'rgba(124, 230, 124, 0.5)')
.style('stroke', 'green')
.on('mouseover', (d) => { showToolTip.call(this, d), d3.event.stopPropagation(); })
.on('mousemove',
function () { return tooltip.style('top', (d3.event.pageY - 10) + 'px').style('left', (d3.event.pageX + 10) + 'px'); })
.on('mouseout', function () { return tooltip.style('visibility', 'hidden'); });
this.svg.selectAll('text')
.data(root.children)
.enter().append('text')
.attr('class', 'label')
.style('fill-opacity', function (d) { return d.parent === root ? 1 : 0; })
.style('display', function (d) { return d.parent === root ? 'inline' : 'none'; })
.text(function (d) { return d.name; })
.on('mouseover', (d) => { showToolTip.call(this, d), d3.event.stopPropagation(); })
.on('mousemove',
function () { return tooltip.style('top', (d3.event.pageY - 10) + 'px').style('left', (d3.event.pageX + 10) + 'px'); })
.on('mouseout', function () { return tooltip.style('visibility', 'hidden'); });
let node = this.svg.selectAll('circle,text');
showCircle.call(this, [root.x, root.y, root.r * 2 + this.margin]);
function showToolTip(d) {
tooltip.html("<div class='result_tooltip'><span class='result_name'>"
+ d.name + "</span><span class='result_num'>" + d.size + "</span></div>");
tooltip.style('visibility', 'visible');
}
function showCircle(v) {
const k = this.diameter / v[2]; view = v;
node.attr('transform', function (d) { return 'translate(' + (d.x - v[0]) * k + ',' + (d.y - v[1]) * k + ')'; });
circle.attr('r', function (d) { return d.r * k; });
}
}
}
My container width is 900px and same for SVG, But g element inside a SVG taking only 350 width.
If increased diameter height is also increase. I just want to increase size or all bubble spread in container.

SVG too small and excluding ticks and appended text d3.js

I have a bar chart and somehow the whole svg container is only rects and everything that falls in the area where the rects are, and so y-axis ticks are left outside of the container. How can I fix that so that the text at the top and y-axis ticks which are images are not left outside.
my code,
var barsData = [{
name: "walnuts",
value: 332
}, {
name: "apples",
value: 206
}]
// mapBars start here
/* Set chart dimensions */
var widthBar = 960,
heightBar = 250,
marginBar = {top:10, right:10, bottom:20, left:60};
//subtract margins
widthBar = widthBar - marginBar.left - marginBar.right;
heightBar = heightBar - marginBar.top - marginBar.bottom;
//sort data from highest to lowest
barsData = barsData.sort(function(a, b){ return b.value - a.value; });
//Sets the y scale from 0 to the maximum data element
var y = d3.scale.ordinal()
.domain(barsData.map(function(d){ return d.name}))
.rangeRoundBands([0, heightBar], .1);
var x = d3.scale.linear()
.range([0, widthBar])
.domain([0, d3.max(barsData, function(d){return d.value})])
var yAxis = d3.svg.axis()
.scale(y)
.orient('left')
var barsSvg = d3.select("#chart")
.append("svg")
.attr("class", "barChart")
.attr("width", "100%")
.attr('preserveAspectRatio', 'xMidYMin')
.attr("viewBox", '0 0 ' + parseInt(widthBar + marginBar.left + marginBar.right) + ' ' + parseInt(heightBar + marginBar.top + marginBar.bottom));
var bar = barsSvg.selectAll(".bar")
.data(barsData)
.enter()
.append("rect")
.attr("id", function(d, i) {return "bar" + d.name;})
.attr('class', 'mapBars')
.attr("x", 0)
.attr("y", function(d){ return y(d.name)})
.attr("width", function(d) {return x(d.value)})
.attr("height", y.rangeBand())
.attr("fill", function(d, i){
if(d.name == 'walnuts') {return '#006600'} else {return '#2980b9'}
});
var labelsBar = barsSvg.selectAll('text')
.data(barsData)
.enter()
.append('text')
.text(function(d){return d.value})
.attr('x', marginBar.top)
.attr('y', function(d, i) {return 90*i + 80;})
.attr("font-size", "38px")
.attr("fill", "#fff")
.style("font-weight", "bold");;
var y_xis = barsSvg.call(yAxis);
var lineEnd = 270;
var line = barsSvg.append("line")
.attr('class', 'endLine')
.attr("x1", function(){ return x(lineEnd)})
.attr("x2", function(){ return x(lineEnd)})
.attr("y1", 0)
.attr("y2", heightBar)
.attr("stroke-width", 6)
.attr("stroke", "red")
.attr("stroke-dasharray", "8,8")
var myText = barsSvg.append("text")
.attr("x", function(){ return x(lineEnd - 107)})
.attr("class", "myLabel")//easy to style with CSS
.attr("y", 9)//magical number here
.text("Winner crosses this line")
.attr('fill', 'red')
.attr('font-size', '25px');
barsSvg.selectAll(".tick text").remove()
barsSvg.selectAll(".tick")
.each( function(d) {
var p = d3.select(this);
p.append("svg:image")
.attr("x", -120)
.attr("y", -40)
.attr("dy", widthBar)
.attr("width", 100)
.attr("height", 100)
.attr("xlink:href",
function(d){
if(d == 'walnuts') { return 'http://nutritionfacts.org/wp-content/uploads/2015/08/NF-Aug11-Walnuts-and-Artery-Function.jpg'}
else if (d == 'apples') { return 'http://nutritionfacts.org/wp-content/uploads/2015/08/NF-Aug11-Walnuts-and-Artery-Function.jpg'}
});
})
see plunker
You should edit the svg viewBox
.attr("viewBox", '0 0 ' + parseInt(widthBar + marginBar.left + marginBar.right) + ' ' + parseInt(heightBar + marginBar.top + marginBar.bottom));
to show elements below 0 in x or y
.attr("viewBox", '-120 -40 ' + parseInt(widthBar + marginBar.left + marginBar.right) + ' ' + parseInt(heightBar + marginBar.top + marginBar.bottom));
I chose -120 and -40 based on the relative position of your images, although I might have missed something: feel free to adjust if it's too large/too small.

Categories