What is the proper way to use D3's projection.stream()?
Asked Answered
S

1

28

So I'm experimenting a bit with D3's geo stream API, and things feel a bit hazy. I've been reading through the documentation here:

https://github.com/mbostock/d3/wiki/Geo-Streams

One point of confusion I have is the proper implementation of stream transforms. Let's say I create one:

//a stream transform that applies a simple translate [20,5]:
var transform = d3.geo.transform({
    point:function(){this.stream.point(x+20,y+5)}
}) 

Per the documentation, this.stream references the "wrapped stream." But what is the stream, really? From what I can gather, it is more of a procedure than explicit data structure--a sequence of data and function calls to transform the data. The syntax above seems to suggest that the wrapped stream is simply the object containing "stream listeners"

Moving on, I'm able to apply the stream transform using the projection method:

//a path generator with the transform applied using the projection() method
var path = d3.geo.path().projection(transform);

While I don't quite understand the underlying mechanics, the effect seems relatively straightforward: the underlying transform function of the path generator is called with transformed x,y arguments.

For my use case, I don't find this that helpful, particularly because my input data is not already projected. I'd like to use a projection to transform the data first, then transform those outputted coordinates. To that end, is there a general pattern for layering transforms?

I see that D3 does provide the projection.stream(listener) pattern which applies the projecting transform first, before applying the listener, but I'm not sure how to implement this. What should the listener argument be? Here's an example: http://jsfiddle.net/kv7yn8rw/2/.

Any guidance would be greatly appreciated!

Seagirt answered 18/12, 2014 at 23:47 Comment(2)
Are you trying to move your projected map data 20px to the right and 5px down using this method? Or is there more that you're trying to do when you refer to layering transforms?Contexture
Sorry the bounty hasn't generated any answers. I started looking through the source code, but my best guess was that var path2 = d3.geo.path().projection( proj.stream(transform) ); should work for your fiddle, and it was still throwing errors. I might come back again when I have more time; I've been meaning to learn more about how the d3.geo methods work.Idiotic
T
6

A key fact from the documentation is that "a geographic projection is one example of a stream transform."

Streams just allow one to transform (e.g. project) data multiple times without saving the intermediate data. A projection can just be an object with a stream attribute, e.g. proj_then_transform below.

The way to chain streams is as follows:

// stream 1
var proj = d3.geo.equirectangular();
// stream 2
var transform = d3.geo.transform({
    point:function(x,y){this.stream.point(x+20,y+5)}
});
// stream 1 then stream 2
var proj_then_transform = {
        stream: function(s) { 
            return proj.stream(transform.stream(s)); 
        }
     };

I've updated the example with a working solution: http://jsfiddle.net/cvs5d7o9/2/

That answered 27/7, 2015 at 7:22 Comment(1)
Just to I understand the order of things correctly, the function is called proj_then_transform, but it looks like the transform is taking place first, and then that is being fed to the projection. Should that be the case?Moonshine

© 2022 - 2024 — McMap. All rights reserved.