1,class類的定義
class WebAR { /** * 初始化Web AR * @param interval 識別間隔(毫秒) * @param recognizeUrl 識別服務地址 * @param isDebug 是否輸入調試信息 * @param token 非必需,使用token認證識別 */ constructor(interval, recognizeUrl, token) { this.isRecognizing = false; // 前/后置攝像頭 this.cameras = ["user", "environment"]; this.interval = interval; this.recognizeUrl = recognizeUrl; this.token = token; } /** * 列表設備上的所有攝像頭 * @param videoDevice * @returns {Promise<T>} */ listCamera(videoDevice) { return new Promise((resolve, reject) => { navigator.mediaDevices.enumerateDevices() .then((devices) => { let index = 1; devices.find((device) => { if (device.kind === 'videoinput') { const option = document.createElement('option'); // 在iOS12.2上deviceId為空 if (device.deviceId == '') { option.text = device.label || 'camera ' + this.cameras[index]; option.value = JSON.stringify({ audio: false, video: { facingMode: { exact: this.cameras[index] } } }); index++; } else { option.text = device.label || 'camera ' + (videoDevice.length + 1).toString(); option.value = JSON.stringify({ audio: false, video: { deviceId: { exact: device.deviceId } } }); } // 將攝像頭信息存儲在select元素中,方便切換前、后置攝像頭 videoDevice.appendChild(option); } return false; }); if (videoDevice.length === 0) { reject('沒有可使用的視頻設備'); } else { this.initVideo(); this.initCanvas(); resolve(true); } }).catch(err => { reject(err); }); }); } /** * 打開攝像頭 * 攝像頭設置參數請查看: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints * @param videoDeviceIndex * @returns {Promise<T>} */ openCamera(constraints) { // 如果是切換攝像頭,則需要先關閉。 if (this.videoElement && this.videoElement.srcObject) { this.videoElement.srcObject.getTracks().forEach(track => { track.stop(); }); } return new Promise((resolve, reject) => { navigator.mediaDevices.getUserMedia(constraints) .then(stream => { this.videoElement.srcObject = stream; this.videoElement.style.display = 'block'; this.videoElement.play(); this.videoElement.onloadedmetadata = () => { const cameraSize = { width: this.videoElement.offsetWidth, height: this.videoElement.offsetHeight }; console.info(JSON.stringify(cameraSize)); if (window.innerWidth < window.innerHeight) { // 豎屏 if (cameraSize.height < window.innerHeight) { this.videoElement.setAttribute('height', window.innerHeight.toString() + 'px'); } } else { // 橫屏 if (cameraSize.width < window.innerWidth) { this.videoElement.setAttribute('width', window.innerWidth.toString() + 'px'); } } resolve(true); }; }) .catch(err => { reject(err); }); }); } /** * 截取攝像頭圖片 * @returns {string} */ captureVideo() { this.canvasContext.drawImage(this.videoElement, 0, 0, this.videoElement.offsetWidth, this.videoElement.offsetHeight); // console.log(this.canvasElement.toDataURL('image/jpeg', 0.5).split('base64,')[1]); return this.canvasElement.toDataURL('image/jpeg', 0.5).split('base64,')[1]; } /** * 創建視頻詳情元素,播放攝像頭視頻流 */ initVideo() { this.videoElement = document.createElement('video'); this.videoElement.setAttribute('playsinline', 'playsinline'); document.body.appendChild(this.videoElement); } /** * 創建canvas,截取攝像頭圖片時使用 */ initCanvas() { this.canvasElement = document.createElement('canvas'); this.canvasElement.setAttribute('width', window.innerWidth.toString() + 'px'); this.canvasElement.setAttribute('height', window.innerHeight.toString() + 'px'); this.canvasContext = this.canvasElement.getContext('2d'); // document.body.appendChild(this.canvasElement); } /** * 識別 * @param callback */ startRecognize(callback) { this.timer = window.setInterval(() => { // 等待上一次識別結果 if (this.isRecognizing) { return; } this.isRecognizing = true; // 從攝像頭中抓取一張圖片 const image = { image: this.captureVideo() }; // 發送到服務器識別 this.httpPost(image) .then((msg) => { this.stopRecognize(); callback(msg); }) .catch((err) => { this.isRecognizing = false; console.info(err); }); }, this.interval); } /** * 停止識別 */ stopRecognize() { if (this.timer) { window.clearInterval(this.timer); this.isRecognizing = false; } } httpPost(image) { return new Promise((resolve, reject) => { const http = new XMLHttpRequest(); http.onload = () => { try { const msg = JSON.parse(http.responseText); if (http.status === 200) { if (msg.statusCode === 0) { resolve(msg.result); } else { reject(msg); } } else { reject(msg); } } catch (err) { reject(err); } }; http.onerror = (err) => { reject(err); }; http.open('POST', this.recognizeUrl); http.setRequestHeader('Content-Type', 'application/json;Charset=UTF-8'); if (this.token) { // 將雲識別認證token寫在請求頭中 http.setRequestHeader('Authorization', this.token); } http.send(JSON.stringify(image)); }); } } //# sourceMappingURL=webar.js.map
2,類的創建和調用
// 別間隔時間(毫秒), 識別服務地址 // const webAR = new WebAR(1000, '/webar/recognize'); const webAR = new WebAR(1000, url, token); // 列出並打開設備上的攝像頭 document.querySelector('#openCamera').addEventListener('click', function () { const videoSelect = document.querySelector('#videoDevice'); webAR.listCamera(videoSelect) .then(msg => { // 隱藏"打開攝像頭"按鈕 this.style.display = 'none'; videoSelect.style.display = 'inline-block'; document.querySelector('#start').style.display = 'inline-block'; document.querySelector('#stop').style.display = 'inline-block'; videoSelect.onchange = () => { webAR.openCamera(JSON.parse(videoSelect.value)); }; // 打開攝像頭 // 打開后置攝像頭參數: {audio: false, video: {facingMode: {exact: 'environment'}}} webAR.openCamera(JSON.parse(videoSelect.value)) .then(msg => { console.info(msg); }).catch(err => { console.info(err); }); }) .catch(err => { // 沒有找到攝像頭 console.info(err); }); console.log("list0"); }); // 開啟識別 document.querySelector('#start').addEventListener('click', () => { webAR.startRecognize((msg) => { console.info(msg); alert('識別成功'); }); }, false); // 暫停識別 document.querySelector('#stop').addEventListener('click', () => { webAR.stopRecognize(); }, false); //# sourceMappingURL=app.js.map