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

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

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

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

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

Q&A

解決済

2回答

563閲覧

Uncaught TypeError: Cannot read property '0' of undefined at init (point_object.html:81)

aiai8976

総合スコア112

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

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

0グッド

0クリップ

投稿2019/06/13 05:38

前提・実現したいこと

現在、csvファイルに書かれている距離データと角度データを読み込んでthree.jsの3次元上に点を打ちたいと考えております。
csvファイルを読み込めていることはアラート関数で確認できましたが、読み込んで格納した二次元配列をうまく渡すことができません。
以下のようなエラーが出てしまいます。
分かる方がいましたら、コメントお願いします。

発生している問題・エラーメッセージ

Uncaught TypeError: Cannot read property '0' of undefined at init (point_object.html:81)

該当のソースコード

該当しているところはinit関数の中のgetCSV()の部分とgetCSV()を見ていただけたらと思います。

point_object.html

1<html> 2<head> 3 <style> 4 div#WebGL-area{ 5 width: 900px; 6 height: 600px; 7 } 8 </style> 9 <script type="text/javascript" src="../three.js-master/build/three.min.js"></script> 10 <script type="text/javascript" src="js/OrbitControls.js"></script> 11 <script type="text/javascript"> 12 //CSVファイルを読み込む関数getCSV()の定義 13 function getCSV(){ 14 var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成 15 req.open("get", "test.csv", true); // アクセスするファイルを指定 16 req.send(null); // HTTPリクエストの発行 17 18 // レスポンスが返ってきたらconvertCSVtoArray()を呼ぶ 19 req.onload = function(){ 20 return convertCSVtoArray(req.responseText); // 渡されるのは読み込んだCSVデータ 21 } 22 } 23 24 // 読み込んだCSVデータを二次元配列に変換する関数convertCSVtoArray()の定義 25 function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される 26 var result = []; // 最終的な二次元配列を入れるための配列 27 var tmp = str.split("\n"); // 改行を区切り文字として行を要素とした配列を生成 28 29 // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成 30 for(var i=0;i<tmp.length;++i){ 31 result[i] = tmp[i].split(','); 32 } 33 alert(result[0][1]) 34 return result; 35 } 36 37 function init() { 38 ///////////////////////three.js初期化/////////////////////// 39 40 var scene = new THREE.Scene(); //仮想空間に各種オブジェクトを配置するシーンオブジェクト生成 41 42 var renderer = new THREE.WebGLRenderer(); //レンダラーオブジェクトの生成 43 renderer.setSize(900, 600); //レンダラーサイズの設定 44 45 //自動生成されるcanvas要素を指定した要素の子要素として追加 46 document.getElementById("WebGL-area").appendChild(renderer.domElement); 47 48 49 ///////////////////カメラ初期化///////////////////// 50 51 var camera = new THREE.PerspectiveCamera(45, 1.5, 0.1, 1000); //透視投影カメラオブジェクト生成 52 //(fov:視野角,aspect:縦横比,near:カメラから視体積の手前までの距離,far:カメラから視体積の奥までの距離) 53 54 camera.position.set(30, 45, 30); 55 camera.lookAt(scene.position); //カメラの視野中心座標 56 57 var controls = new THREE.OrbitControls(camera); //カメラコントローラー生成 58 controls.autoRotate = true; //自動周回 59 60 61 62 ///////////////////オブジェクト初期化/////////////////// 63 64 // 座標軸を表示 65 var axes = new THREE.AxisHelper(50); //引数は線の長さ 66 scene.add(axes); 67 68 //形状オブジェクトの宣言と生成 69 var geometry= new THREE.Geometry(); 70 //頂点座標データの追加 71 /*for(i=0;i<30;i++){ 72 geometry.vertices[i]= new THREE.Vector3(30,30,30-i); 73 } 74 for(i;i<60;i++){ 75 geometry.vertices[i]= new THREE.Vector3(i-30,30,30); 76 }*/ 77 var data=[]; 78 data=getCSV(); 79 80 for(var i=0;i<1000;i++){ 81 geometry.vertices[i]= new THREE.Vector3(data[i][0] * Math.cos( data[i][1] * (Math.PI / 180) ),data[i][0] * Math.sin( data[i][1] * (Math.PI / 180) )); 82 } 83 84 85 86 //geometry.vertices[0]= new THREE.Vector3(30,30,28);//(x軸,z軸,y軸) 87 //geometry.vertices[1]= new THREE.Vector3(30,30,29); 88 //geometry.vertices[2]= new THREE.Vector3(30,30,30); 89 //材質オブジェクトの宣言と生成 90 var material=new THREE.ParticleBasicMaterial({color: 0xFF0000, size: 1.0}); 91 //点オブジェクトの生成 92 particles = new THREE.ParticleSystem(geometry,material); 93 //点オブジェクトのシーンへの追加 94 scene.add(particles) 95 96 97 98 //////////////////描画関数の定義////////////////////// 99 100 render(); 101 102 function render() { 103 controls.update(); //再描画 104 requestAnimationFrame(render); //アニメーション実装時など、再描画が頻繁に行われる処理に使えるメソッド 105 renderer.render(scene, camera); 106 } 107 } 108 window.onload = init 109 </script> 110 111</head> 112 113<body> 114 <div id="WebGL-area"></div> 115</body> 116</html> 117

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

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

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

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

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

guest

回答2

0

ベストアンサー

getCSVPromise を返し、init 関数を async function として宣言し、getCSV 関数実行時に await演算子を使用すると、あまりコードをいじらずに済みます。

js

1function getCSV() { 2 return new Promise((resolve, reject) => { 3 var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成 4 req.open("get", "test.csv", true); // アクセスするファイルを指定 5 req.onload = () => { 6 if (req.readyState === 4 && req.status === 200) { 7 resolve(convertCSVtoArray(req.responseText)); 8 } else { 9 reject(new Error(req.statusText)); 10 } 11 }; 12 req.onerror = () => { 13 reject(new Error(req.statusText)); 14 }; 15 req.send(null); // HTTPリクエストの発行 16 }); 17} 18 19// 省略 20 21async function init() { 22 23// 省略 24 25var data=[]; 26data = await getCSV(); 27 28// 以下省略

投稿2019/06/13 06:47

編集2019/06/13 06:59
YukiYamashina

総合スコア1011

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

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

aiai8976

2019/06/13 06:56

コメントありがとうございます。 やってみたところ、xhrが定義されていないと出たのでreqに直しました。 そうするとreq.onloadでエラーとなりました。 何が問題なのでしょうか。
YukiYamashina

2019/06/13 07:06 編集

申し訳ないです、タイポです。回答修正しておきます。 req.onload でエラーということは IE を利用されてますでしょうか?
aiai8976

2019/06/13 07:15

chromを使っています。
aiai8976

2019/06/13 07:16

sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args -allow-file-access-from-files このコマンドで立ち上げています。
YukiYamashina

2019/06/13 07:42 編集

おそらく状況としてはプロトコルが file なため、req.status に 0 が返ってきてる(httpであれば 200 が返ってきます)のだと思います。それで req.status === 200 に引っかかって Promise が reject されてるのではないかと。ひとまず req.status === 200 を req.status === 0 にしてみてください。 ファイルの読み込みエラーとかを気にしないのであれば、req.onload の中を resolve(convertCSVtoArray(req.responseText)); だけにしてみてもいいと思います。
aiai8976

2019/06/13 13:56

req.status === 0にしてみたらいけました! ありがとうございます!
aiai8976

2019/06/14 06:08

何度もすいません。 asyncとawaitがよくわかっていないのですが、実際非同期通信を行うのはgetCSVなのにそこではなく、initにasyncとするのは何故なのか。また、getCSVが非同期通信なのにawaitとしてしまっては同期通信になってしまうのではないかと思うのですが、どうお考えですか?
YukiYamashina

2019/06/14 06:15

await は async function 内でないと利用できないからです。一度 init を async なしにしてみてください。await is only valid in async function というエラーが表示されると思います。
aiai8976

2019/06/14 06:30

解答ありがとうございます。 initをasyncにする理由はわかりました。 非同期通信getCSVをawaitにするのはどうしてでしょうか。
YukiYamashina

2019/06/14 06:53 編集

await という言葉の通り、非同期通信である getCSV が完了するのを「待つ」ためです。 data = await getCSV() の下で、data 配列を使って geometry.vertices[i] をセットしていますが、await でファイルの取得と配列への変換という非同期処理が終わるのを待つことによって、data 配列にCSVの値が入って正常に処理を進めることができるようになります。
aiai8976

2019/06/14 06:59

なるほど。 つまり非同期通信と言いながら同期通信ということですよね。 CSVファイルを読み込むのは非同期通信じゃなくてもできたんですかね泣
YukiYamashina

2019/06/14 07:20

いえ、違います。 XMLHttpRequest によるファイルの読み込みは非同期処理です。 async / await を使えば「非同期処理を同期処理のように書ける」ということです。
aiai8976

2019/06/14 14:30

getCSVが非同期通信でもメインの方でawait getCSV()としていれば、待つ(プログラム一時停止する)ことになりますよね。 待つってことは同期処理ってことではないですか? すいません理解力乏しくて。
YukiYamashina

2019/06/14 15:29

私の語彙力では上のコメント以上の説明は難しいです。申し訳ないです。 この辺りのことを別の質問であげてみてはいかがでしょうか? 私よりもうまく説明できる方がいらっしゃると思います。
aiai8976

2019/06/15 05:16

すいません他の方の意見も聞きたいと思います。 お時間いただきありがとうございました。
guest

0

getCSV() は何も return していません。
Ajax 非同期通信の場合、getCSV() の実行後に req.onload の function が呼ばれるので、そこですべて完了させてください。

投稿2019/06/13 06:13

編集2019/06/13 06:14
x_x

総合スコア13749

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

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

aiai8976

2019/06/13 06:18

なるほど。 逆に関数にするのをやめて、関数の中の処理をそのままinit()の中で行うことは可能でしょうか?
x_x

2019/06/13 06:23

getCSV() の実行後と言いましたが、init() の後です。 「レスポンスが返ってきたら」というコメントの通り、サーバーが応答するまでは呼ばれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問