質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
D3.js

D3.jsとは、データに基づいてHTMLやSVGドキュメントを編集するために作られた、小規模なオープンソースのJavaScript可視化ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

3186閲覧

D3.jsにおいて、開閉するtreeグラフを複数表示する方法

wi-fi

総合スコア10

D3.js

D3.jsとは、データに基づいてHTMLやSVGドキュメントを編集するために作られた、小規模なオープンソースのJavaScript可視化ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2018/08/16 13:02

編集2018/08/16 13:07

前提・実現したいこと

JavaScript(D3.js)でこちらのURL(D3.js v4/v5 treeを開閉する方法 – サンプル)を参考にして、開閉するグラフを作成しています。
このグラフを同じページに複数作成したいのです。
下記のソースコードにより、複数表示自体はできるのですが、開閉する機能を全てにつけることができません。
一番下に描画されたグラフには、開閉機能が付いているのですが、それ以外のグラフは、ノードをクリックしても動きません。
これを、全ての木に対して、開閉するグラフにしようとしているのですが、どのように作成すればよいでしょうか。
当方D3.js初心者ですよろしくお願いいたします。

該当のソースコード

html

1<!DOCTYPE html> 2<html> 3 4 <head> 5 <meta charset="utf-8"> 6 <title>D3 collapsible tree in v4/v5</title> 7 <!-- 1. スタイルの設定 --> 8 <style> 9 .node { 10 cursor: pointer; 11 } 12 13 .node circle { 14 fill: #fff; 15 stroke: steelblue; 16 stroke-width: 1.5px; 17 } 18 19 .link { 20 fill: none; 21 stroke: #555; 22 stroke-opacity: 0.6; 23 stroke-width: 1.5px; 24 } 25 </style> 26 </head> 27 28 <body> 29 <svg id="tree0" width="800" height="600"></svg> 30 <svg id="tree1" width="800" height="600"></svg> 31 <svg id="tree2" width="800" height="600"></svg> 32 <script src="https://d3js.org/d3.v5.min.js"></script> 33 <script> 34 for(var j=0;j<3;j++){ 35 // 2. 描画用データの準備 36 var width = document.querySelector(`#tree${j}`).clientWidth; 37 var height = document.querySelector(`#tree${j}`).clientHeight; 38 var data = { 39 "name": "A", 40 "children": [ 41 { "name": "B" }, 42 { 43 "name": "C", 44 "children": [{ "name": "D" }, { "name": "E" }, { "name": "F" }] 45 }, 46 { "name": "G" }, 47 { 48 "name": "H", 49 "children": [{ "name": "I" }, { "name": "J" }] 50 }, 51 { "name": "K" } 52 ] 53 }; 54 55 // 3. 描画用データの変換 56 root = d3.hierarchy(data); 57 root.x0 = height / 2; 58 root.y0 = 0; 59 60 var tree = d3.tree().size([height, width - 160]); 61 62 // 4. svgデータの描画用データの変換 63 g = d3.select(`#tree${j}`).append("g").attr("transform", "translate(80,0)"); 64 update(root); 65 } 66 67 // 5. クリック時の呼び出し関数 68 function toggle(d) { 69 if(d.children) { 70 d._children = d.children; 71 d.children = null; 72 } else { 73 d.children = d._children; 74 d._children = null; 75 } 76 } 77 78 // 6.svg要素の更新関数 79 var i = 0; 80 function update(source) { 81 82 // tree レイアウト位置を計算 83 tree(root); 84 85 // 子、孫方向の位置設定 86 root.each(function(d) { d.y = d.depth * 320; }); 87 88 // ノードデータをsvg要素に設定 89 var node = g.selectAll('.node') 90 .data(root.descendants(), function(d) { return d.id || (d.id = ++i); }); 91 92 // ノード enter領域の設定 93 var nodeEnter = node 94 .enter() 95 .append("g") 96 .attr("class", "node") 97 .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) 98 .on("click", function(d) { 99 toggle(d); 100 update(d); 101 }); 102 103 nodeEnter.append("circle") 104 .attr("r", 5) 105 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 106 107 nodeEnter.append("text") 108 .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) 109 .attr("dy", "3") 110 .attr("font-size", "150%") 111 .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) 112 .text(function(d) { return d.data.name; }) 113 .style("fill-opacity", 1e-6); 114 115 // ノード enter+update領域の設定 116 var nodeUpdate = nodeEnter.merge(node); 117 var duration = 500; 118 119 nodeUpdate.transition() 120 .duration(duration) 121 .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); 122 123 nodeUpdate.select("circle") 124 .attr("r", 8) 125 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 126 127 nodeUpdate.select("text") 128 .style("fill-opacity", 1); 129 130 // ノード exit領域の設定 131 var nodeExit = node 132 .exit() 133 .transition() 134 .duration(duration) 135 .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) 136 .remove(); 137 138 nodeExit.select("circle") 139 .attr("r", 1e-6); 140 141 nodeExit.select("text") 142 .style("fill-opacity", 1e-6); 143 144 // リンクデータをsvg要素に設定 145 var link = g.selectAll(".link") 146 .data(root.links(), function(d) { return d.target.id; }); 147 148 // リンク enter領域のsvg要素定義 149 var linkEnter = link.enter().insert('path', "g") 150 .attr("class", "link") 151 .attr("d", d3.linkHorizontal() 152 .x(function(d) { return source.y0; }) 153 .y(function(d) { return source.x0; })); 154 155 // リンク enter+update領域の設定 156 var linkUpdate = linkEnter.merge(link); 157 linkUpdate 158 .transition() 159 .duration(duration) 160 .attr("d", d3.linkHorizontal() 161 .x(function(d) { return d.y; }) 162 .y(function(d) { return d.x; })); 163 164 // リンク exit領域の設定 165 link 166 .exit() 167 .transition() 168 .duration(duration) 169 .attr("d", d3.linkHorizontal() 170 .x(function(d) { return source.y; }) 171 .y(function(d) { return source.x; }) 172 ) 173 .remove(); 174 175 // 次の動作のために現在位置を記憶 176 node.each(function(d) { 177 d.x0 = d.x; 178 d.y0 = d.y; 179 }); 180 } 181 182 </script> 183 </body> 184 185</html>

試したこと

rootやgといった変数を自分で新たに設定したり、update関数の中の変数を全てグローバルスコープにしたりと色々試したのですが実現せず・・・
どうやら、 (///ノードデータをsvg要素に設定) とコメントアウトに書いてる部分 のidの設定が上手くいってない模様・・・
それ以外にも原因はあると思いますが。

補足情報(FW/ツールのバージョンなど)

D3.js v5
ブラウザはChromeを使用しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

update関数でグローバル変数使ってるせいですね
ちょっと強引ですが(多分このデータでしか動かない気もしますが)

html

1<!DOCTYPE html> 2<html> 3 4 <head> 5 <meta charset="utf-8"> 6 <title>D3 collapsible tree in v4/v5</title> 7 <!-- 1. スタイルの設定 --> 8 <style> 9 .node { 10 cursor: pointer; 11 } 12 13 .node circle { 14 fill: #fff; 15 stroke: steelblue; 16 stroke-width: 1.5px; 17 } 18 19 .link { 20 fill: none; 21 stroke: #555; 22 stroke-opacity: 0.6; 23 stroke-width: 1.5px; 24 } 25 </style> 26 </head> 27 28 <body> 29 <svg id="tree0" width="800" height="600"></svg> 30 <svg id="tree1" width="800" height="600"></svg> 31 <svg id="tree2" width="800" height="600"></svg> 32 <script src="https://d3js.org/d3.v5.min.js"></script> 33 <script> 34 for(var j=0;j<3;j++){ 35 // 2. 描画用データの準備 36 var width = document.querySelector(`#tree${j}`).clientWidth; 37 var height = document.querySelector(`#tree${j}`).clientHeight; 38 var data = { 39 "name": "A", 40 "children": [ 41 { "name": "B" }, 42 { 43 "name": "C", 44 "children": [{ "name": "D" }, { "name": "E" }, { "name": "F" }] 45 }, 46 { "name": "G" }, 47 { 48 "name": "H", 49 "children": [{ "name": "I" }, { "name": "J" }] 50 }, 51 { "name": "K" } 52 ] 53 }; 54 55 // 3. 描画用データの変換 56 var root = d3.hierarchy(data); 57 root.x0 = height / 2; 58 root.y0 = 0; 59 60 root.root = root; 61 62 root.tree = d3.tree().size([height, width - 160]); 63 64 // 4. svgデータの描画用データの変換 65 root.g = d3.select(`#tree${j}`).append("g").attr("transform", "translate(80,0)"); 66 update(root, root, root.g, root.tree); 67 } 68 69 // 5. クリック時の呼び出し関数 70 function toggle(d) { 71 if(d.children) { 72 d._children = d.children; 73 d.children = null; 74 } else { 75 d.children = d._children; 76 d._children = null; 77 } 78 } 79 80 // 6.svg要素の更新関数 81 var i = 0; 82 function update(source, root, g, tree) { 83 // tree レイアウト位置を計算 84 tree(root); 85 86 // 子、孫方向の位置設定 87 root.each(function(d) { d.y = d.depth * 320; }); 88 89 // ノードデータをsvg要素に設定 90 var node = g.selectAll('.node') 91 .data(root.descendants(), function(d) { return d.id || (d.id = ++i); }); 92 93 // ノード enter領域の設定 94 var nodeEnter = node 95 .enter() 96 .append("g") 97 .attr("class", "node") 98 .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) 99 .on("click", function(d) { 100 toggle(d); 101 update(d, 102 d.parent ? d.parent.root : d.root, 103 d.parent ? d.parent.g : d.g, 104 d.parent ? d.parent.tree : d.tree 105 ); 106 }); 107 108 nodeEnter.append("circle") 109 .attr("r", 5) 110 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 111 112 nodeEnter.append("text") 113 .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) 114 .attr("dy", "3") 115 .attr("font-size", "150%") 116 .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) 117 .text(function(d) { return d.data.name; }) 118 .style("fill-opacity", 1e-6); 119 120 // ノード enter+update領域の設定 121 var nodeUpdate = nodeEnter.merge(node); 122 var duration = 500; 123 124 nodeUpdate.transition() 125 .duration(duration) 126 .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); 127 128 nodeUpdate.select("circle") 129 .attr("r", 8) 130 .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 131 132 nodeUpdate.select("text") 133 .style("fill-opacity", 1); 134 135 // ノード exit領域の設定 136 var nodeExit = node 137 .exit() 138 .transition() 139 .duration(duration) 140 .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) 141 .remove(); 142 143 nodeExit.select("circle") 144 .attr("r", 1e-6); 145 146 nodeExit.select("text") 147 .style("fill-opacity", 1e-6); 148 149 // リンクデータをsvg要素に設定 150 var link = g.selectAll(".link") 151 .data(root.links(), function(d) { return d.target.id; }); 152 153 // リンク enter領域のsvg要素定義 154 var linkEnter = link.enter().insert('path', "g") 155 .attr("class", "link") 156 .attr("d", d3.linkHorizontal() 157 .x(function(d) { return source.y0; }) 158 .y(function(d) { return source.x0; })); 159 160 // リンク enter+update領域の設定 161 var linkUpdate = linkEnter.merge(link); 162 linkUpdate 163 .transition() 164 .duration(duration) 165 .attr("d", d3.linkHorizontal() 166 .x(function(d) { return d.y; }) 167 .y(function(d) { return d.x; })); 168 169 // リンク exit領域の設定 170 link 171 .exit() 172 .transition() 173 .duration(duration) 174 .attr("d", d3.linkHorizontal() 175 .x(function(d) { return source.y; }) 176 .y(function(d) { return source.x; }) 177 ) 178 .remove(); 179 180 // 次の動作のために現在位置を記憶 181 node.each(function(d) { 182 d.x0 = d.x; 183 d.y0 = d.y; 184 }); 185 } 186 187 </script> 188 </body> 189 190</html>

投稿2018/08/17 06:05

rururu3

総合スコア5545

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wi-fi

2018/08/17 08:57

解答いただいた方法で、現在作っているWEBページにて正常に動かすことができました。 困っていたので、本当に助かりました。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問