Trying D3, and have some issues. Not sure what is the best way to endure coordinate system. Please find the source below.
EDIT: Fiddle here
I simulated the inverted coordinate by yScale -> .range([ height - padding, padding]); Instead of .range([ padding - height - padding]); . Is this the best way. If all the objects in the svg needs to be correctly oriented, is it best to apply to the outermost element?
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g") <---
The bigger rectangle ({"X":100, "Y": 100, "W":40, "H": 40}), is outside the axis. So, I am doing something wrong.
Any help to make this graph to contain within the axis, with proper scaling and orientation is highly appreciated.
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="d3.v2.min.js"></script>
<link type="text/css" rel="stylesheet" href="style.css"/>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
var margin = {top: 10, right: 20, bottom: 20, left: 10},
width = 960 - margin.right - margin.left,
height = 480 - margin.top - margin.bottom
padding = 40;
var data = [
{"X":10, "Y": 10, "W":10, "H": 10},
{"X":100, "Y": 100, "W":40, "H": 40}
]
var xScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.X; })])
.range([padding, width - padding]),
yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.Y; })])
.range([ height - padding, padding]);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom"),
yAxis = d3.svg.axis().scale(yScale).orient("left");
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate("
+ margin.left + ","
+ margin.top + ")");
svg.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return xScale(d.X); })
.attr("y", function (d) { return yScale(d.Y); })
.attr("width", function (d) { return (d.W); })
.attr("height", function (d) { return (d.H); })
//Create X axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
Re 1.: yes, that is the best way.
Also note that D3 will not save your bacon when you 'flip' a scale like that and then feed widths into it, which will come out negative: when using those for SVG height attributes, those will be flagged as illegal SVG content and the browser will barf a hairball (not show what you want).
Re 2.: once you have corrected your negative widths / heights, then you can prevent 'plotting outside the area' by wrapping your s in a clipping rectangle; this can be done by placing them in a separate group, which is then assigned a clipping rect matching your output area.
For #1, see also in reply to your question to the mailing list:
http://bl.ocks.org/3671490
has all bugs fixed and showing a proper rect.
Style issue: your code would only have worked with a linear axis as you convert width and height via a single call to xScale/yScale instead of calculating the absolute coordinates in domain space first, then convert both via scale to calculate the width / height in output space. To show that the new approach works in log space too, here's a copy of the above gist using log/log scales instead:
http://bl.ocks.org/3671592
The code is 'rough' in that all calculations are explicitly done and no 'invariants' are moved outside the .attr() calls: x1/y1/x2/y2 get calculated several times as each .attr() needs two of them. This sort of thing is usually 'solved' by setting up the data (precalculating / sorting / swapping / whatever is needed) before feeding it to d3.selection.data().
Lesson learned: you need to do more work to be completely scale agnostic when working with SVG; if you want faster code instead, you need to prepare your data so that the output will produce valid SVG (here: 'processed' input = [{X:80,Y:80,W:10,H:-60]]), in particular positive values for width and height (or similarly x2 > x1 and y2 > y1 for )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With