0

I created a D3 graph which works with an local JSON file. Now I want to utilize a MySQL DB, where I wrote a PHP script to fetch the data. The script is working but I receive a parsing error, as soon as I feed my D3 graph with it.

I am pretty new in terms of DB and PHP handling. I guess my Javascript file can´t resolve the PHP result proper, as the local JSON file starts with "nodes"... instead of "0".

How can I resolve that?

enter image description here

The JSON file looks like:

{
 "nodes": [
  { "id": 0, "type": "food" },
  { "id": 1, "type": "drinks" },
  { "id": 2, "type": "snacks" }
 ]
}

The PHP script and output:

<?php
$username = "root"; 
$password = "root";   
$host = "localhost";
$database="idep3";

$connection = mysqli_connect($host, $username, $password, $database);
$connection2 = mysqli_select_db($connection, $database);

$myquery = "
SELECT * FROM idep3.nodes";

$query = mysqli_query($connection, $myquery);

if ( ! $query ) {
    echo mysql_error();
    die;
}

$data = array();

for ($x = 0; $x < mysqli_num_rows($query); $x++) {
    $data[] = mysqli_fetch_assoc($query);
}

echo json_encode($data, JSON_FORCE_OBJECT);     
 
mysqli_close($connection);
?>

Output:

 {"0":{"id":"0","type":"food"},"1":{"id":"1","type":"drinks"},"2":{"id":"2","type":"snacks"}}

And finally the graph:

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

<head>
    <meta charset="UTF-8">
    <title>D3v6 DB demo</title>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>

<style>
    body {
        background-color: #e6e7ee;
    }

    circle {
        stroke: black;
        stroke-width: 1px;
        cursor: pointer;
    }
</style>

<body>
    <script>       
        const data = "connection.php";

        const onLoad = graph => {

            var svg = d3.select("body").append("svg")
                .attr("width", window.innerWidth)
                .attr("height", window.innerHeight)
                .attr("class", "svg")
                .call(d3.zoom().on("zoom", function (event) {
                    svg.attr("transform", event.transform)
                }))
                .append("g")

            d3.select("svg").on("dblclick.zoom", null)

            //var linkContainer = svg.append("g").attr("class", "linkContainer")
            var nodeContainer = svg.append("g").attr("class", "nodeContainer")

            var forceLayout = d3.forceSimulation()
                .force("charge", d3.forceManyBody().strength(-25))
                .force("center", d3.forceCenter(window.innerWidth / 2, window.innerHeight / 2))
                .force("collision", d3.forceCollide().radius(50))


            //###############################################
            //################## initialize #################
            //###############################################

            init()

            function init() {
                nodes = nodeContainer.selectAll(".node")
                    .data(graph.nodes, function (d) { return d.id; })
                    .join("g")
                    .attr("class", "node")
                    .attr("id", function (d) { return "node" + d.id; })
                    .call(d3.drag()
                        .on("start", dragStarted)
                        .on("drag", dragged)
                        .on("end", dragEnded)
                    )

                nodes.selectAll("circle")
                    .data(d => [d])
                    .join("circle")
                    .attr("r", 40)
                    .style("fill", "whitesmoke")
                    .on("click", addNode)

                nodes.selectAll("text")
                    .data(d => [d])
                    .join("text")
                    .attr("dominant-baseline", "central")
                    .attr("text-anchor", "middle")
                    .attr("id", function (d) { return "text" + d.id })
                    .attr("pointer-events", "none")
                    .text(function (d) {
                        return d.id + " " + d.type
                    })

                forceLayout
                    .nodes(graph.nodes)
                    .on("tick", tick)
            }

            //add node function

            function addNode(event, d) {
                thisNode = d

                var newNode = {
                    "id": graph.nodes.length + 1,
                    "type": "drinks",
                    x: thisNode.x,
                    y: thisNode.y
                }

                graph.nodes.push(newNode)

                init()
            }

            //tick function

            function tick() {

                nodes.attr("transform", function (d) {
                    return "translate(" + d.x + "," + d.y + ")";
                });
            }


            //drag function

            function dragStarted(event, d) {
                if (!event.active) forceLayout.alphaTarget(0.3).restart();

                d.fx = d.x;
                d.fy = d.y;
            }

            function dragged(event, d) {
                d.fx = event.x;
                d.fy = event.y;
            }

            function dragEnded(event, d) {
                if (!event.active) forceLayout.alphaTarget(0);

                d.fx = undefined;
                d.fy = undefined;
            }
        }

        d3.json(data).then(onLoad).catch(err => console.log(err))

    </script>
</body>

</html>
ICoded
  • 319
  • 3
  • 18
  • 3
    Are you sure that the client code successfully retrieves your data, i.e. the output of you PHP script? The Fetch API only rejects the promise on hard network errors! A 404 NOT FOUND or a 500 SERVER ERROR is still a successful response as far as the fetch is concerned. Put a `console.log(graph)` at the beginning of the `onLoad()` function. Have a these resources: https://www.tjvantoll.com/2015/09/13/fetch-and-errors/ and https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#checking_that_the_fetch_was_successful. – altocumulus May 27 '21 at 09:59
  • 1
    You have an error. [`mysql_error()`](https://www.php.net/manual/en/function.mysql-error.php) worked only for the old API. Please consider switching error mode on instead. [How to get the error message in MySQLi?](https://stackoverflow.com/a/22662582/1839439) – Dharman May 27 '21 at 10:07
  • @altocumulus well, I do not receive anything. At least with "Firefox". I executed the HTML in "Firefox with Firebug" and receiving CORS request not HTTP. Which confuse me even more. Of course it is not HTTP. I want to pass the output from a local PHP file, which contains the MySQL query. – ICoded May 28 '21 at 07:02
  • @Dharman thanks for mentioning. Yes it should be fixed to but it has nothing to do with the current issue now. Still important for future progress. – ICoded May 28 '21 at 07:03

0 Answers0