{"id":1267,"date":"2017-09-12T15:49:11","date_gmt":"2017-09-12T20:49:11","guid":{"rendered":"http:\/\/billdwhite.com\/?p=1267"},"modified":"2017-09-12T15:49:11","modified_gmt":"2017-09-12T20:49:11","slug":"d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap","status":"publish","type":"post","link":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/","title":{"rendered":"d3 Minimap v4 Update"},"content":{"rendered":"<h5 data-height=\"600\" data-theme-id=\"2092\" data-slug-hash=\"qPWKOg\" data-default-tab=\"result\" data-user=\"billdwhite\" data-embed-version=\"2\" data-pen-title=\"d3 Minimap Pan and Zoom Demo\"><strong>Understanding d3 v4 ZoomBehavior in the Pan and Zoom Minimap<\/strong><\/h5>\n<p class=\"codepen\" data-height=\"600\" data-theme-id=\"2092\" data-slug-hash=\"qPWKOg\" data-default-tab=\"result\" data-user=\"billdwhite\" data-embed-version=\"2\" data-pen-title=\"d3 Minimap Pan and Zoom Demo\">See the Pen <a href=\"https:\/\/codepen.io\/billdwhite\/pen\/qPWKOg\/\">d3 Minimap Pan and Zoom Demo<\/a> by Bill White (<a href=\"https:\/\/codepen.io\/billdwhite\">@billdwhite<\/a>) on <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<\/p>\n<p><script async=\"\" src=\"https:\/\/production-assets.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<p>It has been a while since I posted any new articles. \u00a0I&#8217;ve been working \u00a0non-stop with Angular 4 (formerly Angular 2), Typescript, RxJS and d3 v4. \u00a0 I\u00a0recently needed to add a minimap for a visualization and I decided to update my old minimap demo to make us of d3 version 4. \u00a0While researching the updates to the zooming behavior, I came across\u00a0<a href=\"https:\/\/github.com\/d3\/d3-zoom\/issues\/88\">this post<\/a> on GitHub where another developer user was trying to do the same thing (funny enough, also using my previous example). \u00a0After reading Mike&#8217;s response about cross-linking the zoom listeners, I decided to give it a try. \u00a0 While implementing his suggestion, I learned quite a bit about how the new and improved zoom functionality works and I wanted to share that in this post.<\/p>\n<p>My previous example did not make good use of the capabilities of d3&#8217;s ZoomBehavior. \u00a0I was manually updating the transforms for the elements based on zoom events as well as directly inspecting the attributes of related elements. \u00a0With the latest updates to d3 v4, creating this type of minimap functionality ended being really simple and I was able to remove a lot of code from the old demo. \u00a0I found that, while the <a href=\"https:\/\/github.com\/d3\/d3\/blob\/master\/CHANGES.md#zooming-d3-zoom\">release notes<\/a>\u00a0and the <a href=\"https:\/\/github.com\/d3\/d3\/blob\/master\/API.md#zooming-d3-zoom\">docs<\/a> for the zoom feature are helpful, actually <a href=\"https:\/\/github.com\/d3\/d3-zoom\/blob\/master\/src\/zoom.js\">reading through the source<\/a> is also enlightening. \u00a0I was eventually able to boil it down to some basic bullet points.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Design<\/strong><\/p>\n<ol>\n<li>The is a canvas component (the visualization) and a minimap component. \u00a0I will refer to these as counterparts, with each making updates to the other. \u00a0The canvas has a viewport (the innerwrapper element in my example) and a visualization (the pancanvas in my example). \u00a0The minimap also has a viewport (the frame) and a miniature version of the visualization (the container). \u00a0As the visualization is scaled and translated, the relative size and scale is portrayed in the minimap.<\/li>\n<li>The d3 v4 updated demo has 2 zoomHandler methods that each react separately to &#8216;local&#8217; zoom events. \u00a0One makes changes to the main visualization&#8217;s transform and scale. \u00a0The other does the same to the minimap&#8217;s frame.<\/li>\n<li>There are also 2 &#8216;update&#8217; methods. \u00a0These are called by the zoomHandler in the counterpart component. \u00a0Each update method will then call the local zoomHandler on behalf of the counterpart. \u00a0This effectively convey&#8217;s the ZoomBehavior changes made in one counterpart over to the other component.<\/li>\n<li>There will continue to be separate logic for updating the miniature version of the base visualization over to the minimap. (found in the minimap&#8217;s render() method)<\/li>\n<li>There will continue to be separate logic to sync the size of the visualization with the size of the frame. (also found in the minimap&#8217;s render() method)<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><strong>Zoom Behavior notes<\/strong><\/p>\n<ol>\n<li>The ZoomBehavior is applied to an element, <em>but that does not mean it will zoom THAT element<\/em>. \u00a0It simply hooks up listeners to that element upon which it is called\/applied and gives you a place to react to those events (the zoomHandler that is listening for the &#8220;zoom&#8221; event).<\/li>\n<li>The actual manipulation of the elements on the screen will take place in the zoomHandler which receives a d3.event.transform value (which is of type ZoomEvent for those of you using Typescript). \u00a0That event provides you with the details about what just happened (i.e. the transformation and scale that the user just performed on the ZoomBehavior&#8217;s target). \u00a0At this point, you have to decide what to do with that information, such as applying that transformation\/scaling to an element. \u00a0Again, that element does not have to be the same element that the ZoomBehavior was originally applied to (as is the case here).<\/li>\n<li>We have to add a filtering if() check within each zoom handler to avoid creating an infinite loop. \u00a0More on that in a in the next section&#8230;..<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><strong>Logic Flow<\/strong><\/p>\n<ol>\n<li>We apply the ZoomBehavior on two elements (using &lt;element&gt;.call(zoom)). \u00a0The InnerWrapper of the visualization&#8217;s canvas and the Container of the minimap. \u00a0They will listen for user actions and report back using the zoomHandler.<\/li>\n<li>Once the zoomHandler is called, we will take the d3.event.transform information it received and update some other element. \u00a0In this demo, the InnerWrapper&#8217;s zoom events are applied to the PanCanvas, while the minimap&#8217;s Container events are used to transform the minimap&#8217;s Frame element.<\/li>\n<li>Once each zoom handler has transformed it&#8217;s own local target, it then examines the event to see if it originated from its own local ZoomBehavior. \u00a0If it did, then the logic executes an &#8216;update()&#8217; call over on its counterpart so that it can also be modified. \u00a0So we get a sequence like this: \u00a0&#8220;InnerWrapper(ZoomBehavior) &#8211;&gt; zoomHandler(in Canvas component) &#8211;&gt; updates PanCanvas element &#8211;&gt; did zoom event occur locally? &#8211;&gt; if so, update minimap&#8221;. \u00a0And from the other side we have this: &#8220;minimap Container(ZoomBehavior) -&gt; zoomHandler(in minimap) -&gt; updates minimap Frame element -&gt; did zoom event occur locally? -&gt; if so, update visualization&#8221;. \u00a0You can see how this could lead to an infinite loop so the check to see if the event originated locally is vital.<\/li>\n<\/ol>\n<p>This diagram shows the general structure I&#8217;m describing:<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1285\" src=\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\" alt=\"\" width=\"578\" height=\"600\" \/><\/a><\/p>\n<p>So the end result is a &#8220;push me\/pull you&#8221; type of action. \u00a0Each side makes its own updates and, if necessary, tells the counterpart about those updates. \u00a0A few other things to point out:<\/p>\n<ol>\n<li>Because the minimap&#8217;s frame (representing the visualization&#8217;s viewport) needs to move and resize inverse to the viewport, I modify the transform event <em>within<\/em>\u00a0the minimap when they are received and before they are sent out. \u00a0The encapsulates the inversion logic in one place and puts that burden solely on the minimap component.<\/li>\n<li>When modifying a transform, <strong>ordering matters<\/strong>. \u00a0Mike Bostock mentions this in the <a href=\"https:\/\/github.com\/d3\/d3-zoom\">docs<\/a>, but I still got tripped up by this when my minimap was not quite in sync with the visualization. \u00a0I had to scale <em>first<\/em>, then apply the transform.<\/li>\n<li>Rather than using the old\u00a0<strong>getXYFromTranslate()<\/strong> method that parses the .attr(&#8220;transform&#8221;) string property off an element, it is much easier to use the method <strong>d3.zoomTransform(elementNode)<\/strong> to get this information. (remember, that method works with nodes, not selections)<\/li>\n<\/ol>\n<p>At this point, the design works. \u00a0However, there&#8217;s another problem waiting for us:<\/p>\n<p>When the user moves an element on one side, the counterpart on the other gets updated. \u00a0However, when the user goes to move the counterpart element, the element will &#8220;jump back&#8221; to the last position that it&#8217;s own ZoomBehavior triggered. \u00a0This is because, when the ZoomBehavior on an element contacts its zoomHandler, <em>it stashes the transform data for future reference so it can pick up where it left off on future zoom actions<\/em>. \u00a0This &#8216;stashing&#8217; only happens when the ZoomBehavior is triggered from UI events (user zooming\/dragging etc). \u00a0So when we manually update the PanCanvas in response to something other than the ZoomBehavior&#8217;s &#8216;zoom&#8217; event, the stashing does not occur and the state is lost. \u00a0To fix this, we must manually stash the latest transform information ourselves when updating the element outside of the ZoomBehavior&#8217;s knowledge. \u00a0There&#8217;s another subtle point here that briefly tripped me up: \u00a0the ZoomBehavior stashes the zoom transform <em>on the element to which it was applied, NOT the element upon which we are acting<\/em>. \u00a0So when the ZoomBehavior hears zoom events on the InnerWrapper, it updates the __zoom property on the InnerWrapper. \u00a0Later on, when the minimap makes an update call back to the visualization, we have to manually update that property on the InnerWrapper, even though we are using that data to transform the PanCanvas in the zoomHandler.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>So here is the final interaction:<\/strong><\/p>\n<ol>\n<li>User moves the mouse over the PanCanvas<\/li>\n<li>The ZoomBehavior on the InnerWrapper hears those events and saves that transform data in the __zoom property on the InnerWrapper.<\/li>\n<li>The ZoomBehavior then emits the &#8216;zoom&#8217; event which is handled by the local zoomHandler in the visualization (canvas component in the demo)<\/li>\n<li>The zoomHandler will apply the transform to the PanCanvas to visibly update its appearance in response to the mouse actions from step #1<\/li>\n<li>The zoomHandler looks at the event and if it determines that it originated locally, it makes an update call over to the minimap so it can be updated<\/li>\n<li>The minimap&#8217;s update handler inverts the transform event data and applies it to the Frame element<\/li>\n<li>Because the minimap&#8217;s updates to the Frame element occurred outside of the minimap&#8217;s own ZoomBehavior, \u00a0we stash the latest transform data for future state reference. Note: we stash that state, not on the Frame element, but on the minimap&#8217;s Container element because that is the element to which the minimap&#8217;s ZoomBehavior was applied and that is where it will look for previous state when subsequent ZoomBehavior events are fired when the user mouses over the minimap.<\/li>\n<li>The minimap&#8217;s zoomHandler is called by the update method which applies the matching minimap appearance update to the Frame element.<\/li>\n<li>The minimap&#8217;s zoomHandler determines the update event did not come from the local ZoomBehavior and therefore it does not call the update method on the visualization, thus preventing an infinite loop.<\/li>\n<\/ol>\n<p>Hopefully this will save you some time and help you understand how the d3 v4 ZoomBehavior can be used for functionality such as this demo. \u00a0\ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Understanding d3 v4 ZoomBehavior in the Pan and Zoom Minimap See the Pen d3 Minimap Pan and Zoom Demo by Bill White (@billdwhite) on CodePen. It has been a while since I posted any new articles. \u00a0I&#8217;ve been working \u00a0non-stop with Angular 4 (formerly Angular 2), Typescript, RxJS and d3 v4. \u00a0 I\u00a0recently needed to\u2026 <span class=\"read-more\"><a href=\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4,9],"tags":[],"class_list":["post-1267","post","type-post","status-publish","format-standard","hentry","category-d3","category-javascript"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>d3 Minimap v4 Update - Bill White<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"d3 Minimap v4 Update - Bill White\" \/>\n<meta property=\"og:description\" content=\"Understanding d3 v4 ZoomBehavior in the Pan and Zoom Minimap See the Pen d3 Minimap Pan and Zoom Demo by Bill White (@billdwhite) on CodePen. It has been a while since I posted any new articles. \u00a0I&#8217;ve been working \u00a0non-stop with Angular 4 (formerly Angular 2), Typescript, RxJS and d3 v4. \u00a0 I\u00a0recently needed to\u2026 Read More &raquo;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\" \/>\n<meta property=\"og:site_name\" content=\"Bill White\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-12T20:49:11+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\" \/>\n<meta name=\"author\" content=\"Bill White\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@bill_d_white\" \/>\n<meta name=\"twitter:site\" content=\"@bill_d_white\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Bill White\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\"},\"author\":{\"name\":\"Bill White\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\"},\"headline\":\"d3 Minimap v4 Update\",\"datePublished\":\"2017-09-12T20:49:11+00:00\",\"dateModified\":\"2017-09-12T20:49:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\"},\"wordCount\":1567,\"commentCount\":9,\"publisher\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\"},\"image\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\",\"articleSection\":[\"d3\",\"Javascript\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\",\"url\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\",\"name\":\"d3 Minimap v4 Update - Bill White\",\"isPartOf\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\",\"datePublished\":\"2017-09-12T20:49:11+00:00\",\"dateModified\":\"2017-09-12T20:49:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage\",\"url\":\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\",\"contentUrl\":\"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/billdwhite.com\/wordpress\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"d3 Minimap v4 Update\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#website\",\"url\":\"https:\/\/billdwhite.com\/wordpress\/\",\"name\":\"Bill White's Blog\",\"description\":\"UI Development and Data Visualization:  Angular \/ React \/ D3 \/ Typescript \/ Javascript \/ UI \/ UX \/ Etc\",\"publisher\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/billdwhite.com\/wordpress\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\",\"name\":\"Bill White\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3c3595ee8305a186eea4ea5286143893?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3c3595ee8305a186eea4ea5286143893?s=96&d=mm&r=g\",\"caption\":\"Bill White\"},\"logo\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/image\/\"},\"sameAs\":[\"http:\/\/www.billdwhite.com\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"d3 Minimap v4 Update - Bill White","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/","og_locale":"en_US","og_type":"article","og_title":"d3 Minimap v4 Update - Bill White","og_description":"Understanding d3 v4 ZoomBehavior in the Pan and Zoom Minimap See the Pen d3 Minimap Pan and Zoom Demo by Bill White (@billdwhite) on CodePen. It has been a while since I posted any new articles. \u00a0I&#8217;ve been working \u00a0non-stop with Angular 4 (formerly Angular 2), Typescript, RxJS and d3 v4. \u00a0 I\u00a0recently needed to\u2026 Read More &raquo;","og_url":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/","og_site_name":"Bill White","article_published_time":"2017-09-12T20:49:11+00:00","og_image":[{"url":"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png","type":"","width":"","height":""}],"author":"Bill White","twitter_card":"summary_large_image","twitter_creator":"@bill_d_white","twitter_site":"@bill_d_white","twitter_misc":{"Written by":"Bill White","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#article","isPartOf":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/"},"author":{"name":"Bill White","@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314"},"headline":"d3 Minimap v4 Update","datePublished":"2017-09-12T20:49:11+00:00","dateModified":"2017-09-12T20:49:11+00:00","mainEntityOfPage":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/"},"wordCount":1567,"commentCount":9,"publisher":{"@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314"},"image":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage"},"thumbnailUrl":"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png","articleSection":["d3","Javascript"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/","url":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/","name":"d3 Minimap v4 Update - Bill White","isPartOf":{"@id":"https:\/\/billdwhite.com\/wordpress\/#website"},"primaryImageOfPage":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage"},"image":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage"},"thumbnailUrl":"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png","datePublished":"2017-09-12T20:49:11+00:00","dateModified":"2017-09-12T20:49:11+00:00","breadcrumb":{"@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#primaryimage","url":"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png","contentUrl":"http:\/\/billdwhite.com\/wp-content\/uploads\/2017\/09\/2017-09-12-at-3.18-PM.png"},{"@type":"BreadcrumbList","@id":"https:\/\/billdwhite.com\/wordpress\/2017\/09\/12\/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/billdwhite.com\/wordpress\/"},{"@type":"ListItem","position":2,"name":"d3 Minimap v4 Update"}]},{"@type":"WebSite","@id":"https:\/\/billdwhite.com\/wordpress\/#website","url":"https:\/\/billdwhite.com\/wordpress\/","name":"Bill White's Blog","description":"UI Development and Data Visualization:  Angular \/ React \/ D3 \/ Typescript \/ Javascript \/ UI \/ UX \/ Etc","publisher":{"@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/billdwhite.com\/wordpress\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314","name":"Bill White","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/3c3595ee8305a186eea4ea5286143893?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3c3595ee8305a186eea4ea5286143893?s=96&d=mm&r=g","caption":"Bill White"},"logo":{"@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/image\/"},"sameAs":["http:\/\/www.billdwhite.com"]}]}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/posts\/1267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/comments?post=1267"}],"version-history":[{"count":0,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/posts\/1267\/revisions"}],"wp:attachment":[{"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/media?parent=1267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/categories?post=1267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/tags?post=1267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}