Reputation: 2904
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?
Upvotes: 3
Views: 6509
Reputation: 26403
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
Upvotes: 2
Reputation: 2173
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()
Upvotes: 4
Reputation: 102194
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 + ")");
Upvotes: 0