Sunday 20 March 2022

Web Tutorial: The Highcharts Line Chart

Welcome to TeochewThunder's next web tutorial!

We covered the creation of a Highchart's column chart last year, and today we will dive right into creating a line chart. This is going to be a piece of cake, because all we really need to do is make a few adjustments.

If you need the previous code, you can get it here. This is important, because in true lazy programmer fashion, we will just be modifying the code to get what we want. No point repeating ourselves here, right?

Editor's Note: The screenshots provided for the title are inaccurate due to an error in the code, retroactively detected.

One of the first things we should change is the title.
<title>Line Chart</title>


We will then follow up with a name change to the function.
function renderLineChart()


... and the call in the HTML.
<div id="dashboard">
    <label for="ddlSeason">
        SEASON
        <select id="ddlSeason" onchange="renderLineChart()">

        </select>
    </label>

    <label for="ddlStat">
        STATISTICS
        <select id="ddlStat" onchange="renderLineChart()">
            <option value="appearances" selected>Appearances</option>
            <option value="goals">Goals</option>
        </select>
    </label>
</div>


... and in the JavaScript. Comment it out for now, as well.
//renderLineChart();    


And now for a major change. Line charts are most useful when they show statistics over a time period. So for this, we will change the drop-down list to make players selectable instead of seasons. The intended effect is that we can view statistics from player to player, and the line will display the statistics over different seasons.
<label for="ddlPlayer">
    PLAYER
    <select id="ddlPlayer" onchange="renderLineChart()">

    </select>
</label>


So we can get a list of the players from the data with this. The variable players is declared as an empty array.
var ddlPlayer = document.getElementById("ddlPlayer");
var keys = Object.keys(data);
var players = [];

for(let i = 0; i < keys.length; i++)
{
    var option = document.createElement("option");
    option.value = keys[i];
    option.innerHTML = keys[i];
    ddlSeason.appendChild(option);
}


We use a For loop to go through the data. This has not changed. What has changed is that we populate players with each element from the categories property of the current data object. And create an option to populate the drop-down list. Also, remember to rename the drop-down list!
var ddlPlayer = document.getElementById("ddlPlayer");
var keys = Object.keys(data);
var players = [];

for(let i = 0; i < keys.length; i++)
{
    for(let j = 0; j < data[keys[i]]["categories"].length; j++)
    {

        var option = document.createElement("option");
        option.value = data[keys[i]]["categories"][j];
        option.innerHTML = data[keys[i]]["categories"][j];
        ddlPlayer.appendChild(option);    
    }
}

//renderLineChart();


To avoid duplication, we use a conditional block to check if the current player name is already in the players array before the operation. And if not, in addition to the operation, we push the value into the players array.
var ddlPlayer = document.getElementById("ddlPlayer");
var keys = Object.keys(data);
var players = [];

for(let i = 0; i < keys.length; i++)
{
    for(let j = 0; j < data[keys[i]]["categories"].length; j++)
    {
        if (players.indexOf(data[keys[i]]["categories"][j]) == -1)
        {
            players.push(data[keys[i]]["categories"][j]);


            var option = document.createElement("option");
            option.value = data[keys[i]]["categories"][j];
            option.innerHTML = data[keys[i]]["categories"][j];
            ddlPlayer.appendChild(option);    
        }
    }
}

//renderLineChart();


Here we go, that's a good start!



The data

We won't change the data... but we will massage it into a form that the line chart will read properly. First, declare reasons and values as arrays. Also declare keys the same way we did previously.
function renderLineChart()
{
    var player = document.getElementById("ddlPlayer").value;
    var stat = document.getElementById("ddlStat").value;

    var arrAverage = [];
    var total = 0;

    var keys = Object.keys(data);
    var seasons = [];
    var values = [];


    for(let i = 0; i < data[season][stat].length; i++)
    {
        total += data[season][stat][i];
    }

    for(let i = 0; i < data[season][stat].length; i++)
    {
        arrAverage.push(parseFloat((total / data[season][stat].length).toFixed(2)));
    }


Iterate through keys, which is a list of seasons. declare playerIndex. We will use it to store the index position of player within the categories array of the current object. Then check if player actually exists within that array by making sure playerIndex is not -1.
var player = document.getElementById("ddlPlayer").value;
var stat = document.getElementById("ddlStat").value;

var arrAverage = [];
var total = 0;

var keys = Object.keys(data);
var seasons = [];
var values = [];

for(let i = 0; i < keys.length; i++)
{
    var playerIndex = data[keys[i]]["categories"].indexOf(player);
    if (playerIndex != -1)
    {

    }
}

for(let i = 0; i < data[season][stat].length; i++)
{
    total += data[season][stat][i];
}

for(let i = 0; i < data[season][stat].length; i++)
{
    arrAverage.push(parseFloat((total / data[season][stat].length).toFixed(2)));
}


If so, push the season into seasons. And push the value (determined by stat) into values.
var player = document.getElementById("ddlPlayer").value;
var stat = document.getElementById("ddlStat").value;

var arrAverage = [];
var total = 0;

var keys = Object.keys(data);
var seasons = [];
var values = [];

for(let i = 0; i < keys.length; i++)
{
    var playerIndex = data[keys[i]]["categories"].indexOf(player);
    if (playerIndex != -1)
    {
        seasons.push(keys[i]);
        values.push(data[keys[i]][stat][playerIndex]);

    }
}

for(let i = 0; i < data[season][stat].length; i++)
{
    total += data[season][stat][i];
}

for(let i = 0; i < data[season][stat].length; i++)
{
    arrAverage.push(parseFloat((total / data[season][stat].length).toFixed(2)));
}


Then we iterate through values twice using For loops, and derive total and average values using the elements of values instead.
var player = document.getElementById("ddlPlayer").value;
var stat = document.getElementById("ddlStat").value;

var arrAverage = [];
var total = 0;

var keys = Object.keys(data);
var seasons = [];
var values = [];

for(let i = 0; i < keys.length; i++)
{
    var playerIndex = data[keys[i]]["categories"].indexOf(player);
    if (playerIndex != -1)
    {
        seasons.push(keys[i]);
        values.push(data[keys[i]][stat][playerIndex]);
    }
}

for(let i = 0; i < values.length; i++)
{
    total += values[i];
}

for(let i = 0; i < values.length; i++)
{
    arrAverage.push(parseFloat((total / values.length).toFixed(2)));
}


Using the data

First, remove the type property.
const chart = Highcharts.chart("container", {
    chart:
    {
        /* type: "column",*/
        borderColor: "rgba(200, 0, 0, 1)",
        borderRadius: 10,
        borderWidth: 2,
    },


The xAxis property's categories property will be the seasons array.
xAxis:
{
    categories: seasons
},


Make these following changes. The name is self-explanatory. This series is used to display the average of the current player's requested statistics over the course of all the seasons he played for.
series:
[                        
    {
        name: "Average " + stat + " for " + player,
        type: "spline",
        data: arrAverage,
        lineColor: "rgba(255, 200, 0, 1)",
        lineWidth: 3,
        dashStyle: "Dot",
        marker:
        {
            fillColor: "rgba(255, 200, 0, 1)"
        }
    }
]


You'll see the yellow line. It's a straight line, and it will change when you change the player or the statistic. Note that the scale will change as well!



Add an object to the series array. It will be a solid red line, and the data will use the values array.
series:
[                        
    {
        name: "Average " + stat + " for " + player,
        type: "spline",
        data: arrAverage,
        lineColor: "rgba(255, 200, 0, 1)",
        lineWidth: 3,
        dashStyle: "Dot",
        marker:
        {
            fillColor: "rgba(255, 200, 0, 1)"
        }
    },                        
    {
        name: player + " " + stat,
        type: "spline",
        data: values,
        lineColor: "rgba(200, 0, 0, 1)",
        lineWidth: 5,
        dashStyle: "Solid",
        marker:
        {
            fillColor: "rgba(200, 0, 0, 1)"
        }
    }

]


Yep, and there it is! Now that you have a variance of values, the scale has more numbers.



Final notes

Highcharts is really easy to use once you get the hang of it. It took only a tiny bit of effort to covert from a column chart to a line chart.

Time to draw a line in the sand chart,
T___T

No comments:

Post a Comment