iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
1

終於要來開始實作存取「裝置的媒體」和「地理位置」的功能。/images/emoticon/emoticon07.gif

當用戶要發佈貼文時,應該要開啟裝置的攝像鏡頭並將畫面顯示在PWA的表單中,當用戶按下拍照鍵時即完成影像拍攝,另外也會有一個按鈕來獲取裝置所在的地理位置。

首先,在index.html中的表單加入上面說到的button以及video元素吧:

<video id="player" autoplay></video>
<canvas id="canvas" width="320px", height="240px"></canvas>
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored" id="capture-btn">拍下屬於你的時刻</button>
        
<div id="pick-image">
    <h6>選擇圖片</h6>
    <input type="file" accept="image/*" id="image-picker">
</div>

<div class="input-section">
    <button class="mdl-button mdl-js-button mdl-button mdl-button-colored" type="button" id="location-btn">目前所在地</button>
    <div class="mdl-spinner mdl-js-spinner is-active" id="location-loader"></div>
</div>

除了用video元素來顯示串流影像之外,這邊為了要實現拍照的功能,當用戶按下拍照鍵後,就會擷取當下影像中的frame並放置在canvas中。

但如果用戶裝置沒有攝像鏡頭或是browser不支援的話,就改為自行上傳圖片來代替(image uploader)。最後加入要獲取地理位置的button,以及等待時的loading圖示。


接下來在feed.js修改一下新增的element大小和位置,並預設將file uploader隱藏起來:

#create-post {
  z-index: 1001;
  position: fixed;
  width: 100%;
  min-height: calc(100vh - 56px);
  overflow-y: scroll;
  bottom: 0;
  top: 56px;
  background: white;
  text-align: center;
  transform: translateY(100vh);
  transition: transform 0.3s;
}

#create-post video, #create-post canvas {
  width: 512px;
  max-width: 100%;
  display: none;
  margin: auto;
}

#create-post #pick-image {
  display: none;
}

#create-post #capture-btn {
  margin: 10px auto;
}

.mdl-spinner {
  margin: auto;
}

結果如下:

接下來,在feed.js中存取剛剛添加的element,並針對這些element開始實作拍照的功能吧:

var videoPlayer = document.querySelector('#player');
var canvasElement = document.querySelector('#canvas');
var captureButton = document.querySelector('#capture-btn');
var imagePicker = document.querySelector('#image-picker');
var imagePickerArea = document.querySelector('#pick-image');

在openCreatePostModal() function中新增「初始化媒體(initializeMedia)」的函式。希望用戶在開啟表單前,先確認瀏覽器是否有支援「存取媒體(getUserMedia)」這個API。

所以為了在舊的browser中使用getUserMedia() API,必須帶一個polyfill以適應舊browser:(參考連結)

function initializeMedia() {
    
  // 舊browser可能根本沒有實現mediaDevices,所以可以先設置一個empty object
  if(!('mediaDevices' in navigator)) {
    navigator.mediaDevices = {};
  }
  
  // 一些browser只有部分支持mediaDevices。所以不能直接給在該object設置getUserMedia 
  // 因為這樣可能會覆蓋已有的屬性。這裡我們只會在沒有 getUserMedia 屬性的時候添加它。
  if(!('getUserMedia' in navigator.mediaDevices)) {
    
    // getUserMedia的constraints參數包含了video和audio兩個成員的MediaStreamConstraints object
    navigator.mediaDevices.getUserMedia = function(constraints) {
      
      // 首先,如果有getUserMedia的話,就取得它
      var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

      // 一些browser根本沒實現它 - 那麼就返回一個error到promise的reject
      if(!getUserMedia) {
        return Promise.reject(new Error('getUserMedia is not implemented!'));
      }
      
      // 否則,為原有的navigator.getUserMedia()方法包裹一個Promise
      return new Promise(function(resolve, reject) {
        getUserMedia.call(navigator, constraints, resolve, reject);
      });
    }
  }
  
  // getUserMedia會返回一個Promise,這個Promise成功後的callback帶一個MediaStream object作為參數。
  navigator.mediaDevices.getUserMedia({video: true}).then(function(stream) {
  
    // 顯示video element
    videoPlayer.srcObject = stream;
    videoPlayer.style.display = 'block';
  }).catch(function(err) {
    // 若getUserMedia返回error,就讓用戶自行上傳圖片(image uploader)來代替
    imagePickerArea.style.display = 'block';
  });
}

明天再來實作當用戶按下拍照鍵後,就將當下影像的frame顯示在canvas上,並將這張圖片儲存至後台的firebase storage中。

Day25 結束!! /images/emoticon/emoticon15.gif


上一篇
[Day24] 實作PWA推播通知(Part3)
下一篇
[Day26] 了解Media API和Geolocation API(Part2)
系列文
你應該要知道的新一代Web技術---漸進式網頁(PWA)29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
RenZhou
iT邦新手 4 級 ‧ 2019-10-09 11:11:59

等等 發現大大連發三篇 但是他挑戰天數沒有加欸 XD!?

我要留言

立即登入留言