ExcelVBAマクロ exce.liveクラウドのデモ紹介

プログラミング

前回記事にて「exce.liveクラウド」について紹介しました。

今回の記事ではこの「exce.liveクラウド」を使って作ったデモが公開されたので紹介します。

exce.liveクラウドのデモ

exce.liveクラウドの公式ページにてVBAidとコラボしたデモを公開中です。

exce.live デモサンプル - エクセリブ クラウド
ダウンロード サンプルプログラム (xlsm形式) 856KB ※PCにダウンロードし、ご自身のアカウントの認

第一弾はいきさん(@aero_iki)による「Excelスピログラフ with exce.live」です。

そして第二弾は僕が作った「3Dモデル回転」です。

「3Dモデル回転」の全体構成

「3Dモデル回転」は以下の構成になっています。

送信用ページはHTML形式でJavaScriptを埋め込み、スマホのジャイロセンサから傾きを取得し、その情報をexce.liveクラウドへメッセージ送信します。

受信用Excelがそのメッセージを受信するとシートチェンジイベントが実行され、受け取ったメッセージの値に合わせて3Dモデルを回転しています。

この構成の中作成したのはHTMLファイル1つとExcelファイル1つだけです。

メッセージのやりとりは全てexce.liveクラウドに任せてしまえるので本当に簡単に外部情報をExcel内に取り込む事ができます。

ソース解説

ソースはデモページからダウンロードできます。

送信用HTML

送信用HTMLはJavaScriptを埋め込んでいます。

順番に何をやっているかを解説していきます。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sensor</title>
<script>
// 変数「token」に送信トークンの文字列を設定する必要があります
// getパラメータでセットしてください。
var token = "";
var cur_a = 0;
var cur_b = 0;
var cur_g = 0;
var last_a = 0;
var last_b = 0;
var last_g = 0;
var checked = false;
var last_checked = false;

var arr_a = [0,0,0];
var arr_b = [0,0,0];
var arr_g = [0,0,0];

//ジャイロ情報取得
window.addEventListener("deviceorientation", function(evt){
	tmp_a = evt.alpha;
	tmp_b = evt.beta;
	tmp_g = evt.gamma;
	
	// 移動平均
    var sum_a = 0;
    var sum_b = 0;
    var sum_g = 0;
    for (var i=0; i<arr_a.length-1; i++) {
        arr_a[i] = arr_a[i+1];
        sum_a += arr_a[i];
        arr_b[i] = arr_b[i+1];
        sum_b += arr_b[i];
        arr_g[i] = arr_g[i+1];
        sum_g += arr_g[i];
    }
    arr_a[arr_a.length-1] = tmp_a;
    sum_a += tmp_a;
    sum_a /= arr_a.length;
    arr_b[arr_b.length-1] = tmp_b;
    sum_b += tmp_b;
    sum_b /= arr_b.length;
    arr_g[arr_g.length-1] = tmp_g;
    sum_g += tmp_g;
    sum_g /= arr_g.length;
    
    tmp_a =  Math.round(sum_a / 15) * 15;
    tmp_b =  Math.round(sum_b / 15) * 15;
    tmp_g =  Math.round(sum_g / 15) * 15;

    cur_a = tmp_a
    cur_b = tmp_b
    cur_g = tmp_g
    
	//確認用に変数の内容をページに出力するHTMLを組み立てる
	var html ="";
	html += "Z回転(alpha):" + cur_a + "<br>";
	html += "X回転(beta):" + cur_b + "<br>";
	html += "Y回転(gumma):" + cur_g;
	document.getElementById("gyroscope").innerHTML = html;
}, false);
//送信ボタン処理
window.addEventListener('load',
	function(event){
		var elem = document.getElementById('btn_sendmessage');
		elem.addEventListener('click', sendmessage_reset, false);
	}
, false);

//0.1秒毎の繰り返し処理をセット
window.onload = function(){

	var queryString = window.location.search;
	console.log(queryString);
	var queryObject = new Object();
	if(queryString){
	  queryString = queryString.substring(1);
	  var parameters = queryString.split('&');

	  for (var i = 0; i < parameters.length; i++) {
	    var element = parameters[i].split('=');

	    var paramName = decodeURIComponent(element[0]);
	    var paramValue = decodeURIComponent(element[1]);

	    queryObject[paramName] = paramValue;
	  }
	  
	  token = queryObject.token;
	  console.log(token);
	}

	if ((token==undefined) || (token=="")) {
		document.body.innerHTML = 'tokenをセットしてください';
	}
	else {
		//100ミリ秒毎に関数「sendmessage()」を呼び出す
		setInterval("realtimemessage()", 100);	
	}
}

//リアルタイムメッセージ送信処理
function realtimemessage(event){
	//リアルタイム送信設定になっているかチェックする
	var elem = document.getElementById('cb_realtime');
	checked = elem.checked;
	
	if(checked){
	
		if(cur_a == last_a && cur_b == last_b && cur_g == last_g){
	    } else {

			//前回の値を更新する
			last_a = cur_a;
			last_b = cur_b;
			last_g = cur_g;
			
			//前回と違う値のため送信する
			sendmessage();
		}

	}
	
	last_checked = checked;
	
}

//メッセージ送信処理
function sendmessage(event){
	//キャラクター情報取得
//	var selChar = document.getElementById('sel_char');
//	var num = selChar.selectedIndex;
//	var charID = selChar.options[num].value;
	var charID = "Archdemon";
	//メッセージを組み立てる
	var url = "";
	url += "https://api.exce.live/sendmsg?";
	url += "token=" + token + "&";
	url += "sheet=ajaxtest&";
	url += "msg=";
	url += cur_a + ",";
	url += cur_b + ",";
	url += cur_g + ",";
	url += charID;
	
	var req = new XMLHttpRequest();
	req.open('GET', url);
	req.onreadystatechange = function(event){
		if(req.readyState == 4){
			var text = document.getElementById('text');
			if(req.status == 200){
				text.innerHTML = req.responseText;
			} else {
				text.innerHTML = '送信完了';
			}
		}
	};
	
	req.send();
	
}


function sendmessage_reset(event){
	//キャラクター情報取得
//	var selChar = document.getElementById('sel_char');
//	var num = selChar.selectedIndex;
//	var charID = selChar.options[num].value;
	var charID = "Archdemon";
	//メッセージを組み立てる
	var url = "";
	url += "https://api.exce.live/sendmsg?";
	url += "token=" + token + "&";
	url += "sheet=ajaxtest&";
	url += "msg=";
	url += cur_a + ",";
	url += cur_b + ",";
	url += cur_g + ",";
	url += "reset";
	var req = new XMLHttpRequest();
	req.open('GET', url);
	req.onreadystatechange = function(event){
		if(req.readyState == 4){
			var text = document.getElementById('text');
			if(req.status == 200){
				text.innerHTML = req.responseText;
			} else {
				text.innerHTML = '送信完了';
			}
		}
	};
	
	req.send();
	
}

</script>
</head>
<body>
<h2>ジャイロ</h2>
<div id="gyroscope">0</div>
	<h1>メッセージ送信</h1>
<!--
	キャラクター
	<select id="sel_char">
		<option value="Archdemon">アークデーモン</option>
		<option value="Momon_angry">モーモン(怒)</option>
		<option value="Slime">スライム</option>
	</select><br>
-->
	<input id="cb_realtime" type="checkbox">リアルタイム<br><br>
	<input id="btn_sendmessage" type="button" style="width:90%;padding:8px;font-size:24px;" value="リセット">
	<div id="text">
	</div>

	<br/>
		
	<div style="text-align:center;">
	<img src="https://account.exce.live/daemon.png">
	</div>
	
	<br/>
	
	<div style="text-align:center;">
	<img src="https://account.exce.live/excelive_vbaid.jpg" width="90%">
	</div>
	
</body>
</html>

ジャイロ情報取得

スマホなどのハードウェア側の傾きセンサの値をここで取得します。

確認用のためにジャイロセンサの値をページに表示させています。

送信用のボタン処理と0.1秒毎に送信し続ける処理もここに記載しています。

※0.1秒毎の送信は関数を呼び出しているだけで実際の送信処理は後で説明の関数で行っています。

リアルタイムメッセージ送信処理

0.1秒毎の送信処理を行っています。

無駄な送信を避けるために前回送信時の角度を記憶しておき今回送信しようとしている角度と差が無ければ送信しないようにしています。

exce.liveを使っての送信は別で行っています。

メッセージ送信処理

exce.liveを使って送信をしています。

送信トークンとメッセージを組み合わせた送信用URLを組み立てて送信しています。

レスポンスによって何かリアクションする必要が無かったため送るだけの実装にしました。

ボタン押下時メッセージ送信処理

送信用ボタン押下時のメッセージ送信処理を行います。

リアルタイムメッセージ送信処理とは違い前回の送信情報は考慮していません。

現時点の回転角度をそのまま送信します。

受信用Excel

受信用Excelはシートのチェンジイベントでマクロが実行するようにしています。

これはexce.liveクラウドからExcelへ受信すると受信用シートの内容が更新されるため、シートのチェンジイベントを利用する事でexce.liveクラウドからメッセージを受信するタイミングでマクロを実行する事ができます。

受信した情報はシートに出力されているのでこの情報をそのまま3Dモデルの回転プロパティへ代入する事で回転を実現しています。

Option Explicit

Private 原点X As Long
Private 原点Y As Long
Private 原点Z As Long


Public Sub rotationShape()
    
    ''Debug.Print wsLog.Range("A1").Value
    ''Debug.Print wsMsg.Range("A1").Value
    
    'メッセージから回転角度とキャラクターIDを取得
    Dim dRotX As Double
    Dim dRotY As Double
    Dim dRotZ As Double
    Dim sCharID As String
    With wsMsg
        dRotZ = CDbl(.Range("B1").Value)
        dRotX = CDbl(.Range("C1").Value)
        dRotY = CDbl(.Range("D1").Value)
        sCharID = .Range("E1").Value
        
    End With
    
    
    '' リセット情報から補正
    If sCharID = "reset" Then
        原点X = dRotX
        原点Y = dRotY
        原点Z = dRotZ
    End If
    
    dRotX = dRotX - 原点X
    dRotY = dRotY - 原点Y
    dRotZ = dRotZ - 原点Z
    
    Do While dRotX > 360
        dRotX = dRotX - 360
    Loop
    Do While dRotX < 0
        dRotX = dRotX + 360
    Loop
    
    Do While dRotY > 360
        dRotY = dRotY - 360
    Loop
    Do While dRotY < 0
        dRotY = dRotY + 360
    Loop
    
    Do While dRotZ > 360
        dRotZ = dRotZ - 360
    Loop
    Do While dRotX < 0
        dRotZ = dRotZ + 360
    Loop
    
    
    Debug.Print "( " & dRotX & " , " & dRotY & " , " & dRotZ & " )"
    
    
    'キャラクターを取得
    '※複数キャラクターを用意して表示・非表示で切り替えようとしたが重くなったため断念
    Dim shape3D As Shape
    Set shape3D = wsData.Shapes.Item(1)
    ''
    
    'キャラクターを回転
    With shape3D.Model3D
''
''        Application.ScreenUpdating = False
''        Application.EnableEvents = True
''        Application.Calculation = xlCalculationManual
    
        .RotationX = dRotX '' 5
        .RotationY = dRotY
        .RotationZ = dRotZ

''        Application.ScreenUpdating = True
''        Application.EnableEvents = False
''        Application.Calculation = xlCalculationAutomatic
        
        
    End With
    
End Sub

こちらは大したことをしていないです。

受信したデータに合わせて3Dのシェイプの回転角度を設定しているだけです。

プログラム内のコメントにも書いていますが複数のキャラクターを準備しておいて送信用HTMLで表示するキャラクターを選べるようにしようとしましたが複数の3Dのシェイプを保持しているとかなり重くなってしまったので断念しました。

まとめ

今回紹介したデモ「3Dモデル回転」はかなり特殊な使い方をした事例です。

スマホのジャイロセンサをなんとかexce.liveクラウドで活用できないか?の考えからこのデモを作成しました。

僕がVBAに慣れている事もありますが今回の肝となる送信用プログラムは難儀しました。

無駄な実装があるかもしれないですがご了承ください。

コメント

タイトルとURLをコピーしました