D3.js and coordinate system

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

  1. 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") <---

  2. 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.

Index.html
<!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>
Script.js
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);

Answers


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 )


Need Your Help

List View Item Clickable

android android-listview

I need to make my list item clickable instead of individual textview or Image view. My Activity code calling adapter is as below:

Spring Autowired DAO with hibernate.cfg.xml

spring hibernate junit4 dao autowired

I have a Spring Maven DAO Project which is packaged into a jar. It was originally a Spring DAO Ivy project, but I converted it to maven. This was a legacy project which used Spring 3.2.0 and Hib...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.