Jericho
Jericho

Reputation: 81

Update chart and text with button (D3.js)

I want to make 3 chart that can be updated (display one by one) when user click the button. Like this: chart-example

But also I want to DOM a text (h3 element) below the chart. Here's my code: HTML:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button onclick="update(pageViews)">Page Views</button>
    <button onclick="update(users)">Reader</button>
    <button onclick="update(BounceRate)">Bounce Rate</button>

    <div id="myChart"></div>
    <h3>
        Total of Page View on March is xxxx.
    </h3>
    <script src="https://d3js.org/d3.v4.js"></script>
    <script src="stackOverflow.js" charset="utf-8"></script>
</body>

</html>

JS (Pure w/o Jquery):

var pageViews = [
    { ser1: 1, ser2: 3625 },
    { ser1: 2, ser2: 2698 },
    { ser1: 3, ser2: 2441 },
    { ser1: 4, ser2: 2399 },
    { ser1: 5, ser2: 2342 },
    { ser1: 6, ser2: 2279 },
    { ser1: 7, ser2: 2087 },
    { ser1: 8, ser2: 2070 },
    { ser1: 9, ser2: 2490 },
    { ser1: 10, ser2: 2535 },
    { ser1: 11, ser2: 3468 },
    { ser1: 12, ser2: 2526 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

var users = [
    { ser1: 1, ser2: 1332 },
    { ser1: 2, ser2: 956 },
    { ser1: 3, ser2: 909 },
    { ser1: 4, ser2: 924 },
    { ser1: 5, ser2: 864 },
    { ser1: 6, ser2: 799 },
    { ser1: 7, ser2: 824 },
    { ser1: 8, ser2: 812 },
    { ser1: 9, ser2: 881 },
    { ser1: 10, ser2: 926 },
    { ser1: 11, ser2: 1330 },
    { ser1: 12, ser2: 964 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

var BounceRate = [
    { ser1: 1, ser2: 5.68 },
    { ser1: 2, ser2: 4.49 },
    { ser1: 3, ser2: 5.29 },
    { ser1: 4, ser2: 5.74 },
    { ser1: 5, ser2: 6.14 },
    { ser1: 6, ser2: 3.95 },
    { ser1: 7, ser2: 6.03 },
    { ser1: 8, ser2: 5.08 },
    { ser1: 9, ser2: 5.1 },
    { ser1: 10, ser2: 4.78 },
    { ser1: 11, ser2: 3.84 },
    { ser1: 12, ser2: 5.75 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 20, left: 50 },
    width = 650 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3
    .select("#myChart")
    .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 + ")");

// Initialise a X axis:
var x = d3.scaleLinear().range([0, width]);
var xAxis = d3.axisBottom().scale(x);
svg
    .append("g")
    .attr("transform", "translate(0," + height + ")")
    .attr("class", "myXaxis");

// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g").attr("class", "myYaxis");

// Create a function that takes a dataset as input and update the plot:
function update(data) {
    // Create the X axis:
    x.domain([
        0,
        d3.max(data, function (d) {
            return d.ser1;
        })
    ]);
    svg
        .selectAll(".myXaxis")
        .transition()
        .duration(2500)
        .call(xAxis);

    // create the Y axis
    y.domain([
        0,
        d3.max(data, function (d) {
            return d.ser2;
        })
    ]);
    svg
        .selectAll(".myYaxis")
        .transition()
        .duration(2500)
        .call(yAxis);

    // Create a update selection: bind to the new data
    var u = svg.selectAll(".lineTest").data([data], function (d) {
        return d.ser1;
    });

    // Update the line
    u.enter()
        .append("path")
        .attr("class", "lineTest")
        .merge(u)
        .transition()
        .duration(2500)
        .attr(
            "d",
            d3
                .line()
                .x(function (d) {
                    return x(d.ser1);
                })
                .y(function (d) {
                    return y(d.ser2);
                })
        )
        .attr("fill", "none")
        .attr("stroke", "#ef504d")
        .attr("stroke-width", 5);

    // update tulisan bawah
}
/// update Jumlah Tayangan dulu (onload)
var tulisanBawah = document.getElementsByTagName("h3")[0];
if (update(pageViews)) {
    tulisanBawah.innerHTML = "Total page views of march";
    console.log("pageviews");
} else if (update(users)) {
    tulisanBawah.innerHTML = "Total users of march";
    console.log("users");
}

The chart running good, but the text won't change. Anyone can help? I think I make some mistake in the if statement but I still can't figure it out. Here's my JSFiddle: https://jsfiddle.net/tw0jbd81/1/

Upvotes: 0

Views: 849

Answers (1)

Gevorg Harutyunyan
Gevorg Harutyunyan

Reputation: 56

So you're passing the dataset as the argument to the update function on the button click from the global variable.

Also this part is useless

if (update(pageViews)) {
    tulisanBawah.innerHTML = "Total page views of march";
    console.log("pageviews");
} else if (update(users)) {
    tulisanBawah.innerHTML = "Total users of march";
    console.log("users");
}

Because what is done, it calls the update(pageViews) in the first IF condition, which resolves to undefined (because the function doesn't return anything), then it calls the update(users) again, which again resolves to undefined so the conditions body aren't triggered.

I would have done this in a bit different way

  1. make the function parameter as a string data set name we want to use, so we can call it from the HTML vie update('pageViews')
  2. call the update method on the script footer
  3. Move the title update login inside the update function
  4. Attach button callbacks like Page Views
  5. In order to update the contents of the H3 element, use innerText, instead of innerHTML

So the final JS will look like this

var pageViews = [
    { ser1: 1, ser2: 3625 },
    { ser1: 2, ser2: 2698 },
    { ser1: 3, ser2: 2441 },
    { ser1: 4, ser2: 2399 },
    { ser1: 5, ser2: 2342 },
    { ser1: 6, ser2: 2279 },
    { ser1: 7, ser2: 2087 },
    { ser1: 8, ser2: 2070 },
    { ser1: 9, ser2: 2490 },
    { ser1: 10, ser2: 2535 },
    { ser1: 11, ser2: 3468 },
    { ser1: 12, ser2: 2526 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

var users = [
    { ser1: 1, ser2: 1332 },
    { ser1: 2, ser2: 956 },
    { ser1: 3, ser2: 909 },
    { ser1: 4, ser2: 924 },
    { ser1: 5, ser2: 864 },
    { ser1: 6, ser2: 799 },
    { ser1: 7, ser2: 824 },
    { ser1: 8, ser2: 812 },
    { ser1: 9, ser2: 881 },
    { ser1: 10, ser2: 926 },
    { ser1: 11, ser2: 1330 },
    { ser1: 12, ser2: 964 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

var BounceRate = [
    { ser1: 1, ser2: 5.68 },
    { ser1: 2, ser2: 4.49 },
    { ser1: 3, ser2: 5.29 },
    { ser1: 4, ser2: 5.74 },
    { ser1: 5, ser2: 6.14 },
    { ser1: 6, ser2: 3.95 },
    { ser1: 7, ser2: 6.03 },
    { ser1: 8, ser2: 5.08 },
    { ser1: 9, ser2: 5.1 },
    { ser1: 10, ser2: 4.78 },
    { ser1: 11, ser2: 3.84 },
    { ser1: 12, ser2: 5.75 },
    { ser1: 13, ser2: 0 },
    { ser1: 14, ser2: 0 },
    { ser1: 15, ser2: 0 },
    { ser1: 16, ser2: 0 },
    { ser1: 17, ser2: 0 },
    { ser1: 18, ser2: 0 },
    { ser1: 19, ser2: 0 },
    { ser1: 20, ser2: 0 },
    { ser1: 21, ser2: 0 },
    { ser1: 22, ser2: 0 },
    { ser1: 23, ser2: 0 },
    { ser1: 24, ser2: 0 },
    { ser1: 25, ser2: 0 },
    { ser1: 26, ser2: 0 },
    { ser1: 27, ser2: 0 },
    { ser1: 28, ser2: 0 },
    { ser1: 29, ser2: 0 },
    { ser1: 30, ser2: 0 },
    { ser1: 31, ser2: 0 }
];

// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 20, left: 50 },
    width = 650 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3
    .select("#myChart")
    .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 + ")");

// Initialise a X axis:
var x = d3.scaleLinear().range([0, width]);
var xAxis = d3.axisBottom().scale(x);
svg
    .append("g")
    .attr("transform", "translate(0," + height + ")")
    .attr("class", "myXaxis");

// Initialize an Y axis
var y = d3.scaleLinear().range([height, 0]);
var yAxis = d3.axisLeft().scale(y);
svg.append("g").attr("class", "myYaxis");


var title = document.querySelector("#title");

// Create a function that takes a dataset as input and update the plot:
function update(dataSetName) {
    if (dataSetName === "pageViews") {
        var data = pageViews
      title.innerText = "Page Views"
    }
    else if (dataSetName === "users") {
        var data = users
      title.innerText = "Users"
    }
    else if (dataSetName === "BounceRate") {
        var data = BounceRate
      title.innerText = "Bounce Rate"
    }

    // Create the X axis:
    x.domain([
        0,
        d3.max(data, function (d) {
            return d.ser1;
        })
    ]);
    svg
        .selectAll(".myXaxis")
        .transition()
        .duration(2500)
        .call(xAxis);

    // create the Y axis
    y.domain([
        0,
        d3.max(data, function (d) {
            return d.ser2;
        })
    ]);
    svg
        .selectAll(".myYaxis")
        .transition()
        .duration(2500)
        .call(yAxis);

    // Create a update selection: bind to the new data
    var u = svg.selectAll(".lineTest").data([data], function (d) {
        return d.ser1;
    });

    // Update the line
    u.enter()
        .append("path")
        .attr("class", "lineTest")
        .merge(u)
        .transition()
        .duration(2500)
        .attr(
            "d",
            d3
                .line()
                .x(function (d) {
                    return x(d.ser1);
                })
                .y(function (d) {
                    return y(d.ser2);
                })
        )
        .attr("fill", "none")
        .attr("stroke", "#ef504d")
        .attr("stroke-width", 5);

    // update tulisan bawah
}

update('pageViews')

See the JS fiddle here https://jsfiddle.net/modularcoder/tLv3pusb/21/

Upvotes: 3

Related Questions