{"id":1053,"date":"2015-01-12T15:55:49","date_gmt":"2015-01-12T21:55:49","guid":{"rendered":"http:\/\/billdwhite.com\/?p=1053"},"modified":"2015-01-12T15:55:49","modified_gmt":"2015-01-12T21:55:49","slug":"d3-in-3d-combining-d3-js-and-three-js","status":"publish","type":"post","link":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/","title":{"rendered":"D3 in 3D: Combining d3.js and three.js"},"content":{"rendered":"<p>Along with <a title=\"d3\" href=\"http:\/\/d3js.org\/\" target=\"_blank\" rel=\"noopener\">d3<\/a>, the <a title=\"Three JS\" href=\"https:\/\/github.com\/mrdoob\/three.js\/\" target=\"_blank\" rel=\"noopener\">three.js<\/a> library is one of the most powerful javascript libraries available for creating slick visualizations. I wondered if it would be possible to create data visualizations in threejs as easily as I had done using d3. One thing that d3 does very well is to take your data and apply a layout algorithm to it for use in drawing visualizations such as treemaps and piecharts. While I&#8217;m sure there are other ways to generate this layout data, the d3 approach is the one that I&#8217;m most comfortable with and I wondered if it would be possible to use this layout data to render 3D versions of those same visualizations.<\/p>\n<p>This first demo shows a WebGL (or Canvas if you&#8217;ve got a crappy browser like IE) rendered treemap that was created using the d3 treemap layout: (I had to use JSBin instead of CodePen for the demos because the embedded CodePen snippets kept locking a few seconds after loading; no idea why)<\/p>\n<p class=\"codepen\" data-height=\"600\" data-theme-id=\"2092\" data-slug-hash=\"qJpLKd\" data-default-tab=\"result\" data-user=\"billdwhite\" data-pen-title=\"d3 3D Treemap\">See the Pen <a href=\"https:\/\/codepen.io\/billdwhite\/pen\/qJpLKd\/\">d3 3D Treemap<\/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:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<p>The results work pretty well. The Tweening is handled using TweenJS which is what the threejs folks use. I wanted to do the updates using d3 transitions but using the Tween code from the examples I had seen worked straight away so maybe I can swithc over to d3 transitions in the future. Also, when you set the zscale to 0, you see a bit of color bleeding and I have no idea why. (Let me know if you have a solution.)<\/p>\n<p>First, I must give credit to <a title=\"Delimited\" href=\"http:\/\/www.delimited.io\/\" target=\"_blank\" rel=\"noopener\">Steve Hall<\/a> who has also investigated this concept. Last year I explored ways to create 3D visualizations with <a title=\"Three JS\" href=\"http:\/\/threejs.org\/\" target=\"_blank\" rel=\"noopener\">threejs<\/a> using layout data from <a title=\"d3 library\" href=\"http:\/\/d3js.org\/\" target=\"_blank\" rel=\"noopener\">d3<\/a>, but I hit a wall when I was unable to get the coordinates to translate between the two worlds correctly. Steve also worked on this idea and wrote some fantastic <a title=\"ThreeJS and D3 Article 1\" href=\"http:\/\/www.delimited.io\/blog\/2014\/3\/14\/d3js-threejs-and-css-3d-transforms?rq=d3\" target=\"_blank\" rel=\"noopener\">blog<\/a> <a title=\"ThreeJS with D3 Article 2\" href=\"http:\/\/www.delimited.io\/blog\/2014\/5\/10\/maps-with-d3js-threejs-and-mapbox\" target=\"_blank\" rel=\"noopener\">entries<\/a> about it. His work focused more on created mini-visualizations, attaching them to DOM nodes and then having threejs render those nodes in 3D. After reading his work, I contacted him to ask if he knew how to correctly translate the coordinates and to my relief, he gladly provided the solution. So in the interests of full disclosure, my work here was greatly facilitated by his assistance. Thanks Steve!<\/p>\n<p>The solution I landed on is relatively straightforward: Take a dataset, run it through d3 to apply layout positioning information to each data item and then render those items in threejs rather than the normal DOM-oriented CSS styling that we use with d3. In a typical d3 visualization, the data is bound to the DOM nodes and you use the <a title=\"General Update Pattern\" href=\"http:\/\/bl.ocks.org\/mbostock\/3808218\" target=\"_blank\" rel=\"noopener\">enter\/update\/exit<\/a> lifecycle to add, modify and remove those nodes. With threejs, we are no longer adding stuff to the DOM tree (unless we use the CSS3DRenderer, but more on that in a second) because the 3D world is rendered using WebGL (or Canvas when WebGL is unsupported).<\/p>\n<p>So I am taking the dataset that has been processed by d3 and then adding each item to the threejs scene. I add, update and remove items from the scene in reaction to the add\/update\/remove calls from the d3 <a title=\"General Update Pattern II\" href=\"http:\/\/bl.ocks.org\/mbostock\/3808221\" target=\"_blank\" rel=\"noopener\">general update<\/a> lifecycle. Interestingly, I&#8217;m actually adding DOM nodes to the tree using d3 but they are empty and unstyled so they end up only serving as placeholders for the current set of rendered data in the threejs scene. If the data changes, the d3-generated empty nodes are <a title=\"General Update Pattern III\" href=\"http:\/\/bl.ocks.org\/mbostock\/3808234\" target=\"_blank\" rel=\"noopener\">added\/updated\/removed<\/a> and then, for each change, a corresponding change is made to the objects in the threejs scene.<\/p>\n<p>Steve&#8217;s demos are implemented using the <a title=\"CSS3DRenderer\" href=\"http:\/\/mrdoob.com\/lab\/javascript\/threejs\/css3d\/\" target=\"_blank\" rel=\"noopener\">CSS3DRenderer<\/a> which actually displays the 3D objects using only CSS3 transforms. Because of this, you are actually still in the d3 data-bound-to-the-DOM-node situation. It is really the best of both d3 and threejs because you can take full advantage of d3 selections and still have threejs display the 3D results using those same nodes. However, if you want your 3D visualization to look, well, three-dimensional, you have to bridge the gap between the d3 generated DOM nodes and the corresponding objects in the threejs scene yourself.<\/p>\n<p>This second demo uses the CSS3DRenderer and uses d3 to create the DOM elements which are then manipulated by threejs. You can see that while it is nice, it is not quite as fancy as the first demo:<\/p>\n<p data-height=\"600\" data-theme-id=\"2092\" data-slug-hash=\"RexEEV\" data-default-tab=\"result\" data-user=\"billdwhite\" data-pen-title=\"CSS3DRenderer Treemap\" class=\"codepen\">See the Pen <a href=\"https:\/\/codepen.io\/billdwhite\/pen\/RexEEV\/\">CSS3DRenderer Treemap<\/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:\/\/static.codepen.io\/assets\/embed\/ei.js\"><\/script><\/p>\n<p><!--\n\n\n<p data-height=\"500\" data-theme-id=\"2092\" data-slug-hash=\"GgrXGK\" data-default-tab=\"result\" data-user=\"billdwhite\" class='codepen'>See the Pen <a href='http:\/\/codepen.io\/billdwhite\/pen\/GgrXGK\/'>d3 3d ThreeJS Visualization<\/a> by Bill White (<a href='http:\/\/codepen.io\/billdwhite'>@billdwhite<\/a>) on <a href='http:\/\/codepen.io'>CodePen<\/a>.<\/p>\n\n\n<script async src=\"\/\/assets.codepen.io\/assets\/embed\/ei.js\"><\/script>\n\n\n<p data-height=\"500\" data-theme-id=\"2092\" data-slug-hash=\"vEgvoB\" data-default-tab=\"result\" data-user=\"billdwhite\" class='codepen'>See the Pen <a href='http:\/\/codepen.io\/billdwhite\/pen\/MYJqXv\/'>d3 3d WebGL ThreeJS Visualization<\/a> by Bill White (<a href='http:\/\/codepen.io\/billdwhite'>@billdwhite<\/a>) on <a href='http:\/\/codepen.io'>CodePen<\/a>.<\/p>\n\n\n<script async src=\"\/\/assets.codepen.io\/assets\/embed\/ei.js\"><\/script>\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Along with d3, the three.js library is one of the most powerful javascript libraries available for creating slick visualizations. I wondered if it would be possible to create data visualizations in threejs as easily as I had done using d3. One thing that d3 does very well is to take your data and apply a\u2026 <span class=\"read-more\"><a href=\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\">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,7,9,16],"tags":[23,31,39],"class_list":["post-1053","post","type-post","status-publish","format-standard","hentry","category-d3","category-html5","category-javascript","category-threejs","tag-d3","tag-javascript","tag-threejs"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>D3 in 3D: Combining d3.js and three.js - 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\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"D3 in 3D: Combining d3.js and three.js - Bill White\" \/>\n<meta property=\"og:description\" content=\"Along with d3, the three.js library is one of the most powerful javascript libraries available for creating slick visualizations. I wondered if it would be possible to create data visualizations in threejs as easily as I had done using d3. One thing that d3 does very well is to take your data and apply a\u2026 Read More &raquo;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\" \/>\n<meta property=\"og:site_name\" content=\"Bill White\" \/>\n<meta property=\"article:published_time\" content=\"2015-01-12T21:55:49+00:00\" \/>\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=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\"},\"author\":{\"name\":\"Bill White\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\"},\"headline\":\"D3 in 3D: Combining d3.js and three.js\",\"datePublished\":\"2015-01-12T21:55:49+00:00\",\"dateModified\":\"2015-01-12T21:55:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\"},\"wordCount\":762,\"commentCount\":6,\"publisher\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314\"},\"keywords\":[\"d3\",\"javascript\",\"threejs\"],\"articleSection\":[\"d3\",\"HTML5\",\"Javascript\",\"threejs\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\",\"url\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\",\"name\":\"D3 in 3D: Combining d3.js and three.js - Bill White\",\"isPartOf\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/#website\"},\"datePublished\":\"2015-01-12T21:55:49+00:00\",\"dateModified\":\"2015-01-12T21:55:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/billdwhite.com\/wordpress\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"D3 in 3D: Combining d3.js and three.js\"}]},{\"@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 in 3D: Combining d3.js and three.js - 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\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/","og_locale":"en_US","og_type":"article","og_title":"D3 in 3D: Combining d3.js and three.js - Bill White","og_description":"Along with d3, the three.js library is one of the most powerful javascript libraries available for creating slick visualizations. I wondered if it would be possible to create data visualizations in threejs as easily as I had done using d3. One thing that d3 does very well is to take your data and apply a\u2026 Read More &raquo;","og_url":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/","og_site_name":"Bill White","article_published_time":"2015-01-12T21:55:49+00:00","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":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#article","isPartOf":{"@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/"},"author":{"name":"Bill White","@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314"},"headline":"D3 in 3D: Combining d3.js and three.js","datePublished":"2015-01-12T21:55:49+00:00","dateModified":"2015-01-12T21:55:49+00:00","mainEntityOfPage":{"@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/"},"wordCount":762,"commentCount":6,"publisher":{"@id":"https:\/\/billdwhite.com\/wordpress\/#\/schema\/person\/ea6b87554d0eed13a0152765dd01d314"},"keywords":["d3","javascript","threejs"],"articleSection":["d3","HTML5","Javascript","threejs"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/","url":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/","name":"D3 in 3D: Combining d3.js and three.js - Bill White","isPartOf":{"@id":"https:\/\/billdwhite.com\/wordpress\/#website"},"datePublished":"2015-01-12T21:55:49+00:00","dateModified":"2015-01-12T21:55:49+00:00","breadcrumb":{"@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/billdwhite.com\/wordpress\/2015\/01\/12\/d3-in-3d-combining-d3-js-and-three-js\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/billdwhite.com\/wordpress\/"},{"@type":"ListItem","position":2,"name":"D3 in 3D: Combining d3.js and three.js"}]},{"@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\/1053","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=1053"}],"version-history":[{"count":0,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/posts\/1053\/revisions"}],"wp:attachment":[{"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/media?parent=1053"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/categories?post=1053"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/billdwhite.com\/wordpress\/wp-json\/wp\/v2\/tags?post=1053"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}