-
Notifications
You must be signed in to change notification settings - Fork 684
d3.geo.tile should actually do geo stuff #37
Comments
We've implemented all of the basic APIs, zoom, center, extent, etc in iD, but they're not generalized currently: https://github.com/systemed/iD/blob/master/js/id/renderer/map.js#L213 (demo: http://geowiki.com/iD/ ) (iD's background layer also supports backbuffering and such) |
On the contrary my dear fellow, the built-in support for geographic coordinates is a d3.geo.projection! Here's your example using the Mercator projection: var projection = d3.geo.mercator()
.center([-76.3429, 38.7351]) // geographic center
.scale(1 << 12) // zoom level in tile coordinates
.translate([width / 2, height / 2]);
var tile = d3.geo.tile()
.scale(projection.scale())
.translate(projection([0, 0]))
.size([width, height]); And here's a live example: http://bl.ocks.org/4150951 |
Trying to switch to For instance, right now, |
No kidding @tmcw that code is pretty fearsome. I’m sitting this one out, no plans to use d3.tile. |
Let the zoom behavior drive the projection, rather than creating a feedback loop through projection.invert. For example, with Mercator, first create the projection: var projection = d3.geo.mercator(); Then, on zoom, update the scale and translate (but don’t change the center, and don’t use projection.invert): projection
.scale(zoom.scale())
.translate(zoom.translate()); And that’s it. Live example, showing the mouse location: http://bl.ocks.org/4132797/dc4d80534125f326349e7fefa05430293e4f5bf8 |
Ah, okay - that's essentially the approach we were doing before, though it makes functions that set center & zoom programmatically significantly more complex: https://github.com/systemed/iD/blob/master/js/id/renderer/map.js#L213 |
It gets a lot simpler if you temporarily set projection.center to compute the appropriate translate, and then reset it. For example, to zoom to San Francisco: projection
.scale(1 << 19)
.center([-122.4183, 37.7750]) // temporarily set center
.translate([width / 2, height / 2])
.translate(projection([0, 0])) // compute appropriate translate
.center([0, 0]); // reset
zoom
.scale(projection.scale())
.translate(projection.translate()); |
Probably time for a pyramid-aware “Coordinate” abstraction between geography and pixels. |
@migurski If you are referring to pixels in screen space, the abstraction is d3.geo.projection. If you are referring to the quadtree tile pyramid, the abstraction is d3.geo.tile, except there’s no reason to expose the tile coordinates outside of d3.geo.tile (since you have d3.geo.projection for screen coordinates). Seems simpler to avoid exposing a third coordinate system unless necessary. |
I’m referring to the quadtree, and there’s definitely reason to expose the third coordinate system. Being able to “speak tile” and have English-looking words for concepts like tile-to-the-right, tile-one-zoom-out-from-this-one and so on is huge, huge, huge when you need to sync image and non-image layers. UTFGrid interaction layers, vector data loading, and multi-zoom pyramid loading to eliminate the flash of unloaded tiles are three examples. The density of the code snippets in this thread is another: the tile concept is implied in the serial calls to |
I completely agree there is a use for tile coordinates when you need to speak tiles, but that is not the case in the simple examples above. There is no tile coordinate system implied in my earlier snippet; there is only the geographic coordinate system and pixels. It is d3.geo.tile that internally maps pixels to tile coordinates, but it could apply any number of strategies to do so (why not hex tiles?) and my point is that it is not required to expose the tile coordinate system in order to use d3.geo.tile. But, as you say, d3.geo.tile could expose the mapping from pixels to tiles, as there are useful applications of the tile coordinate system outside of simply loading them. And in essence it does that already, because d3.geo.tile returns the set of tile coordinates that are visible in the viewport. This interface could be extended to expose the direct mapping between pixels and tiles, similar to projection. What I am arguing for, albeit poorly, is that I would like to avoid coupling d3.geo.projection to tile coordinates, and likewise avoid coupling d3.geo.tile to geographic coordinates. d3.geo.projection should handle geography ↔ pixels, and d3.geo.tile should handle pixels ↔ tiles. |
Where I see the tile system implied is in the bit-shifted zoom levels passed to In Modest Maps, I chose a coupling that’s actually quite similar to the one you’re trying to avoid, so this might be a matter of taste. =) MMaps projections know about tile coordinates but not about pixels, so they have an explicit post-projection affine transformation, typically from ±π to 0…1 for spherical mercator. Maps know about tile coordinates and pixels but not geography, so they defer to the projection to perform that translation. Tile providers link the two together. I’ve found it very helpful for additional work to have that available. |
Yeah so I kinda went and scratched a whole bunch of itches at once with this: https://github.com/migurski/Squares#readme Includes the first-class quadtree I've been talking about, mostly ported from @RandomEtc’s 2011 D3 + tiles exercise. |
You might be interested in the recent wheel event fixes to d3.behavior.zoom; see d3/d3#1050. I wonder if you can use d3.behavior.zoom in Squares? |
I’ll have a look, thanks. The DIV-based scroll thingie does have quite different rates in FFox vs. Chrome, with Safari someplace in the middle. |
I think d3.behavior.zoom is going to be a dead-end for me. Based on the example I could find, which I only sort-of understand, it looks like something that you |
I would look at the d3.geo.tile example: http://bl.ocks.org/4132797 And no, you don’t need to add it for each element that gets appended, you only need to add it to the parent container. |
I tried both combinations, and got no movement either time. I suspect that I'm not putting the pieces together correctly, so I’m not going to pursue D3 behaviors any further for the time being. I also tried porting over the new mousewheel support from the commit you linked to above (migurski/Squares@1d04b8f0). It sort-of works, but Safari reports 10x the movement that Chrome does, so the zooming behavior appears wildly erratic, much moreso than with the hidden div. I'll leave it the way it was previously. |
Anyway, I've got to 👍 the idea of coordinates as a plugin and would be happy to write it. At the moment, a basic 'd3 + tiles demo' with zoom in and zoom out buttons is very non-obvious. |
d3.geo.tile holds promise, but right now it's seriously lacking for all but demo maps because there's no built-in support for working with geographic coordinates. E.g.:
Are there plans to support this? I'm wondering aloud if @tmcw, @migurski, or @RandomEtc might be working on this already.
The text was updated successfully, but these errors were encountered: