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

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

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

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Three.js

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

1回答

2535閲覧

Uncaught TypeError: Cannot read property '0' of undefined at init

aiai8976

総合スコア112

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Three.js

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/07/12 05:07

編集2019/07/12 07:19

前提・実現したいこと

現在、csvファイルを読み込んでthree.jsの座標上に点を打ちたいと考えております。
しかしながら、以下のようなエラーが発生しており、どのようにすればいいのかわかりません。
一応、変数resultに値が入っていないのかと思い、alertで確認したのですが、きちんと値は入っていました。
受け渡しで何かミスがあるのでしょうか。

getCSV()でreturnする前のresultの中身をアラートで確認したところ、ちゃんと値が入っていました。
しかし、この返り値を受け取るdata配列をその直後にalertで確かめてみると中身がありませんでした。
つまり渡すところでエラーが起きているみたいです。
javascriptの多次元配列の渡し方は調べてみてもなかなかヒットしません。
お分かりの方いましたら回答お願いいたします。

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

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

ここでいう110行目は以下のソースの

geometry.vertices[i]=

この部分になっています。
つまり、dataにうまく結果が入っておらず、定義されていないor nullとなっているのではないかと思います。

非同期処理の場合のエラーは以下のようになっています。

three.min.js:672 Uncaught (in promise) TypeError: Cannot convert undefined or null to object at Function.keys (<anonymous>) at ac.updateMorphTargets (three.min.js:672) at new ac (three.min.js:216) at new l.ParticleSystem (three.min.js:980) at init (layout.html:87)

該当のソースコード

sample.html

sample.html

1<html> 2<head> 3 <script type="text/javascript" src="three.js-master/build/three.min.js"></script> 4 <script type="text/javascript" src="js/OrbitControls.js"></script> 5</head> 6 7<body> 8 <div id="WebGL-area"></div> 9 10 <script type="text/javascript"> 11 12 13 //CSVファイルを読み込む関数getCSV()の定義 14function getCSV(){ 15 var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成 16 req.open("get", "test.csv", true); // アクセスするファイルを指定 17 req.send(null); // HTTPリクエストの発行 18 19 // レスポンスが返ってきたらconvertCSVtoArray()を呼ぶ 20 req.onload = function(){ 21 var result=convertCSVtoArray(req.responseText); // 渡されるのは読み込んだCSVデータ 22 return result; 23 } 24} 25 26// 読み込んだCSVデータを二次元配列に変換する関数convertCSVtoArray()の定義 27function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される 28 var result = []; // 最終的な二次元配列を入れるための配列 29 var tmp = str.split("\n"); // 改行を区切り文字として行を要素とした配列を生成 30 31 // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成 32 for(var i=0;i<tmp.length;++i){ 33 result[i] = tmp[i].split(','); 34 } 35 alert(result); 36 return result; 37} 38 39 40 41 42 function init() { 43 var scene = new THREE.Scene(); 44 45 var renderer = new THREE.WebGLRenderer(); 46 renderer.setSize(900, 600); 47 48 document.getElementById("WebGL-area").appendChild(renderer.domElement); 49 50 51 52 53 var camera = new THREE.PerspectiveCamera(45, 1.5, 0.1, 1000); 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(100); 66 scene.add(axes); 67 68 //形状オブジェクトの宣言と生成 69 var geometry= new THREE.Geometry(); 70 var data=[]; 71 //data = await getCSV(); 72 data = getCSV(); 73 74 for(var i=0;i<1000;i++){ 75 geometry.vertices[i]= new THREE.Vector3((data[i][0] * Math.cos( data[i][1] * (Math.PI / 180) ))/2, 76 0, 77 (data[i][0] * Math.sin( data[i][1] * (Math.PI / 180) ))/2); 78 } 79 80 //材質オブジェクトの宣言と生成 81 var material=new THREE.ParticleBasicMaterial({color: 0xFF0000, size: 10.0}); 82 //点オブジェクトの生成 83 var particles = new THREE.ParticleSystem(geometry,material); 84 //点オブジェクトのシーンへの追加 85 scene.add(particles); 86 87 88 89 render(); 90 91 function render() { 92 controls.update(); 93 requestAnimationFrame(render); 94 renderer.render(scene, camera); 95 } 96 } 97 window.onload = init 98 </script> 99</body> 100</html> 101

非同期処理ver

<html> <head> <script type="text/javascript" src="three.js-master/build/three.min.js"></script> <script type="text/javascript" src="js/OrbitControls.js"></script> </head> <body> <div id="WebGL-area"></div> <script type="text/javascript"> function getCSV() { //promiseを使うことで簡潔に記述できる return new Promise((resolve, reject) => { //resolveまたはrejectの結果を返す var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成、サーバと非同期通信するためのAPI req.open("get", "test.csv", true); // アクセスするファイルを指定 //受信が成功した時に呼び出されるイベント req.onload = () => { //通信が正常に終了したかを確認する if (req.readyState === 4 && req.status === 200) { resolve(convertCSVtoArray(req.responseText)); } else { alert(req.status); reject(new Error(req.statusText)); } }; //受信が失敗した時に呼び出されるイベント req.onerror = () => { reject(new Error(req.statusText)); }; req.send(null); // HTTPリクエストの発行 }); } // 読み込んだCSVデータを二次元配列に変換する関数convertCSVtoArray()の定義 function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される var result = []; // 最終的な二次元配列を入れるための配列 var tmp = str.split("\n"); // 改行を区切り文字として行を要素とした配列を生成 // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成 for(var i=0;i<tmp.length;++i){ result[i] = tmp[i].split(','); } return result; } async function init() { var scene = new THREE.Scene(); var renderer = new THREE.WebGLRenderer(); renderer.setSize(900, 600); document.getElementById("WebGL-area").appendChild(renderer.domElement); var camera = new THREE.PerspectiveCamera(45, 1.5, 0.1, 1000); camera.position.set(30, 45, 30); camera.lookAt(scene.position); var controls = new THREE.OrbitControls(camera); controls.autoRotate = true; //自動周回 // 座標軸を表示 var axes = new THREE.AxisHelper(100); scene.add(axes); //形状オブジェクトの宣言と生成 var geometry= new THREE.Geometry(); var data=[]; data = await getCSV(); for(var i=0;i<1000;i++){ geometry.vertices[i]= new THREE.Vector3((data[i][0] * Math.cos( data[i][1] * (Math.PI / 180) ))/2, 0, (data[i][0] * Math.sin( data[i][1] * (Math.PI / 180) ))/2); } //材質オブジェクトの宣言と生成 var material=new THREE.ParticleBasicMaterial({color: 0xFF0000, size: 10.0}); //点オブジェクトの生成 var particles = new THREE.ParticleSystem(geometry,material); //点オブジェクトのシーンへの追加 scene.add(particles); render(); function render() { controls.update(); requestAnimationFrame(render); renderer.render(scene, camera); } } window.onload = init </script> </body> </html>

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

ブラウザ:chrom

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

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

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

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

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

guest

回答1

0

問題はいくつかあると思います。

  1. req.onloadを設定するのが遅い。

→sendの前に設定してください。
0. 非同期実行している(req.open("get", "test.csv", true);)が、終了を待っていない。
→getCSV実行後、直ちにはdataは格納されないと考えてください。
0. getCSVが値を返していない。

解決方法は二通り、
0. csvの読み取りを同期実行にする。
0. getCSVより後の処理は非同期実行完了後に実行する。

同期および非同期リクエスト

  1. の"getCSVより後の処理は非同期実行完了後に実行する。"について追記です。

XMLHttpRequestで非同期でデータを取得する場合、普通はどこかのオブジェクトに格納するだけだったり、コールバック関数に取得結果を渡したりすると思います。
非同期なので、その処理の終了は待てません。そのため、getCSVの呼び出し直後にdataにアクセスしても、読み込み完了していなければデータはありません。ただし、呼び出したら直ちに結果が返ってくるほど軽く、回線も早ければ動くかもしれません。

最初に非同期実行し、それ以外の処理はコールバックにするサンプル

function getCSV(callback) { var req = new XMLHttpRequest(); req.open("get", "test.csv", true); req.onload = () => { if (req.readyState === 4 && req.status === 200) { callback(convertCSVtoArray(req.responseText)); // これ } else { alert(req.status); } }; req.onerror = () => { alert(req.status); }; req.send(null); } function preInit() { getCSV(init); } // getCSV以外をやる function init(data) { for(var i=0;i<data.length;i++){ console.log("i : " + i); for(var j = 0; j < data[i].length; j++) { console.log("j : " + j); console.log(data[i][j] + ""); } } }

投稿2019/07/12 07:08

編集2019/07/16 06:33
moredeep

総合スコア1507

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

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

aiai8976

2019/07/12 07:20

コメントありがとうございます。 実はこのソースの前に非同期処理を行うようにしていたものがあります。 こちらだと解決方法を満たしていると思うのですが、、、 確認お願いします。
moredeep

2019/07/12 07:32

非同期Verでもだめってことですかね? getCSVの中身は非同期で実行されますが、さらに非同期でRequestを投げており、その終了を待っていないように見えます。 req.openの第三引数をfalseにしてもだめですか?
aiai8976

2019/07/12 07:59

そうですね。 falseに変えてもダメでした。 エラーもundefined or nullのままです。
moredeep

2019/07/12 08:03

あ、falseにしただけですかね? 張り付けた参考サイトを参照し、一部処理を修正してください。 とりあえずはreq.onloadの中の処理を、send後に実行するように外に出すだけでかなと思います。
aiai8976

2019/07/12 08:26

sendもあとにしましたがダメでした。 なぜ、オブジェクトを渡せなくなっているのでしょうか。
moredeep

2019/07/12 08:41

非同期はやめたほうがいい気がしてきました。 差し当たり、上のコードをベースに、 Requestを同期処理化(req.openの第三引数をfalseに変更)、 不要行を削除("req.onload = function(){"とそれに対応する閉じ括弧) して実行してみてください。
aiai8976

2019/07/13 07:41

了解です。 非同期がダメな理由は何でしょうか? 変更しましたが、エラー表示は同じでした。
aiai8976

2019/07/13 07:42

実は以前非同期処理で点の表示までできていたのですが、放置していてもう一度やってみるとできなくなっていたという状態なんです。
moredeep

2019/07/16 06:35

遅くなってすみません。 非同期がダメなわけではないです。ただ、原因の切り分けが面倒なので、一度同期で動くようにして、それから非同期にした方が早いかなと。 以前は出来ていたということでちょっと追記してみました。プラスで、取得するcsvデータは完全であるかを確認してみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問