简体   繁体   中英

D3 Updating a data array

I was wondering if you could help me with the general update pattern in D3...

I'm trying to display a very basic data array as a bar chart, with an input form to add new data to the array and dynamically update on the chart.

There's lots of repetition because I'm trying to refactor the process of adding a new rectangle to the svg, but not having any luck...

If anyone could explain to me how I could get a new object into the data array and then refresh the svg that would be brilliant. I hope this question falls within moderator guidelines too...

Here's my code so far:

app.js:

// set a width and height for the svg

var height = 500;
var width = 1000;
var barPadding = 10;
var barWidth = width / data.length - barPadding;

var maxPoints = d3.max(data, function(d){
    return d.score;
});

var myScale = d3.scaleLinear()
    .domain([0, maxPoints])
    .range([height, 0]);


var svg = d3.select('svg')
    .attr("height", height) //setting the height 
    .attr("width", width) // setting the width
    .style("display", "block") // svgs are inline, hence needs to be block
    .style("margin", "100px auto") // centering
    .selectAll("rect") // creating nodes 
    .data(data) // binds data to the nodes
    .enter() // goes into the enter selection
    .append("rect") 
        .attr("width", barWidth) 
        .attr("height", function(d){
            return height - myScale(d.score);
        })
        .attr("x", function(d, i){
            return (barWidth + barPadding) * i;
        })
        .attr("y", function(d, i){
            return myScale(d.score);
        })

        .attr("fill", "green");

// INPUT NEW DATA

var nameInput = "input[name='name']";
var scoreInput = "input[name='score']";

function addRect(){
    barWidth = width / data.length - barPadding;
    svg
    .append("rect") 
        .attr("height", function(d){
            return height - myScale(d.score);
        })

        .attr("x", function(d, i){
            return (barWidth + barPadding) * i;
        })

        .attr("y", function(d, i){
            return myScale(d.score);
        })

        .attr("fill", "green");
};


d3.select("form")
    .on("submit", function() {
        d3.event.preventDefault();
        var firstInput = d3.select(nameInput)
            .property("value");
        var secondInput = d3.select(scoreInput)
            .property("value");
        data.push({player: firstInput, score: secondInput });
        console.log(data);

        svg
            .data(data)
            .enter();
            addRect();
    });

html:

 <body>
    <div class="display">
        <svg 
        version="1.1"
        baseProfile="full"
        xmlns="http://www.w3.org/2000/svg"
        id="letters">
    </svg>
</div>
<div class="form">
    <form action="">
        <input type="text" placeholder="Name" name="name">
        <input type="text" placeholder="Score" name="score">
        <input type="submit">
    </form>
</div>


<script src="https://d3js.org/d3.v4.js"></script>
<script src="data.js"></script>
<script src="app.js"></script>
</body>

data.js:

var data = [
    {player: "Raph", score: 12},
    {player: "Henry", score: 43},
    {player: "James", score: 29},
    {player: "Andrew", score: 200},
    {player: "Ella", score: 87},
    {player: "Bob", score: 3},
    {player: "Lil", score: 19},
    {player: "Jenny", score: 223},
    {player: "Dad", score: 33},
    {player: "Rhys", score: 45}

];

Many thanks for any help in advance,

Raph

You will have to update attributes of existing rectangles also while adding a new rect.

Try as shown below -

 var data = [ {player: "Raph", score: 12}, {player: "Henry", score: 43}, {player: "James", score: 29}, {player: "Andrew", score: 200}, {player: "Ella", score: 87}, {player: "Bob", score: 3}, {player: "Lil", score: 19}, {player: "Jenny", score: 223}, {player: "Dad", score: 33}, {player: "Rhys", score: 45} ]; // set a width and height for the svg var height = 200; var width = 400; var barPadding = 10; var barWidth = width / data.length - barPadding; var maxPoints = d3.max(data, function(d) { return d.score; }); var myScale = d3.scaleLinear() .domain([0, maxPoints]) .range([height, 0]); var svg = d3.select("svg") .attr("height", height) .attr("width", width) .style("display", "block") .style("margin", "10px 0px"); //changed for look and feel //.style("margin", "100px auto"); drawRect(); //Creating rects //Moved the code to create rectangles and style into a function. function drawRect() { var rect = svg .selectAll("rect") .data(data) .enter() .append("rect"); svg .selectAll("rect") .attr("width", barWidth) .attr("height", function(d) { return height - myScale(d.score); }) .attr("x", function(d, i) { return (barWidth + barPadding) * i; }) .attr("y", function(d, i) { return myScale(d.score); }) .attr("fill", "green"); } // INPUT NEW DATA var nameInput = "input[name='name']"; var scoreInput = "input[name='score']"; d3.select("form") .on("submit", function() { d3.event.preventDefault(); var firstInput = d3.select(nameInput) .property("value"); var secondInput = d3.select(scoreInput) .property("value"); data.push({ player: firstInput, score: secondInput }); barWidth = width / data.length - barPadding; drawRect(); //Adding new rects and update others }); 
 <script src="https://d3js.org/d3.v4.js"></script> <body> <div class="display"> <svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" id="letters"> </svg> </div> <div class="form"> <form action=""> <input type="text" placeholder="Name" name="name"> <input type="text" placeholder="Score" name="score"> <input type="submit"> </form> </div> </body> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM