3

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
},
2
  • Can you provide a sample Data.json? Commented May 4, 2017 at 9:00
  • Don't remove the elements in the SVG just to paint them again every time you select an option. I call this a lazy update. Besides that, you'll have to do a major refactor in your code: put the d3.json outside Changement, not the other way around (you don't need to load/parse the data every time you choose an option), and move most of the code outside Changement, leaving there only the small parts of the code that change the scales and the bars. Commented May 4, 2017 at 9:03

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Okay, I will try to improve that with your tips. I'm new to this, I've just learned that 3 weeks ago, so I really need to improve myself! Thanks you for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.