mhemesath / r2d3

Raphael Rendered, Data Driven Documents
MIT License
546 stars 133 forks source link

Support for d3.transform #12

Closed mbecica closed 11 years ago

mbecica commented 11 years ago

Using attr('transform', function() { return "translate(4,5)" }) on elements results in an incorrect matrix being set for the value, ie transform=matrix(0,0,0,0,0,0).

D3 uses the native svg transform while Raphael expects a string similar to the path string. I'm assuming that the translate() function doesn't work in ie.

Several edits would have to be made to D3.transform:

d3_transform.prototype.toString = function() {
  return "t" + this.translate
      + "r" + this.rotate
      + "s" + this.scale;
};

Raphael doesn't have support for 'skew', so that might be buildable with transform, rotate, and scale?

I'm still debugging transform, so there might be more.

mhemesath commented 11 years ago

Yeah, this is going to be <sarcasm>fun</sarcasm>. I think we may be able to avoid manipulating the d3_transform module. Instead we should attempt to make the expected properties accessible on the raphael objects so it can consume them as is. This will probably involve overriding the Raphael element transform method to set/get SVG strings and map them to what Raphael expects.

IPWright83 commented 11 years ago

I've been trying to get the D3 Sankey diagram working which uses a transition. Is there anyway you can think of to fudge this to get it working?

I've tried coupling @mhemesath 'grouping' fork which works for the most part (I believe this is the 'set' instead of 'g') part, and then tried swapping the toString prototype. I found though that the transform didn't seem to get called in my code but I'm not sure why, so I'm wondering if there's something more to change?

mhemesath commented 11 years ago
 I've been trying to get the D3 Sankey diagram working which uses a transition

Transition or transformation/translation?

In R2D3, under the covers the .attr D3 method is really calling each property against a Raphael paper element. So when you do this in D3

circle.attr({ fill: 'red', stroke: 'blue' })

you are doing this in Raphael:

circle.fill('red')
circle.stroke('blue')

With that said, Raphael does support transforms, they just look quite a bit different than the standard SVG syntax. You can seem here: http://raphaeljs.com/reference.html#Element.transform.

IPWright83 commented 11 years ago

Sorry, my mistake I meant Transformation, which in actual fact is just a simple translation. I had a quick read of that link, and saw why mbecica's solution looked like it might work so I gave that a try. I found however that

var node = svg.append("g").selectAll(".node")
     .data(energy.nodes)
     .enter().append("g")
       .attr("class", "node")
       .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })

Placing a break point in the following however, it seemed to never be called. d3_transform.prototype.toString

mhemesath commented 11 years ago

Attribute calls are mapped directly to Rapahel.Element calls. When you set transform, its actually trying to invoke http://raphaeljs.com/reference.html#Element.transform. Until we get transformations fixed, you'll have to use Raphael's syntax for transformations if you want them to work.

IPWright83 commented 11 years ago

@mhemesath : Hmm, true. I never thought about trying to access the Raphael element directly. How would I translate what I've currently got, something like this?

var paper = d3.select('svg');
paper.selectAll('.node').transform( /* Not sure what goes in here */);

or like this one:

var node = svg.append("g").selectAll(".node")
 .data(energy.nodes)
 .enter().append("g")
 .attr("class", "node")
 .Element.transition( /* Not sure what goes in here */);
mhemesath commented 11 years ago

D3 works by wrapping Raphael elements and accessing the setAttribute extension I've added to them. With that in mind, to set a Raphael transform you would just do the following:

var node = svg.append("g").selectAll(".node")
 .data(energy.nodes)
 .enter().append("g")
 .attr("class", "node")
 .attr("transform", "t100,100")

Again, this is just a temporary workaround until we fix transforms. Also, I'd avoid using groups until I merge that branch.

IPWright83 commented 11 years ago

@mhemesath : Understand the suggestion on avoiding groups, at the moment I don't quite understand the alternative approaches enough to do it the other way. On the plus side I've managed to get this working, and groups are indeed the problem in this case.

Instead of applying the transform on the nodes (which i believe are groups) I applied it a little later on to a rectangle and a text item that had been appended to the group also and all seems to work at that point. On the plus side of this group stuff, at least you're getting some early testing for things to watch out for ;)

mhemesath commented 11 years ago

@mbecica I started playing with a function to convert a transform String into a Raphael matrix object. The gist can be found here: https://gist.github.com/3856324

It probably has bugs, but I'm going to keep playing with it and if it works I'll push it through into a branch.