{"action":"created","issue":{"url":"https://api.github.com/repos/d3/d3-zoom/issues/59","repository_url":"https://api.github.com/repos/d3/d3-zoom","labels_url":"https://api.github.com/repos/d3/d3-zoom/issues/59/labels{/name}","comments_url":"https://api.github.com/repos/d3/d3-zoom/issues/59/comments","events_url":"https://api.github.com/repos/d3/d3-zoom/issues/59/events","html_url":"https://github.com/d3/d3-zoom/issues/59","id":179122748,"number":59,"title":"D3 Zoom on Selections?","user":{"login":"canyon289","id":7213793,"avatar_url":"https://avatars.githubusercontent.com/u/7213793?v=3","gravatar_id":"","url":"https://api.github.com/users/canyon289","html_url":"https://github.com/canyon289","followers_url":"https://api.github.com/users/canyon289/followers","following_url":"https://api.github.com/users/canyon289/following{/other_user}","gists_url":"https://api.github.com/users/canyon289/gists{/gist_id}","starred_url":"https://api.github.com/users/canyon289/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/canyon289/subscriptions","organizations_url":"https://api.github.com/users/canyon289/orgs","repos_url":"https://api.github.com/users/canyon289/repos","events_url":"https://api.github.com/users/canyon289/events{/privacy}","received_events_url":"https://api.github.com/users/canyon289/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-09-26T01:37:01Z","updated_at":"2016-09-26T16:37:53Z","closed_at":"2016-09-26T16:37:53Z","body":"Maybe not an issue but I have a question of whether this is meaningful or not. Consider the example below\r\n\r\n```html\r\n<!DOCTYPE html>\r\n<meta charset=\"utf-8\">\r\n<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.6/d3.min.js\"></script>\r\n<body>\r\n</body>\r\n<script>\r\nvar zoom\r\nvar svg\r\nvar initial_transform\r\n\r\nzoom = d3.zoom()\r\ninitial_transform = d3.zoomIdentity.translate(50,50)\r\n\r\nsvg = d3.select(\"body\").append(\"svg\")\r\n svg.call(zoom.transform, initial_transform)\r\n\r\nconsole.log(d3.zoomTransform(svg))\r\nconsole.log(d3.zoomTransform(svg.node()))\r\n</script>\r\n</html>\r\n```\r\n\r\n> ea {k: 1, x: 0, y: 0}\r\n> ea {k: 1, x: 50, y: 50}\r\n\r\nThe first line is the d3.zoomTransform object on the selection, the second is the zoom transform on the element.\r\n\r\nMy twofold question is\r\nIs passing a selection to zoomTransform meaningful? I especially ask because all the documentation shows node as an argument.\r\n\r\nIf not would it be better for d3 to raise an error if I try passing a selection to d3.zoomTransform instead of a node? I spent a couple of hours scratching my head trying to figure out why the **initial_transform** was not working and it took a while for me to realize I needed to pass the svg node, not the svg selection.\r\n\r\nalso thanks for the great library!"},"comment":{"url":"https://api.github.com/repos/d3/d3-zoom/issues/comments/249624457","html_url":"https://github.com/d3/d3-zoom/issues/59#issuecomment-249624457","issue_url":"https://api.github.com/repos/d3/d3-zoom/issues/59","id":249624457,"user":{"login":"mbostock","id":230541,"avatar_url":"https://avatars.githubusercontent.com/u/230541?v=3","gravatar_id":"","url":"https://api.github.com/users/mbostock","html_url":"https://github.com/mbostock","followers_url":"https://api.github.com/users/mbostock/followers","following_url":"https://api.github.com/users/mbostock/following{/other_user}","gists_url":"https://api.github.com/users/mbostock/gists{/gist_id}","starred_url":"https://api.github.com/users/mbostock/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbostock/subscriptions","organizations_url":"https://api.github.com/users/mbostock/orgs","repos_url":"https://api.github.com/users/mbostock/repos","events_url":"https://api.github.com/users/mbostock/events{/privacy}","received_events_url":"https://api.github.com/users/mbostock/received_events","type":"User","site_admin":false},"created_at":"2016-09-26T16:37:53Z","updated_at":"2016-09-26T16:37:53Z","body":"As documented, d3.zoomTransform takes a *node*, not a selection. This is because a selection may consist of multiple nodes, and d3.zoomTransform only returns a single transform. I’ve added some clarifying text to the README to make this more obvious.\r\n\r\nRegarding the implementation: perhaps it could be changed to use the first node from the selection if passed a selection, similar to selection getter methods, but I’d rather avoid overloading the method signature and have usage be consistent. Often this method is used from within an event handler, where you want to pass in `this`, being the active element.\r\n\r\nOr it could be changed to throw an error if *node* is a selection, but that seems tailored to the exact error here. Wouldn’t it be better if it throw an error if the given *node* is *not* a node? Yet there isn’t a strict definition of what a “node” *is* in the context of selections, though `node instanceof Element` would likely be reasonable here. There are some cases where it’s valid to create a selection of non-element objects; see tomwanzek/d3-v4-definitelytyped#2. D3 selections use duck typing: if a node is an object that defines the needed methods, then it’s fine to create a selection from it. \r\n\r\nMore generally, D3 does not try very hard to protect against incorrect usage. This is partly a language consequence: JavaScript is a weakly-typed language. Some operations enforce types, while others do not. For example, consider the following abuse of [*function*.apply](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply), which takes an array of arguments as the second argument:\r\n\r\n```js\r\nfunction log(message) {\r\n  console.log(message);\r\n}\r\n\r\nlog.apply(null, \"hello\"); // TypeError: CreateListFromArrayLike called on non-object(…)\r\n```\r\n\r\nYet JavaScript is perfectly happy to take other questionably-array inputs:\r\n\r\n```js\r\nlog.apply(null, {0: \"hello\"}); // logs \"undefined\"\r\nlog.apply(null, {0: \"hello\", length: 1}); // logs \"hello\"\r\n```\r\n\r\nAs another example, d3.dispatch [throws an error](https://github.com/d3/d3-dispatch/blob/master/src/dispatch.js#L41) if you try to register a callback listener that is not a function. This is so because callbacks are typically invoked asynchronously, and so it’s much easier to debug if there error is thrown when the callback is registered rather than when it is invoked. But if you pass the *wrong* sort of thing to d3.zoomTransform, the result is synchronous: the returned transform will always be the default identity transform. If you use a debugger, you can step through the code and see why (*node*.\\_\\_zoom is undefined).\r\n\r\nSo, I’m not convinced it’s worthwhile to add an assertion here, though if people continue to run into this confusion, then I’ll consider it again in the future.\r\n\r\nAnother option for stronger protection is a language enhancement such as TypeScript; see [tomwanzek/d3-v4-definitelytyped](https://github.com/tomwanzek/d3-v4-definitelytyped) and DefinitelyTyped/DefinitelyTyped#9936.\r\n"}}
{"actor":{"display_login":"mbostock"}}