deck.glで地図上に動画を表示する
この記事はdeck.gl Advent Calendar 2021 参加記事です。
概要
deck.glには地図上に画像をひょうじするBitmapLayerが存在しますが、ときにはLeafletのサンプルにあるように動画を地図上に描画したい場合があります。ちょっとした工夫で動画を表示することができるので、その方法を説明します。
なお、動画を表示するにはexperimental(実験的)となっているレイヤーのアニメーションレンダリング機能を使用する必要があるのですが、今のことスマートフォン(特にiOS)には非対応のようです。
サンプルコード
解説
動画ファイルをvideo要素に読み込み、SimpleMeshLayerを用いて生成した平面ジオメトリにテクスチャーとして描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import { TileLayer } from "deck.gl"; import { PlaneGeometry } from "@luma.gl/engine"; //平面のジオメトリを生成 const plane = new PlaneGeometry({ type: "x,z", xlen: 426, zlen: 260, nx: 5, nz: 5, offset: 0 }); //planeを描画する位置(緯度経度)を指定 const data = [ { position: [-115, 22.5] } ]; export function renderLayers(props) { const { video } = props; //親コンポーネントからvideo要素を受け取る //geometryをレンダリングする const meshlayer = new SimpleMeshLayer({ id: "mesh-layer", data: data, //位置情報を渡す mesh: plane, //平面ジオメトリを指定する texture: video, //動画を再生しているvideo要素をテクスチャーとして指定する sizeScale: 9000, getPosition: (d) => d.position, getColor: (d) => [255, 0, 0], getOrientation: (d) => [0, 0, 90], material: false }); return [meshlayer]; } |
再生している動画を連続的にレンダリングするために、Deckコンポーネントの_animateプロパティを有効化してます。
_animateプロパティを有効にすると、deck.glはアニメーションフレームごとにレイヤーの再描画を行うようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
const VIDEO_URL = "./video/patricia_nasa.mp4"; const App = () => { const [video, setVideo] = useState(null); useEffect(() => { let videoEl; if (typeof document !== "undefined") { //ビデオ要素を生成する videoEl = document.createElement("video"); videoEl.crossOrigin = "anonymous"; //ユーザー資格情報を送信 videoEl.preload = "auto"; // 自動で動画データの読み込みを行う videoEl.muted = true; //音声をミュートに videoEl.loop = true; //ループ再生を有効化 videoEl.autoplay = true; //自動再生を有効化 //動画ソース要素を生成 const source = document.createElement("source"); source.src = VIDEO_URL; //ビデオファイルを読み込み指定 videoEl.append(source); //ビデオ要素に動画ソース要素を加える videoEl.onloadeddata = (event) => { //データが読み込まれ動画の再生が可能になったら、再生する videoEl.play(); }; //ビデオ要素を保存 setVideo(videoEl); } }, []); //レンダリング return ( <DeckGL views={ new MapView({ repeat: true }) } layers={renderLayers({ video })} //レイヤーにビデオ要素を渡す controller={{ type: MapController }} initialViewState={viewState} _animate={true} //アニメーションフレームごとのレンダリングを有効化する /> ); }; export default App; |