JavaScript/HTML5おぼえがき
デバイスの情報取得
スマートフォン/タブレットのGPS、ジャイロセンサー、マイク、カメラなどのデバイス情報が取得出来て、色々な処理が出来ます。
デバイスの向き情報を取得する 戻る
デバイスのz・x・y軸の向き情報が取得できます。
- alpha の値は z 軸を中心にした端末の向きを表し、0 以上 360 未満の範囲の度数表示。
- beta の値は x 軸を中心にした端末の向きを表し、-180 以上 180 未満の範囲の度数表示。
- gamma の値は y 軸を中心にした端末の向きを表し、-90 以上 90 未満の範囲の度数表示。
方位(z軸)は、相対方位と絶対方位(北向き)があり、絶対方位はios(iPhone/iPad)の場合はdeviceorientationのイベントでwebkitCompassHeading値を取得します。
それ以外(Android)の場合はdeviceorientationabsoluteのイベントでalpha値を取得します。
またiosの場合は向きデータへアクセス許可を取得するために requestPermission() を通して明示的に利用者による同意を要求します。
iOS13以降は DeviceOrientationEvent.requestPermission() を呼んでユーザーが「許可」を押さないとセンサーが使えません。
deviceorientation / deviceorientationabsolute は ページロード直後には動かず、ボタンなどをタップしてから DeviceOrientationEvent.requestPermission() を呼ぶ必要があります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ジャイロセンサー</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<h1>ジャイロセンサ</h1>
<input type="button" id="permit" value="デバイス情報取得許可"/>
<div id="out"></div>
<p>ジャイロセンサの(Gyo Sernsor)取得値<br>
alpha(z)は画面に対して垂直な軸の角度(0~360度)<br>
beta(x)は横軸の角度(-180~180度)<br>
gammer(y)は縦軸の角度(-90~90度)</p>
<script>
<!--
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
window.onload = function() {
if (!isIOS) {
permit.style.display = "none" ;
window.addEventListener("deviceorientationabsolute", handleOrientation, true);
}
dsp(0,45,0) ;
}
// ユーザーの操作(ボタンタップなど)で呼び出す関数
document.getElementById('permit').addEventListener('click', () => {
// 許可をリクエスト
if (typeof DeviceOrientationEvent.requestPermission === 'function') {
DeviceOrientationEvent.requestPermission()
.then(permissionState => {
if (permissionState === 'granted') { window.addEventListener("deviceorientation", handleOrientation, true); }
})
.catch(console.error);
} else {
// requestPermission がない古いブラウザの場合
window.addEventListener("deviceorientation", handleOrientation, true);
}
permit.style.display = "none" ;
});
function handleOrientation(e){
a = e.alpha ;
b = e.beta; // X軸(端末の左右)周りの回転角度
g = e.gamma; // Y軸(端末の上下)周りの回転角度
if ( isIOS ) { a = 360-e.webkitCompassHeading; }
dsp(a,b,g) ;
}
function dsp(a,b,g) {
var output = document.getElementById("out");
output.innerHTML = "Gyro Sensor<br />";
output.innerHTML += "alpha" + " = " + a + "<br />";
output.innerHTML += "beta" + " = " + b + "<br />";
output.innerHTML += "gamma" + " = " + g + "<br /><br />";
}
</script>
</body>
</html>
位置情報取得 戻る
GPS(地球上の現在位置を測定するためのシステム)より位置情報(緯度・経度)を取得します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>位置情報の取得</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script>
z_latitude = "" ;
z_longitude = "" ;
z_altitude = "" ;
z_accuracy = "" ;
z_altitudeAccuracy ="" ;
z_heading = "" ;
z_speed = "" ;
z_timestamp = "" ;
z_msg ="" ;
if (navigator.geolocation) {
// navigator.geolocation.getCurrentPosition(successCallback, errorCallback,{ enableHighAccuracy:true,timeout :5000 });
navigator.geolocation.watchPosition (successCallback, errorCallback);
}
else {z_msg ="Geo Location APIに対応していません" ; dsp() ;alert("\nこのブラウザでは動作しません。\nHTML5サポートプラウザをご利用下さい。"); }
function successCallback(position) {
z_latitude = position.coords.latitude ; //緯度
z_longitude = position.coords.longitude ; //経度
z_altitude = position.coords.altitude ;
z_accuracy = position.coords.accuracy ;
z_altitudeAccuracy = position.coords.altitudeAccuracy ;
z_heading = position.coords.heading ; //方角
z_speed = position.coords.speed * 3.6 ; //速度
z_timestamp = position.timestamp ;
time = position.timestamp;
dateObj = new Date(time);
yy = dateObj.getFullYear();
mo = dateObj.getMonth() + 1;
dd = dateObj.getDate();
hh = dateObj.getHours();
mm = dateObj.getMinutes();
ss = dateObj.getSeconds();
ms = dateObj.getMilliseconds();
z_timestamp = hh+":"+mm+":"+ss+"."+ms ;
z_msg ="" ;
dsp() ;
}
function dsp() {
tx = "緯度(度): " + z_latitude + "<br>";
tx += "経度(度): " + z_longitude + "<br>";
tx += "高度(m): " + z_altitude + "<br>";
tx += "緯度・経度の<br>";
tx += "誤差(度): " + z_accuracy + "<br>";
tx += "高度の誤差(m): " + z_altitudeAccuracy + "<br>";
tx += "方角(度): " + z_heading + "<br>";
tx += "速度(Km/h): " + z_speed + "<br>";
tx += "時間(時分秒): " + z_timestamp + "<br>";
tx += "状態: " + z_msg + "<br><br>";
document.getElementById("show_result").innerHTML = tx;
msg.innerHTML ="" ;
}
function errorCallback(error) {
var z_msg = "予期しないエラー:"+error ;
switch(error) {
case 1 : z_msg = "位置情報の利用が許可されていません" ; break;
case 2 : z_msg = "デバイスの位置が判定できません" ; break;
case 3 : z_msg = "タイムアウトしました" ; break;
}
dsp() ;
}
</script>
</head>
<body>
<h1>位置情報の取得</h1>
<p id="msg">しばらくお待ちください。</p>
<div id="show_result"></div>
</body>
</html>
マイクの操作 戻る
navigator.mediaDevices.getUserMediaでマイクから音声を取り込んで、WevAudioAPIの処理で音の加工ができます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>音声チェック</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
<h1>音響チェック</h1>
<p><br>
入力音(マイクなど)の波形とスペクトル(音を構成する周波数とその強度の分布)分析グラフを表示します。スペクトル分析範囲は0~22028Hzです。</p>
<canvas id = "c1" width="320" height="160"></canvas><br>
<canvas id = "c2" width="320" height="160"></canvas>
<form name="form">
Level:<input type="range" min="0" max="1" step="0.1" name="level" value="0.5" onchange="srt()">
</form>
<script type="text/javascript">
canvas1 = document.getElementById("c1"); // キャンバスの設定
canvasContext1 = canvas1.getContext('2d');
canvas2 = document.getElementById("c2"); // キャンバスの設定
canvasContext2 = canvas2.getContext('2d');
var handleSuccess = function(stream) {
window.AudioContext = window.AudioContext || window.webkitAudioContext; // AudioContextクラスインスタンス生成(Web互換指定)
context = new AudioContext();
input = context.createMediaStreamSource(stream) ;
analyser = context.createAnalyser(); // Analyserノードのインスタンスの作成
analyser.fftSize = 2048; // 標準値 context.createGain = context.createGain || context.createGainNode;
gain = context.createGain(); // gainノードのインスタンスの作成
gain.gain.value = parseFloat(form.level.value); // レベルの設定
input.connect(gain); // analyserノードに接続する
//analyser.connect(gain); // gainノードに接続する
gain.connect(analyser); // サウンド出力ノードに接続する
analyser.connect(context.destination); // サウンド出力ノードに接続する
drawwave1() ;
drawwave3() ;
}
srt() ;
function srt(){
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(handleSuccess,errorFunc) ;
}
function cngg() { stp() ; srt() ; }
function cng() {}
function errorFunc(error) { alert("error"); }
function stp() { context.close() } // 音源の再生停止
function errorFunc(error) { alert("入力音源がありません"); }
function drawwave1() {
intervalid1 = window.setInterval(function() {
var times = new Uint8Array(analyser.fftSize); // Array sizeは1024 (FFTサイズの半分の値)
analyser.getByteTimeDomainData(times);
canvasContext1.fillStyle = "#333333" ;
canvasContext1.fillRect(0, 0, canvas1.width, canvas1.height); // キャンバスのクリア
canvasContext1.beginPath(); // 描画の開始
canvasContext1.strokeStyle ="#ffffff" ;
for (var i = 0, len = times.length; i < len; i++) {
var x = (i / len) * canvas1.width;
var y = (1 - (times[i] / 255)) * canvas1.height;
if (i === 0) { canvasContext1.moveTo(x, y); } else { canvasContext1.lineTo(x, y); }
}
canvasContext1.stroke(); // 描画
}, 50); // 1秒間に50回
}
function drawwave3() {
intervalid2 = window.setInterval(function() {
var spectrums = new Uint8Array(analyser.frequencyBinCount); // Array sizeは1024 (FFTサイズの半分の値)
analyser.getByteFrequencyData(spectrums);
canvasContext2.fillStyle = "#333333" ;
canvasContext2.fillRect(0, 0, canvas2.width, canvas2.height); //キャンバスのクリア
k = Math.round( 5000 * canvas2.width / 22050) ;
canvasContext2.fillStyle = "#ffffff" ;
canvasContext2.strokeRect(0,0,canvas2.width,canvas2.height);
canvasContext2.font = "11pt Arial";
canvasContext2.fillStyle = "#ffffff";
jj = 0 ;
for ( var j = 0 ; j < canvas2.width ; j = j + k ) {
canvasContext2.strokeRect(0,0,j,canvas2.height ) ;
canvasContext2.fillText ( jj*5 + "kHz",j-40, 15); jj++ ;
}
canvasContext2.beginPath(); // 描画開始
for (var i = 0, len = spectrums.length; i < len; i++) {
var value = spectrums[i]
var percent = value /256 ;
var height = canvas2.height * percent ;
var offset = canvas2.height - height - 1 ;
var barWidth = canvas2.width / analyser.frequencyBinCount ;
var hue = i / analyser.frequencyBinCount * 360 ;
canvasContext2.fillStyle = "hsl(" + hue + ",100%,50%)" ;
canvasContext2.fillStyle = "#ffffff" ;
canvasContext2.fillRect( i * barWidth,offset,barWidth,height) ;
}
}, 10); // 1秒間に10回
}
</script>
</body>
</html>
カメラの操作 戻る
navigator.mediaDevices.getUserMediaでカメラの操作ができます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>カメラの応用</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style></style>
</head>
<body>
<h1>カメラの応用</h1>
<p>スマートフォンカメラの応用で、鏡、虫メガネで使えます。</P><br>
<div id="contents" style="text-align: center;">
<video id="camera"></video>
<br>
<button type="button" onclick="cng_camera()">カメラの切替</button>
<button type="button" onclick="video.pause();">停止</button>
<button type="button" onclick="video.play() ;">開始</button>
<p>カメラの切替でフロントとリアが無い場合はエラーになりますので、再度切替ボタンを押してください。</P>
</div>
<script>
// カメラのデフォルト設定
var CONSTRAINTS = {
audio: false,
video: {
width: 320,
height: 240,
facingMode: null // どのカメラを利用するか
// facingModeには最終的に以下のいずれかの値を入れる
// facingMode: "user" // フロントカメラを利用する
// facingMode: { exact: "environment" } // リアカメラを利用する
}
}
// 現在のStream
var curSTREAM = null;
window.onload = function() {
video = document.querySelector("#camera");
useFront = true; // フロントカメラ:true, バックカメラ:false
// 縦横の解像度を調整
//adjustCameraSize(video, 640, 480);
// カメラと同期開始
syncCamera(video, useFront);
useFront = !useFront; // boolean値を反転
} ;
// 切り替えボタン押下
function cng_camera() {
syncCamera(video, useFront);
useFront = !useFront; // boolean値を反転
}
// カメラを<video>と同期
function syncCamera(video, is_front=true){
// 前後カメラの設定
CONSTRAINTS.video.facingMode = (is_front)? "user":{ exact: "environment" };
// すでにカメラと接続していたら停止
if( curSTREAM !== null ){
curSTREAM.getVideoTracks().forEach( function (camera) { camera.stop() ; });
}
// カメラと接続する
navigator.mediaDevices.getUserMedia(CONSTRAINTS)
.then( function(stream) {
curSTREAM = stream; // 前後の切り替え用に保持
// <video>とStremaを接続
video.srcObject = stream;
video.onloadedmetadata = (e) => {
video.play();
};
})
.catch( function(err) {
// console.log(`${err.name}: ${err.message}`);
alert("カメラとの接続時にエラーが発生しました");
});
}
//解像度に合わせて<video>サイズを調整する
function adjustCameraSize(video, longside, shortside){
if( window.innerWidth < window.innerHeight ){
CONSTRAINTS.video.width = shortside;
CONSTRAINTS.video.height = longside;
video.style.width = shortside;
video.style.height = longside;
}
}
</script>
</body>
</html>