score:13

Accepted answer

There's no problem at all using multiple SVGs on the same page. Here's an example:

var svg1 = d3.select("#svg1");
svg1.append("circle")
       .attr("cx",100)
       .attr("cy", 100)
       .attr("r", 90)
       .attr("fill", "red");
var svg2 = d3.select("#svg2");
svg2.append("circle")
       .attr("cx",100)
       .attr("cy", 100)
       .attr("r", 90)
       .attr("fill", "blue");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="200" height="200" id="svg1"></svg>
<svg width="200" height="200" id="svg2"></svg>

score:0

If the two charts use the same code, I think the most d3-like way to go about it would be

var width = 960,
    height = 960,
    margin = 30;

var svgs = d3.select('#area1')
    .selectAll('svg')
    .data([json1, json2])
    .enter()
    .append('svg')
    .attr('width', width)
    .attr('height', height)

svgs.append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .each(function(d) {console.log(d)}) // will log json1, then json2

You'll then have json1 and json2 bound to each of the newly appended svgs, and all code that follows will be done to both.

var width = 200,
    height = 100,
    margin = 30;

var svgs = d3.select('#area1')
    .selectAll('svg')
    .data([{text:'thing1'}, {text:'thing2'}])
    .enter()
    .append('svg')
    .attr('width', width)
    .attr('height', height);

svgs.append("text")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .text(function(d) {return d.text});
<script src="https://d3js.org/d3.v4.js"></script>
<div id='area1'></div>

score:5

There is no need for repeating all the code, as you're doing right now. Don't repeat yourself.

An easy alternative is wrapping all your D3 code in a function that has two parameters, selector and url:

function draw(selector, url){
    //code here
};

Then, inside that function draw, you set the position of your SVG:

var svg = d3.select(selector).append("svg")...

And the URL you get the data:

d3.json(ulr, function(error, root) {...

After that, just call the draw function twice, with different arguments:

draw(selector1, url1);
draw(selector2, url2);

Here is a demo, read it carefully to see how it works:

draw("#svg1", "#data1");
draw("#svg2", "#data2");

function draw(selector, url){

var data = d3.csvParse(d3.select(url).text())

var width = 500,
    height = 150;

var svg = d3.select(selector)
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var xScale = d3.scalePoint()
    .domain(data.map(function(d) {
        return d.name
    }))
    .range([50, width - 50])
    .padding(0.5);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(data, function(d) {
        return d.value
    }) * 1.1])
    .range([height - 20, 6]);

var line = d3.line()
	.x(function(d){ return xScale(d.name)})
	.y(function(d){ return yScale(d.value)});
	
svg.append("path")
	.attr("d", line(data))
	.attr("stroke", "teal")
	.attr("stroke-width", "2")
	.attr("fill", "none");

var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);

svg.append("g").attr("transform", "translate(0,130)")
    .attr("class", "xAxis")
    .call(xAxis);

svg.append("g")
    .attr("transform", "translate(50,0)")
    .attr("class", "yAxis")
    .call(yAxis);

}
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div>First SVG</div>
<div id="svg1"></div>
<div>Second SVG</div>
<div id="svg2"></div>
<pre id="data1">name,value
foo,8
bar,1
baz,7
foobar,9
foobaz,4</pre>
<pre id="data2">name,value
foo,1
bar,2
baz,3
foobar,9
foobaz,8</pre>


Related Query