WHATWG Fullscreen API を仕様通りに使えるモジュール「fullscrn」
WEBページ内の特定HTML要素を画面全体に広げられるフルスクリーンAPIのラッパーモジュールをnpmで公開しました。
WHATWGが策定しているフルスクリーンAPIは、現状(2017年5月現在)、多くのブラウザで、プリフィックス付きの実装(moz
とかwebkit
というアレですね)となっています。
なので、いろんなブラウザで動作させるには結構邪魔くさいことをするわけですが、このモジュールを使えば標準仕様と同じように利用できます。
目次
↓npm fullscrnはコチラです。
売り上げランキング: 247,047
1. リリースファイル
- fullscrn.js - SCRIPTタグで読み込む用。Browserifyでまとめているからちょっと読みにくいかも。
- fullscrn.min.js - ↑をミニファイしたもの(uglify使用)
- index.js - ソースファイル。npmでBrowserifyを使用してrequireする場合はコチラが使用されると思います。
2. サンプル
あまり意味のないサンプルですけどすみません。動きはわかると思います。
<body onload="main();"> <button type="button" onclick="request1();" >Full>></button> <span id="panel"> <button type="button" onclick="request2();" >Full>></button> <button type="button" id="exitButton" onclick="exit();"><<Exit</button> </span> <script src="fullscrn.js"></script> <script> var panel = document.getElementById("panel"); var exitButton = document.getElementById("exitButton"); Fullscreen.debugMode(true);// Enables debug log function main() { // Handle change event document.addEventListener("fullscreenchange", function() { var fse = document.fullscreenElement; console.log("FULLSCREEN CHANGE: " + ((fse == null)? "(null)": "#" + fse.id)); }); // Handle error event document.addEventListener("fullscreenerror", function() { console.log("FULLSCREEN ERROR"); }); request1(); // This should be error } function request1() { panel.requestFullscreen().then(function(){ console.log("request1 done."); }).catch(function(err) { console.error(err.message); }); } function request2() { exitButton.requestFullscreen().then(function(){ console.log("request2 done."); }).catch(function(err) { console.error(err.message); }); } function exit() { document.exitFullscreen() .then(function(){ console.log("exit done."); }).catch(function(err) { console.error(err.message); }); } </script> </body>
3. API
以降の各インターフェースは、標準仕様の通りに使用できるように、DOMの DocumentクラスやElementクラスのprototypeに、インジェクトしています。
ただし、完全一致を狙っているわけではないので、完全に同じ挙動をすることを保証しません。各社ブラウザ間でも挙動が微妙に違っていたりしますが、そこには全く触れていません。
また、2017-05-16にWHATWGの仕様が改定されており、本モジュール作成にあたっては、それ以前の仕様を参考にしていたため、違うところがあるかもしれません(未確認)。
※ 別途、独立したAPIもエクスポートしていますが、使う必要が無いのでここでは説明しません。
1) プロパティ
Document.fullscreenEnabled
フルスクリーンAPIが使用できるかどうかを示すbool型のプロパティ。スクリプトの読み込み時に決定します。
Document.fullscreenElement
全画面モードになっている要素を保持します。全画面モードでないときはnullです。
Document.fullscreen
参照時点で全画面モードかどうかを示すbool型のプロパティ(Document.fullscreenElement != null
と同等)。
2) メソッド
以下、どちらも、操作の完了時に解決するPromiseを返します。まあ殆どの場合無視して構いません。
Element.requestFullscreen()
HTML要素で全画面モードを開始する要求を行います。
Document.exitFullscreen()
全画面モードを終了します。
3) イベント
全画面の状態が変化した場合や、エラー発生時のイベントです。
どちらも、document.addEventListener
でイベントハンドラを登録して利用してください。
(Document.onfullscreenchange
/ Documentonfullscreenerror
には未対応です)
Document "fullscreenchange"
全画面モードの状態変化時に発生します。
Document "fullscreenerror"
全画面モードに関するエラーがあった時に発生します。
ていうか標準仕様と同じですから。
4. リンク
- Fullscreen API Living Standard — Last Updated 16 May 2017
- フルスクリーンモードを使用する - ウェブデベロッパーガイド|MDN
- npm fullscrn - Fullscreen API
5. あとがき
標準仕様と実装の混乱ぶり
現状、フルスクリーンAPIはプリフィックス付きで実装されているのに、既にObsoleteな仕様があったりしてカオスです。
さらに「Fullscreen
なの?FullScreen
なの?どっち?」という若干低レベルな混乱ぶりも垣間見れ、非常に使いづらい状況でした。
各社勝手に実装して、後から仕様をまとめるからこうなるんだろうなあ。知らんけど。
どうでもいいこと
このモジュール、ほとんどフルスクリーンAPIのPolyfillだと言えると思うのですが、npmでは既にfullscreenというモジュールが公開されていたため、仕方なくfullscrnという名になってます。
アチラはAPIのインターフェースがWHATWGの仕様に合致していないっぽいので、色んな意味でちょっと残念。 (# ̄З ̄)
しかしダウンロード数が遥かに多くて(約20倍!)、本家といえばアチラなのかも?
SVGの重なり順序をJavaScriptで制御する「svg-z-order」
JavaScriptからSVG要素の重なり順(Z-Order)を操作するモジュールのご紹介。
SVG要素には、HTMLに使えるz-index
スタイルが効きません。
なので、重なり順を変更するには、単純に要素を並べ替える必要があります。
コードからDOM要素を並べ替えるにはNodeクラスのinsertBefore
メソッドが使えます。
Node
クラスはSVG要素SVGElement
の基本クラスですから、SVG要素でも使えます。
SVG関連最新記事:
takamints.hatenablog.jp
takamints.hatenablog.jp
ところで、SVG要素にはz-index
が効かないことを「SVGの致命的な欠陥」と言ってる人がいますが、さすがにそれは言い過ぎですよ。SVGは単体で存在できる画像ファイルであってHTMLとの直接的なつながりはありません。単体のSVGファイル中で図形の重なり順序をz-index
で定義されていると、画像としてどのように表示されるか理解しにくいはずです。要素の順序で重なり順序が決定される方が、SVG的に「よりシンプル」なんですね。
さらに「HTMLのDIVにSVGを入れてz-index
で…」などというヤヤコシイ方法が検索で出てくるのですが、これは既にSVGではなくなっていますから、一般的な解決法とはいえないように思います。全体のスケールを変えるとかViewportを移動したいとかいったシーンで困りそう。
というか、DOM要素の並べ替え自体は前述のようにinsertBeforeで簡単なんです。 DOMのベタな扱いに慣れていないと難しそうに思うのかもしれないですね。
ただし、ベタにやると「どれの前に持ってくる?」といったコードが煩雑になるのは確かです。 てことで怒りに任せて(?)npmを書きなぐりました。以降、このモジュールのサンプルとかAPIを説明します。
とりあえずは動くサンプル
以下は、このモジュールを使ったサンプルです。コードは下の方に掲載してます。 3つの円をクリックすると、その要素にドロップダウンで選ばれているメソッドを適用します。
使い方
このモジュールを使って、特定要素を最前面へ持ってくるコードを少し冗長に書いてみました。
//モジュール取得 var svgz = require("svg-z-order");// (1) //SVG要素 g#foo を最前面へ表示 var g = svg.getElementById("foo"); var svgzG = svgz.element(g); //(2) svgzG.toTop(); //(3) // D3.jsで使う(4) var d3 = require("d3"); var d3g = d3.select("#foo"); svgz.element(d3g.node()).toTop();
- モジュールをインポートして、
element
メソッドで、DOM要素を参照するインスタンスを作り- 最前面へ表示します。
- D3.jsを使っていますが、例として書いているだけで、依存関係はありません。
上の例では、Browserifyを使って、
var svgz = require("svg-z-orger");
でモジュールを取り込んでいますが、
HTMLで<script src="svg-z-order.js"/>
としている場合は、
(2)の行の svgz.element(g)
を、 svgz_element(g)
に変更して下さい。
require
できない環境ではグローバルスコープに定義します。
API
element(e:Element)
SVG要素を参照する SVGZElement クラスのインスタンスを返します。 Z-Orderを操作するAPIは SVGZElementクラスのメソッドです。
パラメータ
- e:Element - 参照するDOM要素を指定します。
SVGZElementクラス
SVGZElement.toTop()
参照している要素を最前面に移動。
SVGZElement.toBottom()
参照している要素を最背面に移動。
SVGZElement.moveUp(e:Element / n:number)
参照している要素を上(前面)へ移動。
パラメータ
- e:Element - この要素よりも上になるように移動します。
- n:number - 要素の並びの中でこの回数分だけ上へ移動します。
要素を指定したときはその要素よりも上へ。数値指定した場合は、その回数だけ上へ移動。
SVGZElement.moveDown(e:Element / n:number)
参照している要素を下(背面)へ移動。
パラメータ
- e:Element - この要素よりも下になるように移動します。
- n:number - 要素の並びの中でこの回数分だけ下へ移動します。
要素を指定したときはその要素よりも下へ。数値指定の場合は、その回数だけ下へ移動。
サンプルコード
一番上にあるサンプルのコードです。
/sample/web/index.js
リポジトリ
いくつになってもお勉強
JavaScriptのプログラムからSVG要素を最前面へもってくる方法を検索したら、結構微妙な情報が出てきたので少しインターネッツに失望しました。
曰く、
こういう情報を見て、当初「エラいヤヤコシイな」と思いましたが、どうにも納得がいかなくて、いろいろやってみているとDOMの標準機能で可能だと判明。
当初「複製作って、追加して、元のを消す」という処理手順をイメージしていましたが、移動できますね。
Node.appendChild
やNode.insertBefore
は、既にDOMツリーにある要素は移動するのですが、メソッド名を見る限りではそう思えないところが落とし穴かも。
いくつになってもお勉強です。
Node.js / npm 関連記事
takamints.hatenablog.jp takamints.hatenablog.jp takamints.hatenablog.jp takamints.hatenablog.jp takamints.hatenablog.jp
D3.js v4 でドラッグするには d3.drag() で behavior を取得する
D3.jsでドラッグイベントを処理する必要があったのですよ。
ほぼ初めてのD3ですからグーグル先生にいろいろ聞いて、「ほうほうなるほど」と学習していたのですけど、 ドラッグに関して各所で示されていたサンプル通りにやってみたら、まさかのエラー。
結局は、大きな問題ではありませんで、ひと言で言ってしまえばバージョン違いだったのですが、どうにも日本語の情報が少ないようなので書いておきます。
D3.js/v3でのコード
「D3.js ドラッグ」などと検索して出てくるサンプルコードの多くが、D3.jsのv3(バージョン3)のために書かれたコードで、最新のv4では動かないんですね。
v3でドラッグするには、d3.behavior.drag()
で、Drag Behavior を取得するのですが、v4ではこれが動かない。
// D3.js v3でDrag Behaviorを取得 var drag = d3.behavior.drag(); //V4ではエラー
D3.js/v4でのOKコード
じゃあどうやるんだって―と、v4以降では以下のように、d3.drag()
とするのだそうだ。
// D3.js/V4 でDrag Behaviorを取得 var drag = d3.drag(); // これでOK
リンク
リポジトリの CHANGES にはしっかり書いてありました。
CHANGES
github.com
Dragに関する詳細は以下に
github.com
いやしかし
メジャーバージョンが上がっているので、APIに互換性がなくなってても文句は言わない約束だけど、 レガシーコードには警告を出すとかって対応があればモアベターね。
JavaScriptのラムダ式(アロー関数)は丸括弧で括らなければ即時実行できませんのね
Node.jsで以下のようにラムダ式を即時実行していたのですが、ブラウザでは構文エラーとなって動かないんです。
(()=>{ console.log("これ動きません"); }());
まさかコレが動かないとか思いもよらず。 どう見直しても問題があるとは思えなかったのだが動かないから仕方がない。
追記(2017-03-29):JavaScriptの言葉的には「ラムダ式」ではなく「アロー関数」のようですので、タイトルにのみ追記しました。
色々やってみた結果、ブラウザで動作させるには、以下のようにラムダ式全体を丸括弧で括る必要があるようですね。 しかし、なんだかカッコが多すぎ。ラムダ的に台無し感がありますなー。
((()=>{ console.log("これでヨシ。だがしかし・・・"); })());
丸括弧なしでは関数オブジェクトとして評価されていないようです。
アロー演算子(=>
)の優先度の問題かな?
そもそも、どちらが正しいのかわからなかったので、調べてみると、どうやらECMAScript6の仕様のバグだそうで、 Node.jsでは便利な様に解釈して実装されているのかも知れませんが、今の所ブラウザではどうにもならないようですね。
即時実行するときはラムダ式を使わないというのが安全・安心? 関数内のthisが定義時にバインドされちゃうようなので、単なる無名関数の構文糖として使うのはマズいらしいし・・・
JavaScriptでマイクロ秒単位の定期処理を実行する(npm fractional-timer)
JavaScriptで1ミリ秒より短いインターバルタイマー処理を提供するモジュール fractional-timer
のご紹介。
Link: Flickr PAGE - CC BY-SA 2.0
実際のところ、精度はよくありませんので、クリティカルな用途には向きません。 単純な処理をなるべく高速にタイマーで実行したいけど、標準タイマーの1ミリ秒では遅すぎる・・・といった時に使える感じ。 処理が重い場合は、呼び出し間隔は長くなります。
Chrome と Node.Js で、正しく動いていることを確認していますが、 FirefoxやEdgeでは、まともに動いていなかったので、ご注意下さい。
使い方
使い方は遅延時間に実数を指定できる点を除けば、標準のsetInterval
/clearInterval
と同じです。
遅延時間は標準と同じくミリ秒単位で指定します(0.1=100マイクロ秒)。
以下のように呼び出すことで、タイマーの数と遅延時間等を調整して、定期処理を実行します。
(function() { "use strict"; var ft = require("fractional-timer"); var ftid = ft.setInterval( function(){ ft.clearInterval(ftid); }, 0.001);// 1 microsecond }());
インストール
npmでインストールすればNode.jsから使えます。
> npm install fraction-timer
ブラウザのWEBアプリでは、browserify
でrequire
するか、
script
タグで読み込んで、FractionalTimer
クラスの静的メソッドsetInterval
/clearInterval
を直接使ってくださいね。
リポジトリ
その他、能書き
やっていることは単純です。複数のインターバルタイマーで一つの処理を呼び出しているだけです。
例えば、1マイクロ秒で実行したい場合、1ミリ秒のタイマーを1000個使って呼び出すということです。
実際には、指定された間隔から算出される単位時間あたりの実行回数を計算し、タイマーの数と間隔を自動的に算出、ベストエフォートで呼び出します。
「MZ-700フルJavaScriptエミュレータ」で、エミュレーションをワーカースレッドの定期処理で実装していて、当初は単一のインターバルタイマーで、最も高速になるように調整していたのですが、ある時タイマーが二重に動いてしまったことがあって、速度がなんと2倍程度に跳ね上がっていたのです。
「うわあ!世紀の大発見!!!」と思ったけれど、単一スレッド内ではシーケンシャル動作が保証されているので、当然の挙動なんですよね。
ただ、こういうことをやってる人があまりいないところを見ると、需要はないみたいなんですけどね(笑)