Data is not correctly scaling to range.
I am appending an svg to a div,
var svg = d3.select("#box")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
and then a group to that svg.
// create group
var group = svg.append("g")
.attr("class", "main_group")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Then scaling for the x axis,
var x = d3.scaleLinear()
.domain(0, d3.max(function(d) {
return d.x_pos
})).range([0, width]);
The width is set with,
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = 600 - margin.left - margin.right, // width=500
height = 600 - margin.top - margin.bottom; // height=500
When I change the x_pos value to greater than 800 the rendered rect is outside the svg. At the moment at x_pos=525 the top left of the rect is visible.
{
// "x_pos": "800",
"x_pos": "525",
"y_pos": "300",
"name": "Dd"
},
I expected the x_pos value in the data to always scale to the range [0, width].
Why is the data not scaling to the range?
svg {
border: 2px solid gray;
}
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<div id="box">
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
data = [{
"x_pos": "100",
"y_pos": "400",
"name": "Aa"
},
{
"x_pos": "200",
"y_pos": "200",
"name": "Bb"
},
{
"x_pos": "300",
"y_pos": "100",
"name": "Cc"
},
{
// "x_pos": "300",
"x_pos": "525",
"y_pos": "300",
"name": "Dd"
},
{
"x_pos": "0",
"y_pos": "0",
"name": "Ee"
}
]
data.forEach(function(d) {
d.x_pos = +d.x_pos;
d.y_pos = +d.y_pos;
});
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = 600 - margin.left - margin.right, // width=500
height = 600 - margin.top - margin.bottom; // height=500
var x = d3.scaleLinear()
.domain(0, d3.max(function(d) {
return d.x_pos
})).range([0, width]);
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.y_pos
})]).range([height, 0]);
var svg = d3.select("#box")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// create group
var group = svg.append("g")
.attr("class", "main_group")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// bind the data
var boxes = group.selectAll("boxes")
.data(data)
.enter();
// add rects
boxes.append("rect")
.attr("class", "boxes")
.attr("x", function(d) {
return d.x_pos
})
.attr("y", function(d) {
return d.y_pos
})
.attr("rx", "5px")
.attr("width", 60)
.attr("height", 20)
.attr("stroke", "darkgray")
.attr("fill", "lightblue");
// add text
boxes.append("text")
.attr("class", "legend_text")
.attr("x", function(d) {
return d.x_pos
})
.attr("y", function(d) {
return d.y_pos
})
.attr("dx", "0.5em")
.attr("dy", "1.0em")
.style("font-weight", "bold")
.text(function(d) {
return d.name;
});
// add text coordinates
boxes.append("text")
.attr("class", "legend_text")
.attr("x", function(d) {
return d.x_pos
})
.attr("y", function(d) {
return d.y_pos
})
.attr("dx", "-2.5em")
.attr("dy", "-.5em")
.style("font-weight", "bold")
.text(function(d) {
return "(" + d.x_pos + ", " + d.y_pos + ")";
});
</script>
The issue here is very simple: you are not using any scale to position the rectangles:
.attr("x", function(d) {
return d.x_pos
})
Solution: Use your scale.
.attr("x", function(d) {
return x(d.x_pos)
// ^--- scale here
})
Also, you're not setting your domain correctly. It should be:
var x = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.x_pos
})]).range([0, width]);
Here is your code with those changes:
svg {
border: 2px solid gray;
}
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<div id="box">
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
data = [{
"x_pos": "100",
"y_pos": "400",
"name": "Aa"
},
{
"x_pos": "200",
"y_pos": "200",
"name": "Bb"
},
{
"x_pos": "300",
"y_pos": "100",
"name": "Cc"
},
{
// "x_pos": "300",
"x_pos": "525",
"y_pos": "300",
"name": "Dd"
},
{
"x_pos": "0",
"y_pos": "0",
"name": "Ee"
}
]
data.forEach(function(d) {
d.x_pos = +d.x_pos;
d.y_pos = +d.y_pos;
});
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 50
},
width = 600 - margin.left - margin.right, // width=500
height = 600 - margin.top - margin.bottom; // height=500
var x = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.x_pos
})]).range([0, width]);
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.y_pos
})]).range([height, 0]);
var svg = d3.select("#box")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// create group
var group = svg.append("g")
.attr("class", "main_group")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// bind the data
var boxes = group.selectAll("boxes")
.data(data)
.enter();
// add rects
boxes.append("rect")
.attr("class", "boxes")
.attr("x", function(d) {
return x(d.x_pos)
})
.attr("y", function(d) {
return y(d.y_pos)
})
.attr("rx", "5px")
.attr("width", 60)
.attr("height", 20)
.attr("stroke", "darkgray")
.attr("fill", "lightblue");
// add text
boxes.append("text")
.attr("class", "legend_text")
.attr("x", function(d) {
return x(d.x_pos)
})
.attr("y", function(d) {
return y(d.y_pos)
})
.attr("dx", "0.5em")
.attr("dy", "1.0em")
.style("font-weight", "bold")
.text(function(d) {
return d.name;
});
// add text coordinates
boxes.append("text")
.attr("class", "legend_text")
.attr("x", function(d) {
return x(d.x_pos)
})
.attr("y", function(d) {
return y(d.y_pos)
})
.attr("dx", "-2.5em")
.attr("dy", "-.5em")
.style("font-weight", "bold")
.text(function(d) {
return "(" + d.x_pos + ", " + d.y_pos + ")";
});
</script>