Reputation: 71
I'm trying to run an application for data visualization, I'm using D3.js, my code works but when I change the selected option, the graph change but go down and it goes down every change. I have no idea where the problem is.
That's my code :
<!DOCTYPE html>
<html>
<head>
<title> Graphique </title>
<script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
</head>
<body>
<FORM>
<SELECT id="Nb" size="1" onchange="Changement()">
<option>Selection</option>
<option>NbCopie</option>
<option>NbTache</option>
<option>NbCopieBW</option>
<option>NbCopieCouleur</option>
<option>MtTotal</option>
</SELECT>
</FORM>
<div id="chart"></div>
<svg width="960" height="500"></svg>
<script>
function Changement() {
d3.selectAll("svg > *").remove();
d3.json("Data.json", function(error, data) {
var Nb = data.map(function(d) {
var x = document.getElementById('Nb');
var i = x.selectedIndex;
var text = x.options[i].text;
if (text == "NbCopie")
return d.NbCopie;
else if (text == "NbTache")
return d.NbTache;
else if (text == "NbCopieBW")
return d.NbCopieBW;
else if (text == " NbCopieCouleur")
return d.NbCopieCouleur;
else if (text == "MtTotal")
return d.MtTotal;
});
var maxNb = d3.max(Nb);
var svg = d3.select("svg"),
margin = {
top: 30,
right: 30,
bottom: 40,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var animateDuration = 700;
var animateDelay = 30;
var tooltip = d3.select('body').append('div')
.style('position', 'absolute')
.style('background', '#f4f4f4')
.style('padding', '5 15px')
.style('border', '1px #333 solid')
.style('border-raduis', '5px')
.style('opacity', '0')
var yScale = d3.scaleLinear()
.domain([0, maxNb])
.range([0, height])
var xScale = d3.scaleBand()
.domain(d3.range(0, Nb.length))
.range([0, width])
var colors = d3.scaleLinear()
.domain([0, Nb.length])
.range(['#0080FF', '#FF3333'])
var myChart = d3.select('#chart').append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.style('background', '#f4f4f4')
.selectAll('rect')
.data(Nb)
.enter().append('rect')
.style('fill', function(d, i) {
return colors(i);
})
.attr('width', xScale.bandwidth())
.attr('x', function(d, i) {
return xScale(i)
})
.attr('height', 0)
.attr('y', height)
.on('mouseover', function(d) {
tooltip.transition()
.style('opacity', 1)
tooltip.html(d)
.style('left', (d3.event.pageX) + 'px')
.style('top', (d3.event.pageY + 'px'))
d3.select(this).style('opacity', 0.5)
})
.on('mouseout', function(d) {
tooltip.transition()
.style('opacity', 0)
d3.select(this).style('opacity', 1)
})
myChart.transition()
.attr('height', function(d) {
return yScale(d);
})
.attr('y', function(d) {
return height - yScale(d);
})
.duration(animateDuration)
.delay(function(d, i) {
return i * animateDelay
})
.duration(1000)
.ease(d3.easeElastic)
var vScale = d3.scaleLinear()
.domain([0, maxNb])
.range([height, 0])
var vAxis = d3.axisLeft()
.scale(vScale)
.ticks(5)
.tickPadding(5)
var vGuide = d3.select('svg')
.append('g')
vAxis(vGuide)
vGuide.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
vGuide.selectAll('path')
.style('fill', 'none')
.style('stroke', '#000')
vGuide.selectAll('line')
.style('stroke', '#000')
var hScale = d3.scaleTime()
.domain(d3.extent(data, function(d) {
var parseDate = d3.timeParse("%Y%m%d");
Date_Id = parseDate(d.Date_Id);
return Date_Id;
}))
.range([0, width - 150])
var hAxis = d3.axisBottom()
.scale(hScale)
.ticks(d3.timeMonth)
var hGuide = d3.select('svg')
.append('g')
.attr("class", "axis axis--x")
.attr("transform", "translate(" + margin.left + "," + (height + margin.top) + ")")
.call(hAxis);
});
};
</script>
And here a screenshot of my problem:
first attempt enter image description here
second attempt enter image description here
and here is an extract of my JSON file
[{
"ConsoPhot_Id": "10148",
"idLotImport": 390,
"Date_Id": 20170201,
"Orga_Id": "203938",
"NbTache": 153,
"NbCopie": 798,
"NbCopieBW": 488,
"NbCopieCouleur": 310,
"MtTotal": 13.69
},
{
"ConsoPhot_Id": "10602",
"idLotImport": 391,
"Date_Id": 20161201,
"Orga_Id": "203938",
"NbTache": 153,
"NbCopie": 909,
"NbCopieBW": 779,
"NbCopieCouleur": 130,
"MtTotal": 7.93
},
{
"ConsoPhot_Id": "10905",
"idLotImport": 392,
"Date_Id": 20161101,
"Orga_Id": "203938",
"NbTache": 115,
"NbCopie": 515,
"NbCopieBW": 409,
"NbCopieCouleur": 106,
"MtTotal": 5.6
},
Upvotes: 3
Views: 492
Reputation: 102174
Don't append a new SVG every time you choose an option.
Thus, instead of:
var myChart = d3.select('#chart').append('svg')
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.append('g')
//etc...
Simply do:
var myChart = svg.append('g')
//etc...
Here is a plunker with that change only, using the small JSON sample you provided: https://plnkr.co/edit/PMnNI4hoBz3Q2k5fQTp5?p=preview
PS: As I said in my comment, this code right now has a lot of problems, the main one being the fact that you're erasing everything inside the SVG just to paint it again, and the second one the fact that you are loading the same JSON every time you choose an option. That being said, you should reconsider a major refactor in this code. Have in mind that here I'm only answering the problem stated in your question.
Upvotes: 1