3

I'm trying to render graph using react.js. In which I'm trying to use simple ReactDOM.render() method on html page. when I'm appending this graph content to the body it will work for me well but I want to render this using react.js.

program-code:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!--react js url here -->
</head>
<body>
<script>
var csv_data = "date,bucket,count\n19:37:1 164,30000,12\n19:37:1 283,30000,8\n19:37:1 349,80000,2\n19:37:1 421,30000,16\n19:37:1 599,30000,2\n19:37:1 608,40000,4\n19:37:1 755,30000,4\n19:37:1 857,30000,2\n19:37:1 915,40000,6";
var margin = {
        top : 20,
        right : 90,
        bottom : 30,
        left : 50
    }, width = 960 - margin.left - margin.right, height = 500 - margin.top
            - margin.bottom;

var svg = d3.select("#svg").attr("width",
            width + margin.left + margin.right).attr("height",
            height + margin.top + margin.bottom).append("g").attr(
            "transform",
            "translate(" + margin.left + "," + margin.top + ")");
var buckets = d3.csv.parse(csv_data);

    buckets.forEach(function(d) {
        d.date = new Date(timeFormat.parse(d.date));
        d.bucket = +d.bucket;
        d.count = +d.count;
    });

    x.domain(d3.extent(buckets, function(d) {
        return d.date;
    }));

    y.domain(d3.extent(buckets, function(d) {
        return d.bucket;
    }));

    z.domain([ 0, d3.max(buckets, function(d) {
        return d.count;
    }) ]);
x.domain([ x.domain()[0], +x.domain()[1] + xStep ]);
    y.domain([ y.domain()[0], y.domain()[1] + yStep ]);

    // Display the tiles for each non-zero bucket.
    svg.selectAll(".tile").data(buckets).enter().append("rect").attr(
            "class", "tile").attr("x", function(d) {
        return x(d.date);
    }).attr("y", function(d) {
        return y(d.bucket + yStep);
    }).attr("width", x(xStep) - x(0)).attr("height", y(0) - y(yStep))
            .style("fill", function(d) {
                return z(d.count);
            });

    // Add a legend for the color values.
    var legend = svg.selectAll(".legend").data(
            z.ticks(6).slice(1).reverse()).enter().append("g").attr(
            "class", "legend").attr("transform", function(d, i) {
        return "translate(" + (width + 20) + "," + (20 + i * 20) + ")";
    });

    legend.append("rect").attr("width", 20).attr("height", 20).style(
            "fill", z);

    legend.append("text").attr("x", 26).attr("y", 10).attr("dy", ".35em")
            .text(String);

    svg.append("text").attr("class", "label").attr("x", width + 20).attr(
            "y", 10).attr("dy", ".35em").text("Count");

    // Add an x-axis with label.
    svg.append("g").attr("class", "x axis").attr("transform",
            "translate(0," + height + ")").call(xAxis).append("text").attr(
            "class", "label").attr("x", width).attr("y", -6).attr(
            "text-anchor", "end").text("Time");

    // Add a y-axis with label.
    svg.append("g").attr("class", "y axis").call(yAxis).append("text")
            .attr("class", "label").attr("y", 6).attr("dy", ".71em").attr(
                    "text-anchor", "end").attr("transform", "rotate(-90)")
            .text("Latency");
</script>
<div id="container"></div>
<script type="text/jsx">
    ReactDOM.render(<svg id="svg"></svg>,document.getElementById('container'));     
</script>
</body>
</html>

But graph is not visible in the browser when I'm requesting to this page. what is that I'm missing here?

6
  • Have a look at this Commented Aug 25, 2016 at 11:45
  • @Gerardo Furtado- yeah right. corrected this mistake. In other way can I render this svg variable itself by selecting div or something like that? Commented Aug 25, 2016 at 11:53
  • I'm not sure if I understand your question... Do you mean if you can choose a div to render the SVG inside it? Commented Aug 25, 2016 at 11:56
  • @Gerardo Furtado- yeah like that. But I'm tried with that also but still not working for me. Commented Aug 25, 2016 at 11:58
  • Do you have anything in the page with an ID named "svg"? If not, just create a div with that ID, or simply select the "body". Commented Aug 25, 2016 at 11:59

3 Answers 3

4

Since the d3 code is executed before the React code, the svg element doesn't exist yet. You can create a react class which renders the svg element, and then place your d3 code componentDidMount and/or componentDidUpdate method. React renders everything in a shadow DOM before adding it to the actual DOM so you need to make sure the element is available before you can select it with d3 (or jQuery, etc.)

class MySVG extends React.Component {

  componentDidMount() {
    var svg = d3.select('#my-svg');
    //Do svg stuff
  }

  render() {
    return (
      <svg id="my-svg"></svg>
    );
  }

}

export default MySVG;

and then render mySVG with ReactDOM.render()

Sign up to request clarification or add additional context in comments.

1 Comment

Note that this is using ES6 syntax. I am not completely sure how it would look in vanilla javascript..
2

I published a tiny npm package to resolve this. npm i hook-use-d3 and then use like so:

In sample below I added some d3 code to show you animated green dot, to make sure you will have visual to confirm it works. As an extra, it's also animated :)

import * as d3 from "d3";
import React from "react";
import useD3 from "hook-use-d3";

export default function SomeComponent() {
  const d3ref = useD3((svg) => {
    const circle = svg
      .append("circle")
      .attr("cx", 50)
      .attr("cy", 50)
      .attr("r", 1)
      .attr("fill", "#4CAF50");

    function animate() {
      let radius = 5;
      let distance = 35;
      circle
        .transition()
        .duration(2000)
        .attrTween("r", () => d3.interpolate(radius, radius + distance))
        .on("end", () => {
          radius = circle.attr("r");
          distance = 35;

          circle
            .transition()
            .duration(2000)
            .attrTween("r", () => d3.interpolate(radius, radius - distance))
            .on("end", animate);
        });
    }
    animate();
  }, []);

  return <svg ref={d3ref} style={{ height: 100, width: 100 }}></svg>;
}

If you want to see the code of the hook, posted it on github: https://github.com/liesislukas/hook-use-d3/tree/main

enter image description here

1 Comment

If anyone is trying to get this working with TypeScript, I ported this fine example to TypeScript in gist.github.com/fasiha/d23ea4905cf5e4650e8cdeabdd15249f (and embedded your library hook into the body of the component to see exactly how it worked). There were some confusing type errors so hopefully this will help others.
0

Unless "svg" is the ID of an existing svg in the page, it seems to me that you forgot to append the SVG in your variable svg:

var svg = d3.select("#svg")
    .append("svg")//this appends the SVG
    .attr("width", width + margin.left + margin.right)
    .attr("height",  height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

1 Comment

yeah right. corrected this mistake still facing same issue graph is not visible in rendered svg.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.