Elijah Leis
Elijah Leis

Reputation: 415

Inserting title in line chart on d3.js

I have this line chart that works but the problem is that I'm trying to put a title on the line chart above it and it won't work because d3.js keeps appending it inside the the elements of the chart. How can I fix this? Below is the snippet of my code:

$(document).ready(() => {
    // set the dimensions and margins of the graph
    var margin = { top: 20, right: 20, bottom: 30, left: 50 },
        width = 1000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    // parse the date / time
    var parseTime = d3.timeParse("%H:%M:%S");


    // set the ranges
    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    // define the line
    var valueline = d3.line()
        .x(function (d) { return x(d.availability_time); })
        .y(function (d) { return y(d.total_hour_percentage); });

    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("#lineChart").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 + ")");

    function draw(data) {
        console.log(data[0].availability_time);

        // format the data
        data.forEach(function (d) {
            d.availability_time = (parseTime(d.availability_time));
            d.total_hour_percentage = d.total_hour_percentage;
        });

        // sort time ascending
        data.sort(function (a, b) {
            return a["availability_time"] - b["availability_time"];
        })

        // Scale the range of the data
        x.domain(d3.extent(data, function (d) {
            return d.availability_time;
        }));
        y.domain([0, d3.max(data, function (d) {
            return Math.max(d.total_hour_percentage);
        })]);

        // Add the valueline path.
        svg.append("path")
            .data([data])
            .attr("class", "line")
            .attr("d", valueline);
        // Add the X Axis
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x).ticks(d3.timeHour.every(1)).tickFormat(d3.timeFormat('%H:%M')));

        // Add the Y Axis
        svg.append("g")
            .call(d3.axisLeft(y));
    }

    svg.append('text')
        .attr('class', 'title')
        .attr('x', width / 2 + margin)
        .attr('y', 40)
        .attr('text-anchor', 'middle')
        .text('Availability (%) of CAM for date: ');
    // Get the data
    // var perHourResult = "/perHourAvailabilities/" + defaultDate;
    // console.log(perHourResult);

    var perHourResult =
        [
            { "id": 0, "availability_time": "00:00:00", "total_hour_percentage": 99.55 },
            { "id": 0, "availability_time": "01:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "02:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "03:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "04:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "05:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "06:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "07:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "08:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "09:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "10:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "11:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "12:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "13:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "14:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "15:00:00", "total_hour_percentage": 99.75 },
            { "id": 0, "availability_time": "16:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "17:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "18:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "19:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "20:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "21:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "22:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "23:00:00", "total_hour_percentage": 100.0 }
        ];

    console.log(perHourResult[0].availability_time); //shows 00:00:00

    draw(perHourResult);
});
<!DOCTYPE html>
<html lang="en">

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

    <!--Lib css-->
    <!--bootstrap-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <!--fontawesome-->
    <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
        integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">

    <!--jquery-->
    <script src="https://code.jquery.com/jquery-3.5.0.js"
        integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>

    <!--own css-->
    <style>
        @import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";

        body {
            font-family: 'Poppins', sans-serif;
            background: #fafafa;
        }

        p {
            font-family: 'Poppins', sans-serif;
            font-size: 1.1em;
            font-weight: 300;
            line-height: 1.7em;
            color: #999;
        }

        a,
        a:hover,
        a:focus {
            color: inherit;
            text-decoration: none;
            transition: all 0.3s;
        }

        .navbar {
            padding: 15px 10px;
            background: #fff;
            border: none;
            border-radius: 0;
            margin-bottom: 40px;
            box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
        }

        .navbar-btn {
            box-shadow: none;
            outline: none !important;
            border: none;
        }


        /* ---------------------------------------------------
    SIDEBAR STYLE
----------------------------------------------------- */

        .wrapper {
            display: flex;
            width: 100%;
            align-items: stretch;
        }

        #sidebar {
            min-width: 250px;
            max-width: 250px;
            background: rgb(60, 95, 238);
            color: #fff;
            transition: all 0.3s;
        }

        #sidebar.active {
            margin-left: -250px;
        }

        #sidebar .sidebar-header {
            padding: 20px;
            background: rgb(90, 121, 243);
        }

        #sidebar ul.components {
            padding: 20px 0;
            border-bottom: 1px solid #47748b;
        }

        #sidebar ul p {
            color: #fff;
            padding: 10px;
        }

        #sidebar ul li a {
            padding: 10px;
            font-size: 1.1em;
            display: block;
        }

        #sidebar ul li a:hover {
            color: #7386D5;
            background: #fff;
        }

        #sidebar ul li.active>a,
        a[aria-expanded="true"] {
            color: #fff;
            background: #6d7fcc;
        }

        a[data-toggle="collapse"] {
            position: relative;
        }

        .dropdown-toggle::after {
            display: block;
            position: absolute;
            top: 50%;
            right: 20px;
            transform: translateY(-50%);
        }

        ul ul a {
            font-size: 0.9em !important;
            padding-left: 30px !important;
            background: #6d7fcc;
        }

        ul.CTAs {
            padding: 20px;
        }

        ul.CTAs a {
            text-align: center;
            font-size: 0.9em !important;
            display: block;
            border-radius: 5px;
            margin-bottom: 5px;
        }

        a.download {
            background: #fff;
            color: #7386D5;
        }

        a.article,
        a.article:hover {
            background: #6d7fcc !important;
            color: #fff !important;
        }

        /* ---------------------------------------------------
    CONTENT STYLE
----------------------------------------------------- */

        #content {
            width: 100%;
            padding: 20px;
            min-height: 100vh;
            transition: all 0.3s;
        }

        /* ---------------------------------------------------
    MEDIAQUERIES
----------------------------------------------------- */

        @media (max-width: 768px) {
            #sidebar {
                margin-left: -250px;
            }

            #sidebar.active {
                margin-left: 0;
            }

            #sidebarCollapse span {
                display: none;
            }
        }

        /* ---------------------------------------------------
    CHART STYLE
----------------------------------------------------- 

        /* LINE CHART STYLE */

        .axis--x path {
            display: none;
        }

        .line {
            fill: none;
            stroke: steelblue;
            stroke-width: 1.5px;
        }
    </style>

    <!--lib js-->

    <!--bootstrap-->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>

    <!--fontawesome js-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>

    <!--d3(chart) js-->
    <script src="https://d3js.org/d3.v5.min.js"></script>

</head>

<body>
    <div class="wrapper">
        <!-- Sidebar -->
        <nav id="sidebar">
            <ul class="list-unstyled components">
                <li class="active">
                    <a href="/">DASHBOARD</a>
                </li>
            </ul>
            <!--End of nav.sidebar-->
        </nav>

        <!--Page content-->
        <div id="content">
            <!-- navbar -->
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <div class="container-fluid">
                    <button type="button" id="sidebarCollapse" class="btn btn-info">
                        <i class="fas fa-align-justify"></i>
                    </button>
                </div>
            </nav>

            <!--End of div.row-->
            <div class="row">
                <div class="col-12">
                    <div class="card shadow mb-5">
                        <div class="card-body">
                            <div id="lineChart">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--End of div.row-->
        </div>


    </div>
    <!--End of div.content-->

    </div>
    <!--End of div.wrapper-->

    <!--Lib <script>-->


    <!--own <script>-->

    <script src="js/script3.js"></script>


</body>

</html>

I've tried creating another element to hold the svg as a container and append the all the characteristic of the line chart below the text element that holds the title of the line chart but what happens is that it appends inside the <text> element. Please help.

Upvotes: 0

Views: 3091

Answers (1)

Marcelo
Marcelo

Reputation: 4282

the variable svg is in fact the element that you appended. If you want to add the title on top the element, you need to have a variable to hold the element. Also margin is an object, you need reference the property that holds the value.

$(document).ready(() => {
    // set the dimensions and margins of the graph
    var margin = { top: 40, right: 20, bottom: 30, left: 50 },
        width = 1000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    // parse the date / time
    var parseTime = d3.timeParse("%H:%M:%S");


    // set the ranges
    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    // define the line
    var valueline = d3.line()
        .x(function (d) { return x(d.availability_time); })
        .y(function (d) { return y(d.total_hour_percentage); });

    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svgp = d3.select("#lineChart").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)

     var svg= svgp.append("g")
        .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");

    function draw(data) {
        console.log(data[0].availability_time);

        // format the data
        data.forEach(function (d) {
            d.availability_time = (parseTime(d.availability_time));
            d.total_hour_percentage = d.total_hour_percentage;
        });

        // sort time ascending
        data.sort(function (a, b) {
            return a["availability_time"] - b["availability_time"];
        })

        // Scale the range of the data
        x.domain(d3.extent(data, function (d) {
            return d.availability_time;
        }));
        y.domain([0, d3.max(data, function (d) {
            return Math.max(d.total_hour_percentage);
        })]);

        // Add the valueline path.
        svg.append("path")
            .data([data])
            .attr("class", "line")
            .attr("d", valueline);
        // Add the X Axis
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x).ticks(d3.timeHour.every(1)).tickFormat(d3.timeFormat('%H:%M')));

        // Add the Y Axis
        svg.append("g")
            .call(d3.axisLeft(y));
    }

    svgp.append('text')
        .attr('class', 'title')
        .attr('x', width / 2)
        .attr('y', margin.top/2)
        .attr('text-anchor', 'middle')
        .text('Availability (%) of CAM for date: ');
    // Get the data
    // var perHourResult = "/perHourAvailabilities/" + defaultDate;
    // console.log(perHourResult);

    var perHourResult =
        [
            { "id": 0, "availability_time": "00:00:00", "total_hour_percentage": 99.55 },
            { "id": 0, "availability_time": "01:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "02:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "03:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "04:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "05:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "06:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "07:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "08:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "09:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "10:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "11:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "12:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "13:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "14:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "15:00:00", "total_hour_percentage": 99.75 },
            { "id": 0, "availability_time": "16:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "17:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "18:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "19:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "20:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "21:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "22:00:00", "total_hour_percentage": 100.0 },
            { "id": 0, "availability_time": "23:00:00", "total_hour_percentage": 100.0 }
        ];

    console.log(perHourResult[0].availability_time); //shows 00:00:00

    draw(perHourResult);
});
<!DOCTYPE html>
<html lang="en">

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

    <!--Lib css-->
    <!--bootstrap-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <!--fontawesome-->
    <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
        integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">

    <!--jquery-->
    <script src="https://code.jquery.com/jquery-3.5.0.js"
        integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>

    <!--own css-->
    <style>
        @import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";

        body {
            font-family: 'Poppins', sans-serif;
            background: #fafafa;
        }

        p {
            font-family: 'Poppins', sans-serif;
            font-size: 1.1em;
            font-weight: 300;
            line-height: 1.7em;
            color: #999;
        }

        a,
        a:hover,
        a:focus {
            color: inherit;
            text-decoration: none;
            transition: all 0.3s;
        }

        .navbar {
            padding: 15px 10px;
            background: #fff;
            border: none;
            border-radius: 0;
            margin-bottom: 40px;
            box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
        }

        .navbar-btn {
            box-shadow: none;
            outline: none !important;
            border: none;
        }


        /* ---------------------------------------------------
    SIDEBAR STYLE
----------------------------------------------------- */

        .wrapper {
            display: flex;
            width: 100%;
            align-items: stretch;
        }

        #sidebar {
            min-width: 250px;
            max-width: 250px;
            background: rgb(60, 95, 238);
            color: #fff;
            transition: all 0.3s;
        }

        #sidebar.active {
            margin-left: -250px;
        }

        #sidebar .sidebar-header {
            padding: 20px;
            background: rgb(90, 121, 243);
        }

        #sidebar ul.components {
            padding: 20px 0;
            border-bottom: 1px solid #47748b;
        }

        #sidebar ul p {
            color: #fff;
            padding: 10px;
        }

        #sidebar ul li a {
            padding: 10px;
            font-size: 1.1em;
            display: block;
        }

        #sidebar ul li a:hover {
            color: #7386D5;
            background: #fff;
        }

        #sidebar ul li.active>a,
        a[aria-expanded="true"] {
            color: #fff;
            background: #6d7fcc;
        }

        a[data-toggle="collapse"] {
            position: relative;
        }

        .dropdown-toggle::after {
            display: block;
            position: absolute;
            top: 50%;
            right: 20px;
            transform: translateY(-50%);
        }

        ul ul a {
            font-size: 0.9em !important;
            padding-left: 30px !important;
            background: #6d7fcc;
        }

        ul.CTAs {
            padding: 20px;
        }

        ul.CTAs a {
            text-align: center;
            font-size: 0.9em !important;
            display: block;
            border-radius: 5px;
            margin-bottom: 5px;
        }

        a.download {
            background: #fff;
            color: #7386D5;
        }

        a.article,
        a.article:hover {
            background: #6d7fcc !important;
            color: #fff !important;
        }

        /* ---------------------------------------------------
    CONTENT STYLE
----------------------------------------------------- */

        #content {
            width: 100%;
            padding: 20px;
            min-height: 100vh;
            transition: all 0.3s;
        }

        /* ---------------------------------------------------
    MEDIAQUERIES
----------------------------------------------------- */

        @media (max-width: 768px) {
            #sidebar {
                margin-left: -250px;
            }

            #sidebar.active {
                margin-left: 0;
            }

            #sidebarCollapse span {
                display: none;
            }
        }

        /* ---------------------------------------------------
    CHART STYLE
----------------------------------------------------- 

        /* LINE CHART STYLE */

        .axis--x path {
            display: none;
        }

        .line {
            fill: none;
            stroke: steelblue;
            stroke-width: 1.5px;
        }
    </style>

    <!--lib js-->

    <!--bootstrap-->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>

    <!--fontawesome js-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>

    <!--d3(chart) js-->
    <script src="https://d3js.org/d3.v5.min.js"></script>

</head>

<body>
    <div class="wrapper">
        <!-- Sidebar -->
        <nav id="sidebar">
            <ul class="list-unstyled components">
                <li class="active">
                    <a href="/">DASHBOARD</a>
                </li>
            </ul>
            <!--End of nav.sidebar-->
        </nav>

        <!--Page content-->
        <div id="content">
            <!-- navbar -->
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <div class="container-fluid">
                    <button type="button" id="sidebarCollapse" class="btn btn-info">
                        <i class="fas fa-align-justify"></i>
                    </button>
                </div>
            </nav>

            <!--End of div.row-->
            <div class="row">
                <div class="col-12">
                    <div class="card shadow mb-5">
                        <div class="card-body">
                            <div id="lineChart">
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--End of div.row-->
        </div>


    </div>
    <!--End of div.content-->

    </div>
    <!--End of div.wrapper-->

    <!--Lib <script>-->


    <!--own <script>-->

    <script src="js/script3.js"></script>


</body>

</html>

Upvotes: 1

Related Questions