-
Notifications
You must be signed in to change notification settings - Fork 141
Why no translateTo function? #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Yes. It is not clear whether the coordinates x,y you pass to zoom.translateTo should depend on the transform’s scale. You have to decide whether you want this: zoom.translate(selection, d3.zoomIdentity.scale(k).translate(x, y)); Or this: zoom.translate(selection, d3.zoomIdentity.translate(x, y).scale(k)); Given the ambiguity, it seemed better to not implement this method, and use one of the two above instead. |
Something else that I think would be nice is that zoom.translateTo could respect the translateExtent values automatically. Otherwise, it must be done prior to calling zoom.translate. My use case is that I want to programmatically center the visualization on an element, but only if it would respect the translateExtent (i.e. it would not be respected if the element is on the edge of the visualization). |
I'm aware of the ambiguity, but the reason I was looking for this method is exactly that I wanted a way to translate to a specific point with respect to zoom = () ->
_zoom = d3.zoom()
# Custom "zoom.transform" that enforces translate and scale extents.
_zoom.strictTransform = (selection, transform) ->
[[x0, y0], [x1, y1]] = _zoom.translateExtent()
[k0, k1] = _zoom.scaleExtent()
constrain = (transform, extent) ->
dx0 = transform.invertX(extent[0][0]) - x0
dx1 = transform.invertX(extent[1][0]) - x1
dy0 = transform.invertY(extent[0][1]) - y0
dy1 = transform.invertY(extent[1][1]) - y1
x = if dx1 > dx0 then (dx0 + dx1) / 2 \
else Math.min(0, dx0) or Math.max(0, dx1)
y = if dy1 > dy0 then (dy0 + dy1) / 2 \
else Math.min(0, dy0) or Math.max(0, dy1)
transform.translate(x, y)
selection.call(_zoom.transform, () ->
{ x, y, k } = if typeof transform is 'function' then \
transform.apply(this, arguments) else transform
k = Math.max(k0, Math.min(k1, k))
constrain(d3.zoomIdentity.translate(x, y).scale(k),
_zoom.extent().apply(this, arguments)))
# Translates to position.
_zoom.translateTo = (selection, position) ->
selection.call(_zoom.strictTransform, () ->
{ x, y, k } = Object.assign({},
d3.zoomTransform(this), position)
d3.zoomIdentity.translate(x, y).scale(k))
_zoom The |
On second thought, I don’t think it is ambiguous because the x and y you pass to zoom.translateTo should be consistent with the x and y you pass to zoom.translateBy. That means that tx1 = k × x and ty1 = k × y, or in other words: zoom.translate(selection, d3.zoomIdentity.scale(k).translate(x, y)); I haven’t tested it, but there’s an implementation in #109. Is that what you want? |
This seems like exactly what I needed. It'd be nice to see this feature in future releases. Thank you for such a quick response, this is great! :) |
I would love to see a live example of why this is useful if you have time! |
Sure, I came up with a simple example that shows the problem. My original use case is different and more complex (it also involves a custom brush, transitions, etc.), but to the number of reasons I can't provide it, sorry. I hope this helps. |
Just pinpointing that @baygeldin's example uses the other translation order:
Wouldn't it be this form that is consistent with zoom.translateBy? |
@pmalouin No. That produces {k: k, x: x, y: y}, while the other order produces {k: k, x: k * x, y: k * y}, which is consistent with zoom.translateBy. |
@pmalouin, seems like I made a mistake in a hurry. I changed the order and updated the example. |
The issue I see with the proposed implementation in #109 and @baygeldin’s use case is that zoom.translateTo would not be especially helpful as this method puts the specified point ⟨x, y⟩ at the origin ⟨0,0⟩. What you typically want instead is for the specified point to be at the center of the viewport. Fortunately, there’s already logic in place to compute the center of the extent, which is used in zoom.scaleTo and transitions. So I think we can tweak the proposed implementation accordingly, and then zoom.translateTo will be useful in any situation where you want to center something at the current zoom level (such as the zoom transitions example). |
In my opinion, the proposed implementation is already quite useful, because it helps to avoid a lot of boilerplate with writing your own constrain logic or figuring out how to acomplish the same thing with |
Okay, I tested the new #109 on the zoom transitions example, and it worked great! Will release soon as 1.4.0. Thanks for the motivation. 😁 |
There is scaleBy and scaleTo, but only translateBy. Is there a specific reason or is it just not implemented?
The text was updated successfully, but these errors were encountered: